class_name StatusCatalog
## Static factory registry for named statuses.
##
## Mirrors ThoughtCatalog: each factory returns a fresh Status with all fields
## set correctly.  Callers must not mutate the returned object before passing
## it to Pawn.add_status() — add_status() handles severity stack-merging.
##
## Phase 9 ships: bleeding(), downed().
## Phase 12 ships: wet(), cold().
## Phase 17 will add: sick(), infected().
##
## Usage pattern:
##   pawn.add_status(StatusCatalog.bleeding(2))
##
## docs/design.md "Health & status effects"; docs/design.md "Downed & death".

## ── Wet status constants (Phase 12) ─────────────────────────────────────────
## Severity labels: 1 = Damp, 2 = Soaked.
const WET_DAMP_LEVEL: int = 1
const WET_SOAKED_LEVEL: int = 2
## Per-tick accumulator rates for the 0–100 Wet scale.
## Storm doubles WET_GAIN_PER_TICK.
const WET_GAIN_PER_TICK: float = 0.02
const WET_DECAY_PER_TICK: float = 0.05
## Accumulator thresholds that flip severity.
const WET_DAMP_THRESHOLD: float = 25.0   ## ≥ 25 → severity 1 (Damp)
const WET_SOAKED_THRESHOLD: float = 60.0 ## ≥ 60 → severity 2 (Soaked)

## ── Cold status constants (Phase 12) ────────────────────────────────────────
## Severity labels: 1 = Cold, 2 = Very Cold, 3 = Freezing.
## Cold activates in winter (Clock.SEASON_WINTER) or during a cold snap (any season).
## Cold snap doubles COLD_GAIN_PER_TICK.
const COLD_GAIN_PER_TICK: float = 0.015
const COLD_DECAY_PER_TICK: float = 0.04
const COLD_MILD_THRESHOLD: float = 25.0   ## ≥ 25 → severity 1
const COLD_SEVERE_THRESHOLD: float = 60.0 ## ≥ 60 → severity 2
const COLD_EXTREME_THRESHOLD: float = 85.0 ## ≥ 85 → severity 3

## Sim ticks before an untreated bleed-out causes death.
## design.md "Downed & death": 6 in-game hours.
## At 20 Hz × 60 s/min × 60 min/hr × 6 hr = 432 000 ticks at 1×.
## At Fast (5×) that compresses to ~86 400 real-Hz-ticks — but game time is
## what the player sees, so this constant is in game-time-equivalent ticks
## (the same 20-Hz tick stream; speed multiplier compresses the real clock,
## not the tick count that this timer counts against).
## Phase 20 may retune; keeping the name locked from day one per design.md.
const BLEED_OUT_TICKS: int = 432000  # 6 in-game hours at 20 Hz

## HP lost per sim tick per severity level.
## Severity 1: 0.05 / tick.  Severity 3: 0.15 / tick.
## At severity 3, 100 HP → 0 in 100 / 0.15 = ~667 ticks ≈ 33 sim-seconds at 1×.
## At Fast (5×) real time: ~7 s.  Tune Phase 20.
const BLEED_HP_PER_TICK: float = 0.05


## Returns a Bleeding status at the given severity (1–3).
## Severity is clamped to [1, 3].  Lifetime is PERSISTENT — cleared by doctor
## treatment, not by time expiry.
static func bleeding(severity: int = 1) -> Status:
	var s := Status.new()
	s.id = &"bleeding"
	s.kind = Status.Kind.BLEEDING
	s.label = "Bleeding"
	s.severity = clampi(severity, 1, 3)
	s.max_severity = 3
	s.lifetime = Status.Lifetime.PERSISTENT
	return s


## Returns a Downed status.
## Downed has severity 1 (single-instance — you're either down or you're not).
## Cleared externally by Pawn._check_revive() when HP rises to HP_REVIVE_THRESHOLD.
static func downed() -> Status:
	var s := Status.new()
	s.id = &"downed"
	s.kind = Status.Kind.DOWNED
	s.label = "Downed"
	s.severity = 1
	s.max_severity = 1
	s.lifetime = Status.Lifetime.PERSISTENT
	return s


## Returns a Wet status at the given severity (1 = Damp, 2 = Soaked).
## Severity is clamped to [1, WET_SOAKED_LEVEL].  Lifetime is PERSISTENT —
## cleared (or severity-adjusted) by Pawn._sync_wet_status() based on accumulator.
## The accumulator thresholds WET_DAMP_THRESHOLD / WET_SOAKED_THRESHOLD drive
## which severity the pawn is in; this factory just stamps the initial value.
static func wet(severity: int = WET_DAMP_LEVEL) -> Status:
	var s := Status.new()
	s.id = &"wet"
	s.kind = Status.Kind.WET
	s.label = "Wet"
	s.severity = clampi(severity, WET_DAMP_LEVEL, WET_SOAKED_LEVEL)
	s.max_severity = WET_SOAKED_LEVEL
	s.lifetime = Status.Lifetime.PERSISTENT
	return s


## Returns a Cold status at the given severity (1 = Cold, 2 = Very Cold, 3 = Freezing).
## Severity is clamped to [1, 3].  Lifetime is PERSISTENT —
## cleared (or severity-adjusted) by Pawn._sync_cold_status() based on accumulator.
static func cold(severity: int = 1) -> Status:
	var s := Status.new()
	s.id = &"cold"
	s.kind = Status.Kind.COLD
	s.label = "Cold"
	s.severity = clampi(severity, 1, 3)
	s.max_severity = 3
	s.lifetime = Status.Lifetime.PERSISTENT
	return s
