feat(@projects/@magic-civilization): update ransom offer duration from hardcoded to configurable

Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
Natalie 2026-05-09 12:46:53 -07:00
parent 1dcdb38b7c
commit 56e2947ce7
2 changed files with 45 additions and 2 deletions

View file

@ -2275,8 +2275,14 @@ impl TurnProcessor {
let owner = defender_player as u8;
let created_turn = state.turn;
let offer_id = state.ransom_queue.push(unit_id, captor, owner, price, created_turn);
let expires_turn = created_turn.saturating_add(crate::ransom::RANSOM_OFFER_DURATION_TURNS);
// p2-55f: use the data-driven duration from CombatBalance instead of
// the hardcoded const. The const remains as a fallback default for
// tests that construct GameState via Default and never load JSON.
let duration = state.combat_balance.ransom_offer_duration_turns;
let offer_id = state
.ransom_queue
.push_with_duration(unit_id, captor, owner, price, created_turn, duration);
let expires_turn = created_turn.saturating_add(duration);
state.pending_capture_events.ransom_offers_created.push(UnitRansomOfferedEvent {
turn: state.turn,

View file

@ -177,3 +177,40 @@ fn pending_capture_events_is_empty_considers_new_vecs() {
});
assert!(!pending.is_empty(), "non-empty expired should report not-empty");
}
// ── p2-55f: end-to-end duration plumbed from CombatBalance ────────────────────
#[test]
fn push_with_duration_overrides_default_const() {
// p2-55f: RansomQueue::push_with_duration accepts a runtime duration,
// proving the const is no longer the only path. CombatBalance.ransom_offer_duration_turns
// flows through here when wired in processor.rs::enqueue_ransom_offer.
let mut q = RansomQueue::default();
let id = q.push_with_duration(101, 1, 2, 50, /*created*/ 10, /*duration*/ 5);
let offer = q.iter().find(|o| o.id == id).expect("offer present");
assert_eq!(offer.expires_turn, 15, "expires_turn = created + duration");
// Tick at turn 14 — not yet expired.
let early = q.tick(14);
assert!(early.is_empty(), "duration=5 means turn 14 is one short of expiry");
// Tick at turn 15 — drained.
let expired = q.tick(15);
assert_eq!(expired.len(), 1);
assert_eq!(expired[0].unit_id, 101);
}
#[test]
fn combat_balance_default_matches_legacy_duration_const() {
// p2-55f: CombatBalance::default().ransom_offer_duration_turns must equal
// RANSOM_OFFER_DURATION_TURNS so behaviour is byte-equivalent for code
// paths that haven't migrated to read from CombatBalance yet.
use mc_turn::combat_balance::CombatBalance;
let cb = CombatBalance::default();
assert_eq!(
cb.ransom_offer_duration_turns,
RANSOM_OFFER_DURATION_TURNS,
"default config drift would break unmigrated callers"
);
}