M7: svårighet, tid, poäng, debuffar, egna kort och sittplatsval
All checks were successful
release / build-release (push) Successful in 1m37s

- sim/stats.go: Stats (fart, törst, fokus, toalett, tur), debuffar som
  multiplikatorer, Profile som följer med mellan banor och räknar ned
- sim.Run: tidsgräns och maxantal missade tåg förlorar banan; poängformel
  (tid mot par, pengar, sällskapets mätare, utforskat, avdrag); debuffar
  tjänas av många steg, lång tid, tom matmätare och seedad otur vid
  kiosken; stats påverkar fart, mätartakter, läsning och hjälptid
- egna kort (individualCards): Member.Card, spärren kräver allas saldo och
  drar från alla, automaten frågar vems kort, biljetter köps åt alla
- sittplatsval (seatSelection): Ticket får ett sittplatssteg med seedade
  önskemål (fönster/gång/sida/bredvid); missnöjda ger mätar- och poängavdrag
- level: maxMissedTrains, individualCards, seatSelection; bana 003 Shibuya
  (svårighet 3, fyra i sällskapet) och 002 med tidsgräns och sittplatser;
  ordboken utökad; generatorn är spec-driven
- game: tid kvar/missade i HUD, debuffar i meny/HUD/resultat, poäng och
  förlustorsaker på resultatet, vyer för personval och vagn, skript-pick,
  flaggan -debuffs; HUD och resultat komprimerade för fyra i sällskapet
- plan (Björn 2026-10-24): flera våningar med trappor som M9a, egna kort
  och sittplatsval som svårighetsinställningar i M7 – i spelbeskrivning,
  roadmap, testplan
- docs/README/wiki med sittplatsbilden

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
2026-10-24 10:18:17 +02:00
parent 9fc7e94074
commit b2995d4ca9
44 changed files with 1567 additions and 177 deletions

View File

@@ -2,11 +2,13 @@ package minigame
import "gitea.brasse-pc.eu/brasse/metro-puzzle-jp/internal/rng"
// TopUp är påfyllningsautomaten: hitta チャージ-knappen bland japanska
// knappar i seedad ordning, välj belopp, mata in sedlar genom att hålla
// Enter. Fel knapp kostar en straffsekund eller två.
// TopUp är påfyllningsautomaten: (vems kort, om alla har egna), hitta
// チャージ-knappen bland japanska knappar i seedad ordning, välj belopp, mata
// in sedlar genom att hålla Enter. Fel knapp kostar en straffsekund eller två.
type TopUp struct {
base
Members []string // namn när alla har egna kort (annars tom)
Member int // vald person (index i Members, 0 = spelaren)
Stage TopUpStage
Buttons []string // knapparnas text, seedad ordning
Cursor int
@@ -26,6 +28,7 @@ const (
TopUpPickButton TopUpStage = iota
TopUpPickAmount
TopUpFeed
TopUpPickMember // först, bara med egna kort
)
// Knapparna på en japansk biljettautomat. チャージ är den rätta.
@@ -40,10 +43,15 @@ const (
topUpDrainPerSec = 1.2
)
// NewTopUp skapar automaten. maxCash begränsar beloppen.
func NewTopUp(seed rng.Seed, maxCash int) *TopUp {
// NewTopUp skapar automaten. maxCash begränsar beloppen. members anges
// när alla i sällskapet har egna kort; då väljs person först.
func NewTopUp(seed rng.Seed, maxCash int, members []string) *TopUp {
r := newRand(seed, "topup")
g := &TopUp{Buttons: append([]string(nil), topUpButtons...), MaxCash: maxCash}
if len(members) > 1 {
g.Members = append([]string(nil), members...)
g.Stage = TopUpPickMember
}
r.shuffle(len(g.Buttons), func(i, j int) { g.Buttons[i], g.Buttons[j] = g.Buttons[j], g.Buttons[i] })
for _, a := range TopUpAmounts {
if a <= maxCash {
@@ -70,8 +78,14 @@ func (g *TopUp) Update(in Input, dt float64) {
return
}
switch g.Stage {
case TopUpPickMember:
g.Cursor = wrap(g.Cursor+in.Move, len(g.Members))
if in.Confirm {
g.Member = g.Cursor
g.Stage, g.Cursor = TopUpPickButton, 0
}
case TopUpPickButton:
g.Cursor = wrap(g.Cursor+in.Move, len(g.Buttons))
g.Cursor = wrap(g.Cursor+2*in.Move+in.MoveX, len(g.Buttons)) // 2×2-rutnät
if in.Confirm {
if g.Buttons[g.Cursor] == topUpButtons[0] {
g.Stage, g.Cursor = TopUpPickAmount, 0