Files
metro-puzzle-jp/internal/game/people.go
claude de61568e44
All checks were successful
release / build-release (push) Successful in 1m33s
M9b: folk, filer, reklam, sorl och vagnval
Folk på stationen (NPC:er som vandrar, kliver av tåg och går mot
utgången, blockerar spelaren men inte varandra), vänster-/högerfiler
som bromsar på fel sida, bredare gångar, reklamaffischer (clutter),
japanskt sorl i loop (noise), vagnval med kvinnovagn (stort avdrag med
man i sällskapet, tidsstyrd), kömarkeringar på perrongen, trängsel per
vagn (bonus för tom vagn, svettig-debuff och svårare resa i full vagn,
släpp förbi passagerare) och att folk kliver av innan man får gå på.
Ny bana 005 Ueno. Skärmdumpsverktyget kan filtrera på bana/skript.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-24 12:33:44 +02:00

99 lines
2.8 KiB
Go

package game
import (
"image/color"
"math"
"github.com/hajimehoshi/ebiten/v2"
"github.com/hajimehoshi/ebiten/v2/vector"
"gitea.brasse-pc.eu/brasse/metro-puzzle-jp/internal/level"
"gitea.brasse-pc.eu/brasse/metro-puzzle-jp/internal/sim"
)
// Folk, affischer och kömarkeringar (M9b).
// npcTints är gråtoner för passagerare tills de har egna sprites.
var npcTints = [][3]float32{{0.75, 0.75, 0.8}, {0.7, 0.8, 0.75}, {0.8, 0.72, 0.72}, {0.78, 0.78, 0.7}}
// drawNPCs ritar passagerarna på spelarens våning.
func (s *LevelScene) drawNPCs(g *Game, screen *ebiten.Image, ox, oy float64) {
z := s.run.Player.Tile.Z
for i, n := range s.run.NPCs {
if n.Mover.Tile.Z != z {
continue
}
x, y := n.Mover.WorldPos(TileSize)
var op ebiten.DrawImageOptions
op.GeoM.Translate(ox+math.Round(x), oy+math.Round(y))
t := npcTints[i%len(npcTints)]
op.ColorScale.Scale(t[0], t[1], t[2], 1)
screen.DrawImage(g.Assets.PlayerFrame(n.Mover.Facing, n.Mover.Moving(), s.animT+float64(i)*0.07), &op)
}
}
// buildPosters väljer seedat vilka väggrutor som får affischer (visuell röra).
func (s *LevelScene) buildPosters() {
s.posters = map[level.Point]int{}
l := s.run.Level
if l.Clutter == 0 {
return
}
r := s.run.Seed.Derive("posters").New()
chance := 0.12 * float64(l.Clutter)
for z := 0; z < l.NumFloors(); z++ {
for y := 0; y < l.Height(); y++ {
for x := 0; x < l.Width(); x++ {
p := level.Point{X: x, Y: y, Z: z}
if l.At(p) != level.Wall {
continue
}
adjFloor := false
for _, n := range l.Neighbors(p) {
if n.Z == z && l.At(n).Passable() {
adjFloor = true
}
}
if adjFloor && r.Float64() < chance {
s.posters[p] = r.IntN(posterCount)
}
}
}
}
}
// drawQueueMarks ritar kömarkeringar på perrongen (var man ställer sig för
// varje vagn) när tåget är på väg in eller står inne.
func (s *LevelScene) drawQueueMarks(screen *ebiten.Image, ox, oy float64) {
z := s.run.Player.Tile.Z
for _, tr := range s.tracks {
if tr.platform.Z != z {
continue
}
phase, _ := s.run.PlatformPhase(tr.tile)
if phase == level.Away || phase == level.Leaving {
continue
}
train := s.run.Level.TrainAt(tr.tile)
if train == nil {
continue
}
x := float32(ox + float64(tr.platform.X*TileSize))
y := float32(oy + float64(tr.platform.Y*TileSize))
cars := train.Cars
for k := 0; k < cars && k < 4; k++ {
col := color.RGBA{255, 255, 255, 200}
if train.WomenOnlyActive(s.run.Time) && k+1 == train.WomenOnlyCar {
col = color.RGBA{255, 150, 200, 230} // rosa: kvinnovagn
}
if tr.horizontal {
vector.DrawFilledRect(screen, x+float32(2+k*4), y+TileSize-6, 2, 3, col, false)
} else {
vector.DrawFilledRect(screen, x+TileSize-6, y+float32(2+k*4), 3, 2, col, false)
}
}
}
}
var _ = sim.NPCSpeed