package minigame import "gitea.brasse-pc.eu/brasse/metro-puzzle-jp/internal/rng" // 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 Amounts []int Mistakes int Penalty float64 // sekunder kvar av frysning efter fel knapp Fill float64 // 0..1 sedelinmatning Amount int // valt belopp (resultat) MaxCash int // vad spelaren har råd med } // TopUpStage är var i flödet man är. type TopUpStage int // Steg. const ( TopUpPickButton TopUpStage = iota TopUpPickAmount TopUpFeed TopUpPickMember // först, bara med egna kort ) // Knapparna på en japansk biljettautomat. チャージ är den rätta. var topUpButtons = []string{"チャージ", "きっぷ", "定期券", "取消"} // TopUpAmounts är beloppen man kan välja. var TopUpAmounts = []int{1000, 2000, 3000, 5000} const ( topUpPenaltySec = 1.5 topUpFeedPerSec = 0.8 // hålla Enter: fyller på 1/0.8 s topUpDrainPerSec = 1.2 ) // 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 { g.Amounts = append(g.Amounts, a) } } if len(g.Amounts) == 0 { g.done = true // inga pengar: inget att göra } return g } // Update för automaten framåt. func (g *TopUp) Update(in Input, dt float64) { if g.done { return } if in.Cancel { g.done = true return } if g.Penalty > 0 { g.Penalty -= dt 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+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 } else { g.Mistakes++ g.Penalty = topUpPenaltySec } } case TopUpPickAmount: g.Cursor = wrap(g.Cursor+in.Move, len(g.Amounts)) if in.Confirm { g.Amount = g.Amounts[g.Cursor] g.Stage = TopUpFeed } case TopUpFeed: if in.Hold { g.Fill += topUpFeedPerSec * dt } else { g.Fill = max(0, g.Fill-topUpDrainPerSec*dt) } if g.Fill >= 1 { g.Fill = 1 g.done, g.success = true, true } } } func wrap(i, n int) int { if n == 0 { return 0 } return ((i % n) + n) % n }