werewolves/werewolves-proto/src/role.rs

192 lines
5.3 KiB
Rust
Raw Normal View History

use core::num::NonZeroU8;
use serde::{Deserialize, Serialize};
use werewolves_macros::{ChecksAs, Titles};
use crate::{
game::{DateTime, Village},
message::CharacterIdentity,
player::CharacterId,
};
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, ChecksAs, Titles)]
pub enum Role {
#[checks(Alignment::Village)]
Villager,
#[checks(Alignment::Wolves)]
#[checks("killer")]
#[checks("powerful")]
2025-10-04 17:50:29 +01:00
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")]
Gravedigger,
#[checks(Alignment::Village)]
#[checks("killer")]
#[checks("powerful")]
#[checks("is_mentor")]
#[checks]
Hunter { target: Option<CharacterId> },
#[checks(Alignment::Village)]
#[checks("killer")]
#[checks("powerful")]
#[checks("is_mentor")]
Militia { targeted: Option<CharacterId> },
#[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<PreviousGuardianAction>,
},
#[checks(Alignment::Village)]
#[checks("powerful")]
#[checks("is_mentor")]
Protector { last_protected: Option<CharacterId> },
#[checks(Alignment::Village)]
#[checks("powerful")]
2025-10-04 17:50:29 +01:00
Apprentice(RoleTitle),
#[checks(Alignment::Village)]
#[checks("powerful")]
#[checks("is_mentor")]
2025-10-04 17:50:29 +01:00
Elder {
knows_on_night: NonZeroU8,
woken_for_reveal: bool,
lost_protection_night: Option<NonZeroU8>,
2025-10-04 17:50:29 +01:00
},
#[checks(Alignment::Wolves)]
#[checks("killer")]
#[checks("powerful")]
#[checks("wolf")]
Werewolf,
#[checks(Alignment::Wolves)]
#[checks("killer")]
#[checks("powerful")]
#[checks("wolf")]
AlphaWolf { killed: Option<CharacterId> },
#[checks(Alignment::Village)]
#[checks("killer")]
#[checks("powerful")]
#[checks("wolf")]
DireWolf,
#[checks(Alignment::Wolves)]
#[checks("killer")]
#[checks("powerful")]
#[checks("wolf")]
Shapeshifter { shifted_into: Option<CharacterId> },
}
impl Role {
/// [RoleTitle] as shown to the player on role assignment
pub const fn initial_shown_role(&self) -> RoleTitle {
match self {
2025-10-04 17:50:29 +01:00
Role::Apprentice(_) | Role::Elder { .. } => RoleTitle::Villager,
_ => self.title(),
}
}
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 match self {
Role::DireWolf | Role::Arcanist | Role::Seer => true,
2025-10-04 17:50:29 +01:00
Role::Shapeshifter { .. }
| Role::Werewolf
2025-10-04 17:50:29 +01:00
| Role::AlphaWolf { .. }
| Role::Elder { .. }
| Role::Gravedigger
2025-10-04 17:50:29 +01:00
| Role::Hunter { .. }
| Role::Militia { .. }
| Role::MapleWolf { .. }
| Role::Guardian { .. }
| Role::Apprentice(_)
| Role::Villager
2025-10-04 17:50:29 +01:00
| Role::Scapegoat { .. }
| Role::Protector { .. } => false,
};
}
match self {
Role::AlphaWolf { killed: Some(_) }
| Role::Werewolf
2025-10-04 17:50:29 +01:00
| Role::Scapegoat { redeemed: false }
| Role::Militia { targeted: Some(_) }
| Role::Villager => false,
2025-10-04 17:50:29 +01:00
Role::Scapegoat { redeemed: true }
| Role::Shapeshifter { .. }
| Role::DireWolf
| Role::AlphaWolf { killed: None }
| Role::Arcanist
2025-10-04 17:50:29 +01:00
| Role::Protector { .. }
| Role::Gravedigger
2025-10-04 17:50:29 +01:00
| Role::Hunter { .. }
| Role::Militia { targeted: None }
2025-10-04 17:50:29 +01:00
| Role::MapleWolf { .. }
| Role::Guardian { .. }
| Role::Seer => true,
2025-10-04 17:50:29 +01:00
Role::Apprentice(title) => village
.characters()
.iter()
2025-10-04 17:50:29 +01:00
.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();
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum RoleBlock {
Direwolf,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum PreviousGuardianAction {
Protect(CharacterIdentity),
Guard(CharacterIdentity),
}