promps/pages/results for a bunch of roles

This commit is contained in:
emilis 2025-10-13 23:29:10 +01:00
parent 2075f07bb7
commit 00617afe7b
No known key found for this signature in database
55 changed files with 3999 additions and 830 deletions

View File

@ -250,7 +250,7 @@ impl Character {
.is_empty() .is_empty()
.not() .not()
.then_some(ActionPrompt::MasonsWake { .then_some(ActionPrompt::MasonsWake {
leader: self.character_id(), leader: self.identity(),
masons: recruits.clone(), masons: recruits.clone(),
}) })
.into_iter() .into_iter()
@ -396,9 +396,20 @@ impl Character {
living_villagers: village.living_players_excluding(self.character_id()), living_villagers: village.living_players_excluding(self.character_id()),
marked: None, marked: None,
}, },
Role::DireWolf => ActionPrompt::DireWolf { Role::DireWolf {
last_blocked: Some(last_blocked),
} => ActionPrompt::DireWolf {
character_id: self.identity(), character_id: self.identity(),
living_players: village.living_players(), living_players: village
.living_players_excluding(self.character_id())
.into_iter()
.filter(|c| c.character_id != *last_blocked)
.collect(),
marked: None,
},
Role::DireWolf { .. } => ActionPrompt::DireWolf {
character_id: self.identity(),
living_players: village.living_players_excluding(self.character_id()),
marked: None, marked: None,
}, },
Role::Shapeshifter { shifted_into: None } => ActionPrompt::Shapeshifter { Role::Shapeshifter { shifted_into: None } => ActionPrompt::Shapeshifter {
@ -718,6 +729,28 @@ impl Character {
} }
} }
pub const fn direwolf<'a>(&'a self) -> Result<Direwolf<'a>> {
let title = self.role.title();
match &self.role {
Role::DireWolf { last_blocked } => Ok(Direwolf(last_blocked)),
_ => Err(GameError::InvalidRole {
expected: RoleTitle::DireWolf,
got: title,
}),
}
}
pub const fn direwolf_mut<'a>(&'a mut self) -> Result<DirewolfMut<'a>> {
let title = self.role.title();
match &mut self.role {
Role::DireWolf { last_blocked } => Ok(DirewolfMut(last_blocked)),
_ => Err(GameError::InvalidRole {
expected: RoleTitle::DireWolf,
got: title,
}),
}
}
pub const fn initial_shown_role(&self) -> RoleTitle { pub const fn initial_shown_role(&self) -> RoleTitle {
self.role.initial_shown_role() self.role.initial_shown_role()
} }
@ -758,6 +791,7 @@ decl_ref_and_mut!(
Empath, EmpathMut: bool; Empath, EmpathMut: bool;
BlackKnight, BlackKnightMut: Option<DiedTo>; BlackKnight, BlackKnightMut: Option<DiedTo>;
Guardian, GuardianMut: Option<PreviousGuardianAction>; Guardian, GuardianMut: Option<PreviousGuardianAction>;
Direwolf, DirewolfMut: Option<CharacterId>;
); );
pub struct BlackKnightKill<'a> { pub struct BlackKnightKill<'a> {

View File

@ -169,7 +169,7 @@ impl SetupRoleTitle {
}, },
SetupRoleTitle::Werewolf => Role::Werewolf, SetupRoleTitle::Werewolf => Role::Werewolf,
SetupRoleTitle::AlphaWolf => Role::AlphaWolf { killed: None }, SetupRoleTitle::AlphaWolf => Role::AlphaWolf { killed: None },
SetupRoleTitle::DireWolf => Role::DireWolf, SetupRoleTitle::DireWolf => Role::DireWolf { last_blocked: None },
SetupRoleTitle::Shapeshifter => Role::Shapeshifter { shifted_into: None }, SetupRoleTitle::Shapeshifter => Role::Shapeshifter { shifted_into: None },
SetupRoleTitle::Adjudicator => Role::Adjudicator, SetupRoleTitle::Adjudicator => Role::Adjudicator,
SetupRoleTitle::PowerSeer => Role::PowerSeer, SetupRoleTitle::PowerSeer => Role::PowerSeer,
@ -269,7 +269,7 @@ impl SetupRole {
}, },
SetupRole::Werewolf => Role::Werewolf, SetupRole::Werewolf => Role::Werewolf,
SetupRole::AlphaWolf => Role::AlphaWolf { killed: None }, SetupRole::AlphaWolf => Role::AlphaWolf { killed: None },
SetupRole::DireWolf => Role::DireWolf, SetupRole::DireWolf => Role::DireWolf { last_blocked: None },
SetupRole::Shapeshifter => Role::Shapeshifter { shifted_into: None }, SetupRole::Shapeshifter => Role::Shapeshifter { shifted_into: None },
SetupRole::MasonLeader { recruits_available } => Role::MasonLeader { SetupRole::MasonLeader { recruits_available } => Role::MasonLeader {
recruits_available: recruits_available.get(), recruits_available: recruits_available.get(),

View File

@ -292,7 +292,7 @@ impl StoryActionPrompt {
chosen: marked, chosen: marked,
}, },
ActionPrompt::MasonsWake { leader, masons } => Self::MasonsWake { ActionPrompt::MasonsWake { leader, masons } => Self::MasonsWake {
leader, leader: leader.character_id,
masons: masons.into_iter().map(|c| c.character_id).collect(), masons: masons.into_iter().map(|c| c.character_id).collect(),
}, },
ActionPrompt::MasonLeaderRecruit { ActionPrompt::MasonLeaderRecruit {
@ -413,6 +413,19 @@ impl GameStory {
Ok(()) Ok(())
} }
pub fn final_village(&self) -> Result<Village> {
let mut village = self.starting_village.clone();
for (_, actions) in self.iter() {
village = match actions {
GameActions::DayDetails(day_details) => village.with_day_changes(day_details)?,
GameActions::NightDetails(night_details) => {
village.with_night_changes(&night_details.changes)?
}
};
}
Ok(village)
}
pub fn village_at(&self, at_time: GameTime) -> Result<Option<Village>> { pub fn village_at(&self, at_time: GameTime) -> Result<Option<Village>> {
let mut village = self.starting_village.clone(); let mut village = self.starting_village.clone();
for (time, actions) in self.iter() { for (time, actions) in self.iter() {

View File

@ -299,7 +299,7 @@ impl RoleTitle {
}, },
RoleTitle::Werewolf => Role::Werewolf, RoleTitle::Werewolf => Role::Werewolf,
RoleTitle::AlphaWolf => Role::AlphaWolf { killed: None }, RoleTitle::AlphaWolf => Role::AlphaWolf { killed: None },
RoleTitle::DireWolf => Role::DireWolf, RoleTitle::DireWolf => Role::DireWolf { last_blocked: None },
RoleTitle::Shapeshifter => Role::Shapeshifter { shifted_into: None }, RoleTitle::Shapeshifter => Role::Shapeshifter { shifted_into: None },
RoleTitle::Protector => Role::Protector { RoleTitle::Protector => Role::Protector {
last_protected: None, last_protected: None,

View File

@ -9,7 +9,7 @@ use crate::{
story::DayDetail, story::DayDetail,
}, },
player::Protection, player::Protection,
role::{PYREMASTER_VILLAGER_KILLS_TO_DIE, PreviousGuardianAction, RoleTitle}, role::{PYREMASTER_VILLAGER_KILLS_TO_DIE, PreviousGuardianAction, RoleBlock, RoleTitle},
}; };
type Result<T> = core::result::Result<T, GameError>; type Result<T> = core::result::Result<T, GameError>;
@ -100,7 +100,18 @@ impl Village {
}); });
} }
NightChange::RoleBlock { .. } | NightChange::Protection { .. } => {} NightChange::RoleBlock {
source,
target,
block_type: RoleBlock::Direwolf,
} => {
new_village
.character_by_id_mut(*source)?
.direwolf_mut()?
.replace(*target);
}
NightChange::Protection { .. } => {}
NightChange::MasonRecruit { NightChange::MasonRecruit {
mason_leader, mason_leader,
recruiting, recruiting,

View File

@ -217,14 +217,14 @@ impl ActionResultExt for ActionResult {
fn arcanist(&self) -> bool { fn arcanist(&self) -> bool {
match self { match self {
ActionResult::Arcanist(same) => same.same(), ActionResult::Arcanist(same) => same.same(),
_ => panic!("expected an arcanist result"), resp => panic!("expected an arcanist result, got {resp:?}"),
} }
} }
fn insomniac(&self) -> Visits { fn insomniac(&self) -> Visits {
match self { match self {
ActionResult::Insomniac(v) => v.clone(), ActionResult::Insomniac(v) => v.clone(),
_ => panic!("expected an insomniac result"), resp => panic!("expected an insomniac result, got {resp:?}"),
} }
} }
} }
@ -298,9 +298,13 @@ pub trait GameExt {
#[allow(unused)] #[allow(unused)]
fn get_state(&mut self) -> ServerToHostMessage; fn get_state(&mut self) -> ServerToHostMessage;
fn next_expect_game_over(&mut self) -> GameOver; fn next_expect_game_over(&mut self) -> GameOver;
fn prev(&mut self) -> ServerToHostMessage;
} }
impl GameExt for Game { impl GameExt for Game {
fn prev(&mut self) -> ServerToHostMessage {
self.process(HostGameMessage::PreviousState).unwrap()
}
fn next_expect_game_over(&mut self) -> GameOver { fn next_expect_game_over(&mut self) -> GameOver {
match self match self
.process(HostGameMessage::Night( .process(HostGameMessage::Night(

View File

@ -1,13 +1,20 @@
use core::num::NonZeroU8;
#[allow(unused)] #[allow(unused)]
use pretty_assertions::{assert_eq, assert_ne, assert_str_eq}; use pretty_assertions::{assert_eq, assert_ne, assert_str_eq};
use crate::{ use crate::{
game::{Game, GameSettings, GameState, SetupRole}, diedto::DiedToTitle,
game_test::{ActionPromptTitleExt, ActionResultExt, GameExt, SettingsExt, gen_players}, game::{Game, GameSettings, GameState, OrRandom, SetupRole},
game_test::{
ActionPromptTitleExt, ActionResultExt, GameExt, SettingsExt, gen_players, init_log,
},
message::{ message::{
Identification, PublicIdentity,
host::ServerToHostMessage, host::ServerToHostMessage,
night::{ActionPrompt, ActionPromptTitle, ActionResponse}, night::{ActionPrompt, ActionPromptTitle, ActionResponse},
}, },
player::PlayerId,
role::RoleTitle, role::RoleTitle,
}; };
@ -125,3 +132,258 @@ fn previous_shapeshifter_undone_and_changed_to_no() {
&[] &[]
); );
} }
#[test]
fn previous_prompt() {
init_log();
let players = (1..32u8)
.filter_map(NonZeroU8::new)
.map(|n| Identification {
player_id: PlayerId::from_u128(n.get() as _),
public: PublicIdentity {
name: format!("Player {n}"),
pronouns: Some("he/him".into()),
number: Some(n),
},
})
.collect::<Box<[_]>>();
let mut players_iter = players.iter().map(|p| p.player_id);
let (
werewolf,
dire_wolf,
shapeshifter,
alpha_wolf,
seer,
arcanist,
maple_wolf,
guardian,
vindicator,
adjudicator,
power_seer,
beholder,
gravedigger,
mortician,
insomniac,
empath,
scapegoat,
hunter,
) = (
(SetupRole::Werewolf, players_iter.next().unwrap()),
(SetupRole::DireWolf, players_iter.next().unwrap()),
(SetupRole::Shapeshifter, players_iter.next().unwrap()),
(SetupRole::AlphaWolf, players_iter.next().unwrap()),
(SetupRole::Seer, players_iter.next().unwrap()),
(SetupRole::Arcanist, players_iter.next().unwrap()),
(SetupRole::MapleWolf, players_iter.next().unwrap()),
(SetupRole::Guardian, players_iter.next().unwrap()),
(SetupRole::Vindicator, players_iter.next().unwrap()),
(SetupRole::Adjudicator, players_iter.next().unwrap()),
(SetupRole::PowerSeer, players_iter.next().unwrap()),
(SetupRole::Beholder, players_iter.next().unwrap()),
(SetupRole::Gravedigger, players_iter.next().unwrap()),
(SetupRole::Mortician, players_iter.next().unwrap()),
(SetupRole::Insomniac, players_iter.next().unwrap()),
(SetupRole::Empath, players_iter.next().unwrap()),
(
SetupRole::Scapegoat {
redeemed: OrRandom::Determined(false),
},
players_iter.next().unwrap(),
),
(SetupRole::Hunter, players_iter.next().unwrap()),
);
let mut settings = GameSettings::empty();
settings.add_and_assign(werewolf.0, werewolf.1);
settings.add_and_assign(dire_wolf.0, dire_wolf.1);
settings.add_and_assign(shapeshifter.0, shapeshifter.1);
settings.add_and_assign(alpha_wolf.0, alpha_wolf.1);
settings.add_and_assign(seer.0, seer.1);
settings.add_and_assign(arcanist.0, arcanist.1);
settings.add_and_assign(maple_wolf.0, maple_wolf.1);
settings.add_and_assign(guardian.0, guardian.1);
settings.add_and_assign(vindicator.0, vindicator.1);
settings.add_and_assign(adjudicator.0, adjudicator.1);
settings.add_and_assign(power_seer.0, power_seer.1);
settings.add_and_assign(beholder.0, beholder.1);
settings.add_and_assign(gravedigger.0, gravedigger.1);
settings.add_and_assign(mortician.0, mortician.1);
settings.add_and_assign(insomniac.0, insomniac.1);
settings.add_and_assign(empath.0, empath.1);
settings.add_and_assign(scapegoat.0, scapegoat.1);
settings.add_and_assign(hunter.0, hunter.1);
settings.fill_remaining_slots_with_villagers(players.len());
let (
werewolf,
dire_wolf,
shapeshifter,
alpha_wolf,
seer,
arcanist,
maple_wolf,
guardian,
vindicator,
adjudicator,
power_seer,
beholder,
gravedigger,
mortician,
insomniac,
empath,
scapegoat,
hunter,
) = (
werewolf.1,
dire_wolf.1,
shapeshifter.1,
alpha_wolf.1,
seer.1,
arcanist.1,
maple_wolf.1,
guardian.1,
vindicator.1,
adjudicator.1,
power_seer.1,
beholder.1,
gravedigger.1,
mortician.1,
insomniac.1,
empath.1,
scapegoat.1,
hunter.1,
);
let mut game = Game::new(&players, settings).unwrap();
game.r#continue().r#continue();
game.next().title().wolves_intro();
game.r#continue().r#continue();
game.next().title().direwolf();
game.mark(game.character_by_player_id(seer).character_id());
game.r#continue().sleep();
game.next().title().seer();
game.mark(game.character_by_player_id(werewolf).character_id());
game.r#continue().seer();
game.next().title().arcanist();
game.mark(game.character_by_player_id(seer).character_id());
game.mark(game.character_by_player_id(werewolf).character_id());
game.r#continue().role_blocked();
game.next().title().adjudicator();
game.mark(game.character_by_player_id(werewolf).character_id());
game.r#continue().adjudicator();
game.next().title().power_seer();
match game.prev() {
ServerToHostMessage::ActionPrompt(
ActionPrompt::Adjudicator {
character_id,
marked: Some(mark),
..
},
_,
) => {
assert_eq!(
character_id,
game.character_by_player_id(adjudicator).identity()
);
assert_eq!(mark, game.character_by_player_id(werewolf).character_id());
}
resp => panic!("expected adjudicator prompt, got {resp:?}"),
}
match game.prev() {
ServerToHostMessage::ActionPrompt(
ActionPrompt::Arcanist {
character_id,
marked: (Some(mark1), Some(mark2)),
..
},
_,
) => {
assert_eq!(
character_id,
game.character_by_player_id(arcanist).identity()
);
assert_eq!(mark1, game.character_by_player_id(seer).character_id());
assert_eq!(mark2, game.character_by_player_id(werewolf).character_id());
}
resp => panic!("expected arcanist prompt, got {resp:?}"),
}
game.r#continue().role_blocked();
game.next().title().adjudicator();
game.r#continue().adjudicator();
game.next().title().power_seer();
game.mark(game.character_by_player_id(werewolf).character_id());
game.r#continue().power_seer();
game.next().title().beholder();
game.mark(game.character_by_player_id(arcanist).character_id());
game.r#continue().role_blocked();
game.next_expect_day();
game.mark_for_execution(game.character_by_player_id(dire_wolf).character_id());
game.mark_for_execution(game.character_by_player_id(alpha_wolf).character_id());
game.execute().title().guardian();
let protect = game.living_villager();
game.mark(protect.character_id());
game.r#continue().sleep();
game.next().title().wolf_pack_kill();
game.mark(protect.character_id());
game.r#continue().r#continue();
game.next().title().shapeshifter();
game.response(ActionResponse::Shapeshift).sleep();
game.next().title().seer();
game.mark(game.character_by_player_id(werewolf).character_id());
game.r#continue().seer();
game.next().title().arcanist();
game.mark(game.character_by_player_id(seer).character_id());
game.mark(game.character_by_player_id(werewolf).character_id());
game.r#continue().arcanist();
game.next().title().adjudicator();
game.mark(game.character_by_player_id(seer).character_id());
game.r#continue().adjudicator();
game.next().title().power_seer();
game.mark(game.living_villager().character_id());
game.r#continue().power_seer();
game.next().title().gravedigger();
game.mark(game.character_by_player_id(dire_wolf).character_id());
assert_eq!(game.r#continue().gravedigger(), Some(RoleTitle::DireWolf));
game.next().title().mortician();
game.mark(game.character_by_player_id(dire_wolf).character_id());
assert_eq!(game.r#continue().mortician(), DiedToTitle::Execution);
game.next().title().empath();
game.mark(game.living_villager().character_id());
assert!(!game.r#continue().empath());
game.next().title().maple_wolf();
game.mark(
game.living_villager_excl(protect.player_id())
.character_id(),
);
game.r#continue().sleep();
game.next().title().hunter();
game.mark(game.character_by_player_id(insomniac).character_id());
game.r#continue().sleep();
game.next().title().insomniac();
game.r#continue().insomniac();
game.next().title().beholder();
game.mark(game.character_by_player_id(power_seer).character_id());
game.r#continue().power_seer();
game.next_expect_day();
}

View File

@ -47,7 +47,7 @@ fn recruits_decrement() {
ActionPrompt::MasonsWake { ActionPrompt::MasonsWake {
leader: game leader: game
.character_by_player_id(mason_leader_player_id) .character_by_player_id(mason_leader_player_id)
.character_id(), .identity(),
masons: Box::new([ masons: Box::new([
game.character_by_player_id(mason_leader_player_id) game.character_by_player_id(mason_leader_player_id)
.identity(), .identity(),
@ -105,7 +105,7 @@ fn dies_recruiting_wolf() {
ActionPrompt::MasonsWake { ActionPrompt::MasonsWake {
leader: game leader: game
.character_by_player_id(mason_leader_player_id) .character_by_player_id(mason_leader_player_id)
.character_id(), .identity(),
masons: Box::new([game masons: Box::new([game
.character_by_player_id(mason_leader_player_id) .character_by_player_id(mason_leader_player_id)
.identity()]) .identity()])
@ -165,7 +165,7 @@ fn masons_wake_even_if_leader_died() {
ActionPrompt::MasonsWake { ActionPrompt::MasonsWake {
leader: game leader: game
.character_by_player_id(mason_leader_player_id) .character_by_player_id(mason_leader_player_id)
.character_id(), .identity(),
masons: Box::new([ masons: Box::new([
game.character_by_player_id(mason_leader_player_id) game.character_by_player_id(mason_leader_player_id)
.identity(), .identity(),
@ -192,7 +192,7 @@ fn masons_wake_even_if_leader_died() {
ActionPrompt::MasonsWake { ActionPrompt::MasonsWake {
leader: game leader: game
.character_by_player_id(mason_leader_player_id) .character_by_player_id(mason_leader_player_id)
.character_id(), .identity(),
masons: Box::new([ masons: Box::new([
game.character_by_player_id(black_knight_player_id) game.character_by_player_id(black_knight_player_id)
.identity(), .identity(),
@ -220,7 +220,7 @@ fn masons_wake_even_if_leader_died() {
ActionPrompt::MasonsWake { ActionPrompt::MasonsWake {
leader: game leader: game
.character_by_player_id(mason_leader_player_id) .character_by_player_id(mason_leader_player_id)
.character_id(), .identity(),
masons: Box::new([ masons: Box::new([
game.character_by_player_id(black_knight_player_id) game.character_by_player_id(black_knight_player_id)
.identity(), .identity(),

View File

@ -137,7 +137,7 @@ pub enum ActionPrompt {
}, },
#[checks(ActionType::MasonsWake)] #[checks(ActionType::MasonsWake)]
MasonsWake { MasonsWake {
leader: CharacterId, leader: CharacterIdentity,
masons: Box<[CharacterIdentity]>, masons: Box<[CharacterIdentity]>,
}, },
#[checks(ActionType::MasonRecruit)] #[checks(ActionType::MasonRecruit)]

View File

@ -248,7 +248,7 @@ pub enum Role {
#[checks(Killer::Killer)] #[checks(Killer::Killer)]
#[checks(Powerful::Powerful)] #[checks(Powerful::Powerful)]
#[checks("wolf")] #[checks("wolf")]
DireWolf, DireWolf { last_blocked: Option<CharacterId> },
#[checks(Alignment::Wolves)] #[checks(Alignment::Wolves)]
#[checks(Killer::Killer)] #[checks(Killer::Killer)]
#[checks(Powerful::Powerful)] #[checks(Powerful::Powerful)]
@ -299,7 +299,7 @@ impl Role {
Role::Werewolf => KillingWolfOrder::Werewolf, Role::Werewolf => KillingWolfOrder::Werewolf,
Role::AlphaWolf { .. } => KillingWolfOrder::AlphaWolf, Role::AlphaWolf { .. } => KillingWolfOrder::AlphaWolf,
Role::DireWolf => KillingWolfOrder::DireWolf, Role::DireWolf { .. } => KillingWolfOrder::DireWolf,
Role::Shapeshifter { .. } => KillingWolfOrder::Shapeshifter, Role::Shapeshifter { .. } => KillingWolfOrder::Shapeshifter,
Role::LoneWolf => KillingWolfOrder::LoneWolf, Role::LoneWolf => KillingWolfOrder::LoneWolf,
}) })
@ -311,7 +311,7 @@ impl Role {
| Role::PowerSeer | Role::PowerSeer
| Role::Beholder | Role::Beholder
| Role::Adjudicator | Role::Adjudicator
| Role::DireWolf | Role::DireWolf { .. }
| Role::Arcanist | Role::Arcanist
| Role::Seer => true, | Role::Seer => true,
@ -377,7 +377,7 @@ impl Role {
| Role::Adjudicator | Role::Adjudicator
| Role::Scapegoat { redeemed: true } | Role::Scapegoat { redeemed: true }
| Role::Shapeshifter { .. } | Role::Shapeshifter { .. }
| Role::DireWolf | Role::DireWolf { .. }
| Role::AlphaWolf { killed: None } | Role::AlphaWolf { killed: None }
| Role::Arcanist | Role::Arcanist
| Role::Protector { .. } | Role::Protector { .. }

View File

@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="18.946421mm"
height="18.95406mm"
viewBox="0 0 18.946421 18.95406"
version="1.1"
id="svg1"
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
sodipodi:docname="icons.svg"
xml:space="preserve"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="true"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
showgrid="false"
inkscape:zoom="1.4142136"
inkscape:cx="233.34524"
inkscape:cy="503.81359"
inkscape:window-width="1918"
inkscape:window-height="1042"
inkscape:window-x="0"
inkscape:window-y="17"
inkscape:window-maximized="0"
inkscape:current-layer="layer4"><inkscape:grid
id="grid1"
units="mm"
originx="-81.683493"
originy="-164.22112"
spacingx="0.26458333"
spacingy="0.26458334"
empcolor="#0099e5"
empopacity="0.30196078"
color="#0099e5"
opacity="0.14901961"
empspacing="5"
enabled="true"
visible="false" /><inkscape:page
x="0"
y="0"
width="18.946421"
height="18.95406"
id="page2"
margin="0"
bleed="0" /></sodipodi:namedview><defs
id="defs1" /><g
inkscape:groupmode="layer"
id="layer4"
inkscape:label="Layer 4"
transform="translate(-81.683494,-164.22111)"><path
sodipodi:type="star"
style="fill:#8cff91;fill-opacity:0.697629;stroke:#ccffcc;stroke-width:0.548;stroke-dasharray:none;stroke-opacity:0.698625"
id="path3"
inkscape:flatsided="false"
sodipodi:sides="6"
sodipodi:cx="109.63396"
sodipodi:cy="232.73831"
sodipodi:r1="8.0361061"
sodipodi:r2="7.7416453"
sodipodi:arg1="-2.0943951"
sodipodi:arg2="-2.9866062"
inkscape:rounded="0.5"
inkscape:randomized="0"
d="m 105.6159,225.77884 c -1.22761,-3.17739 -7.037083,5.76416 -3.63079,5.76442 6.50663,5e-4 7.58314,-0.69893 11.6669,-5.76442 2.13789,-2.65184 -8.51045,-3.21222 -6.80753,-0.26215 3.25288,5.63516 4.39686,6.21772 10.82558,7.22162 3.36551,0.52555 -1.47336,-8.97637 -3.17673,-6.02657 -3.25375,5.63466 -3.18628,6.91666 -0.84132,12.98604 1.22761,3.17739 7.03709,-5.76416 3.6308,-5.76442 -6.50664,-4.9e-4 -7.58314,0.69893 -11.66691,5.76442 -2.13789,2.65184 8.51046,3.21222 6.80754,0.26216 -3.25289,-5.63516 -4.39687,-6.21773 -10.82559,-7.22163 -3.365501,-0.52555 1.47337,8.97638 3.17674,6.02657 3.25374,-5.63466 3.18627,-6.91665 0.84131,-12.98604 z"
inkscape:transform-center-x="-0.32847244"
inkscape:transform-center-y="-0.29842497"
transform="translate(-18.477247,-59.040163)"
inkscape:export-filename="diseased.svg"
inkscape:export-xdpi="900.08"
inkscape:export-ydpi="900.08" /></g></svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -2,9 +2,9 @@
<!-- Created with Inkscape (http://www.inkscape.org/) --> <!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg <svg
width="14.519332mm" width="20.907848mm"
height="14.518607mm" height="24.813328mm"
viewBox="0 0 14.519332 14.518607" viewBox="0 0 20.907848 24.813328"
version="1.1" version="1.1"
id="svg1" id="svg1"
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)" inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
@ -23,20 +23,33 @@
inkscape:pagecheckerboard="true" inkscape:pagecheckerboard="true"
inkscape:deskcolor="#d1d1d1" inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm" inkscape:document-units="mm"
showgrid="true" showgrid="false"
inkscape:zoom="2" inkscape:zoom="1.4142136"
inkscape:cx="92.75" inkscape:cx="233.34524"
inkscape:cy="546.5" inkscape:cy="503.81359"
inkscape:window-width="1918" inkscape:window-width="1918"
inkscape:window-height="1061" inkscape:window-height="1042"
inkscape:window-x="0" inkscape:window-x="0"
inkscape:window-y="17" inkscape:window-y="17"
inkscape:window-maximized="0" inkscape:window-maximized="0"
inkscape:current-layer="layer4"><inkscape:page inkscape:current-layer="layer4"><inkscape:grid
x="-3.6500685e-13" id="grid1"
units="mm"
originx="-94.492683"
originy="-224.65327"
spacingx="0.26458333"
spacingy="0.26458334"
empcolor="#0099e5"
empopacity="0.30196078"
color="#0099e5"
opacity="0.14901961"
empspacing="5"
enabled="true"
visible="false" /><inkscape:page
x="0"
y="0" y="0"
width="14.519333" width="20.907848"
height="14.518607" height="24.813328"
id="page2" id="page2"
margin="0" margin="0"
bleed="0" /></sodipodi:namedview><defs bleed="0" /></sodipodi:namedview><defs
@ -44,10 +57,25 @@
inkscape:groupmode="layer" inkscape:groupmode="layer"
id="layer4" id="layer4"
inkscape:label="Layer 4" inkscape:label="Layer 4"
transform="translate(-81.081288,-167.88827)"><path transform="translate(-94.492686,-224.65327)"><g
id="rect172" id="g10-3"
style="fill:#7f7f7f;fill-opacity:1;stroke:#000000;stroke-width:0.4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal" inkscape:export-filename="../../src/werewolves/werewolves/img/gravedigger.svg"
d="m 94.511966,168.08826 -8.159189,8.15918 -1.539827,-1.53983 -3.324114,3.32339 -0.207549,4.17587 4.176605,-0.20681 3.32375,-3.32376 -1.540192,-1.54019 8.159186,-8.15919 z" /><path inkscape:export-xdpi="900.08"
id="path145-7" inkscape:export-ydpi="900.08"
style="fill:#a0a0a0;fill-opacity:0.5;stroke:#545454;stroke-width:0.232;stroke-dasharray:none;stroke-opacity:0.7" transform="translate(-23.17051,-0.63943083)"><path
d="m 88.300286,169.67427 c -0.48287,0.009 -0.965274,0.0916 -1.420584,0.25373 -1.738714,0.59694 -3.342068,0.9627 -3.03444,4.1274 -0.06576,0.94137 -0.0783,1.89737 0.06408,2.83239 0.07766,0.53633 0.382678,1.09991 0.888836,1.32446 0.446178,0.0891 0.985208,-0.0139 1.31258,0.39223 0.88847,0.68196 0.349966,2.06997 1.028362,1.973 0.4264,-0.0609 0.136174,-0.73886 0.260966,-0.80202 0.192692,-0.0975 0.181336,-0.0608 0.241846,0.18087 0.03243,0.38247 -0.05245,0.69761 0.28112,0.66198 0.550572,-0.0588 0.28691,-0.48129 0.328144,-0.95808 0.0732,-0.0163 0.08707,-0.0125 0.0894,-0.0114 h 5.18e-4 c 0.0023,-0.001 0.01617,-0.005 0.0894,0.0114 0.04123,0.47679 -0.222428,0.89925 0.328144,0.95808 0.333568,0.0356 0.248694,-0.27951 0.28112,-0.66198 0.06051,-0.2417 0.04915,-0.27839 0.241846,-0.18087 0.124792,0.0632 -0.165434,0.74107 0.260966,0.80202 0.678396,0.097 0.139892,-1.29104 1.028362,-1.973 0.327372,-0.40615 0.866402,-0.30311 1.31258,-0.39223 0.506158,-0.22455 0.81169,-0.78813 0.889352,-1.32446 0.14238,-0.93502 0.129318,-1.89102 0.06356,-2.83239 0.307628,-3.1647 -1.295726,-3.53046 -3.03444,-4.1274 -0.45531,-0.16216 -0.937716,-0.24475 -1.420586,-0.25373 -0.0135,0 -0.02664,-1e-4 -0.04031,0 -0.01367,-1e-4 -0.02733,0 -0.04083,0 z m -2.07274,4.18424 c 0.703538,-0.004 1.021816,0.49934 1.094506,0.7059 0.462654,1.11185 -0.373098,1.45665 -1.174088,1.42576 -0.699984,0.0989 -1.258414,0.0508 -1.342554,-1.01286 -0.01001,-0.33209 0.308906,-0.96177 1.096574,-1.08366 0.116648,-0.0235 0.225056,-0.0346 0.325562,-0.0351 z m 4.226614,0 c 0.100506,5.1e-4 0.208914,0.0116 0.325562,0.0351 0.787668,0.12189 1.106584,0.75157 1.096574,1.08366 -0.08414,1.06367 -0.64257,1.11173 -1.342554,1.01286 -0.80099,0.0309 -1.636742,-0.31391 -1.174088,-1.42576 0.07269,-0.20656 0.390968,-0.70943 1.094506,-0.7059 z m -2.113048,2.94194 c 0.215198,0.0216 0.284064,0.38489 0.583426,0.77618 0.276858,0.50031 -0.16476,0.69652 -0.409794,0.48318 -0.146516,-0.11734 -0.171114,-0.12967 -0.173632,-0.13074 -0.0025,0.001 -0.02763,0.0134 -0.17415,0.13074 -0.245034,0.21334 -0.686652,0.0171 -0.409794,-0.48318 0.299362,-0.39129 0.368746,-0.75459 0.583944,-0.77618 z" /></g></svg> id="rect1-3-9-6"
style="fill:#803300;fill-opacity:1;stroke:#441b00;stroke-width:0.860999;stroke-opacity:1"
d="m 124.55133,225.72321 -4,4.95837 v 4.079 l 4,14.53587 h 4.347 l 4,-14.53587 v -4.079 l -4,-4.95837 z"
sodipodi:nodetypes="ccccccccc"
inkscape:export-filename="mortician.svg"
inkscape:export-xdpi="900.08"
inkscape:export-ydpi="900.08" /><path
id="path145-7-2-2-1"
style="fill:#ffffff;fill-opacity:0.5;stroke:#441b00;stroke-width:0.232;stroke-dasharray:none;stroke-opacity:1"
d="m 126.68415,227.8032 c -0.48287,0.009 -0.96527,0.0916 -1.42058,0.25373 -1.73872,0.59694 -3.34207,0.9627 -3.03444,4.1274 -0.0658,0.94137 -0.0783,1.89737 0.0641,2.83239 0.0777,0.53633 0.38267,1.09991 0.88883,1.32446 0.44618,0.0891 0.98521,-0.0139 1.31258,0.39223 0.88847,0.68196 0.34997,2.06997 1.02836,1.973 0.4264,-0.0609 0.13618,-0.73886 0.26097,-0.80202 0.19269,-0.0975 0.18134,-0.0608 0.24185,0.18087 0.0324,0.38247 -0.0524,0.69761 0.28112,0.66198 0.55057,-0.0588 0.28691,-0.48129 0.32814,-0.95808 0.0732,-0.0163 0.0871,-0.0125 0.0894,-0.0114 h 5.2e-4 c 0.002,-0.001 0.0162,-0.005 0.0894,0.0114 0.0412,0.47679 -0.22243,0.89925 0.32814,0.95808 0.33357,0.0356 0.24869,-0.27951 0.28112,-0.66198 0.0605,-0.2417 0.0491,-0.27839 0.24185,-0.18087 0.12479,0.0632 -0.16544,0.74107 0.26096,0.80202 0.6784,0.097 0.13989,-1.29104 1.02836,-1.973 0.32738,-0.40615 0.86641,-0.30311 1.31258,-0.39223 0.50616,-0.22455 0.81169,-0.78813 0.88936,-1.32446 0.14238,-0.93502 0.12931,-1.89102 0.0636,-2.83239 0.30762,-3.1647 -1.29573,-3.53046 -3.03444,-4.1274 -0.45531,-0.16216 -0.93772,-0.24475 -1.42059,-0.25373 -0.0135,0 -0.0266,-1e-4 -0.0403,0 -0.0137,-1e-4 -0.0273,0 -0.0408,0 z m -2.07274,4.18424 c 0.70354,-0.004 1.02182,0.49934 1.09451,0.7059 0.46265,1.11185 -0.3731,1.45665 -1.17409,1.42576 -0.69999,0.0989 -1.25842,0.0508 -1.34256,-1.01286 -0.01,-0.33209 0.30891,-0.96177 1.09658,-1.08366 0.11665,-0.0235 0.22505,-0.0346 0.32556,-0.0351 z m 4.22661,0 c 0.10051,5.1e-4 0.20892,0.0116 0.32556,0.0351 0.78767,0.12189 1.10659,0.75157 1.09658,1.08366 -0.0841,1.06367 -0.64257,1.11173 -1.34256,1.01286 -0.80099,0.0309 -1.63674,-0.31391 -1.17408,-1.42576 0.0727,-0.20656 0.39096,-0.70943 1.0945,-0.7059 z m -2.11305,2.94194 c 0.2152,0.0216 0.28407,0.38489 0.58343,0.77618 0.27686,0.50031 -0.16476,0.69652 -0.40979,0.48318 -0.14652,-0.11734 -0.17112,-0.12967 -0.17364,-0.13074 -0.002,0.001 -0.0276,0.0134 -0.17414,0.13074 -0.24504,0.21334 -0.68666,0.0171 -0.4098,-0.48318 0.29936,-0.39129 0.36875,-0.75459 0.58394,-0.77618 z" /></g><path
id="rect172-2"
style="fill:#7f7f7f;fill-opacity:1;stroke:#000000;stroke-width:0.576;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
d="m 113.83285,228.84782 -11.74921,11.74921 -2.217361,-2.21735 -4.786727,4.78568 -0.298871,6.01325 6.014309,-0.2978 4.7862,-4.78621 -2.21787,-2.21788 11.74922,-11.74924 z"
inkscape:export-filename="../../src/werewolves/werewolves/img/gravedigger.svg"
inkscape:export-xdpi="900.08"
inkscape:export-ydpi="900.08" /></g></svg>

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

@ -2,9 +2,9 @@
<!-- Created with Inkscape (http://www.inkscape.org/) --> <!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg <svg
width="49.5746mm" width="49.480812mm"
height="46.331978mm" height="46.331978mm"
viewBox="0 0 49.5746 46.331978" viewBox="0 0 49.480812 46.331978"
version="1.1" version="1.1"
id="svg1" id="svg1"
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)" inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
@ -23,35 +23,48 @@
inkscape:pagecheckerboard="true" inkscape:pagecheckerboard="true"
inkscape:deskcolor="#d1d1d1" inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm" inkscape:document-units="mm"
showgrid="true" showgrid="false"
inkscape:zoom="1.4142136" inkscape:zoom="0.99999999"
inkscape:cx="290.26733" inkscape:cx="147"
inkscape:cy="686.60068" inkscape:cy="885.50001"
inkscape:window-width="1918" inkscape:window-width="1918"
inkscape:window-height="1061" inkscape:window-height="1042"
inkscape:window-x="0" inkscape:window-x="0"
inkscape:window-y="17" inkscape:window-y="17"
inkscape:window-maximized="0" inkscape:window-maximized="0"
inkscape:current-layer="layer4"><inkscape:page inkscape:current-layer="layer4"><inkscape:grid
x="-1.2367246e-13" id="grid1"
units="mm"
originx="-111.78369"
originy="-150.9173"
spacingx="0.26458333"
spacingy="0.26458334"
empcolor="#0099e5"
empopacity="0.30196078"
color="#0099e5"
opacity="0.14901961"
empspacing="5"
enabled="true"
visible="false" /><inkscape:page
x="0"
y="0" y="0"
width="49.574596" width="49.480812"
height="46.331978" height="46.331978"
id="page2" id="page2"
margin="0" margin="0"
bleed="0" /></sodipodi:namedview><defs bleed="0" /></sodipodi:namedview><defs
id="defs1"><inkscape:path-effect id="defs1"><inkscape:path-effect
effect="mirror_symmetry" effect="mirror_symmetry"
start_point="86.254165,185.51628" start_point="86.207393,185.56305"
end_point="86.385181,235.08332" end_point="86.338409,235.13009"
center_point="86.319673,210.2998" center_point="86.272901,210.34657"
id="path-effect149" id="path-effect149"
is_visible="true" is_visible="true"
lpeversion="1.2" lpeversion="1.2"
lpesatellites="" lpesatellites=""
mode="free" mode="free"
discard_orig_path="false" discard_orig_path="false"
fuse_paths="false" fuse_paths="true"
oposite_fuse="false" oposite_fuse="false"
split_items="false" split_items="false"
split_open="false" split_open="false"
@ -59,14 +72,18 @@
inkscape:groupmode="layer" inkscape:groupmode="layer"
id="layer4" id="layer4"
inkscape:label="Layer 4" inkscape:label="Layer 4"
transform="translate(-61.512867,-189.01705)"><g transform="translate(-111.78369,-150.9173)"><g
id="g151"><path id="g151"
inkscape:export-filename="../../src/werewolves/werewolves/dist/img/heart.svg"
inkscape:export-xdpi="900.08"
inkscape:export-ydpi="900.08"
transform="translate(50.270833,-38.1)"><path
style="fill:#ff2424;fill-opacity:1;stroke:#ff2424;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" style="fill:#ff2424;fill-opacity:1;stroke:#ff2424;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 86.254166,235.08229 c 0,0 -24.302335,-18.46127 -24.606251,-31.8823 -0.126849,-5.60168 4.153389,-12.70855 9.657292,-13.75832 5.852331,-1.11623 14.123929,1.87077 14.932422,9.82265 z m 0.262022,-6.9e-4 c 0,0 24.204402,-18.58949 24.437362,-32.01193 0.0972,-5.60228 -4.22051,-12.68642 -9.72988,-13.70708 -5.858155,-1.08528 -14.113847,1.94541 -14.880292,9.90145 z" d="m 86.254166,235.08229 c 0,0 -24.302335,-18.46127 -24.606251,-31.8823 -0.126849,-5.60168 4.153389,-12.70855 9.657292,-13.75832 5.852331,-1.11623 14.123929,1.87077 14.932422,9.82265 z m 0.168232,-4.4e-4 c 0,0 24.204402,-18.58949 24.437362,-32.01194 0.0972,-5.60227 -4.22051,-12.68641 -9.72989,-13.70707 -5.858145,-1.08528 -14.113837,1.94541 -14.880282,9.90145 z"
id="path148" id="path148"
sodipodi:nodetypes="caacc" sodipodi:nodetypes="caacc"
inkscape:path-effect="#path-effect149" inkscape:original-d="m 86.254166,235.08229 c 0,0 -24.302335,-18.46127 -24.606251,-31.8823 -0.126849,-5.60168 4.153389,-12.70855 9.657292,-13.75832 5.852331,-1.11623 14.123929,1.87077 14.932422,9.82265 z"
inkscape:original-d="m 86.254166,235.08229 c 0,0 -24.302335,-18.46127 -24.606251,-31.8823 -0.126849,-5.60168 4.153389,-12.70855 9.657292,-13.75832 5.852331,-1.11623 14.123929,1.87077 14.932422,9.82265 z" /><path inkscape:path-effect="#path-effect149" /><path
sodipodi:type="star" sodipodi:type="star"
style="fill:#fff001;fill-opacity:1;stroke:#ff2424;stroke-width:0.15;stroke-dasharray:none;stroke-opacity:1" style="fill:#fff001;fill-opacity:1;stroke:#ff2424;stroke-width:0.15;stroke-dasharray:none;stroke-opacity:1"
id="path150" id="path150"
@ -95,4 +112,19 @@
sodipodi:arg2="1.5925996" sodipodi:arg2="1.5925996"
inkscape:rounded="0.5" inkscape:rounded="0.5"
inkscape:randomized="0" inkscape:randomized="0"
d="m 73.525842,205.79755 c -1.802133,1.72521 -2.255654,-1.4788 -4.749977,-1.5277 -2.4873,-0.0488 -3.071191,3.13767 -4.791545,1.34061 -1.725212,-1.80213 1.478793,-2.25565 1.527701,-4.74998 0.04877,-2.4873 -3.137671,-3.07119 -1.340613,-4.79154 1.802133,-1.72521 2.255655,1.47879 4.749978,1.5277 2.487299,0.0488 3.07119,-3.13767 4.791545,-1.34061 1.725212,1.80213 -1.478794,2.25565 -1.527702,4.74997 -0.04877,2.4873 3.137671,3.07119 1.340613,4.79155 z" /></g></g></svg> d="m 73.525842,205.79755 c -1.802133,1.72521 -2.255654,-1.4788 -4.749977,-1.5277 -2.4873,-0.0488 -3.071191,3.13767 -4.791545,1.34061 -1.725212,-1.80213 1.478793,-2.25565 1.527701,-4.74998 0.04877,-2.4873 -3.137671,-3.07119 -1.340613,-4.79154 1.802133,-1.72521 2.255655,1.47879 4.749978,1.5277 2.487299,0.0488 3.07119,-3.13767 4.791545,-1.34061 1.725212,1.80213 -1.478794,2.25565 -1.527702,4.74997 -0.04877,2.4873 3.137671,3.07119 1.340613,4.79155 z" /></g><path
sodipodi:type="star"
style="fill:#7f6500;fill-opacity:1;stroke:#daaf00;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
id="path155-0"
inkscape:flatsided="false"
sodipodi:sides="6"
sodipodi:cx="99.020317"
sodipodi:cy="191.42604"
sodipodi:r1="7.1881213"
sodipodi:r2="4.5083508"
sodipodi:arg1="1.906205"
sodipodi:arg2="1.8672678"
inkscape:rounded="0.5"
inkscape:randomized="0"
d="m 96.65431,198.21361 c -1.309919,0.3028 1.927067,-1.45786 1.048904,-2.4759 -2.111403,-2.44772 -3.538875,-0.60338 -5.744108,-2.96691 -0.917188,-0.98302 2.22608,0.93996 2.668647,-0.32957 1.064081,-3.05239 -1.2469,-3.36644 -0.30264,-6.458 0.392731,-1.28582 0.299014,2.39782 1.619743,2.14633 3.175484,-0.60467 2.291975,-2.76307 5.441464,-3.49109 1.30992,-0.30279 -1.927062,1.45787 -1.0489,2.4759 2.1114,2.44772 3.53888,0.60338 5.74411,2.96691 0.91719,0.98302 -2.22608,-0.93996 -2.66865,0.32957 -1.06408,3.05239 1.2469,3.36645 0.30264,6.458 -0.39273,1.28582 -0.29901,-2.39782 -1.61974,-2.14633 -3.175485,0.60467 -2.291977,2.76307 -5.44147,3.49109 z"
transform="translate(6.9985536,-38.801292)" /></g></svg>

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

View File

@ -23,16 +23,29 @@
inkscape:pagecheckerboard="true" inkscape:pagecheckerboard="true"
inkscape:deskcolor="#d1d1d1" inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm" inkscape:document-units="mm"
showgrid="true" showgrid="false"
inkscape:zoom="0.5" inkscape:zoom="2.8284272"
inkscape:cx="-77" inkscape:cx="35.885668"
inkscape:cy="466" inkscape:cy="411.71291"
inkscape:window-width="1918" inkscape:window-width="1918"
inkscape:window-height="1061" inkscape:window-height="1042"
inkscape:window-x="0" inkscape:window-x="0"
inkscape:window-y="17" inkscape:window-y="17"
inkscape:window-maximized="0" inkscape:window-maximized="0"
inkscape:current-layer="layer4"><inkscape:page inkscape:current-layer="layer4"><inkscape:grid
id="grid1"
units="mm"
originx="-1.6153444"
originy="-96.526486"
spacingx="0.26458333"
spacingy="0.26458334"
empcolor="#0099e5"
empopacity="0.30196078"
color="#0099e5"
opacity="0.14901961"
empspacing="5"
enabled="true"
visible="false" /><inkscape:page
x="0" x="0"
y="0" y="0"
width="24.399992" width="24.399992"
@ -60,85 +73,87 @@
id="layer4" id="layer4"
inkscape:label="Layer 4" inkscape:label="Layer 4"
transform="translate(-1.6153444,-96.526492)"><g transform="translate(-1.6153444,-96.526492)"><g
id="g179"><g id="g166-2"
id="g166-2" inkscape:path-effect="#path-effect166-2"
inkscape:path-effect="#path-effect166-2" style="fill:#ff0707;fill-opacity:0.697154;stroke:#c10000;stroke-width:0.4;stroke-dasharray:none;stroke-opacity:1"
style="fill:#ff0505;fill-opacity:0.7;stroke:#c20000;stroke-width:0.4;stroke-dasharray:none;stroke-opacity:0.5" transform="matrix(1.728,0,0,1.728,-72.928813,-210.62831)"
transform="translate(-36.557573,-76.085222)" inkscape:export-filename="hunter.svg"
inkscape:export-filename="../../src/werewolves/werewolves/img/hunter.svg" inkscape:export-xdpi="900.08"
inkscape:export-xdpi="900.08" inkscape:export-ydpi="900.08"><path
inkscape:export-ydpi="900.08"><path id="path164-8"
id="path164-8" style="fill:#ff0707;fill-opacity:0.697154;stroke:#c10000;stroke-width:0.4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
style="fill:#ff0505;fill-opacity:0.7;stroke:#c20000;stroke-width:0.4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:0.5;paint-order:normal" d="m 50.373047,183.43359 c -1.534096,0.26874 -1.029204,1.24619 -1.832031,2.63672 -0.65564,1.13559 -1.854319,1.39291 -1.029297,2.41211 0.94012,1.1614 1.512735,0.45231 2.861328,0.33008 1.348593,0.12223 1.921208,0.83132 2.861328,-0.33008 0.825022,-1.0192 -0.373657,-1.27652 -1.029297,-2.41211 -0.802827,-1.39053 -0.297935,-2.36798 -1.832031,-2.63672 z"
d="m 50.373047,183.43359 c -1.534096,0.26874 -1.029204,1.24619 -1.832031,2.63672 -0.65564,1.13559 -1.854319,1.39291 -1.029297,2.41211 0.94012,1.1614 1.512735,0.45231 2.861328,0.33008 1.348593,0.12223 1.921208,0.83132 2.861328,-0.33008 0.825022,-1.0192 -0.373657,-1.27652 -1.029297,-2.41211 -0.802827,-1.39053 -0.297935,-2.36798 -1.832031,-2.63672 z" inkscape:original-d="m 50.372741,183.43371 c -1.534096,0.26874 -1.028586,1.24549 -1.831413,2.63602 -0.65564,1.13559 -1.854933,1.39253 -1.029911,2.41173 0.94012,1.1614 1.512731,0.45348 2.861324,0.33125 z" /><path
inkscape:original-d="m 50.372741,183.43371 c -1.534096,0.26874 -1.028586,1.24549 -1.831413,2.63602 -0.65564,1.13559 -1.854933,1.39253 -1.029911,2.41173 0.94012,1.1614 1.512731,0.45348 2.861324,0.33125 z" /><path sodipodi:type="star"
sodipodi:type="star" style="fill:#ff0707;fill-opacity:0.697154;stroke:#c10000;stroke-width:0.4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
style="fill:#ff0505;fill-opacity:0.7;stroke:#c20000;stroke-width:0.4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:0.5;paint-order:normal" id="path165-3"
id="path165-3" inkscape:flatsided="false"
inkscape:flatsided="false" sodipodi:sides="2"
sodipodi:sides="2" sodipodi:cx="51.634216"
sodipodi:cx="51.634216" sodipodi:cy="182.45293"
sodipodi:cy="182.45293" sodipodi:r1="1.3725731"
sodipodi:r1="1.3725731" sodipodi:r2="0.82291079"
sodipodi:r2="0.82291079" sodipodi:arg1="1.1071487"
sodipodi:arg1="1.1071487" sodipodi:arg2="2.677945"
sodipodi:arg2="2.677945" inkscape:rounded="0.5"
inkscape:rounded="0.5" inkscape:randomized="0"
inkscape:randomized="0" d="m 52.24805,183.68059 c -0.715701,0.35785 -0.992017,-0.14395 -1.349867,-0.85965 -0.357851,-0.7157 -0.593501,-1.23783 0.1222,-1.59568 0.715701,-0.35785 0.992017,0.14395 1.349867,0.85965 0.357851,0.7157 0.593501,1.23783 -0.1222,1.59568 z m 5.18186,0 c 0.7157,0.35785 0.992016,-0.14395 1.349867,-0.85965 0.35785,-0.7157 0.5935,-1.23783 -0.122201,-1.59568 -0.715701,-0.35785 -0.992016,0.14395 -1.349867,0.85965 -0.35785,0.7157 -0.5935,1.23783 0.122201,1.59568 z"
d="m 52.24805,183.68059 c -0.715701,0.35785 -0.992017,-0.14395 -1.349867,-0.85965 -0.357851,-0.7157 -0.593501,-1.23783 0.1222,-1.59568 0.715701,-0.35785 0.992017,0.14395 1.349867,0.85965 0.357851,0.7157 0.593501,1.23783 -0.1222,1.59568 z m 5.18186,0 c 0.7157,0.35785 0.992016,-0.14395 1.349867,-0.85965 0.35785,-0.7157 0.5935,-1.23783 -0.122201,-1.59568 -0.715701,-0.35785 -0.992016,0.14395 -1.349867,0.85965 -0.35785,0.7157 -0.5935,1.23783 0.122201,1.59568 z" inkscape:transform-center-x="0.12681959"
inkscape:transform-center-x="0.12681959" inkscape:transform-center-y="0.079724714"
inkscape:transform-center-y="0.079724714" transform="translate(-4.4662386,1.8414355)" /><path
transform="translate(-4.4662386,1.8414355)" /><path sodipodi:type="star"
sodipodi:type="star" style="fill:#ff0707;fill-opacity:0.697154;stroke:#c10000;stroke-width:0.4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
style="fill:#ff0505;fill-opacity:0.7;stroke:#c20000;stroke-width:0.4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:0.5;paint-order:normal" id="path165-6-8"
id="path165-6-8" inkscape:flatsided="false"
inkscape:flatsided="false" sodipodi:sides="2"
sodipodi:sides="2" sodipodi:cx="51.634216"
sodipodi:cx="51.634216" sodipodi:cy="182.45293"
sodipodi:cy="182.45293" sodipodi:r1="1.3725731"
sodipodi:r1="1.3725731" sodipodi:r2="0.82291079"
sodipodi:r2="0.82291079" sodipodi:arg1="1.1071487"
sodipodi:arg1="1.1071487" sodipodi:arg2="2.677945"
sodipodi:arg2="2.677945" inkscape:rounded="0.5"
inkscape:rounded="0.5" inkscape:randomized="0"
inkscape:randomized="0" d="m 52.24805,183.68059 c -0.715701,0.35785 -0.992017,-0.14395 -1.349867,-0.85965 -0.357851,-0.7157 -0.593501,-1.23783 0.1222,-1.59568 0.715701,-0.35785 0.992017,0.14395 1.349867,0.85965 0.357851,0.7157 0.593501,1.23783 -0.1222,1.59568 z m 2.374602,-1.10775 c 0.734072,-0.31847 0.527114,-0.85263 0.208644,-1.5867 -0.31847,-0.73407 -0.567138,-1.25013 -1.30121,-0.93166 -0.734072,0.31847 -0.527114,0.85263 -0.208644,1.5867 0.31847,0.73407 0.567138,1.25013 1.30121,0.93166 z"
d="m 52.24805,183.68059 c -0.715701,0.35785 -0.992017,-0.14395 -1.349867,-0.85965 -0.357851,-0.7157 -0.593501,-1.23783 0.1222,-1.59568 0.715701,-0.35785 0.992017,0.14395 1.349867,0.85965 0.357851,0.7157 0.593501,1.23783 -0.1222,1.59568 z m 2.374602,-1.10775 c 0.734072,-0.31847 0.527114,-0.85263 0.208644,-1.5867 -0.31847,-0.73407 -0.567138,-1.25013 -1.30121,-0.93166 -0.734072,0.31847 -0.527114,0.85263 -0.208644,1.5867 0.31847,0.73407 0.567138,1.25013 1.30121,0.93166 z" inkscape:transform-center-x="0.14863452"
inkscape:transform-center-x="0.14863452" inkscape:transform-center-y="0.01863483"
inkscape:transform-center-y="0.01863483" transform="rotate(25.009099,51.670619,176.27381)" /></g><g
transform="rotate(25.009099,51.670619,176.27381)" /></g><g id="g6"
id="g178"><path inkscape:export-filename="../../src/werewolves/werewolves/img/hunter.svg"
id="path166-0" inkscape:export-xdpi="900.08"
style="fill:#0f07ff;fill-opacity:1;stroke:#05009e;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal" inkscape:export-ydpi="900.08"><path
d="m 13.815426,98.72668 c -5.522776,5e-5 -10.000374,4.47713 -10.000423,9.99991 4.9e-5,5.52277 4.477647,9.99985 10.000423,9.9999 5.522777,-5e-5 9.999857,-4.47713 9.999907,-9.9999 -5e-5,-5.52278 -4.47713,-9.99986 -9.999907,-9.99991 z m 0,1.99988 c 4.418297,-2e-5 8.000047,3.58172 8.000027,8.00003 2e-5,4.4183 -3.58173,8.00004 -8.000027,8.00002 -4.418301,2e-5 -8.000045,-3.58172 -8.000029,-8.00002 -1.6e-5,-4.41831 3.581728,-8.00005 8.000029,-8.00003 z" /><rect id="path166-0"
style="fill:#0f07ff;fill-opacity:1;stroke:#05009e;stroke-width:0.4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal" style="fill:#0f07ff;fill-opacity:0.496669;stroke:#05009e;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
id="rect167-8-0-4" d="m 13.815426,98.72668 c -5.522776,5e-5 -10.000374,4.47713 -10.000423,9.99991 4.9e-5,5.52277 4.477647,9.99985 10.000423,9.9999 5.522777,-5e-5 9.999857,-4.47713 9.999907,-9.9999 -5e-5,-5.52278 -4.47713,-9.99986 -9.999907,-9.99991 z m 0,1.99988 c 4.418297,-2e-5 8.000047,3.58172 8.000027,8.00003 2e-5,4.4183 -3.58173,8.00004 -8.000027,8.00002 -4.418301,2e-5 -8.000045,-3.58172 -8.000029,-8.00002 -1.6e-5,-4.41831 3.581728,-8.00005 8.000029,-8.00003 z" /><rect
width="1.5" style="fill:#0f07ff;fill-opacity:1;stroke:#05009e;stroke-width:0.4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
height="6" id="rect167-8-0-4"
x="-109.47657" width="1.5"
y="19.815336" height="6"
transform="rotate(-90)" x="-109.47657"
ry="0" /><rect y="19.815336"
style="fill:#0f07ff;fill-opacity:1;stroke:#05009e;stroke-width:0.4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal" transform="rotate(-90)"
id="rect167-8-0-9-2" ry="0" /><rect
width="1.5" style="fill:#0f07ff;fill-opacity:1;stroke:#05009e;stroke-width:0.4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
height="6" id="rect167-8-0-9-2"
x="-109.47657" width="1.5"
y="1.8153445" height="6"
transform="rotate(-90)" x="-109.47657"
ry="0" /><rect y="1.8153445"
style="fill:#0f07ff;fill-opacity:1;stroke:#05009e;stroke-width:0.4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal" transform="rotate(-90)"
id="rect167-8-0-1-2" ry="0" /><rect
width="1.5" style="fill:#0f07ff;fill-opacity:1;stroke:#05009e;stroke-width:0.4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
height="6" id="rect167-8-0-1-2"
x="-14.56517" width="1.5"
y="-120.72649" height="6"
transform="scale(-1)" x="-14.56517"
ry="0" /><rect y="-120.72649"
style="fill:#0f07ff;fill-opacity:1;stroke:#05009e;stroke-width:0.4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal" transform="scale(-1)"
id="rect167-8-0-1-7-2" ry="0" /><rect
width="1.5" style="fill:#0f07ff;fill-opacity:1;stroke:#05009e;stroke-width:0.4;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
height="6" id="rect167-8-0-1-7-2"
x="-14.56517" width="1.5"
y="-102.72649" height="6"
transform="scale(-1)" x="-14.56517"
ry="0" /></g></g></g></svg> y="-102.72649"
transform="scale(-1)"
ry="0" /></g></g></svg>

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 8.0 KiB

1458
werewolves/img/icons.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 127 KiB

View File

@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="23.228039mm"
height="25.150064mm"
viewBox="0 0 23.228039 25.150064"
version="1.1"
id="svg1"
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
sodipodi:docname="icons.svg"
xml:space="preserve"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="true"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
showgrid="false"
inkscape:zoom="1.4142136"
inkscape:cx="233.34524"
inkscape:cy="503.81359"
inkscape:window-width="1918"
inkscape:window-height="1042"
inkscape:window-x="0"
inkscape:window-y="17"
inkscape:window-maximized="0"
inkscape:current-layer="layer4"><inkscape:grid
id="grid1"
units="mm"
originx="-138.94072"
originy="-238.20293"
spacingx="0.26458333"
spacingy="0.26458334"
empcolor="#0099e5"
empopacity="0.30196078"
color="#0099e5"
opacity="0.14901961"
empspacing="5"
enabled="true"
visible="false" /><inkscape:page
x="0"
y="0"
width="23.228039"
height="25.150064"
id="page2"
margin="0"
bleed="0" /></sodipodi:namedview><defs
id="defs1" /><g
inkscape:groupmode="layer"
id="layer4"
inkscape:label="Layer 4"
transform="translate(-138.94072,-238.20292)"><g
id="g10-8"
inkscape:export-filename="mortician.svg"
inkscape:export-xdpi="900.08"
inkscape:export-ydpi="900.08"
transform="translate(21.695837,13.62604)"><path
id="rect1-3-9-4"
style="fill:#803300;fill-opacity:1;stroke:#441b00;stroke-width:0.860999;stroke-opacity:1"
d="m 124.55133,225.72321 -4,4.95837 v 4.079 l 4,14.53587 h 4.347 l 4,-14.53587 v -4.079 l -4,-4.95837 z"
sodipodi:nodetypes="ccccccccc"
inkscape:export-filename="mortician.svg"
inkscape:export-xdpi="900.08"
inkscape:export-ydpi="900.08" /><path
id="path145-7-2-2-5"
style="fill:#ffffff;fill-opacity:0.5;stroke:#441b00;stroke-width:0.232;stroke-dasharray:none;stroke-opacity:1"
d="m 126.68415,227.8032 c -0.48287,0.009 -0.96527,0.0916 -1.42058,0.25373 -1.73872,0.59694 -3.34207,0.9627 -3.03444,4.1274 -0.0658,0.94137 -0.0783,1.89737 0.0641,2.83239 0.0777,0.53633 0.38267,1.09991 0.88883,1.32446 0.44618,0.0891 0.98521,-0.0139 1.31258,0.39223 0.88847,0.68196 0.34997,2.06997 1.02836,1.973 0.4264,-0.0609 0.13618,-0.73886 0.26097,-0.80202 0.19269,-0.0975 0.18134,-0.0608 0.24185,0.18087 0.0324,0.38247 -0.0524,0.69761 0.28112,0.66198 0.55057,-0.0588 0.28691,-0.48129 0.32814,-0.95808 0.0732,-0.0163 0.0871,-0.0125 0.0894,-0.0114 h 5.2e-4 c 0.002,-0.001 0.0162,-0.005 0.0894,0.0114 0.0412,0.47679 -0.22243,0.89925 0.32814,0.95808 0.33357,0.0356 0.24869,-0.27951 0.28112,-0.66198 0.0605,-0.2417 0.0491,-0.27839 0.24185,-0.18087 0.12479,0.0632 -0.16544,0.74107 0.26096,0.80202 0.6784,0.097 0.13989,-1.29104 1.02836,-1.973 0.32738,-0.40615 0.86641,-0.30311 1.31258,-0.39223 0.50616,-0.22455 0.81169,-0.78813 0.88936,-1.32446 0.14238,-0.93502 0.12931,-1.89102 0.0636,-2.83239 0.30762,-3.1647 -1.29573,-3.53046 -3.03444,-4.1274 -0.45531,-0.16216 -0.93772,-0.24475 -1.42059,-0.25373 -0.0135,0 -0.0266,-1e-4 -0.0403,0 -0.0137,-1e-4 -0.0273,0 -0.0408,0 z m -2.07274,4.18424 c 0.70354,-0.004 1.02182,0.49934 1.09451,0.7059 0.46265,1.11185 -0.3731,1.45665 -1.17409,1.42576 -0.69999,0.0989 -1.25842,0.0508 -1.34256,-1.01286 -0.01,-0.33209 0.30891,-0.96177 1.09658,-1.08366 0.11665,-0.0235 0.22505,-0.0346 0.32556,-0.0351 z m 4.22661,0 c 0.10051,5.1e-4 0.20892,0.0116 0.32556,0.0351 0.78767,0.12189 1.10659,0.75157 1.09658,1.08366 -0.0841,1.06367 -0.64257,1.11173 -1.34256,1.01286 -0.80099,0.0309 -1.63674,-0.31391 -1.17408,-1.42576 0.0727,-0.20656 0.39096,-0.70943 1.0945,-0.7059 z m -2.11305,2.94194 c 0.2152,0.0216 0.28407,0.38489 0.58343,0.77618 0.27686,0.50031 -0.16476,0.69652 -0.40979,0.48318 -0.14652,-0.11734 -0.17112,-0.12967 -0.17364,-0.13074 -0.002,0.001 -0.0276,0.0134 -0.17414,0.13074 -0.24504,0.21334 -0.68666,0.0171 -0.4098,-0.48318 0.29936,-0.39129 0.36875,-0.75459 0.58394,-0.77618 z" /></g><g
id="g9-5-0"
transform="matrix(1.4662567,-1.4662567,1.4662567,1.4662567,-373.25727,72.676841)"
style="stroke:#231f7b;stroke-opacity:1"><circle
style="fill:#1bd9ff;fill-opacity:0.394368;stroke:#231f7b;stroke-width:0.860999;stroke-opacity:1"
id="path2-9-3"
cx="118.21665"
cy="237.36874"
r="4" /><path
style="fill:none;stroke:#231f7b;stroke-width:1.15033;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 118.21665,241.199 -0.15789,5.31553"
id="path6-2-6"
sodipodi:nodetypes="cc" /></g></g></svg>

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

@ -0,0 +1,95 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="22.945572mm"
height="28.24629mm"
viewBox="0 0 22.945572 28.24629"
version="1.1"
id="svg1"
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
sodipodi:docname="icons.svg"
xml:space="preserve"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="true"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
showgrid="false"
inkscape:zoom="2.8284272"
inkscape:cx="329.68853"
inkscape:cy="1037.856"
inkscape:window-width="1918"
inkscape:window-height="1042"
inkscape:window-x="0"
inkscape:window-y="17"
inkscape:window-maximized="0"
inkscape:current-layer="layer4"><inkscape:grid
id="grid1"
units="mm"
originx="-84.294216"
originy="-256.51758"
spacingx="0.26458333"
spacingy="0.26458334"
empcolor="#0099e5"
empopacity="0.30196078"
color="#0099e5"
opacity="0.14901961"
empspacing="5"
enabled="true"
visible="false" /><inkscape:page
x="0"
y="0"
width="22.945572"
height="28.24629"
id="page2"
margin="0"
bleed="0" /></sodipodi:namedview><defs
id="defs1" /><g
inkscape:groupmode="layer"
id="layer4"
inkscape:label="Layer 4"
transform="translate(-84.29421,-256.51757)"><g
id="g17"><path
id="path13-2"
style="fill:#ff0707;fill-opacity:0.796663;stroke:#ffbb33;stroke-width:0.665;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 102.26758,259.22827 -4.652431,14.9748 c 0,0 -3.853406,-2.83967 -6.441467,-7.23625 -0.281201,4.36457 0.45945,18.75999 11.093898,19.05465 10.63444,-0.29466 11.37665,-14.69008 11.09545,-19.05465 -2.58806,4.39658 -6.44097,7.23625 -6.44096,7.23625 z m -6.895188,20.4246 h 4.976438 a 2.48832,2.48832 0 0 1 -2.488217,2.48822 2.48832,2.48832 0 0 1 -2.488221,-2.48822 z m 8.815478,0 h 4.97645 a 2.48832,2.48832 0 0 1 -2.48822,2.48822 2.48832,2.48832 0 0 1 -2.48823,-2.48822 z"
transform="translate(-6.5013311,-1.5902536)" /><path
sodipodi:type="star"
style="fill:#ff0707;fill-opacity:0.796663;stroke:#ffbb33;stroke-width:0.665001;stroke-dasharray:none;stroke-opacity:1"
id="path14"
inkscape:flatsided="false"
sodipodi:sides="3"
sodipodi:cx="63.610146"
sodipodi:cy="259.77261"
sodipodi:r1="2.4050174"
sodipodi:r2="0.8495208"
sodipodi:arg1="1.3352513"
sodipodi:arg2="2.2426747"
inkscape:rounded="0.2"
inkscape:randomized="0"
d="m 64.171412,262.11122 c -0.371671,0.14644 -0.815095,-1.38393 -1.090057,-1.67373 -0.307066,-0.32362 -1.843044,-0.90688 -1.777137,-1.34811 0.05902,-0.3951 1.606071,-0.0139 1.994519,-0.10715 0.433804,-0.10412 1.706909,-1.14268 2.05607,-0.86499 0.312654,0.24866 -0.790976,1.39786 -0.904463,1.78088 -0.126738,0.42774 0.136135,2.04957 -0.278932,2.2131 z"
transform="translate(25.967913,5.8850319)" /><path
sodipodi:type="star"
style="fill:#ff0707;fill-opacity:0.796663;stroke:#ffbb33;stroke-width:0.665001;stroke-dasharray:none;stroke-opacity:1"
id="path15"
inkscape:flatsided="false"
sodipodi:sides="4"
sodipodi:cx="73.712936"
sodipodi:cy="258.36945"
sodipodi:r1="1.9284658"
sodipodi:r2="1.1014973"
sodipodi:arg1="1.3258177"
sodipodi:arg2="2.1112159"
inkscape:rounded="0.2"
inkscape:randomized="0"
d="m 74.180658,260.24033 c -0.269428,0.0674 -0.796295,-0.78347 -1.034437,-0.92636 -0.238143,-0.14288 -1.236814,-0.20738 -1.304171,-0.4768 -0.06736,-0.26943 0.783475,-0.7963 0.92636,-1.03444 0.142886,-0.23814 0.207377,-1.23681 0.476805,-1.30417 0.269427,-0.0674 0.796295,0.78347 1.034437,0.92636 0.238143,0.14289 1.236814,0.20738 1.304171,0.4768 0.06736,0.26943 -0.783475,0.7963 -0.926361,1.03444 -0.142885,0.23814 -0.207376,1.23682 -0.476804,1.30417 z"
transform="translate(28.887732,7.0275078)" /></g></g></svg>

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="53.178997mm"
height="53.178989mm"
viewBox="0 0 53.178997 53.178989"
version="1.1"
id="svg1"
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
sodipodi:docname="icons.svg"
xml:space="preserve"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="true"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
showgrid="false"
inkscape:zoom="0.7071068"
inkscape:cx="-43.133512"
inkscape:cy="1034.4972"
inkscape:window-width="1918"
inkscape:window-height="1042"
inkscape:window-x="0"
inkscape:window-y="17"
inkscape:window-maximized="0"
inkscape:current-layer="layer4"><inkscape:grid
id="grid1"
units="mm"
originx="-22.053554"
originy="-242.63108"
spacingx="0.26458333"
spacingy="0.26458334"
empcolor="#0099e5"
empopacity="0.30196078"
color="#0099e5"
opacity="0.14901961"
empspacing="5"
enabled="true"
visible="false" /><inkscape:page
x="0"
y="0"
width="53.178997"
height="53.178989"
id="page2"
margin="0"
bleed="0" /></sodipodi:namedview><defs
id="defs1" /><g
inkscape:groupmode="layer"
id="layer4"
inkscape:label="Layer 4"
transform="translate(-22.053555,-242.63109)"><g
id="g19"><circle
style="fill:#ff2424;fill-opacity:1;stroke:#c10000;stroke-width:3.179;stroke-dasharray:none;stroke-opacity:1"
id="path18"
cx="48.643055"
cy="269.22058"
r="25" /><rect
style="fill:#ffffff;fill-opacity:0.902751;stroke:none;stroke-width:7.48793;stroke-dasharray:none;stroke-opacity:1"
id="rect19"
width="30"
height="10"
x="33.643055"
y="264.22058" /><circle
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.5;stroke-dasharray:none;stroke-opacity:1"
id="path19"
cx="48.643055"
cy="269.22058"
r="25" /></g></g></svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="61.086262mm"
height="70.948692mm"
viewBox="0 0 61.086262 70.948692"
version="1.1"
id="svg1"
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
sodipodi:docname="icons.svg"
xml:space="preserve"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="true"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
showgrid="false"
inkscape:zoom="0.99999999"
inkscape:cx="147"
inkscape:cy="885.50001"
inkscape:window-width="1918"
inkscape:window-height="1042"
inkscape:window-x="0"
inkscape:window-y="17"
inkscape:window-maximized="0"
inkscape:current-layer="layer4"><inkscape:grid
id="grid1"
units="mm"
originx="-14.168536"
originy="-171.71318"
spacingx="0.26458333"
spacingy="0.26458334"
empcolor="#0099e5"
empopacity="0.30196078"
color="#0099e5"
opacity="0.14901961"
empspacing="5"
enabled="true"
visible="false" /><inkscape:page
x="0"
y="0"
width="61.086262"
height="70.948692"
id="page2"
margin="0"
bleed="0" /></sodipodi:namedview><defs
id="defs1" /><g
inkscape:groupmode="layer"
id="layer4"
inkscape:label="Layer 4"
transform="translate(-14.168537,-171.71318)"><path
id="rect55"
style="display:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.7;stroke-dasharray:none;stroke-opacity:1"
d="m 54.680079,205.91192 0.0075,3.95139 h -0.02186 v 1.21435 h 2.712393 v 25.2552 l 0.5302,0.68461 0.58136,-0.68461 v -25.2552 h 2.712392 v -1.21435 h -0.02232 l -0.007,-3.95139 -0.404006,-1.44994 -0.408967,1.44994 0.007,3.95139 h -1.877095 -0.149294 l -0.0075,-3.95139 -0.440632,-1.43824 -0.372342,1.43824 0.007,3.95139 H 57.37808 55.50052 l -0.007,-3.95139 -0.442679,-1.43824 z"
sodipodi:nodetypes="ccccccccccccccccccccccccccc" /><path
id="path145-5"
style="fill:#0f07ff;fill-opacity:0.698287;stroke:#05009e;stroke-width:0.661;stroke-dasharray:none;stroke-opacity:1"
d="m 15.328263,172.81891 c -0.006,0.0619 -1.574466,16.33979 -0.360701,22.78207 1.118918,5.93888 7.519695,11.32363 7.269324,13.90044 -1.315571,12.29009 4.666937,14.58151 11.327474,22.74745 4.44235,3.40984 1.748274,10.34937 5.140254,9.86452 2.132,-0.30475 0.68242,-3.69534 1.30638,-4.01113 0.96346,-0.48761 0.906162,-0.30316 1.208712,0.90537 0.16213,1.91232 -0.261724,3.48859 1.406116,3.3104 2.75286,-0.29411 1.433523,-2.40746 1.639693,-4.79144 0.380196,-0.0845 0.440732,-0.0612 0.448552,-0.0563 h 5.16e-4 5.17e-4 l 5.17e-4,-5.2e-4 c 0.011,-0.006 0.07972,-0.025 0.448035,0.0568 0.20617,2.38398 -1.113167,4.49733 1.639693,4.79144 1.66784,0.17819 1.243985,-1.39808 1.406115,-3.3104 0.30255,-1.20853 0.245252,-1.39298 1.208712,-0.90537 0.62396,0.31579 -0.82562,3.70638 1.30638,4.01113 3.39198,0.48485 0.697905,-6.45468 5.140255,-9.86452 6.660537,-8.16594 12.643045,-10.45736 11.327474,-22.74745 -0.250371,-2.57681 6.150409,-7.96156 7.269324,-13.90044 1.21447,-6.44598 -0.357038,-22.73876 -0.361218,-22.78207 -1.22374,2.2493 -4.89321,20.52768 -12.072649,25.27649 -5.697887,4.31136 -17.377299,5.29548 -17.377299,5.29548 -6.311171,0.0296 -12.005471,-1.80477 -17.250039,-5.29548 -7.179344,-4.74875 -10.848343,-23.02679 -12.072132,-25.27649 z m 18.820557,35.70015 c 3.51769,-0.0177 5.108051,2.49515 5.471501,3.52795 2.31327,5.55922 -1.864976,7.28272 -5.869926,7.12824 -3.49992,0.49438 -6.292069,0.25355 -6.712769,-5.0648 -0.05005,-1.66043 1.545046,-4.80782 5.483386,-5.41725 0.58324,-0.11752 1.125278,-0.17162 1.627808,-0.17414 z m 21.131527,0 c 0.50253,0.003 1.044567,0.0566 1.627807,0.17414 3.93834,0.60943 5.533437,3.75682 5.483387,5.41725 -0.4207,5.31835 -3.212849,5.55918 -6.712769,5.0648 -4.00495,0.15448 -8.183196,-1.56902 -5.869926,-7.12824 0.36345,-1.0328 1.953811,-3.54565 5.471501,-3.52795 z m -10.661365,14.72313 h 0.190686 c 1.002355,0.2034 1.370965,1.9696 2.822567,3.86694 1.38429,2.50156 -0.823801,3.48209 -2.048971,2.41536 -0.781777,-0.62611 -0.869157,-0.65369 -0.869197,-0.65371 -4e-5,2e-5 -0.08742,0.0276 -0.869198,0.65371 -1.22517,1.06673 -3.433261,0.0862 -2.048971,-2.41536 1.451602,-1.89734 1.820729,-3.66354 2.823084,-3.86694 z"
sodipodi:nodetypes="csccsscsccccccscssccscccccccccccccccccccccscccc" /></g></svg>

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@ -2,9 +2,9 @@
<!-- Created with Inkscape (http://www.inkscape.org/) --> <!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg <svg
width="45.428978mm" width="46.290329mm"
height="54.734951mm" height="55.595428mm"
viewBox="0 0 45.428978 54.734951" viewBox="0 0 46.290329 55.595428"
version="1.1" version="1.1"
id="svg1" id="svg1"
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)" inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
@ -23,35 +23,48 @@
inkscape:pagecheckerboard="true" inkscape:pagecheckerboard="true"
inkscape:deskcolor="#d1d1d1" inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm" inkscape:document-units="mm"
showgrid="true" showgrid="false"
inkscape:zoom="1.4142136" inkscape:zoom="1.4142136"
inkscape:cx="204.00031" inkscape:cx="558.61436"
inkscape:cy="749.53319" inkscape:cy="667.15525"
inkscape:window-width="1918" inkscape:window-width="1918"
inkscape:window-height="1061" inkscape:window-height="1042"
inkscape:window-x="0" inkscape:window-x="0"
inkscape:window-y="17" inkscape:window-y="17"
inkscape:window-maximized="0" inkscape:window-maximized="0"
inkscape:current-layer="layer4"><inkscape:page inkscape:current-layer="layer4"><inkscape:grid
x="0" id="grid1"
units="mm"
originx="-160.58582"
originy="-190.77645"
spacingx="0.26458333"
spacingy="0.26458334"
empcolor="#0099e5"
empopacity="0.30196078"
color="#0099e5"
opacity="0.14901961"
empspacing="5"
enabled="true"
visible="false" /><inkscape:page
x="2.454365e-15"
y="0" y="0"
width="45.428978" width="46.290325"
height="54.734951" height="55.595428"
id="page2" id="page2"
margin="0" margin="0"
bleed="0" /></sodipodi:namedview><defs bleed="0" /></sodipodi:namedview><defs
id="defs1"><inkscape:path-effect id="defs1"><inkscape:path-effect
effect="mirror_symmetry" effect="mirror_symmetry"
start_point="145.93901,200.00018" start_point="86.207393,185.56305"
end_point="145.93901,257.23118" end_point="86.338409,235.13009"
center_point="145.93901,228.61568" center_point="86.272901,210.34657"
id="path-effect146" id="path-effect149"
is_visible="true" is_visible="true"
lpeversion="1.2" lpeversion="1.2"
lpesatellites="" lpesatellites=""
mode="free" mode="free"
discard_orig_path="false" discard_orig_path="false"
fuse_paths="false" fuse_paths="true"
oposite_fuse="false" oposite_fuse="false"
split_items="false" split_items="false"
split_open="false" split_open="false"
@ -59,14 +72,53 @@
inkscape:groupmode="layer" inkscape:groupmode="layer"
id="layer4" id="layer4"
inkscape:label="Layer 4" inkscape:label="Layer 4"
transform="translate(-102.64477,-201.30981)"><path transform="translate(-160.58582,-190.77645)"><path
d="m 145.93901,249.87364 c 0,0 -0.0303,-0.0367 -0.44909,0.0563 -0.20617,2.38398 1.11335,4.49732 -1.63951,4.79143 -1.66784,0.17819 -1.24406,-1.39832 -1.40619,-3.31064 -0.30255,-1.20853 -0.24531,-1.39312 -1.20877,-0.90551 -0.62396,0.31579 0.82573,3.70676 -1.30627,4.01151 -3.39198,0.48485 -0.69804,-6.45466 -5.14039,-9.8645 -1.63686,-2.03072 -4.33202,-1.51761 -6.56291,-1.96319 -2.53079,-1.12277 -4.05741,-3.94017 -4.44572,-6.62182 -0.7119,-4.67507 -0.64763,-9.45558 -0.31885,-14.16244 -1.53814,-15.82349 6.47812,-17.65127 15.17169,-20.63595 2.27655,-0.8108 4.68806,-1.22375 7.10241,-1.26865 0.0675,0 0.13527,2e-5 0.2036,5.1e-4 v 35.63039 c -1.07599,0.10793 -1.42136,1.92498 -2.91817,3.88142 -1.38429,2.50152 0.8238,3.48208 2.04897,2.41535 0.78196,-0.62623 0.8692,-0.65371 0.8692,-0.65371 z m -17.67696,-23.3593 c 0.4207,5.31835 3.21309,5.55909 6.71301,5.06471 4.00495,0.15448 8.18296,-1.56893 5.86969,-7.12815 -0.41537,-1.18035 -2.43304,-4.29435 -7.09899,-3.3542 -3.93834,0.60943 -5.53376,3.75721 -5.48371,5.41764 z m 17.67696,23.3593 c 0,0 0.0303,-0.0367 0.44909,0.0563 0.20617,2.38398 -1.11335,4.49732 1.63951,4.79143 1.66784,0.17819 1.24406,-1.39832 1.40619,-3.31064 0.30255,-1.20853 0.24531,-1.39312 1.20877,-0.90551 0.62396,0.31579 -0.82573,3.70676 1.30627,4.01151 3.39198,0.48485 0.69804,-6.45466 5.14039,-9.8645 1.63686,-2.03072 4.33202,-1.51761 6.56291,-1.96319 2.53079,-1.12277 4.05741,-3.94017 4.44572,-6.62182 0.7119,-4.67507 0.64763,-9.45558 0.31885,-14.16244 1.53814,-15.82349 -6.47812,-17.65127 -15.17169,-20.63595 -2.27655,-0.8108 -4.68806,-1.22375 -7.10241,-1.26865 -0.0675,0 -0.13527,2e-5 -0.2036,5.1e-4 v 35.63039 c 1.07599,0.10793 1.42136,1.92498 2.91817,3.88142 1.38429,2.50152 -0.8238,3.48208 -2.04897,2.41535 -0.78196,-0.62623 -0.8692,-0.65371 -0.8692,-0.65371 z m 17.67696,-23.3593 c -0.4207,5.31835 -3.21309,5.55909 -6.71301,5.06471 -4.00495,0.15448 -8.18296,-1.56893 -5.86969,-7.12815 0.41537,-1.18035 2.43304,-4.29435 7.09899,-3.3542 3.93834,0.60943 5.53376,3.75721 5.48371,5.41764 z"
style="fill:#a0a0a0;fill-opacity:1;stroke-width:0.161404"
id="path145" id="path145"
inkscape:original-d="m 145.93901,249.87364 c 0,0 -0.0303,-0.0367 -0.44909,0.0563 -0.20617,2.38398 1.11335,4.49732 -1.63951,4.79143 -1.66784,0.17819 -1.24406,-1.39832 -1.40619,-3.31064 -0.30255,-1.20853 -0.24531,-1.39312 -1.20877,-0.90551 -0.62396,0.31579 0.82573,3.70676 -1.30627,4.01151 -3.39198,0.48485 -0.69804,-6.45466 -5.14039,-9.8645 -1.63686,-2.03072 -4.33202,-1.51761 -6.56291,-1.96319 -2.53079,-1.12277 -4.05741,-3.94017 -4.44572,-6.62182 -0.7119,-4.67507 -0.64763,-9.45558 -0.31885,-14.16244 -1.53814,-15.82349 6.47812,-17.65127 15.17169,-20.63595 2.27655,-0.8108 4.68806,-1.22375 7.10241,-1.26865 0.0675,0 0.13527,2e-5 0.2036,5.1e-4 v 35.63039 c -1.07599,0.10793 -1.42136,1.92498 -2.91817,3.88142 -1.38429,2.50152 0.8238,3.48208 2.04897,2.41535 0.78196,-0.62623 0.8692,-0.65371 0.8692,-0.65371 z m -17.67696,-23.3593 c 0.4207,5.31835 3.21309,5.55909 6.71301,5.06471 4.00495,0.15448 8.18296,-1.56893 5.86969,-7.12815 -0.41537,-1.18035 -2.43304,-4.29435 -7.09899,-3.3542 -3.93834,0.60943 -5.53376,3.75721 -5.48371,5.41764 z" style="fill:#878787;fill-opacity:0.8;stroke:#4c4c4c;stroke-width:0.861;stroke-dasharray:none;stroke-opacity:1"
inkscape:path-effect="#path-effect146" d="m 183.52738,191.20695 c -2.41435,0.0449 -4.82586,0.45785 -7.10241,1.26865 -8.69357,2.98468 -16.70982,4.81246 -15.17168,20.63595 -0.32878,4.70686 -0.39306,9.48738 0.31884,14.16245 0.38831,2.68165 1.91493,5.49905 4.44572,6.62182 2.23089,0.44558 4.92605,-0.0675 6.56291,1.96318 4.44235,3.40984 1.74827,10.34937 5.14025,9.86452 2.132,-0.30475 0.68242,-3.69585 1.30638,-4.01164 0.96346,-0.48761 0.90617,-0.30265 1.20872,0.90588 0.16213,1.91232 -0.26173,3.48859 1.40611,3.3104 2.75286,-0.29411 1.43353,-2.40746 1.6397,-4.79144 0.37937,-0.0842 0.43999,-0.0618 0.44803,-0.0568 h 5.2e-4 l 5.1e-4,5.2e-4 5.2e-4,-5.2e-4 h 5.2e-4 c 0.008,-0.005 0.0686,-0.0274 0.44803,0.0568 0.20617,2.38398 -1.11317,4.49733 1.63969,4.79144 1.66784,0.17819 1.24399,-1.39808 1.40612,-3.3104 0.30255,-1.20853 0.24525,-1.39349 1.20871,-0.90588 0.62396,0.31579 -0.82562,3.70689 1.30638,4.01164 3.39198,0.48485 0.69791,-6.45468 5.14026,-9.86452 1.63686,-2.03072 4.33201,-1.5176 6.5629,-1.96318 2.53079,-1.12277 4.05742,-3.94017 4.44573,-6.62182 0.7119,-4.67507 0.64762,-9.45559 0.31884,-14.16245 1.53814,-15.82349 -6.47811,-17.65127 -15.17168,-20.63595 -2.27655,-0.8108 -4.68806,-1.22375 -7.10241,-1.26865 -0.0675,0 -0.13528,3e-5 -0.20361,5.2e-4 -0.0683,-4.9e-4 -0.1361,-5.2e-4 -0.2036,-5.2e-4 z m -10.36216,20.92224 c 3.5177,-0.0177 5.10805,2.49566 5.4715,3.52846 2.31327,5.55922 -1.86498,7.28273 -5.86993,7.12825 -3.49992,0.49438 -6.29206,0.25354 -6.71276,-5.06481 -0.05,-1.66043 1.54504,-4.80832 5.48338,-5.41775 0.58325,-0.11752 1.12528,-0.17163 1.62781,-0.17415 z m 21.13153,0 c 0.50252,0.003 1.04404,0.0566 1.62729,0.17415 3.93834,0.60943 5.53395,3.75732 5.4839,5.41775 -0.4207,5.31835 -3.21336,5.55919 -6.71328,5.06481 -4.00495,0.15448 -8.18268,-1.56903 -5.86941,-7.12825 0.36344,-1.0328 1.9538,-3.54611 5.4715,-3.52846 z m -10.56577,14.70866 c 1.07599,0.10793 1.42136,1.92498 2.91817,3.88142 1.38429,2.50152 -0.8238,3.48208 -2.04897,2.41535 -0.78178,-0.62609 -0.86916,-0.65369 -0.8692,-0.65371 -4e-5,2e-5 -0.0874,0.0276 -0.86919,0.65371 -1.22517,1.06673 -3.43326,0.0862 -2.04897,-2.41535 1.49681,-1.95644 1.84217,-3.77349 2.91816,-3.88142 z"
transform="translate(-20.579754,1.3096207)" inkscape:export-filename="../../src/werewolves/src/werewolves/werewolves/img/skull.svg"
sodipodi:nodetypes="ccscssccccccccccccccccc"
inkscape:export-filename="../../src/werewolves/werewolves/img/skull;.svg"
inkscape:export-xdpi="900.08" inkscape:export-xdpi="900.08"
inkscape:export-ydpi="900.08" /></g></svg> inkscape:export-ydpi="900.08" /><g
id="g151"
inkscape:export-filename="../../src/werewolves/werewolves/dist/img/heart.svg"
inkscape:export-xdpi="900.08"
inkscape:export-ydpi="900.08"
transform="translate(50.270833,-38.1)"><path
style="fill:#ff2424;fill-opacity:1;stroke:#ff2424;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 86.254166,235.08229 c 0,0 -24.302335,-18.46127 -24.606251,-31.8823 -0.126849,-5.60168 4.153389,-12.70855 9.657292,-13.75832 5.852331,-1.11623 14.123929,1.87077 14.932422,9.82265 z m 0.168232,-4.4e-4 c 0,0 24.204402,-18.58949 24.437362,-32.01194 0.0972,-5.60227 -4.22051,-12.68641 -9.72989,-13.70707 -5.858145,-1.08528 -14.113837,1.94541 -14.880282,9.90145 z"
id="path148"
sodipodi:nodetypes="caacc"
inkscape:original-d="m 86.254166,235.08229 c 0,0 -24.302335,-18.46127 -24.606251,-31.8823 -0.126849,-5.60168 4.153389,-12.70855 9.657292,-13.75832 5.852331,-1.11623 14.123929,1.87077 14.932422,9.82265 z"
inkscape:path-effect="#path-effect149"
inkscape:export-filename="../../src/werewolves/werewolves/img/heart.svg"
inkscape:export-xdpi="900.08"
inkscape:export-ydpi="900.08" /><path
sodipodi:type="star"
style="fill:#fff001;fill-opacity:1;stroke:#ff2424;stroke-width:0.15;stroke-dasharray:none;stroke-opacity:1"
id="path150"
inkscape:flatsided="false"
sodipodi:sides="4"
sodipodi:cx="79.886864"
sodipodi:cy="208.97804"
sodipodi:r1="5.2418227"
sodipodi:r2="2.8830025"
sodipodi:arg1="0.607802"
sodipodi:arg2="1.3932002"
inkscape:rounded="0.5"
inkscape:randomized="0"
d="m 84.189903,211.97146 c -1.084141,1.55845 -1.92512,-0.49115 -3.793716,-0.15576 -1.868596,0.33539 -1.944289,2.54952 -3.502742,1.46538 -1.558453,-1.08414 0.491151,-1.92512 0.155762,-3.79371 -0.335389,-1.8686 -2.549524,-1.94429 -1.465383,-3.50275 1.084141,-1.55845 1.925121,0.49116 3.793717,0.15577 1.868596,-0.33539 1.944289,-2.54953 3.502742,-1.46539 1.558452,1.08414 -0.491152,1.92512 -0.155763,3.79372 0.335389,1.8686 2.549524,1.94429 1.465383,3.50274 z"
transform="rotate(28.628814,62.558026,193.09515)" /><path
sodipodi:type="star"
style="fill:#fff001;fill-opacity:1;stroke:#ff2424;stroke-width:0.15;stroke-dasharray:none;stroke-opacity:1"
id="path151"
inkscape:flatsided="false"
sodipodi:sides="4"
sodipodi:cx="68.848625"
sodipodi:cy="200.93324"
sodipodi:r1="6.7481718"
sodipodi:r2="3.3373971"
sodipodi:arg1="0.80500349"
sodipodi:arg2="1.5925996"
inkscape:rounded="0.5"
inkscape:randomized="0"
d="m 73.525842,205.79755 c -1.802133,1.72521 -2.255654,-1.4788 -4.749977,-1.5277 -2.4873,-0.0488 -3.071191,3.13767 -4.791545,1.34061 -1.725212,-1.80213 1.478793,-2.25565 1.527701,-4.74998 0.04877,-2.4873 -3.137671,-3.07119 -1.340613,-4.79154 1.802133,-1.72521 2.255655,1.47879 4.749978,1.5277 2.487299,0.0488 3.07119,-3.13767 4.791545,-1.34061 1.725212,1.80213 -1.478794,2.25565 -1.527702,4.74997 -0.04877,2.4873 3.137671,3.07119 1.340613,4.79155 z" /></g></g></svg>

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

80
werewolves/img/sword.svg Normal file
View File

@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="22.314859mm"
height="22.297653mm"
viewBox="0 0 22.314859 22.297653"
version="1.1"
id="svg1"
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
sodipodi:docname="icons.svg"
xml:space="preserve"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="true"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
showgrid="false"
inkscape:zoom="2.8284272"
inkscape:cx="329.68853"
inkscape:cy="1037.856"
inkscape:window-width="1918"
inkscape:window-height="1042"
inkscape:window-x="0"
inkscape:window-y="17"
inkscape:window-maximized="0"
inkscape:current-layer="layer4"><inkscape:grid
id="grid1"
units="mm"
originx="-56.082429"
originy="-239.74316"
spacingx="0.26458333"
spacingy="0.26458334"
empcolor="#0099e5"
empopacity="0.30196078"
color="#0099e5"
opacity="0.14901961"
empspacing="5"
enabled="true"
visible="false" /><inkscape:page
x="0"
y="0"
width="22.314859"
height="22.297653"
id="page2"
margin="0"
bleed="0" /></sodipodi:namedview><defs
id="defs1" /><g
inkscape:groupmode="layer"
id="layer4"
inkscape:label="Layer 4"
transform="translate(-56.082426,-239.74318)"><path
id="path4-9-8-6"
style="fill:#ffa606;fill-opacity:1;stroke-width:0.679;stroke-dasharray:none"
inkscape:transform-center-x="-0.11920648"
inkscape:transform-center-y="-9.0503731"
d="m 75.968916,255.39833 -14.375127,-14.37513 -5.51136,-1.28003 1.279797,5.51159 14.375127,14.37513 z"
sodipodi:nodetypes="cccccc" /><path
id="path4-1-2-1-9"
style="fill:#000000;fill-opacity:0.504713;stroke-width:0.339521"
inkscape:transform-center-x="-0.11920648"
inkscape:transform-center-y="-9.0503731"
d="m 72.46276,258.16133 2.037184,-2.03718 -16.922161,-14.88563 z" /><path
id="path159-3"
style="fill:#ffffff;fill-opacity:0.696867;stroke-width:0.339521"
inkscape:transform-center-x="-0.11920648"
inkscape:transform-center-y="-9.0503731"
d="m 78.294558,260.62268 -3.768526,-3.76853 2.07583,-2.07583 c 0.126016,-0.12601 -0.252031,-0.50406 -0.378048,-0.37805 -0.0188,0.0188 -5.484278,5.48428 -5.484278,5.48428 -0.188161,0.18816 0.177445,0.57865 0.378048,0.37805 l 2.075593,-2.07559 3.768526,3.76852 c 0.423571,0.42357 1.82288,-0.84283 1.332855,-1.33285 z"
sodipodi:nodetypes="zcsssscsz"
inkscape:export-filename="sword.svg"
inkscape:export-xdpi="900.08"
inkscape:export-ydpi="900.08" /></g></svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -25,6 +25,13 @@ $defensive_border_faint: color.change($defensive_border, $alpha: 0.3);
$intel_border_faint: color.change($intel_border, $alpha: 0.3); $intel_border_faint: color.change($intel_border, $alpha: 0.3);
$starts_as_villager_border_faint: color.change($starts_as_villager_border, $alpha: 0.3); $starts_as_villager_border_faint: color.change($starts_as_villager_border, $alpha: 0.3);
$wolves_color_faint: color.change($wolves_color, $alpha: 0.1);
$village_color_faint: color.change($village_color, $alpha: 0.1);
$offensive_color_faint: color.change($offensive_color, $alpha: 0.1);
$defensive_color_faint: color.change($defensive_color, $alpha: 0.1);
$intel_color_faint: color.change($intel_color, $alpha: 0.1);
$starts_as_villager_color_faint: color.change($starts_as_villager_color, $alpha: 0.1);
@mixin flexbox() { @mixin flexbox() {
display: -webkit-box; display: -webkit-box;
@ -353,9 +360,26 @@ button {
.character { .character {
text-align: center; text-align: center;
border: 3px solid rgba(0, 0, 0, 0.4); border: 3px solid rgba(0, 0, 0, 0.4);
// min-width: 20%;
flex-shrink: 1;
.role { .role {
font-size: 2rem; font-size: 1.5rem;
}
&.wolves {
padding-top: 20px;
padding-bottom: 20px;
&>.role {
margin: 0;
}
display: flex;
flex-direction: column;
justify-content: center;
min-width: 15vw;
} }
} }
@ -805,16 +829,23 @@ error {
} }
.binary { .binary {
margin: 0;
padding: 0;
.button-container { .button-container {
background-color: $village_color;
border: 3px solid darken($village_color, 20%);
text-align: center; text-align: center;
padding: 0; padding: 0;
margin: 0; margin: 0;
display: flex; display: flex;
flex: 1 1 0; flex: 1 1 0;
gap: 20px;
margin-top: 20px;
justify-content: space-around;
width: 100%;
button { button {
background-color: $wolves_color_faint;
border: 3px solid $wolves_border_faint;
font-size: 3rem; font-size: 3rem;
font-weight: bold; font-weight: bold;
align-self: center; align-self: center;
@ -822,8 +853,14 @@ error {
width: 100%; width: 100%;
height: 100%; height: 100%;
margin: 0; margin: 0;
&:hover {
background-color: $wolves_border_faint;
color: white;
}
} }
} }
} }
input { input {
@ -911,6 +948,7 @@ input {
width: 100%; width: 100%;
align-items: center; align-items: center;
color: white; color: white;
height: 90vh;
$marked_bg: color.change($wolves_color, $alpha: 0.3); $marked_bg: color.change($wolves_color, $alpha: 0.3);
$marked_border: color.change($wolves_color, $alpha: 1.0); $marked_border: color.change($wolves_color, $alpha: 1.0);
$village_bg: color.change($village_color, $alpha: 0.3); $village_bg: color.change($village_color, $alpha: 0.3);
@ -921,6 +959,9 @@ input {
flex-direction: row; flex-direction: row;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: space-evenly; justify-content: space-evenly;
align-items: center;
flex-grow: 1;
align-content: center;
} }
.character { .character {
@ -1037,6 +1078,11 @@ input {
color: white; color: white;
background-color: $village_border; background-color: $village_border;
} }
&.faint {
border: 1px solid $village_border_faint;
background-color: $village_color_faint;
}
} }
.wolves { .wolves {
@ -1050,6 +1096,7 @@ input {
&.faint { &.faint {
border: 1px solid $wolves_border_faint; border: 1px solid $wolves_border_faint;
background-color: $wolves_color_faint;
} }
} }
@ -1064,6 +1111,7 @@ input {
&.faint { &.faint {
border: 1px solid $intel_border_faint; border: 1px solid $intel_border_faint;
background-color: $intel_color_faint;
} }
} }
@ -1078,6 +1126,7 @@ input {
&.faint { &.faint {
border: 1px solid $defensive_border_faint; border: 1px solid $defensive_border_faint;
background-color: $defensive_color_faint;
} }
} }
@ -1092,6 +1141,7 @@ input {
&.faint { &.faint {
border: 1px solid $offensive_border_faint; border: 1px solid $offensive_border_faint;
background-color: $offensive_color_faint;
} }
} }
@ -1106,6 +1156,7 @@ input {
&.faint { &.faint {
border: 1px solid $starts_as_villager_border_faint; border: 1px solid $starts_as_villager_border_faint;
background-color: $starts_as_villager_color_faint;
} }
} }
@ -1330,6 +1381,8 @@ input {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
flex-wrap: nowrap; flex-wrap: nowrap;
align-items: center;
width: 100%;
} }
.page { .page {
@ -1339,9 +1392,6 @@ input {
align-items: center; align-items: center;
width: 100%; width: 100%;
height: 100%; height: 100%;
// width: ;
& .next {}
} }
.signin { .signin {
@ -1374,9 +1424,17 @@ input {
.story { .story {
user-select: text; .cast {
display: flex;
flex-direction: row;
flex-wrap: wrap;
gap: 10px;
justify-content: center;
}
.time-period { .time-period {
user-select: text;
.day { .day {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -1462,30 +1520,6 @@ input {
border: 1px solid rgba(255, 255, 255, 0.3); border: 1px solid rgba(255, 255, 255, 0.3);
} }
&.wolves {
background-color: color.change($wolves_color, $alpha: 0.1);
}
&.intel {
background-color: color.change($intel_color, $alpha: 0.1);
}
&.defensive {
background-color: color.change($defensive_color, $alpha: 0.1);
}
&.offensive {
background-color: color.change($offensive_color, $alpha: 0.1);
}
&.village {
background-color: color.change($village_color, $alpha: 0.1);
}
&.starts-as-villager {
background-color: color.change($starts_as_villager_color, $alpha: 0.1);
}
} }
.alignment-eq { .alignment-eq {
@ -1513,6 +1547,10 @@ input {
justify-items: baseline; justify-items: baseline;
gap: 5px; gap: 5px;
.number {
color: rgba(255, 255, 0, 0.7);
}
.role { .role {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
@ -1595,3 +1633,58 @@ input {
flex-wrap: nowrap; flex-wrap: nowrap;
width: 100%; width: 100%;
} }
.role-page {
width: 100%;
display: flex;
flex-direction: column;
flex-wrap: nowrap;
justify-content: center;
h1 {
text-align: center;
// align-self: flex-start;
}
.information {
font-size: 1.2em;
padding-left: 5%;
padding-right: 5%;
}
.yellow {
color: yellow;
}
.red {
color: red;
}
}
.icons {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: center;
align-items: center;
gap: 30px;
}
.icon-info {
flex-shrink: 1;
}
.info-player-list {
display: flex;
flex-direction: column;
flex-wrap: nowrap;
align-items: center;
width: 100%;
justify-content: center;
gap: 10px;
&.masons {
font-size: 2em;
}
}

View File

@ -59,6 +59,7 @@ pub fn test_story() -> GameStory {
empath, empath,
scapegoat, scapegoat,
hunter, hunter,
diseased,
) = ( ) = (
(SetupRole::Werewolf, players_iter.next().unwrap()), (SetupRole::Werewolf, players_iter.next().unwrap()),
(SetupRole::DireWolf, players_iter.next().unwrap()), (SetupRole::DireWolf, players_iter.next().unwrap()),
@ -83,6 +84,7 @@ pub fn test_story() -> GameStory {
players_iter.next().unwrap(), players_iter.next().unwrap(),
), ),
(SetupRole::Hunter, players_iter.next().unwrap()), (SetupRole::Hunter, players_iter.next().unwrap()),
(SetupRole::Diseased, players_iter.next().unwrap()),
); );
let mut settings = GameSettings::empty(); let mut settings = GameSettings::empty();
settings.add_and_assign(werewolf.0, werewolf.1); settings.add_and_assign(werewolf.0, werewolf.1);
@ -103,6 +105,7 @@ pub fn test_story() -> GameStory {
settings.add_and_assign(empath.0, empath.1); settings.add_and_assign(empath.0, empath.1);
settings.add_and_assign(scapegoat.0, scapegoat.1); settings.add_and_assign(scapegoat.0, scapegoat.1);
settings.add_and_assign(hunter.0, hunter.1); settings.add_and_assign(hunter.0, hunter.1);
settings.add_and_assign(diseased.0, diseased.1);
settings.fill_remaining_slots_with_villagers(players.len()); settings.fill_remaining_slots_with_villagers(players.len());
let ( let (

View File

@ -27,7 +27,7 @@ pub fn BinaryChoice(
html! { html! {
<div class="column-list binary"> <div class="column-list binary">
{children.clone()} {children.clone()}
<div class="row-list gap"> <div class="button-container">
<Button on_click={yes}>{"Yes"}</Button> <Button on_click={yes}>{"Yes"}</Button>
<Button on_click={no}>{"No"}</Button> <Button on_click={no}>{"No"}</Button>
</div> </div>

View File

@ -1,10 +1,7 @@
use werewolves_proto::{ use werewolves_proto::{character::CharacterId, message::CharacterIdentity};
character::CharacterId,
message::{CharacterIdentity, PublicIdentity},
};
use yew::prelude::*; use yew::prelude::*;
use crate::components::{Button, Identity}; use crate::components::{Button, CharacterTargetCard};
#[derive(Debug, Clone, PartialEq, Properties)] #[derive(Debug, Clone, PartialEq, Properties)]
pub struct TargetPickerProps { pub struct TargetPickerProps {
@ -72,10 +69,9 @@ pub fn TargetCard(
.map(|cb| Callback::from(move |_| cb.emit(click_target))) .map(|cb| Callback::from(move |_| cb.emit(click_target)))
.unwrap_or_default(); .unwrap_or_default();
let marked = marked.then_some("marked"); let marked = marked.then_some("marked");
let ident: PublicIdentity = target.into();
html! { html! {
<Button on_click={on_click} classes={classes!(marked, "character")}> <Button on_click={on_click} classes={classes!(marked, "character")}>
<Identity ident={ident}/> <CharacterTargetCard ident={target.clone()}/>
</Button> </Button>
} }
} }

View File

@ -12,9 +12,12 @@ use werewolves_proto::{
}; };
use yew::prelude::*; use yew::prelude::*;
use crate::components::{ use crate::{
Button, CoverOfDarkness, Identity, components::{
action::{BinaryChoice, TargetPicker, WolvesIntro}, Button, CoverOfDarkness, Identity,
action::{BinaryChoice, TargetPicker, WolvesIntro},
},
pages::MasonsWake,
}; };
#[derive(Debug, Clone, PartialEq, Properties)] #[derive(Debug, Clone, PartialEq, Properties)]
@ -109,58 +112,27 @@ pub fn Prompt(props: &ActionPromptProps) -> Html {
/> />
}; };
} }
ActionPrompt::ElderReveal { character_id } => { ActionPrompt::MasonsWake { .. } => {
return html! { props
<div class="role-change"> .on_complete
{identity_html(props, Some(character_id))} .emit(HostMessage::InGame(HostGameMessage::Night(
<h1>{"you are the elder"}</h1> HostNightMessage::ActionResponse(ActionResponse::Continue),
{cont} )));
</div> props
}; .on_complete
.emit(HostMessage::InGame(HostGameMessage::Night(
HostNightMessage::Next,
)));
props.on_complete.emit(HostMessage::GetState);
return html! {};
} }
ActionPrompt::Insomniac { character_id } => { ActionPrompt::RoleChange { .. }
return html! { | ActionPrompt::ElderReveal { .. }
<div class="insomniac prompt"> | ActionPrompt::Insomniac { .. } => {
{identity_html(props, Some(character_id))} if let Some(cb) = continue_callback {
<h2>{"you are the insomniac"}</h2> cb.emit(());
{cont} }
</div> return html! {};
};
}
ActionPrompt::RoleChange {
character_id,
new_role,
} => {
return html! {
<div class="role-change">
{identity_html(props, Some(character_id))}
<h2>{"your role has changed"}</h2>
<h1>{new_role.to_string()}</h1>
{cont}
</div>
};
}
ActionPrompt::MasonsWake { leader, masons } => {
let masons = masons
.into_iter()
.map(|c| {
let leader = (c.character_id == *leader).then_some("leader");
let ident: PublicIdentity = c.into();
html! {
<Identity class={classes!(leader)} ident={ident}/>
}
})
.collect::<Html>();
return html! {
<div class="masons">
<h2>{"these are the masons"}</h2>
<div class="mason-list">
{masons}
</div>
{cont}
</div>
};
} }
ActionPrompt::Guardian { ActionPrompt::Guardian {
@ -408,10 +380,22 @@ pub fn Prompt(props: &ActionPromptProps) -> Html {
} }
}); });
return html! { return html! {
<div> <div class="role-page">
{identity_html(props, Some(character_id))} {identity_html(props, Some(character_id))}
<h1 class="wolves">{"SHAPESHIFTER"}</h1>
<div class="information wolves faint">
<h3>
{"WOULD YOU LIKE TO USE YOUR "}
<span class="yellow">{"ONCE PER GAME"}</span>
{" SHAPESHIFT ABILITY?"}
</h3>
<h4>
<span class="yellow">{"YOU WILL DIE"}</span>{", AND THE "}
{"TARGET OF THE WOLFPACK KILL"}
{" SHALL INSTEAD BECOME A WOLF"}
</h4>
</div>
<BinaryChoice on_chosen={on_select}> <BinaryChoice on_chosen={on_select}>
<h2>{"shapeshift?"}</h2>
</BinaryChoice> </BinaryChoice>
</div> </div>
}; };
@ -434,14 +418,16 @@ pub fn Prompt(props: &ActionPromptProps) -> Html {
Some(character_id), Some(character_id),
living_players, living_players,
marked.iter().cloned().collect(), marked.iter().cloned().collect(),
html! {{"dire wolf"}}, html! {{"direwolf"}},
), ),
}; };
let role_info = props.big_screen.not().then_some(html! {
<h2>{role_info}</h2>
});
html! { html! {
<div class="prompt"> <div class="prompt">
{identity_html(props, character_id)} {identity_html(props, character_id)}
<h2>{role_info}</h2> {role_info}
<TargetPicker <TargetPicker
targets={targets.clone()} targets={targets.clone()}
marked={marked} marked={marked}
@ -450,343 +436,4 @@ pub fn Prompt(props: &ActionPromptProps) -> Html {
/> />
</div> </div>
} }
// match &props.prompt {
// ActionPrompt::CoverOfDarkness => {
// let on_complete = props.on_complete.clone();
// let next = props.big_screen.not().then(|| {
// Callback::from(move |_| {
// on_complete.emit(HostMessage::InGame(HostGameMessage::Night(
// HostNightMessage::ActionResponse(ActionResponse::ClearCoverOfDarkness),
// )))
// })
// });
// return html! {
// <CoverOfDarkness next={next} />
// };
// }
// ActionPrompt::WolvesIntro { wolves } => {
// let on_complete = props.on_complete.clone();
// let on_complete = Callback::from(move |_| {
// on_complete.emit(HostMessage::InGame(HostGameMessage::Night(
// HostNightMessage::ActionResponse(
// werewolves_proto::message::night::ActionResponse::WolvesIntroAck,
// ),
// )))
// });
// html! {
// <WolvesIntro
// big_screen={props.big_screen}
// on_complete={on_complete}
// wolves={wolves.clone()}
// />
// }
// }
// ActionPrompt::Seer {
// character_id,
// living_players,
// } => {
// let on_complete = props.on_complete.clone();
// let on_select = props.big_screen.not().then(|| {
// Callback::from(move |target: CharacterId| {
// on_complete.emit(HostMessage::InGame(HostGameMessage::Night(
// HostNightMessage::ActionResponse(ActionResponse::Seer(target)),
// )));
// })
// });
// html! {
// <div>
// {identity_html(props, Some(&character_id))}
// <SingleTarget
// targets={living_players.clone()}
// target_selection={on_select}
// headline={"check alignment"}
// />
// </div>
// }
// }
// ActionPrompt::RoleChange {
// character_id,
// new_role,
// } => {
// let on_complete = props.on_complete.clone();
// let on_click = Callback::from(move |_| {
// on_complete.emit(HostMessage::InGame(HostGameMessage::Night(
// HostNightMessage::ActionResponse(ActionResponse::RoleChangeAck),
// )))
// });
// let cont = props.big_screen.not().then(|| {
// html! {
// <Button on_click={on_click}>{"continue"}</Button>
// }
// });
// html! {
// <div>
// {identity_html(props, Some(&character_id))}
// <h2>{"your role has changed"}</h2>
// <p>{new_role.to_string()}</p>
// {cont}
// </div>
// }
// }
// ActionPrompt::Protector {
// character_id,
// targets,
// } => {
// let on_complete = props.on_complete.clone();
// let on_select = props.big_screen.not().then(|| {
// Callback::from(move |target: CharacterId| {
// on_complete.emit(HostMessage::InGame(HostGameMessage::Night(
// HostNightMessage::ActionResponse(ActionResponse::Protector(target)),
// )));
// })
// });
// html! {
// <div>
// {identity_html(props, Some(&character_id))}
// <SingleTarget
// targets={targets.clone()}
// target_selection={on_select}
// headline={"protector"}
// />
// </div>
// }
// }
// ActionPrompt::Arcanist {
// character_id,
// living_players,
// } => {
// let on_complete = props.on_complete.clone();
// let on_select = props.big_screen.not().then(|| {
// Callback::from(move |(t1, t2): (CharacterId, CharacterId)| {
// on_complete.emit(HostMessage::InGame(HostGameMessage::Night(
// HostNightMessage::ActionResponse(ActionResponse::Arcanist(t1, t2)),
// )));
// })
// });
// html! {
// <div>
// {identity_html(props, Some(&character_id))}
// <TwoTarget
// targets={living_players.clone()}
// target_selection={on_select}
// headline={"arcanist"}
// />
// </div>
// }
// }
// ActionPrompt::Gravedigger {
// character_id,
// dead_players,
// } => {
// let on_complete = props.on_complete.clone();
// let on_select = props.big_screen.not().then(|| {
// Callback::from(move |target: CharacterId| {
// on_complete.emit(HostMessage::InGame(HostGameMessage::Night(
// HostNightMessage::ActionResponse(ActionResponse::Gravedigger(target)),
// )));
// })
// });
// html! {
// <div>
// {identity_html(props, Some(&character_id))}
// <SingleTarget
// targets={dead_players.clone()}
// target_selection={on_select}
// headline={"gravedigger"}
// />
// </div>
// }
// }
// ActionPrompt::Hunter {
// character_id,
// current_target,
// living_players,
// } => {
// let on_complete = props.on_complete.clone();
// let on_select = props.big_screen.not().then(|| {
// Callback::from(move |target: CharacterId| {
// on_complete.emit(HostMessage::InGame(HostGameMessage::Night(
// HostNightMessage::ActionResponse(ActionResponse::Hunter(target)),
// )));
// })
// });
// html! {
// <div>
// {identity_html(props, Some(&character_id))}
// <SingleTarget
// targets={living_players.clone()}
// target_selection={on_select}
// headline={"hunter"}
// >
// <h3>
// <b>{"current target: "}</b>{current_target.clone().map(|t| html!{
// <Identity ident={Into::<PublicIdentity>::into(t)} />
// }).unwrap_or_else(|| html!{<i>{"none"}</i>})}
// </h3>
// </SingleTarget>
// </div>
// }
// }
// ActionPrompt::Militia {
// character_id,
// living_players,
// } => {
// let on_complete = props.on_complete.clone();
// let on_select = props.big_screen.not().then(|| {
// Callback::from(move |target: Option<CharacterId>| {
// on_complete.emit(HostMessage::InGame(HostGameMessage::Night(
// HostNightMessage::ActionResponse(ActionResponse::Militia(target)),
// )));
// })
// });
// html! {
// <div>
// {identity_html(props, Some(&character_id))}
// <OptionalSingleTarget
// targets={living_players.clone()}
// target_selection={on_select}
// headline={"pew pew?"}
// />
// </div>
// }
// }
// ActionPrompt::MapleWolf {
// character_id,
// kill_or_die,
// living_players,
// marked,
// } => {
// let kill_or_die = kill_or_die.then(|| {
// html! {
// <em>{"if you fail to eat tonight, you will starve"}</em>
// }
// });
// html! {
// <div>
// {identity_html(props, Some(&character_id))}
// <OptionalSingleTarget
// targets={living_players.clone()}
// target_selection={on_select}
// headline={"nom nom?"}
// >
// {kill_or_die}
// </OptionalSingleTarget>
// </div>
// }
// }
// ActionPrompt::Guardian {
// character_id,
// previous,
// living_players,
// marked,
// } => {
// let last_protect = previous.as_ref().map(|prev| match prev {
// PreviousGuardianAction::Protect(target) => {
// html! {
// <>
// <b>{"last night you protected: "}</b>
// <Identity ident={Into::<PublicIdentity>::into(target)}/>
// </>
// }
// }
// PreviousGuardianAction::Guard(target) => html! {
// <>
// <b>{"last night you guarded: "}</b>
// <Identity ident={Into::<PublicIdentity>::into(target)}/>
// </>
// },
// });
// let marked = marked.iter().cloned().collect();
// html! {
// <div>
// {identity_html(props, Some(&character_id))}
// <h2>{"guardian"}</h2>
// {last_protect}
// <TargetPicker
// targets={living_players.clone()}
// marked={marked}
// mark_callback={mark_callback}
// continue_callback={continue_callback}
// />
// </div>
// }
// }
// ActionPrompt::WolfPackKill { living_villagers } => {
// let on_complete = props.on_complete.clone();
// html! {
// <SingleTarget
// targets={living_villagers.clone()}
// target_selection={on_select}
// headline={"wolf pack kill"}
// />
// }
// }
// ActionPrompt::Shapeshifter { character_id } => {
// let on_complete = props.on_complete.clone();
// let on_select = props.big_screen.not().then_some({
// move |shift| {
// on_complete.emit(HostMessage::InGame(HostGameMessage::Night(
// HostNightMessage::ActionResponse(ActionResponse::Shapeshifter(shift)),
// )));
// }
// });
// html! {
// <div>
// {identity_html(props, Some(&character_id))}
// <BinaryChoice on_chosen={on_select}>
// <h2>{"shapeshift?"}</h2>
// </BinaryChoice>
// </div>
// }
// }
// ActionPrompt::AlphaWolf {
// character_id,
// living_villagers,
// } => {
// let on_complete = props.on_complete.clone();
// let on_select = props.big_screen.not().then(|| {
// Callback::from(move |target: Option<CharacterId>| {
// on_complete.emit(HostMessage::InGame(HostGameMessage::Night(
// HostNightMessage::ActionResponse(ActionResponse::AlphaWolf(target)),
// )));
// })
// });
// html! {
// <div>
// {identity_html(props, Some(&character_id))}
// <OptionalSingleTarget
// targets={living_villagers.clone()}
// target_selection={on_select}
// headline={"alpha wolf target"}
// />
// </div>
// }
// }
// ActionPrompt::DireWolf {
// character_id,
// living_players,
// } => {
// let on_complete = props.on_complete.clone();
// let on_select = props.big_screen.not().then(|| {
// Callback::from(move |target: CharacterId| {
// on_complete.emit(HostMessage::InGame(HostGameMessage::Night(
// HostNightMessage::ActionResponse(ActionResponse::Direwolf(target)),
// )));
// })
// });
// html! {
// <div>
// {identity_html(props, Some(&character_id))}
// <SingleTarget
// targets={living_players.clone()}
// target_selection={on_select}
// headline={"direwolf block target"}
// />
// </div>
// }
// }
// }
} }

View File

@ -1,17 +1,20 @@
use core::ops::Not; use core::ops::Not;
use convert_case::{Case, Casing}; use convert_case::{Case, Casing};
use werewolves_proto::{ use werewolves_proto::message::{
message::{ PublicIdentity,
PublicIdentity, host::{HostGameMessage, HostMessage, HostNightMessage},
host::{HostGameMessage, HostMessage, HostNightMessage}, night::ActionResult,
night::ActionResult,
},
role::Alignment,
}; };
use yew::prelude::*; use yew::prelude::*;
use crate::components::{Button, CoverOfDarkness, Icon, IconSource, Identity}; use crate::{
components::{Button, CoverOfDarkness, Icon, IconSource, Identity},
pages::{
AdjudicatorResult, ArcanistResult, EmpathResult, GravediggerResultPage, InsomniacResult,
MorticianResultPage, PowerSeerResult, RoleblockPage, SeerResult,
},
};
#[derive(Debug, Clone, PartialEq, Properties)] #[derive(Debug, Clone, PartialEq, Properties)]
pub struct ActionResultProps { pub struct ActionResultProps {
@ -42,128 +45,42 @@ pub fn ActionResultView(props: &ActionResultProps) -> Html {
.then(|| html! {<Button on_click={on_complete}>{"continue"}</Button>}); .then(|| html! {<Button on_click={on_complete}>{"continue"}</Button>});
let body = match &props.result { let body = match &props.result {
ActionResult::PowerSeer { powerful } => { ActionResult::PowerSeer { powerful } => {
let inactive = powerful.powerful().not().then_some("inactive");
let text = if powerful.powerful() {
"powerful"
} else {
"not powerful"
};
html! { html! {
<> <PowerSeerResult powerful={*powerful}/>
<img src="/img/powerful.svg" class={classes!(inactive)}/>
<h3>{text}</h3>
</>
} }
} }
ActionResult::Adjudicator { killer } => { ActionResult::Adjudicator { killer } => {
let text = if killer.killer() {
"is a killer"
} else {
"is NOT a killer"
};
html! { html! {
<> <AdjudicatorResult killer={*killer}/>
<h1>{"your target..."}</h1>
<Icon source={IconSource::Killer} inactive={killer.killer().not()}/>
<h2>{text}</h2>
</>
} }
} }
ActionResult::Mortician(died_to) => html! { ActionResult::Mortician(died_to) => html! {
<h2>{"cause of death: "}{died_to.to_string().to_case(Case::Title)}</h2> <MorticianResultPage died_to={*died_to}/>
}, },
ActionResult::Empath { scapegoat: true } => html! { ActionResult::Empath { scapegoat } => html! {
<> <EmpathResult scapegoat={*scapegoat}/>
<h2>{"was the scapegoat!"}</h2>
<h3>{"tag! you're it!"}</h3>
</>
},
ActionResult::Empath { scapegoat: false } => html! {
<h2>{"not the scapegoat"}</h2>
}, },
ActionResult::Insomniac(visits) => { ActionResult::Insomniac(visits) => {
let visits = visits
.iter()
.map(|v| {
let ident: PublicIdentity = v.clone().into();
html! {
<Identity ident={ident}/>
}
})
.collect::<Html>();
html! { html! {
<> <InsomniacResult visits={visits.clone()}/>
<h1>{"tonight you were visited by..."}</h1>
<div class="result-list">
{visits}
</div>
</>
} }
} }
ActionResult::RoleBlocked => { ActionResult::RoleBlocked => {
html! { html! {
<h2>{"you were role blocked"}</h2> <RoleblockPage />
} }
} }
ActionResult::Seer(alignment) => html! { ActionResult::Seer(alignment) => html! {
<> <SeerResult alignment={*alignment}/>
<h2>{"the alignment was"}</h2>
{match alignment {
Alignment::Village => html!{
<>
<Icon source={IconSource::Village}/>
<h3>{"village"}</h3>
</>
},
Alignment::Wolves => html!{
<>
<Icon source={IconSource::Wolves}/>
<h3>{"wolves"}</h3>
</>
},
}}
</>
}, },
ActionResult::Arcanist(same) => { ActionResult::Arcanist(same) => {
let outcome = if same.same() {
html! {
<>
<div class="arcanist-result">
<Icon source={IconSource::Village}/>
<Icon source={IconSource::Village}/>
<Icon source={IconSource::Wolves}/>
<Icon source={IconSource::Wolves}/>
</div>
<h2>{"the same"}</h2>
</>
}
} else {
html! {
<>
<div class="arcanist-result">
<Icon source={IconSource::Village}/>
<Icon source={IconSource::Wolves}/>
</div>
<h2>{"different"}</h2>
</>
}
};
html! { html! {
<> <ArcanistResult alignment_eq={*same}/>
<h1>{"the alignments are:"}</h1>
<p>{outcome}</p>
</>
} }
} }
ActionResult::GraveDigger(role_title) => { ActionResult::GraveDigger(role_title) => {
let dig = role_title
.map(|r| r.to_string().to_case(Case::Title))
.unwrap_or_else(|| String::from("an empty grave"));
html! { html! {
<> <GravediggerResultPage role={*role_title}/>
<h2>{"you see:"}</h2>
<p>{dig}</p>
</>
} }
} }
ActionResult::GoBackToSleep => { ActionResult::GoBackToSleep => {

View File

@ -27,7 +27,7 @@ pub fn WolvesIntro(props: &WolvesIntroProps) -> Html {
<div class="row-list wolves-list"> <div class="row-list wolves-list">
{ {
props.wolves.iter().map(|w| html!{ props.wolves.iter().map(|w| html!{
<div class="character wolves"> <div class="character wolves faint">
<p class="role">{w.1.to_string()}</p> <p class="role">{w.1.to_string()}</p>
<Identity ident={Into::<PublicIdentity>::into(&w.0)} /> <Identity ident={Into::<PublicIdentity>::into(&w.0)} />
</div> </div>

View File

@ -1,5 +1,5 @@
use convert_case::{Case, Casing}; use convert_case::{Case, Casing};
use werewolves_proto::{character::Character, game::SetupRole}; use werewolves_proto::{character::Character, game::SetupRole, message::CharacterIdentity};
use yew::prelude::*; use yew::prelude::*;
use crate::components::{Icon, IconSource, IconType, PartialAssociatedIcon}; use crate::components::{Icon, IconSource, IconType, PartialAssociatedIcon};
@ -7,10 +7,14 @@ use crate::components::{Icon, IconSource, IconType, PartialAssociatedIcon};
#[derive(Debug, Clone, PartialEq, Properties)] #[derive(Debug, Clone, PartialEq, Properties)]
pub struct CharacterCardProps { pub struct CharacterCardProps {
pub char: Character, pub char: Character,
#[prop_or_default]
pub dead: bool,
#[prop_or_default]
pub faint: bool,
} }
#[function_component] #[function_component]
pub fn CharacterCard(CharacterCardProps { char }: &CharacterCardProps) -> Html { pub fn CharacterCard(CharacterCardProps { faint, char, dead }: &CharacterCardProps) -> Html {
let class = Into::<SetupRole>::into(char.role_title()) let class = Into::<SetupRole>::into(char.role_title())
.category() .category()
.class(); .class();
@ -28,10 +32,18 @@ pub fn CharacterCard(CharacterCardProps { char }: &CharacterCardProps) -> Html {
IconSource::Wolves IconSource::Wolves
}); });
let dead = dead.then(|| {
html! {
<Icon source={IconSource::Skull} icon_type={IconType::Small}/>
}
});
let faint = faint.then_some("faint");
html! { html! {
<span class={classes!("character-span", class)}> <span class={classes!("character-span", class, faint)}>
<span class={classes!("role", class)}> <span class={classes!("role", class, faint)}>
<div> <div>
{dead}
<Icon source={source} icon_type={IconType::Small}/> <Icon source={source} icon_type={IconType::Small}/>
</div> </div>
{role} {role}
@ -42,3 +54,20 @@ pub fn CharacterCard(CharacterCardProps { char }: &CharacterCardProps) -> Html {
</span> </span>
} }
} }
#[derive(Debug, Clone, PartialEq, Properties)]
pub struct CharacterTargetCardProps {
pub ident: CharacterIdentity,
}
#[function_component]
pub fn CharacterTargetCard(CharacterTargetCardProps { ident }: &CharacterTargetCardProps) -> Html {
let name = ident.name.clone();
html! {
<span class={classes!("character-span")}>
<span class={classes!("number")}><b>{ident.number.get()}</b></span>
<span class="name">{name}</span>
</span>
}
}

View File

@ -4,43 +4,51 @@ use werewolves_proto::{
}; };
use yew::prelude::*; use yew::prelude::*;
#[derive(Debug, Clone, Copy, PartialEq)] macro_rules! decl_icon {
pub enum IconSource { ($($name:ident: $path:literal,)*) => {
Village, #[derive(Debug, Clone, Copy, PartialEq, Eq)]
Wolves, pub enum IconSource {
Killer, $(
Powerful, $name,
ListItem, )*
Skull, }
Heart,
Shield, impl IconSource {
ShieldAndSword, pub const fn source(&self) -> &'static str {
Seer, match self {
Hunter, $(
MapleWolf, Self::$name => $path,
Gravedigger, )*
PowerSeer, }
}
}
};
} }
decl_icon!(
Village: "/img/village.svg",
Wolves: "/img/wolf.svg",
Killer: "/img/killer.svg",
Powerful: "/img/powerful.svg",
ListItem: "/img/li.svg",
Skull: "/img/skull.svg",
Heart: "/img/heart.svg",
Shield: "/img/shield.svg",
ShieldAndSword: "/img/shield-and-sword.svg",
Seer: "/img/seer.svg",
Hunter: "/img/hunter.svg",
MapleWolf: "/img/maple-wolf.svg",
Gravedigger: "/img/gravedigger.svg",
PowerSeer: "/img/power-seer.svg",
Scapegoat: "/img/scapegoat.svg",
Diseased: "/img/diseased.svg",
Mortician: "/img/mortician.svg",
Pyremaster: "/img/pyremaster.svg",
Sword: "/img/sword.svg",
Roleblock: "/img/roleblock.svg",
);
impl IconSource { impl IconSource {
pub const fn source(&self) -> &'static str {
match self {
IconSource::Village => "/img/village.svg",
IconSource::Wolves => "/img/wolf.svg",
IconSource::Killer => "/img/killer.svg",
IconSource::Powerful => "/img/powerful.svg",
IconSource::ListItem => "/img/li.svg",
IconSource::Skull => "/img/skull.svg",
IconSource::Heart => "/img/heart.svg",
IconSource::Shield => "/img/shield.svg",
IconSource::ShieldAndSword => "/img/shield-and-sword.svg",
IconSource::Seer => "/img/seer.svg",
IconSource::Hunter => "/img/hunter.svg",
IconSource::MapleWolf => "/img/maple-wolf.svg",
IconSource::Gravedigger => "/img/gravedigger.svg",
IconSource::PowerSeer => "/img/power-seer.svg",
}
}
pub const fn class(&self) -> Option<&'static str> { pub const fn class(&self) -> Option<&'static str> {
match self { match self {
IconSource::Killer => Some("killer"), IconSource::Killer => Some("killer"),
@ -53,6 +61,7 @@ impl IconSource {
#[derive(Debug, Clone, Copy, PartialEq, Default)] #[derive(Debug, Clone, Copy, PartialEq, Default)]
pub enum IconType { pub enum IconType {
Small, Small,
Informational,
#[default] #[default]
RoleCheck, RoleCheck,
} }
@ -61,6 +70,7 @@ impl IconType {
pub const fn class(&self) -> &'static str { pub const fn class(&self) -> &'static str {
match self { match self {
IconType::Small => "icon", IconType::Small => "icon",
IconType::Informational => "icon-info",
IconType::RoleCheck => "check-icon", IconType::RoleCheck => "check-icon",
} }
} }
@ -122,27 +132,27 @@ impl AssociatedIcon for Powerful {
impl PartialAssociatedIcon for RoleTitle { impl PartialAssociatedIcon for RoleTitle {
fn icon(&self) -> Option<IconSource> { fn icon(&self) -> Option<IconSource> {
Some(match self { Some(match self {
RoleTitle::Scapegoat RoleTitle::Arcanist
| RoleTitle::Arcanist
| RoleTitle::Adjudicator | RoleTitle::Adjudicator
| RoleTitle::Mortician
| RoleTitle::Beholder | RoleTitle::Beholder
| RoleTitle::MasonLeader | RoleTitle::MasonLeader
| RoleTitle::Diseased
| RoleTitle::BlackKnight | RoleTitle::BlackKnight
| RoleTitle::Weightlifter | RoleTitle::Weightlifter
| RoleTitle::PyreMaster
| RoleTitle::Militia
| RoleTitle::Apprentice | RoleTitle::Apprentice
| RoleTitle::Elder | RoleTitle::Elder
| RoleTitle::Insomniac | RoleTitle::Insomniac
| RoleTitle::Werewolf
| RoleTitle::AlphaWolf | RoleTitle::AlphaWolf
| RoleTitle::DireWolf | RoleTitle::DireWolf
| RoleTitle::Shapeshifter | RoleTitle::Shapeshifter
| RoleTitle::LoneWolf | RoleTitle::LoneWolf
| RoleTitle::Villager => return None, | RoleTitle::Villager => return None,
RoleTitle::Werewolf => IconSource::Wolves,
RoleTitle::Militia => IconSource::Sword,
RoleTitle::PyreMaster => IconSource::Pyremaster,
RoleTitle::Mortician => IconSource::Mortician,
RoleTitle::Diseased => IconSource::Diseased,
RoleTitle::Scapegoat => IconSource::Scapegoat,
RoleTitle::PowerSeer => IconSource::PowerSeer, RoleTitle::PowerSeer => IconSource::PowerSeer,
RoleTitle::Gravedigger => IconSource::Gravedigger, RoleTitle::Gravedigger => IconSource::Gravedigger,
RoleTitle::MapleWolf => IconSource::MapleWolf, RoleTitle::MapleWolf => IconSource::MapleWolf,
@ -160,13 +170,13 @@ impl PartialAssociatedIcon for DiedToTitle {
match self { match self {
DiedToTitle::Execution => Some(IconSource::Skull), DiedToTitle::Execution => Some(IconSource::Skull),
DiedToTitle::MapleWolf | DiedToTitle::MapleWolfStarved => Some(IconSource::MapleWolf), DiedToTitle::MapleWolf | DiedToTitle::MapleWolfStarved => Some(IconSource::MapleWolf),
DiedToTitle::Militia => Some(IconSource::Killer), DiedToTitle::Militia => Some(IconSource::Sword),
DiedToTitle::Wolfpack => None, DiedToTitle::Wolfpack => None,
DiedToTitle::AlphaWolf => None, DiedToTitle::AlphaWolf => None,
DiedToTitle::Shapeshift => None, DiedToTitle::Shapeshift => None,
DiedToTitle::Hunter => Some(IconSource::Hunter), DiedToTitle::Hunter => Some(IconSource::Hunter),
DiedToTitle::GuardianProtecting => Some(IconSource::ShieldAndSword), DiedToTitle::GuardianProtecting => Some(IconSource::ShieldAndSword),
DiedToTitle::PyreMaster => None, DiedToTitle::PyreMaster => Some(IconSource::Pyremaster),
DiedToTitle::PyreMasterLynchMob => None, DiedToTitle::PyreMasterLynchMob => None,
DiedToTitle::MasonLeaderRecruitFail => None, DiedToTitle::MasonLeaderRecruitFail => None,
DiedToTitle::LoneWolf => None, DiedToTitle::LoneWolf => None,

View File

@ -29,14 +29,21 @@ pub struct StoryProps {
#[function_component] #[function_component]
pub fn Story(StoryProps { story }: &StoryProps) -> Html { pub fn Story(StoryProps { story }: &StoryProps) -> Html {
let characters = Rc::new( let final_characters =
story story
.starting_village .final_village()
.unwrap_or_else(|_| story.starting_village.clone())
.characters() .characters()
.into_iter() .into_iter()
.map(|c| (c.character_id(), c)) .map(|c| {
.collect::<HashMap<CharacterId, Character>>(), let dead =c.alive().not();
); html! {
<>
<CharacterCard faint=true char={c} dead={dead}/>
</>
}
})
.collect::<Html>();
let bits = story let bits = story
.iter() .iter()
.map(|(time, changes)| { .map(|(time, changes)| {
@ -51,7 +58,12 @@ pub fn Story(StoryProps { story }: &StoryProps) -> Html {
}).ok().flatten() }).ok().flatten()
.map(|v| Rc::new(v.characters().into_iter() .map(|v| Rc::new(v.characters().into_iter()
.map(|c| (c.character_id(), c)) .map(|c| (c.character_id(), c))
.collect::<HashMap<CharacterId, Character>>())).unwrap_or_else(|| characters.clone()); .collect::<HashMap<CharacterId, Character>>()))
.unwrap_or_else(||
Rc::new(story.starting_village
.characters().into_iter()
.map(|c| (c.character_id(), c))
.collect::<HashMap<_, _>>()));
let changes = match changes { let changes = match changes {
GameActions::DayDetails(day_changes) => { GameActions::DayDetails(day_changes) => {
let execute_list = if day_changes.is_empty() { let execute_list = if day_changes.is_empty() {
@ -66,7 +78,7 @@ pub fn Story(StoryProps { story }: &StoryProps) -> Html {
.map(|c| { .map(|c| {
html! { html! {
// <span> // <span>
<CharacterCard char={c.clone()}/> <CharacterCard faint=true char={c.clone()}/>
// </span> // </span>
} }
}) })
@ -134,6 +146,9 @@ pub fn Story(StoryProps { story }: &StoryProps) -> Html {
.collect::<Html>(); .collect::<Html>();
html! { html! {
<div class="story"> <div class="story">
<div class="cast">
{final_characters}
</div>
{bits} {bits}
</div> </div>
} }
@ -156,9 +171,9 @@ fn StoryNightChange(StoryNightChangeProps { change, characters }: &StoryNightCha
html! { html! {
<> <>
<CharacterCard char={char.clone()}/> <CharacterCard faint=true char={char.clone()}/>
{"is now"} {"is now"}
<CharacterCard char={new_char.clone()}/> <CharacterCard faint=true char={new_char.clone()}/>
</> </>
} }
}) })
@ -170,7 +185,7 @@ fn StoryNightChange(StoryNightChangeProps { change, characters }: &StoryNightCha
html! { html! {
<> <>
<Icon source={IconSource::Skull} icon_type={IconType::Small}/> <Icon source={IconSource::Skull} icon_type={IconType::Small}/>
<CharacterCard char={target.clone()}/> <CharacterCard faint=true char={target.clone()}/>
{"died to"} {"died to"}
<DiedToSpan died_to={died_to.title()}/> <DiedToSpan died_to={died_to.title()}/>
</> </>
@ -183,9 +198,9 @@ fn StoryNightChange(StoryNightChangeProps { change, characters }: &StoryNightCha
.map(|(source, target)| { .map(|(source, target)| {
html! { html! {
<> <>
<CharacterCard char={source.clone()}/> <CharacterCard faint=true char={source.clone()}/>
{"role blocked"} {"role blocked"}
<CharacterCard char={target.clone()}/> <CharacterCard faint=true char={target.clone()}/>
</> </>
} }
}) })
@ -196,9 +211,9 @@ fn StoryNightChange(StoryNightChangeProps { change, characters }: &StoryNightCha
.map(|(source, into)| { .map(|(source, into)| {
html! { html! {
<> <>
<CharacterCard char={source.clone()}/> <CharacterCard faint=true char={source.clone()}/>
{"shapeshifted into"} {"shapeshifted into"}
<CharacterCard char={into.clone()}/> <CharacterCard faint=true char={into.clone()}/>
</> </>
} }
}) })
@ -209,7 +224,7 @@ fn StoryNightChange(StoryNightChangeProps { change, characters }: &StoryNightCha
.map(|elder| { .map(|elder| {
html! { html! {
<> <>
<CharacterCard char={elder.clone()}/> <CharacterCard faint=true char={elder.clone()}/>
{"learned they are the Elder"} {"learned they are the Elder"}
</> </>
} }
@ -221,9 +236,9 @@ fn StoryNightChange(StoryNightChangeProps { change, characters }: &StoryNightCha
.map(|(empath, scapegoat)| { .map(|(empath, scapegoat)| {
html! { html! {
<> <>
<CharacterCard char={empath.clone()}/> <CharacterCard faint=true char={empath.clone()}/>
{"found the scapegoat in"} {"found the scapegoat in"}
<CharacterCard char={scapegoat.clone()}/> <CharacterCard faint=true char={scapegoat.clone()}/>
{"and took on their curse"} {"and took on their curse"}
</> </>
} }
@ -304,7 +319,7 @@ fn StoryNightResult(StoryNightResultProps { result, characters }: &StoryNightRes
.filter_map(|c| characters.get(c)) .filter_map(|c| characters.get(c))
.map(|c| { .map(|c| {
html! { html! {
<CharacterCard char={c.clone()}/> <CharacterCard faint=true char={c.clone()}/>
} }
}) })
.collect::<Html>(); .collect::<Html>();
@ -353,9 +368,9 @@ fn StoryNightChoice(StoryNightChoiceProps { choice, characters }: &StoryNightCho
.map(|(char, chosen)| { .map(|(char, chosen)| {
html! { html! {
<> <>
<CharacterCard char={char.clone()}/> <CharacterCard faint=true char={char.clone()}/>
<span>{action}</span> <span>{action}</span>
<CharacterCard char={chosen.clone()}/> <CharacterCard faint=true char={chosen.clone()}/>
</> </>
} }
}) })
@ -375,11 +390,11 @@ fn StoryNightChoice(StoryNightChoiceProps { choice, characters }: &StoryNightCho
.map(|(arcanist, chosen1, chosen2)| { .map(|(arcanist, chosen1, chosen2)| {
html! { html! {
<> <>
<CharacterCard char={arcanist.clone()}/> <CharacterCard faint=true char={arcanist.clone()}/>
<span>{"compared"}</span> <span>{"compared"}</span>
<CharacterCard char={chosen1.clone()}/> <CharacterCard faint=true char={chosen1.clone()}/>
<span>{"and"}</span> <span>{"and"}</span>
<CharacterCard char={chosen2.clone()}/> <CharacterCard faint=true char={chosen2.clone()}/>
</> </>
} }
}), }),
@ -389,13 +404,13 @@ fn StoryNightChoice(StoryNightChoiceProps { choice, characters }: &StoryNightCho
.filter_map(|m| characters.get(m)) .filter_map(|m| characters.get(m))
.map(|c| { .map(|c| {
html! { html! {
<CharacterCard char={c.clone()}/> <CharacterCard faint=true char={c.clone()}/>
} }
}) })
.collect::<Html>(); .collect::<Html>();
html! { html! {
<> <>
<CharacterCard char={leader.clone()}/> <CharacterCard faint=true char={leader.clone()}/>
<span>{"'s masons"}</span> <span>{"'s masons"}</span>
{masons} {masons}
<span>{"convened in secret"}</span> <span>{"convened in secret"}</span>
@ -447,9 +462,9 @@ fn StoryNightChoice(StoryNightChoiceProps { choice, characters }: &StoryNightCho
.map(|(char, chosen)| { .map(|(char, chosen)| {
html! { html! {
<> <>
<CharacterCard char={char.clone()}/> <CharacterCard faint=true char={char.clone()}/>
<span>{"invited"}</span> <span>{"invited"}</span>
<CharacterCard char={chosen.clone()}/> <CharacterCard faint=true char={chosen.clone()}/>
<span>{"for dinner"}</span> <span>{"for dinner"}</span>
</> </>
} }
@ -486,7 +501,7 @@ fn StoryNightChoice(StoryNightChoiceProps { choice, characters }: &StoryNightCho
<> <>
<AlignmentSpan alignment={Alignment::Wolves}/> <AlignmentSpan alignment={Alignment::Wolves}/>
<span>{"attempted a kill on"}</span> <span>{"attempted a kill on"}</span>
<CharacterCard char={chosen.clone()} /> <CharacterCard faint=true char={chosen.clone()} />
</> </>
} }
}) })
@ -495,7 +510,7 @@ fn StoryNightChoice(StoryNightChoiceProps { choice, characters }: &StoryNightCho
characters.get(character_id).map(|shifter| { characters.get(character_id).map(|shifter| {
html! { html! {
<> <>
<CharacterCard char={shifter.clone()} /> <CharacterCard faint=true char={shifter.clone()} />
<span>{"decided to shapeshift into the wolf kill target"}</span> <span>{"decided to shapeshift into the wolf kill target"}</span>
</> </>
} }
@ -517,7 +532,7 @@ fn StoryNightChoice(StoryNightChoiceProps { choice, characters }: &StoryNightCho
characters.get(character_id).map(|insomniac| { characters.get(character_id).map(|insomniac| {
html! { html! {
<> <>
<CharacterCard char={insomniac.clone()} /> <CharacterCard faint=true char={insomniac.clone()} />
<span>{"witnessed visits from"}</span> <span>{"witnessed visits from"}</span>
</> </>
} }

View File

@ -0,0 +1,36 @@
use convert_case::{Case, Casing};
use werewolves_proto::{
game::SetupRole,
role::{Alignment, RoleTitle},
};
use yew::prelude::*;
use crate::components::{AssociatedIcon, Icon, IconSource, IconType, PartialAssociatedIcon};
#[derive(Debug, Clone, Copy, PartialEq, Properties)]
pub struct RoleChangePageProps {
pub role: RoleTitle,
}
#[function_component]
pub fn RoleChangePage(RoleChangePageProps { role }: &RoleChangePageProps) -> Html {
let class = Into::<SetupRole>::into(*role).category().class();
let icon = role.icon().map(|icon| {
html! {
<h4 class="icons">
<Icon source={icon} icon_type={IconType::Informational}/>
</h4>
}
});
html! {
<div class="role-page">
<h1 class="intel">{"ROLE CHANGE"}</h1>
<div class={classes!("information", class, "faint")}>
<h2>{"YOUR ROLE HAS CHANGED"}</h2>
{icon}
<h3 class="yellow">{"YOUR NEW ROLE IS"}</h3>
<h3>{role.to_string().to_case(Case::Upper)}</h3>
</div>
</div>
}
}

View File

@ -1,10 +1,16 @@
use core::ops::Not; use core::ops::Not;
use std::rc::Rc; use std::rc::Rc;
use werewolves_proto::message::{PublicIdentity, night::ActionPrompt}; use werewolves_proto::{
message::{CharacterIdentity, PublicIdentity, night::ActionPrompt},
role::PreviousGuardianAction,
};
use yew::prelude::*; use yew::prelude::*;
use crate::components::Identity; use crate::{
components::Identity,
pages::{RoleChangePage, WolfpackKillPage},
};
werewolves_macros::include_path!("werewolves/src/pages/role_page"); werewolves_macros::include_path!("werewolves/src/pages/role_page");
pub trait RolePage { pub trait RolePage {
@ -13,28 +19,194 @@ pub trait RolePage {
impl RolePage for ActionPrompt { impl RolePage for ActionPrompt {
fn role_pages(&self, big_screen: bool) -> Rc<[yew::Html]> { fn role_pages(&self, big_screen: bool) -> Rc<[yew::Html]> {
let ident = |character_id: &CharacterIdentity| {
big_screen.not().then(|| {
html! {
<Identity ident={Into::<PublicIdentity>::into(character_id)} />
}
})
};
match self { match self {
ActionPrompt::Beholder { character_id, .. } => { ActionPrompt::Beholder { character_id, .. } => Rc::new([html! {
let ident = big_screen.not().then(|| { <>
html! { {ident(character_id)}
<Identity ident={Into::<PublicIdentity>::into(character_id)} /> <BeholderPage1 />
} </>
}); }]),
Rc::new([ ActionPrompt::DireWolf { character_id, .. } => Rc::new([html! {
html! { <>
<> {ident(character_id)}
{ident.clone()} <DirewolfPage1 />
<BeholderPage1 /> </>
</> }]),
}, ActionPrompt::Adjudicator { character_id, .. } => Rc::new([html! {
html! { <>
<> {ident(character_id)}
{ident} <AdjudicatorPage1 />
<BeholderPage2 /> </>
</> }]),
}, ActionPrompt::Seer { character_id, .. } => Rc::new([html! {
]) <>
} {ident(character_id)}
<SeerPage1 />
</>
}]),
ActionPrompt::PowerSeer { character_id, .. } => Rc::new([html! {
<>
{ident(character_id)}
<PowerSeerPage1 />
</>
}]),
ActionPrompt::Arcanist { character_id, .. } => Rc::new([html! {
<>
{ident(character_id)}
<ArcanistPage1 />
</>
}]),
ActionPrompt::Protector { character_id, .. } => Rc::new([html! {
<>
{ident(character_id)}
<ProtectorPage1 />
</>
}]),
ActionPrompt::Empath { character_id, .. } => Rc::new([html! {
<>
{ident(character_id)}
<EmpathPage1 />
</>
}]),
ActionPrompt::Hunter { character_id, .. } => Rc::new([html! {
<>
{ident(character_id)}
<HunterPage1 />
</>
}]),
ActionPrompt::PyreMaster { character_id, .. } => Rc::new([html! {
<>
{ident(character_id)}
<PyremasterPage1 />
</>
}]),
ActionPrompt::Militia { character_id, .. } => Rc::new([html! {
<>
{ident(character_id)}
<MilitiaPage1 />
</>
}]),
ActionPrompt::MapleWolf {
character_id,
kill_or_die,
..
} => Rc::new([html! {
<>
{ident(character_id)}
<MapleWolfPage1 starving={*kill_or_die} />
</>
}]),
ActionPrompt::MasonLeaderRecruit {
character_id,
recruits_left,
..
} => Rc::new([html! {
<>
{ident(character_id)}
<MasonRecruitPage1 recruits_left={*recruits_left} />
</>
}]),
ActionPrompt::MasonsWake { leader, masons } => Rc::new([html! {
<>
{ident(leader)}
<MasonsWake leader={leader.clone()} masons={masons.clone()}/>
</>
}]),
ActionPrompt::AlphaWolf { character_id, .. } => Rc::new([html! {
<>
{ident(character_id)}
<AlphaWolfPage1 />
</>
}]),
ActionPrompt::Insomniac { character_id, .. } => Rc::new([html! {
<>
{ident(character_id)}
<InsomniacPage1 />
</>
}]),
ActionPrompt::ElderReveal { character_id, .. } => Rc::new([html! {
<>
{ident(character_id)}
<ElderPage1 />
</>
}]),
ActionPrompt::Guardian {
character_id,
previous: None,
..
} => Rc::new([html! {
<>
{ident(character_id)}
<GuardianPageNoPrevProtect/>
</>
}]),
ActionPrompt::Guardian {
character_id,
previous: Some(PreviousGuardianAction::Protect(target)),
..
} => Rc::new([
html! {
<>
{ident(character_id)}
<GuardianPagePreviousProtect1 previous={target.clone()}/>
</>
},
html! {
<>
{ident(character_id)}
<GuardianPagePreviousProtect2 previous={target.clone()}/>
</>
},
]),
ActionPrompt::Guardian {
character_id,
previous: Some(PreviousGuardianAction::Guard(target)),
..
} => Rc::new([html! {
<>
{ident(character_id)}
<GuardianPagePreviousGuard previous={target.clone()}/>
</>
}]),
ActionPrompt::Mortician { character_id, .. } => Rc::new([html! {
<>
{ident(character_id)}
<MorticianPage1 />
</>
}]),
ActionPrompt::RoleChange {
character_id,
new_role,
} => Rc::new([html! {
<>
{ident(character_id)}
<RoleChangePage role={*new_role}/>
</>
}]),
ActionPrompt::WolfPackKill { .. } => Rc::new([html! {
<>
<WolfpackKillPage />
</>
}]),
ActionPrompt::Gravedigger { character_id, .. } => Rc::new([html! {
<>
{ident(character_id)}
<GravediggerPage1 />
</>
}]),
ActionPrompt::Vindicator { character_id, .. } => Rc::new([html! {
<>
{ident(character_id)}
<VindicatorPage1 />
</>
}]),
_ => Rc::new([]), _ => Rc::new([]),
} }
} }

View File

@ -0,0 +1,50 @@
use core::ops::Not;
use werewolves_proto::role::Killer;
use yew::prelude::*;
use crate::components::{Icon, IconSource, IconType};
#[function_component]
pub fn AdjudicatorPage1() -> Html {
html! {
<div class="role-page">
<h1 class="defensive">{"ADJUDICATOR"}</h1>
<div class="information defensive faint">
<h2>{"PICK A PLAYER"}</h2>
<h4 class="icons">
<Icon source={IconSource::Killer} icon_type={IconType::Informational}/>
<Icon source={IconSource::Killer} icon_type={IconType::Informational} inactive={true}/>
</h4>
<h3 class="yellow">{"YOU WILL CHECK IF THEY APPEAR AS A KILLER"}</h3>
</div>
</div>
}
}
#[derive(Debug, Clone, Copy, PartialEq, Properties)]
pub struct AdjudicatorResultProps {
pub killer: Killer,
}
#[function_component]
pub fn AdjudicatorResult(AdjudicatorResultProps { killer }: &AdjudicatorResultProps) -> Html {
let text = match killer {
Killer::Killer => "IS A KILLER",
Killer::NotKiller => "IS NOT A KILLER",
};
html! {
<div class="role-page">
<h1 class="defensive">{"ADJUDICATOR"}</h1>
<div class="information defensive faint">
<h2>{"YOUR TARGET"}</h2>
<h4><Icon
source={IconSource::Killer}
icon_type={IconType::Informational}
inactive={killer.killer().not()}
/></h4>
<h3 class="yellow">{text}</h3>
</div>
</div>
}
}

View File

@ -0,0 +1,21 @@
use yew::prelude::*;
#[function_component]
pub fn AlphaWolfPage1() -> Html {
html! {
<div class="role-page">
<h1 class="wolves">{"ALPHA WOLF"}</h1>
<div class="information wolves faint">
<h2>
{"IF YOU WISH TO USE YOUR "}
<span class="yellow">{"ONCE PER GAME"}</span>
{" KILL ABILITY"}
</h2>
<h3 class="yellow">
{"POINT AT YOUR TARGET "}
{"OR GO BACK TO SLEEP"}
</h3>
</div>
</div>
}
}

View File

@ -0,0 +1,68 @@
use werewolves_proto::role::AlignmentEq;
use yew::prelude::*;
use crate::components::{Icon, IconSource, IconType};
#[function_component]
pub fn ArcanistPage1() -> Html {
html! {
<div class="role-page">
<h1 class="intel">{"ARCANIST"}</h1>
<div class="information intel faint">
<h2>{"PICK TWO PLAYERS"}</h2>
<h4 class="icons">
<Icon source={IconSource::Village} icon_type={IconType::Informational}/>
<Icon source={IconSource::Village} icon_type={IconType::Informational}/>
<Icon source={IconSource::Wolves} icon_type={IconType::Informational}/>
<Icon source={IconSource::Wolves} icon_type={IconType::Informational}/>
</h4>
<h3 class="yellow">{"YOU WILL CHECK IF THEIR ALIGNMENTS ARE THE SAME OR DIFFERENT"}</h3>
</div>
</div>
}
}
#[derive(Debug, Clone, Copy, PartialEq, Properties)]
pub struct ArcanistResultProps {
pub alignment_eq: AlignmentEq,
}
#[function_component]
pub fn ArcanistResult(ArcanistResultProps { alignment_eq }: &ArcanistResultProps) -> Html {
let text = match alignment_eq {
AlignmentEq::Same => "THE SAME",
AlignmentEq::Different => "DIFFERENT",
};
let icons = match alignment_eq {
AlignmentEq::Same => html! {
<>
<Icon source={IconSource::Village} icon_type={IconType::Informational}/>
<Icon source={IconSource::Village} icon_type={IconType::Informational}/>
<span>{"OR"}</span>
<Icon source={IconSource::Wolves} icon_type={IconType::Informational}/>
<Icon source={IconSource::Wolves} icon_type={IconType::Informational}/>
</>
},
AlignmentEq::Different => html! {
<>
<Icon source={IconSource::Village} icon_type={IconType::Informational}/>
<Icon source={IconSource::Wolves} icon_type={IconType::Informational}/>
{"OR"}
<Icon source={IconSource::Wolves} icon_type={IconType::Informational}/>
<Icon source={IconSource::Village} icon_type={IconType::Informational}/>
</>
},
};
html! {
<div class="role-page">
<h1 class="intel">{"ARCANIST"}</h1>
<div class="information intel faint">
<h2>{"YOUR TARGETS APPEAR AS"}</h2>
<h4 class="icons">
{icons}
</h4>
<h3 class="yellow">{text}</h3>
</div>
</div>
}
}

View File

@ -3,19 +3,12 @@ use yew::prelude::*;
#[function_component] #[function_component]
pub fn BeholderPage1() -> Html { pub fn BeholderPage1() -> Html {
html! { html! {
<div> <div class="role-page">
<h1>{"this is a beholder"}</h1> <h1 class="intel">{"BEHOLDER"}</h1>
<h2>{"there's information on this page"}</h2> <div class="information intel faint">
</div> <h2>{"PICK A PLAYER"}</h2>
} <h3 class="yellow">{"IF THEY ARE AN INTEL ROLE, YOU WILL SEE WHAT THEY SAW TONIGHT"}</h3>
} </div>
#[function_component]
pub fn BeholderPage2() -> Html {
html! {
<div>
<h1>{"more information on beholder"}</h1>
<h2>{"idk, hi?"}</h2>
</div> </div>
} }
} }

View File

@ -0,0 +1,15 @@
use yew::prelude::*;
#[function_component]
pub fn DirewolfPage1() -> Html {
html! {
<div class="role-page">
<h1 class="wolves">{"DIREWOLF"}</h1>
<div class="information wolves faint">
<h2>{"CHOOSE A TARGET"}</h2>
<h3 class="yellow">{"ANY VISITORS TO THIS TARGET WILL BE ROLE BLOCKED"}</h3>
<h4>{"YOU CANNOT CHOOSE YOURSELF OR THE SAME TARGET AS LAST NIGHT"}</h4>
</div>
</div>
}
}

View File

@ -0,0 +1,21 @@
use yew::prelude::*;
#[function_component]
pub fn ElderPage1() -> Html {
html! {
<div class="role-page">
<h1 class="starts-as-villager">{"ELDER"}</h1>
<div class="information starts-as-villager faint">
<h2>{"YOU ARE THE ELDER"}</h2>
<h4 class="yellow">
{"IF YOU ARE EXECUTED BY THE VILLAGE FROM NOW ON "}
{"ALL POWER ROLES WILL BE LOST"}
</h4>
<h4>
{"YOU STARTED THE GAME WITH PROTECTION FROM A NIGHT "}
{"DEATH — THIS MAY OR MAY NOT STILL BE INTACT"}
</h4>
</div>
</div>
}
}

View File

@ -0,0 +1,48 @@
use core::ops::Not;
use yew::prelude::*;
use crate::components::{Icon, IconSource, IconType};
#[function_component]
pub fn EmpathPage1() -> Html {
html! {
<div class="role-page">
<h1 class="intel">{"EMPATH"}</h1>
<div class="information intel faint">
<h2>{"PICK A PLAYER"}</h2>
<h3 class="yellow">{"YOU WILL CHECK IF THEY ARE THE SCAPEGOAT"}</h3>
<h3>{"AND IF THEY ARE, TAKE ON THEIR CURSE"}</h3>
</div>
</div>
}
}
#[derive(Debug, Clone, Copy, PartialEq, Properties)]
pub struct EmpathResultProps {
pub scapegoat: bool,
}
#[function_component]
pub fn EmpathResult(EmpathResultProps { scapegoat }: &EmpathResultProps) -> Html {
let text = match scapegoat {
true => "THE SCAPEGOAT",
false => "NOT THE SCAPEGOAT",
};
html! {
<div class="role-page">
<h1 class="intel">{"EMPATH"}</h1>
<div class="information intel faint">
<h2>{"YOUR TARGET IS"}</h2>
<h4>
<Icon
source={IconSource::Scapegoat}
icon_type={IconType::Informational}
inactive={scapegoat.not()}
/>
</h4>
<h3 class="yellow">{text}</h3>
</div>
</div>
}
}

View File

@ -0,0 +1,74 @@
use convert_case::{Case, Casing};
use werewolves_proto::role::RoleTitle;
use yew::prelude::*;
use crate::components::{Icon, IconSource, IconType, PartialAssociatedIcon};
#[function_component]
pub fn GravediggerPage1() -> Html {
html! {
<div class="role-page">
<h1 class="intel">{"GRAVEDIGGER"}</h1>
<div class="information intel faint">
<h2>
{"PICK A "}
<span class="yellow">{"DEAD"}</span>
{" PLAYER"}
</h2>
<div class="icons">
<Icon source={IconSource::Gravedigger} icon_type={IconType::Informational}/>
</div>
<h3 class="yellow">
{"YOU WILL LEARN THEIR ROLE"}
</h3>
</div>
</div>
}
}
#[derive(Debug, Clone, Copy, PartialEq, Properties)]
pub struct GravediggerResultPageProps {
pub role: Option<RoleTitle>,
}
#[function_component]
pub fn GravediggerResultPage(
GravediggerResultPageProps { role }: &GravediggerResultPageProps,
) -> Html {
let text = role
.as_ref()
.map(|r| {
html! {
<h4>
{"YOU DIG UP THE BODY OF A "}
<span class="yellow">
{r.to_string().to_case(Case::Upper)}
</span>
</h4>
}
})
.unwrap_or_else(|| {
html! {
<h4>{"BUT INSTEAD YOU FIND AN EMPTY GRAVE"}</h4>
}
});
let icon = role
.as_ref()
.and_then(|i| i.icon())
.unwrap_or(IconSource::Gravedigger);
html! {
<div class="role-page">
<h1 class="intel">{"GRAVEDIGGER"}</h1>
<div class="information intel faint">
<h2>{"YOU CHECK THE ROLE OF YOUR TARGET"}</h2>
<h4>
<Icon
source={icon}
icon_type={IconType::Informational}
/>
</h4>
{text}
</div>
</div>
}
}

View File

@ -0,0 +1,76 @@
use werewolves_proto::message::CharacterIdentity;
use yew::prelude::*;
use crate::components::{CharacterTargetCard, Icon, IconSource, IconType};
#[derive(Debug, Clone, PartialEq, Properties)]
pub struct GuardianPageProps {
pub previous: CharacterIdentity,
}
#[function_component]
pub fn GuardianPageNoPrevProtect() -> Html {
html! {
<div class="role-page">
<h1 class="defensive">{"GUARDIAN"}</h1>
<div class="information defensive faint">
<h2>{"PICK A PLAYER"}</h2>
<h4 class="icons">
<Icon source={IconSource::ShieldAndSword} icon_type={IconType::Informational}/>
</h4>
<h3 class="yellow">{"CHOOSE SOMEONE TO PROTECT FROM DEATH"}</h3>
</div>
</div>
}
}
#[function_component]
pub fn GuardianPagePreviousProtect1(GuardianPageProps { previous }: &GuardianPageProps) -> Html {
html! {
<div class="role-page">
<h1 class="defensive">{"GUARDIAN"}</h1>
<div class="information defensive faint">
<h2>{"LAST TIME YOU PROTECTED"}</h2>
<div class="info-player-list">
<CharacterTargetCard ident={previous.clone()} />
</div>
<h3 class="yellow">{"IF YOU PROTECT THEM AGAIN, YOU WILL INSTEAD GUARD THEM"}</h3>
</div>
</div>
}
}
#[function_component]
pub fn GuardianPagePreviousProtect2(GuardianPageProps { previous }: &GuardianPageProps) -> Html {
html! {
<div class="role-page">
<h1 class="defensive">{"GUARDIAN"}</h1>
<div class="information defensive faint">
<h2>{"LAST TIME YOU PROTECTED"}</h2>
<div class="info-player-list">
<CharacterTargetCard ident={previous.clone()} />
</div>
<h3 class="yellow">{"IF ATTACKED WHILE GUARDED, YOU AND THEIR ATTACKER WILL INSTEAD DIE"}</h3>
</div>
</div>
}
}
#[function_component]
pub fn GuardianPagePreviousGuard(GuardianPageProps { previous }: &GuardianPageProps) -> Html {
html! {
<div class="role-page">
<h1 class="defensive">{"GUARDIAN"}</h1>
<div class="information defensive faint">
<h2>{"LAST TIME YOU GUARDED"}</h2>
<div class="info-player-list">
<CharacterTargetCard ident={previous.clone()} />
</div>
<h4 class="icons">
<Icon source={IconSource::ShieldAndSword} icon_type={IconType::Informational}/>
</h4>
<h3 class="yellow">{"YOU CANNOT PROTECT THEM TONIGHT"}</h3>
</div>
</div>
}
}

View File

@ -0,0 +1,22 @@
use yew::prelude::*;
use crate::components::{Icon, IconSource, IconType};
#[function_component]
pub fn HunterPage1() -> Html {
html! {
<div class="role-page">
<h1 class="offensive">{"HUNTER"}</h1>
<div class="information offensive faint">
<h2>{"SET A HUNTER'S TRAP ON A PLAYER"}</h2>
<div class="icons">
<Icon source={IconSource::Hunter} icon_type={IconType::Informational}/>
</div>
<h3 class="yellow">
{"IF YOU DIE TONIGHT, OR ARE EXECUTED TOMORROW"}
{"THIS PLAYER WILL DIE AT NIGHT AS WELL"}
</h3>
</div>
</div>
}
}

View File

@ -0,0 +1,47 @@
use werewolves_proto::message::night::Visits;
use yew::prelude::*;
use crate::components::CharacterTargetCard;
#[function_component]
pub fn InsomniacPage1() -> Html {
html! {
<div class="role-page">
<h1 class="intel">{"INSOMNIAC"}</h1>
<div class="information intel faint">
<h2>{"YOUR POOR SLEEP RESULTS IN BEING WOKEN BY VISITORS IN THE NIGHT"}</h2>
<h3 class="yellow">
{"YOU WILL REMEMBER WHO VISITED YOU TONIGHT"}
</h3>
</div>
</div>
}
}
#[derive(Debug, Clone, PartialEq, Properties)]
pub struct InsomniacResultProps {
pub visits: Visits,
}
#[function_component]
pub fn InsomniacResult(InsomniacResultProps { visits }: &InsomniacResultProps) -> Html {
let visitors = visits
.iter()
.map(|visitor| {
html! {
<CharacterTargetCard ident={visitor.clone()}/>
}
})
.collect::<Html>();
html! {
<div class="role-page">
<h1 class="intel">{"INSOMNIAC"}</h1>
<div class="information intel faint">
<h2>{"YOU WERE VISITED IN THE NIGHT BY:"}</h2>
<div class="info-player-list">
{visitors}
</div>
</div>
</div>
}
}

View File

@ -0,0 +1,41 @@
use yew::prelude::*;
use crate::components::{Icon, IconSource, IconType};
#[derive(Debug, Clone, Copy, PartialEq, Properties)]
pub struct MapleWolfPage1Props {
pub starving: bool,
}
#[function_component]
pub fn MapleWolfPage1(MapleWolfPage1Props { starving }: &MapleWolfPage1Props) -> Html {
let starving = starving
.then_some(html! {
<>
<h3 class="red">{"YOU ARE STARVING"}</h3>
<h3>{"IF YOU FAIL TO EAT TONIGHT, YOU WILL DIE"}</h3>
</>
})
.unwrap_or_else(|| {
html! {
<h3>
{"IF YOU DON'T EAT FOR TOO LONG, YOU WILL "}
<span class="red">{"STARVE"}</span>
</h3>
}
});
html! {
<div class="role-page">
<h1 class="offensive">{"MAPLE WOLF"}</h1>
<div class="information offensive faint">
<h2>
{"YOU CAN CHOOSE TO EAT A PLAYER TONIGHT"}
</h2>
<div class="icons">
<Icon source={IconSource::MapleWolf} icon_type={IconType::Informational}/>
</div>
{starving}
</div>
</div>
}
}

View File

@ -0,0 +1,81 @@
use core::num::NonZeroU8;
use werewolves_proto::message::CharacterIdentity;
use yew::prelude::*;
use crate::components::CharacterTargetCard;
#[derive(Debug, Clone, Copy, PartialEq, Properties)]
pub struct MasonRecruitPage1Props {
pub recruits_left: NonZeroU8,
}
#[function_component]
pub fn MasonRecruitPage1(
MasonRecruitPage1Props { recruits_left }: &MasonRecruitPage1Props,
) -> Html {
let recruitments = match recruits_left.get() {
0 => unreachable!(),
1 => html! {
<>
<span class="yellow">{1}</span>
{" RECRUITMENT"}
</>
},
num => html! {
<>
<span class="yellow">{num}</span>
{" RECRUITMENTS"}
</>
},
};
html! {
<div class="role-page">
<h1 class="intel">{"MASON LEADER"}</h1>
<div class="information intel faint">
<h2>{"YOU HAVE "}{recruitments}{" LEFT"}</h2>
<h4>
{"ANYONE YOU RECRUIT INTO THE MASONS WILL WAKE WITH YOU "}
<span class="yellow">{"EVERY NIGHT"}</span>
{", AS LONG AS THEY ARE ALIVE AND REMAIN VILLAGE ALIGNED"}
</h4>
<h3 class="yellow">{"WOULD YOU LIKE TO RECRUIT TONIGHT?"}</h3>
</div>
</div>
}
}
#[derive(Debug, Clone, PartialEq, Properties)]
pub struct MasonsWakeProps {
pub leader: CharacterIdentity,
pub masons: Box<[CharacterIdentity]>,
}
#[function_component]
pub fn MasonsWake(MasonsWakeProps { leader, masons }: &MasonsWakeProps) -> Html {
let title = html! {
<>
{"MASONS OF "}
<span class="yellow">{leader.name.clone()}</span>
</>
};
let masons = masons
.iter()
.map(|mason| {
html! {
<CharacterTargetCard ident={mason.clone()}/>
}
})
.collect::<Html>();
html! {
<div class="role-page">
<h1 class="intel">{title}</h1>
<div class="information intel faint">
<h2>{"YOU ARE ALL MEMBERS "}</h2>
<div class="info-player-list masons">
{masons}
</div>
</div>
</div>
}
}

View File

@ -0,0 +1,26 @@
use yew::prelude::*;
use crate::components::{Icon, IconSource, IconType};
#[function_component]
pub fn MilitiaPage1() -> Html {
html! {
<div class="role-page">
<h1 class="offensive">{"MILITIA"}</h1>
<div class="information offensive faint">
<h2>
{"IF YOU WISH TO USE YOUR "}
<span class="yellow">{"ONCE PER GAME"}</span>
{" KILL ABILITY"}
</h2>
<div class="icons">
<Icon source={IconSource::Sword} icon_type={IconType::Informational}/>
</div>
<h3 class="yellow">
{"POINT AT YOUR TARGET "}
{"OR GO BACK TO SLEEP"}
</h3>
</div>
</div>
}
}

View File

@ -0,0 +1,69 @@
use werewolves_proto::diedto::DiedToTitle;
use yew::prelude::*;
use crate::components::{Icon, IconSource, IconType, PartialAssociatedIcon};
#[function_component]
pub fn MorticianPage1() -> Html {
html! {
<div class="role-page">
<h1 class="intel">{"MORTICIAN"}</h1>
<div class="information intel faint">
<h2>
{"PICK A "}
<span class="yellow">{"DEAD"}</span>
{" PLAYER"}
</h2>
<div class="icons">
<Icon source={IconSource::Mortician} icon_type={IconType::Informational}/>
</div>
<h3 class="yellow">
{"YOU WILL LEARN THE CAUSE "}
{"OF THEIR DEATH"}
</h3>
</div>
</div>
}
}
#[derive(Debug, Clone, Copy, PartialEq, Properties)]
pub struct MorticianResultPageProps {
pub died_to: DiedToTitle,
}
#[function_component]
pub fn MorticianResultPage(
MorticianResultPageProps { died_to }: &MorticianResultPageProps,
) -> Html {
let text = match died_to {
DiedToTitle::Execution => "Execution",
DiedToTitle::MapleWolf => "Maple Wolf",
DiedToTitle::MapleWolfStarved => "Starvation",
DiedToTitle::Militia => "Militia Shot",
DiedToTitle::Wolfpack => "Wolfpack",
DiedToTitle::AlphaWolf => "Alpha Wolf",
DiedToTitle::Shapeshift => "Shapeshifting",
DiedToTitle::Hunter => "Hunter Trap",
DiedToTitle::GuardianProtecting => "Guardian",
DiedToTitle::PyreMaster => "Pyre Master",
DiedToTitle::PyreMasterLynchMob => "An Angry Mob of Villagers Against Fire",
DiedToTitle::MasonLeaderRecruitFail => "Occupational Hazard (Mason Recruit Fail)",
DiedToTitle::LoneWolf => "Lone Wolf",
};
let icon = died_to.icon().unwrap_or(IconSource::Mortician);
html! {
<div class="role-page">
<h1 class="intel">{"MORTICIAN"}</h1>
<div class="information intel faint">
<h2>{"YOUR TARGET DIED TO"}</h2>
<h4>
<Icon
source={icon}
icon_type={IconType::Informational}
/>
</h4>
<h3 class="yellow">{text}</h3>
</div>
</div>
}
}

View File

@ -0,0 +1,52 @@
use core::ops::Not;
use werewolves_proto::role::Powerful;
use yew::prelude::*;
use crate::components::{AssociatedIcon, Icon, IconSource, IconType};
#[function_component]
pub fn PowerSeerPage1() -> Html {
html! {
<div class="role-page">
<h1 class="intel">{"POWER SEER"}</h1>
<div class="information intel faint">
<h2>{"PICK A PLAYER"}</h2>
<h4 class="icons">
<Icon source={IconSource::Powerful} icon_type={IconType::Informational}/>
<Icon source={IconSource::Powerful} icon_type={IconType::Informational} inactive={true}/>
</h4>
<h3 class="yellow">{"YOU WILL CHECK IF THEY ARE POWERFUL"}</h3>
</div>
</div>
}
}
#[derive(Debug, Clone, Copy, PartialEq, Properties)]
pub struct PowerSeerResultProps {
pub powerful: Powerful,
}
#[function_component]
pub fn PowerSeerResult(PowerSeerResultProps { powerful }: &PowerSeerResultProps) -> Html {
let text = match powerful {
Powerful::Powerful => "POWERFUL",
Powerful::NotPowerful => "NOT POWERFUL",
};
html! {
<div class="role-page">
<h1 class="intel">{"POWER SEER"}</h1>
<div class="information intel faint">
<h2>{"YOUR TARGET APPEARS AS"}</h2>
<h4>
<Icon
source={powerful.icon()}
icon_type={IconType::Informational}
inactive={powerful.powerful().not()}
/>
</h4>
<h3 class="yellow">{text}</h3>
</div>
</div>
}
}

View File

@ -0,0 +1,19 @@
use yew::prelude::*;
use crate::components::{Icon, IconSource, IconType};
#[function_component]
pub fn ProtectorPage1() -> Html {
html! {
<div class="role-page">
<h1 class="defensive">{"PROTECTOR"}</h1>
<div class="information defensive faint">
<h2>{"PICK A PLAYER"}</h2>
<h4 class="icons">
<Icon source={IconSource::Shield} icon_type={IconType::Informational}/>
</h4>
<h3 class="yellow">{"YOU WILL PROTECT THEM FROM A DEATH TONIGHT"}</h3>
</div>
</div>
}
}

View File

@ -0,0 +1,22 @@
use yew::prelude::*;
use crate::components::{Icon, IconSource, IconType};
#[function_component]
pub fn PyremasterPage1() -> Html {
html! {
<div class="role-page">
<h1 class="offensive">{"PYREMASTER"}</h1>
<div class="information offensive faint">
<h2>{"IF YOU WISH TO THROW A PLAYER ON THE PYRE"}</h2>
<div class="icons">
<Icon source={IconSource::Pyremaster} icon_type={IconType::Informational}/>
</div>
<h3 class="yellow">
{"IF YOU KILL TWO GOOD VILLAGERS LIKE THIS "}
{"YOU WILL DIE AS WELL"}
</h3>
</div>
</div>
}
}

View File

@ -0,0 +1,49 @@
use werewolves_proto::role::Alignment;
use yew::prelude::*;
use crate::components::{AssociatedIcon, Icon, IconSource, IconType};
#[function_component]
pub fn SeerPage1() -> Html {
html! {
<div class="role-page">
<h1 class="intel">{"SEER"}</h1>
<div class="information intel faint">
<h2>{"PICK A PLAYER"}</h2>
<h4 class="icons">
<Icon source={IconSource::Village} icon_type={IconType::Informational}/>
<Icon source={IconSource::Wolves} icon_type={IconType::Informational}/>
</h4>
<h3 class="yellow">{"YOU WILL CHECK IF THEY APPEAR AS A VILLAGER OR PART OF THE WOLFPACK"}</h3>
</div>
</div>
}
}
#[derive(Debug, Clone, Copy, PartialEq, Properties)]
pub struct SeerResultProps {
pub alignment: Alignment,
}
#[function_component]
pub fn SeerResult(SeerResultProps { alignment }: &SeerResultProps) -> Html {
let text = match alignment {
Alignment::Village => "VILLAGE",
Alignment::Wolves => "WOLFPACK",
};
html! {
<div class="role-page">
<h1 class="intel">{"SEER"}</h1>
<div class="information intel faint">
<h2>{"YOUR TARGET APPEARS AS"}</h2>
<h4>
<Icon
source={alignment.icon()}
icon_type={IconType::Informational}
/>
</h4>
<h3 class="yellow">{text}</h3>
</div>
</div>
}
}

View File

@ -0,0 +1,20 @@
use yew::prelude::*;
use crate::components::{Icon, IconSource, IconType};
#[function_component]
pub fn VindicatorPage1() -> Html {
html! {
<div class="role-page">
<h1 class="defensive">{"VINDICATOR"}</h1>
<div class="information defensive faint">
<h3>{"A VILLAGER WAS EXECUTED"}</h3>
<h2>{"PICK A PLAYER"}</h2>
<h4 class="icons">
<Icon source={IconSource::Shield} icon_type={IconType::Informational}/>
</h4>
<h3 class="yellow">{"YOU WILL PROTECT THEM FROM A DEATH TONIGHT"}</h3>
</div>
</div>
}
}

View File

@ -0,0 +1,19 @@
use yew::prelude::*;
use crate::components::{Icon, IconSource, IconType};
#[function_component]
pub fn RoleblockPage() -> Html {
html! {
<div class="role-page">
<h1 class="wolves">{"ROLE BLOCKED"}</h1>
<div class="information wolves faint">
<h2>{"YOU WERE ROLE BLOCKED"}</h2>
<h4 class="icons">
<Icon source={IconSource::Roleblock} icon_type={IconType::Informational}/>
</h4>
<h3 class="yellow">{"YOUR NIGHT ACTION DID NOT TAKE PLACE"}</h3>
</div>
</div>
}
}

View File

@ -0,0 +1,22 @@
use core::ops::Not;
use werewolves_proto::role::Powerful;
use yew::prelude::*;
use crate::components::{AssociatedIcon, Icon, IconSource, IconType};
#[function_component]
pub fn WolfpackKillPage() -> Html {
html! {
<div class="role-page">
<h1 class="wolves">{"WOLF PACK KILL"}</h1>
<div class="information wolves faint">
<h2>{"CHOOSE A TARGET TO EAT TONIGHT"}</h2>
<h4 class="icons">
<Icon source={IconSource::Wolves} icon_type={IconType::Informational}/>
</h4>
<h3 class="yellow">{"WOLVES MUST BE UNANIMOUS"}</h3>
</div>
</div>
}
}