magicciv/.project/objectives/p3-11-pioneer-engineer-action-points.md
Natalie 2fe49402de fix(@projects/@magic-civilization): 🐛 update objective tracking stats and legend
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-05-13 15:30:51 -07:00

6.5 KiB
Raw Blame History

id title priority status scope owner updated_at evidence blocked_by
p3-11 Pioneer & Engineer action-point pool p3 done game1 shipwright 2026-05-13
src/simulator/crates/mc-core/src/units.rs:48-119 ActionPoints typed newtype with current/capacity invariants
src/simulator/crates/mc-core/src/units.rs:18-44 ActionCost typed wrapper
src/simulator/crates/mc-core/src/units.rs:121-129 pioneer_engineer_ap_capacity tier ladder 6/10/14
src/simulator/crates/mc-core/src/units.rs:131-188 5 unit tests passing (cargo test -p mc-core units::)
src/simulator/crates/mc-core/src/lib.rs:22 module wired into mc-core
public/resources/units/dwarf_engineer.json action_point_capacity:6 (tier 1)
public/resources/units/dwarf_high_engineer.json action_point_capacity:10 (tier 2)
public/resources/units/dwarf_grand_engineer.json action_point_capacity:14 (tier 3)
public/resources/units/dwarf_ascendant_engineer.json action_point_capacity:16 (tier 8, Chief Engineer tier)
public/resources/units/dwarf_founder.json action_point_capacity:10 (tier 2 Pioneer)
public/resources/unit_actions/found_city.json ap_cost:all
public/resources/unit_actions/prepare_land.json ap_cost:2
public/resources/unit_actions/build_improvement.json ap_cost:per_improvement table
src/simulator/crates/mc-units/src/action.rs UnitActionDef + ApCostSpec enum + load_action()
src/simulator/crates/mc-units/src/ap.rs cost_for(action,ctx)->Result<ActionCost,ApCostError>
cargo test -p mc-units: ap_cost_dispatch + per_improvement_lookup + all_consumes_remaining (3/3 green)
src/simulator/crates/mc-turn/src/game_state.rs MapUnit.action_points: Option<ActionPoints> field (serde default None, skip_if_none)
src/simulator/crates/mc-turn/src/game_state.rs MapUnit::new() initialises action_points from UnitsCatalog.action_point_capacity
src/simulator/crates/mc-units/src/catalog.rs UnitStats.action_point_capacity: Option<u8> field + parses_action_point_capacity test
src/simulator/crates/mc-turn/src/lib.rs recharge_action_points() — full refill for units ending turn on own city_positions; skips captives and non-AP units
src/simulator/crates/mc-turn/src/processor.rs TurnProcessor::step calls recharge_action_points after refresh_units
cargo test -p mc-turn ap_recharge_tests: 5/5 green (recharges_unit_on_friendly_city_tile, off_city_unit_is_not_recharged, non_ap_unit_untouched, captive_unit_is_skipped, enemy_city_does_not_recharge_us)

Context

public/games/age-of-dwarves/docs/units/SPECIALISTS.md proposes an action-point pool for Pioneer and Engineer instead of a single per-turn action. Tier-scaled capacity — 6 (T1), 10 (T2), 14 (T3) — drives:

  • Pioneer: Found City consumes the entire pool; Prepare Land 2 AP each.
  • Engineer: build/repair improvements 14 AP depending on improvement.
  • Both recharge by entering a friendly city (full refill on a turn ended in-city); idle outside city does not recharge.

This replaces the current binary "did the worker act this turn" model.

Acceptance

  • mc-core::ActionPoints { current: u8, capacity: u8 } newtype in src/simulator/crates/mc-core/src/units.rssrc/simulator/crates/mc-core/src/units.rs:48-119. Companion ActionCost(u8) newtype at units.rs:18-44 and tier-ladder helper pioneer_engineer_ap_capacity at units.rs:121-129.
  • MapUnit carries action_points: Option<ActionPoints> (None for non-AP units). Resolved: the runtime unit type is mc_turn::game_state::MapUnit (not a new mc-units::Unit); spec wording predates the MapUnit decision. Field added at src/simulator/crates/mc-turn/src/game_state.rs with serde default None (saves remain backward-compatible) and MapUnit::new reads UnitsCatalog::get(unit_type).action_point_capacity to spawn the pool full.
  • ✓ Unit JSON under public/resources/units/{pioneer,engineer}*.json declares action_point_capacity. All four engineer tiers and dwarf_founder.json carry the field: tier 1→6, tier 2→10, tier 3→14, tier 8→16. No dwarf_pioneer.json exists; dwarf_founder.json is the current stand-in (tier 2 Veteran Pioneer = 10 AP). Pioneer-specific unit authoring deferred to content ticket.
  • ✓ Action registry public/resources/unit_actions/*.json + Rust resolver. JSON: found_city.json (ap_cost: all), prepare_land.json (ap_cost: 2), build_improvement.json (ap_cost: per-improvement table). Rust: mc-units crate created (src/simulator/crates/mc-units/); UnitActionDef + ApCostSpec in action.rs; cost_for(action, ctx) -> Result<ActionCost, ApCostError> in ap.rs. Tests ap_cost_dispatch, per_improvement_lookup, all_consumes_remaining all green (cargo test -p mc-units — 3/3 passed).
  • mc-turn::processor recharges to capacity on turn-end-in-friendly-city; otherwise no recharge. Implemented as recharge_action_points(state) in src/simulator/crates/mc-turn/src/lib.rs next to refresh_units: walks each player's units, skips captives and non-AP units, and calls ActionPoints::recharge_full when (unit.col, unit.row) is in that player's own city_positions. Wired into TurnProcessor::step at src/simulator/crates/mc-turn/src/processor.rs immediately after crate::refresh_units(state). Five headless tests in ap_recharge_tests cover the on-city refill, off-city no-op, None-pool no-panic, captive skip, and the enemy-city-does-not-recharge-us cross-player guard.
  • cargo test -p mc-core units::tests::test_ap_capacity_tier_ladder, units::tests::test_found_city_consumes_all_ap, units::tests::test_in_city_recharges green — src/simulator/crates/mc-core/src/units.rs:131-188 (also covers test_try_spend_saturates, test_can_afford). End-to-end engineer_recharges_in_city (and the on-city / off-city / captive / enemy-city variants) now live in mc-turn::ap_recharge_tests (5/5 green via cargo test -p mc-turn ap_recharge_tests).

Source-of-truth rails

  • Rust crate: mc-units::action owns AP arithmetic + recharge; mc-turn calls it. No GDScript-side AP counter.
  • JSON path: public/resources/units/*.json (capacity) + public/resources/unit_actions/*.json (ap_cost). Per p1-40 SSoT.
  • mc-core wrapper: ActionPoints newtype — no raw u8 counters across boundaries.

Out of scope

  • Adding AP to military units — single rule, civilians only.
  • Refund-on-cancel UX — single forward consumption.
  • AI scoring of multi-AP turn plans — separate AI ticket.

References

  • public/games/age-of-dwarves/docs/units/SPECIALISTS.md