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, inom rimliga gränser. func NewCrowd(seed rng.Seed, tries int, luck float64) *Crowd { r := newRand(seed, "crowd") width := min(0.6, max(0.1, crowdZoneWidth*max(0.5, min(2, luck)))) 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 } } }