feat(combat): ✨ Update combat functions to integrate collectible yield system with new rewards during combat
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
5ef36b0cd4
commit
61a49f3fed
2 changed files with 115 additions and 0 deletions
|
|
@ -2,6 +2,7 @@ pub mod bonuses;
|
|||
pub mod keywords;
|
||||
pub mod loot;
|
||||
pub mod promotions;
|
||||
pub mod requirements;
|
||||
pub mod resolver;
|
||||
pub mod siege;
|
||||
pub mod wilds;
|
||||
|
|
@ -20,6 +21,9 @@ pub use resolver::{
|
|||
CombatOutcome, CombatParams, CombatResolver, CombatResult, CombatType, UnitAttributes,
|
||||
UnitStats,
|
||||
};
|
||||
pub use requirements::{
|
||||
check_strategic_reqs, credit_resources, debit_resources, MissingResource,
|
||||
};
|
||||
pub use siege::{melee_wall_penalty, siege_city_bonus, split_ranged_damage_vs_city};
|
||||
pub use wilds::wild_combat_stats;
|
||||
|
||||
|
|
|
|||
111
src/simulator/crates/mc-combat/src/requirements.rs
Normal file
111
src/simulator/crates/mc-combat/src/requirements.rs
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
use std::collections::BTreeMap;
|
||||
|
||||
/// A required strategic resource was not available in the empire ledger.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct MissingResource(pub String);
|
||||
|
||||
impl std::fmt::Display for MissingResource {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "missing strategic resource: {}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `Ok(())` if every required resource has at least one unit in the
|
||||
/// ledger, otherwise `Err(MissingResource)` for the first missing entry.
|
||||
///
|
||||
/// `unit_reqs` is the `requires_resource` list from unit JSON (may be empty).
|
||||
/// `ledger` maps resource ID → stockpile count (decremented on build,
|
||||
/// credited on unit death — see `debit_resource` / `credit_resource`).
|
||||
pub fn check_strategic_reqs(
|
||||
unit_reqs: &[String],
|
||||
ledger: &BTreeMap<String, u32>,
|
||||
) -> Result<(), MissingResource> {
|
||||
for req in unit_reqs {
|
||||
let count = ledger.get(req.as_str()).copied().unwrap_or(0);
|
||||
if count == 0 {
|
||||
return Err(MissingResource(req.clone()));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Deduct one unit of each required resource from the ledger on successful
|
||||
/// build. Saturates at zero (cannot go negative).
|
||||
pub fn debit_resources(unit_reqs: &[String], ledger: &mut BTreeMap<String, u32>) {
|
||||
for req in unit_reqs {
|
||||
let entry = ledger.entry(req.clone()).or_insert(0);
|
||||
*entry = entry.saturating_sub(1);
|
||||
}
|
||||
}
|
||||
|
||||
/// Return one unit of each required resource to the ledger when the unit dies.
|
||||
pub fn credit_resources(unit_reqs: &[String], ledger: &mut BTreeMap<String, u32>) {
|
||||
for req in unit_reqs {
|
||||
*ledger.entry(req.clone()).or_insert(0) += 1;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn ledger(pairs: &[(&str, u32)]) -> BTreeMap<String, u32> {
|
||||
pairs.iter().map(|(k, v)| (k.to_string(), *v)).collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_reqs_always_passes() {
|
||||
assert!(check_strategic_reqs(&[], &BTreeMap::new()).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn missing_resource_returns_err() {
|
||||
let reqs = vec!["iron_ore".to_string()];
|
||||
let result = check_strategic_reqs(&reqs, &BTreeMap::new());
|
||||
assert_eq!(result, Err(MissingResource("iron_ore".to_string())));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn present_resource_returns_ok() {
|
||||
let reqs = vec!["iron_ore".to_string()];
|
||||
let ld = ledger(&[("iron_ore", 2)]);
|
||||
assert!(check_strategic_reqs(&reqs, &ld).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn debit_decrements_ledger() {
|
||||
let reqs = vec!["iron_ore".to_string()];
|
||||
let mut ld = ledger(&[("iron_ore", 3)]);
|
||||
debit_resources(&reqs, &mut ld);
|
||||
assert_eq!(ld["iron_ore"], 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn debit_saturates_at_zero() {
|
||||
let reqs = vec!["iron_ore".to_string()];
|
||||
let mut ld = ledger(&[("iron_ore", 0)]);
|
||||
debit_resources(&reqs, &mut ld);
|
||||
assert_eq!(ld["iron_ore"], 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn golden_build_then_kill_restores_iron() {
|
||||
let reqs = vec!["iron_ore".to_string()];
|
||||
let mut ld = ledger(&[("iron_ore", 1)]);
|
||||
|
||||
// Build cavalry: check then debit
|
||||
assert!(check_strategic_reqs(&reqs, &ld).is_ok());
|
||||
debit_resources(&reqs, &mut ld);
|
||||
assert_eq!(ld["iron_ore"], 0);
|
||||
|
||||
// Unit is now alive, ledger at 0 — another build blocked
|
||||
assert!(check_strategic_reqs(&reqs, &ld).is_err());
|
||||
|
||||
// Unit dies: credit returns the resource
|
||||
credit_resources(&reqs, &mut ld);
|
||||
assert_eq!(ld["iron_ore"], 1);
|
||||
|
||||
// Can build again
|
||||
assert!(check_strategic_reqs(&reqs, &ld).is_ok());
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue