Files
metro-puzzle-jp/internal/sim/stats.go
claude b2995d4ca9
All checks were successful
release / build-release (push) Successful in 1m37s
M7: svårighet, tid, poäng, debuffar, egna kort och sittplatsval
- sim/stats.go: Stats (fart, törst, fokus, toalett, tur), debuffar som
  multiplikatorer, Profile som följer med mellan banor och räknar ned
- sim.Run: tidsgräns och maxantal missade tåg förlorar banan; poängformel
  (tid mot par, pengar, sällskapets mätare, utforskat, avdrag); debuffar
  tjänas av många steg, lång tid, tom matmätare och seedad otur vid
  kiosken; stats påverkar fart, mätartakter, läsning och hjälptid
- egna kort (individualCards): Member.Card, spärren kräver allas saldo och
  drar från alla, automaten frågar vems kort, biljetter köps åt alla
- sittplatsval (seatSelection): Ticket får ett sittplatssteg med seedade
  önskemål (fönster/gång/sida/bredvid); missnöjda ger mätar- och poängavdrag
- level: maxMissedTrains, individualCards, seatSelection; bana 003 Shibuya
  (svårighet 3, fyra i sällskapet) och 002 med tidsgräns och sittplatser;
  ordboken utökad; generatorn är spec-driven
- game: tid kvar/missade i HUD, debuffar i meny/HUD/resultat, poäng och
  förlustorsaker på resultatet, vyer för personval och vagn, skript-pick,
  flaggan -debuffs; HUD och resultat komprimerade för fyra i sällskapet
- plan (Björn 2026-10-24): flera våningar med trappor som M9a, egna kort
  och sittplatsval som svårighetsinställningar i M7 – i spelbeskrivning,
  roadmap, testplan
- docs/README/wiki med sittplatsbilden

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

122 lines
3.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package sim
// Stats är spelarens multiplikatorer: 1,0 = normalt. Debuffar (och i M8
// items/skills) ändrar dem.
type Stats [5]float64
// Statindex.
const (
StatSpeed = iota // gångfart
StatThirst // hur fort dryckesmätaren sjunker (>1 = fortare)
StatFocus // chans att lära av skyltar, hjälptid (>1 = bättre)
StatToilet // hur fort toamätaren sjunker (>1 = fortare)
StatLuck // omskanning, trängsel (>1 = bättre; items i M8)
)
// DefaultStats är allt på 1,0.
func DefaultStats() Stats { return Stats{1, 1, 1, 1, 1} }
// DebuffKind är en typ av debuff (textnyckel: "debuff.<kind>").
type DebuffKind string
// Debuffar. De fyra första uppstår av spelandet (M7), resten delas ut av
// sidouppdrag (M10) och varar 1–4 banor.
const (
SoreFeet DebuffKind = "sore_feet" // många steg
Tired DebuffKind = "tired" // lång bana
Hangry DebuffKind = "hangry" // tom matmätare
FoodPoisoning DebuffKind = "food_poisoning" // otur vid kiosken
DOMS DebuffKind = "doms" // träningsvärk
Blisters DebuffKind = "blisters" // skoskav
HeavyBag DebuffKind = "heavy_bag" // köpt något tungt/stort
Stuffed DebuffKind = "stuffed" // proppmätt
Sweaty DebuffKind = "sweaty" // svettig och varm
)
// DebuffEffects är vad varje debuff gör med statsen.
var DebuffEffects = map[DebuffKind]Stats{
SoreFeet: {0.85, 1, 1, 1, 1},
Tired: {0.9, 1, 0.8, 1, 1},
Hangry: {1, 1.2, 0.7, 1, 1},
FoodPoisoning: {1, 1, 1, 2.0, 1},
DOMS: {0.9, 1, 1, 1, 1},
Blisters: {0.8, 1, 1, 1, 1},
HeavyBag: {0.9, 1.2, 1, 1, 1},
Stuffed: {0.9, 1, 1, 1.3, 1},
Sweaty: {1, 1.5, 0.9, 1, 1},
}
// Utlösare för de spelgenererade debuffarna.
const (
SoreFeetSteps = 150
TiredSec = 300.0
FoodPoisonChance = 0.05
FoodPoisonLevels = 2
)
// Debuff är en aktiv debuff med återstående antal banor.
type Debuff struct {
Kind DebuffKind `json:"kind"`
LevelsLeft int `json:"levelsLeft"`
}
// CombinedStats multiplicerar ihop effekterna av alla debuffar.
func CombinedStats(debuffs []Debuff) Stats {
st := DefaultStats()
for _, d := range debuffs {
if e, ok := DebuffEffects[d.Kind]; ok {
for i := range st {
st[i] *= e[i]
}
}
}
return st
}
// Profile är det som följer spelaren mellan banor och inte hör till
// kunskap eller plånbok: aktiva debuffar (items och skills i M8).
type Profile struct {
Debuffs []Debuff `json:"debuffs"`
}
// Add lägger till en debuff; finns den redan förlängs den till det längsta.
func (p *Profile) Add(kind DebuffKind, levels int) {
for i := range p.Debuffs {
if p.Debuffs[i].Kind == kind {
p.Debuffs[i].LevelsLeft = max(p.Debuffs[i].LevelsLeft, levels)
return
}
}
p.Debuffs = append(p.Debuffs, Debuff{Kind: kind, LevelsLeft: levels})
}
// Has rapporterar om debuffen är aktiv.
func (p *Profile) Has(kind DebuffKind) bool {
for _, d := range p.Debuffs {
if d.Kind == kind {
return true
}
}
return false
}
// EndLevel räknar ned alla debuffar en bana och tar bort de som gått ut.
// Returnerar de som försvann.
func (p *Profile) EndLevel() []DebuffKind {
var expired []DebuffKind
kept := p.Debuffs[:0]
for _, d := range p.Debuffs {
d.LevelsLeft--
if d.LevelsLeft <= 0 {
expired = append(expired, d.Kind)
continue
}
kept = append(kept, d)
}
p.Debuffs = kept
return expired
}
// Stats är de sammanlagda multiplikatorerna just nu.
func (p *Profile) Stats() Stats { return CombinedStats(p.Debuffs) }