M7: svårighet, tid, poäng, debuffar, egna kort och sittplatsval
All checks were successful
release / build-release (push) Successful in 1m37s
All checks were successful
release / build-release (push) Successful in 1m37s
- 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>
This commit is contained in:
121
internal/sim/stats.go
Normal file
121
internal/sim/stats.go
Normal file
@@ -0,0 +1,121 @@
|
||||
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) }
|
||||
Reference in New Issue
Block a user