M10c: vem betalar i kiosken och spärrar utan återvändo
All checks were successful
release / build-release (push) Successful in 2m7s

Björns tillägg 2026-10-24. Med egna kort och fler i sällskapet frågar
kiosken vem som betalar (minigame.Payer: kontant, spelarens kort eller en
följares kort; den som inte har råd nekas, Esc avbryter). Avgiften dras
nu när man passerar spärren in i det betalda området (level.InsideGates),
inte på spärrrutan. Banflaggan oneWayGates: incheckad släpps inte ut igen
förrän man åkt; Enter vid spärren kallar på personal (10 s) som låser upp
korten; ny inpassering kostar igen. På i 005, 007/007b och 008/008b.
Skriptkommandon urge och push. Docs, wiki och skärmdumpar uppdaterade.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
2026-10-24 22:12:13 +02:00
parent 4ae6a1d24c
commit f04d6a88f9
26 changed files with 674 additions and 64 deletions

View File

@@ -409,3 +409,32 @@ func TestRideCrowdLetPass(t *testing.T) {
}
}
}
func TestPayerPicksSourceAndRefusesPoor(t *testing.T) {
opts := []PayOption{{Cash: true, Yen: 100}, {Name: "Du", Yen: 50}, {Name: "Anna", Member: 1, Yen: 400}, {Name: "Ville", Member: 2, Yen: 0}}
g := NewPayer(300, opts)
if g.Cursor != 2 {
t.Fatalf("markören ska stå på första som har råd, står på %d", g.Cursor)
}
g.Update(Input{MoveX: 1}, 0) // Ville: har inte råd
g.Update(Input{Confirm: true}, 0)
if g.Done() || !g.Refused {
t.Fatal("den som inte har råd ska nekas utan att köpet avslutas")
}
g.Update(Input{MoveX: -1}, 0)
if g.Refused {
t.Fatal("att flytta markören nollställer nekandet")
}
g.Update(Input{Confirm: true}, 0)
if !g.Done() || !g.Success() || g.Chosen == nil || g.Chosen.Name != "Anna" || g.Chosen.Member != 1 {
t.Fatalf("Anna ska betala: %+v", g.Chosen)
}
h := NewPayer(300, opts)
h.Update(Input{Cancel: true}, 0)
if !h.Done() || h.Success() || h.Chosen != nil {
t.Fatal("Esc avbryter utan köp")
}
if NewPayer(1000, opts).Cursor != 0 {
t.Fatal("utan någon som har råd står markören först")
}
}

View File

@@ -0,0 +1,61 @@
package minigame
// Payer är frågan "vem betalar?" vid kiosken när alla i sällskapet har egna
// kort: kontant, spelarens kort eller en följares kort. Pilarna väljer,
// Enter betalar (bara om det räcker), Esc avbryter köpet. Poängen är att
// kunna vara strategisk så att alla har kvar pengar till spärrarna.
type PayOption struct {
Name string // vem (tom för kontant)
Cash bool // kontanter i plånboken
Member int // 0 = spelarens kort, annars följarens index i sällskapet
Yen int // tillgängligt belopp
}
// Payer är väljaren.
type Payer struct {
base
Price int
Options []PayOption
Cursor int
Chosen *PayOption // vald källa när det lyckats
Refused bool // försökte betala med något som inte räcker
}
// NewPayer skapar väljaren med markören på första källan som har råd.
func NewPayer(price int, options []PayOption) *Payer {
g := &Payer{Price: price, Options: append([]PayOption(nil), options...)}
for i, o := range g.Options {
if o.Yen >= price {
g.Cursor = i
break
}
}
return g
}
// CanAfford rapporterar om källan i räcker till priset.
func (g *Payer) CanAfford(i int) bool { return g.Options[i].Yen >= g.Price }
// Update flyttar markören och tar emot betala/avbryt.
func (g *Payer) Update(in Input, dt float64) {
if g.done || len(g.Options) == 0 {
return
}
if in.Cancel {
g.done = true
return
}
if mv := in.MoveX + in.Move; mv != 0 {
g.Cursor = wrap(g.Cursor+mv, len(g.Options))
g.Refused = false
}
if in.Confirm {
if !g.CanAfford(g.Cursor) {
g.Refused = true
return
}
o := g.Options[g.Cursor]
g.Chosen = &o
g.done, g.success = true, true
}
}