M6: plånbok, biljetter, kortet i telefonen och seedade minispel
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:
2026-10-24 09:50:12 +02:00
parent 3f56020777
commit 9fc7e94074
45 changed files with 1779 additions and 166 deletions

67
internal/sim/wallet.go Normal file
View File

@@ -0,0 +1,67 @@
package sim
// Wallet är spelarens pengar och biljetter. Följer med mellan banor
// (sparas i M8).
type Wallet struct {
Card int `json:"card"` // IC-kortets saldo (yen)
Cash int `json:"cash"` // kontanter (yen)
Phone bool `json:"phone"` // kortet ligger i telefonen
Battery float64 `json:"battery"` // telefonens batteri 0..100
Ticket string `json:"ticket"` // köpt pappersbiljett: resmålets namn (ja), "" = ingen
TicketFare int `json:"ticketFare"` // vad biljetten kostade
Spent int `json:"spent"` // totalt spenderat (poäng i M7)
}
// Pengar och telefon.
const (
StartCardYen = 2000
StartCashYen = 5000
BatteryPerSec = 100.0 / 900 // telefonen håller 15 min – tar bara slut på långa banor
PhoneSpeedFactor = 1.1 // kortet i telefonen: man slipper rota i plånboken
PhoneRescanChance = 0.15 // ...men ibland måste man skanna igen
RescanSec = 1.5
)
// NewWallet ger startkassan med kortet i plånboken (inte telefonen).
func NewWallet() *Wallet { return &Wallet{Card: StartCardYen, Cash: StartCashYen, Battery: 100} }
// CardUsable: kortet i telefonen går inte att använda med dött batteri.
func (w *Wallet) CardUsable() bool { return !w.Phone || w.Battery > 0 }
// PayCard drar från kortet om det går.
func (w *Wallet) PayCard(yen int) bool {
if !w.CardUsable() || w.Card < yen {
return false
}
w.Card -= yen
w.Spent += yen
return true
}
// PayCash betalar kontant om det går.
func (w *Wallet) PayCash(yen int) bool {
if w.Cash < yen {
return false
}
w.Cash -= yen
w.Spent += yen
return true
}
// TopUp flyttar kontanter till kortet (påfyllning räknas inte som spenderat
// förrän kortet används).
func (w *Wallet) TopUp(yen int) bool {
if w.Cash < yen {
return false
}
w.Cash -= yen
w.Card += yen
return true
}
// Drain laddar ur telefonen när kortet ligger i den.
func (w *Wallet) Drain(dt float64) {
if w.Phone {
w.Battery = max(0, w.Battery-BatteryPerSec*dt)
}
}