use serde::{Deserialize, Serialize};
use crate::types::*;
use crate::combat::types::{Wound, WoundSeverity};
pub fn gunshot_wound() -> Wound {
Wound {
id: InjuryId::new("gunshot"),
name: "Gunshot Wound".to_string(),
description: "Bullet lodged or grazed. Accuracy and speed reduced.".to_string(),
penalties: vec![
super::types::StatPenalty { stat: "accuracy".to_string(), amount: -10 },
super::types::StatPenalty { stat: "speed".to_string(), amount: -2 },
],
treatable: true,
severity: WoundSeverity::Major,
}
}
pub fn blunt_trauma() -> Wound {
Wound {
id: InjuryId::new("blunt_trauma"),
name: "Blunt Trauma".to_string(),
description: "Took a hard hit. Nerve and speed reduced.".to_string(),
penalties: vec![
super::types::StatPenalty { stat: "nerve".to_string(), amount: -5 },
super::types::StatPenalty { stat: "speed".to_string(), amount: -1 },
],
treatable: true,
severity: WoundSeverity::Minor,
}
}
pub fn exhaustion() -> Wound {
Wound {
id: InjuryId::new("exhaustion"),
name: "Exhaustion".to_string(),
description: "Running on fumes. All stats slightly reduced.".to_string(),
penalties: vec![
super::types::StatPenalty { stat: "accuracy".to_string(), amount: -5 },
super::types::StatPenalty { stat: "speed".to_string(), amount: -1 },
super::types::StatPenalty { stat: "nerve".to_string(), amount: -3 },
],
treatable: true,
severity: WoundSeverity::Minor,
}
}
pub fn nerve_shock() -> Wound {
Wound {
id: InjuryId::new("nerve_shock"),
name: "Nerve Shock".to_string(),
description: "Seen too much. Nerve max reduced until treated.".to_string(),
penalties: vec![
super::types::StatPenalty { stat: "nerve".to_string(), amount: -8 },
],
treatable: true,
severity: WoundSeverity::Major,
}
}
pub fn recover_wound(wounds: &mut Vec<Wound>, wound_idx: usize, ada_present: bool) -> bool {
if !ada_present {
return false;
}
if wound_idx >= wounds.len() {
return false;
}
if !wounds[wound_idx].treatable {
return false;
}
wounds.remove(wound_idx);
true
}
pub fn rest_recovery(wounds: &mut Vec<Wound>) -> Option<InjuryId> {
let idx = wounds.iter().position(|w| {
w.treatable && w.severity == WoundSeverity::Minor
});
idx.map(|i| {
let healed = wounds.remove(i);
healed.id
})
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TriageResult {
pub healed: Vec<InjuryId>,
pub hp_restored: i32,
pub nerve_restored: i32,
pub time_cost: i32,
}
pub fn triage(wounds: &[Wound], thorough: bool) -> TriageResult {
let mut healed = Vec::new();
let mut hp_restored = 0;
let mut nerve_restored = 0;
let mut time_cost = 0;
for wound in wounds {
if wound.treatable {
healed.push(wound.id.clone());
for penalty in &wound.penalties {
match penalty.stat.as_str() {
"nerve" => nerve_restored += penalty.amount.abs(),
_ => hp_restored += 5, }
}
time_cost += if thorough { 2 } else { 1 };
}
}
if thorough {
hp_restored = (hp_restored as f32 * 1.5) as i32;
nerve_restored = (nerve_restored as f32 * 1.5) as i32;
}
TriageResult { healed, hp_restored, nerve_restored, time_cost }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn recover_wound_with_ada() {
let mut wounds = vec![gunshot_wound(), exhaustion()];
assert!(recover_wound(&mut wounds, 0, true));
assert_eq!(wounds.len(), 1);
assert_eq!(wounds[0].id.0, "exhaustion");
}
#[test]
fn recover_wound_without_ada_fails() {
let mut wounds = vec![gunshot_wound()];
assert!(!recover_wound(&mut wounds, 0, false));
assert_eq!(wounds.len(), 1);
}
#[test]
fn recover_wound_out_of_bounds() {
let mut wounds = vec![gunshot_wound()];
assert!(!recover_wound(&mut wounds, 5, true));
assert_eq!(wounds.len(), 1);
}
#[test]
fn recover_wound_untreatable() {
let mut wounds = vec![Wound {
id: InjuryId::new("permanent_scar"),
name: "Permanent Scar".to_string(),
description: "This never heals.".to_string(),
penalties: vec![],
treatable: false,
severity: WoundSeverity::Major,
}];
assert!(!recover_wound(&mut wounds, 0, true));
assert_eq!(wounds.len(), 1);
}
#[test]
fn rest_recovery_heals_oldest_minor() {
let mut wounds = vec![gunshot_wound(), exhaustion(), blunt_trauma()];
let healed = rest_recovery(&mut wounds);
assert_eq!(healed, Some(InjuryId::new("exhaustion")));
assert_eq!(wounds.len(), 2);
assert_eq!(wounds[0].id.0, "gunshot");
assert_eq!(wounds[1].id.0, "blunt_trauma");
}
#[test]
fn rest_recovery_skips_major_wounds() {
let mut wounds = vec![gunshot_wound(), nerve_shock()];
let healed = rest_recovery(&mut wounds);
assert_eq!(healed, None);
assert_eq!(wounds.len(), 2);
}
#[test]
fn rest_recovery_empty_wounds() {
let mut wounds: Vec<Wound> = vec![];
let healed = rest_recovery(&mut wounds);
assert_eq!(healed, None);
}
}