Files
metro-puzzle-jp/internal/minigame/crowd.go
claude de61568e44
All checks were successful
release / build-release (push) Successful in 1m33s
M9b: folk, filer, reklam, sorl och vagnval
Folk på stationen (NPC:er som vandrar, kliver av tåg och går mot
utgången, blockerar spelaren men inte varandra), vänster-/högerfiler
som bromsar på fel sida, bredare gångar, reklamaffischer (clutter),
japanskt sorl i loop (noise), vagnval med kvinnovagn (stort avdrag med
man i sällskapet, tidsstyrd), kömarkeringar på perrongen, trängsel per
vagn (bonus för tom vagn, svettig-debuff och svårare resa i full vagn,
släpp förbi passagerare) och att folk kliver av innan man får gå på.
Ny bana 005 Ueno. Skärmdumpsverktyget kan filtrera på bana/skript.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-24 12:33:44 +02:00

61 lines
1.6 KiB
Go

package minigame
import "gitea.brasse-pc.eu/brasse/metro-puzzle-jp/internal/rng"
// Crowd är "få plats på det fulla tåget": en markör pendlar över en stapel,
// tryck Enter när den är i den gröna zonen. Två försök, sedan går tåget.
type Crowd struct {
base
Pos float64 // markörens läge 0..1
dir float64
Speed float64 // enheter per sekund
ZoneLo float64
ZoneHi float64
Attempts int
MaxTries int
}
const crowdZoneWidth = 0.22
// NewCrowd seedar zonens läge och markörens fart. luck (1 = normalt) gör
// zonen bredare eller smalare, och crowdLevel (0 lite, 1 mellan, 2 mycket
// folk i vagnen) smalare ju fler som trängs.
func NewCrowd(seed rng.Seed, tries int, luck float64, crowdLevel int) *Crowd {
r := newRand(seed, "crowd")
level := 1.3 - 0.4*float64(max(0, min(2, crowdLevel)))
width := min(0.6, max(0.1, crowdZoneWidth*max(0.5, min(2, luck))*level))
lo := r.between(0.1, 0.9-width)
return &Crowd{dir: 1, Speed: r.between(0.9, 1.5), ZoneLo: lo, ZoneHi: lo + width, MaxTries: max(1, tries)}
}
// InZone rapporterar om markören är i zonen just nu.
func (g *Crowd) InZone() bool { return g.Pos >= g.ZoneLo && g.Pos <= g.ZoneHi }
// Update pendlar markören och tar emot försök.
func (g *Crowd) Update(in Input, dt float64) {
if g.done {
return
}
if in.Cancel {
g.done = true
return
}
g.Pos += g.dir * g.Speed * dt
for g.Pos < 0 || g.Pos > 1 {
if g.Pos < 0 {
g.Pos = -g.Pos
} else {
g.Pos = 2 - g.Pos
}
g.dir = -g.dir
}
if in.Confirm {
g.Attempts++
if g.InZone() {
g.done, g.success = true, true
} else if g.Attempts >= g.MaxTries {
g.done = true
}
}
}