use core::{fmt::Display, num::NonZeroU8, ops::Not}; use serde::{Deserialize, Serialize}; use werewolves_macros::{ChecksAs, Titles}; use crate::{ character::CharacterId, diedto::DiedTo, game::{GameTime, Village}, message::CharacterIdentity, }; #[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize, Default)] pub enum Killer { Killer, #[default] NotKiller, } impl Killer { pub const fn killer(&self) -> bool { matches!(self, Killer::Killer) } } impl Display for Killer { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Killer::Killer => f.write_str("Killer"), Killer::NotKiller => f.write_str("Not a Killer"), } } } impl Not for Killer { type Output = Killer; fn not(self) -> Self::Output { match self { Killer::Killer => Killer::NotKiller, Killer::NotKiller => Killer::Killer, } } } #[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize, Default)] pub enum Powerful { Powerful, #[default] NotPowerful, } impl Powerful { pub const fn powerful(&self) -> bool { matches!(self, Powerful::Powerful) } } impl Display for Powerful { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Powerful::Powerful => f.write_str("Powerful"), Powerful::NotPowerful => f.write_str("Not Powerful"), } } } impl Not for Powerful { type Output = Powerful; fn not(self) -> Self::Output { match self { Powerful::Powerful => Powerful::NotPowerful, Powerful::NotPowerful => Powerful::Powerful, } } } #[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)] pub enum AlignmentEq { Same, Different, } impl Not for AlignmentEq { type Output = AlignmentEq; fn not(self) -> Self::Output { match self { AlignmentEq::Same => Self::Different, AlignmentEq::Different => Self::Same, } } } impl AlignmentEq { pub const fn new(same: bool) -> Self { match same { true => Self::Same, false => Self::Different, } } pub const fn same(&self) -> bool { matches!(self, Self::Same) } } #[derive(Debug, PartialEq, Clone, Serialize, Deserialize, ChecksAs, Titles)] pub enum Role { #[checks(Alignment::Village)] #[checks(Killer::NotKiller)] #[checks(Powerful::NotPowerful)] Villager, #[checks(Alignment::Wolves)] #[checks(Killer::Killer)] #[checks(Powerful::Powerful)] Scapegoat { redeemed: bool }, #[checks(Alignment::Village)] #[checks(Powerful::Powerful)] #[checks(Killer::NotKiller)] #[checks("is_mentor")] Seer, #[checks(Alignment::Village)] #[checks(Powerful::Powerful)] #[checks(Killer::NotKiller)] #[checks("is_mentor")] Arcanist, #[checks(Alignment::Village)] #[checks(Powerful::Powerful)] #[checks(Killer::NotKiller)] #[checks("is_mentor")] Adjudicator, #[checks(Alignment::Village)] #[checks(Powerful::Powerful)] #[checks(Killer::NotKiller)] #[checks("is_mentor")] PowerSeer, #[checks(Alignment::Village)] #[checks(Powerful::Powerful)] #[checks(Killer::NotKiller)] #[checks("is_mentor")] Mortician, #[checks(Alignment::Village)] #[checks(Powerful::Powerful)] #[checks(Killer::NotKiller)] #[checks("is_mentor")] Beholder, #[checks(Alignment::Village)] #[checks(Powerful::Powerful)] #[checks(Killer::NotKiller)] MasonLeader { recruits_available: u8, recruits: Box<[CharacterId]>, }, #[checks(Alignment::Village)] #[checks(Powerful::Powerful)] #[checks(Killer::NotKiller)] Empath { cursed: bool }, #[checks(Alignment::Village)] #[checks(Powerful::Powerful)] #[checks(Killer::NotKiller)] #[checks("is_mentor")] Vindicator, #[checks(Alignment::Village)] #[checks(Powerful::Powerful)] #[checks(Killer::NotKiller)] #[checks("is_mentor")] Diseased, #[checks(Alignment::Village)] #[checks(Powerful::Powerful)] #[checks(Killer::NotKiller)] #[checks("is_mentor")] BlackKnight { attacked: Option }, #[checks(Alignment::Village)] #[checks(Powerful::Powerful)] #[checks(Killer::NotKiller)] #[checks("is_mentor")] Weightlifter, #[checks(Alignment::Village)] #[checks(Powerful::Powerful)] #[checks(Killer::Killer)] #[checks("is_mentor")] PyreMaster { villagers_killed: u8 }, #[checks(Alignment::Village)] #[checks(Powerful::Powerful)] #[checks(Killer::NotKiller)] #[checks("is_mentor")] Gravedigger, #[checks(Alignment::Village)] #[checks(Killer::Killer)] #[checks(Powerful::Powerful)] #[checks("is_mentor")] #[checks] Hunter { target: Option }, #[checks(Alignment::Village)] #[checks(Killer::Killer)] #[checks(Powerful::Powerful)] #[checks("is_mentor")] Militia { targeted: Option }, #[checks(Alignment::Wolves)] #[checks(Killer::Killer)] #[checks(Powerful::Powerful)] #[checks("is_mentor")] MapleWolf { last_kill_on_night: u8 }, #[checks(Alignment::Village)] #[checks(Powerful::Powerful)] #[checks(Killer::Killer)] #[checks("is_mentor")] Guardian { last_protected: Option, }, #[checks(Alignment::Village)] #[checks(Powerful::Powerful)] #[checks(Killer::NotKiller)] #[checks("is_mentor")] Protector { last_protected: Option }, #[checks(Alignment::Village)] #[checks(Powerful::Powerful)] #[checks(Killer::NotKiller)] Apprentice(RoleTitle), #[checks(Alignment::Village)] #[checks(Powerful::Powerful)] #[checks(Killer::NotKiller)] #[checks("is_mentor")] Elder { knows_on_night: NonZeroU8, woken_for_reveal: bool, lost_protection_night: Option, }, #[checks(Alignment::Village)] #[checks(Powerful::Powerful)] #[checks(Killer::NotKiller)] Insomniac, #[checks(Alignment::Wolves)] #[checks(Killer::Killer)] #[checks(Powerful::Powerful)] #[checks("wolf")] Werewolf, #[checks(Alignment::Wolves)] #[checks(Killer::Killer)] #[checks(Powerful::Powerful)] #[checks("wolf")] AlphaWolf { killed: Option }, #[checks(Alignment::Village)] #[checks(Killer::Killer)] #[checks(Powerful::Powerful)] #[checks("wolf")] DireWolf { last_blocked: Option }, #[checks(Alignment::Wolves)] #[checks(Killer::Killer)] #[checks(Powerful::Powerful)] #[checks("wolf")] Shapeshifter { shifted_into: Option }, #[checks(Alignment::Wolves)] #[checks(Killer::Killer)] #[checks(Powerful::Powerful)] #[checks("wolf")] LoneWolf, } impl Role { /// [RoleTitle] as shown to the player on role assignment pub const fn initial_shown_role(&self) -> RoleTitle { match self { Role::Apprentice(_) | Role::Elder { .. } | Role::Insomniac => RoleTitle::Villager, _ => self.title(), } } pub const fn killing_wolf_order(&self) -> Option { Some(match self { Role::Villager | Role::Scapegoat { .. } | Role::Seer | Role::Arcanist | Role::Adjudicator | Role::PowerSeer | Role::Mortician | Role::Beholder | Role::MasonLeader { .. } | Role::Empath { .. } | Role::Vindicator | Role::Diseased | Role::BlackKnight { .. } | Role::Weightlifter | Role::PyreMaster { .. } | Role::Gravedigger | Role::Hunter { .. } | Role::Militia { .. } | Role::MapleWolf { .. } | Role::Guardian { .. } | Role::Protector { .. } | Role::Apprentice(..) | Role::Elder { .. } | Role::Insomniac => return None, Role::Werewolf => KillingWolfOrder::Werewolf, Role::AlphaWolf { .. } => KillingWolfOrder::AlphaWolf, Role::DireWolf { .. } => KillingWolfOrder::DireWolf, Role::Shapeshifter { .. } => KillingWolfOrder::Shapeshifter, Role::LoneWolf => KillingWolfOrder::LoneWolf, }) } pub const fn wakes_night_zero(&self) -> bool { match self { Role::PowerSeer | Role::Adjudicator | Role::DireWolf { .. } | Role::Arcanist | Role::Seer => true, Role::Insomniac // has to at least get one good night of sleep, right? | Role::Beholder | Role::LoneWolf | Role::Shapeshifter { .. } | Role::Werewolf | Role::AlphaWolf { .. } | Role::Elder { .. } | Role::Gravedigger | Role::Hunter { .. } | Role::Militia { .. } | Role::MapleWolf { .. } | Role::Guardian { .. } | Role::Apprentice(_) | Role::Villager | Role::Scapegoat { .. } | Role::Mortician | Role::MasonLeader { .. } | Role::Empath { .. } | Role::Vindicator | Role::Diseased | Role::BlackKnight { .. } | Role::Weightlifter | Role::PyreMaster { .. } | Role::Protector { .. } => false, } } pub fn wakes(&self, village: &Village) -> bool { let night_zero = match village.time() { GameTime::Day { number: _ } => return false, GameTime::Night { number } => number == 0, }; if night_zero { return self.wakes_night_zero(); } match self { Role::AlphaWolf { killed: Some(_) } | Role::Werewolf | Role::Scapegoat { redeemed: false } | Role::Militia { targeted: Some(_) } | Role::Diseased | Role::BlackKnight { .. } | Role::Villager => false, Role::LoneWolf => match village.time() { GameTime::Day { number: _ } => return false, GameTime::Night { number } => NonZeroU8::new(number), } .map(|night| village.executions_on_day(night)) .map(|execs| execs.iter().any(|e| e.is_wolf())) .unwrap_or_default(), Role::Insomniac | Role::PowerSeer | Role::Mortician | Role::Beholder | Role::MasonLeader { .. } | Role::Empath { .. } | Role::Vindicator | Role::Weightlifter | Role::PyreMaster { .. } | Role::Adjudicator | Role::Scapegoat { redeemed: true } | Role::Shapeshifter { .. } | Role::DireWolf { .. } | Role::AlphaWolf { killed: None } | Role::Arcanist | Role::Protector { .. } | Role::Gravedigger | Role::Hunter { .. } | Role::Militia { targeted: None } | Role::MapleWolf { .. } | Role::Guardian { .. } | Role::Seer => true, Role::Apprentice(title) => village .characters() .iter() .any(|c| c.role_title() == *title), Role::Elder { knows_on_night, woken_for_reveal, .. } => { !woken_for_reveal && match village.time() { GameTime::Night { number } => number == knows_on_night.get(), _ => false, } } } } } impl RoleTitle { pub fn falsely_appear_village() -> Box<[RoleTitle]> { Self::ALL .iter() .copied() .filter(|r| r.wolf() && r.alignment().village()) .collect() } pub fn falsely_appear_wolf() -> Box<[RoleTitle]> { Self::ALL .iter() .copied() .filter(|r| !r.wolf() && r.alignment().wolves()) .collect() } } #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)] pub enum Alignment { Village, Wolves, } impl Alignment { pub const fn village(&self) -> bool { matches!(self, Alignment::Village) } pub const fn wolves(&self) -> bool { matches!(self, Alignment::Wolves) } } impl Display for Alignment { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Alignment::Village => f.write_str("Village"), Alignment::Wolves => f.write_str("Wolves"), } } } #[derive(Debug, Clone, Serialize, Deserialize, ChecksAs)] pub enum ArcanistCheck { #[checks] Same, #[checks] Different, } pub const MAPLE_WOLF_ABSTAIN_LIMIT: NonZeroU8 = NonZeroU8::new(3).unwrap(); pub const PYREMASTER_VILLAGER_KILLS_TO_DIE: NonZeroU8 = NonZeroU8::new(2).unwrap(); #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub enum RoleBlock { Direwolf, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub enum PreviousGuardianAction { Protect(CharacterIdentity), Guard(CharacterIdentity), } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] pub enum KillingWolfOrder { Werewolf, AlphaWolf, Shapeshifter, Berserker, Psion, Bloodletter, Bloodhound, DireWolf, LoneWolf, }