removed unprocessed changes from story

improved some error messages
better icons for !=, insomniac, hunter, apprentice
blocks now apply retroactively
This commit is contained in:
emilis 2025-11-13 22:48:11 +00:00
parent ac4ce81638
commit b2a118a132
No known key found for this signature in database
45 changed files with 1292 additions and 573 deletions

View File

@ -73,6 +73,8 @@ pub enum GameError {
NightNeedsNext, NightNeedsNext,
#[error("night zero actions can only be obtained on night zero")] #[error("night zero actions can only be obtained on night zero")]
NotNightZero, NotNightZero,
#[error("this action cannot happen on night zero")]
CannotHappenOnNightZero,
#[error("wolves intro in progress")] #[error("wolves intro in progress")]
WolvesIntroInProgress, WolvesIntroInProgress,
#[error("a game is still ongoing")] #[error("a game is still ongoing")]
@ -99,4 +101,8 @@ pub enum GameError {
MilitiaSpent, MilitiaSpent,
#[error("this role doesn't mark anyone")] #[error("this role doesn't mark anyone")]
RoleDoesntMark, RoleDoesntMark,
#[error("cannot shapeshift on a non-shapeshifter prompt")]
ShapeshiftingIsForShapeshifters,
#[error("must select a target")]
MustSelectTarget,
} }

View File

@ -19,7 +19,10 @@ use crate::{
character::CharacterId, character::CharacterId,
diedto::DiedTo, diedto::DiedTo,
error::GameError, error::GameError,
game::{Village, night::changes::ChangesLookup}, game::{
Village,
night::changes::{ChangesLookup, NightChange},
},
player::Protection, player::Protection,
}; };
@ -36,7 +39,11 @@ pub enum KillOutcome {
} }
impl KillOutcome { impl KillOutcome {
pub fn apply_to_village(self, village: &mut Village) -> Result<()> { pub fn apply_to_village(
self,
village: &mut Village,
recorded_changes: Option<&mut Vec<NightChange>>,
) -> Result<()> {
match self { match self {
KillOutcome::Single(character_id, died_to) => { KillOutcome::Single(character_id, died_to) => {
village village
@ -64,15 +71,22 @@ impl KillOutcome {
// check if guardian exists before we mutably borrow killer, which would // check if guardian exists before we mutably borrow killer, which would
// prevent us from borrowing village to check after. // prevent us from borrowing village to check after.
village.character_by_id(guardian)?; village.character_by_id(guardian)?;
let guardian_kill = DiedTo::GuardianProtecting {
night,
source: guardian,
protecting: original_target,
protecting_from: original_killer,
protecting_from_cause: Box::new(original_kill.clone()),
};
if let Some(recorded_changes) = recorded_changes {
recorded_changes.push(NightChange::Kill {
target: original_killer,
died_to: guardian_kill.clone(),
});
}
village village
.character_by_id_mut(original_killer)? .character_by_id_mut(original_killer)?
.kill(DiedTo::GuardianProtecting { .kill(guardian_kill);
night,
source: guardian,
protecting: original_target,
protecting_from: original_killer,
protecting_from_cause: Box::new(original_kill.clone()),
});
village.character_by_id_mut(guardian)?.kill(original_kill); village.character_by_id_mut(guardian)?.kill(original_kill);
Ok(()) Ok(())
} }

View File

@ -169,12 +169,13 @@ impl Game {
Ok(_) => self.process(HostGameMessage::GetState), Ok(_) => self.process(HostGameMessage::GetState),
Err(GameError::NightOver) => { Err(GameError::NightOver) => {
let changes = night.collect_changes()?; let changes = night.collect_changes()?;
let village = night.village().with_night_changes(&changes)?; let (village, recorded_changes) =
night.village().with_night_changes(&changes)?;
self.history.add( self.history.add(
night.village().time(), night.village().time(),
GameActions::NightDetails(NightDetails::new( GameActions::NightDetails(NightDetails::new(
&night.used_actions(), &night.used_actions(),
changes, recorded_changes,
)), )),
)?; )?;
self.state = GameState::Day { self.state = GameState::Day {

View File

@ -706,6 +706,11 @@ impl Night {
} }
pub fn received_response(&mut self, resp: ActionResponse) -> Result<ServerAction> { pub fn received_response(&mut self, resp: ActionResponse) -> Result<ServerAction> {
if let ActionResponse::ContinueToResult = &resp
&& let Some(result) = self.current_result()
{
return Ok(ServerAction::Result(result.clone()));
}
match self.received_response_with_role_blocks(resp)? { match self.received_response_with_role_blocks(resp)? {
BlockResolvedOutcome::PromptUpdate(prompt) => match &mut self.night_state { BlockResolvedOutcome::PromptUpdate(prompt) => match &mut self.night_state {
NightState::Active { NightState::Active {

View File

@ -14,6 +14,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
use core::ops::Not; use core::ops::Not;
use super::Result;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use werewolves_macros::Extract; use werewolves_macros::Extract;
@ -21,6 +22,7 @@ use crate::{
aura::Aura, aura::Aura,
character::CharacterId, character::CharacterId,
diedto::DiedTo, diedto::DiedTo,
game::{Village, kill},
player::Protection, player::Protection,
role::{RoleBlock, RoleTitle}, role::{RoleBlock, RoleTitle},
}; };
@ -71,6 +73,29 @@ pub enum NightChange {
}, },
} }
impl NightChange {
pub const fn target(&self) -> Option<CharacterId> {
match self {
NightChange::HunterTarget { target, .. }
| NightChange::Kill { target, .. }
| NightChange::RoleBlock { target, .. }
| NightChange::Shapeshift { into: target, .. }
| NightChange::Protection { target, .. }
| NightChange::MasonRecruit {
recruiting: target, ..
}
| NightChange::EmpathFoundScapegoat {
scapegoat: target, ..
}
| NightChange::ApplyAura { target, .. } => Some(*target),
NightChange::ElderReveal { .. }
| NightChange::RoleChange(..)
| NightChange::LostAura { .. } => None,
}
}
}
pub struct ChangesLookup<'a>(&'a [NightChange], Vec<usize>); pub struct ChangesLookup<'a>(&'a [NightChange], Vec<usize>);
impl<'a> ChangesLookup<'a> { impl<'a> ChangesLookup<'a> {
@ -78,6 +103,30 @@ impl<'a> ChangesLookup<'a> {
Self(changes, Vec::new()) Self(changes, Vec::new())
} }
pub fn collect_remaining(&self) -> Box<[NightChange]> {
self.0
.iter()
.enumerate()
.filter_map(|(idx, c)| self.1.contains(&idx).not().then_some(c))
.cloned()
.collect()
}
pub fn died_to(
&mut self,
character_id: CharacterId,
night: u8,
village: &Village,
) -> Result<Option<DiedTo>> {
if let Some(died_to) = self.killed(character_id)
&& kill::resolve_kill(self, character_id, died_to, night, village)?.is_some()
{
Ok(Some(died_to.clone()))
} else {
Ok(None)
}
}
pub fn killed(&self, target: CharacterId) -> Option<&'a DiedTo> { pub fn killed(&self, target: CharacterId) -> Option<&'a DiedTo> {
self.0.iter().enumerate().find_map(|(idx, c)| { self.0.iter().enumerate().find_map(|(idx, c)| {
self.1 self.1

View File

@ -16,16 +16,19 @@
use core::num::NonZeroU8; use core::num::NonZeroU8;
use crate::{ use crate::{
character::CharacterId,
diedto::DiedTo, diedto::DiedTo,
error::GameError, error::GameError,
game::night::{CurrentResult, Night, NightState, changes::NightChange}, game::night::{CurrentResult, Night, NightState, changes::NightChange},
message::night::{ActionPrompt, ActionResult}, message::night::{ActionPrompt, ActionResult},
role::RoleBlock,
}; };
use super::Result; use super::Result;
impl Night { impl Night {
#[allow(clippy::should_implement_trait)] #[allow(clippy::should_implement_trait)]
pub fn next(&mut self) -> Result<()> { pub fn next(&mut self) -> Result<()> {
self.retroactive_role_blocks()?;
self.next_state_process_maple_starving()?; self.next_state_process_maple_starving()?;
match &self.night_state { match &self.night_state {
@ -145,4 +148,44 @@ impl Night {
Ok(()) Ok(())
} }
fn retroactive_role_blocks(&mut self) -> Result<()> {
let blocks = match &self.night_state {
NightState::Active {
current_changes, ..
} => current_changes
.iter()
.filter_map(|c| match c {
NightChange::RoleBlock {
target, block_type, ..
} => Some((*target, *block_type)),
_ => None,
})
.collect::<Box<[_]>>(),
NightState::Complete => return Err(GameError::NightOver),
};
for (target, block_type) in blocks {
match block_type {
RoleBlock::Direwolf => self.apply_direwolf_block_retroactively(target),
}
}
Ok(())
}
fn apply_direwolf_block_retroactively(&mut self, target: CharacterId) {
self.used_actions
.iter_mut()
.filter_map(|(prompt, res, changes)| match prompt.marked() {
Some((marked, None)) => (marked == target).then_some((res, changes)),
Some((marked1, Some(marked2))) => {
(marked1 == target || marked2 == target).then_some((res, changes))
}
None => None,
})
.for_each(|(result, changes)| {
changes.clear();
*result = ActionResult::RoleBlocked;
});
}
} }

View File

@ -80,7 +80,7 @@ impl Night {
.ok_or(GameError::InvalidTarget)?, .ok_or(GameError::InvalidTarget)?,
}), }),
})), })),
_ => Err(GameError::InvalidMessageForGameState), _ => Err(GameError::ShapeshiftingIsForShapeshifters),
}; };
} }
ActionResponse::Continue => { ActionResponse::Continue => {
@ -107,6 +107,7 @@ impl Night {
})); }));
} }
} }
ActionResponse::ContinueToResult => return self.process(ActionResponse::Continue),
}; };
match current_prompt { match current_prompt {
@ -228,7 +229,7 @@ impl Night {
died_to: DiedTo::Militia { died_to: DiedTo::Militia {
killer: character_id.character_id, killer: character_id.character_id,
night: NonZeroU8::new(self.night) night: NonZeroU8::new(self.night)
.ok_or(GameError::InvalidMessageForGameState)?, .ok_or(GameError::CannotHappenOnNightZero)?,
}, },
}), }),
})), })),
@ -318,7 +319,7 @@ impl Night {
.ok_or(GameError::NoWolves)? .ok_or(GameError::NoWolves)?
.character_id(), .character_id(),
night: NonZeroU8::new(self.night) night: NonZeroU8::new(self.night)
.ok_or(GameError::InvalidMessageForGameState)?, .ok_or(GameError::CannotHappenOnNightZero)?,
}, },
}), }),
})), })),
@ -341,7 +342,7 @@ impl Night {
}) })
.ok_or(GameError::InvalidTarget)?, .ok_or(GameError::InvalidTarget)?,
}), }),
_ => return Err(GameError::InvalidMessageForGameState), _ => return Err(GameError::ShapeshiftingIsForShapeshifters),
}, },
})) }))
} }
@ -356,7 +357,7 @@ impl Night {
died_to: DiedTo::AlphaWolf { died_to: DiedTo::AlphaWolf {
killer: character_id.character_id, killer: character_id.character_id,
night: NonZeroU8::new(self.night) night: NonZeroU8::new(self.night)
.ok_or(GameError::InvalidMessageForGameState)?, .ok_or(GameError::CannotHappenOnNightZero)?,
}, },
}), }),
})), })),
@ -537,7 +538,7 @@ impl Night {
| ActionPrompt::Guardian { marked: None, .. } | ActionPrompt::Guardian { marked: None, .. }
| ActionPrompt::WolfPackKill { marked: None, .. } | ActionPrompt::WolfPackKill { marked: None, .. }
| ActionPrompt::DireWolf { marked: None, .. } | ActionPrompt::DireWolf { marked: None, .. }
| ActionPrompt::Seer { marked: None, .. } => Err(GameError::InvalidMessageForGameState), | ActionPrompt::Seer { marked: None, .. } => Err(GameError::MustSelectTarget),
} }
} }

View File

@ -185,7 +185,14 @@ impl SetupRoleTitle {
} }
AuraTitle::Insane => { AuraTitle::Insane => {
matches!(self.category(), Category::Intel) matches!(self.category(), Category::Intel)
&& !matches!(self, Self::MasonLeader | Self::Empath) && !matches!(
self,
Self::MasonLeader
| Self::Empath
| Self::Insomniac
| Self::Mortician
| Self::Gravedigger
)
} }
AuraTitle::Bloodlet => false, AuraTitle::Bloodlet => false,
} }

View File

@ -455,7 +455,7 @@ impl GameStory {
village = match actions { village = match actions {
GameActions::DayDetails(day_details) => village.with_day_changes(day_details)?, GameActions::DayDetails(day_details) => village.with_day_changes(day_details)?,
GameActions::NightDetails(night_details) => { GameActions::NightDetails(night_details) => {
village.with_night_changes(&night_details.changes)? village.with_night_changes(&night_details.changes)?.0
} }
}; };
} }
@ -468,7 +468,7 @@ impl GameStory {
village = match actions { village = match actions {
GameActions::DayDetails(day_details) => village.with_day_changes(day_details)?, GameActions::DayDetails(day_details) => village.with_day_changes(day_details)?,
GameActions::NightDetails(night_details) => { GameActions::NightDetails(night_details) => {
village.with_night_changes(&night_details.changes)? village.with_night_changes(&night_details.changes)?.0
} }
}; };
if time == at_time { if time == at_time {

View File

@ -12,14 +12,15 @@
// //
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
use core::num::NonZeroU8; use core::{num::NonZeroU8, ops::Not};
use crate::{ use crate::{
aura::{Aura, AuraTitle}, aura::{Aura, AuraTitle},
diedto::DiedTo, diedto::DiedTo,
error::GameError, error::GameError,
game::{ game::{
GameTime, Village, kill, GameTime, Village,
kill::{self, KillOutcome},
night::changes::{ChangesLookup, NightChange}, night::changes::{ChangesLookup, NightChange},
story::DayDetail, story::DayDetail,
}, },
@ -43,7 +44,10 @@ impl Village {
Ok(new_village) Ok(new_village)
} }
pub fn with_night_changes(&self, all_changes: &[NightChange]) -> Result<Self> { pub fn with_night_changes(
&self,
all_changes: &[NightChange],
) -> Result<(Self, Box<[NightChange]>)> {
let night = match self.time { let night = match self.time {
GameTime::Day { .. } => return Err(GameError::NotNight), GameTime::Day { .. } => return Err(GameError::NotNight),
GameTime::Night { number } => number, GameTime::Night { number } => number,
@ -52,6 +56,9 @@ impl Village {
let mut new_village = self.clone(); let mut new_village = self.clone();
// recorded changes: changes sans failed kills, actions failed due to blocks, etc
let mut recorded_changes = all_changes.to_vec();
// dispose of the current drunk token for every drunk in the village // dispose of the current drunk token for every drunk in the village
new_village new_village
.characters_mut() .characters_mut()
@ -82,29 +89,48 @@ impl Village {
NightChange::HunterTarget { source, target } => { NightChange::HunterTarget { source, target } => {
let hunter_character = new_village.character_by_id_mut(*source).unwrap(); let hunter_character = new_village.character_by_id_mut(*source).unwrap();
hunter_character.hunter_mut()?.replace(*target); hunter_character.hunter_mut()?.replace(*target);
if changes.killed(*source).is_some() if changes
&& changes.protected(source).is_none() .died_to(hunter_character.character_id(), night, self)?
&& changes.protected(target).is_none() .is_some()
{ && let Some(kill) = kill::resolve_kill(
new_village &mut changes,
.character_by_id_mut(*target) *target,
.unwrap() &DiedTo::Hunter {
.kill(DiedTo::Hunter {
killer: *source, killer: *source,
night: NonZeroU8::new(night).unwrap(), night: NonZeroU8::new(night)
}) .ok_or(GameError::CannotHappenOnNightZero)?,
},
night,
&new_village,
)?
{
kill.apply_to_village(&mut new_village, Some(&mut recorded_changes))?;
} }
} }
NightChange::Kill { target, died_to } => { NightChange::Kill { target, died_to } => {
if let Some(kill) = if let Some(kill) =
kill::resolve_kill(&mut changes, *target, died_to, night, self)? kill::resolve_kill(&mut changes, *target, died_to, night, self)?
{ {
kill.apply_to_village(&mut new_village)?; if let KillOutcome::Guarding {
guardian,
original_kill,
..
} = &kill
{
recorded_changes.retain(|c| c != change);
recorded_changes.push(NightChange::Kill {
target: *guardian,
died_to: original_kill.clone(),
});
}
kill.apply_to_village(&mut new_village, Some(&mut recorded_changes))?;
if let DiedTo::MapleWolf { source, .. } = died_to if let DiedTo::MapleWolf { source, .. } = died_to
&& let Ok(maple) = new_village.character_by_id_mut(*source) && let Ok(maple) = new_village.character_by_id_mut(*source)
{ {
*maple.maple_wolf_mut()? = night; *maple.maple_wolf_mut()? = night;
} }
} else {
recorded_changes.retain(|c| c != change);
} }
} }
NightChange::Shapeshift { source, into } => { NightChange::Shapeshift { source, into } => {
@ -122,6 +148,8 @@ impl Village {
night: NonZeroU8::new(night).unwrap(), night: NonZeroU8::new(night).unwrap(),
}); });
// role change pushed in [apply_shapeshift] // role change pushed in [apply_shapeshift]
} else {
recorded_changes.retain(|c| c != change);
} }
} }
@ -149,6 +177,11 @@ impl Village {
.character_by_id_mut(*source)? .character_by_id_mut(*source)?
.direwolf_mut()? .direwolf_mut()?
.replace(*target); .replace(*target);
recorded_changes.retain(|c| {
matches!(c, NightChange::RoleBlock { .. })
|| c.target().map(|t| t == *target).unwrap_or_default().not()
});
} }
NightChange::MasonRecruit { NightChange::MasonRecruit {
@ -162,6 +195,7 @@ impl Village {
tried_recruiting: *recruiting, tried_recruiting: *recruiting,
}, },
); );
recorded_changes.retain(|c| c != change);
} else { } else {
new_village new_village
.character_by_id_mut(*mason_leader)? .character_by_id_mut(*mason_leader)?
@ -253,6 +287,6 @@ impl Village {
if new_village.is_game_over().is_none() { if new_village.is_game_over().is_none() {
new_village.to_day()?; new_village.to_day()?;
} }
Ok(new_village) Ok((new_village, recorded_changes.into_boxed_slice()))
} }
} }

View File

