M6: plånbok, biljetter, kortet i telefonen och seedade minispel
All checks were successful
release / build-release (push) Successful in 1m41s
All checks were successful
release / build-release (push) Successful in 1m41s
- sim.Wallet: IC-kort, kontanter, pappersbiljett, telefon med batteri, spenderat; följer med mellan banor (Game.Wallet) - internal/minigame: gemensamt Game-gränssnitt (Update/Done/Success), all slump från del-seeds: TopUp (hitta チャージ, belopp, mata sedlar), Ticket (taxetavla med resmål på japanska), Crowd (tidsfönster, två försök), Ride (stationerna passerar, kliv av vid resmålet) - sim.Run: spärren kräver biljett på biljettbanor annars användbart kort; telefonen ger ×1,1 fart men 15 % seedad omskanning (frysning 1,5 s), dött batteri gör kortet oanvändbart; automaten startar påfyllning eller biljettköp; tåget kontrollerar biljetten; fulla tåg kräver trängsel; resan avgör vinst/förlust (fel station, åkte förbi, fel tåg); StepMini låter klockan och sällskapet ticka medan rörelsen pausar - level: ticketRequired, rideStops, Train.Crowded; 002 är biljettbana med fullt tåg och fyra stopp; ordboken har stationer (kind) + sju nya namn - game: vyer för minispelen, plånbok i HUD, P i menyn = kort i telefonen, förlustorsaker och spenderat på resultatet, flaggor -phone/-card, skriptkommandon hold/waitstop; inforuta/minikarta döljs under minispel - plan: M7b (Björn) – tågvind, ankomstindikator nära rälsen, in-/utkörningsanimation för tåg och bussar – i spelbeskrivning, roadmap, testplan - docs/README/wiki med tre nya bilder (automat, biljettavla, tågresa) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -13,6 +13,7 @@ import (
|
||||
|
||||
"gitea.brasse-pc.eu/brasse/metro-puzzle-jp/internal/lang"
|
||||
"gitea.brasse-pc.eu/brasse/metro-puzzle-jp/internal/level"
|
||||
"gitea.brasse-pc.eu/brasse/metro-puzzle-jp/internal/minigame"
|
||||
"gitea.brasse-pc.eu/brasse/metro-puzzle-jp/internal/rng"
|
||||
"gitea.brasse-pc.eu/brasse/metro-puzzle-jp/internal/sim"
|
||||
)
|
||||
@@ -22,6 +23,7 @@ const (
|
||||
deniedShowSec = 2.0
|
||||
learnedShowSec = 3.0
|
||||
progressedShowSec = 2.5
|
||||
flashShowSec = 2.5
|
||||
)
|
||||
|
||||
// LevelScene är själva spelandet av en bana. All spellogik ligger i sim.Run;
|
||||
@@ -36,14 +38,14 @@ type LevelScene struct {
|
||||
|
||||
// NewLevelScene laddar banan och ställer spelaren på startrutan. know är
|
||||
// spelarens japanska, som delas mellan banor; seed styr omgångens slump.
|
||||
func NewLevelScene(a *Assets, id string, know *lang.Knowledge, seed rng.Seed) (*LevelScene, error) {
|
||||
func NewLevelScene(a *Assets, id string, know *lang.Knowledge, wallet *sim.Wallet, seed rng.Seed) (*LevelScene, error) {
|
||||
lvl, err := level.LoadFile(filepath.Join(a.LevelsDir, id+".json"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s := &LevelScene{
|
||||
id: id,
|
||||
run: sim.NewRun(lvl, sim.RunOptions{Dict: a.Dict, Know: know, Seed: seed}),
|
||||
run: sim.NewRun(lvl, sim.RunOptions{Dict: a.Dict, Know: know, Wallet: wallet, Seed: seed}),
|
||||
cam: sim.NewCamera(ScreenW, ScreenH, float64(lvl.Width()*TileSize), float64(lvl.Height()*TileSize)),
|
||||
}
|
||||
s.followPlayer()
|
||||
@@ -62,12 +64,27 @@ func (s *LevelScene) TrainHere() bool {
|
||||
return tr != nil && at
|
||||
}
|
||||
|
||||
// RideAtDest rapporterar om tågresan står vid resmålet (skriptläget). Utan
|
||||
// pågående resa: true, så att skriptet inte hänger.
|
||||
func (s *LevelScene) RideAtDest() bool {
|
||||
g, ok := s.run.Mini.(*minigame.Ride)
|
||||
return !ok || g.Index == g.Dest
|
||||
}
|
||||
|
||||
func (s *LevelScene) followPlayer() {
|
||||
x, y := s.run.Player.WorldPos(TileSize)
|
||||
s.cam.Follow(x+TileSize/2, y+TileSize/2)
|
||||
}
|
||||
|
||||
func (s *LevelScene) Update(g *Game) error {
|
||||
if s.run.Mini != nil {
|
||||
// Minispel: all input går dit; Esc avbryter minispelet, inte banan.
|
||||
s.run.StepMini(dt, minigame.Input{Move: miniMove(), Confirm: confirmJustPressed(), Hold: confirmHeld(), Cancel: backJustPressed()})
|
||||
if s.run.Outcome != sim.Ongoing {
|
||||
g.SetScene(NewResultScene(s))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if backJustPressed() {
|
||||
m, err := NewMenuScene(g.Assets)
|
||||
if err != nil {
|
||||
@@ -172,6 +189,9 @@ func (s *LevelScene) Draw(g *Game, screen *ebiten.Image) {
|
||||
s.drawUrge(g, screen, s.run.Party.Members[0], int(ox+math.Round(px)), int(oy+math.Round(py)))
|
||||
|
||||
s.drawHUD(g, screen)
|
||||
if s.run.Mini != nil {
|
||||
s.drawMinigame(g, screen)
|
||||
}
|
||||
}
|
||||
|
||||
// memberTints färgar följarnas sprites tills de har egna.
|
||||
@@ -217,14 +237,24 @@ func (s *LevelScene) drawHUD(g *Game, screen *ebiten.Image) {
|
||||
if r.Know.ShowsDestinationJP() { // hint från nivå 1: resmålet på japanska, att matcha mot skyltarna
|
||||
dest += " " + r.Level.Destination.Get("ja")
|
||||
}
|
||||
a.Draw(screen, r.Level.Name.Get(UILang), 4, 0, colText)
|
||||
a.Draw(screen, a.T("hud.destination")+": "+dest, 4+a.Width(r.Level.Name.Get(UILang))+12, 0, colKnown)
|
||||
a.Draw(screen, fmt.Sprintf("%s %3.0fs %s %d %s %d¥ %s Lv%d·%d", a.T("hud.time"), r.Time,
|
||||
a.T("hud.steps"), r.Steps, a.T("hud.card"), r.Card.Balance, a.T("hud.japanese"), r.Know.Level(), r.Know.Count()), 4, LineH, colDim)
|
||||
name := r.Level.Name.Get(UILang)
|
||||
a.Draw(screen, name, 4, 0, colText)
|
||||
destX := 4 + a.Width(name) + 12
|
||||
a.Draw(screen, a.T("hud.destination")+": "+dest, destX, 0, colKnown)
|
||||
a.Draw(screen, fmt.Sprintf("%s Lv%d·%d", a.T("hud.japanese"), r.Know.Level(), r.Know.Count()),
|
||||
destX+a.Width(a.T("hud.destination")+": "+dest)+12, 0, colDim)
|
||||
wallet := fmt.Sprintf("%s %3.0fs %s %d¥ %s %d¥", a.T("hud.time"), r.Time, a.T("hud.card"), r.Wallet.Card, a.T("hud.cash"), r.Wallet.Cash)
|
||||
if r.Wallet.Phone {
|
||||
wallet += fmt.Sprintf(" %s %.0f%%", a.T("hud.phone"), r.Wallet.Battery)
|
||||
}
|
||||
if r.Wallet.Ticket != "" {
|
||||
wallet += " " + a.T("hud.ticket") + " " + r.Wallet.Ticket
|
||||
}
|
||||
a.Draw(screen, wallet, 4, LineH, colDim)
|
||||
s.drawMeters(g, screen)
|
||||
|
||||
if r.Outcome != sim.Ongoing {
|
||||
return // resultatpanelen tar över; ingen inforuta eller minikarta
|
||||
if r.Outcome != sim.Ongoing || r.Mini != nil {
|
||||
return // resultatpanelen eller minispelet tar över; ingen inforuta eller minikarta
|
||||
}
|
||||
lines, accent, bar := s.infoLines(a)
|
||||
if entry := a.Dict.Lookup(r.Learned); entry != nil && r.Time-r.LearnedAt < learnedShowSec {
|
||||
@@ -241,6 +271,13 @@ func (s *LevelScene) drawHUD(g *Game, screen *ebiten.Image) {
|
||||
}
|
||||
lines = append(lines, a.wrapLine(plainLine(strings.Join(parts, " "), colWarn), ScreenW-8)...)
|
||||
}
|
||||
if r.Flashing(flashShowSec) {
|
||||
col := colBad
|
||||
if r.FlashKey == sim.FlashRescan {
|
||||
col = colWarn
|
||||
}
|
||||
lines = append(lines, a.wrapLine(plainLine(a.T(r.FlashKey), col), ScreenW-8)...)
|
||||
}
|
||||
|
||||
// Inforutans läge: nederkant, men flyttas upp under HUD:en om spelaren
|
||||
// (eller tåget under hen) annars skulle hamna bakom den.
|
||||
@@ -344,9 +381,21 @@ func (s *LevelScene) infoLines(a *Assets) (lines []line, accent color.Color, bar
|
||||
return []line{plainLine(fmt.Sprintf(a.T("hud.kiosk_prompt"), n, sim.KioskPriceYen*n), colGood)}, colGood, false
|
||||
}
|
||||
return []line{plainLine(a.T("hud.kiosk_none"), colDim)}, accent, false
|
||||
case level.TicketMachine:
|
||||
if lvl.TicketRequired {
|
||||
return []line{plainLine(fmt.Sprintf(a.T("hud.machine_ticket"), r.Wallet.Cash), colGood)}, colGood, false
|
||||
}
|
||||
return []line{plainLine(fmt.Sprintf(a.T("hud.machine_topup"), r.Wallet.Card, r.Wallet.Cash), colGood)}, colGood, false
|
||||
}
|
||||
if r.DeniedAt >= 0 && r.Time-r.DeniedAt < deniedShowSec {
|
||||
return []line{plainLine(a.T("hud.gate_denied"), colBad)}, colBad, false
|
||||
key := "hud.gate_denied"
|
||||
switch {
|
||||
case lvl.TicketRequired:
|
||||
key = sim.FlashNoTicket
|
||||
case r.Wallet.Phone && r.Wallet.Battery <= 0:
|
||||
key = "hud.phone_dead"
|
||||
}
|
||||
return []line{plainLine(a.T(key), colBad)}, colBad, false
|
||||
}
|
||||
return nil, accent, false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user