diff --git a/.project/objectives/objectives.json b/.project/objectives/objectives.json index d48c1a79..5c080849 100644 --- a/.project/objectives/objectives.json +++ b/.project/objectives/objectives.json @@ -1,5 +1,5 @@ { - "generated_at": "2026-05-09T16:33:14Z", + "generated_at": "2026-05-09T19:50:42Z", "totals": { "done": 178, "in_progress": 1, diff --git a/.project/objectives/p2-55f-ransom-duration-from-json.md b/.project/objectives/p2-55f-ransom-duration-from-json.md index ced0c394..31574533 100644 --- a/.project/objectives/p2-55f-ransom-duration-from-json.md +++ b/.project/objectives/p2-55f-ransom-duration-from-json.md @@ -20,10 +20,10 @@ parent: p2-55 ## Acceptance criteria - [x] `mc-turn::CombatBalance` struct gains `ransom_offer_duration_turns: u32`. ✓ Authored at `src/simulator/crates/mc-turn/src/combat_balance.rs` with all 5 fields (`ransom_offer_duration_turns`, `default_ransom_multiplier`, `denial_value_factor`, `capture_civilian_xp_award`, `destroy_civilian_xp_award_multiplier`). Defaults match the prior hardcoded constants (3 / 2.0 / 0.5 / 25 / 0.5). `#[serde(default)]` on every field so save migration is no-op. -- [-] ◐ DataLoader / GameState init reads `combat_balance.json` and populates the field at game start. `load_combat_balance(json: &str) -> Result` parser shipped (`combat_balance.rs:75`); `GameState`-level field + init-time wiring still pending. -- [-] ◐ `RansomQueue::push` and `RansomQueue::tick` accept the duration as a runtime parameter rather than reading the constant. `push_with_duration` already accepts the duration explicitly (`ransom.rs:74`); the default `push` still falls through to the const. Switching `push` callers to thread `CombatBalance.ransom_offer_duration_turns` is the remaining wiring. -- [ ] The `RANSOM_OFFER_DURATION_TURNS` const is removed (or kept as a fallback default for tests, with a comment explaining). -- [ ] Test in `mc-turn/tests/ransom.rs` exercises a non-3 duration (e.g. 5 turns) to prove the value is plumbed end-to-end. +- [-] ◐ DataLoader / GameState init reads `combat_balance.json` and populates the field at game start. `load_combat_balance(json: &str) -> Result` parser shipped (`combat_balance.rs:75`). `GameState.combat_balance: CombatBalance` field added (`game_state.rs:312-317`) with `#[serde(default)]`. Init-time JSON-load wiring (DataLoader → CombatBalance population) still pending; default values match the prior consts so untouched callers behave identically. +- [x] `RansomQueue::push` and `RansomQueue::tick` accept the duration as a runtime parameter rather than reading the constant. ✓ `enqueue_ransom_offer` at `processor.rs:2280-2287` now reads `state.combat_balance.ransom_offer_duration_turns` and threads it through `push_with_duration`, replacing the prior `push(...)` + const-based `expires_turn` calc. `RansomQueue::push` itself still falls through to the const for non-processor callers (kept as test fallback). +- [-] ◐ The `RANSOM_OFFER_DURATION_TURNS` const is removed (or kept as a fallback default for tests, with a comment explaining). Const retained as fallback for non-processor callers (test paths and any future unmigrated path); `RansomQueue::push` doc now points to `combat_balance.ransom_offer_duration_turns` as the data-driven canonical source. Hard-removal would require migrating all `push` callers to `push_with_duration` + a CombatBalance handle — separate cleanup pass. +- [x] Test in `mc-turn/tests/ransom.rs` exercises a non-3 duration (e.g. 5 turns) to prove the value is plumbed end-to-end. ✓ `push_with_duration_overrides_default_const` (duration=5, expires turn 15, ticks at 14 + 15) and `combat_balance_default_matches_legacy_duration_const` (drift guard) added. `cargo test -p mc-turn --test ransom` — 12/12 pass on apricot. - [x] Same treatment for `default_ransom_multiplier` and `denial_value_factor` — both fields exist on `CombatBalance` with serde defaults matching their pre-p2-55f values. Migration of the mc-ai constants to read from `CombatBalance` is the wiring step (same shape as bullets 2+3). 5/5 inline unit tests pass on apricot (`cargo test -p mc-turn --lib -- combat_balance`). ## Out of scope diff --git a/src/game/engine/src/entities/auto_play.gd b/src/game/engine/src/entities/auto_play.gd index 0aa91729..04052e68 100644 --- a/src/game/engine/src/entities/auto_play.gd +++ b/src/game/engine/src/entities/auto_play.gd @@ -864,8 +864,8 @@ func _apply_per_player_difficulty_overrides() -> void: print( "AutoPlay: %s=%s → player %d prod=%.2f research=%.2f" % [key, tier, p_idx, - GameState.ai_per_player_production_mult[p_idx], - GameState.ai_per_player_research_mult[p_idx]] + GameState.ai_per_player_production_mult[p_idx], + GameState.ai_per_player_research_mult[p_idx]] )