@ -0,0 +1,123 @@
// Copyright (C) 2025 Emilis Bliūdžius
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::{
game::{Game, GameSettings, OrRandom, SetupRole},
game_test::{
ActionPromptTitleExt, ActionResultExt, GameExt, SettingsExt, gen_players, init_log,
},
};
#[allow(unused)]
use pretty_assertions::{assert_eq, assert_ne, assert_str_eq};
#[test]
fn block_on_wolf_kill_target_prevents_kill() {
init_log();
let players = gen_players(1..21);
let mut player_ids = players.iter().map(|p| p.player_id);
let scapegoat = player_ids.next().unwrap();
let direwolf = player_ids.next().unwrap();
let wolf = player_ids.next().unwrap();
let mut settings = GameSettings::empty();
settings.add_and_assign(
SetupRole::Scapegoat {
redeemed: OrRandom::Determined(false),
},
scapegoat,
);
settings.add_and_assign(SetupRole::DireWolf, direwolf);
settings.add_and_assign(SetupRole::Werewolf, wolf);
settings.fill_remaining_slots_with_villagers(20);
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_villager();
game.r#continue().sleep();
game.next_expect_day();
game.execute().title().wolf_pack_kill();
let scapegoat_char_id = game.character_by_player_id(scapegoat).character_id();
game.mark(scapegoat_char_id);
game.r#continue().r#continue();
game.next().title().direwolf();
game.mark(scapegoat_char_id);
game.r#continue().sleep();
game.next_expect_day();
assert_eq!(
game.character_by_player_id(scapegoat).died_to().cloned(),
None
);
}
#[test]
fn block_on_guardian_target_prevents_the_visit() {
init_log();
let players = gen_players(1..21);
let mut player_ids = players.iter().map(|p| p.player_id);
let scapegoat = player_ids.next().unwrap();
let guardian = player_ids.next().unwrap();
let direwolf = player_ids.next().unwrap();
let wolf = player_ids.next().unwrap();
let mut settings = GameSettings::empty();
settings.add_and_assign(
SetupRole::Scapegoat {
redeemed: OrRandom::Determined(false),
},
scapegoat,
);
settings.add_and_assign(SetupRole::Guardian, guardian);
settings.add_and_assign(SetupRole::DireWolf, direwolf);
settings.add_and_assign(SetupRole::Werewolf, wolf);
settings.fill_remaining_slots_with_villagers(20);
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_villager();
game.r#continue().sleep();
game.next_expect_day();
game.execute().title().guardian();
let scapegoat_char_id = game.character_by_player_id(scapegoat).character_id();
game.mark(scapegoat_char_id);
game.r#continue().sleep();
game.next().title().wolf_pack_kill();
game.mark_villager();
game.r#continue().r#continue();
game.next().title().direwolf();
game.mark(scapegoat_char_id);
game.r#continue().sleep();
game.next_expect_day();
assert_eq!(
game.character_by_player_id(guardian)
.guardian()
.unwrap()
.clone(),
None
);
}

View File

@ -14,6 +14,9 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
use core::num::NonZeroU8; use core::num::NonZeroU8;
#[allow(unused)]
use pretty_assertions::{assert_eq, assert_ne, assert_str_eq};
use crate::{ use crate::{
diedto::DiedTo, diedto::DiedTo,
error::GameError, error::GameError,
@ -25,7 +28,7 @@ use crate::{
host::{HostGameMessage, HostNightMessage}, host::{HostGameMessage, HostNightMessage},
night::{ActionPromptTitle, ActionResponse}, night::{ActionPromptTitle, ActionResponse},
}, },
role::{PreviousGuardianAction, Role}, role::{PreviousGuardianAction, Role, RoleTitle},
}; };
#[test] #[test]
@ -215,3 +218,54 @@ fn cannot_visit_previous_nights_guard_target() {
Err(GameError::InvalidTarget) Err(GameError::InvalidTarget)
); );
} }
#[test]
fn protects_from_militia() {
init_log();
let players = gen_players(1..21);
let mut player_ids = players.iter().map(|p| p.player_id);
let guardian = player_ids.next().unwrap();
let militia = player_ids.next().unwrap();
let wolf = player_ids.next().unwrap();
let mut settings = GameSettings::empty();
settings.add_and_assign(SetupRole::Militia, militia);
settings.add_and_assign(SetupRole::Guardian, guardian);
settings.add_and_assign(SetupRole::Werewolf, wolf);
settings.fill_remaining_slots_with_villagers(20);
let mut game = Game::new(&players, settings).unwrap();
game.r#continue().r#continue();
game.next().title().wolves_intro();
game.r#continue().sleep();
game.next_expect_day();
game.execute().title().guardian();
let mut villagers = game
.village()
.characters()
.into_iter()
.filter(|c| c.alive() && matches!(c.role().title(), RoleTitle::Villager));
let protected = villagers.next().unwrap();
game.mark(protected.character_id());
game.r#continue().sleep();
game.next().title().wolf_pack_kill();
game.mark(villagers.next().unwrap().character_id());
game.r#continue().sleep();
game.next().title().militia();
game.mark(protected.character_id());
game.r#continue().sleep();
game.next_expect_day();
assert_eq!(
game.character_by_player_id(protected.player_id())
.died_to()
.cloned(),
None
);
assert_eq!(
game.character_by_player_id(militia).role().clone(),
Role::Militia { targeted: None }
);
}

View File

@ -12,13 +12,13 @@
// //
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
use core::num::NonZeroU8; use core::num::{NonZero, 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::{
diedto::DiedTo, diedto::DiedTo,
game::{Game, GameSettings, SetupRole}, game::{Game, GameSettings, OrRandom, SetupRole},
game_test::{ActionPromptTitleExt, ActionResultExt, GameExt, SettingsExt, gen_players}, game_test::{ActionPromptTitleExt, ActionResultExt, GameExt, SettingsExt, gen_players},
message::night::{ActionPrompt, ActionPromptTitle}, message::night::{ActionPrompt, ActionPromptTitle},
}; };
@ -243,3 +243,63 @@ fn masons_wake_even_if_leader_died() {
} }
); );
} }
#[test]
fn masons_get_go_back_to_sleep() {
let players = gen_players(1..21);
let mut player_ids = players.iter().map(|p| p.player_id);
let mason = player_ids.next().unwrap();
let scapegoat = player_ids.next().unwrap();
let beholder = player_ids.next().unwrap();
let wolf = player_ids.next().unwrap();
let mut settings = GameSettings::empty();
settings.add_and_assign(
SetupRole::MasonLeader {
recruits_available: NonZeroU8::new(1).unwrap(),
},
mason,
);
settings.add_and_assign(
SetupRole::Scapegoat {
redeemed: OrRandom::Determined(false),
},
scapegoat,
);
settings.add_and_assign(SetupRole::Beholder, beholder);
settings.add_and_assign(SetupRole::Werewolf, wolf);
settings.fill_remaining_slots_with_villagers(20);
let mut game = Game::new(&players, settings).unwrap();
game.r#continue().r#continue();
game.next().title().wolves_intro();
game.r#continue().sleep();
game.next_expect_day();
assert_eq!(game.execute().title(), ActionPromptTitle::WolfPackKill);
game.mark_villager();
game.r#continue().sleep();
game.next().title().masons_leader_recruit();
game.mark(game.character_by_player_id(scapegoat).character_id());
game.r#continue().r#continue();
game.next().title().masons_wake();
game.r#continue().sleep();
game.next().title().beholder();
game.mark_villager();
game.r#continue().sleep();
game.next_expect_day();
game.execute().title().wolf_pack_kill();
game.mark_villager();
game.r#continue().sleep();
game.next().title().masons_wake();
game.r#continue().sleep();
game.next().title().beholder();
game.mark_villager();
game.r#continue().sleep();
game.next_expect_day();
}

View File

@ -16,6 +16,7 @@ mod apprentice;
mod beholder; mod beholder;
mod black_knight; mod black_knight;
mod bloodletter; mod bloodletter;
mod direwolf;
mod diseased; mod diseased;
mod elder; mod elder;
mod empath; mod empath;

View File

