bloodletter: wip
This commit is contained in:
parent
ad29c3d59c
commit
bdfd4034b9
|
|
@ -0,0 +1,53 @@
|
|||
// 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 <https://www.gnu.org/licenses/>.
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::game::{GameTime, Village};
|
||||
const BLOODLET_DURATION_DAYS: u8 = 2;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Aura {
|
||||
Drunk,
|
||||
Insane,
|
||||
Bloodlet { night: u8 },
|
||||
}
|
||||
|
||||
impl Aura {
|
||||
pub const fn expired(&self, village: &Village) -> bool {
|
||||
match self {
|
||||
Aura::Drunk | Aura::Insane => false,
|
||||
Aura::Bloodlet { night } => match village.time() {
|
||||
GameTime::Day { .. } => false,
|
||||
GameTime::Night { number } => {
|
||||
night.saturating_add(BLOODLET_DURATION_DAYS) >= number
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn refreshes(&self, other: &Aura) -> bool {
|
||||
match (self, other) {
|
||||
(Aura::Bloodlet { .. }, Aura::Bloodlet { .. }) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn refresh(&mut self, other: Aura) {
|
||||
match (self, other) {
|
||||
(Aura::Bloodlet { night }, Aura::Bloodlet { night: new_night }) => *night = new_night,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -22,11 +22,11 @@ use rand::seq::SliceRandom;
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
aura::Aura,
|
||||
diedto::DiedTo,
|
||||
error::GameError,
|
||||
game::{GameTime, Village},
|
||||
message::{CharacterIdentity, Identification, PublicIdentity, night::ActionPrompt},
|
||||
modifier::Modifier,
|
||||
player::{PlayerId, RoleChange},
|
||||
role::{
|
||||
Alignment, Killer, KillingWolfOrder, MAPLE_WOLF_ABSTAIN_LIMIT, Powerful,
|
||||
|
|
@ -59,7 +59,7 @@ pub struct Character {
|
|||
player_id: PlayerId,
|
||||
identity: CharacterIdentity,
|
||||
role: Role,
|
||||
modifier: Option<Modifier>,
|
||||
auras: Vec<Aura>,
|
||||
died_to: Option<DiedTo>,
|
||||
role_changes: Vec<RoleChange>,
|
||||
}
|
||||
|
|
@ -76,19 +76,20 @@ impl Character {
|
|||
},
|
||||
}: Identification,
|
||||
role: Role,
|
||||
auras: Vec<Aura>,
|
||||
) -> Option<Self> {
|
||||
Some(Self {
|
||||
role,
|
||||
auras,
|
||||
player_id,
|
||||
died_to: None,
|
||||
role_changes: Vec::new(),
|
||||
identity: CharacterIdentity {
|
||||
character_id: CharacterId::new(),
|
||||
name,
|
||||
pronouns,
|
||||
number: number?,
|
||||
},
|
||||
player_id,
|
||||
modifier: None,
|
||||
died_to: None,
|
||||
role_changes: Vec::new(),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -298,6 +299,14 @@ impl Character {
|
|||
AsCharacter(char)
|
||||
}
|
||||
|
||||
pub fn apply_aura(&mut self, aura: Aura) {
|
||||
if let Some(existing) = self.auras.iter_mut().find(|aura| aura.refreshes(&aura)) {
|
||||
existing.refresh(aura);
|
||||
} else {
|
||||
self.auras.push(aura);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn night_action_prompts(&self, village: &Village) -> Result<Box<[ActionPrompt]>> {
|
||||
if self.mason_leader().is_ok() {
|
||||
return self.mason_prompts(village);
|
||||
|
|
@ -345,6 +354,11 @@ impl Character {
|
|||
return Ok(Box::new([]));
|
||||
}
|
||||
}
|
||||
Role::Bloodletter => ActionPrompt::Bloodletter {
|
||||
character_id: self.identity(),
|
||||
living_players: village.living_villagers(),
|
||||
marked: None,
|
||||
},
|
||||
Role::Seer => ActionPrompt::Seer {
|
||||
character_id: self.identity(),
|
||||
living_players: village.living_players_excluding(self.character_id()),
|
||||
|
|
|
|||
|
|
@ -71,7 +71,11 @@ impl ActionPrompt {
|
|||
..
|
||||
} => Some(Unless::TargetsBlocked(*marked1, *marked2)),
|
||||
|
||||
ActionPrompt::LoneWolfKill {
|
||||
ActionPrompt::Bloodletter {
|
||||
marked: Some(marked),
|
||||
..
|
||||
}
|
||||
| ActionPrompt::LoneWolfKill {
|
||||
marked: Some(marked),
|
||||
..
|
||||
}
|
||||
|
|
@ -148,7 +152,8 @@ impl ActionPrompt {
|
|||
..
|
||||
} => Some(Unless::TargetBlocked(*marked)),
|
||||
|
||||
ActionPrompt::LoneWolfKill { marked: None, .. }
|
||||
ActionPrompt::Bloodletter { .. }
|
||||
| ActionPrompt::LoneWolfKill { marked: None, .. }
|
||||
| ActionPrompt::Seer { marked: None, .. }
|
||||
| ActionPrompt::Protector { marked: None, .. }
|
||||
| ActionPrompt::Gravedigger { marked: None, .. }
|
||||
|
|
@ -1083,6 +1088,12 @@ impl Night {
|
|||
}
|
||||
}
|
||||
|
||||
/// returns the matching [Character] with the current night's aura changes
|
||||
/// applied
|
||||
fn character_with_current_auras(&self, id: CharacterId) -> Result<Character> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn changes_from_actions(&self) -> Box<[NightChange]> {
|
||||
self.used_actions
|
||||
.iter()
|
||||
|
|
@ -1109,7 +1120,12 @@ impl Night {
|
|||
.then(|| self.village.killing_wolf().map(|c| c.identity()))
|
||||
.flatten(),
|
||||
|
||||
ActionPrompt::Seer {
|
||||
ActionPrompt::Bloodletter {
|
||||
character_id,
|
||||
marked: Some(marked),
|
||||
..
|
||||
}
|
||||
| ActionPrompt::Seer {
|
||||
character_id,
|
||||
marked: Some(marked),
|
||||
..
|
||||
|
|
@ -1200,7 +1216,8 @@ impl Night {
|
|||
..
|
||||
} => (*marked == visit_char).then(|| character_id.clone()),
|
||||
|
||||
ActionPrompt::WolfPackKill { marked: None, .. }
|
||||
ActionPrompt::Bloodletter { .. }
|
||||
| ActionPrompt::WolfPackKill { marked: None, .. }
|
||||
| ActionPrompt::Arcanist { marked: _, .. }
|
||||
| ActionPrompt::LoneWolfKill { marked: None, .. }
|
||||
| ActionPrompt::Seer { marked: None, .. }
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ use serde::{Deserialize, Serialize};
|
|||
use werewolves_macros::Extract;
|
||||
|
||||
use crate::{
|
||||
aura::Aura,
|
||||
character::CharacterId,
|
||||
diedto::DiedTo,
|
||||
player::Protection,
|
||||
|
|
@ -59,6 +60,11 @@ pub enum NightChange {
|
|||
empath: CharacterId,
|
||||
scapegoat: CharacterId,
|
||||
},
|
||||
ApplyAura {
|
||||
source: CharacterId,
|
||||
target: CharacterId,
|
||||
aura: Aura,
|
||||
},
|
||||
}
|
||||
|
||||
pub struct ChangesLookup<'a>(&'a [NightChange], Vec<usize>);
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
use core::num::NonZeroU8;
|
||||
|
||||
use crate::{
|
||||
aura::Aura,
|
||||
diedto::DiedTo,
|
||||
error::GameError,
|
||||
game::night::{
|
||||
|
|
@ -108,6 +109,19 @@ impl Night {
|
|||
};
|
||||
|
||||
match current_prompt {
|
||||
ActionPrompt::Bloodletter {
|
||||
character_id,
|
||||
living_players,
|
||||
marked: Some(marked),
|
||||
} => Ok(ActionComplete {
|
||||
result: ActionResult::GoBackToSleep,
|
||||
change: Some(NightChange::ApplyAura {
|
||||
source: character_id.character_id,
|
||||
aura: Aura::Bloodlet { night: self.night },
|
||||
target: *marked,
|
||||
}),
|
||||
}
|
||||
.into()),
|
||||
ActionPrompt::LoneWolfKill {
|
||||
character_id,
|
||||
marked: Some(marked),
|
||||
|
|
@ -143,7 +157,7 @@ impl Night {
|
|||
marked: Some(marked),
|
||||
..
|
||||
} => {
|
||||
let alignment = self.village.character_by_id(*marked)?.alignment();
|
||||
let alignment = self.character_with_current_auras(*marked)?.alignment();
|
||||
Ok(ResponseOutcome::ActionComplete(ActionComplete {
|
||||
result: ActionResult::Seer(alignment),
|
||||
change: None,
|
||||
|
|
@ -166,8 +180,8 @@ impl Night {
|
|||
marked: (Some(marked1), Some(marked2)),
|
||||
..
|
||||
} => {
|
||||
let same = self.village.character_by_id(*marked1)?.alignment()
|
||||
== self.village.character_by_id(*marked2)?.alignment();
|
||||
let same = self.character_with_current_auras(*marked1)?.alignment()
|
||||
== self.character_with_current_auras(*marked2)?.alignment();
|
||||
|
||||
Ok(ResponseOutcome::ActionComplete(ActionComplete {
|
||||
result: ActionResult::Arcanist(AlignmentEq::new(same)),
|
||||
|
|
@ -178,7 +192,9 @@ impl Night {
|
|||
marked: Some(marked),
|
||||
..
|
||||
} => {
|
||||
let dig_role = self.village.character_by_id(*marked)?.gravedigger_dig();
|
||||
let dig_role = self
|
||||
.character_with_current_auras(*marked)?
|
||||
.gravedigger_dig();
|
||||
Ok(ResponseOutcome::ActionComplete(ActionComplete {
|
||||
result: ActionResult::GraveDigger(dig_role),
|
||||
change: None,
|
||||
|
|
@ -359,7 +375,7 @@ impl Night {
|
|||
..
|
||||
} => Ok(ActionComplete {
|
||||
result: ActionResult::Adjudicator {
|
||||
killer: self.village.character_by_id(*marked)?.killer(),
|
||||
killer: self.character_with_current_auras(*marked)?.killer(),
|
||||
},
|
||||
change: None,
|
||||
}
|
||||
|
|
@ -369,7 +385,7 @@ impl Night {
|
|||
..
|
||||
} => Ok(ActionComplete {
|
||||
result: ActionResult::PowerSeer {
|
||||
powerful: self.village.character_by_id(*marked)?.powerful(),
|
||||
powerful: self.character_with_current_auras(*marked)?.powerful(),
|
||||
},
|
||||
change: None,
|
||||
}
|
||||
|
|
@ -489,7 +505,8 @@ impl Night {
|
|||
}
|
||||
.into()),
|
||||
|
||||
ActionPrompt::Adjudicator { marked: None, .. }
|
||||
ActionPrompt::Bloodletter { marked: None, .. }
|
||||
| ActionPrompt::Adjudicator { marked: None, .. }
|
||||
| ActionPrompt::PowerSeer { marked: None, .. }
|
||||
| ActionPrompt::Mortician { marked: None, .. }
|
||||
| ActionPrompt::Beholder { marked: None, .. }
|
||||
|
|
|
|||
|
|
@ -23,10 +23,10 @@ use uuid::Uuid;
|
|||
use werewolves_macros::{All, ChecksAs, Titles};
|
||||
|
||||
use crate::{
|
||||
aura::Aura,
|
||||
character::Character,
|
||||
error::GameError,
|
||||
message::Identification,
|
||||
modifier::Modifier,
|
||||
player::PlayerId,
|
||||
role::{Role, RoleTitle},
|
||||
};
|
||||
|
|
@ -127,6 +127,8 @@ pub enum SetupRole {
|
|||
Shapeshifter,
|
||||
#[checks(Category::Wolves)]
|
||||
LoneWolf,
|
||||
#[checks(Category::Wolves)]
|
||||
Bloodletter,
|
||||
|
||||
#[checks(Category::Intel)]
|
||||
Adjudicator,
|
||||
|
|
@ -157,6 +159,7 @@ pub enum SetupRole {
|
|||
impl SetupRoleTitle {
|
||||
pub fn into_role(self) -> Role {
|
||||
match self {
|
||||
SetupRoleTitle::Bloodletter => Role::Bloodletter,
|
||||
SetupRoleTitle::Insomniac => Role::Insomniac,
|
||||
SetupRoleTitle::LoneWolf => Role::LoneWolf,
|
||||
SetupRoleTitle::Villager => Role::Villager,
|
||||
|
|
@ -208,6 +211,7 @@ impl SetupRoleTitle {
|
|||
impl Display for SetupRole {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(match self {
|
||||
SetupRole::Bloodletter => "Bloodletter",
|
||||
SetupRole::Insomniac => "Insomniac",
|
||||
SetupRole::LoneWolf => "Lone Wolf",
|
||||
SetupRole::Villager => "Villager",
|
||||
|
|
@ -244,6 +248,7 @@ impl Display for SetupRole {
|
|||
impl SetupRole {
|
||||
pub fn into_role(self, roles_in_game: &[RoleTitle]) -> Result<Role, GameError> {
|
||||
Ok(match self {
|
||||
Self::Bloodletter => Role::Bloodletter,
|
||||
SetupRole::Insomniac => Role::Insomniac,
|
||||
SetupRole::LoneWolf => Role::LoneWolf,
|
||||
SetupRole::Villager => Role::Villager,
|
||||
|
|
@ -321,6 +326,7 @@ impl From<SetupRole> for RoleTitle {
|
|||
impl From<RoleTitle> for SetupRole {
|
||||
fn from(value: RoleTitle) -> Self {
|
||||
match value {
|
||||
RoleTitle::Bloodletter => SetupRole::Bloodletter,
|
||||
RoleTitle::Insomniac => SetupRole::Insomniac,
|
||||
RoleTitle::LoneWolf => SetupRole::LoneWolf,
|
||||
RoleTitle::Villager => SetupRole::Villager,
|
||||
|
|
@ -373,7 +379,7 @@ impl SlotId {
|
|||
pub struct SetupSlot {
|
||||
pub slot_id: SlotId,
|
||||
pub role: SetupRole,
|
||||
pub modifiers: Vec<Modifier>,
|
||||
pub auras: Vec<Aura>,
|
||||
pub assign_to: Option<PlayerId>,
|
||||
pub created_order: u32,
|
||||
}
|
||||
|
|
@ -384,7 +390,7 @@ impl SetupSlot {
|
|||
created_order,
|
||||
assign_to: None,
|
||||
role: title.into(),
|
||||
modifiers: Vec::new(),
|
||||
auras: Vec::new(),
|
||||
slot_id: SlotId::new(),
|
||||
}
|
||||
}
|
||||
|
|
@ -394,8 +400,12 @@ impl SetupSlot {
|
|||
ident: Identification,
|
||||
roles_in_game: &[RoleTitle],
|
||||
) -> Result<Character, GameError> {
|
||||
Character::new(ident.clone(), self.role.into_role(roles_in_game)?)
|
||||
.ok_or(GameError::PlayerNotAssignedNumber(ident.to_string()))
|
||||
Character::new(
|
||||
ident.clone(),
|
||||
self.role.into_role(roles_in_game)?,
|
||||
self.auras,
|
||||
)
|
||||
.ok_or(GameError::PlayerNotAssignedNumber(ident.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -199,11 +199,23 @@ pub enum StoryActionPrompt {
|
|||
Insomniac {
|
||||
character_id: CharacterId,
|
||||
},
|
||||
BloodLetter {
|
||||
character_id: CharacterId,
|
||||
chosen: CharacterId,
|
||||
},
|
||||
}
|
||||
|
||||
impl StoryActionPrompt {
|
||||
pub fn new(prompt: ActionPrompt) -> Option<Self> {
|
||||
Some(match prompt {
|
||||
ActionPrompt::Bloodletter {
|
||||
character_id,
|
||||
marked: Some(marked),
|
||||
..
|
||||
} => Self::BloodLetter {
|
||||
character_id: character_id.character_id,
|
||||
chosen: marked,
|
||||
},
|
||||
ActionPrompt::Seer {
|
||||
character_id,
|
||||
marked: Some(marked),
|
||||
|
|
@ -378,7 +390,8 @@ impl StoryActionPrompt {
|
|||
character_id: character_id.character_id,
|
||||
},
|
||||
|
||||
ActionPrompt::Protector { .. }
|
||||
ActionPrompt::Bloodletter { .. }
|
||||
| ActionPrompt::Protector { .. }
|
||||
| ActionPrompt::Gravedigger { .. }
|
||||
| ActionPrompt::Hunter { .. }
|
||||
| ActionPrompt::Militia { .. }
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ use serde::{Deserialize, Serialize};
|
|||
|
||||
use super::Result;
|
||||
use crate::{
|
||||
aura::Aura,
|
||||
character::{Character, CharacterId},
|
||||
diedto::DiedTo,
|
||||
error::GameError,
|
||||
|
|
@ -294,6 +295,7 @@ impl Village {
|
|||
impl RoleTitle {
|
||||
pub fn title_to_role_excl_apprentice(self) -> Role {
|
||||
match self {
|
||||
RoleTitle::Bloodletter => Role::Bloodletter,
|
||||
RoleTitle::Insomniac => Role::Insomniac,
|
||||
RoleTitle::LoneWolf => Role::LoneWolf,
|
||||
RoleTitle::Villager => Role::Villager,
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
use core::num::NonZeroU8;
|
||||
|
||||
use crate::{
|
||||
aura::Aura,
|
||||
diedto::DiedTo,
|
||||
error::GameError,
|
||||
game::{
|
||||
|
|
@ -52,6 +53,10 @@ impl Village {
|
|||
let mut new_village = self.clone();
|
||||
for change in all_changes {
|
||||
match change {
|
||||
NightChange::ApplyAura { target, aura, .. } => {
|
||||
let target = new_village.character_by_id_mut(*target)?;
|
||||
target.apply_aura(*aura);
|
||||
}
|
||||
NightChange::ElderReveal { elder } => {
|
||||
new_village.character_by_id_mut(*elder)?.elder_reveal()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#![allow(clippy::new_without_default)]
|
||||
|
||||
pub mod aura;
|
||||
pub mod character;
|
||||
pub mod diedto;
|
||||
pub mod error;
|
||||
|
|
@ -21,7 +22,6 @@ pub mod game;
|
|||
#[cfg(test)]
|
||||
mod game_test;
|
||||
pub mod message;
|
||||
pub mod modifier;
|
||||
pub mod nonzero;
|
||||
pub mod player;
|
||||
pub mod role;
|
||||
|
|
|
|||
|
|
@ -203,6 +203,12 @@ pub enum ActionPrompt {
|
|||
},
|
||||
#[checks(ActionType::Insomniac)]
|
||||
Insomniac { character_id: CharacterIdentity },
|
||||
#[checks(ActionType::OtherWolf)]
|
||||
Bloodletter {
|
||||
character_id: CharacterIdentity,
|
||||
living_players: Box<[CharacterIdentity]>,
|
||||
marked: Option<CharacterId>,
|
||||
},
|
||||
}
|
||||
|
||||
impl ActionPrompt {
|
||||
|
|
@ -230,6 +236,7 @@ impl ActionPrompt {
|
|||
| ActionPrompt::Empath { character_id, .. }
|
||||
| ActionPrompt::Vindicator { character_id, .. }
|
||||
| ActionPrompt::PyreMaster { character_id, .. }
|
||||
| ActionPrompt::Bloodletter { character_id, .. }
|
||||
| ActionPrompt::DireWolf { character_id, .. } => Some(character_id.character_id),
|
||||
|
||||
ActionPrompt::WolvesIntro { .. }
|
||||
|
|
@ -241,6 +248,7 @@ impl ActionPrompt {
|
|||
pub(crate) fn matches_beholding(&self, target: CharacterId) -> bool {
|
||||
match self {
|
||||
ActionPrompt::Insomniac { character_id, .. }
|
||||
| ActionPrompt::Bloodletter { character_id, .. }
|
||||
| ActionPrompt::Seer { character_id, .. }
|
||||
| ActionPrompt::Arcanist { character_id, .. }
|
||||
| ActionPrompt::Gravedigger { character_id, .. }
|
||||
|
|
@ -344,7 +352,12 @@ impl ActionPrompt {
|
|||
Ok(prompt)
|
||||
}
|
||||
|
||||
ActionPrompt::LoneWolfKill {
|
||||
ActionPrompt::Bloodletter {
|
||||
living_players: targets,
|
||||
marked,
|
||||
..
|
||||
}
|
||||
| ActionPrompt::LoneWolfKill {
|
||||
living_players: targets,
|
||||
marked,
|
||||
..
|
||||
|
|
|
|||
|
|
@ -1,21 +0,0 @@
|
|||
// 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 <https://www.gnu.org/licenses/>.
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Modifier {
|
||||
Drunk,
|
||||
Insane,
|
||||
}
|
||||
|
|
@ -271,6 +271,11 @@ pub enum Role {
|
|||
#[checks(Powerful::Powerful)]
|
||||
#[checks("wolf")]
|
||||
LoneWolf,
|
||||
#[checks(Alignment::Wolves)]
|
||||
#[checks(Killer::Killer)]
|
||||
#[checks(Powerful::Powerful)]
|
||||
#[checks("wolf")]
|
||||
Bloodletter,
|
||||
}
|
||||
|
||||
impl Role {
|
||||
|
|
@ -313,6 +318,7 @@ impl Role {
|
|||
|
||||
Role::Werewolf => KillingWolfOrder::Werewolf,
|
||||
Role::AlphaWolf { .. } => KillingWolfOrder::AlphaWolf,
|
||||
Role::BloodLetter { .. } => KillingWolfOrder::Bloodletter,
|
||||
Role::DireWolf { .. } => KillingWolfOrder::DireWolf,
|
||||
Role::Shapeshifter { .. } => KillingWolfOrder::Shapeshifter,
|
||||
Role::LoneWolf => KillingWolfOrder::LoneWolf,
|
||||
|
|
@ -325,7 +331,7 @@ impl Role {
|
|||
| Role::Adjudicator
|
||||
| Role::DireWolf { .. }
|
||||
| Role::Arcanist
|
||||
| Role::Seer => true,
|
||||
| Role::Seer | Role::BloodLetter => true,
|
||||
|
||||
Role::Insomniac // has to at least get one good night of sleep, right?
|
||||
| Role::Beholder
|
||||
|
|
@ -400,6 +406,7 @@ impl Role {
|
|||
| Role::Militia { targeted: None }
|
||||
| Role::MapleWolf { .. }
|
||||
| Role::Guardian { .. }
|
||||
| Role::BloodLetter { .. }
|
||||
| Role::Seer => true,
|
||||
|
||||
Role::Apprentice(title) => village
|
||||
|
|
|
|||
Loading…
Reference in New Issue