M2: tåg med tidtabell, spärrar med kort, skyltar, vinst/förlust
All checks were successful
release / build-release (push) Successful in 1m35s

- level: Schedule (ankomst/intervall/uppehåll) med Status(t), spårnummer,
  avgift, skylttexter per i-ruta, Path (BFS) och UngatedPlatforms – regeln
  att perronger bara nås via spärrar testas för alla banor
- sim.Run: klocka, tågkort (saldo dras vid spärr, tomt kort stoppas),
  ombordstigning med Enter när tåget är inne, vinst/förlust; headless
  bot-test klarar bana 001 och förlorar på fel tåg
- game: perronginfo (avgår om / nästa tåg om), skyltruta, nekad spärr,
  tågvagn som ritas när tåget är inne, inforutan flyttas upp när spelaren
  står nära nederkanten; resultat med spärrpassager och saldo
- bana 001 ombyggd så spärrarna är flaskhalsar; bana 002 omgenererad med
  spärrar runt perrongerna och skylttexter
- tools/shots räknar ut vägar med BFS; skriptkommandot waittrain
- docs/README/wiki uppdaterade med nya bilder

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
2026-10-23 19:36:45 +02:00
parent 3c00c7f356
commit a5a660b32f
26 changed files with 1031 additions and 135 deletions

View File

@@ -8,21 +8,16 @@ import (
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
"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"
)
// ResultScene visas när spelaren nått en perrong.
// ResultScene visas när banan är avgjord (rätt eller fel tåg).
type ResultScene struct {
from *LevelScene
train *level.Train
from *LevelScene
}
// NewResultScene bygger resultatet för banan som just spelades.
func NewResultScene(from *LevelScene, train *level.Train) *ResultScene {
return &ResultScene{from: from, train: train}
}
func (r *ResultScene) correct() bool { return r.train != nil && r.train.Correct }
func NewResultScene(from *LevelScene) *ResultScene { return &ResultScene{from: from} }
func (r *ResultScene) Update(g *Game) error {
switch {
@@ -44,22 +39,33 @@ func (r *ResultScene) Update(g *Game) error {
func (r *ResultScene) Draw(g *Game, screen *ebiten.Image) {
r.from.Draw(g, screen) // banan i bakgrunden
bg := color.RGBA{24, 20, 37, 230}
vector.DrawFilledRect(screen, 20, 40, ScreenW-40, 100, bg, false)
accent := color.RGBA{228, 59, 68, 255}
headline := g.Assets.T("level.wrong_train")
if r.correct() {
accent = color.RGBA{99, 199, 77, 255}
headline = g.Assets.T("level.cleared")
}
vector.DrawFilledRect(screen, 20, 40, ScreenW-40, 3, accent, false)
run := r.from.run
a := g.Assets
vector.DrawFilledRect(screen, 20, 36, ScreenW-40, 112, color.RGBA{24, 20, 37, 235}, false)
ebitenutil.DebugPrintAt(screen, headline, 28, 50)
if r.train != nil {
ebitenutil.DebugPrintAt(screen, fmt.Sprintf("%s -> %s", r.train.Line.Get("romaji"),
r.train.Destination.Get("romaji")), 28, 66) // TODO(M3): japanska när fonten finns
accent, headline := color.RGBA{228, 59, 68, 255}, a.T("level.wrong_train")
if run.Outcome == sim.Won {
accent, headline = color.RGBA{99, 199, 77, 255}, a.T("level.cleared")
}
ebitenutil.DebugPrintAt(screen, fmt.Sprintf("%s %.1fs %s %d", g.Assets.T("hud.time"), r.from.elapsed,
g.Assets.T("hud.steps"), r.from.steps), 28, 86)
ebitenutil.DebugPrintAt(screen, g.Assets.T("result.hint"), 28, 118)
vector.DrawFilledRect(screen, 20, 36, ScreenW-40, 3, accent, false)
ebitenutil.DebugPrintAt(screen, headline, 28, 46)
y := 62
if tr := run.Boarded; tr != nil {
// TODO(M3): japanska när fonten finns
ebitenutil.DebugPrintAt(screen, fmt.Sprintf("%s %s %s -> %s", a.T("hud.track"), tr.Track,
tr.Line.Get("romaji"), tr.Destination.Get("romaji")), 28, y)
y += 12
if run.Outcome == sim.Lost {
for _, l := range wrap(fmt.Sprintf(a.T("result.wrong_detail"), tr.Destination.Get("romaji"),
run.Level.Destination.Get("romaji")), 44) {
ebitenutil.DebugPrintAt(screen, l, 28, y)
y += 12
}
}
}
y += 6
ebitenutil.DebugPrintAt(screen, fmt.Sprintf("%s %.1fs %s %d %s %d %s %d¥", a.T("hud.time"), run.Time,
a.T("hud.steps"), run.Steps, a.T("result.gates"), run.GatePasses, a.T("result.card"), run.Card.Balance), 28, y)
ebitenutil.DebugPrintAt(screen, a.T("result.hint"), 28, 128)
}