use core::num::NonZeroU8; use serde::{Deserialize, Serialize}; use werewolves_macros::{ChecksAs, Titles}; use crate::{ character::CharacterId, diedto::DiedTo, game::{DateTime, Village}, message::CharacterIdentity, }; #[derive(Debug, PartialEq, Clone, Serialize, Deserialize, ChecksAs, Titles)] pub enum Role { #[checks(Alignment::Village)] Villager, #[checks(Alignment::Wolves)] #[checks("killer")] #[checks("powerful")] Scapegoat { redeemed: bool }, #[checks(Alignment::Village)] #[checks("powerful")] #[checks("is_mentor")] Seer, #[checks(Alignment::Village)] #[checks("powerful")] #[checks("is_mentor")] Arcanist, #[checks(Alignment::Village)] #[checks("powerful")] #[checks("is_mentor")] Adjudicator, #[checks(Alignment::Village)] #[checks("powerful")] #[checks("is_mentor")] PowerSeer, #[checks(Alignment::Village)] #[checks("powerful")] #[checks("is_mentor")] Mortician, #[checks(Alignment::Village)] #[checks("powerful")] #[checks("is_mentor")] Beholder, #[checks(Alignment::Village)] #[checks("powerful")] MasonLeader { recruits_available: u8, recruits: Box<[CharacterId]>, }, #[checks(Alignment::Village)] #[checks("powerful")] Empath { cursed: bool }, #[checks(Alignment::Village)] #[checks("powerful")] #[checks("is_mentor")] Vindicator, #[checks(Alignment::Village)] #[checks("powerful")] #[checks("is_mentor")] Diseased, #[checks(Alignment::Village)] #[checks("powerful")] #[checks("is_mentor")] BlackKnight { attacked: Option }, #[checks(Alignment::Village)] #[checks("powerful")] #[checks("is_mentor")] Weightlifter, #[checks(Alignment::Village)] #[checks("powerful")] #[checks("is_mentor")] PyreMaster { villagers_killed: u8 }, #[checks(Alignment::Village)] #[checks("powerful")] #[checks("is_mentor")] Gravedigger, #[checks(Alignment::Village)] #[checks("killer")] #[checks("powerful")] #[checks("is_mentor")] #[checks] Hunter { target: Option }, #[checks(Alignment::Village)] #[checks("killer")] #[checks("powerful")] #[checks("is_mentor")] Militia { targeted: Option }, #[checks(Alignment::Wolves)] #[checks("killer")] #[checks("powerful")] #[checks("is_mentor")] MapleWolf { last_kill_on_night: u8 }, #[checks(Alignment::Village)] #[checks("powerful")] #[checks("killer")] #[checks("is_mentor")] Guardian { last_protected: Option, }, #[checks(Alignment::Village)] #[checks("powerful")] #[checks("is_mentor")] Protector { last_protected: Option }, #[checks(Alignment::Village)] #[checks("powerful")] Apprentice(RoleTitle), #[checks(Alignment::Village)] #[checks("powerful")] #[checks("is_mentor")] Elder { knows_on_night: NonZeroU8, woken_for_reveal: bool, lost_protection_night: Option, }, #[checks(Alignment::Village)] #[checks("powerful")] Insomniac, #[checks(Alignment::Wolves)] #[checks("killer")] #[checks("powerful")] #[checks("wolf")] Werewolf, #[checks(Alignment::Wolves)] #[checks("killer")] #[checks("powerful")] #[checks("wolf")] AlphaWolf { killed: Option }, #[checks(Alignment::Village)] #[checks("killer")] #[checks("powerful")] #[checks("wolf")] DireWolf, #[checks(Alignment::Wolves)] #[checks("killer")] #[checks("powerful")] #[checks("wolf")] Shapeshifter { shifted_into: Option }, #[checks(Alignment::Wolves)] #[checks("killer")] #[checks("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 wakes_night_zero(&self) -> bool { match self { Role::Insomniac | Role::PowerSeer | Role::Beholder | Role::Adjudicator | Role::DireWolf | Role::Arcanist | Role::Seer => true, 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.date_time() { DateTime::Day { number: _ } => return false, DateTime::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.date_time() { DateTime::Day { number: _ } => return false, DateTime::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.date_time() { DateTime::Night { number } => number == knows_on_night.get(), _ => false, } } } } } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub enum Alignment { Village, 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), }