package minigame import "gitea.brasse-pc.eu/brasse/metro-puzzle-jp/internal/rng" // Ride är tågresan: stationerna passerar en i taget med "次は …"-utrop; // tryck Enter vid ditt resmål. Fel station eller att åka förbi är misslyckat. type Ride struct { base Stops []string // stationsnamn på japanska i ordning Dest int // index för resmålet, -1 om det inte finns på linjen (fel tåg) Index int // aktuell station Timer float64 // sekunder kvar vid aktuell station StopSec float64 GotOff int // index där spelaren klev av, -1 = inte än // Trängsel: vid stationer där man inte ska av vill andra passagerare ut. Crowd int // vagnens trängselnivå 0–2 WantsOut []bool // per station: någon vill förbi LetPass bool // spelaren har släppt förbi vid aktuell station Blocked int // stationer där ingen släpptes förbi (avdrag) } // Tid per station efter trängsel: 2,5 / 2,0 / 1,5 s. const rideStopSec = 2.5 // RideStopSec är tiden per station för en trängselnivå. func RideStopSec(crowd int) float64 { return rideStopSec - 0.5*float64(max(0, min(2, crowd))) } // NewRide bygger linjen: fillers är andra stationsnamn (blandas), dest läggs // på en seedad plats (aldrig först) om det är rätt tåg, annars utelämnas det. // crowd (0–2) ger kortare tid per station och passagerare som vill förbi. func NewRide(seed rng.Seed, dest string, fillers []string, stops int, correctTrain bool, crowd int) *Ride { r := newRand(seed, "ride") f := append([]string(nil), fillers...) r.shuffle(len(f), func(i, j int) { f[i], f[j] = f[j], f[i] }) stops = max(2, stops) di := -1 if correctTrain { di = 1 + r.intn(stops-1) } var names []string for i := 0; i < stops; i++ { switch { case i == di: names = append(names, dest) case len(f) > 0: names = append(names, f[0]) f = f[1:] default: names = append(names, UnknownStop) // slut på namn: en namnlös station } } return newRide(r, names, di, crowd) } // NewRideStops bygger resan av givna stationer i ordning (linjenätets // riktiga stationer); dest är resmålets index, -1 om det inte kommer. func NewRideStops(seed rng.Seed, stops []string, dest int, crowd int) *Ride { r := newRand(seed, "ride") if len(stops) < 2 { stops = append(append([]string(nil), stops...), UnknownStop, UnknownStop)[:2] } if dest >= len(stops) { dest = -1 } return newRide(r, append([]string(nil), stops...), dest, crowd) } func newRide(r *randSrc, stops []string, dest int, crowd int) *Ride { crowd = max(0, min(2, crowd)) sec := RideStopSec(crowd) g := &Ride{StopSec: sec, Timer: sec, GotOff: -1, Dest: dest, Crowd: crowd, Stops: stops} g.WantsOut = make([]bool, len(g.Stops)) chance := [...]float64{0, 0.4, 0.7}[crowd] for i := range g.Stops { if i != g.Dest && r.float() < chance { g.WantsOut[i] = true } } return g } // NeedsLetPass rapporterar om någon vill förbi vid aktuell station just nu. func (g *Ride) NeedsLetPass() bool { return g.WantsOut[g.Index] && !g.LetPass } // UnknownStop används när det inte finns fler stationsnamn att ta av. const UnknownStop = "・・・" // Current är stationen tåget står vid. func (g *Ride) Current() string { return g.Stops[g.Index] } // Update låter stationerna passera och tar emot "kliv av". func (g *Ride) Update(in Input, dt float64) { if g.done { return } if in.Confirm { g.GotOff = g.Index g.done = true g.success = g.Index == g.Dest return } if in.MoveX < 0 && g.NeedsLetPass() { g.LetPass = true // kliv åt sidan } g.Timer -= dt if g.Timer <= 0 { if g.NeedsLetPass() { g.Blocked++ } g.Index++ g.Timer = g.StopSec g.LetPass = false if g.Index >= len(g.Stops) { g.Index = len(g.Stops) - 1 g.done = true // åkte till slutstationen utan att kliva av } } }