// Copyright (C) 2025 Emilis Bliūdžius
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
use core::{num::NonZeroU8, ops::Not};
use super::Result;
use crate::{
character::CharacterId,
diedto::DiedTo,
error::GameError,
game::{Village, night::changes::ChangesLookup},
player::Protection,
};
#[derive(Debug, PartialEq)]
pub enum KillOutcome {
Single(CharacterId, DiedTo),
Guarding {
original_killer: CharacterId,
original_target: CharacterId,
original_kill: DiedTo,
guardian: CharacterId,
night: NonZeroU8,
},
}
impl KillOutcome {
pub fn apply_to_village(self, village: &mut Village) -> Result<()> {
match self {
KillOutcome::Single(character_id, died_to) => {
village.character_by_id_mut(character_id)?.kill(died_to);
Ok(())
}
KillOutcome::Guarding {
original_killer,
original_target,
original_kill,
guardian,
night,
} => {
// check if guardian exists before we mutably borrow killer, which would
// prevent us from borrowing village to check after.
village.character_by_id(guardian)?;
village
.character_by_id_mut(original_killer)?
.kill(DiedTo::GuardianProtecting {
night,
source: guardian,
protecting: original_target,
protecting_from: original_killer,
protecting_from_cause: Box::new(original_kill.clone()),
});
village.character_by_id_mut(guardian)?.kill(original_kill);
Ok(())
}
}
}
}
fn resolve_protection(
killer: CharacterId,
killed_with: &DiedTo,
target: CharacterId,
protection: &Protection,
night: NonZeroU8,
) -> Option {
match protection {
Protection::Guardian {
source,
guarding: true,
} => Some(KillOutcome::Guarding {
original_killer: killer,
guardian: *source,
original_target: target,
original_kill: killed_with.clone(),
night,
}),
Protection::Guardian {
source: _,
guarding: false,
}
| Protection::Vindicator { .. }
| Protection::Protector { source: _ } => None,
}
}
pub fn resolve_kill(
changes: &mut ChangesLookup<'_>,
target: CharacterId,
died_to: &DiedTo,
night: u8,
village: &Village,
) -> Result