diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e992b8..dd6572b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Oreleaset +- Texterna ryms på skärmen på både svenska och engelska: kortare etiketter + ("Mål"/"To"), bankartans tangentrad på två rader, HUD-raden stryker + delar som inte får plats, radbrytning i fler rutor; breddtester för alla + enradstexter med den riktiga fonten. - Bussar: flygbussterminalen (sidobana 001b) med tre bussar på väg, egen sprite, hållplatsskylt och tuta; sidobanan 003b Harajuku; överstimulerande UI med reklamticker på Ueno och Tokyo. diff --git a/doc/img/approach.png b/doc/img/approach.png index 0c72597..d603d6c 100644 Binary files a/doc/img/approach.png and b/doc/img/approach.png differ diff --git a/doc/img/bus.png b/doc/img/bus.png index 4f698fd..72e7680 100644 Binary files a/doc/img/bus.png and b/doc/img/bus.png differ diff --git a/doc/img/cars-alight.png b/doc/img/cars-alight.png index 36504cf..d5a7158 100644 Binary files a/doc/img/cars-alight.png and b/doc/img/cars-alight.png differ diff --git a/doc/img/cars.png b/doc/img/cars.png index 436ecc5..69b03d9 100644 Binary files a/doc/img/cars.png and b/doc/img/cars.png differ diff --git a/doc/img/crowd.png b/doc/img/crowd.png index 179beeb..6224790 100644 Binary files a/doc/img/crowd.png and b/doc/img/crowd.png differ diff --git a/doc/img/ending-summary.png b/doc/img/ending-summary.png index 687ac62..104873e 100644 Binary files a/doc/img/ending-summary.png and b/doc/img/ending-summary.png differ diff --git a/doc/img/endless.png b/doc/img/endless.png index d74a737..30a40a1 100644 Binary files a/doc/img/endless.png and b/doc/img/endless.png differ diff --git a/doc/img/floors-1f.png b/doc/img/floors-1f.png index 9cb7291..e721a0e 100644 Binary files a/doc/img/floors-1f.png and b/doc/img/floors-1f.png differ diff --git a/doc/img/floors-b1.png b/doc/img/floors-b1.png index 4604ddc..6a75da5 100644 Binary files a/doc/img/floors-b1.png and b/doc/img/floors-b1.png differ diff --git a/doc/img/level-001.png b/doc/img/level-001.png index 23aad12..bf71567 100644 Binary files a/doc/img/level-001.png and b/doc/img/level-001.png differ diff --git a/doc/img/level-002.png b/doc/img/level-002.png index d543ae3..6c81fd7 100644 Binary files a/doc/img/level-002.png and b/doc/img/level-002.png differ diff --git a/doc/img/map-en.png b/doc/img/map-en.png new file mode 100644 index 0000000..b6004d0 Binary files /dev/null and b/doc/img/map-en.png differ diff --git a/doc/img/map-signs.png b/doc/img/map-signs.png index 42ac1be..d9664cf 100644 Binary files a/doc/img/map-signs.png and b/doc/img/map-signs.png differ diff --git a/doc/img/map.png b/doc/img/map.png index 58b0f38..48a1dce 100644 Binary files a/doc/img/map.png and b/doc/img/map.png differ diff --git a/doc/img/nav-list.png b/doc/img/nav-list.png index 8d52e3e..cb85519 100644 Binary files a/doc/img/nav-list.png and b/doc/img/nav-list.png differ diff --git a/doc/img/no-exit.png b/doc/img/no-exit.png index bc7c2c8..f9f8fae 100644 Binary files a/doc/img/no-exit.png and b/doc/img/no-exit.png differ diff --git a/doc/img/pause.png b/doc/img/pause.png index 3f8e45f..3f286a2 100644 Binary files a/doc/img/pause.png and b/doc/img/pause.png differ diff --git a/doc/img/payer.png b/doc/img/payer.png index 2b8eca2..d8182f7 100644 Binary files a/doc/img/payer.png and b/doc/img/payer.png differ diff --git a/doc/img/platform.png b/doc/img/platform.png index 99b9e8c..b40b7f4 100644 Binary files a/doc/img/platform.png and b/doc/img/platform.png differ diff --git a/doc/img/result.png b/doc/img/result.png index 975f3d0..9fe9216 100644 Binary files a/doc/img/result.png and b/doc/img/result.png differ diff --git a/doc/img/ride-real.png b/doc/img/ride-real.png index 3634f33..ba42f80 100644 Binary files a/doc/img/ride-real.png and b/doc/img/ride-real.png differ diff --git a/doc/img/ride.png b/doc/img/ride.png index fbafe98..cd15f43 100644 Binary files a/doc/img/ride.png and b/doc/img/ride.png differ diff --git a/doc/img/seats.png b/doc/img/seats.png index c5a8577..3eee79e 100644 Binary files a/doc/img/seats.png and b/doc/img/seats.png differ diff --git a/doc/img/shop.png b/doc/img/shop.png index 87171a9..2ed6141 100644 Binary files a/doc/img/shop.png and b/doc/img/shop.png differ diff --git a/doc/img/sign-en.png b/doc/img/sign-en.png new file mode 100644 index 0000000..e084bcf Binary files /dev/null and b/doc/img/sign-en.png differ diff --git a/doc/img/sign-help.png b/doc/img/sign-help.png index 113c3de..1e12dbe 100644 Binary files a/doc/img/sign-help.png and b/doc/img/sign-help.png differ diff --git a/doc/img/sign-learned.png b/doc/img/sign-learned.png index c6ecf36..535cfb4 100644 Binary files a/doc/img/sign-learned.png and b/doc/img/sign-learned.png differ diff --git a/doc/img/sign.png b/doc/img/sign.png index f4218a7..4d64c84 100644 Binary files a/doc/img/sign.png and b/doc/img/sign.png differ diff --git a/doc/img/staff.png b/doc/img/staff.png index c6950dd..21f4018 100644 Binary files a/doc/img/staff.png and b/doc/img/staff.png differ diff --git a/doc/img/terminal.png b/doc/img/terminal.png index 0b5b0e6..390e31e 100644 Binary files a/doc/img/terminal.png and b/doc/img/terminal.png differ diff --git a/doc/img/ticket.png b/doc/img/ticket.png index 223c34c..940aa2f 100644 Binary files a/doc/img/ticket.png and b/doc/img/ticket.png differ diff --git a/doc/img/tips-sign.png b/doc/img/tips-sign.png index d1de1bd..50da8b7 100644 Binary files a/doc/img/tips-sign.png and b/doc/img/tips-sign.png differ diff --git a/doc/img/tips.png b/doc/img/tips.png index 9b7d4cb..2319581 100644 Binary files a/doc/img/tips.png and b/doc/img/tips.png differ diff --git a/doc/img/title.png b/doc/img/title.png index 80cb06c..d57dab7 100644 Binary files a/doc/img/title.png and b/doc/img/title.png differ diff --git a/doc/img/too-far.png b/doc/img/too-far.png index e0be13a..d72ba0e 100644 Binary files a/doc/img/too-far.png and b/doc/img/too-far.png differ diff --git a/doc/img/topup.png b/doc/img/topup.png index 18f0bfb..7f3b4f7 100644 Binary files a/doc/img/topup.png and b/doc/img/topup.png differ diff --git a/doc/img/transfer.png b/doc/img/transfer.png index 209f872..daefb02 100644 Binary files a/doc/img/transfer.png and b/doc/img/transfer.png differ diff --git a/doc/img/words.png b/doc/img/words.png index f1a1468..1052bd9 100644 Binary files a/doc/img/words.png and b/doc/img/words.png differ diff --git a/doc/mal-och-tester.md b/doc/mal-och-tester.md index 10fd222..caedcfe 100644 --- a/doc/mal-och-tester.md +++ b/doc/mal-och-tester.md @@ -139,6 +139,7 @@ att bygga på Linux som på Windows. | `internal/endless` | `TestPlanIsDeterministicAndValid`, `TestDestinationsNeedTrapAndRoute` | **M11:** samma seed → samma följd, annan seed → annan; varje mål har 1–4 rätta tåg och en fälla, nytt resmål, inga byten, aldrig samma station två gånger i rad; sällskapet växer och tidsgränsen krymper | | `internal/progress` | `TestNewGamePlusKeepsSkillsResetsItems` | **M11:** NG+ behåller skills, XP, skillpoäng och klarad story; nollställer items, utrustning och banresultat | | `internal/save` | `TestEndlessRecords` | **M11:** poänglistan sorterad, kapad till fem, "ny bästa" bara när toppen slås | +| `internal/game` | `TestSingleLineTextsFit`, `TestLevelNamesFitHUD` | **Textbredd (Björn 2026-10-25):** alla texter som ritas på en rad mäts med den riktiga fonten på svenska och engelska mot sitt utrymme (skärm, panel, pausmeny, inställningsrad, bankartans sammansatta rader); bannamn + resmål + mätare ryms på HUD:ens första rad för alla banor. `TestReportTextWidths -v` listar allt över skärmbredden | | `internal/game` | `TestHighlightDestination` | **M13:** resmålets tecken får markeringsfärg, resten nedtonas, flera träffar, ingen träff | | `internal/game` | `TestAllSoundsDecode`, `TestMelodyForIsStableAndKnown` | **M12:** alla ljud i `AllSounds` finns, avkodas och är minst 50 ms; melodin per bana är stabil och känd; ljudlagret är nil-säkert | | `internal/save` | `TestSettingsDefaultsAndNormalize` | **M12:** standardinställningar, klampning av volymer/skala, okänt språk blir sv, saknade inställningar fylls i | @@ -181,6 +182,7 @@ att bygga på Linux som på Windows. En milstolpe är klar när: 1. Alla tester i raden ovan finns och är gröna. +1. Ingen text går utanför skärmen på svenska eller engelska – nya enradstexter läggs till i `TestSingleLineTextsFit`, och långa texter radbryts med `wrapLine`. 2. `go vet ./...` och `go test -race ./...` är gröna. 3. Debug- och release-bygget går igenom för Linux och Windows. 4. Roadmapen är uppdaterad med datum och eventuella avsteg. diff --git a/internal/game/scene_level.go b/internal/game/scene_level.go index 465f528..91f7169 100644 --- a/internal/game/scene_level.go +++ b/internal/game/scene_level.go @@ -416,13 +416,6 @@ func (s *LevelScene) drawHUD(g *Game, screen *ebiten.Image) { a := g.Assets vector.DrawFilledRect(screen, 0, 0, ScreenW, 24, color.RGBA{24, 20, 37, 200}, false) - dest := r.FinalDestination().Get("romaji") - if !r.IsLastLeg() { // resa med byte: den här delbanan slutar vid bytesstationen - dest += " " + a.T("hud.via") + " " + r.Level.Destination.Get("romaji") - } - if r.Know.ShowsDestinationJP() { // hint från nivå 1: delbanans mål på japanska, att matcha mot skyltarna - dest += " " + r.Level.Destination.Get("ja") - } name := r.Level.Name.Get(UILang) if r.Level.NumFloors() > 1 { name += " " + r.Level.FloorName(r.Player.Tile.Z) @@ -433,39 +426,72 @@ func (s *LevelScene) drawHUD(g *Game, screen *ebiten.Image) { if s.endless && g.Endless != nil { name = fmt.Sprintf("#%d %s", g.Endless.Step+1, name) } + metersX := ScreenW - 4 - len(r.Party.Members)*(meterW+meterGap) + name = a.fitText(name, metersX/2) a.Draw(screen, name, 4, 0, colText) destX := 4 + a.Width(name) + 12 - a.Draw(screen, a.T("hud.destination")+": "+dest, destX, 0, colKnown) - // Japanska-nivån får plats till vänster om mätarna; annars kortas den. - jpX := destX + a.Width(a.T("hud.destination")+": "+dest) + 12 - metersX := ScreenW - 4 - len(r.Party.Members)*(meterW+meterGap) - jp := fmt.Sprintf("%s Lv%d·%d", a.T("hud.japanese"), r.Know.Level(), r.Know.Count()) - if jpX+a.Width(jp) > metersX-4 { - jp = fmt.Sprintf("Lv%d", r.Know.Level()) + // Resmålet: slutmålet, "via" bytesstationen och japanska hinten – i den + // ordningen stryks delar som inte får plats före mätarna. + final := r.FinalDestination().Get("romaji") + via, jp := "", "" + if !r.IsLastLeg() { // resa med byte: den här delbanan slutar vid bytesstationen + via = " " + a.T("hud.via") + " " + r.Level.Destination.Get("romaji") } - if jpX+a.Width(jp) <= metersX-4 { - a.Draw(screen, jp, jpX, 0, colDim) + if r.Know.ShowsDestinationJP() { // hint från nivå 1: delbanans mål på japanska, att matcha mot skyltarna + jp = " " + r.Level.Destination.Get("ja") + } + label := a.T("hud.destination") + ": " + dest := label + final + via + jp + for _, cand := range []string{label + final + via + jp, label + final + via, label + final + jp, label + final} { + dest = cand + if destX+a.Width(cand) <= metersX-4 { + break + } + } + dest = a.fitText(dest, metersX-4-destX) + a.Draw(screen, dest, destX, 0, colKnown) + // Japanska-nivån får plats till vänster om mätarna; annars kortas den. + jpX := destX + a.Width(dest) + 12 + lv := fmt.Sprintf("%s Lv%d·%d", a.T("hud.japanese"), r.Know.Level(), r.Know.Count()) + if jpX+a.Width(lv) > metersX-4 { + lv = fmt.Sprintf("Lv%d", r.Know.Level()) + } + if jpX+a.Width(lv) <= metersX-4 { + a.Draw(screen, lv, jpX, 0, colDim) } timeStr := fmt.Sprintf("%s %3.0fs", a.T("hud.time"), r.Time) if r.TimeLimit() > 0 { left := r.TimeLeft() timeStr = fmt.Sprintf("%s %d:%02d", a.T("hud.time_left"), int(left)/60, int(left)%60) } - wallet := fmt.Sprintf("%s %s %d¥ %s %d¥", timeStr, a.T("hud.card"), r.Wallet.Card, a.T("hud.cash_short"), r.Wallet.Cash) + // Plånboksraden: tid, kort, kontanter, sedan valfria delar (missade tåg, + // biljett, telefon) som stryks bakifrån om de inte får plats före mätarna. + must := fmt.Sprintf("%s %s %d¥ %s %d¥", timeStr, a.T("hud.card"), r.Wallet.Card, a.T("hud.cash_short"), r.Wallet.Cash) + var optional []string if r.MaxMissed() > 0 { - wallet += fmt.Sprintf(" %s %d/%d", a.T("hud.missed_short"), r.MissedTrains, r.MaxMissed()) - } - if r.Wallet.Phone { - wallet += fmt.Sprintf(" %s %.0f%%", a.T("hud.phone"), r.Wallet.Battery) + optional = append(optional, fmt.Sprintf("%s %d/%d", a.T("hud.missed_short"), r.MissedTrains, r.MaxMissed())) } if r.Wallet.Ticket != "" { - wallet += " " + a.T("hud.ticket") + " " + r.Wallet.Ticket + optional = append(optional, a.T("hud.ticket")+" "+r.Wallet.Ticket) + } + if r.Wallet.Phone { + optional = append(optional, fmt.Sprintf("%s %.0f%%", a.T("hud.phone"), r.Wallet.Battery)) + } + wallet := must + for n := len(optional); n >= 0; n-- { + wallet = must + for _, o := range optional[:n] { + wallet += " " + o + } + if 4+a.Width(wallet) <= metersX-4 { + break + } } walletCol := colDim if r.TimeLimit() > 0 && r.TimeLeft() < 30 { walletCol = colBad } - a.Draw(screen, wallet, 4, LineH, walletCol) + a.Draw(screen, a.fitText(wallet, metersX-8), 4, LineH, walletCol) s.drawMeters(g, screen) if r.Outcome != sim.Ongoing || r.Mini != nil || s.shop != nil { @@ -634,9 +660,9 @@ func (s *LevelScene) infoLines(a *Assets) (lines []line, accent color.Color, bar case r.NoExitAt >= 0 && r.Time-r.NoExitAt < deniedShowSec: return a.wrapLine(plainLine(fmt.Sprintf(a.T("hud.no_exit"), sim.StaffSec), colBad), maxW), colBad, false case r.NeedsStaff(): - return []line{plainLine(fmt.Sprintf(a.T("hud.staff_prompt"), sim.StaffSec), colWarn)}, colWarn, false + return a.wrapLine(plainLine(fmt.Sprintf(a.T("hud.staff_prompt"), sim.StaffSec), colWarn), maxW), colWarn, false case lvl.OneWayGates && r.StaffUnlocked: - return []line{plainLine(a.T("hud.unlocked_prompt"), colGood)}, colGood, false + return a.wrapLine(plainLine(a.T("hud.unlocked_prompt"), colGood), maxW), colGood, false } case level.Toilet: if r.Facility.Active { diff --git a/internal/game/scene_map.go b/internal/game/scene_map.go index b89ece8..76cb741 100644 --- a/internal/game/scene_map.go +++ b/internal/game/scene_map.go @@ -9,7 +9,6 @@ import ( "github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2/vector" - "gitea.brasse-pc.eu/brasse/metro-puzzle-jp/internal/buildinfo" "gitea.brasse-pc.eu/brasse/metro-puzzle-jp/internal/level" ) @@ -266,7 +265,7 @@ func (m *MapScene) Draw(g *Game, screen *ebiten.Image) { a.Draw(screen, a.T("hud.debuffs")+": "+strings.Join(parts, ", "), 8, y, colBad) } a.Draw(screen, a.T("map.hint"), 8, ScreenH-24, colDim) - a.Draw(screen, fmt.Sprintf("%s (%s)", buildinfo.Version, buildinfo.Mode), 8, ScreenH-12, colDim) + a.Draw(screen, a.T("map.hint2"), 8, ScreenH-12, colDim) // versionen står på titelskärmen } // drawLine ritar en tjock linje mellan två punkter. diff --git a/internal/game/scene_result.go b/internal/game/scene_result.go index f978b3e..d291393 100644 --- a/internal/game/scene_result.go +++ b/internal/game/scene_result.go @@ -123,8 +123,10 @@ func (r *ResultScene) Draw(g *Game, screen *ebiten.Image) { if len(run.LearnedDest) > 0 { msg += " " + a.T("hud.learned") + ": " + strings.Join(run.LearnedDest, " ") + " (" + a.T("result.destination") + ")" } - a.Draw(screen, msg, 28, y, colKnown) - y += LineH + for _, l := range a.wrapLine(plainLine(msg, colKnown), ScreenW-56) { + a.drawLines(screen, []line{l}, 28, y) + y += LineH + } } if o := r.from.outcome; run.Outcome == sim.Won { prog := fmt.Sprintf("+%d %s", o.XP, a.T("map.xp")) diff --git a/internal/game/scene_title.go b/internal/game/scene_title.go index 3339b50..b934c86 100644 --- a/internal/game/scene_title.go +++ b/internal/game/scene_title.go @@ -94,7 +94,7 @@ func (s *TitleScene) Draw(g *Game, screen *ebiten.Image) { y += LineH } if s.confirm { - a.Draw(screen, a.T("title.quit_confirm"), 150, y-LineH, colWarn) + a.Draw(screen, a.T("title.quit_confirm"), 16, y+2, colWarn) } a.Draw(screen, a.T("title.hint"), 8, ScreenH-12, colDim) } diff --git a/internal/game/text.go b/internal/game/text.go index ecabef9..5e64788 100644 --- a/internal/game/text.go +++ b/internal/game/text.go @@ -136,6 +136,21 @@ func (a *Assets) drawLines(dst drawTarget, lines []line, x, y int) { } } +// fitText kortar en text med ".." tills den ryms i maxW pixlar. +func (a *Assets) fitText(s string, maxW int) string { + if a.Width(s) <= maxW { + return s + } + r := []rune(s) + for len(r) > 0 { + r = r[:len(r)-1] + if a.Width(string(r)+"..") <= maxW { + return string(r) + ".." + } + } + return "" +} + // highlightLine är tutorialens sätt att läsa en skylt: resmålets japanska // tecken i markeringsfärg, allt annat nedtonat. func highlightLine(text, needle string, hi, dim color.Color) line { diff --git a/internal/game/textwidth_test.go b/internal/game/textwidth_test.go new file mode 100644 index 0000000..beb3893 --- /dev/null +++ b/internal/game/textwidth_test.go @@ -0,0 +1,156 @@ +package game + +import ( + "fmt" + "path/filepath" + "sort" + "strings" + "testing" + + "github.com/hajimehoshi/ebiten/v2/text/v2" + + "gitea.brasse-pc.eu/brasse/metro-puzzle-jp/internal/level" + "gitea.brasse-pc.eu/brasse/metro-puzzle-jp/internal/res" +) + +// loadTexts läser ett språks UI-texter. +func loadTexts(t *testing.T, lang string) map[string]string { + t.Helper() + m := map[string]string{} + if err := res.LoadJSON(&m, "text", lang+".json"); err != nil { + t.Fatal(err) + } + return m +} + +func uiFace(t *testing.T) *text.GoTextFace { + t.Helper() + face, err := loadFont("PixelMplus10-Regular.ttf", 10) + if err != nil { + t.Fatal(err) + } + return face +} + +// TestSingleLineTextsFit: texter som ritas på en rad utan radbrytning ska +// rymmas i sitt utrymme på båda språken. Bredderna mäts med den riktiga +// fonten. Texter som radbryts vid visning (tutorial, tips, premiss …) ingår +// inte. +func TestSingleLineTextsFit(t *testing.T) { + face := uiFace(t) + width := func(s string) int { return int(text.Advance(s, face)) } + const ( + full = ScreenW - 16 // en rad över hela skärmen med marginal + panel = ScreenW - 24 - 16 // minispelspanelens innerbredd + resW = ScreenW - 56 // resultatpanelen + pause = ScreenW - 96 // pausmenyn + ) + type check struct { + key string + max int + args []any + } + checks := []check{ + {"map.hint", full, nil}, {"map.hint2", full, nil}, {"menu.hint", full, nil}, {"settings.hint", full, nil}, + {"title.hint", full, nil}, {"tutorial.hint", full, nil}, {"ending.hint", full, nil}, + {"result.hint", resW, nil}, {"result.hint_endless", resW, nil}, {"result.hint_endless_over", resW, nil}, + {"pause.hint", pause, nil}, {"pause.quit_confirm", pause, nil}, {"pause.resume", pause, nil}, {"pause.leave", pause, nil}, {"pause.quit", pause, nil}, + {"title.quit_confirm", ScreenW - 32, nil}, {"title.tutorial", 110, nil}, {"menu.settings", 110, nil}, {"menu.quit", 110, nil}, {"menu.continue", 110, nil}, {"menu.start", 110, nil}, + {"items.hint", full, nil}, {"skills.hint", full, nil}, {"words.hint", full, nil}, {"shop.hint", panel, nil}, + {"mini.car.hint", panel, nil}, {"mini.car.pick", panel, nil}, {"mini.car.alighting", panel, nil}, {"mini.car.men", panel, nil}, + {"mini.crowd.title", panel - 60, nil}, {"mini.crowd.hint", panel, []any{2}}, + {"mini.ride.title", panel - 60, nil}, {"mini.ride.hint", panel, nil}, {"mini.ride.let_pass", panel, nil}, + {"mini.ticket.title", panel - 60, nil}, {"mini.ticket.hint", panel, []any{"Narita Airport", 5000}}, + {"mini.seat.hint", panel, []any{"Ville"}}, {"mini.seat.prefs", panel, nil}, + {"mini.topup.title", panel - 60, nil}, {"mini.topup.feed", panel, []any{5000}}, {"mini.topup.pick", panel, nil}, {"mini.topup.amount", panel, nil}, {"mini.topup.member", panel, nil}, {"mini.topup.wrong", panel - 60, nil}, + {"mini.payer.title", panel - 60, nil}, {"mini.payer.price", panel, []any{900}}, {"mini.payer.short", panel, nil}, {"mini.payer.hint", panel, nil}, + {"hud.kiosk_prompt", full - 60, []any{4, 800}}, {"hud.toilet_prompt", full, []any{4, 32.0}}, {"hud.machine_topup", full, []any{100000, 100000}}, {"hud.machine_ticket", full, []any{100000}}, + {"hud.help_prompt", full, []any{30.0}}, {"hud.train_near", full, nil}, {"hud.staff_busy", full, nil}, {"hud.toilet_busy", full, nil}, {"hud.kiosk_none", full - 60, nil}, {"hud.toilet_none", full, nil}, + {"settings.master", 118, nil}, {"settings.effects", 118, nil}, {"settings.music", 118, nil}, {"settings.lang", 118, nil}, {"settings.scale", 118, nil}, {"settings.fullscreen", 118, nil}, + {"settings.scale_auto", ScreenW - 130 - 8, nil}, + {"ending.summary", full, nil}, {"ending.story_done", full * 2, nil}, + } + for _, lang := range []string{"sv", "en"} { + m := loadTexts(t, lang) + for _, c := range checks { + s, ok := m[c.key] + if !ok { + t.Errorf("%s: nyckeln %s saknas", lang, c.key) + continue + } + if len(c.args) > 0 { + s = fmt.Sprintf(s, c.args...) + } + if w := width(s); w > c.max { + t.Errorf("%s %s är %d px, får vara %d: %q", lang, c.key, w, c.max, s) + } + } + // Bankartans sammansatta rader. + line2 := fmt.Sprintf(m["menu.phone"], m["menu.on"]) + " " + fmt.Sprintf(m["menu.mode"], m["mode.signs"]) + if w := width(line2); w > full { + t.Errorf("%s bankartans lägesrad är %d px: %q", lang, w, line2) + } + endless := m["map.endless"] + " (" + fmt.Sprintf(m["map.endless_best"], 99999, 99) + ") " + m["map.ngplus"] + " (" + fmt.Sprintf(m["map.ngplus_level"], 9) + ")" + if w := width(endless); w > full { + t.Errorf("%s bankartans oändligt-rad är %d px: %q", lang, w, endless) + } + } +} + +// TestLevelNamesFitHUD: bannamnet, resmålet och mätarna ska rymmas på +// HUD:ens första rad även med fullt sällskap och byte, på båda språken. +func TestLevelNamesFitHUD(t *testing.T) { + face := uiFace(t) + width := func(s string) int { return int(text.Advance(s, face)) } + dir, err := res.Path("data", "levels") + if err != nil { + t.Fatal(err) + } + all, err := level.LoadAll(dir) + if err != nil { + t.Fatal(err) + } + for _, lang := range []string{"sv", "en"} { + m := loadTexts(t, lang) + for _, l := range all { + name := l.Name.Get(lang) + if l.NumFloors() > 1 { + name += " " + l.FloorName(0) + } + chain := level.ChainOf(all, l.ID) + if len(chain) > 1 { + name += " 1/2" + } + dest := m["hud.destination"] + ": " + level.FinalOf(all, l).Destination.Get("romaji") + if len(chain) > 1 { + dest += " " + m["hud.via"] + " " + l.Destination.Get("romaji") + } + metersX := ScreenW - 4 - max(1, l.Party)*(meterW+meterGap) + if w := 4 + width(name) + 12 + width(dest); w > metersX-4 { + t.Errorf("%s %s: HUD-raden %q + %q är %d px, mätarna börjar vid %d", lang, l.ID, name, dest, w, metersX) + } + } + } +} + +// TestReportTextWidths skriver (med -v) ut alla texter bredare än skärmen, +// som hjälp vid textgranskning. Fäller inget: de flesta radbryts vid visning. +func TestReportTextWidths(t *testing.T) { + face := uiFace(t) + for _, lang := range []string{"sv", "en"} { + m := loadTexts(t, lang) + var keys []string + for k := range m { + keys = append(keys, k) + } + sort.Strings(keys) + for _, k := range keys { + for _, line := range strings.Split(m[k], "\n") { + if w := int(text.Advance(line, face)); w > ScreenW-16 { + t.Logf("WIDE %s %-28s %4d px %q", lang, k, w, line) + } + } + } + } + _ = filepath.Base +} diff --git a/resources/data/levels/001b-flygbussen.json b/resources/data/levels/001b-flygbussen.json index f28152d..4de1342 100644 --- a/resources/data/levels/001b-flygbussen.json +++ b/resources/data/levels/001b-flygbussen.json @@ -33,9 +33,9 @@ "id": "001b-flygbussen", "kind": "side", "name": { - "en": "Airport bus terminal", + "en": "Airport buses", "ja": "空港バスのりば", - "sv": "Flygbussterminalen" + "sv": "Flygbussarna" }, "order": 1, "parent": "001-flygplatsen", @@ -57,9 +57,9 @@ }, { "text": { - "en": "\u003c- Stop 2 limousine bus for Yokohama Stop 1 limousine bus for Shinjuku -\u003e", + "en": "<- Stop 2 limousine bus for Yokohama Stop 1 limousine bus for Shinjuku ->", "ja": "← 2番 リムジンバス 横浜方面 1番 リムジンバス 新宿方面 →", - "sv": "\u003c- Hållplats 2 flygbuss mot Yokohama Hållplats 1 flygbuss mot Shinjuku -\u003e" + "sv": "<- Hållplats 2 flygbuss mot Yokohama Hållplats 1 flygbuss mot Shinjuku ->" }, "x": 3, "y": 3, @@ -151,4 +151,4 @@ "vehicle": "bus" } ] -} \ No newline at end of file +} diff --git a/resources/data/levels/002-shinjuku.json b/resources/data/levels/002-shinjuku.json index 86fd3c7..8cb9a85 100644 --- a/resources/data/levels/002-shinjuku.json +++ b/resources/data/levels/002-shinjuku.json @@ -34,9 +34,9 @@ "kind": "main", "maxMissedTrains": 2, "name": { - "en": "Shinjuku Station", + "en": "Shinjuku", "ja": "新宿駅", - "sv": "Shinjuku station" + "sv": "Shinjuku" }, "order": 2, "party": 3, @@ -62,9 +62,9 @@ }, { "text": { - "en": "\u003c- Track 8 Chuo Line (Tokyo) Track 14 Yamanote Line (Shibuya) -\u003e", + "en": "<- Track 8 Chuo Line (Tokyo) Track 14 Yamanote Line (Shibuya) ->", "ja": "← 8番線 中央線 東京方面 14番線 山手線 渋谷方面 →", - "sv": "\u003c- Spår 8 Chuo-linjen (Tokyo) Spår 14 Yamanote-linjen (Shibuya) -\u003e" + "sv": "<- Spår 8 Chuo-linjen (Tokyo) Spår 14 Yamanote-linjen (Shibuya) ->" }, "x": 11, "y": 15, @@ -130,4 +130,4 @@ "track": "8" } ] -} \ No newline at end of file +} diff --git a/resources/data/levels/003-shibuya.json b/resources/data/levels/003-shibuya.json index bedd0c2..12ee97f 100644 --- a/resources/data/levels/003-shibuya.json +++ b/resources/data/levels/003-shibuya.json @@ -3,9 +3,9 @@ "kind": "main", "order": 3, "name": { - "en": "Shibuya Station", + "en": "Shibuya", "ja": "渋谷駅", - "sv": "Shibuya station" + "sv": "Shibuya" }, "difficulty": 3, "party": 4, diff --git a/resources/data/levels/004-tokyo.json b/resources/data/levels/004-tokyo.json index d697fb0..f21b002 100644 --- a/resources/data/levels/004-tokyo.json +++ b/resources/data/levels/004-tokyo.json @@ -65,9 +65,9 @@ "kind": "main", "maxMissedTrains": 2, "name": { - "en": "Tokyo Station", + "en": "Tokyo", "ja": "東京駅", - "sv": "Tokyo station" + "sv": "Tokyo" }, "order": 4, "party": 3, @@ -92,9 +92,9 @@ }, { "text": { - "en": "\u003c- Track 7 Tokaido Line (Shinagawa) Track 4 Yamanote Line (Ueno) -\u003e", + "en": "<- Track 7 Tokaido Line (Shinagawa) Track 4 Yamanote Line (Ueno) ->", "ja": "← 7番線 東海道線 品川方面 4番線 山手線 上野方面 →", - "sv": "\u003c- Spår 7 Tokaido-linjen (Shinagawa) Spår 4 Yamanote-linjen (Ueno) -\u003e" + "sv": "<- Spår 7 Tokaido-linjen (Shinagawa) Spår 4 Yamanote-linjen (Ueno) ->" }, "x": 3, "y": 3, @@ -160,4 +160,4 @@ "track": "7" } ] -} \ No newline at end of file +} diff --git a/resources/data/levels/005-ueno.json b/resources/data/levels/005-ueno.json index cb2b7ab..bcb8a7c 100644 --- a/resources/data/levels/005-ueno.json +++ b/resources/data/levels/005-ueno.json @@ -36,9 +36,9 @@ "kind": "main", "maxMissedTrains": 2, "name": { - "en": "Ueno Station", + "en": "Ueno", "ja": "上野駅", - "sv": "Ueno station" + "sv": "Ueno" }, "noise": 2, "oneWayGates": true, diff --git a/resources/data/levels/006-ikebukuro.json b/resources/data/levels/006-ikebukuro.json index 1369ac5..63081a6 100644 --- a/resources/data/levels/006-ikebukuro.json +++ b/resources/data/levels/006-ikebukuro.json @@ -36,9 +36,9 @@ "kind": "main", "maxMissedTrains": 2, "name": { - "en": "Ikebukuro Station", + "en": "Ikebukuro", "ja": "池袋駅", - "sv": "Ikebukuro station" + "sv": "Ikebukuro" }, "noise": 1, "order": 6, @@ -62,9 +62,9 @@ }, { "text": { - "en": "\u003c- Track 2 Saikyo Line for Omiya Track 1 Saikyo Line for Osaki -\u003e", + "en": "<- Track 2 Saikyo Line for Omiya Track 1 Saikyo Line for Osaki ->", "ja": "← 2番線 埼京線 大宮方面 1番線 埼京線 大崎方面 →", - "sv": "\u003c- Spår 2 Saikyo-linjen mot Omiya Spår 1 Saikyo-linjen mot Osaki -\u003e" + "sv": "<- Spår 2 Saikyo-linjen mot Omiya Spår 1 Saikyo-linjen mot Osaki ->" }, "x": 17, "y": 9, @@ -174,4 +174,4 @@ "track": "11" } ] -} \ No newline at end of file +} diff --git a/resources/data/levels/007-akihabara.json b/resources/data/levels/007-akihabara.json index 1216455..07a388c 100644 --- a/resources/data/levels/007-akihabara.json +++ b/resources/data/levels/007-akihabara.json @@ -37,9 +37,9 @@ "kind": "main", "maxMissedTrains": 3, "name": { - "en": "Akihabara Station", + "en": "Akihabara", "ja": "秋葉原駅", - "sv": "Akihabara station" + "sv": "Akihabara" }, "next": "007b-ueno", "noise": 1, @@ -65,9 +65,9 @@ }, { "text": { - "en": "\u003c- Track 3 Hibiya Line for Naka-Meguro Track 4 Hibiya Line for Kita-Senju -\u003e", + "en": "<- Track 3 Hibiya Line for Naka-Meguro Track 4 Hibiya Line for Kita-Senju ->", "ja": "← 3番線 日比谷線 中目黒方面 4番線 日比谷線 北千住方面 →", - "sv": "\u003c- Spår 3 Hibiya-linjen mot Naka-Meguro Spår 4 Hibiya-linjen mot Kita-Senju -\u003e" + "sv": "<- Spår 3 Hibiya-linjen mot Naka-Meguro Spår 4 Hibiya-linjen mot Kita-Senju ->" }, "x": 9, "y": 11, @@ -177,4 +177,4 @@ "track": "1" } ] -} \ No newline at end of file +} diff --git a/resources/data/levels/007b-ueno.json b/resources/data/levels/007b-ueno.json index 5b98a97..aca77a5 100644 --- a/resources/data/levels/007b-ueno.json +++ b/resources/data/levels/007b-ueno.json @@ -11,23 +11,23 @@ "fareYen": 170, "grid": [ "#################################", - "#S.#.i\u003c..\u003c..\u003c..\u003c..\u003c..\u003c..\u003c..\u003c..###", - "#..#..\u003e..\u003e..\u003e..\u003e..\u003e..\u003e..\u003e..\u003e..###", - "#\u003c\u003e################\u003c\u003e#######\u003c\u003e###", - "#..#..\u003c..\u003c..\u003c..\u003c..#..#..\u003c..#..###", - "#..#..\u003e..\u003e..\u003e..\u003e..#..#..\u003e..#..###", - "#\u003c\u003e#\u003c\u003e##########\u003c\u003e#\u003c\u003e#\u003c\u003e####\u003c\u003e###", - "#..\u003c..#..\u003c..\u003c..#..#..#..\u003c..\u003c..###", - "#..\u003e..#..\u003e..\u003e..#..#..#..\u003e..\u003e..###", - "####\u003c\u003e#\u003c\u003e#\u003c\u003e#\u003c\u003e#\u003c\u003e#\u003c\u003e#\u003c\u003e#########", - "#..\u003c..\u003ci.\u003cT.#..#..#..\u003c..#..\u003c..###", - "#..\u003e..\u003e.K\u003e..#..#..#..\u003e..#..\u003e..###", - "#\u003c\u003e#\u003c\u003e#######\u003c\u003e#\u003c\u003e#\u003c\u003e#\u003c\u003e####\u003c\u003e###", - "#..#..\u003c..\u003c..#..#..\u003c.i#..\u003c..\u003c..###", - "#..#..\u003e..\u003e..#..#..\u003e..#..\u003e..\u003e..###", - "####\u003c\u003e####\u003c\u003e#\u003c\u003e#G\u003e##########\u003c\u003e###", - "#.G\u003cW.\u003c..\u003c..#..#.G#..\u003c..\u003c..\u003c.G###", - "#p.G..\u003e..\u003e..#..#Q.#..\u003e..\u003e..\u003eGP###", + "#S.#.i<..<..<..<..<..<..<..<..###", + "#..#..>..>..>..>..>..>..>..>..###", + "#<>################<>#######<>###", + "#..#..<..<..<..<..#..#..<..#..###", + "#..#..>..>..>..>..#..#..>..#..###", + "#<>#<>##########<>#<>#<>####<>###", + "#..<..#..<..<..#..#..#..<..<..###", + "#..>..#..>..>..#..#..#..>..>..###", + "####<>#<>#<>#<>#<>#<>#<>#########", + "#..<....>.K>..#..#..#..>..#..>..###", + "#<>#<>#######<>#<>#<>#<>####<>###", + "#..#..<..<..#..#..<.i#..<..<..###", + "#..#..>..>..#..#..>..#..>..>..###", + "####<>####<>#<>#G>##########<>###", + "#.G..>..#..#Q.#..>..>..>GP###", "##W##############################", "#################################", "#################################" @@ -36,9 +36,9 @@ "individualCards": true, "kind": "leg", "name": { - "en": "Ueno Station", + "en": "Ueno", "ja": "上野駅", - "sv": "Ueno station" + "sv": "Ueno" }, "noise": 2, "oneWayGates": true, @@ -57,9 +57,9 @@ }, { "text": { - "en": "\u003c- Track 2 Ginza Line for Shibuya Track 1 Ginza Line for Asakusa -\u003e", + "en": "<- Track 2 Ginza Line for Shibuya Track 1 Ginza Line for Asakusa ->", "ja": "← 2番線 銀座線 渋谷方面 1番線 銀座線 浅草方面 →", - "sv": "\u003c- Spår 2 Ginza-linjen mot Shibuya Spår 1 Ginza-linjen mot Asakusa -\u003e" + "sv": "<- Spår 2 Ginza-linjen mot Shibuya Spår 1 Ginza-linjen mot Asakusa ->" }, "x": 20, "y": 13, @@ -146,4 +146,4 @@ "track": "3" } ] -} \ No newline at end of file +} diff --git a/resources/data/levels/008-tokyo-hemresa.json b/resources/data/levels/008-tokyo-hemresa.json index e9147e3..a4cb025 100644 --- a/resources/data/levels/008-tokyo-hemresa.json +++ b/resources/data/levels/008-tokyo-hemresa.json @@ -68,9 +68,9 @@ "kind": "main", "maxMissedTrains": 3, "name": { - "en": "Tokyo Station, going home", + "en": "Tokyo", "ja": "東京駅", - "sv": "Tokyo station, hemresan" + "sv": "Tokyo" }, "next": "008b-nippori", "noise": 2, diff --git a/resources/data/levels/008b-nippori.json b/resources/data/levels/008b-nippori.json index b30fcb8..5ce81d3 100644 --- a/resources/data/levels/008b-nippori.json +++ b/resources/data/levels/008b-nippori.json @@ -36,9 +36,9 @@ "individualCards": true, "kind": "leg", "name": { - "en": "Nippori Station", + "en": "Nippori", "ja": "日暮里駅", - "sv": "Nippori station" + "sv": "Nippori" }, "noise": 1, "oneWayGates": true, @@ -58,9 +58,9 @@ }, { "text": { - "en": "\u003c- Track 2 Keisei Line for Keisei-Ueno Track 1 Keisei Line for Narita Airport -\u003e", + "en": "<- Track 2 Keisei Line for Keisei-Ueno Track 1 Keisei Line for Narita Airport ->", "ja": "← 2番線 京成本線 京成上野方面 1番線 京成本線 成田空港方面 →", - "sv": "\u003c- Spår 2 Keisei-linjen mot Keisei-Ueno Spår 1 Keisei-linjen mot Narita flygplats -\u003e" + "sv": "<- Spår 2 Keisei-linjen mot Keisei-Ueno Spår 1 Keisei-linjen mot Narita flygplats ->" }, "x": 1, "y": 17, @@ -148,4 +148,4 @@ "track": "11" } ] -} \ No newline at end of file +} diff --git a/resources/text/en.json b/resources/text/en.json index c26166e..f1de198 100644 --- a/resources/text/en.json +++ b/resources/text/en.json @@ -5,7 +5,7 @@ "menu.endless": "Endless mode", "menu.settings": "Settings", "menu.quit": "Quit", - "hud.destination": "Destination", + "hud.destination": "To", "hud.next_train": "Next train", "hud.card_balance": "Card balance", "meter.food": "Food", @@ -46,7 +46,7 @@ "hud.progress": "Progress", "words.title": "Word list 言葉", "words.points": "Points", - "words.hint": "Arrows: select Enter: learn the word for points Esc/L: back", + "words.hint": "Arrows: select Enter: learn for points Esc: back", "words.already": "You already know that word.", "words.bought": "New word: %s = %s", "words.too_expensive": "Costs %d points - clear levels with good times for more.", @@ -89,7 +89,7 @@ "mini.ticket.title": "Tickets", "mini.ticket.hint": "Buy a ticket to %s. Cash: %d¥", "mini.crowd.title": "Crowded train - squeeze in", - "mini.crowd.hint": "Press Enter when the marker is in the green zone (%d tries left)", + "mini.crowd.hint": "Enter when the marker is in the green zone (%d left)", "mini.ride.title": "On the train - next stop", "mini.ride.hint": "Enter: get off here (you are going to %s)", "hud.time_left": "Left", @@ -140,7 +140,7 @@ "map.party": "Party", "map.resume": "⟳ resume (saved seed)", "map.locked": "Locked - clear the previous level first.", - "map.hint": "Enter start N mode L words T skills I items P phone S set.", + "map.hint": "Enter: start level N: mode L: words T: skills", "skills.title": "Skills 技", "skills.to_next": "XP to next", "skills.already": "Already unlocked.", @@ -185,7 +185,7 @@ "mini.car.title": "Choose a car", "mini.car.alighting": "People are getting off - wait…", "mini.car.pick": "Pick a car with the arrows, board with Enter.", - "mini.car.men": "There is a man in the party - not the women-only car (pink)!", + "mini.car.men": "Man in the party - avoid the women-only car (pink)!", "mini.car.hint": "←/→: car Enter: board Esc: cancel", "car.crowd.low": "few people", "car.crowd.mid": "some people", @@ -225,7 +225,7 @@ "ending.hint": "Enter: continue Esc: level map", "ending.credits": "Metro Puzzle JP\n\nIdea and game design\nBjörn\n\nCode and pixels\nClaude (Anthropic)\n\nEngine\nEbitengine\n\nFont\nPixelMplus (M+ FONT LICENSE)\n\nThe trains, the signs and the chatter\nTokyo\n\nThanks for riding!\nまたね", "mini.payer.title": "Who pays?", - "mini.payer.price": "To pay: %d¥ (food and drink for everyone who needs it)", + "mini.payer.price": "To pay: %d¥ (for everyone who needs it)", "mini.payer.cash": "Cash", "mini.payer.card": "card", "mini.payer.short": "Not enough - pick someone else.", @@ -291,5 +291,6 @@ "tip.sign": "Tip: reading the sign - {ja} is the destination (highlighted), 番線 = track, 方面 = for. Press H to ask for help.", "tip.party": "Tip: someone in the party needs something. The kiosk (K) gives food and drink, the toilet (W) solves toilet needs.", "tip.gate": "Tip: the gate charges the fare from your card when you enter. Top up an empty card at the machine (T).", - "tip.platform": "Tip: wait for the train and press Enter when it is in. Let people off, pick a car with the arrows." + "tip.platform": "Tip: wait for the train and press Enter when it is in. Let people off, pick a car with the arrows.", + "map.hint2": "I: wardrobe P: phone S: settings Esc: title" } diff --git a/resources/text/sv.json b/resources/text/sv.json index db7e306..a9b739e 100644 --- a/resources/text/sv.json +++ b/resources/text/sv.json @@ -5,7 +5,7 @@ "menu.endless": "Oändligt läge", "menu.settings": "Inställningar", "menu.quit": "Avsluta", - "hud.destination": "Resmål", + "hud.destination": "Mål", "hud.next_train": "Nästa tåg", "hud.card_balance": "Kortsaldo", "meter.food": "Mat", @@ -46,7 +46,7 @@ "hud.progress": "Framsteg", "words.title": "Ordlista 言葉", "words.points": "Poäng", - "words.hint": "Pilar: välj Enter: lär dig ordet för poäng Esc/L: tillbaka", + "words.hint": "Pilar: välj Enter: lär ordet för poäng Esc: tillbaka", "words.already": "Det ordet kan du redan.", "words.bought": "Nytt ord: %s = %s", "words.too_expensive": "Kostar %d poäng - klara banor med bra tid för fler.", @@ -89,7 +89,7 @@ "mini.ticket.title": "Biljetter", "mini.ticket.hint": "Köp biljett till %s. Kontant: %d¥", "mini.crowd.title": "Fullt tåg - tränga sig på", - "mini.crowd.hint": "Tryck Enter när markören är i det gröna fältet (%d försök kvar)", + "mini.crowd.hint": "Enter när markören är i det gröna fältet (%d försök kvar)", "mini.ride.title": "På tåget - nästa station", "mini.ride.hint": "Enter: kliv av här (du ska till %s)", "hud.time_left": "Kvar", @@ -140,7 +140,7 @@ "map.party": "Sällskap", "map.resume": "⟳ fortsätt (sparad seed)", "map.locked": "Låst - klara föregående bana först.", - "map.hint": "Enter start N läge L ord T skills I items P tel S inst.", + "map.hint": "Enter: starta banan N: läge L: ordlista T: skills", "skills.title": "Skills 技", "skills.to_next": "XP till nästa", "skills.already": "Redan upplåst.", @@ -185,7 +185,7 @@ "mini.car.title": "Välj vagn", "mini.car.alighting": "Folk kliver av - vänta…", "mini.car.pick": "Välj vagn med pilarna, kliv på med Enter.", - "mini.car.men": "Det finns en man i sällskapet - inte kvinnovagnen (rosa)!", + "mini.car.men": "Man i sällskapet - undvik kvinnovagnen (rosa)!", "mini.car.hint": "←/→: vagn Enter: kliv på Esc: avbryt", "car.crowd.low": "lite folk", "car.crowd.mid": "en del folk", @@ -225,7 +225,7 @@ "ending.hint": "Enter: vidare Esc: bankartan", "ending.credits": "Metro Puzzle JP\n\nIdé och speldesign\nBjörn\n\nKod och pixlar\nClaude (Anthropic)\n\nMotor\nEbitengine\n\nTypsnitt\nPixelMplus (M+ FONT LICENSE)\n\nTågen, skyltarna och sorlet\nTokyo\n\nTack för resan!\nまたね", "mini.payer.title": "Vem betalar?", - "mini.payer.price": "Att betala: %d¥ (mat och dryck åt alla som behöver)", + "mini.payer.price": "Att betala: %d¥ (åt alla som behöver)", "mini.payer.cash": "Kontant", "mini.payer.card": "kort", "mini.payer.short": "Det räcker inte - välj någon annan.", @@ -243,7 +243,7 @@ "result.endless_won": "Mål %d klart! Totalt %d poäng.", "result.endless_lost": "Oändligt läge slut efter %d mål: %d poäng (bästa %d).", "result.endless_best": "Ny bästa!", - "result.hint_endless": "Enter: nästa mål L: ordlista Esc: avsluta omgången", + "result.hint_endless": "Enter: nästa mål L: ord Esc: avsluta", "result.hint_endless_over": "Enter/Esc: bankartan L: ordlista", "settings.title": "Inställningar", "settings.master": "Huvudvolym", @@ -266,7 +266,7 @@ "pause.leave": "Lämna banan (framsteg på banan försvinner)", "pause.quit": "Avsluta spelet", "pause.hint": "Esc: fortsätt Enter: välj", - "pause.quit_confirm": "Enter igen för att avsluta spelet, Esc avbryter.", + "pause.quit_confirm": "Enter igen avslutar spelet, Esc avbryter.", "tutorial.hint": "←/→ eller Enter: bläddra Esc: tillbaka", "tutorial.page": "sida %d/%d", "tutorial.p1.title": "Målet och stationen", @@ -291,5 +291,6 @@ "tip.sign": "Tips: så läser du skylten - {ja} är resmålet (markerat), 番線 = spår, 方面 = mot. Tryck H för att fråga om hjälp.", "tip.party": "Tips: någon i sällskapet behöver något. Kiosken (K) ger mat och dryck, toaletten (W) löser toabehov.", "tip.gate": "Tips: spärren drar avgiften från kortet när du går in. Tomt kort fylls på i automaten (T).", - "tip.platform": "Tips: vänta in tåget och tryck Enter när det står inne. Låt folk kliva av, välj vagn med pilarna." + "tip.platform": "Tips: vänta in tåget och tryck Enter när det står inne. Låt folk kliva av, välj vagn med pilarna.", + "map.hint2": "I: garderob P: telefon S: inställningar Esc: titel" } diff --git a/tools/shots/main.go b/tools/shots/main.go index ff4b9e4..6114480 100644 --- a/tools/shots/main.go +++ b/tools/shots/main.go @@ -26,6 +26,19 @@ import ( // demoSave skriver en sparfil med lite progression så att kartan, skills // och garderoben har något att visa. Används bara av skärmdumparna. +// demoSaveEN är samma demosparfil på engelska (för språkkontrollen). +func demoSaveEN(path string) error { + if err := demoSave(path); err != nil { + return err + } + st, _, err := save.Load(path) + if err != nil { + return err + } + st.Settings.Lang = "en" + return save.Store(path, st) +} + func demoSave(path string) error { st := save.New() st.Know.Learn("改札") @@ -55,7 +68,7 @@ type shot struct { // bilderna överlever ändringar i banorna. var shots []shot -var demo, fresh string +var demo, demoEN, fresh string func buildShots(levelsDir string) error { l, err := level.LoadFile(filepath.Join(levelsDir, "001-flygplatsen.json")) @@ -180,6 +193,8 @@ func buildShots(levelsDir string) error { {"", "wait 150; shot $OUT/ending.png; press enter; wait 5; shot $OUT/ending-summary.png; press enter; wait 250; shot $OUT/credits.png; quit", []string{"-ending", "-save", "$DEMO"}}, {"007-akihabara", toKiosk7 + "; urge Ville; press enter; wait 5; press right; wait 3; shot $OUT/payer.png; quit", []string{"-seed", "7"}}, {"", "wait 10; shot $OUT/endless.png; quit", []string{"-endless", "-seed", "7", "-mode", "list", "-save", "$DEMO"}}, + {"", "wait 5; press enter; wait 10; shot $OUT/map-en.png; quit", []string{"-save", "$DEMOEN"}}, + {"001-flygplatsen", toSign + "; wait 5; shot $OUT/sign-en.png; quit", []string{"-seed", "7", "-save", "$DEMOEN", "-know", "改札,番線,方面"}}, {"001b-flygbussen", toMachine1b + "; press enter; pick 新宿; press enter; wait 5; " + toStop1b + "; waittrain; wait 10; shot $OUT/bus.png; quit", []string{"-seed", "7", "-know", "新宿,方面"}}, {"", "wait 5; press enter; wait 10; press s; wait 5; press down; wait 3; shot $OUT/settings.png; quit", []string{"-save", "$DEMO"}}, {"", "wait 10; shot $OUT/lang.png; press enter; wait 30; shot $OUT/title.png; press down; press enter; wait 5; press right; wait 5; shot $OUT/tutorial.png; quit", []string{"-save", "$FRESH"}}, @@ -269,6 +284,8 @@ func main() { must(demoSave(demo)) fresh = filepath.Join(root, "build", "fresh-save.json") // finns inte: första starten (språkval, titel, tips) os.Remove(fresh) + demoEN = filepath.Join(root, "build", "demo-save-en.json") + must(demoSaveEN(demoEN)) must(buildShots(filepath.Join(root, "resources", "data", "levels"))) build := exec.Command("go", "run", "./tools/build", "-mode", "debug") @@ -297,7 +314,7 @@ func main() { args = append(args, "-level", s.level) } for _, a := range s.args { - args = append(args, strings.ReplaceAll(strings.ReplaceAll(a, "$DEMO", demo), "$FRESH", fresh)) + args = append(args, strings.NewReplacer("$DEMOEN", demoEN, "$DEMO", demo, "$FRESH", fresh).Replace(a)) } run := exec.Command(exe, args...) run.Dir, run.Stdout, run.Stderr = filepath.Dir(exe), os.Stdout, os.Stderr