@ -15,7 +15,7 @@
use core::{num::NonZeroU8, ops::Deref}; use core::{num::NonZeroU8, ops::Deref};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use werewolves_macros::{ChecksAs, Titles}; use werewolves_macros::{ChecksAs, Extract, Titles};
use crate::{ use crate::{
character::CharacterId, character::CharacterId,
@ -56,7 +56,7 @@ pub enum ActionType {
Beholder, Beholder,
} }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, ChecksAs, Titles)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, ChecksAs, Titles, Extract)]
pub enum ActionPrompt { pub enum ActionPrompt {
#[checks(ActionType::Cover)] #[checks(ActionType::Cover)]
CoverOfDarkness, CoverOfDarkness,
@ -215,6 +215,58 @@ pub enum ActionPrompt {
} }
impl ActionPrompt { impl ActionPrompt {
pub(crate) const fn marked(&self) -> Option<(CharacterId, Option<CharacterId>)> {
match self {
ActionPrompt::Seer { marked, .. }
| ActionPrompt::Protector { marked, .. }
| ActionPrompt::Gravedigger { marked, .. }
| ActionPrompt::Hunter { marked, .. }
| ActionPrompt::Militia { marked, .. }
| ActionPrompt::MapleWolf { marked, .. }
| ActionPrompt::Guardian { marked, .. }
| ActionPrompt::Adjudicator { marked, .. }
| ActionPrompt::PowerSeer { marked, .. }
| ActionPrompt::Mortician { marked, .. }
| ActionPrompt::Beholder { marked, .. }
| ActionPrompt::MasonLeaderRecruit { marked, .. }
| ActionPrompt::Empath { marked, .. }
| ActionPrompt::Vindicator { marked, .. }
| ActionPrompt::PyreMaster { marked, .. }
| ActionPrompt::WolfPackKill { marked, .. }
| ActionPrompt::AlphaWolf { marked, .. }
| ActionPrompt::DireWolf { marked, .. }
| ActionPrompt::LoneWolfKill { marked, .. }
| ActionPrompt::Bloodletter { marked, .. } => match *marked {
Some(marked) => Some((marked, None)),
None => None,
},
ActionPrompt::Arcanist {
marked: (None, Some(marked)),
..
}
| ActionPrompt::Arcanist {
marked: (Some(marked), None),
..
} => Some((*marked, None)),
ActionPrompt::Arcanist {
marked: (Some(marked1), Some(marked2)),
..
} => Some((*marked1, Some(*marked2))),
ActionPrompt::Arcanist {
marked: (None, None),
..
}
| ActionPrompt::CoverOfDarkness
| ActionPrompt::WolvesIntro { .. }
| ActionPrompt::RoleChange { .. }
| ActionPrompt::ElderReveal { .. }
| ActionPrompt::MasonsWake { .. }
| ActionPrompt::Shapeshifter { .. }
| ActionPrompt::Insomniac { .. }
| ActionPrompt::TraitorIntro { .. } => None,
}
}
pub(crate) const fn character_id(&self) -> Option<CharacterId> { pub(crate) const fn character_id(&self) -> Option<CharacterId> {
match self { match self {
ActionPrompt::TraitorIntro { character_id } ActionPrompt::TraitorIntro { character_id }
@ -283,6 +335,17 @@ impl ActionPrompt {
| ActionPrompt::LoneWolfKill { .. } => false, | ActionPrompt::LoneWolfKill { .. } => false,
} }
} }
pub fn interactive(&self) -> bool {
match self {
Self::Shapeshifter { .. } => true,
_ => !matches!(
self.with_mark(CharacterId::new()),
Err(GameError::RoleDoesntMark)
),
}
}
pub(crate) fn with_mark(&self, mark: CharacterId) -> Result<ActionPrompt> { pub(crate) fn with_mark(&self, mark: CharacterId) -> Result<ActionPrompt> {
let mut prompt = self.clone(); let mut prompt = self.clone();
match &mut prompt { match &mut prompt {
@ -490,6 +553,7 @@ pub enum ActionResponse {
MarkTarget(CharacterId), MarkTarget(CharacterId),
Shapeshift, Shapeshift,
Continue, Continue,
ContinueToResult,
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]

View File

@ -133,31 +133,37 @@ pub enum Role {
#[checks(Powerful::Powerful)] #[checks(Powerful::Powerful)]
#[checks(Killer::NotKiller)] #[checks(Killer::NotKiller)]
#[checks("is_mentor")] #[checks("is_mentor")]
#[checks("doesnt_wake_if_died_tonight")]
Seer, Seer,
#[checks(Alignment::Village)] #[checks(Alignment::Village)]
#[checks(Powerful::Powerful)] #[checks(Powerful::Powerful)]
#[checks(Killer::NotKiller)] #[checks(Killer::NotKiller)]
#[checks("is_mentor")] #[checks("is_mentor")]
#[checks("doesnt_wake_if_died_tonight")]
Arcanist, Arcanist,
#[checks(Alignment::Village)] #[checks(Alignment::Village)]
#[checks(Powerful::Powerful)] #[checks(Powerful::Powerful)]
#[checks(Killer::NotKiller)] #[checks(Killer::NotKiller)]
#[checks("is_mentor")] #[checks("is_mentor")]
#[checks("doesnt_wake_if_died_tonight")]
Adjudicator, Adjudicator,
#[checks(Alignment::Village)] #[checks(Alignment::Village)]
#[checks(Powerful::Powerful)] #[checks(Powerful::Powerful)]
#[checks(Killer::NotKiller)] #[checks(Killer::NotKiller)]
#[checks("is_mentor")] #[checks("is_mentor")]
#[checks("doesnt_wake_if_died_tonight")]
PowerSeer, PowerSeer,
#[checks(Alignment::Village)] #[checks(Alignment::Village)]
#[checks(Powerful::Powerful)] #[checks(Powerful::Powerful)]
#[checks(Killer::NotKiller)] #[checks(Killer::NotKiller)]
#[checks("is_mentor")] #[checks("is_mentor")]
#[checks("doesnt_wake_if_died_tonight")]
Mortician, Mortician,
#[checks(Alignment::Village)] #[checks(Alignment::Village)]
#[checks(Powerful::Powerful)] #[checks(Powerful::Powerful)]
#[checks(Killer::NotKiller)] #[checks(Killer::NotKiller)]
#[checks("is_mentor")] #[checks("is_mentor")]
#[checks("doesnt_wake_if_died_tonight")]
Beholder, Beholder,
#[checks(Alignment::Village)] #[checks(Alignment::Village)]
#[checks(Powerful::Powerful)] #[checks(Powerful::Powerful)]
@ -199,6 +205,7 @@ pub enum Role {
#[checks(Powerful::Powerful)] #[checks(Powerful::Powerful)]
#[checks(Killer::NotKiller)] #[checks(Killer::NotKiller)]
#[checks("is_mentor")] #[checks("is_mentor")]
#[checks("doesnt_wake_if_died_tonight")]
Gravedigger, Gravedigger,
#[checks(Alignment::Village)] #[checks(Alignment::Village)]
#[checks(Killer::Killer)] #[checks(Killer::Killer)]
@ -243,6 +250,7 @@ pub enum Role {
#[checks(Alignment::Village)] #[checks(Alignment::Village)]
#[checks(Powerful::Powerful)] #[checks(Powerful::Powerful)]
#[checks(Killer::NotKiller)] #[checks(Killer::NotKiller)]
#[checks("doesnt_wake_if_died_tonight")]
Insomniac, Insomniac,
#[checks(Alignment::Wolves)] #[checks(Alignment::Wolves)]
@ -487,7 +495,7 @@ pub enum ArcanistCheck {
pub const MAPLE_WOLF_ABSTAIN_LIMIT: NonZeroU8 = NonZeroU8::new(3).unwrap(); pub const MAPLE_WOLF_ABSTAIN_LIMIT: NonZeroU8 = NonZeroU8::new(3).unwrap();
pub const PYREMASTER_VILLAGER_KILLS_TO_DIE: NonZeroU8 = NonZeroU8::new(2).unwrap(); pub const PYREMASTER_VILLAGER_KILLS_TO_DIE: NonZeroU8 = NonZeroU8::new(2).unwrap();
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub enum RoleBlock { pub enum RoleBlock {
Direwolf, Direwolf,
} }

View File

@ -296,7 +296,7 @@ impl GameRunner {
HostMessage::GetState => self.game.process(HostGameMessage::GetState), HostMessage::GetState => self.game.process(HostGameMessage::GetState),
HostMessage::InGame(msg) => self.game.process(msg), HostMessage::InGame(msg) => self.game.process(msg),
HostMessage::Lobby(_) | HostMessage::PostGame(_) | HostMessage::ForceRoleAckFor(_) => { HostMessage::Lobby(_) | HostMessage::PostGame(_) | HostMessage::ForceRoleAckFor(_) => {
Err(GameError::InvalidMessageForGameState) Err(GameError::GameOngoing)
} }
HostMessage::Echo(echo) => Ok(echo), HostMessage::Echo(echo) => Ok(echo),
} }

View File

@ -2,9 +2,9 @@
<!-- Created with Inkscape (http://www.inkscape.org/) --> <!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg <svg
width="45.363396mm" width="58.49649mm"
height="45.36343mm" height="55.059494mm"
viewBox="0 0 45.363396 45.36343" viewBox="0 0 58.49649 55.059494"
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)"
@ -24,9 +24,9 @@
inkscape:deskcolor="#d1d1d1" inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm" inkscape:document-units="mm"
showgrid="false" showgrid="false"
inkscape:zoom="1" inkscape:zoom="2.8284271"
inkscape:cx="1108.5" inkscape:cx="470.75634"
inkscape:cy="797.49998" inkscape:cy="2967.1969"
inkscape:window-width="1918" inkscape:window-width="1918"
inkscape:window-height="1042" inkscape:window-height="1042"
inkscape:window-x="0" inkscape:window-x="0"
@ -35,8 +35,8 @@
inkscape:current-layer="layer4"><inkscape:grid inkscape:current-layer="layer4"><inkscape:grid
id="grid1" id="grid1"
units="mm" units="mm"
originx="-266.17087" originx="-29.360038"
originy="-217.22292" originy="-825.92692"
spacingx="0.26458333" spacingx="0.26458333"
spacingy="0.26458334" spacingy="0.26458334"
empcolor="#0099e5" empcolor="#0099e5"
@ -48,46 +48,232 @@
visible="false" /><inkscape:page visible="false" /><inkscape:page
x="0" x="0"
y="0" y="0"
width="45.363396" width="58.49649"
height="45.36343" height="55.059494"
id="page2" id="page2"
margin="0" margin="0"
bleed="0" /></sodipodi:namedview><defs bleed="0" /></sodipodi:namedview><defs
id="defs1" /><g id="defs1"><inkscape:path-effect
effect="interpolate_points"
id="path-effect41-5"
is_visible="true"
lpeversion="1"
interpolator_type="CubicBezierJohan" /><inkscape:path-effect
effect="interpolate_points"
id="path-effect41-8"
is_visible="true"
lpeversion="1"
interpolator_type="CubicBezierJohan" /><inkscape:path-effect
effect="interpolate_points"
id="path-effect41-5-67"
is_visible="true"
lpeversion="1"
interpolator_type="CubicBezierJohan" /><inkscape:path-effect
effect="interpolate_points"
id="path-effect41-8-3"
is_visible="true"
lpeversion="1"
interpolator_type="CubicBezierJohan" /></defs><g
inkscape:groupmode="layer" inkscape:groupmode="layer"
id="layer4" id="layer4"
inkscape:label="Layer 4" inkscape:label="Layer 4"
transform="translate(-266.17087,-217.22291)"><g transform="translate(-29.360037,-825.92694)"><g
id="g61" id="g43"
transform="translate(-56.091665,-3.7041666)"><path transform="translate(0.07389574)"><g
d="m 347.07926,221.66934 c -0.45815,-0.0281 -0.90857,0.004 -1.35031,0.0992 -1.05487,0.22775 -2.05439,0.76275 -2.99671,1.56425 -1.13002,-0.2664 -2.18934,-0.42422 -3.16415,-0.46147 -0.97482,-0.0373 -1.86513,0.0461 -2.65772,0.26096 -0.38599,0.10465 -0.74872,0.24076 -1.08675,0.40928 -0.41079,0.20479 -0.78496,0.45722 -1.11983,0.76068 -0.79968,0.72467 -1.398,1.68777 -1.81333,2.85306 -2.22365,0.66859 -3.98388,1.57251 -5.1418,2.7373 -0.28196,0.28362 -0.52842,0.58265 -0.73691,0.89762 -0.25336,0.38274 -0.45083,0.7888 -0.58911,1.21904 -0.33021,1.02743 -0.36713,2.16074 -0.14418,3.37757 -1.59144,1.69085 -2.66416,3.35361 -3.08456,4.9413 -0.10237,0.38661 -0.16607,0.76866 -0.18914,1.14567 -0.028,0.45815 0.004,0.90857 0.0992,1.35031 0.22775,1.05487 0.76275,2.05439 1.56424,2.99671 -0.5328,2.26004 -0.63027,4.23669 -0.2005,5.82187 0.10465,0.38599 0.24024,0.74872 0.40876,1.08675 0.20479,0.41079 0.45773,0.78496 0.76119,1.11983 0.72468,0.79968 1.68778,1.398 2.85306,1.81333 0.6686,2.22365 1.57252,3.9844 2.7373,5.14232 0.28363,0.28196 0.58266,0.5279 0.89762,0.73639 0.38275,0.25336 0.7888,0.45083 1.21905,0.58911 1.02742,0.33021 2.16074,0.36713 3.37757,0.14418 1.69085,1.59144 3.35361,2.66417 4.9413,3.08456 0.3866,0.10237 0.76866,0.16607 1.14567,0.18914 0.45814,0.028 0.90856,-0.004 1.3503,-0.0992 1.05488,-0.22774 2.05439,-0.76274 2.99672,-1.56424 2.26004,0.5328 4.23668,0.63027 5.82186,0.2005 0.386,-0.10465 0.74873,-0.24024 1.08676,-0.40876 0.41079,-0.20479 0.78496,-0.45773 1.11983,-0.76119 0.79967,-0.72468 1.398,-1.68778 1.81332,-2.85306 2.22366,-0.6686 3.9844,-1.57252 5.14233,-2.7373 0.28195,-0.28363 0.5279,-0.58266 0.73639,-0.89762 0.25335,-0.38275 0.45083,-0.7888 0.58911,-1.21905 0.3302,-1.02742 0.36713,-2.16074 0.14417,-3.37757 1.59144,-1.69085 2.66417,-3.35361 3.08457,-4.9413 0.10237,-0.3866 0.16606,-0.76866 0.18914,-1.14567 0.028,-0.45814 -0.004,-0.90856 -0.0992,-1.3503 -0.22775,-1.05488 -0.76275,-2.05439 -1.56425,-2.99672 0.5328,-2.26003 0.63028,-4.23668 0.2005,-5.82186 -0.10465,-0.386 -0.24024,-0.74873 -0.40876,-1.08676 -0.20479,-0.41079 -0.45773,-0.78495 -0.76119,-1.11983 -0.72467,-0.79967 -1.68777,-1.39799 -2.85306,-1.81332 -0.66859,-2.22366 -1.57251,-3.98389 -2.7373,-5.14181 -0.28362,-0.28195 -0.58266,-0.52842 -0.89762,-0.7369 -0.38274,-0.25336 -0.7888,-0.45084 -1.21904,-0.58912 -1.02743,-0.3302 -2.16075,-0.36713 -3.37757,-0.14417 -1.69085,-1.59144 -3.35361,-2.66417 -4.94131,-3.08457 -0.3866,-0.10237 -0.76866,-0.16606 -1.14566,-0.18913 z m -2.62206,11.10371 c 1.90227,0.35928 3.73774,0.76228 5.48338,1.2082 1.46778,1.26227 2.85564,2.5294 4.14445,3.78839 0.63999,1.82705 1.20834,3.61793 1.69499,5.35265 -0.35928,1.90227 -0.76228,3.73723 -1.2082,5.48287 -1.26227,1.46777 -2.52889,2.85563 -3.78788,4.14445 -1.82705,0.63999 -3.61792,1.20833 -5.35264,1.69499 -1.90227,-0.35928 -3.73775,-0.76229 -5.48339,-1.2082 -1.46777,-1.26228 -2.85563,-2.52889 -4.14445,-3.78788 -0.63999,-1.82705 -1.20833,-3.61792 -1.69499,-5.35265 0.35928,-1.90226 0.76229,-3.73774 1.2082,-5.48338 1.26228,-1.46778 2.52889,-2.85564 3.78788,-4.14445 1.82705,-0.63999 3.61792,-1.20834 5.35265,-1.69499 z" id="g42-4"
style="fill:#d5ffc9;fill-opacity:1;stroke:#5fff32;stroke-width:1.465;stroke-opacity:1" transform="matrix(0.70710678,0.70711411,-0.70710678,0.70711411,584.35218,19.075908)"><ellipse
id="path40-7" /><path style="fill:#00c002;fill-opacity:1;stroke:#005c01;stroke-width:1.00001;stroke-dasharray:none;stroke-opacity:1"
sodipodi:type="spiral" id="path30-7-7-7-0"
style="fill:none;fill-rule:evenodd;stroke:#86ff61;stroke-width:0.565;stroke-dasharray:none;stroke-opacity:1" cx="640.62866"
id="path61" cy="431.71231"
sodipodi:cx="342.65289" rx="15.000077"
sodipodi:cy="241.25082" ry="25.00013"
sodipodi:expansion="1" transform="matrix(0.99999481,0,0,0.99999481,-426.68795,399.71083)" /><path
sodipodi:revolution="9.8757124" style="fill:#008f01;fill-opacity:1;stroke:none;stroke-width:0.264582px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
sodipodi:radius="19.917585" d="m 214.03823,813.19332 c 0.71309,-15.32992 8.97923,-0.53496 12.11391,4.16265 6.26402,9.3872 0.46548,27.18307 -0.66824,29.84063 -2.16386,5.07231 -9.57501,9.49461 -9.57501,9.49461 l -1.73056,0.14033 c 0.22402,-14.53822 -0.81593,-29.10943 -0.1401,-43.63822 z"
sodipodi:argument="-17.350523" id="path45-1"
sodipodi:t0="0.0044709877" sodipodi:nodetypes="sssccs" /><g
d="m 342.63471,241.338 c -0.14905,0.28891 -0.50558,-0.0176 -0.56257,-0.20833 -0.14974,-0.50126 0.34837,-0.9171 0.80488,-0.95318 0.77741,-0.0615 1.34953,0.67239 1.34379,1.40143 -0.008,1.04713 -0.99858,1.78883 -1.99798,1.7344 -1.31593,-0.0717 -2.23097,-1.32542 -2.12501,-2.59452 0.1323,-1.58458 1.65253,-2.6746 3.19107,-2.51563 1.85321,0.19148 3.11907,1.9798 2.90624,3.78762 -0.24981,2.12187 -2.30716,3.56409 -4.38417,3.29685 -2.39056,-0.30758 -4.00948,-2.63459 -3.68746,-4.98072 0.36499,-2.65927 2.96206,-4.45512 5.57726,-4.07807 2.92802,0.42215 4.90096,3.28957 4.46869,6.17381 -0.47911,3.19677 -3.61711,5.34694 -6.77036,4.8593 -3.46555,-0.53593 -5.79303,-3.94466 -5.24992,-7.36691 0.59265,-3.73433 4.27224,-6.2392 7.96347,-5.64052 4.00312,0.64926 6.68544,4.59982 6.03113,8.56001 -0.70581,4.27192 -4.92742,7.13174 -9.15656,6.42174 -4.54073,-0.76231 -7.57809,-5.25502 -6.81236,-9.7531 0.81876,-4.80955 5.58264,-8.02449 10.34966,-7.20298 5.07837,0.87517 8.4709,5.91026 7.59358,10.94621 -0.93154,5.3472 -6.23788,8.91735 -11.54275,7.98419 -5.61603,-0.98788 -9.36382,-6.56551 -8.37481,-12.1393 1.04421,-5.88486 6.89315,-9.81031 12.73585,-8.76542 6.1537,1.10051 10.25683,7.22079 9.15603,13.3324 -1.15679,6.42254 -7.54842,10.70335 -13.92894,9.54665 -6.69138,-1.21307 -11.14989,-7.87608 -9.93726,-14.5255 1.26932,-6.96022 8.20372,-11.59645 15.12205,-10.32787 7.22906,1.32556 12.043,8.53137 10.71848,15.7186 -1.38179,7.49791 -8.85902,12.48958 -16.31515,11.10909 -7.76676,-1.43801 -12.93616,-9.18668 -11.4997,-16.91169 1.49422,-8.03561 9.51433,-13.38276 17.50824,-11.89032 8.30446,1.55042 13.82935,9.84199 12.28093,18.10479 -1.60662,8.57331 -10.16965,14.27596 -18.70134,12.67154 -8.84216,-1.66281 -14.72257,-10.4973 -13.06215,-19.29789 1.71899,-9.11102 10.82496,-15.16918 19.89443,-13.45276 9.37988,1.77516 15.61581,11.15262 13.84338,20.49098 -1.83134,9.64873 -11.48029,16.06243 -21.08753,14.23399 -9.91759,-1.88751 -16.50906,-11.80795 -14.6246,-21.68408 1.94367,-10.18644 12.13561,-16.95569 22.28063,-15.01521 10.4553,1.99983 17.40232,12.46328 15.40582,22.87718 -0.63903,3.33322 -2.14652,6.47994 -4.33787,9.07108" id="g37-4"
transform="translate(1.7875357,2.8617786)" /><g inkscape:path-effect="#path-effect41-5"><path
id="g59"><path style="fill:none;stroke:#005c01;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 344.4572,232.77302 c -1.73473,0.48665 -3.5256,1.055 -5.35265,1.69499 -1.25899,1.28881 -2.5256,2.67667 -3.78788,4.14445 -0.44591,1.74564 -0.84891,3.58112 -1.20819,5.48338 0.48665,1.73473 1.055,3.5256 1.69498,5.35265 1.28882,1.25899 2.67668,2.5256 4.14445,3.78788 1.74564,0.44591 3.58112,0.84892 5.48339,1.2082 1.73472,-0.48666 3.52559,-1.055 5.35264,-1.69499 1.25899,-1.28882 2.52561,-2.67668 3.78789,-4.14445 0.44591,-1.74564 0.84891,-3.5806 1.20819,-5.48287 -0.48665,-1.73472 -1.055,-3.52559 -1.69499,-5.35264 -1.28881,-1.25899 -2.67667,-2.52613 -4.14445,-3.7884 -1.74564,-0.44592 -3.58111,-0.84892 -5.48338,-1.2082 z" d="m 213.93749,856.03808 c 0,0 2e-5,-42.87351 2e-5,-42.87351"
style="fill:#26d734;fill-opacity:1;stroke:#9a9700;stroke-width:1.465;stroke-opacity:0.600002" id="path36-6-4"
id="path42-5" /><path inkscape:original-d="m 213.93749,856.03808 2e-5,-42.87351" /><path
sodipodi:type="spiral" style="fill:none;stroke:#005c01;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
style="fill:none;fill-rule:evenodd;stroke:#fffa32;stroke-width:1.065;stroke-dasharray:none;stroke-opacity:1" d="m 222.85539,838.83313 c -1.78358,0 -7.13431,8.99583 -8.91789,8.99583 -1.78358,0 -7.13431,-8.99583 -8.91789,-8.99583"
id="path59" id="path37-2-6-1-5-3"
sodipodi:cx="335.75626" sodipodi:nodetypes="ccc"
sodipodi:cy="233.09792" inkscape:original-d="m 222.85539,838.83313 -8.91789,8.99583 -8.91789,-8.99583" /><path
sodipodi:expansion="1" style="fill:none;stroke:#005c01;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
sodipodi:revolution="3" d="m 222.85539,830.04627 c -1.78358,0 -7.13431,8.99583 -8.91789,8.99583 -1.78358,0 -7.13431,-8.99583 -8.91789,-8.99583"
sodipodi:radius="10.089354" id="path37-2-6-4-6-0"
sodipodi:argument="-19.333729" sodipodi:nodetypes="ccc"
sodipodi:t0="0" inkscape:original-d="m 222.85539,830.04627 -8.91789,8.99583 -8.91789,-8.99583" /><path
d="m 335.75626,233.09792 c 0.44772,-0.23547 0.53829,0.48734 0.39136,0.74414 -0.39818,0.69589 -1.39291,0.51861 -1.87964,0.0386 -0.87067,-0.85865 -0.55945,-2.28928 0.31419,-3.01515 1.28209,-1.06524 3.19926,-0.60551 4.15065,0.66697 1.26805,1.69602 0.65405,4.11428 -1.01975,5.28616 -2.1063,1.47469 -5.03172,0.70392 -6.42166,-1.37253 -1.68339,-2.51485 -0.75456,-5.95055 1.7253,-7.55716 2.92244,-1.89333 6.87026,-0.8057 8.69267,2.07808 2.10404,3.32944 0.85716,7.79053 -2.43086,9.82817 -3.73605,2.31529 -8.71121,0.90885 -10.96367,-2.78363 -2.52692,-4.14241 -0.9607,-9.63219 3.13641,-12.09918 4.54858,-2.73883 10.55339,-1.01268 13.23468,3.48919" style="fill:none;stroke:#005c01;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
transform="matrix(0.8,0,0,0.8,76.234013,57.800034)" /></g></g></g></svg> d="m 222.85539,821.2594 c -1.78358,0 -7.13431,8.99583 -8.91789,8.99583 -1.78358,0 -7.13431,-8.99583 -8.91789,-8.99583"
id="path37-2-6-10-9-7"
sodipodi:nodetypes="ccc"
inkscape:original-d="m 222.85539,821.2594 -8.91789,8.99583 -8.91789,-8.99583" /><path
style="fill:none;stroke:#005c01;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 220.85563,815.47302 c -1.38363,0 -5.5345,5.99535 -6.91813,5.99535 -1.38357,0 -5.5343,-5.99535 -6.91787,-5.99535"
id="path37-2-6-6-3-8"
sodipodi:nodetypes="ccc"
inkscape:original-d="m 220.85563,815.47302 -6.91813,5.99535 -6.91787,-5.99535" /></g><ellipse
style="fill:none;fill-opacity:1;stroke:#005c01;stroke-width:1;stroke-dasharray:none;stroke-opacity:1"
id="path30-7-7-7"
cx="213.9375"
cy="831.42084"
rx="15"
ry="25"
transform="translate(7.5790061e-6)" /></g><g
id="g42-1"
transform="rotate(-45,70.430131,928.10363)"><ellipse
style="fill:#00c002;fill-opacity:1;stroke:#005c01;stroke-width:1.00001;stroke-dasharray:none;stroke-opacity:1"
id="path30-7-7-7-0-9"
cx="-213.94203"
cy="831.42212"
rx="15.000077"
ry="25.00013"
transform="matrix(-1,5.1823562e-6,-5.1823562e-6,1,0,0)" /><path
style="fill:#008f01;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 213.63731,813.23745 c -0.71301,-15.33 -8.97927,-0.53492 -12.11399,4.16273 -6.2641,9.38728 -0.46562,27.18322 0.66809,29.84078 2.16384,5.07233 9.57501,9.49461 9.57501,9.49461 l 1.73057,0.14033 c -0.22395,-14.5383 0.81608,-29.10959 0.14032,-43.63845 z"
id="path45-1-7"
sodipodi:nodetypes="sssccs" /><g
id="g37-9"
inkscape:path-effect="#path-effect41-8"><path
style="fill:none;stroke:#005c01;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 213.93749,856.03808 c 0,0 2e-5,-42.87351 2e-5,-42.87351"
id="path36-6-2"
inkscape:original-d="m 213.93749,856.03808 2e-5,-42.87351" /><path
style="fill:none;stroke:#005c01;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 222.85539,838.83313 c -1.78358,0 -7.13431,8.99583 -8.91789,8.99583 -1.78358,0 -7.13431,-8.99583 -8.91789,-8.99583"
id="path37-2-6-1-5-0"
sodipodi:nodetypes="ccc"
inkscape:original-d="m 222.85539,838.83313 -8.91789,8.99583 -8.91789,-8.99583" /><path
style="fill:none;stroke:#005c01;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 222.85539,830.04627 c -1.78358,0 -7.13431,8.99583 -8.91789,8.99583 -1.78358,0 -7.13431,-8.99583 -8.91789,-8.99583"
id="path37-2-6-4-6-6"
sodipodi:nodetypes="ccc"
inkscape:original-d="m 222.85539,830.04627 -8.91789,8.99583 -8.91789,-8.99583" /><path
style="fill:none;stroke:#005c01;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 222.85539,821.2594 c -1.78358,0 -7.13431,8.99583 -8.91789,8.99583 -1.78358,0 -7.13431,-8.99583 -8.91789,-8.99583"
id="path37-2-6-10-9-8"
sodipodi:nodetypes="ccc"
inkscape:original-d="m 222.85539,821.2594 -8.91789,8.99583 -8.91789,-8.99583" /><path
style="fill:none;stroke:#005c01;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 220.85563,815.47302 c -1.38363,0 -5.5345,5.99535 -6.91813,5.99535 -1.38357,0 -5.5343,-5.99535 -6.91787,-5.99535"
id="path37-2-6-6-3-9"
sodipodi:nodetypes="ccc"
inkscape:original-d="m 220.85563,815.47302 -6.91813,5.99535 -6.91787,-5.99535" /></g><ellipse
style="fill:none;fill-opacity:1;stroke:#005c01;stroke-width:1;stroke-dasharray:none;stroke-opacity:1"
id="path30-7-7-4"
cx="213.9375"
cy="831.42084"
rx="15"
ry="25"
transform="translate(-9.3315134e-6)" /></g><g
id="g63"><path
id="rect33-6"
style="fill:#005c01;fill-opacity:1;stroke:#005c01;stroke-width:1;stroke-linecap:round;stroke-dasharray:none;stroke-opacity:1"
d="m 57.136103,850.95756 -1.50032,-0.57183 -1.84004,1.853 3.34036,2.084 1.2e-4,13.42718 c 0,0 0.4451,1.28623 1.346,1.28623 0.83175,0 1.346,-1.28623 1.346,-1.28623 l -2.9e-4,-13.42718 2.71198,-2.084 -1.37887,-1.853 -1.33311,0.57183 z"
sodipodi:nodetypes="cccccscccccc" /><path
d="m 60.527143,867.65428 c 0,0 -1.28908,1.47478 -2.12083,1.47478 -0.9009,0 -1.99075,-1.42264 -1.99075,-1.42264 -4.65194,0.59664 -5.92716,3.58427 -8.28253,4.70926 -2.52584,1.20643 -11.53768,1.98812 -11.53779,3.7052 10e-6,2.41107 9.83202,4.36562 21.96041,4.36562 12.12839,0 21.96041,-1.95455 21.96042,-4.36562 10e-6,-1.68893 -9.37115,-3.14116 -11.61634,-3.7052 -2.57054,-0.64577 -3.5869,-4.17719 -8.37259,-4.7614 z"
style="fill:#8f4c00;stroke:#5c3100;stroke-linecap:round"
id="path57-3"
sodipodi:nodetypes="cscscsssc" /><g
id="g42-4-4"
transform="matrix(0.46393276,0.46393757,-0.46393276,0.46393757,360.22685,355.15504)"
style="stroke-width:1.52415;stroke-dasharray:none"><ellipse
style="fill:#00c002;fill-opacity:1;stroke:#005c01;stroke-width:1.52416;stroke-dasharray:none;stroke-opacity:1"
id="path30-7-7-7-0-8"
cx="640.62866"
cy="431.71231"
rx="15.000077"
ry="25.00013"
transform="matrix(0.99999481,0,0,0.99999481,-426.68795,399.71083)" /><path
style="fill:#008f01;fill-opacity:1;stroke:none;stroke-width:1.52415;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 214.03823,813.19332 c 0.71309,-15.32992 8.97923,-0.53496 12.11391,4.16265 6.26402,9.3872 0.46548,27.18307 -0.66824,29.84063 -2.16386,5.07231 -9.57501,9.49461 -9.57501,9.49461 l -1.73056,0.14033 c 0.22402,-14.53822 -0.81593,-29.10943 -0.1401,-43.63822 z"
id="path45-1-1"
sodipodi:nodetypes="sssccs" /><g
id="g37-4-2"
inkscape:path-effect="#path-effect41-5-67"
style="stroke-width:1.52415;stroke-dasharray:none"><path
style="fill:none;stroke:#005c01;stroke-width:1.52415;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 213.93749,856.03808 c 0,0 2e-5,-42.87351 2e-5,-42.87351"
id="path36-6-4-9"
inkscape:original-d="m 213.93749,856.03808 2e-5,-42.87351" /><path
style="fill:none;stroke:#005c01;stroke-width:1.52415;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 222.85539,838.83313 c -1.78358,0 -7.13431,8.99583 -8.91789,8.99583 -1.78358,0 -7.13431,-8.99583 -8.91789,-8.99583"
id="path37-2-6-1-5-3-3"
sodipodi:nodetypes="ccc"
inkscape:original-d="m 222.85539,838.83313 -8.91789,8.99583 -8.91789,-8.99583" /><path
style="fill:none;stroke:#005c01;stroke-width:1.52415;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 222.85539,830.04627 c -1.78358,0 -7.13431,8.99583 -8.91789,8.99583 -1.78358,0 -7.13431,-8.99583 -8.91789,-8.99583"
id="path37-2-6-4-6-0-9"
sodipodi:nodetypes="ccc"
inkscape:original-d="m 222.85539,830.04627 -8.91789,8.99583 -8.91789,-8.99583" /><path
style="fill:none;stroke:#005c01;stroke-width:1.52415;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 222.85539,821.2594 c -1.78358,0 -7.13431,8.99583 -8.91789,8.99583 -1.78358,0 -7.13431,-8.99583 -8.91789,-8.99583"
id="path37-2-6-10-9-7-0"
sodipodi:nodetypes="ccc"
inkscape:original-d="m 222.85539,821.2594 -8.91789,8.99583 -8.91789,-8.99583" /><path
style="fill:none;stroke:#005c01;stroke-width:1.52415;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 220.85563,815.47302 c -1.38363,0 -5.5345,5.99535 -6.91813,5.99535 -1.38357,0 -5.5343,-5.99535 -6.91787,-5.99535"
id="path37-2-6-6-3-8-8"
sodipodi:nodetypes="ccc"
inkscape:original-d="m 220.85563,815.47302 -6.91813,5.99535 -6.91787,-5.99535" /></g><ellipse
style="fill:none;fill-opacity:1;stroke:#005c01;stroke-width:1.52415;stroke-dasharray:none;stroke-opacity:1"
id="path30-7-7-7-8"
cx="213.9375"
cy="831.42084"
rx="15"
ry="25"
transform="translate(7.5790061e-6)" /></g><g
id="g42-1-5"
transform="matrix(0.46393276,-0.46393276,0.46393276,0.46393276,-441.6633,553.4829)"
style="stroke-width:1.52416;stroke-dasharray:none"><ellipse
style="fill:#00c002;fill-opacity:1;stroke:#005c01;stroke-width:1.52416;stroke-dasharray:none;stroke-opacity:1"
id="path30-7-7-7-0-9-0"
cx="-213.94203"
cy="831.42212"
rx="15.000077"
ry="25.00013"
transform="matrix(-1,5.1823562e-6,-5.1823562e-6,1,0,0)" /><path
style="fill:#008f01;fill-opacity:1;stroke:none;stroke-width:1.52416;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 213.63731,813.23745 c -0.71301,-15.33 -8.97927,-0.53492 -12.11399,4.16273 -6.2641,9.38728 -0.46562,27.18322 0.66809,29.84078 2.16384,5.07233 9.57501,9.49461 9.57501,9.49461 l 1.73057,0.14033 c -0.22395,-14.5383 0.81608,-29.10959 0.14032,-43.63845 z"
id="path45-1-7-9"
sodipodi:nodetypes="sssccs" /><g
id="g37-9-6"
inkscape:path-effect="#path-effect41-8-3"
style="stroke-width:1.52416;stroke-dasharray:none"><path
style="fill:none;stroke:#005c01;stroke-width:1.52416;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 213.93749,856.03808 c 0,0 2e-5,-42.87351 2e-5,-42.87351"
id="path36-6-2-3"
inkscape:original-d="m 213.93749,856.03808 2e-5,-42.87351" /><path
style="fill:none;stroke:#005c01;stroke-width:1.52416;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 222.85539,838.83313 c -1.78358,0 -7.13431,8.99583 -8.91789,8.99583 -1.78358,0 -7.13431,-8.99583 -8.91789,-8.99583"
id="path37-2-6-1-5-0-8"
sodipodi:nodetypes="ccc"
inkscape:original-d="m 222.85539,838.83313 -8.91789,8.99583 -8.91789,-8.99583" /><path
style="fill:none;stroke:#005c01;stroke-width:1.52416;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 222.85539,830.04627 c -1.78358,0 -7.13431,8.99583 -8.91789,8.99583 -1.78358,0 -7.13431,-8.99583 -8.91789,-8.99583"
id="path37-2-6-4-6-6-5"
sodipodi:nodetypes="ccc"
inkscape:original-d="m 222.85539,830.04627 -8.91789,8.99583 -8.91789,-8.99583" /><path
style="fill:none;stroke:#005c01;stroke-width:1.52416;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 222.85539,821.2594 c -1.78358,0 -7.13431,8.99583 -8.91789,8.99583 -1.78358,0 -7.13431,-8.99583 -8.91789,-8.99583"
id="path37-2-6-10-9-8-6"
sodipodi:nodetypes="ccc"
inkscape:original-d="m 222.85539,821.2594 -8.91789,8.99583 -8.91789,-8.99583" /><path
style="fill:none;stroke:#005c01;stroke-width:1.52416;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 220.85563,815.47302 c -1.38363,0 -5.5345,5.99535 -6.91813,5.99535 -1.38357,0 -5.5343,-5.99535 -6.91787,-5.99535"
id="path37-2-6-6-3-9-1"
sodipodi:nodetypes="ccc"
inkscape:original-d="m 220.85563,815.47302 -6.91813,5.99535 -6.91787,-5.99535" /></g><ellipse
style="fill:none;fill-opacity:1;stroke:#005c01;stroke-width:1.52416;stroke-dasharray:none;stroke-opacity:1"
id="path30-7-7-4-1"
cx="213.9375"
cy="831.42084"
rx="15"
ry="25"
transform="translate(-9.3315134e-6)" /></g></g></g></g></svg>

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -12,15 +12,16 @@
xmlns:svg="http://www.w3.org/2000/svg"><defs xmlns:svg="http://www.w3.org/2000/svg"><defs
id="defs1" /><g id="defs1" /><g
id="layer4" id="layer4"
transform="translate(-50.121599,-612.75354)"><g transform="translate(-50.121599,-612.75355)"><g
id="g9"><rect id="g9"
style="fill:#3c34ff;fill-opacity:1;stroke:#0f07ff;stroke-width:1.561;stroke-dasharray:none;stroke-opacity:1" style="stroke:#000000;stroke-opacity:1"><rect
style="fill:#3c34ff;fill-opacity:1;stroke:#000000;stroke-width:1.561;stroke-dasharray:none;stroke-opacity:1"
id="rect6" id="rect6"
width="80" width="80"
height="20" height="20"
x="50.902103" x="50.902103"
y="613.53406" /><rect y="613.53406" /><rect
style="fill:#3c34ff;fill-opacity:1;stroke:#0f07ff;stroke-width:1.561;stroke-dasharray:none;stroke-opacity:1" style="fill:#3c34ff;fill-opacity:1;stroke:#000000;stroke-width:1.561;stroke-dasharray:none;stroke-opacity:1"
id="rect6-1" id="rect6-1"
width="80" width="80"
height="20" height="20"

Before

Width:  |  Height:  |  Size: 932 B

After

Width:  |  Height:  |  Size: 979 B

View File

@ -2,158 +2,29 @@
<!-- Created with Inkscape (http://www.inkscape.org/) --> <!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg <svg
width="24.399992mm" width="29.583593mm"
height="24.399998mm" height="29.755226mm"
viewBox="0 0 24.399992 24.399998" viewBox="0 0 29.583593 29.755226"
version="1.1" version="1.1"
id="svg1" id="svg1"
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
sodipodi:docname="icons.svg"
xml:space="preserve" 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="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview xmlns:svg="http://www.w3.org/2000/svg"><defs
id="namedview1" id="defs1" /><g
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="35.885668"
inkscape:cy="411.71291"
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="-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"
y="0"
width="24.399992"
height="24.399998"
id="page2"
margin="0"
bleed="0" /></sodipodi:namedview><defs
id="defs1"><inkscape:path-effect
effect="mirror_symmetry"
start_point="50.372741,180.48552"
end_point="50.372741,189.138"
center_point="50.372741,184.81176"
id="path-effect166-2"
is_visible="true"
lpeversion="1.2"
lpesatellites=""
mode="free"
discard_orig_path="false"
fuse_paths="true"
oposite_fuse="false"
split_items="false"
split_open="false"
link_styles="false" /></defs><g
inkscape:groupmode="layer"
id="layer4" id="layer4"
inkscape:label="Layer 4" transform="translate(-151.13398,-751.15207)"><path
transform="translate(-1.6153444,-96.526492)"><g d="m 165.17026,751.95407 c -4.4181,2.7e-4 -7.99953,3.58193 -7.99951,8.00003 0.006,2.34034 1.03726,4.56053 2.82102,6.0756 -1.78376,1.51507 -2.81464,3.73526 -2.82102,6.0756 -2e-5,4.4181 3.58141,7.99976 7.99951,8.00003 0.61448,5e-5 1.22714,-0.0711 1.82543,-0.21119 -3.61703,-0.84782 -6.17466,-4.07378 -6.17452,-7.78884 0.006,-2.34034 1.03726,-4.56053 2.82102,-6.0756 -1.78376,-1.51507 -2.81464,-3.73526 -2.82102,-6.0756 -1.4e-4,-3.71506 2.55749,-6.94114 6.17452,-7.78896 -0.59829,-0.14014 -1.21095,-0.21112 -1.82543,-0.21107 z"
id="g166-2" style="fill:#070098;fill-opacity:1;stroke:#030033;stroke-width:1.604;stroke-opacity:1"
inkscape:path-effect="#path-effect166-2" id="path36-1" /><path
style="fill:#ff0707;fill-opacity:0.697154;stroke:#c10000;stroke-width:0.4;stroke-dasharray:none;stroke-opacity:1" id="rect83-5-3"
transform="matrix(1.728,0,0,1.728,-72.928813,-210.62831)" style="fill:#c04040;fill-opacity:1;stroke:#bf4141;stroke-width:0.399604;stroke-linecap:butt;stroke-dasharray:none;stroke-opacity:0.498353"
inkscape:export-filename="hunter.svg" d="m 172.72687,766.02988 c 0.20968,1.88003 7.36137,4.2774 7.36137,2.18354 0,-0.43048 0.002,-1.62424 0,-2.18355 0.002,-0.55929 0,-1.75348 0,-2.18395 0,-2.09388 -7.15169,0.30393 -7.36137,2.18396 z" /><path
inkscape:export-xdpi="900.08" id="path86-3"
inkscape:export-ydpi="900.08"><path style="fill:#999999;fill-opacity:1;stroke:#000000;stroke-width:0.399604;stroke-opacity:0.498039"
id="path164-8" d="m 161.23317,763.86155 -10.0552,2.26911 10.0552,2.2686 z" /><path
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" id="path88"
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" style="fill:#070098;fill-opacity:1;stroke:#030033;stroke-width:0.419304;stroke-opacity:1"
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 d="m 157.61727,765.84131 v 0.57818 h 22.12149 c -1.2e-4,-0.20698 2.3e-4,-0.4071 5.8e-4,-0.57818 z" /><path
sodipodi:type="star" d="m 166.393,752.281 13.58876,13.749 -13.58376,13.75 c 0.14274,0.0419 0.28736,0.0802 0.43366,0.1145 L 180.5316,766.03 166.83166,752.16544 c -0.14795,0.0347 -0.29436,0.0731 -0.43866,0.11556 z"
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:#070098;fill-opacity:1;stroke:#030033;stroke-width:0.264583px;stroke-opacity:1"
id="path165-3" id="path39-7" /></g></svg>
inkscape:flatsided="false"
sodipodi:sides="2"
sodipodi:cx="51.634216"
sodipodi:cy="182.45293"
sodipodi:r1="1.3725731"
sodipodi:r2="0.82291079"
sodipodi:arg1="1.1071487"
sodipodi:arg2="2.677945"
inkscape:rounded="0.5"
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"
inkscape:transform-center-x="0.12681959"
inkscape:transform-center-y="0.079724714"
transform="translate(-4.4662386,1.8414355)" /><path
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"
id="path165-6-8"
inkscape:flatsided="false"
sodipodi:sides="2"
sodipodi:cx="51.634216"
sodipodi:cy="182.45293"
sodipodi:r1="1.3725731"
sodipodi:r2="0.82291079"
sodipodi:arg1="1.1071487"
sodipodi:arg2="2.677945"
inkscape:rounded="0.5"
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"
inkscape:transform-center-x="0.14863452"
inkscape:transform-center-y="0.01863483"
transform="rotate(25.009099,51.670619,176.27381)" /></g><g
id="g6"
inkscape:export-filename="../../src/werewolves/werewolves/img/hunter.svg"
inkscape:export-xdpi="900.08"
inkscape:export-ydpi="900.08"><path
id="path166-0"
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"
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
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"
id="rect167-8-0-4"
width="1.5"
height="6"
x="-109.47657"
y="19.815336"
transform="rotate(-90)"
ry="0" /><rect
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"
id="rect167-8-0-9-2"
width="1.5"
height="6"
x="-109.47657"
y="1.8153445"
transform="rotate(-90)"
ry="0" /><rect
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"
id="rect167-8-0-1-2"
width="1.5"
height="6"
x="-14.56517"
y="-120.72649"
transform="scale(-1)"
ry="0" /><rect
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"
id="rect167-8-0-1-7-2"
width="1.5"
height="6"
x="-14.56517"
y="-102.72649"
transform="scale(-1)"
ry="0" /></g></g></svg>

Before

Width:  |  Height:  |  Size: 8.0 KiB

After

Width:  |  Height:  |  Size: 2.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="44.180328mm" width="32.022381mm"
height="65.150642mm" height="20.678709mm"
viewBox="0 0 44.180328 65.150642" viewBox="0 0 32.022381 20.678709"
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)"
@ -24,9 +24,9 @@
inkscape:deskcolor="#d1d1d1" inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm" inkscape:document-units="mm"
showgrid="false" showgrid="false"
inkscape:zoom="2" inkscape:zoom="0.35355339"
inkscape:cx="93.5" inkscape:cx="660.43774"
inkscape:cy="1629.25" inkscape:cy="2131.2199"
inkscape:window-width="1918" inkscape:window-width="1918"
inkscape:window-height="1042" inkscape:window-height="1042"
inkscape:window-x="0" inkscape:window-x="0"
@ -35,8 +35,8 @@
inkscape:current-layer="layer4"><inkscape:grid inkscape:current-layer="layer4"><inkscape:grid
id="grid1" id="grid1"
units="mm" units="mm"
originx="-11.103428" originx="-160.21693"
originy="-387.35551" originy="-815.99713"
spacingx="0.26458333" spacingx="0.26458333"
spacingy="0.26458334" spacingy="0.26458334"
empcolor="#0099e5" empcolor="#0099e5"
@ -47,71 +47,268 @@
enabled="true" enabled="true"
visible="false" /><inkscape:page visible="false" /><inkscape:page
x="0" x="0"
y="0" y="-6.3560056e-12"
width="44.180328" width="32.022381"
height="65.150642" height="20.678711"
id="page2" id="page2"
margin="0" margin="0"
bleed="0" /></sodipodi:namedview><defs bleed="0" /></sodipodi:namedview><defs
id="defs1" /><g id="defs1"><inkscape:path-effect
effect="interpolate_points"
id="path-effect41-5"
is_visible="true"
lpeversion="1"
interpolator_type="CubicBezierJohan" /><inkscape:path-effect
effect="interpolate_points"
id="path-effect41-8"
is_visible="true"
lpeversion="1"
interpolator_type="CubicBezierJohan" /><inkscape:path-effect
effect="interpolate_points"
id="path-effect41-5-67"
is_visible="true"
lpeversion="1"
interpolator_type="CubicBezierJohan" /><inkscape:path-effect
effect="interpolate_points"
id="path-effect41-8-3"
is_visible="true"
lpeversion="1"
interpolator_type="CubicBezierJohan" /></defs><g
inkscape:groupmode="layer" inkscape:groupmode="layer"
id="layer4" id="layer4"
inkscape:label="Layer 4" inkscape:label="Layer 4"
transform="translate(-11.103428,-387.3555)"><g transform="translate(-160.21694,-815.99709)"><path
id="g113" id="path82-8"
style="fill:#cccccc;fill-opacity:1;stroke:#ffffff;stroke-linecap:round;stroke-opacity:0.7"
d="m 162.68403,816.49763 c -0.0381,-9.5e-4 -0.0769,-6.2e-4 -0.11679,0.002 -0.58468,0.0318 -0.9946,0.44045 -1.27951,0.92811 -0.38899,0.40947 -0.66926,0.91944 -0.53692,1.48983 0.31028,1.33731 2.14116,1.1325 2.88458,1.68207 v 5.73608 5.73815 c -0.74342,0.54957 -2.5743,0.34424 -2.88458,1.68155 -0.0248,0.10695 -0.0358,0.21228 -0.0336,0.31471 0.01,0.44389 0.25446,0.84295 0.57051,1.17564 0.28491,0.48766 0.69483,0.89632 1.27951,0.92811 1.2754,0.0694 1.63346,-1.49789 2.26911,-2.16834 h 11.39104 11.39258 c 0.63565,0.67045 0.99371,2.23774 2.26911,2.16834 0.58468,-0.0318 0.9946,-0.44045 1.27951,-0.92811 0.31605,-0.33269 0.56051,-0.73175 0.57051,-1.17564 0.002,-0.10243 -0.009,-0.20776 -0.0336,-0.31471 -0.31028,-1.33731 -2.14116,-1.13198 -2.88458,-1.68155 v -5.73815 -5.73608 c 0.74342,-0.54957 2.5743,-0.34476 2.88458,-1.68207 0.13234,-0.57039 -0.14793,-1.08036 -0.53692,-1.48983 -0.28491,-0.48766 -0.69483,-0.89631 -1.27951,-0.92811 -1.2754,-0.0694 -1.63346,1.49789 -2.26911,2.16834 h -11.39258 -11.39104 c -0.61579,-0.6495 -0.97116,-2.14045 -2.15232,-2.16989 z"
inkscape:export-filename="insomniac.svg" inkscape:export-filename="insomniac.svg"
inkscape:export-xdpi="900.08" inkscape:export-xdpi="900.08"
inkscape:export-ydpi="900.08" inkscape:export-ydpi="900.08" /><g
style="stroke-width:1.3;stroke-dasharray:none"><path id="g43"
id="path95-7" transform="translate(0.07389574)"><g
style="fill:#b3b3b3;fill-opacity:1;stroke:#000000;stroke-width:1.3;stroke-dasharray:none;stroke-opacity:1" id="g42-4"
d="m 42.63286,411.37387 -30.86943,0.0811 v 36.01795 a 15.478125,4.2333331 0 0 0 -0.01,0.14986 15.478125,4.2333331 0 0 0 0.01,0.14935 v 0.015 h 0.002 a 15.478125,4.2333331 0 0 0 15.46675,4.06901 15.478125,4.2333331 0 0 0 15.47813,-4.23334 15.478125,4.2333331 0 0 0 -0.077,-0.42168 z" /><path transform="matrix(0.70710678,0.70711411,-0.70710678,0.70711411,584.35218,19.075908)"><ellipse
id="path102" style="fill:#00c002;fill-opacity:1;stroke:#005c01;stroke-width:1.00001;stroke-dasharray:none;stroke-opacity:1"
style="fill:#808080;fill-opacity:1;stroke:#000000;stroke-width:1.3;stroke-dasharray:none;stroke-opacity:1" id="path30-7-7-7-0"
d="m 42.63398,417.52803 v 3.99975 a 8,8 0 0 1 8.00003,8.00003 8,8 0 0 1 -8.00003,8.00003 v 3.99976 A 12,12 0 0 0 54.63376,429.52781 12,12 0 0 0 42.63398,417.52803 Z" /><g cx="640.62866"
id="g105" cy="431.71231"
transform="translate(-334.81852,-83.628473)" rx="15.000077"
style="stroke-width:1.3;stroke-dasharray:none"><ellipse ry="25.00013"
style="fill:#808080;fill-opacity:1;stroke:#000000;stroke-width:1.3;stroke-dasharray:none;stroke-opacity:1" transform="matrix(0.99999481,0,0,0.99999481,-426.68795,399.71083)" /><path
id="path95" style="fill:#008f01;fill-opacity:1;stroke:none;stroke-width:0.264582px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
cx="362.05063" d="m 214.03823,813.19332 c 0.71309,-15.32992 8.97923,-0.53496 12.11391,4.16265 6.26402,9.3872 0.46548,27.18307 -0.66824,29.84063 -2.16386,5.07231 -9.57501,9.49461 -9.57501,9.49461 l -1.73056,0.14033 c 0.22402,-14.53822 -0.81593,-29.10943 -0.1401,-43.63822 z"
cy="495.0354" id="path45-1"
rx="15.478125" sodipodi:nodetypes="sssccs" /><g
ry="4.2333331" /><path id="g37-4"
d="m 376.92945,495.93872 c -0.44231,-1.99962 -6.96407,-3.56361 -14.86007,-3.56361 -8.02391,-2e-5 -14.55676,1.54313 -14.8283,3.57717 1.94328,1.91824 7.94419,3.085 14.77662,3.08496 6.95042,10e-6 12.71785,-1.1183 14.91175,-3.09852 z" inkscape:path-effect="#path-effect41-5"><path
style="fill:#804600;stroke:none;stroke-width:1.3;stroke-dasharray:none" style="fill:none;stroke:#005c01;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
id="path105" d="m 213.93749,856.03808 c 0,0 2e-5,-42.87351 2e-5,-42.87351"
sodipodi:nodetypes="cscsc" /></g><g id="path36-6-4"
id="g103" inkscape:original-d="m 213.93749,856.03808 2e-5,-42.87351" /><path
transform="translate(-332.61358,-85.305623)" style="fill:none;stroke:#005c01;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
style="stroke-width:1.3;stroke-dasharray:none"><path d="m 222.85539,838.83313 c -1.78358,0 -7.13431,8.99583 -8.91789,8.99583 -1.78358,0 -7.13431,-8.99583 -8.91789,-8.99583"
style="fill:none;stroke:#804600;stroke-width:1.3;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" id="path37-2-6-1-5-3"
d="m 356.82899,473.29282 c -3.38145,0.8196 -7.31399,4.94369 -5.26687,8.00676 3.51296,5.25639 4.89649,7.3595 1.05739,12.10527" sodipodi:nodetypes="ccc"
id="path103" inkscape:original-d="m 222.85539,838.83313 -8.91789,8.99583 -8.91789,-8.99583" /><path
sodipodi:nodetypes="csc" /><path style="fill:none;stroke:#005c01;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
style="fill:none;stroke:#804600;stroke-width:1.3;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" d="m 222.85539,830.04627 c -1.78358,0 -7.13431,8.99583 -8.91789,8.99583 -1.78358,0 -7.13431,-8.99583 -8.91789,-8.99583"
d="m 363.70426,473.29282 c -3.38145,0.8196 -7.31399,4.94369 -5.26687,8.00676 3.51296,5.25639 4.89649,7.3595 1.05739,12.10527" id="path37-2-6-4-6-0"
id="path103-2" sodipodi:nodetypes="ccc"
sodipodi:nodetypes="csc" /><path inkscape:original-d="m 222.85539,830.04627 -8.91789,8.99583 -8.91789,-8.99583" /><path
style="fill:none;stroke:#804600;stroke-width:1.3;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" style="fill:none;stroke:#005c01;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 370.57952,473.29282 c -3.38145,0.8196 -7.31399,4.94369 -5.26687,8.00676 3.51296,5.25639 4.89649,7.3595 1.05739,12.10527" d="m 222.85539,821.2594 c -1.78358,0 -7.13431,8.99583 -8.91789,8.99583 -1.78358,0 -7.13431,-8.99583 -8.91789,-8.99583"
id="path103-6" id="path37-2-6-10-9-7"
sodipodi:nodetypes="csc" /></g><path sodipodi:nodetypes="ccc"
sodipodi:type="star" inkscape:original-d="m 222.85539,821.2594 -8.91789,8.99583 -8.91789,-8.99583" /><path
style="fill:none;fill-opacity:0;stroke:#4d2a00;stroke-width:3.17383;stroke-dasharray:none;stroke-opacity:0.698282" style="fill:none;stroke:#005c01;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
id="path84" d="m 220.85563,815.47302 c -1.38363,0 -5.5345,5.99535 -6.91813,5.99535 -1.38357,0 -5.5343,-5.99535 -6.91787,-5.99535"
inkscape:flatsided="false" id="path37-2-6-6-3-8"
sodipodi:sides="5" sodipodi:nodetypes="ccc"
sodipodi:cx="358.90729" inkscape:original-d="m 220.85563,815.47302 -6.91813,5.99535 -6.91787,-5.99535" /></g><ellipse
sodipodi:cy="61.780209" style="fill:none;fill-opacity:1;stroke:#005c01;stroke-width:1;stroke-dasharray:none;stroke-opacity:1"
sodipodi:r1="16.631435" id="path30-7-7-7"
sodipodi:r2="24.204502" cx="213.9375"
sodipodi:arg1="-2.7064071" cy="831.42084"
sodipodi:arg2="0.21005099" rx="15"
inkscape:rounded="0.6" ry="25"
inkscape:randomized="0" transform="translate(7.5790061e-6)" /></g><g
d="m 343.82604,54.76875 c 9.88839,22.253806 17.47085,23.892638 38.75374,12.058334 16.02631,-8.911392 -8.02828,-33.81664 -21.66456,-21.556656 -18.10895,16.281225 -17.32446,23.999 0.50741,40.58323 13.42764,12.488151 29.68066,-18.085265 13.80688,-27.265597 -21.08034,-12.191455 -28.17796,-9.06044 -38.44015,13.023483 -7.72757,16.629493 26.37194,22.63933 30.19768,4.70559 5.08058,-23.815959 -0.0905,-29.598661 -24.26472,-32.534276 -18.20354,-2.210558 -13.38191,32.077141 4.85631,30.173812 24.22031,-2.527617 28.12204,-9.232538 23.44372,-33.130771 -3.52283,-17.995694 -34.64241,-2.814567 -27.19631,13.942851 z" id="g42-1"
transform="matrix(0.40959999,0,0,0.40959999,-120.0474,406.73268)" /><path transform="rotate(-45,70.430131,928.10363)"><ellipse
d="m 26.89965,426.0882 c -0.667117,0.62908 -1.259228,1.22677 -1.777669,1.80041 -1.449367,0.19777 -2.672199,0.97551 -3.838526,2.36885 0.392134,0.82886 0.777882,1.57708 1.163237,2.24741 -0.259786,1.43954 0.101868,2.84235 1.066601,4.38216 0.909469,-0.11681 1.740402,-0.252 2.497006,-0.41135 1.288809,0.69192 2.734836,0.78121 4.4974,0.33952 0.169949,-0.90105 0.29757,-1.73284 0.379821,-2.50166 1.056314,-1.01192 1.588482,-2.35957 1.713074,-4.17235 -0.804435,-0.44008 -1.556108,-0.8185 -2.261877,-1.1343 -0.635972,-1.31732 -1.753505,-2.24001 -3.439067,-2.91869 z" style="fill:#00c002;fill-opacity:1;stroke:#005c01;stroke-width:1.00001;stroke-dasharray:none;stroke-opacity:1"
style="fill:#804600;fill-opacity:0.701315;stroke:none;stroke-width:1.3;stroke-dasharray:none;stroke-opacity:0.497152" id="path30-7-7-7-0-9"
id="path113" /></g></g></svg> cx="-213.94203"
cy="831.42212"
rx="15.000077"
ry="25.00013"
transform="matrix(-1,5.1823562e-6,-5.1823562e-6,1,0,0)" /><path
style="fill:#008f01;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 213.63731,813.23745 c -0.71301,-15.33 -8.97927,-0.53492 -12.11399,4.16273 -6.2641,9.38728 -0.46562,27.18322 0.66809,29.84078 2.16384,5.07233 9.57501,9.49461 9.57501,9.49461 l 1.73057,0.14033 c -0.22395,-14.5383 0.81608,-29.10959 0.14032,-43.63845 z"
id="path45-1-7"
sodipodi:nodetypes="sssccs" /><g
id="g37-9"
inkscape:path-effect="#path-effect41-8"><path
style="fill:none;stroke:#005c01;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 213.93749,856.03808 c 0,0 2e-5,-42.87351 2e-5,-42.87351"
id="path36-6-2"
inkscape:original-d="m 213.93749,856.03808 2e-5,-42.87351" /><path
style="fill:none;stroke:#005c01;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 222.85539,838.83313 c -1.78358,0 -7.13431,8.99583 -8.91789,8.99583 -1.78358,0 -7.13431,-8.99583 -8.91789,-8.99583"
id="path37-2-6-1-5-0"
sodipodi:nodetypes="ccc"
inkscape:original-d="m 222.85539,838.83313 -8.91789,8.99583 -8.91789,-8.99583" /><path
style="fill:none;stroke:#005c01;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 222.85539,830.04627 c -1.78358,0 -7.13431,8.99583 -8.91789,8.99583 -1.78358,0 -7.13431,-8.99583 -8.91789,-8.99583"
id="path37-2-6-4-6-6"
sodipodi:nodetypes="ccc"
inkscape:original-d="m 222.85539,830.04627 -8.91789,8.99583 -8.91789,-8.99583" /><path
style="fill:none;stroke:#005c01;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 222.85539,821.2594 c -1.78358,0 -7.13431,8.99583 -8.91789,8.99583 -1.78358,0 -7.13431,-8.99583 -8.91789,-8.99583"
id="path37-2-6-10-9-8"
sodipodi:nodetypes="ccc"
inkscape:original-d="m 222.85539,821.2594 -8.91789,8.99583 -8.91789,-8.99583" /><path
style="fill:none;stroke:#005c01;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 220.85563,815.47302 c -1.38363,0 -5.5345,5.99535 -6.91813,5.99535 -1.38357,0 -5.5343,-5.99535 -6.91787,-5.99535"
id="path37-2-6-6-3-9"
sodipodi:nodetypes="ccc"
inkscape:original-d="m 220.85563,815.47302 -6.91813,5.99535 -6.91787,-5.99535" /></g><ellipse
style="fill:none;fill-opacity:1;stroke:#005c01;stroke-width:1;stroke-dasharray:none;stroke-opacity:1"
id="path30-7-7-4"
cx="213.9375"
cy="831.42084"
rx="15"
ry="25"
transform="translate(-9.3315134e-6)" /></g><g
id="g63"
inkscape:export-filename="apprentice.svg"
inkscape:export-xdpi="900.08"
inkscape:export-ydpi="900.08"><path
id="rect33-6"
style="fill:#005c01;fill-opacity:1;stroke:#005c01;stroke-width:1;stroke-linecap:round;stroke-dasharray:none;stroke-opacity:1"
d="m 57.136103,850.95756 -1.50032,-0.57183 -1.84004,1.853 3.34036,2.084 1.2e-4,13.42718 c 0,0 0.4451,1.28623 1.346,1.28623 0.83175,0 1.346,-1.28623 1.346,-1.28623 l -2.9e-4,-13.42718 2.71198,-2.084 -1.37887,-1.853 -1.33311,0.57183 z"
sodipodi:nodetypes="cccccscccccc" /><path
d="m 60.527143,867.65428 c 0,0 -1.28908,1.47478 -2.12083,1.47478 -0.9009,0 -1.99075,-1.42264 -1.99075,-1.42264 -4.65194,0.59664 -5.92716,3.58427 -8.28253,4.70926 -2.52584,1.20643 -11.53768,1.98812 -11.53779,3.7052 10e-6,2.41107 9.83202,4.36562 21.96041,4.36562 12.12839,0 21.96041,-1.95455 21.96042,-4.36562 10e-6,-1.68893 -9.37115,-3.14116 -11.61634,-3.7052 -2.57054,-0.64577 -3.5869,-4.17719 -8.37259,-4.7614 z"
style="fill:#8f4c00;stroke:#5c3100;stroke-linecap:round"
id="path57-3"
sodipodi:nodetypes="cscscsssc" /><g
id="g42-4-4"
transform="matrix(0.46393276,0.46393757,-0.46393276,0.46393757,360.22685,355.15504)"
style="stroke-width:1.52415;stroke-dasharray:none"><ellipse
style="fill:#00c002;fill-opacity:1;stroke:#005c01;stroke-width:1.52416;stroke-dasharray:none;stroke-opacity:1"
id="path30-7-7-7-0-8"
cx="640.62866"
cy="431.71231"
rx="15.000077"
ry="25.00013"
transform="matrix(0.99999481,0,0,0.99999481,-426.68795,399.71083)" /><path
style="fill:#008f01;fill-opacity:1;stroke:none;stroke-width:1.52415;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 214.03823,813.19332 c 0.71309,-15.32992 8.97923,-0.53496 12.11391,4.16265 6.26402,9.3872 0.46548,27.18307 -0.66824,29.84063 -2.16386,5.07231 -9.57501,9.49461 -9.57501,9.49461 l -1.73056,0.14033 c 0.22402,-14.53822 -0.81593,-29.10943 -0.1401,-43.63822 z"
id="path45-1-1"
sodipodi:nodetypes="sssccs" /><g
id="g37-4-2"
inkscape:path-effect="#path-effect41-5-67"
style="stroke-width:1.52415;stroke-dasharray:none"><path
style="fill:none;stroke:#005c01;stroke-width:1.52415;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 213.93749,856.03808 c 0,0 2e-5,-42.87351 2e-5,-42.87351"
id="path36-6-4-9"
inkscape:original-d="m 213.93749,856.03808 2e-5,-42.87351" /><path
style="fill:none;stroke:#005c01;stroke-width:1.52415;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 222.85539,838.83313 c -1.78358,0 -7.13431,8.99583 -8.91789,8.99583 -1.78358,0 -7.13431,-8.99583 -8.91789,-8.99583"
id="path37-2-6-1-5-3-3"
sodipodi:nodetypes="ccc"
inkscape:original-d="m 222.85539,838.83313 -8.91789,8.99583 -8.91789,-8.99583" /><path
style="fill:none;stroke:#005c01;stroke-width:1.52415;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 222.85539,830.04627 c -1.78358,0 -7.13431,8.99583 -8.91789,8.99583 -1.78358,0 -7.13431,-8.99583 -8.91789,-8.99583"
id="path37-2-6-4-6-0-9"
sodipodi:nodetypes="ccc"
inkscape:original-d="m 222.85539,830.04627 -8.91789,8.99583 -8.91789,-8.99583" /><path
style="fill:none;stroke:#005c01;stroke-width:1.52415;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 222.85539,821.2594 c -1.78358,0 -7.13431,8.99583 -8.91789,8.99583 -1.78358,0 -7.13431,-8.99583 -8.91789,-8.99583"
id="path37-2-6-10-9-7-0"
sodipodi:nodetypes="ccc"
inkscape:original-d="m 222.85539,821.2594 -8.91789,8.99583 -8.91789,-8.99583" /><path
style="fill:none;stroke:#005c01;stroke-width:1.52415;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 220.85563,815.47302 c -1.38363,0 -5.5345,5.99535 -6.91813,5.99535 -1.38357,0 -5.5343,-5.99535 -6.91787,-5.99535"
id="path37-2-6-6-3-8-8"
sodipodi:nodetypes="ccc"
inkscape:original-d="m 220.85563,815.47302 -6.91813,5.99535 -6.91787,-5.99535" /></g><ellipse
style="fill:none;fill-opacity:1;stroke:#005c01;stroke-width:1.52415;stroke-dasharray:none;stroke-opacity:1"
id="path30-7-7-7-8"
cx="213.9375"
cy="831.42084"
rx="15"
ry="25"
transform="translate(7.5790061e-6)" /></g><g
id="g42-1-5"
transform="matrix(0.46393276,-0.46393276,0.46393276,0.46393276,-441.6633,553.4829)"
style="stroke-width:1.52416;stroke-dasharray:none"><ellipse
style="fill:#00c002;fill-opacity:1;stroke:#005c01;stroke-width:1.52416;stroke-dasharray:none;stroke-opacity:1"
id="path30-7-7-7-0-9-0"
cx="-213.94203"
cy="831.42212"
rx="15.000077"
ry="25.00013"
transform="matrix(-1,5.1823562e-6,-5.1823562e-6,1,0,0)" /><path
style="fill:#008f01;fill-opacity:1;stroke:none;stroke-width:1.52416;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 213.63731,813.23745 c -0.71301,-15.33 -8.97927,-0.53492 -12.11399,4.16273 -6.2641,9.38728 -0.46562,27.18322 0.66809,29.84078 2.16384,5.07233 9.57501,9.49461 9.57501,9.49461 l 1.73057,0.14033 c -0.22395,-14.5383 0.81608,-29.10959 0.14032,-43.63845 z"
id="path45-1-7-9"
sodipodi:nodetypes="sssccs" /><g
id="g37-9-6"
inkscape:path-effect="#path-effect41-8-3"
style="stroke-width:1.52416;stroke-dasharray:none"><path
style="fill:none;stroke:#005c01;stroke-width:1.52416;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 213.93749,856.03808 c 0,0 2e-5,-42.87351 2e-5,-42.87351"
id="path36-6-2-3"
inkscape:original-d="m 213.93749,856.03808 2e-5,-42.87351" /><path
style="fill:none;stroke:#005c01;stroke-width:1.52416;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 222.85539,838.83313 c -1.78358,0 -7.13431,8.99583 -8.91789,8.99583 -1.78358,0 -7.13431,-8.99583 -8.91789,-8.99583"
id="path37-2-6-1-5-0-8"
sodipodi:nodetypes="ccc"
inkscape:original-d="m 222.85539,838.83313 -8.91789,8.99583 -8.91789,-8.99583" /><path
style="fill:none;stroke:#005c01;stroke-width:1.52416;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 222.85539,830.04627 c -1.78358,0 -7.13431,8.99583 -8.91789,8.99583 -1.78358,0 -7.13431,-8.99583 -8.91789,-8.99583"
id="path37-2-6-4-6-6-5"
sodipodi:nodetypes="ccc"
inkscape:original-d="m 222.85539,830.04627 -8.91789,8.99583 -8.91789,-8.99583" /><path
style="fill:none;stroke:#005c01;stroke-width:1.52416;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 222.85539,821.2594 c -1.78358,0 -7.13431,8.99583 -8.91789,8.99583 -1.78358,0 -7.13431,-8.99583 -8.91789,-8.99583"
id="path37-2-6-10-9-8-6"
sodipodi:nodetypes="ccc"
inkscape:original-d="m 222.85539,821.2594 -8.91789,8.99583 -8.91789,-8.99583" /><path
style="fill:none;stroke:#005c01;stroke-width:1.52416;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 220.85563,815.47302 c -1.38363,0 -5.5345,5.99535 -6.91813,5.99535 -1.38357,0 -5.5343,-5.99535 -6.91787,-5.99535"
id="path37-2-6-6-3-9-1"
sodipodi:nodetypes="ccc"
inkscape:original-d="m 220.85563,815.47302 -6.91813,5.99535 -6.91787,-5.99535" /></g><ellipse
style="fill:none;fill-opacity:1;stroke:#005c01;stroke-width:1.52416;stroke-dasharray:none;stroke-opacity:1"
id="path30-7-7-4-1"
cx="213.9375"
cy="831.42084"
rx="15"
ry="25"
transform="translate(-9.3315134e-6)" /></g></g></g><g
id="g100-5"
transform="matrix(1.771561,0,0,1.771561,-126.11368,-663.87619)"><path
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-dasharray:none;stroke-opacity:1"
id="path89-4-9"
sodipodi:arc-type="arc"
sodipodi:type="arc"
sodipodi:cx="170.66406"
sodipodi:cy="-843.37482"
sodipodi:rx="2"
sodipodi:ry="2"
sodipodi:start="0"
sodipodi:end="3.1415927"
d="m 172.66406,-843.37482 a 2,2 0 0 1 -1,1.73205 2,2 0 0 1 -2,0 2,2 0 0 1 -1,-1.73205"
sodipodi:open="true"
transform="scale(1,-1)" /><g
id="g97-4"><circle
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-dasharray:none;stroke-opacity:1"
id="path90-6"
cx="169.00261"
cy="839.49762"
r="1" /><circle
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-dasharray:none;stroke-opacity:1"
id="path90-9-9"
cx="172.32553"
cy="839.49762"
r="1" /></g></g></g></svg>

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -3,8 +3,8 @@
<svg <svg
width="81.560997mm" width="81.560997mm"
height="79.98938mm" height="79.989365mm"
viewBox="0 0 81.560997 79.98938" viewBox="0 0 81.560997 79.989365"
version="1.1" version="1.1"
id="svg1" id="svg1"
xml:space="preserve" xml:space="preserve"
@ -13,20 +13,21 @@
id="defs1" /><g id="defs1" /><g
id="layer4" id="layer4"
transform="translate(-50.121599,-596.91049)"><g transform="translate(-50.121599,-596.91049)"><g
id="g9"><rect id="g9"
style="fill:#3c34ff;fill-opacity:1;stroke:#0f07ff;stroke-width:1.561;stroke-dasharray:none;stroke-opacity:1" style="stroke:#000000;stroke-opacity:1"><rect
style="fill:#3c34ff;fill-opacity:1;stroke:#000000;stroke-width:1.561;stroke-dasharray:none;stroke-opacity:1"
id="rect6" id="rect6"
width="80" width="80"
height="20" height="20"
x="50.902103" x="50.902103"
y="613.53406" /><rect y="613.53406" /><rect
style="fill:#3c34ff;fill-opacity:1;stroke:#0f07ff;stroke-width:1.561;stroke-dasharray:none;stroke-opacity:1" style="fill:#3c34ff;fill-opacity:1;stroke:#000000;stroke-width:1.561;stroke-dasharray:none;stroke-opacity:1"
id="rect6-1" id="rect6-1"
width="80" width="80"
height="20" height="20"
x="50.902103" x="50.902103"
y="640.27625" /></g><rect y="640.27625" /></g><rect
style="fill:#ff0707;fill-opacity:1;stroke:#c10000;stroke-width:1.561;stroke-dasharray:none;stroke-opacity:1" style="fill:#ff0707;fill-opacity:1;stroke:#000000;stroke-width:1.561;stroke-dasharray:none;stroke-opacity:1"
id="rect6-3" id="rect6-3"
width="100" width="100"
height="10" height="10"

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -2,94 +2,26 @@
<!-- Created with Inkscape (http://www.inkscape.org/) --> <!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg <svg
width="22.945572mm" width="22.945564mm"
height="28.24629mm" height="28.246271mm"
viewBox="0 0 22.945572 28.24629" viewBox="0 0 22.945564 28.246271"
version="1.1" version="1.1"
id="svg1" id="svg1"
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
sodipodi:docname="icons.svg"
xml:space="preserve" 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="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview xmlns:svg="http://www.w3.org/2000/svg"><defs
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 id="defs1" /><g
inkscape:groupmode="layer"
id="layer4" id="layer4"
inkscape:label="Layer 4" transform="translate(-403.75417,-318.29373)"><g
transform="translate(-84.29421,-256.51757)"><g id="g28"><path
id="g17"><path id="path13-2-7"
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" 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" d="m 415.2262,319.4142 -4.65243,14.9748 c 0,0 -3.85341,-2.83967 -6.44147,-7.23625 -0.2812,4.36457 0.45945,18.75999 11.0939,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.89519,20.4246 h 4.97644 a 2.48832,2.48832 0 0 1 -2.48822,2.48822 2.48832,2.48832 0 0 1 -2.48822,-2.48822 z m 8.81548,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" /><path
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" style="fill:#ff0707;fill-opacity:0.796663;stroke:#ffbb33;stroke-width:0.665001;stroke-dasharray:none;stroke-opacity:1"
id="path14" id="path14-5"
inkscape:flatsided="false" transform="translate(345.42786,67.661219)"
sodipodi:sides="3" 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" /><path
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" style="fill:#ff0707;fill-opacity:0.796663;stroke:#ffbb33;stroke-width:0.665001;stroke-dasharray:none;stroke-opacity:1"
id="path15" id="path15-9"
inkscape:flatsided="false" transform="translate(348.34768,68.803695)"
sodipodi:sides="4" 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" /></g></g></svg>
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>

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -411,6 +411,7 @@ button {
border: 3px solid rgba(0, 0, 0, 0.4); border: 3px solid rgba(0, 0, 0, 0.4);
// min-width: 20%; // min-width: 20%;
flex-shrink: 1; flex-shrink: 1;
flex-grow: 1;
.headline { .headline {
display: flex; display: flex;
@ -663,19 +664,22 @@ clients {
justify-content: space-evenly; justify-content: space-evenly;
color: black; color: black;
align-items: center; align-items: center;
align-content: center;
gap: 10px; gap: 10px;
max-height: 100vh;
} }
.role-reveal-card { .role-reveal-card {
justify-content: center; justify-content: center;
min-width: 5cm; // min-width: 5cm;
flex-grow: 1;
display: flex; display: flex;
align-items: center; align-items: center;
align-content: center; align-content: center;
flex-direction: column; flex-direction: column;
gap: 10px; gap: 10px;
padding: 1cm; padding: 20px;
border: 1px solid $wolves_color; border: 1px solid $wolves_color;
background-color: color.change($wolves_color, $alpha: 0.1); background-color: color.change($wolves_color, $alpha: 0.1);
min-width: 100px; min-width: 100px;
@ -1436,6 +1440,23 @@ input {
} }
} }
li.change,
li.choice {
width: fit-content;
&:hover {
.li-icon {
filter: brightness(5000%);
}
backdrop-filter: invert(15%);
}
}
.li-icon {
filter: grayscale(100%) brightness(150%);
}
.icon { .icon {
width: 32px; width: 32px;
height: 32px; height: 32px;
@ -1853,6 +1874,19 @@ input {
} }
} }
.info-icon-list-grow {
padding: 20px 0 20px 0;
flex-grow: 1;
width: 100%;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
img {
flex-grow: 1;
}
}
.info-player-list { .info-player-list {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -1862,7 +1896,8 @@ input {
justify-content: center; justify-content: center;
gap: 10px; gap: 10px;
&.masons { &.masons,
&.large {
font-size: 2rem; font-size: 2rem;
} }
} }
@ -1870,13 +1905,15 @@ input {
.two-column { .two-column {
display: grid; display: grid;
grid-template-columns: 3fr 2fr; grid-template-columns: 3fr 2fr;
height: 100%;
} }
.seer-check { .seer-check {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
flex-wrap: nowrap; flex-wrap: nowrap;
zoom: 90%; height: 100%;
justify-content: space-around;
} }
.role-title-span { .role-title-span {
@ -1923,6 +1960,7 @@ input {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
gap: 10px;
} }
.add-player { .add-player {
@ -2005,10 +2043,28 @@ input {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
flex-wrap: nowrap; flex-wrap: nowrap;
justify-content: center; justify-content: space-around;
align-items: center; align-items: center;
gap: 10px;
height: var(--information-height); height: var(--information-height);
h1,
h2,
h3,
h4,
h5,
h6 {
margin: 0;
&:first-child {
padding-top: 10px;
}
&:last-child {
padding-bottom: 10px;
}
}
} }
.setup-aura { .setup-aura {
@ -2042,3 +2098,11 @@ input {
flex-shrink: 1; flex-shrink: 1;
} }
} }
.guardian-select {
max-height: 100vh;
}
.story-text {
font-size: 1.7em;
}

View File

@ -66,9 +66,16 @@ pub fn Prompt(props: &ActionPromptProps) -> Html {
if let Some(page) = props.pages.get(props.page_idx).map(|page| { if let Some(page) = props.pages.get(props.page_idx).map(|page| {
let next = props.big_screen.not().then(|| { let next = props.big_screen.not().then(|| {
let send = props.on_complete.clone(); let send = props.on_complete.clone();
let page_idx = props.page_idx;
let pages_total = props.pages.len();
let prompt = props.prompt.clone();
let on_page_next = Callback::from(move |_| { let on_page_next = Callback::from(move |_| {
send.emit(HostMessage::InGame(HostGameMessage::Night( send.emit(HostMessage::InGame(HostGameMessage::Night(
HostNightMessage::NextPage, if page_idx + 1 >= pages_total && !prompt.interactive() {
HostNightMessage::ActionResponse(ActionResponse::ContinueToResult)
} else {
HostNightMessage::NextPage
},
))) )))
}); });
html! { html! {
@ -152,41 +159,29 @@ pub fn Prompt(props: &ActionPromptProps) -> Html {
ActionPrompt::RoleChange { .. } ActionPrompt::RoleChange { .. }
| ActionPrompt::ElderReveal { .. } | ActionPrompt::ElderReveal { .. }
| ActionPrompt::Insomniac { .. } => { | ActionPrompt::Insomniac { .. } => {
if let Some(cb) = continue_callback { if !props.big_screen {
cb.emit(()); props
.on_complete
.emit(HostMessage::InGame(HostGameMessage::Night(
HostNightMessage::ActionResponse(ActionResponse::ContinueToResult),
)));
} }
return html! {}; return html! {
<CoverOfDarkness message={"oops".to_string()} />
};
} }
ActionPrompt::Guardian { ActionPrompt::Guardian {
character_id, character_id,
previous,
living_players, living_players,
marked, 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::<Box<[CharacterId]>>(); let marked = marked.iter().cloned().collect::<Box<[CharacterId]>>();
return html! { return html! {
<div> <div class="guardian-select">
{identity_html(props, Some(character_id))} {identity_html(props, Some(character_id))}
<h2>{"guardian"}</h2>
{last_protect}
<TargetPicker <TargetPicker
targets={living_players.clone()} targets={living_players.clone()}
marked={marked} marked={marked}

View File

@ -12,6 +12,7 @@
// //
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
use convert_case::{Case, Casing};
use werewolves_proto::{ use werewolves_proto::{
message::{CharacterIdentity, PublicIdentity}, message::{CharacterIdentity, PublicIdentity},
role::RoleTitle, role::RoleTitle,
@ -42,7 +43,7 @@ pub fn WolvesIntro(props: &WolvesIntroProps) -> Html {
{ {
props.wolves.iter().map(|w| html!{ props.wolves.iter().map(|w| html!{
<div class="character wolves faint"> <div class="character wolves faint">
<p class="role">{w.1.to_string()}</p> <p class="role yellow">{w.1.to_string().to_case(Case::Title)}</p>
<Identity ident={Into::<PublicIdentity>::into(&w.0)} /> <Identity ident={Into::<PublicIdentity>::into(&w.0)} />
</div> </div>
}).collect::<Html>() }).collect::<Html>()

View File

@ -124,6 +124,8 @@ pub struct IconProps {
pub inactive: bool, pub inactive: bool,
#[prop_or_default] #[prop_or_default]
pub icon_type: IconType, pub icon_type: IconType,
#[prop_or_default]
pub classes: Classes,
} }
#[function_component] #[function_component]
pub fn Icon( pub fn Icon(
@ -131,12 +133,13 @@ pub fn Icon(
source, source,
inactive, inactive,
icon_type, icon_type,
classes,
}: &IconProps, }: &IconProps,
) -> Html { ) -> Html {
html! { html! {
<img <img
src={source.source()} src={source.source()}
class={classes!(source.class(), icon_type.class(), inactive.then_some("inactive"))} class={classes!(source.class(), icon_type.class(), inactive.then_some("inactive"), classes.clone())}
/> />
} }
} }

View File

@ -77,9 +77,7 @@ pub fn Story(StoryProps { story }: &StoryProps) -> Html {
.collect::<HashMap<_, _>>())); .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 =
html! {<span>{"no one was executed"}</span>}
} else {
day_changes day_changes
.iter() .iter()
.map(|c| match c { .map(|c| match c {
@ -88,15 +86,12 @@ pub fn Story(StoryProps { story }: &StoryProps) -> Html {
.filter_map(|c| story.starting_village.character_by_id(c).ok()) .filter_map(|c| story.starting_village.character_by_id(c).ok())
.map(|c| { .map(|c| {
html! { html! {
// <span>
<CharacterCard faint=true char={c.clone()}/> <CharacterCard faint=true char={c.clone()}/>
// </span>
} }
}) })
.collect::<Html>() .collect::<Html>();
};
Some(html! { day_changes.is_empty().not().then_some(html! {
<div class="day"> <div class="day">
<h3>{"village executed"}</h3> <h3>{"village executed"}</h3>
<div class="executed"> <div class="executed">
@ -117,16 +112,19 @@ pub fn Story(StoryProps { story }: &StoryProps) -> Html {
.collect::<Html>(); .collect::<Html>();
let changes = details let changes = details
.changes .changes
.iter() .iter()
.map(|c| { .map(|c| {
html! { html! {
<li> <li class="change">
<StoryNightChange change={c.clone()} characters={characters.clone()}/> <StoryNightChange
</li> change={c.clone()}
} characters={characters.clone()}
}) />
.collect::<Html>(); </li>
}
})
.collect::<Html>();
html! { html! {
<div class="night"> <div class="night">
@ -174,7 +172,6 @@ struct StoryNightChangeProps {
#[function_component] #[function_component]
fn StoryNightChange(StoryNightChangeProps { change, characters }: &StoryNightChangeProps) -> Html { fn StoryNightChange(StoryNightChangeProps { change, characters }: &StoryNightChangeProps) -> Html {
match change { match change {
NightChange::LostAura { character, aura } => characters.get(character).map(|character| html!{ NightChange::LostAura { character, aura } => characters.get(character).map(|character| html!{
<> <>
<CharacterCard faint=true char={character.clone()}/> <CharacterCard faint=true char={character.clone()}/>
@ -187,9 +184,9 @@ fn StoryNightChange(StoryNightChangeProps { change, characters }: &StoryNightCha
html!{ html!{
<> <>
<CharacterCard faint=true char={target.clone()}/> <CharacterCard faint=true char={target.clone()}/>
{"gained the"} <span class="story-text">{"gained the"}</span>
<AuraSpan aura={aura.title()}/> <AuraSpan aura={aura.title()}/>
{"aura from"} <span class="story-text">{"aura from"}</span>
<CharacterCard faint=true char={source.clone()}/> <CharacterCard faint=true char={source.clone()}/>
</> </>
} }
@ -203,26 +200,29 @@ fn StoryNightChange(StoryNightChangeProps { change, characters }: &StoryNightCha
html! { html! {
<> <>
<CharacterCard faint=true char={char.clone()}/> <CharacterCard faint=true char={char.clone()}/>
{"is now"} <span class="story-text">{"is now"}</span>
<CharacterCard faint=true char={new_char.clone()}/> <CharacterCard faint=true char={new_char.clone()}/>
</> </>
} }
}) })
.unwrap_or_default(), .unwrap_or_default(),
NightChange::Kill { target, died_to } => characters NightChange::Kill { target, died_to } => {
characters
.get(target) .get(target)
.map(|target| { .map(|target| {
html! { html! {
<> <>
<Icon source={IconSource::Skull} icon_type={IconType::Small}/> <Icon source={IconSource::Skull} icon_type={IconType::Small}/>
<CharacterCard faint=true char={target.clone()}/> <CharacterCard faint=true char={target.clone()}/>
{"died to"} <span class="story-text">{"died to"}</span>
<DiedToSpan died_to={died_to.title()}/> <DiedToSpan died_to={died_to.title()}/>
</> </>
} }
}) })
.unwrap_or_default(), .unwrap_or_default()
},
NightChange::RoleBlock { source, target, .. } => characters NightChange::RoleBlock { source, target, .. } => characters
.get(source) .get(source)
.and_then(|s| characters.get(target).map(|t| (s, t))) .and_then(|s| characters.get(target).map(|t| (s, t)))
@ -230,7 +230,7 @@ fn StoryNightChange(StoryNightChangeProps { change, characters }: &StoryNightCha
html! { html! {
<> <>
<CharacterCard faint=true char={source.clone()}/> <CharacterCard faint=true char={source.clone()}/>
{"role blocked"} <span class="story-text">{"role blocked"}</span>
<CharacterCard faint=true char={target.clone()}/> <CharacterCard faint=true char={target.clone()}/>
</> </>
} }
@ -243,7 +243,7 @@ fn StoryNightChange(StoryNightChangeProps { change, characters }: &StoryNightCha
html! { html! {
<> <>
<CharacterCard faint=true char={source.clone()}/> <CharacterCard faint=true char={source.clone()}/>
{"shapeshifted into"} <span class="story-text">{"shapeshifted into"}</span>
<CharacterCard faint=true char={into.clone()}/> <CharacterCard faint=true char={into.clone()}/>
</> </>
} }
@ -256,7 +256,7 @@ fn StoryNightChange(StoryNightChangeProps { change, characters }: &StoryNightCha
html! { html! {
<> <>
<CharacterCard faint=true char={elder.clone()}/> <CharacterCard faint=true char={elder.clone()}/>
{"learned they are the Elder"} <span class="story-text">{"learned they are the Elder"}</span>
</> </>
} }
}) })
@ -268,9 +268,9 @@ fn StoryNightChange(StoryNightChangeProps { change, characters }: &StoryNightCha
html! { html! {
<> <>
<CharacterCard faint=true char={empath.clone()}/> <CharacterCard faint=true char={empath.clone()}/>
{"found the scapegoat in"} <span class="story-text">{"found the scapegoat in"}</span>
<CharacterCard faint=true char={scapegoat.clone()}/> <CharacterCard faint=true char={scapegoat.clone()}/>
{"and took on their curse"} <span class="story-text">{"and took on their curse"}</span>
</> </>
} }
}) })
@ -292,28 +292,28 @@ struct StoryNightResultProps {
fn StoryNightResult(StoryNightResultProps { result, characters }: &StoryNightResultProps) -> Html { fn StoryNightResult(StoryNightResultProps { result, characters }: &StoryNightResultProps) -> Html {
match result { match result {
StoryActionResult::ShiftFailed => html!{ StoryActionResult::ShiftFailed => html!{
<span>{"but it failed"}</span> <span class="story-text">{"but it failed"}</span>
}, },
StoryActionResult::Drunk => html! { StoryActionResult::Drunk => html! {
<span> <>
{"but got "} <span class="story-text">{"but got "}</span>
<AuraSpan aura={AuraTitle::Drunk}/> <AuraSpan aura={AuraTitle::Drunk}/>
{" instead"} <span class="story-text">{" instead"}</span>
</span> </>
}, },
StoryActionResult::BeholderSawEverything => html!{ StoryActionResult::BeholderSawEverything => html!{
<span>{"and saw everything 👁️"}</span> <span class="story-text">{"and saw everything 👁️"}</span>
}, },
StoryActionResult::BeholderSawNothing => html!{ StoryActionResult::BeholderSawNothing => html!{
<span>{"but saw nothing"}</span> <span class="story-text">{"but saw nothing"}</span>
}, },
StoryActionResult::RoleBlocked => html! { StoryActionResult::RoleBlocked => html! {
<span>{"but was role blocked"}</span> <span class="story-text">{"but was role blocked"}</span>
}, },
StoryActionResult::Seer(alignment) => { StoryActionResult::Seer(alignment) => {
html! { html! {
<span> <span>
<span>{"and saw"}</span> <span class="story-text">{"and saw"}</span>
<AlignmentSpan alignment={*alignment}/> <AlignmentSpan alignment={*alignment}/>
</span> </span>
} }
@ -321,25 +321,25 @@ fn StoryNightResult(StoryNightResultProps { result, characters }: &StoryNightRes
StoryActionResult::PowerSeer { powerful } => { StoryActionResult::PowerSeer { powerful } => {
html! { html! {
<span> <span>
<span>{"and discovered they are"}</span> <span class="story-text">{"and discovered they are"}</span>
<PowerfulSpan powerful={*powerful}/> <PowerfulSpan powerful={*powerful}/>
</span> </span>
} }
} }
StoryActionResult::Adjudicator { killer } => html! { StoryActionResult::Adjudicator { killer } => html! {
<span> <span>
<span>{"and saw"}</span> <span class="story-text">{"and saw"}</span>
<KillerSpan killer={*killer}/> <KillerSpan killer={*killer}/>
</span> </span>
}, },
StoryActionResult::Arcanist(same) => html! { StoryActionResult::Arcanist(same) => html! {
<span> <span>
<span>{"and saw"}</span> <span class="story-text">{"and saw"}</span>
<AlignmentComparisonSpan comparison={*same}/> <AlignmentComparisonSpan comparison={*same}/>
</span> </span>
}, },
StoryActionResult::GraveDigger(None) => html! { StoryActionResult::GraveDigger(None) => html! {
<span> <span class="story-text">
{"found an empty grave"} {"found an empty grave"}
</span> </span>
}, },
@ -347,7 +347,7 @@ fn StoryNightResult(StoryNightResultProps { result, characters }: &StoryNightRes
let category = Into::<SetupRole>::into(*role_title).category(); let category = Into::<SetupRole>::into(*role_title).category();
html! { html! {
<span> <span>
<span>{"found the body of a"}</span> <span class="story-text">{"found the body of a"}</span>
<CategorySpan category={category} icon={role_title.icon()}> <CategorySpan category={category} icon={role_title.icon()}>
{role_title.to_string().to_case(Case::Title)} {role_title.to_string().to_case(Case::Title)}
</CategorySpan> </CategorySpan>
@ -356,7 +356,7 @@ fn StoryNightResult(StoryNightResultProps { result, characters }: &StoryNightRes
} }
StoryActionResult::Mortician(died_to_title) => html! { StoryActionResult::Mortician(died_to_title) => html! {
<> <>
{"and found the cause of death to be"} <span class="story-text">{"and found the cause of death to be"}</span>
<DiedToSpan died_to={*died_to_title}/> <DiedToSpan died_to={*died_to_title}/>
</> </>
}, },
@ -377,7 +377,7 @@ fn StoryNightResult(StoryNightResultProps { result, characters }: &StoryNightRes
StoryActionResult::Empath { scapegoat: false } => html! { StoryActionResult::Empath { scapegoat: false } => html! {
<> <>
{"and saw that they are"} <span class="story-text">{"and saw that they are"}</span>
<span class="attribute-span faint"> <span class="attribute-span faint">
<div class="inactive"> <div class="inactive">
<Icon source={IconSource::Heart} icon_type={IconType::Small}/> <Icon source={IconSource::Heart} icon_type={IconType::Small}/>
@ -388,7 +388,7 @@ fn StoryNightResult(StoryNightResultProps { result, characters }: &StoryNightRes
}, },
StoryActionResult::Empath { scapegoat: true } => html! { StoryActionResult::Empath { scapegoat: true } => html! {
<> <>
{"and saw that they are"} <span class="story-text">{"and saw that they are"}</span>
<span class="attribute-span faint wolves"> <span class="attribute-span faint wolves">
<div> <div>
<Icon source={IconSource::Heart} icon_type={IconType::Small}/> <Icon source={IconSource::Heart} icon_type={IconType::Small}/>
@ -416,7 +416,7 @@ fn StoryNightChoice(StoryNightChoiceProps { choice, characters}: &StoryNightChoi
html! { html! {
<> <>
<CharacterCard faint=true char={char.clone()}/> <CharacterCard faint=true char={char.clone()}/>
<span>{action}</span> <span class="story-text">{action}</span>
<CharacterCard faint=true char={chosen.clone()}/> <CharacterCard faint=true char={chosen.clone()}/>
</> </>
} }
@ -438,9 +438,9 @@ fn StoryNightChoice(StoryNightChoiceProps { choice, characters}: &StoryNightChoi
html! { html! {
<> <>
<CharacterCard faint=true char={arcanist.clone()}/> <CharacterCard faint=true char={arcanist.clone()}/>
<span>{"compared"}</span> <span class="story-text">{"compared"}</span>
<CharacterCard faint=true char={chosen1.clone()}/> <CharacterCard faint=true char={chosen1.clone()}/>
<span>{"and"}</span> <span class="story-text">{"and"}</span>
<CharacterCard faint=true char={chosen2.clone()}/> <CharacterCard faint=true char={chosen2.clone()}/>
</> </>
} }
@ -458,9 +458,9 @@ fn StoryNightChoice(StoryNightChoiceProps { choice, characters}: &StoryNightChoi
html! { html! {
<> <>
<CharacterCard faint=true char={leader.clone()}/> <CharacterCard faint=true char={leader.clone()}/>
<span>{"'s masons"}</span> <span class="story-text">{"'s masons"}</span>
{masons} {masons}
<span>{"convened in secret"}</span> <span class="story-text">{"convened in secret"}</span>
</> </>
} }
}), }),
@ -511,9 +511,9 @@ fn StoryNightChoice(StoryNightChoiceProps { choice, characters}: &StoryNightChoi
html! { html! {
<> <>
<CharacterCard faint=true char={char.clone()}/> <CharacterCard faint=true char={char.clone()}/>
<span>{"invited"}</span> <span class="story-text">{"invited"}</span>
<CharacterCard faint=true char={chosen.clone()}/> <CharacterCard faint=true char={chosen.clone()}/>
<span>{"for dinner"}</span> <span class="story-text">{"for dinner"}</span>
</> </>
} }
}), }),
@ -548,7 +548,7 @@ fn StoryNightChoice(StoryNightChoiceProps { choice, characters}: &StoryNightChoi
html! { html! {
<> <>
<AlignmentSpan alignment={Alignment::Wolves}/> <AlignmentSpan alignment={Alignment::Wolves}/>
<span>{"attempted a kill on"}</span> <span class="story-text">{"attempted a kill on"}</span>
<CharacterCard faint=true char={chosen.clone()} /> <CharacterCard faint=true char={chosen.clone()} />
</> </>
} }
@ -562,7 +562,7 @@ fn StoryNightChoice(StoryNightChoiceProps { choice, characters}: &StoryNightChoi
html! { html! {
<> <>
<CharacterCard faint=true char={shifter.clone()} /> <CharacterCard faint=true char={shifter.clone()} />
<span>{"decided to shapeshift into the wolf kill target"}</span> <span class="story-text">{"decided to shapeshift into the wolf kill target"}</span>
</> </>
} }
}) })
@ -584,7 +584,7 @@ fn StoryNightChoice(StoryNightChoiceProps { choice, characters}: &StoryNightChoi
html! { html! {
<> <>
<CharacterCard faint=true char={insomniac.clone()} /> <CharacterCard faint=true char={insomniac.clone()} />
<span>{"witnessed visits from"}</span> <span class="story-text">{"witnessed visits from"}</span>
</> </>
} }
}) })
@ -598,8 +598,12 @@ fn StoryNightChoice(StoryNightChoiceProps { choice, characters}: &StoryNightChoi
choice_body choice_body
.map(|choice_body| { .map(|choice_body| {
html! { html! {
<li> <li class="choice">
<Icon source={IconSource::ListItem} icon_type={IconType::Small}/> <Icon
source={IconSource::ListItem}
icon_type={IconType::Small}
classes={classes!("li-icon")}
/>
{choice_body} {choice_body}
{result} {result}
</li> </li>

View File

@ -11,9 +11,9 @@ pub fn DrunkPage() -> Html {
<h1 class="drunk">{"DRUNK"}</h1> <h1 class="drunk">{"DRUNK"}</h1>
<div class="information drunk faint"> <div class="information drunk faint">
<h2>{"YOU GOT DRUNK INSTEAD"}</h2> <h2>{"YOU GOT DRUNK INSTEAD"}</h2>
<h4 class="icons"> <div class="info-icon-grow">
<Icon source={icon} icon_type={IconType::Informational}/> <Icon source={icon}/>
</h4> </div>
<h3 class="yellow">{"YOUR NIGHT ACTION DID NOT TAKE PLACE"}</h3> <h3 class="yellow">{"YOUR NIGHT ACTION DID NOT TAKE PLACE"}</h3>
</div> </div>
</div> </div>

View File

@ -12,8 +12,6 @@
// //
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
use core::ops::Not;
use werewolves_proto::role::Killer; use werewolves_proto::role::Killer;
use yew::prelude::*; use yew::prelude::*;
@ -26,10 +24,9 @@ pub fn AdjudicatorPage1() -> Html {
<h1 class="defensive">{"ADJUDICATOR"}</h1> <h1 class="defensive">{"ADJUDICATOR"}</h1>
<div class="information defensive faint"> <div class="information defensive faint">
<h2>{"PICK A PLAYER"}</h2> <h2>{"PICK A PLAYER"}</h2>
<h4 class="icons"> <div class="info-icon-grow">
<Icon source={IconSource::Killer} icon_type={IconType::Informational}/> <Icon source={IconSource::Killer}/>
<Icon source={IconSource::Killer} icon_type={IconType::Informational} inactive={true}/> </div>
</h4>
<h3 class="yellow">{"YOU WILL CHECK IF THEY APPEAR AS A KILLER"}</h3> <h3 class="yellow">{"YOU WILL CHECK IF THEY APPEAR AS A KILLER"}</h3>
</div> </div>
</div> </div>
@ -51,13 +48,11 @@ pub fn AdjudicatorResult(AdjudicatorResultProps { killer }: &AdjudicatorResultPr
Killer::Killer => html! { Killer::Killer => html! {
<Icon <Icon
source={IconSource::Killer} source={IconSource::Killer}
icon_type={IconType::Informational}
/> />
}, },
Killer::NotKiller => html! { Killer::NotKiller => html! {
<Icon <Icon
source={IconSource::RedX} source={IconSource::RedX}
icon_type={IconType::Informational}
/> />
}, },
}; };
@ -66,7 +61,7 @@ pub fn AdjudicatorResult(AdjudicatorResultProps { killer }: &AdjudicatorResultPr
<h1 class="defensive">{"ADJUDICATOR"}</h1> <h1 class="defensive">{"ADJUDICATOR"}</h1>
<div class="information defensive faint"> <div class="information defensive faint">
<h2>{"YOUR TARGET"}</h2> <h2>{"YOUR TARGET"}</h2>
<h4>{icon}</h4> <div class="info-icon-grow">{icon}</div>
<h3 class="yellow">{text}</h3> <h3 class="yellow">{text}</h3>
</div> </div>
</div> </div>

View File

@ -25,10 +25,10 @@ pub fn AlphaWolfPage1() -> Html {
<span class="yellow">{"ONCE PER GAME"}</span> <span class="yellow">{"ONCE PER GAME"}</span>
{" KILL ABILITY"} {" KILL ABILITY"}
</h2> </h2>
<h3 class="yellow"> <h2>
{"POINT AT YOUR TARGET "} {"POINT AT YOUR TARGET "}
{"OR GO BACK TO SLEEP"} {"OR GO BACK TO SLEEP"}
</h3> </h2>
</div> </div>
</div> </div>
} }

View File

@ -49,22 +49,12 @@ pub fn ArcanistResult(ArcanistResultProps { alignment_eq }: &ArcanistResultProps
}; };
let icons = match alignment_eq { let icons = match alignment_eq {
AlignmentEq::Same => html! { AlignmentEq::Same => html! {
<> <Icon source={IconSource::Equal} />
// <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}/>
<Icon source={IconSource::Equal} icon_type={IconType::Informational} />
</>
}, },
AlignmentEq::Different => html! { AlignmentEq::Different => html! {
<> <>
<Icon source={IconSource::Village} icon_type={IconType::Informational}/> <Icon source={IconSource::Village} />
<Icon source={IconSource::Wolves} icon_type={IconType::Informational}/> <Icon source={IconSource::Wolves} />
// {"OR"}
// <Icon source={IconSource::Wolves} icon_type={IconType::Informational}/>
// <Icon source={IconSource::Village} icon_type={IconType::Informational}/>
</> </>
}, },
}; };
@ -73,9 +63,9 @@ pub fn ArcanistResult(ArcanistResultProps { alignment_eq }: &ArcanistResultProps
<h1 class="intel">{"ARCANIST"}</h1> <h1 class="intel">{"ARCANIST"}</h1>
<div class="information intel faint"> <div class="information intel faint">
<h2>{"YOUR TARGETS APPEAR AS"}</h2> <h2>{"YOUR TARGETS APPEAR AS"}</h2>
<h4 class="icons"> <div class="info-icon-list-grow">
{icons} {icons}
</h4> </div>
<h1 class="yellow">{text}</h1> <h1 class="yellow">{text}</h1>
</div> </div>
</div> </div>

View File

@ -24,9 +24,8 @@ pub fn BloodletterPage1() -> Html {
<div class="information wolves faint"> <div class="information wolves faint">
<h2>{"PICK A PLAYER"}</h2> <h2>{"PICK A PLAYER"}</h2>
<h3>{"THEY WILL BE COVERED IN WOLF BLOOD"}</h3> <h3>{"THEY WILL BE COVERED IN WOLF BLOOD"}</h3>
<h4>{"AND"}</h4>
<h2 class="yellow inline-icons"> <h2 class="yellow inline-icons">
{"APPEAR AS A WOLF "} {"AND APPEAR AS A WOLF "}
<Icon source={IconSource::Wolves} icon_type={IconType::Fit}/> <Icon source={IconSource::Wolves} icon_type={IconType::Fit}/>
{" KILLER "} {" KILLER "}
<Icon source={IconSource::Killer} icon_type={IconType::Fit}/> <Icon source={IconSource::Killer} icon_type={IconType::Fit}/>

View File

@ -26,7 +26,7 @@ pub fn EmpathPage1() -> Html {
<div class="information intel faint"> <div class="information intel faint">
<h2>{"PICK A PLAYER"}</h2> <h2>{"PICK A PLAYER"}</h2>
<h3 class="yellow">{"YOU WILL CHECK IF THEY ARE THE SCAPEGOAT"}</h3> <h3 class="yellow">{"YOU WILL CHECK IF THEY ARE THE SCAPEGOAT"}</h3>
<h3>{"AND IF THEY ARE, TAKE ON THEIR CURSE"}</h3> <h3>{"IF THEY ARE, YOU WILL TAKE ON THEIR CURSE"}</h3>
</div> </div>
</div> </div>
} }
@ -43,18 +43,26 @@ pub fn EmpathResult(EmpathResultProps { scapegoat }: &EmpathResultProps) -> Html
true => "THE SCAPEGOAT", true => "THE SCAPEGOAT",
false => "NOT THE SCAPEGOAT", false => "NOT THE SCAPEGOAT",
}; };
let icon = match scapegoat {
true => html! {
<Icon
source={IconSource::Scapegoat}
/>
},
false => html! {
<Icon
source={IconSource::RedX}
/>
},
};
html! { html! {
<div class="role-page"> <div class="role-page">
<h1 class="intel">{"EMPATH"}</h1> <h1 class="intel">{"EMPATH"}</h1>
<div class="information intel faint"> <div class="information intel faint">
<h2>{"YOUR TARGET IS"}</h2> <h2>{"YOUR TARGET IS"}</h2>
<h4> <div class="info-icon-grow">
<Icon {icon}
source={IconSource::Scapegoat} </div>
icon_type={IconType::Informational}
inactive={scapegoat.not()}
/>
</h4>
<h3 class="yellow">{text}</h3> <h3 class="yellow">{text}</h3>
</div> </div>
</div> </div>

View File

@ -29,8 +29,8 @@ pub fn GravediggerPage1() -> Html {
<span class="yellow">{"DEAD"}</span> <span class="yellow">{"DEAD"}</span>
{" PLAYER"} {" PLAYER"}
</h2> </h2>
<div class="icons"> <div class="info-icon-grow">
<Icon source={IconSource::Gravedigger} icon_type={IconType::Informational}/> <Icon source={IconSource::Gravedigger}/>
</div> </div>
<h3 class="yellow"> <h3 class="yellow">
{"YOU WILL LEARN THEIR ROLE"} {"YOU WILL LEARN THEIR ROLE"}
@ -54,7 +54,7 @@ pub fn GravediggerResultPage(
.map(|r| { .map(|r| {
html! { html! {
<h4> <h4>
{"YOU DIG UP THE BODY OF A "} {"AND FIND A "}
<span class="yellow"> <span class="yellow">
{r.to_string().to_case(Case::Upper)} {r.to_string().to_case(Case::Upper)}
</span> </span>
@ -75,12 +75,9 @@ pub fn GravediggerResultPage(
<h1 class="intel">{"GRAVEDIGGER"}</h1> <h1 class="intel">{"GRAVEDIGGER"}</h1>
<div class="information intel faint"> <div class="information intel faint">
<h2>{"YOU CHECK THE ROLE OF YOUR TARGET"}</h2> <h2>{"YOU CHECK THE ROLE OF YOUR TARGET"}</h2>
<h4> <div class="info-icon-grow">
<Icon <Icon source={icon} />
source={icon} </div>
icon_type={IconType::Informational}
/>
</h4>
{text} {text}
</div> </div>
</div> </div>

View File

@ -29,9 +29,9 @@ pub fn GuardianPageNoPrevProtect() -> Html {
<h1 class="defensive">{"GUARDIAN"}</h1> <h1 class="defensive">{"GUARDIAN"}</h1>
<div class="information defensive faint"> <div class="information defensive faint">
<h2>{"PICK A PLAYER"}</h2> <h2>{"PICK A PLAYER"}</h2>
<h4 class="icons"> <div class="info-icon-grow">
<Icon source={IconSource::ShieldAndSword} icon_type={IconType::Informational}/> <Icon source={IconSource::ShieldAndSword}/>
</h4> </div>
<h3 class="yellow">{"CHOOSE SOMEONE TO PROTECT FROM DEATH"}</h3> <h3 class="yellow">{"CHOOSE SOMEONE TO PROTECT FROM DEATH"}</h3>
</div> </div>
</div> </div>
@ -90,12 +90,12 @@ pub fn GuardianPagePreviousGuard(GuardianPageProps { previous }: &GuardianPagePr
<h1 class="defensive">{"GUARDIAN"}</h1> <h1 class="defensive">{"GUARDIAN"}</h1>
<div class="information defensive faint"> <div class="information defensive faint">
<h2>{"LAST TIME YOU GUARDED"}</h2> <h2>{"LAST TIME YOU GUARDED"}</h2>
<div class="info-icon-grow">
<Icon source={IconSource::ShieldAndSword} />
</div>
<div class="info-player-list"> <div class="info-player-list">
<CharacterTargetCard ident={previous.clone()} /> <CharacterTargetCard ident={previous.clone()} />
</div> </div>
<h4 class="icons">
<Icon source={IconSource::ShieldAndSword} icon_type={IconType::Informational}/>
</h4>
<h3 class="yellow">{"YOU CANNOT PROTECT THEM TONIGHT"}</h3> <h3 class="yellow">{"YOU CANNOT PROTECT THEM TONIGHT"}</h3>
</div> </div>
</div> </div>

View File

@ -23,12 +23,12 @@ pub fn HunterPage1() -> Html {
<h1 class="offensive">{"HUNTER"}</h1> <h1 class="offensive">{"HUNTER"}</h1>
<div class="information offensive faint"> <div class="information offensive faint">
<h2>{"SET A HUNTER'S TRAP ON A PLAYER"}</h2> <h2>{"SET A HUNTER'S TRAP ON A PLAYER"}</h2>
<div class="icons"> <div class="info-icon-grow">
<Icon source={IconSource::Hunter} icon_type={IconType::Informational}/> <Icon source={IconSource::Hunter}/>
</div> </div>
<h3 class="yellow"> <h3 class="yellow">
{"IF YOU DIE TONIGHT, OR ARE EXECUTED TOMORROW"} {"IF YOU DIE TONIGHT, OR ARE EXECUTED TOMORROW "}
{"THIS PLAYER WILL DIE AT NIGHT AS WELL"} {"THIS PLAYER WILL DIE AT NIGHT"}
</h3> </h3>
</div> </div>
</div> </div>

View File

@ -15,7 +15,7 @@
use werewolves_proto::message::night::Visits; use werewolves_proto::message::night::Visits;
use yew::prelude::*; use yew::prelude::*;
use crate::components::CharacterTargetCard; use crate::components::{CharacterTargetCard, Icon, IconSource};
#[function_component] #[function_component]
pub fn InsomniacPage1() -> Html { pub fn InsomniacPage1() -> Html {
@ -23,9 +23,12 @@ pub fn InsomniacPage1() -> Html {
<div class="role-page"> <div class="role-page">
<h1 class="intel">{"INSOMNIAC"}</h1> <h1 class="intel">{"INSOMNIAC"}</h1>
<div class="information intel faint"> <div class="information intel faint">
<h2>{"YOUR POOR SLEEP RESULTS IN BEING WOKEN BY VISITORS IN THE NIGHT"}</h2> <h2>{"YOUR SLEEP IS INTERRUPTED"}</h2>
<div class="info-icon-grow">
<Icon source={IconSource::Insomniac}/>
</div>
<h3 class="yellow"> <h3 class="yellow">
{"YOU WILL REMEMBER WHO VISITED YOU TONIGHT"} {"THE FOLLOWING PEOPLE VISITED YOU TONIGHT"}
</h3> </h3>
</div> </div>
</div> </div>
@ -52,7 +55,7 @@ pub fn InsomniacResult(InsomniacResultProps { visits }: &InsomniacResultProps) -
<h1 class="intel">{"INSOMNIAC"}</h1> <h1 class="intel">{"INSOMNIAC"}</h1>
<div class="information intel faint"> <div class="information intel faint">
<h2>{"YOU WERE VISITED IN THE NIGHT BY:"}</h2> <h2>{"YOU WERE VISITED IN THE NIGHT BY:"}</h2>
<div class="info-player-list"> <div class="info-player-list large">
{visitors} {visitors}
</div> </div>
</div> </div>

View File

@ -53,7 +53,7 @@ pub fn MasonRecruitPage1(
<span class="yellow">{"EVERY NIGHT"}</span> <span class="yellow">{"EVERY NIGHT"}</span>
{", AS LONG AS THEY ARE ALIVE AND REMAIN VILLAGE ALIGNED"} {", AS LONG AS THEY ARE ALIVE AND REMAIN VILLAGE ALIGNED"}
</h4> </h4>
<h3 class="yellow">{"WOULD YOU LIKE TO RECRUIT TONIGHT?"}</h3> <h2 class="yellow">{"WOULD YOU LIKE TO RECRUIT TONIGHT?"}</h2>
</div> </div>
</div> </div>
} }

View File

@ -27,8 +27,8 @@ pub fn MilitiaPage1() -> Html {
<span class="yellow">{"ONCE PER GAME"}</span> <span class="yellow">{"ONCE PER GAME"}</span>
{" KILL ABILITY"} {" KILL ABILITY"}
</h2> </h2>
<div class="icons"> <div class="info-icon-grow">
<Icon source={IconSource::Sword} icon_type={IconType::Informational}/> <Icon source={IconSource::Sword}/>
</div> </div>
<h3 class="yellow"> <h3 class="yellow">
{"POINT AT YOUR TARGET "} {"POINT AT YOUR TARGET "}

View File

@ -16,7 +16,7 @@
use werewolves_proto::role::Powerful; use werewolves_proto::role::Powerful;
use yew::prelude::*; use yew::prelude::*;
use crate::components::{Icon, IconSource, IconType}; use crate::components::{Icon, IconSource};
#[function_component] #[function_component]
pub fn PowerSeerPage1() -> Html { pub fn PowerSeerPage1() -> Html {
@ -26,7 +26,7 @@ pub fn PowerSeerPage1() -> Html {
<div class="information intel faint"> <div class="information intel faint">
<h2>{"PICK A PLAYER"}</h2> <h2>{"PICK A PLAYER"}</h2>
<div class="info-icon-grow"> <div class="info-icon-grow">
<Icon source={IconSource::PowerSeer} /> <Icon source={IconSource::Powerful} />
</div> </div>
<h3 class="yellow">{"YOU WILL CHECK IF THEY ARE POWERFUL"}</h3> <h3 class="yellow">{"YOU WILL CHECK IF THEY ARE POWERFUL"}</h3>
</div> </div>
@ -49,13 +49,13 @@ pub fn PowerSeerResult(PowerSeerResultProps { powerful }: &PowerSeerResultProps)
Powerful::Powerful => html! { Powerful::Powerful => html! {
<Icon <Icon
source={IconSource::Powerful} source={IconSource::Powerful}
icon_type={IconType::Informational} // icon_type={IconType::Informational}
/> />
}, },
Powerful::NotPowerful => html! { Powerful::NotPowerful => html! {
<Icon <Icon
source={IconSource::RedX} source={IconSource::RedX}
icon_type={IconType::Informational} // icon_type={IconType::Informational}
/> />
}, },
}; };
@ -64,7 +64,7 @@ pub fn PowerSeerResult(PowerSeerResultProps { powerful }: &PowerSeerResultProps)
<h1 class="intel">{"POWER SEER"}</h1> <h1 class="intel">{"POWER SEER"}</h1>
<div class="information intel faint"> <div class="information intel faint">
<h2>{"YOUR TARGET APPEARS AS"}</h2> <h2>{"YOUR TARGET APPEARS AS"}</h2>
<h4>{icon}</h4> <div class="info-icon-grow">{icon}</div>
<h3 class="yellow">{text}</h3> <h3 class="yellow">{text}</h3>
</div> </div>
</div> </div>

View File

@ -22,12 +22,14 @@ pub fn PyremasterPage1() -> Html {
<div class="role-page"> <div class="role-page">
<h1 class="offensive">{"PYREMASTER"}</h1> <h1 class="offensive">{"PYREMASTER"}</h1>
<div class="information offensive faint"> <div class="information offensive faint">
<h2>{"IF YOU WISH TO THROW A PLAYER ON THE PYRE"}</h2> <h3>{"YOU CAN CHOOSE TO THROW A PLAYER ON THE PYRE"}</h3>
<div class="icons"> <div class="info-icon-grow">
<Icon source={IconSource::Pyremaster} icon_type={IconType::Informational}/> <Icon source={IconSource::Pyremaster}/>
</div> </div>
<h3 class="yellow"> <h3>
{"IF YOU KILL TWO GOOD VILLAGERS LIKE THIS "} {"IF YOU KILL "}
<span class="yellow">{"TWO"}</span>
{" GOOD VILLAGERS LIKE THIS "}
{"YOU WILL DIE AS WELL"} {"YOU WILL DIE AS WELL"}
</h3> </h3>
</div> </div>

View File

@ -26,10 +26,10 @@ pub fn SeerPage1() -> Html {
<h1 class="intel">{"SEER"}</h1> <h1 class="intel">{"SEER"}</h1>
<div class="information intel faint"> <div class="information intel faint">
<h2>{"PICK A PLAYER"}</h2> <h2>{"PICK A PLAYER"}</h2>
<h4 class="icons"> <div class="info-icon-list-grow">
<Icon source={IconSource::Village} icon_type={IconType::Informational}/> <Icon source={IconSource::Village} />
<Icon source={IconSource::Wolves} icon_type={IconType::Informational}/> <Icon source={IconSource::Wolves} />
</h4> </div>
<h3 class="yellow">{"YOU WILL CHECK IF THEY APPEAR AS A VILLAGER OR PART OF THE WOLFPACK"}</h3> <h3 class="yellow">{"YOU WILL CHECK IF THEY APPEAR AS A VILLAGER OR PART OF THE WOLFPACK"}</h3>
</div> </div>
</div> </div>

View File

@ -24,9 +24,9 @@ pub fn VindicatorPage1() -> Html {
<div class="information defensive faint"> <div class="information defensive faint">
<h3>{"A VILLAGER WAS EXECUTED"}</h3> <h3>{"A VILLAGER WAS EXECUTED"}</h3>
<h2>{"PICK A PLAYER"}</h2> <h2>{"PICK A PLAYER"}</h2>
<h4 class="icons"> <div class="info-icon-grow">
<Icon source={IconSource::Shield} icon_type={IconType::Informational}/> <Icon source={IconSource::Vindicator} />
</h4> </div>
<h3 class="yellow">{"YOU WILL PROTECT THEM FROM A DEATH TONIGHT"}</h3> <h3 class="yellow">{"YOU WILL PROTECT THEM FROM A DEATH TONIGHT"}</h3>
</div> </div>
</div> </div>

View File

@ -26,9 +26,9 @@ pub fn WolfpackKillPage() -> Html {
<h1 class="wolves">{"WOLF PACK KILL"}</h1> <h1 class="wolves">{"WOLF PACK KILL"}</h1>
<div class="information wolves faint"> <div class="information wolves faint">
<h2>{"CHOOSE A TARGET TO EAT TONIGHT"}</h2> <h2>{"CHOOSE A TARGET TO EAT TONIGHT"}</h2>
<h4 class="icons"> <div class="info-icon-grow">
<Icon source={IconSource::Wolves} icon_type={IconType::Informational}/> <Icon source={IconSource::Wolves} />
</h4> </div>
<h3 class="yellow">{"WOLVES MUST BE UNANIMOUS"}</h3> <h3 class="yellow">{"WOLVES MUST BE UNANIMOUS"}</h3>
</div> </div>
</div> </div>