diff --git a/server/src/game/role/santa_claus.rs b/server/src/game/role/santa_claus.rs index 0d70b540f..32a9b78cc 100644 --- a/server/src/game/role/santa_claus.rs +++ b/server/src/game/role/santa_claus.rs @@ -1,25 +1,19 @@ -use rand::seq::SliceRandom; -use rand::thread_rng; use serde::Serialize; - use crate::game::chat::ChatMessageVariant; use crate::game::components::detained::Detained; use crate::game::game_conclusion::GameConclusion; use crate::game::phase::PhaseType; use crate::game::win_condition::WinCondition; -use crate::game::attack_power::DefensePower; +use crate::game::attack_power::{AttackPower, DefensePower}; use crate::game::player::PlayerReference; - -use crate::game::visit::{Visit, VisitTag}; +use crate::game::visit::Visit; use crate::game::Game; use crate::vec_set::{vec_set, VecSet}; - use super::{AbilitySelection, ControllerID, ControllerParametersMap, Priority, Role, RoleStateImpl}; #[derive(Clone, Debug, Default, Serialize)] #[serde(rename_all = "camelCase")] pub struct SantaClaus { - pub next_ability: SantaListKind, pub ability_used_last_night: Option, } @@ -39,27 +33,28 @@ impl RoleStateImpl for SantaClaus { fn do_night_action(self, game: &mut Game, actor_ref: PlayerReference, priority: Priority) { if priority != Priority::Convert { return } - match self.next_ability { + match self.get_next_santa_ability() { SantaListKind::Nice => { let actor_visits = actor_ref.untagged_night_visits_cloned(game).into_iter(); let targets = actor_visits.map(|v| v.target); for target_ref in targets { + let WinCondition::GameConclusionReached { mut win_if_any } = target_ref.win_condition(game).clone() else { continue }; if !get_eligible_players(game, actor_ref).contains(&target_ref) { continue } - - match target_ref.win_condition(game).clone() { - WinCondition::GameConclusionReached { mut win_if_any } => { - win_if_any.insert(GameConclusion::NiceList); - target_ref.set_win_condition(game, WinCondition::GameConclusionReached { win_if_any }); - - target_ref.push_night_message(game, ChatMessageVariant::AddedToNiceList); - actor_ref.set_role_state(game, Self { - ability_used_last_night: Some(SantaListKind::Nice), - ..self - }); - } - WinCondition::RoleStateWon => {} + + if !AttackPower::ArmorPiercing.can_pierce(target_ref.defense(game)) { + actor_ref.push_night_message(game, ChatMessageVariant::YourConvertFailed); + continue; } + + win_if_any.insert(GameConclusion::NiceList); + target_ref.set_win_condition(game, WinCondition::GameConclusionReached { win_if_any }); + target_ref.push_night_message(game, ChatMessageVariant::AddedToNiceList); + + actor_ref.set_role_state(game, Self { + ability_used_last_night: Some(SantaListKind::Nice), + ..self + }); } } SantaListKind::Naughty => { @@ -67,38 +62,36 @@ impl RoleStateImpl for SantaClaus { let targets = actor_visits.map(|v| v.target); for target_ref in targets { - match target_ref.win_condition(game).clone() { - WinCondition::GameConclusionReached { mut win_if_any } => { - win_if_any.insert(GameConclusion::NaughtyList); - target_ref.set_win_condition(game, WinCondition::GameConclusionReached { win_if_any }); - - - let krampus_list: Vec = PlayerReference::all_players(game) - .filter(|player| player.role(game) == Role::Krampus) - .collect(); - - if !krampus_list.is_empty() { - target_ref.push_night_message(game, ChatMessageVariant::AddedToNaughtyList); - } - for krampus in krampus_list { - krampus.push_night_message(game, - ChatMessageVariant::SantaAddedPlayerToNaughtyList { player: target_ref } - ); - } - actor_ref.set_role_state(game, Self { - ability_used_last_night: Some(SantaListKind::Naughty), - ..self - }); - } - WinCondition::RoleStateWon => {} + let WinCondition::GameConclusionReached { mut win_if_any } = target_ref.win_condition(game).clone() else { continue }; + if !get_eligible_players(game, actor_ref).contains(&target_ref) { continue }; + + if !AttackPower::ArmorPiercing.can_pierce(target_ref.defense(game)) { + actor_ref.push_night_message(game, ChatMessageVariant::YourConvertFailed); + continue; + } + + win_if_any.insert(GameConclusion::NaughtyList); + target_ref.set_win_condition(game, WinCondition::GameConclusionReached { win_if_any }); + target_ref.push_night_message(game, ChatMessageVariant::AddedToNaughtyList); + + actor_ref.set_role_state(game, Self { + ability_used_last_night: Some(SantaListKind::Naughty), + ..self + }); + + for krampus in PlayerReference::all_players(game) { + if krampus.role(game) != Role::Krampus { continue } + + krampus.push_night_message(game, + ChatMessageVariant::SantaAddedPlayerToNaughtyList { player: target_ref } + ); } } } } } - fn controller_parameters_map(self, game: &Game, actor_ref: PlayerReference) -> super::ControllerParametersMap { - match self.next_ability { + match self.get_next_santa_ability() { SantaListKind::Nice => { ControllerParametersMap::new_controller_fast( game, @@ -133,64 +126,34 @@ impl RoleStateImpl for SantaClaus { } } } - fn convert_selection_to_visits(self, game: &Game, actor_ref: PlayerReference) -> Vec { - // Note: Sam, fix this when you fix jester - if !actor_ref.alive(game) { - return vec![]; - } - - match self.next_ability { + fn convert_selection_to_visits(self, game: &Game, actor_ref: PlayerReference) -> Vec { + match self.get_next_santa_ability() { SantaListKind::Nice => { crate::game::role::common_role::convert_controller_selection_to_visits( game, actor_ref, ControllerID::role(actor_ref, Role::SantaClaus, 0), - false, + true, ) } SantaListKind::Naughty => { - let visits = crate::game::role::common_role::convert_controller_selection_to_visits( + crate::game::role::common_role::convert_controller_selection_to_visits( game, actor_ref, ControllerID::role(actor_ref, Role::SantaClaus, 1), - false, - ); - let eligible_targets: Vec = visits.iter() - .map(|v| v.target) - .filter(|t| get_eligible_players(game, actor_ref).contains(t)) - .collect(); - - let mut eligible_options = get_eligible_players(game, actor_ref) - .into_iter() - .filter(|e| !eligible_targets.contains(e)) - .collect::>(); - - eligible_options.shuffle(&mut thread_rng()); - - let mut targets: Vec = eligible_targets.into_iter().chain(eligible_options).collect(); - - targets.truncate(1); - - targets.into_iter() - .map(|target| Visit::new(actor_ref, target, false, VisitTag::Role)) - .collect() + true, + ) } } } fn on_phase_start(self, game: &mut Game, actor_ref: PlayerReference, phase: PhaseType){ - if phase == PhaseType::Obituary || phase == PhaseType::Night { - let mut new_state = self.clone(); - - if let Some(ability) = self.ability_used_last_night { - new_state.next_ability = match ability { - SantaListKind::Naughty => SantaListKind::Nice, - SantaListKind::Nice => SantaListKind::Naughty, - }; - new_state.ability_used_last_night = None; - } - - actor_ref.add_private_chat_message(game, ChatMessageVariant::NextSantaAbility { ability: new_state.next_ability }); - actor_ref.set_role_state(game, new_state); + match phase { + PhaseType::Night => { + actor_ref.add_private_chat_message(game, + ChatMessageVariant::NextSantaAbility { ability: self.get_next_santa_ability() } + ); + }, + _ => {} } } fn default_win_condition(self) -> WinCondition where super::RoleState: From { @@ -198,6 +161,15 @@ impl RoleStateImpl for SantaClaus { } } +impl SantaClaus { + fn get_next_santa_ability(&self)->SantaListKind{ + match self.ability_used_last_night { + Some(SantaListKind::Nice) => SantaListKind::Naughty, + _ => SantaListKind::Nice, + } + } +} + fn get_selectable_players(game: &Game, actor_ref: PlayerReference) -> VecSet { PlayerReference::all_players(game) .filter(|&p|