apprentice gets power same night
also various cosmetic changes
This commit is contained in:
parent
15a6454ae2
commit
79c8c464b6
|
|
@ -1,4 +1,8 @@
|
||||||
use core::{fmt::Display, num::NonZeroU8, ops::Not};
|
use core::{
|
||||||
|
fmt::Display,
|
||||||
|
num::NonZeroU8,
|
||||||
|
ops::{Deref, Not},
|
||||||
|
};
|
||||||
|
|
||||||
use rand::seq::SliceRandom;
|
use rand::seq::SliceRandom;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
@ -272,6 +276,14 @@ impl Character {
|
||||||
.collect())
|
.collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a copy of this character with their role replaced
|
||||||
|
/// in a read-only type
|
||||||
|
pub fn as_role(&self, role: Role) -> AsCharacter {
|
||||||
|
let mut char = self.clone();
|
||||||
|
char.role = role;
|
||||||
|
AsCharacter(char)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn night_action_prompts(&self, village: &Village) -> Result<Box<[ActionPrompt]>> {
|
pub fn night_action_prompts(&self, village: &Village) -> Result<Box<[ActionPrompt]>> {
|
||||||
if self.mason_leader().is_ok() {
|
if self.mason_leader().is_ok() {
|
||||||
return self.mason_prompts(village);
|
return self.mason_prompts(village);
|
||||||
|
|
@ -834,3 +846,13 @@ impl MasonLeaderMut<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct AsCharacter(Character);
|
||||||
|
|
||||||
|
impl Deref for AsCharacter {
|
||||||
|
type Target = Character;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -270,7 +270,31 @@ impl Night {
|
||||||
.partial_cmp(right_prompt)
|
.partial_cmp(right_prompt)
|
||||||
.unwrap_or(core::cmp::Ordering::Equal)
|
.unwrap_or(core::cmp::Ordering::Equal)
|
||||||
});
|
});
|
||||||
let mut action_queue = VecDeque::from(action_queue);
|
|
||||||
|
let mut action_queue = VecDeque::from({
|
||||||
|
// insert actions for role-changed roles
|
||||||
|
let mut expanded_queue = Vec::new();
|
||||||
|
for action in action_queue {
|
||||||
|
match &action {
|
||||||
|
ActionPrompt::RoleChange {
|
||||||
|
character_id,
|
||||||
|
new_role,
|
||||||
|
} => {
|
||||||
|
let char = village.character_by_id(character_id.character_id)?;
|
||||||
|
let as_role = char.as_role(new_role.title_to_role_excl_apprentice());
|
||||||
|
expanded_queue.push(action);
|
||||||
|
for prompt in as_role.night_action_prompts(&village)? {
|
||||||
|
expanded_queue.push(prompt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
expanded_queue.push(action);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expanded_queue
|
||||||
|
});
|
||||||
|
|
||||||
if night == 0 {
|
if night == 0 {
|
||||||
action_queue.push_front(ActionPrompt::WolvesIntro {
|
action_queue.push_front(ActionPrompt::WolvesIntro {
|
||||||
|
|
@ -716,6 +740,39 @@ impl Night {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn received_response_consecutive_same_player_no_sleep(
|
||||||
|
&self,
|
||||||
|
resp: ActionResponse,
|
||||||
|
) -> Result<ResponseOutcome> {
|
||||||
|
let same_char = self
|
||||||
|
.current_character_id()
|
||||||
|
.and_then(|curr| {
|
||||||
|
self.action_queue
|
||||||
|
.iter()
|
||||||
|
.next()
|
||||||
|
.map(|n| n.character_id() == Some(curr))
|
||||||
|
})
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
match (
|
||||||
|
self.received_response_consecutive_wolves_dont_sleep(resp)?,
|
||||||
|
same_char,
|
||||||
|
) {
|
||||||
|
(ResponseOutcome::PromptUpdate(p), _) => Ok(ResponseOutcome::PromptUpdate(p)),
|
||||||
|
(
|
||||||
|
ResponseOutcome::ActionComplete(ActionComplete {
|
||||||
|
result: ActionResult::GoBackToSleep,
|
||||||
|
change,
|
||||||
|
}),
|
||||||
|
true,
|
||||||
|
) => Ok(ResponseOutcome::ActionComplete(ActionComplete {
|
||||||
|
result: ActionResult::Continue,
|
||||||
|
change,
|
||||||
|
})),
|
||||||
|
(act, _) => Ok(act),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn received_response_consecutive_wolves_dont_sleep(
|
fn received_response_consecutive_wolves_dont_sleep(
|
||||||
&self,
|
&self,
|
||||||
resp: ActionResponse,
|
resp: ActionResponse,
|
||||||
|
|
@ -775,7 +832,7 @@ impl Night {
|
||||||
&self,
|
&self,
|
||||||
resp: ActionResponse,
|
resp: ActionResponse,
|
||||||
) -> Result<BlockResolvedOutcome> {
|
) -> Result<BlockResolvedOutcome> {
|
||||||
match self.received_response_consecutive_wolves_dont_sleep(resp)? {
|
match self.received_response_consecutive_same_player_no_sleep(resp)? {
|
||||||
ResponseOutcome::PromptUpdate(update) => Ok(BlockResolvedOutcome::PromptUpdate(update)),
|
ResponseOutcome::PromptUpdate(update) => Ok(BlockResolvedOutcome::PromptUpdate(update)),
|
||||||
ResponseOutcome::ActionComplete(ActionComplete { result, change }) => {
|
ResponseOutcome::ActionComplete(ActionComplete { result, change }) => {
|
||||||
match self
|
match self
|
||||||
|
|
@ -864,36 +921,7 @@ impl Night {
|
||||||
current_prompt,
|
current_prompt,
|
||||||
current_result: _,
|
current_result: _,
|
||||||
..
|
..
|
||||||
} => match current_prompt {
|
} => current_prompt.character_id(),
|
||||||
ActionPrompt::Insomniac { character_id, .. }
|
|
||||||
| ActionPrompt::LoneWolfKill { character_id, .. }
|
|
||||||
| ActionPrompt::ElderReveal { character_id }
|
|
||||||
| ActionPrompt::RoleChange { character_id, .. }
|
|
||||||
| ActionPrompt::Seer { character_id, .. }
|
|
||||||
| ActionPrompt::Protector { character_id, .. }
|
|
||||||
| ActionPrompt::Arcanist { character_id, .. }
|
|
||||||
| ActionPrompt::Gravedigger { character_id, .. }
|
|
||||||
| ActionPrompt::Hunter { character_id, .. }
|
|
||||||
| ActionPrompt::Militia { character_id, .. }
|
|
||||||
| ActionPrompt::MapleWolf { character_id, .. }
|
|
||||||
| ActionPrompt::Guardian { character_id, .. }
|
|
||||||
| ActionPrompt::Shapeshifter { character_id }
|
|
||||||
| ActionPrompt::AlphaWolf { character_id, .. }
|
|
||||||
| ActionPrompt::Adjudicator { character_id, .. }
|
|
||||||
| ActionPrompt::PowerSeer { character_id, .. }
|
|
||||||
| ActionPrompt::Mortician { character_id, .. }
|
|
||||||
| ActionPrompt::Beholder { character_id, .. }
|
|
||||||
| ActionPrompt::MasonLeaderRecruit { character_id, .. }
|
|
||||||
| ActionPrompt::Empath { character_id, .. }
|
|
||||||
| ActionPrompt::Vindicator { character_id, .. }
|
|
||||||
| ActionPrompt::PyreMaster { character_id, .. }
|
|
||||||
| ActionPrompt::DireWolf { character_id, .. } => Some(character_id.character_id),
|
|
||||||
|
|
||||||
ActionPrompt::WolvesIntro { wolves: _ }
|
|
||||||
| ActionPrompt::MasonsWake { .. }
|
|
||||||
| ActionPrompt::WolfPackKill { .. }
|
|
||||||
| ActionPrompt::CoverOfDarkness => None,
|
|
||||||
},
|
|
||||||
NightState::Complete => None,
|
NightState::Complete => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,36 +13,32 @@ use crate::{
|
||||||
|
|
||||||
type Result<T> = core::result::Result<T, GameError>;
|
type Result<T> = core::result::Result<T, GameError>;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, PartialOrd)]
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, PartialOrd, ChecksAs)]
|
||||||
pub enum ActionType {
|
pub enum ActionType {
|
||||||
Cover,
|
Cover,
|
||||||
|
#[checks("is_wolfy")]
|
||||||
WolvesIntro,
|
WolvesIntro,
|
||||||
|
RoleChange,
|
||||||
Protect,
|
Protect,
|
||||||
|
#[checks("is_wolfy")]
|
||||||
WolfPackKill,
|
WolfPackKill,
|
||||||
Direwolf,
|
#[checks("is_wolfy")]
|
||||||
|
Shapeshifter,
|
||||||
|
#[checks("is_wolfy")]
|
||||||
|
AlphaWolfKill,
|
||||||
|
#[checks("is_wolfy")]
|
||||||
OtherWolf,
|
OtherWolf,
|
||||||
|
#[checks("is_wolfy")]
|
||||||
|
Direwolf,
|
||||||
LoneWolfKill,
|
LoneWolfKill,
|
||||||
Block,
|
Block,
|
||||||
|
VillageKill,
|
||||||
Intel,
|
Intel,
|
||||||
Other,
|
Other,
|
||||||
MasonRecruit,
|
MasonRecruit,
|
||||||
MasonsWake,
|
MasonsWake,
|
||||||
Insomniac,
|
Insomniac,
|
||||||
Beholder,
|
Beholder,
|
||||||
RoleChange,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ActionType {
|
|
||||||
const fn is_wolfy(&self) -> bool {
|
|
||||||
// note: Lone Wolf isn't wolfy, as they don't wake with wolves
|
|
||||||
matches!(
|
|
||||||
self,
|
|
||||||
ActionType::Direwolf
|
|
||||||
| ActionType::OtherWolf
|
|
||||||
| ActionType::WolfPackKill
|
|
||||||
| ActionType::WolvesIntro
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, ChecksAs, Titles)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, ChecksAs, Titles)]
|
||||||
|
|
@ -91,7 +87,7 @@ pub enum ActionPrompt {
|
||||||
living_players: Box<[CharacterIdentity]>,
|
living_players: Box<[CharacterIdentity]>,
|
||||||
marked: Option<CharacterId>,
|
marked: Option<CharacterId>,
|
||||||
},
|
},
|
||||||
#[checks(ActionType::Other)]
|
#[checks(ActionType::VillageKill)]
|
||||||
Militia {
|
Militia {
|
||||||
character_id: CharacterIdentity,
|
character_id: CharacterIdentity,
|
||||||
living_players: Box<[CharacterIdentity]>,
|
living_players: Box<[CharacterIdentity]>,
|
||||||
|
|
@ -159,7 +155,7 @@ pub enum ActionPrompt {
|
||||||
living_players: Box<[CharacterIdentity]>,
|
living_players: Box<[CharacterIdentity]>,
|
||||||
marked: Option<CharacterId>,
|
marked: Option<CharacterId>,
|
||||||
},
|
},
|
||||||
#[checks(ActionType::Other)]
|
#[checks(ActionType::VillageKill)]
|
||||||
PyreMaster {
|
PyreMaster {
|
||||||
character_id: CharacterIdentity,
|
character_id: CharacterIdentity,
|
||||||
living_players: Box<[CharacterIdentity]>,
|
living_players: Box<[CharacterIdentity]>,
|
||||||
|
|
@ -171,9 +167,9 @@ pub enum ActionPrompt {
|
||||||
living_villagers: Box<[CharacterIdentity]>,
|
living_villagers: Box<[CharacterIdentity]>,
|
||||||
marked: Option<CharacterId>,
|
marked: Option<CharacterId>,
|
||||||
},
|
},
|
||||||
#[checks(ActionType::OtherWolf)]
|
#[checks(ActionType::Shapeshifter)]
|
||||||
Shapeshifter { character_id: CharacterIdentity },
|
Shapeshifter { character_id: CharacterIdentity },
|
||||||
#[checks(ActionType::OtherWolf)]
|
#[checks(ActionType::AlphaWolfKill)]
|
||||||
AlphaWolf {
|
AlphaWolf {
|
||||||
character_id: CharacterIdentity,
|
character_id: CharacterIdentity,
|
||||||
living_villagers: Box<[CharacterIdentity]>,
|
living_villagers: Box<[CharacterIdentity]>,
|
||||||
|
|
@ -196,6 +192,38 @@ pub enum ActionPrompt {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ActionPrompt {
|
impl ActionPrompt {
|
||||||
|
pub(crate) const fn character_id(&self) -> Option<CharacterId> {
|
||||||
|
match self {
|
||||||
|
ActionPrompt::Insomniac { character_id, .. }
|
||||||
|
| ActionPrompt::LoneWolfKill { character_id, .. }
|
||||||
|
| ActionPrompt::ElderReveal { character_id }
|
||||||
|
| ActionPrompt::RoleChange { character_id, .. }
|
||||||
|
| ActionPrompt::Seer { character_id, .. }
|
||||||
|
| ActionPrompt::Protector { character_id, .. }
|
||||||
|
| ActionPrompt::Arcanist { character_id, .. }
|
||||||
|
| ActionPrompt::Gravedigger { character_id, .. }
|
||||||
|
| ActionPrompt::Hunter { character_id, .. }
|
||||||
|
| ActionPrompt::Militia { character_id, .. }
|
||||||
|
| ActionPrompt::MapleWolf { character_id, .. }
|
||||||
|
| ActionPrompt::Guardian { character_id, .. }
|
||||||
|
| ActionPrompt::Shapeshifter { character_id }
|
||||||
|
| ActionPrompt::AlphaWolf { character_id, .. }
|
||||||
|
| ActionPrompt::Adjudicator { character_id, .. }
|
||||||
|
| ActionPrompt::PowerSeer { character_id, .. }
|
||||||
|
| ActionPrompt::Mortician { character_id, .. }
|
||||||
|
| ActionPrompt::Beholder { character_id, .. }
|
||||||
|
| ActionPrompt::MasonLeaderRecruit { character_id, .. }
|
||||||
|
| ActionPrompt::Empath { character_id, .. }
|
||||||
|
| ActionPrompt::Vindicator { character_id, .. }
|
||||||
|
| ActionPrompt::PyreMaster { character_id, .. }
|
||||||
|
| ActionPrompt::DireWolf { character_id, .. } => Some(character_id.character_id),
|
||||||
|
|
||||||
|
ActionPrompt::WolvesIntro { .. }
|
||||||
|
| ActionPrompt::MasonsWake { .. }
|
||||||
|
| ActionPrompt::WolfPackKill { .. }
|
||||||
|
| ActionPrompt::CoverOfDarkness => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
pub(crate) fn matches_beholding(&self, target: CharacterId) -> bool {
|
pub(crate) fn matches_beholding(&self, target: CharacterId) -> bool {
|
||||||
match self {
|
match self {
|
||||||
ActionPrompt::Insomniac { character_id, .. }
|
ActionPrompt::Insomniac { character_id, .. }
|
||||||
|
|
|
||||||
|
|
@ -219,7 +219,6 @@ pub enum Role {
|
||||||
#[checks(Alignment::Village)]
|
#[checks(Alignment::Village)]
|
||||||
#[checks(Powerful::Powerful)]
|
#[checks(Powerful::Powerful)]
|
||||||
#[checks(Killer::NotKiller)]
|
#[checks(Killer::NotKiller)]
|
||||||
#[checks("is_mentor")]
|
|
||||||
Elder {
|
Elder {
|
||||||
knows_on_night: NonZeroU8,
|
knows_on_night: NonZeroU8,
|
||||||
woken_for_reveal: bool,
|
woken_for_reveal: bool,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="81.560997mm"
|
||||||
|
height="48.303188mm"
|
||||||
|
viewBox="0 0 81.560997 48.303188"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1"
|
||||||
|
xml:space="preserve"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||||
|
id="defs1" /><g
|
||||||
|
id="layer4"
|
||||||
|
transform="translate(-50.121599,-612.75354)"><g
|
||||||
|
id="g9"><rect
|
||||||
|
style="fill:#3c34ff;fill-opacity:1;stroke:#0f07ff;stroke-width:1.561;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="rect6"
|
||||||
|
width="80"
|
||||||
|
height="20"
|
||||||
|
x="50.902103"
|
||||||
|
y="613.53406" /><rect
|
||||||
|
style="fill:#3c34ff;fill-opacity:1;stroke:#0f07ff;stroke-width:1.561;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="rect6-1"
|
||||||
|
width="80"
|
||||||
|
height="20"
|
||||||
|
x="50.902103"
|
||||||
|
y="640.27625" /></g></g></svg>
|
||||||
|
After Width: | Height: | Size: 932 B |
|
|
@ -0,0 +1,35 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="81.560997mm"
|
||||||
|
height="79.98938mm"
|
||||||
|
viewBox="0 0 81.560997 79.98938"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1"
|
||||||
|
xml:space="preserve"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||||
|
id="defs1" /><g
|
||||||
|
id="layer4"
|
||||||
|
transform="translate(-50.121599,-596.91049)"><g
|
||||||
|
id="g9"><rect
|
||||||
|
style="fill:#3c34ff;fill-opacity:1;stroke:#0f07ff;stroke-width:1.561;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="rect6"
|
||||||
|
width="80"
|
||||||
|
height="20"
|
||||||
|
x="50.902103"
|
||||||
|
y="613.53406" /><rect
|
||||||
|
style="fill:#3c34ff;fill-opacity:1;stroke:#0f07ff;stroke-width:1.561;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="rect6-1"
|
||||||
|
width="80"
|
||||||
|
height="20"
|
||||||
|
x="50.902103"
|
||||||
|
y="640.27625" /></g><rect
|
||||||
|
style="fill:#ff0707;fill-opacity:1;stroke:#c10000;stroke-width:1.561;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="rect6-3"
|
||||||
|
width="100"
|
||||||
|
height="10"
|
||||||
|
x="-436.08246"
|
||||||
|
y="509.63745"
|
||||||
|
transform="rotate(-45)" /></g></svg>
|
||||||
|
After Width: | Height: | Size: 1.2 KiB |
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="87.060303mm"
|
||||||
|
height="87.060318mm"
|
||||||
|
viewBox="0 0 87.060303 87.060318"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1"
|
||||||
|
xml:space="preserve"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||||
|
id="defs1" /><g
|
||||||
|
id="layer4"
|
||||||
|
transform="translate(-207.43333,-614.36255)"><path
|
||||||
|
id="rect6-3-3"
|
||||||
|
style="fill:#ff0707;fill-opacity:1;stroke:#c10000;stroke-width:1.561;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m -277.74226,592.65854 h -20.00022 v 39.9997 h -39.99971 v 20.00022 h 39.99971 v 39.9997 h 20.00022 v -39.9997 h 39.9997 v -20.00022 h -39.9997 z"
|
||||||
|
transform="rotate(-45)" /></g></svg>
|
||||||
|
After Width: | Height: | Size: 776 B |
|
|
@ -102,7 +102,7 @@ app {
|
||||||
left: 0;
|
left: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 2rem;
|
font-size: 2.7vw;
|
||||||
}
|
}
|
||||||
|
|
||||||
$link_color: #432054;
|
$link_color: #432054;
|
||||||
|
|
@ -383,16 +383,38 @@ button {
|
||||||
}
|
}
|
||||||
|
|
||||||
.identity {
|
.identity {
|
||||||
font-size: 1.5em;
|
font-size: 1.5rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.day-char {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
// min-width: 1vw;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.red {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
.character {
|
.character {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
border: 3px solid rgba(0, 0, 0, 0.4);
|
border: 3px solid rgba(0, 0, 0, 0.4);
|
||||||
// min-width: 20%;
|
// min-width: 20%;
|
||||||
flex-shrink: 1;
|
flex-shrink: 1;
|
||||||
|
|
||||||
|
.headline {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
gap: 5px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
.role {
|
.role {
|
||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
|
|
||||||
|
|
@ -881,6 +903,7 @@ error {
|
||||||
.binary {
|
.binary {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
font-size: 1.5vw;
|
||||||
|
|
||||||
.button-container {
|
.button-container {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
@ -1281,7 +1304,7 @@ input {
|
||||||
|
|
||||||
.setup-screen {
|
.setup-screen {
|
||||||
margin-top: 2%;
|
margin-top: 2%;
|
||||||
font-size: 1rem;
|
font-size: 1.5vw;
|
||||||
|
|
||||||
.setup {
|
.setup {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -1341,6 +1364,7 @@ input {
|
||||||
filter: saturate(40%);
|
filter: saturate(40%);
|
||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
padding-right: 10px;
|
padding-right: 10px;
|
||||||
|
font-weight: bolder;
|
||||||
|
|
||||||
&.wakes {
|
&.wakes {
|
||||||
border: 2px solid yellow;
|
border: 2px solid yellow;
|
||||||
|
|
@ -1361,7 +1385,8 @@ input {
|
||||||
}
|
}
|
||||||
|
|
||||||
.inactive {
|
.inactive {
|
||||||
filter: grayscale(100%) brightness(30%);
|
// filter: grayscale(100%) brightness(30%);
|
||||||
|
filter: brightness(0%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.qrcode {
|
.qrcode {
|
||||||
|
|
@ -1383,6 +1408,7 @@ input {
|
||||||
}
|
}
|
||||||
|
|
||||||
.details {
|
.details {
|
||||||
|
font-size: 5vw;
|
||||||
// height: 100%;
|
// height: 100%;
|
||||||
// width: 100%;
|
// width: 100%;
|
||||||
border: 1px solid $village_border;
|
border: 1px solid $village_border;
|
||||||
|
|
@ -1485,12 +1511,17 @@ input {
|
||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.full-height {
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
& input {
|
& input {
|
||||||
height: 2rem;
|
height: 2rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
&#number {
|
#number {
|
||||||
font-size: 2rem;
|
font-size: 2rem;
|
||||||
|
max-width: 50vw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1724,10 +1755,11 @@ input {
|
||||||
h1 {
|
h1 {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
// align-self: flex-start;
|
// align-self: flex-start;
|
||||||
|
font-size: 4vw;
|
||||||
}
|
}
|
||||||
|
|
||||||
.information {
|
.information {
|
||||||
font-size: 1.2em;
|
font-size: 1.2rem;
|
||||||
padding-left: 5%;
|
padding-left: 5%;
|
||||||
padding-right: 5%;
|
padding-right: 5%;
|
||||||
}
|
}
|
||||||
|
|
@ -1764,7 +1796,7 @@ input {
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
|
|
||||||
&.masons {
|
&.masons {
|
||||||
font-size: 2em;
|
font-size: 2rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -459,13 +459,17 @@ impl Component for Host {
|
||||||
<Button on_click={to_normal}>{"small screen"}</Button>
|
<Button on_click={to_normal}>{"small screen"}</Button>
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let to_big = Callback::from(|_| {
|
// let to_big = Callback::from(|_| {
|
||||||
if let Some(loc) = gloo::utils::document().location() {
|
// if let Some(loc) = gloo::utils::document().location() {
|
||||||
let _ = loc.replace("/host/big");
|
// let _ = loc.replace("/host/big");
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
html! {
|
html! {
|
||||||
<Button on_click={to_big}>{"big screen 📺"}</Button>
|
<a href="/host/big">
|
||||||
|
<Button on_click={Callback::default()}>
|
||||||
|
{"big screen 📺"}
|
||||||
|
</Button>
|
||||||
|
</a>
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let story_on_click = if let HostState::Story { .. } = &self.state {
|
let story_on_click = if let HostState::Story { .. } = &self.state {
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ pub fn Signin(props: &SigninProps) -> Html {
|
||||||
|
|
||||||
let on_change = crate::components::input_element_number_oninput(num_value);
|
let on_change = crate::components::input_element_number_oninput(num_value);
|
||||||
html! {
|
html! {
|
||||||
<div class="signin">
|
<div class="signin full-height">
|
||||||
<div class="column-list">
|
<div class="column-list">
|
||||||
<label for="name">{"Name"}</label>
|
<label for="name">{"Name"}</label>
|
||||||
<input oninput={name_on_input} name="name" id="name" type="text"/>
|
<input oninput={name_on_input} name="name" id="name" type="text"/>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use core::{num::NonZeroU8, ops::Not};
|
use core::{num::NonZeroU8, ops::Not};
|
||||||
|
|
||||||
|
use convert_case::{Case, Casing};
|
||||||
use werewolves_proto::{
|
use werewolves_proto::{
|
||||||
character::CharacterId,
|
character::CharacterId,
|
||||||
game::GameTime,
|
game::GameTime,
|
||||||
|
|
@ -7,7 +8,10 @@ use werewolves_proto::{
|
||||||
};
|
};
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
|
|
||||||
use crate::components::{Button, Identity};
|
use crate::components::{
|
||||||
|
AssociatedIcon, Button, Icon, IconType, Identity, PartialAssociatedIcon,
|
||||||
|
attributes::RoleTitleSpan,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Properties)]
|
#[derive(Debug, Clone, PartialEq, Properties)]
|
||||||
pub struct DaytimePlayerListProps {
|
pub struct DaytimePlayerListProps {
|
||||||
|
|
@ -115,7 +119,7 @@ pub fn DaytimePlayer(
|
||||||
character:
|
character:
|
||||||
CharacterState {
|
CharacterState {
|
||||||
player_id: _,
|
player_id: _,
|
||||||
role: _,
|
role,
|
||||||
died_to,
|
died_to,
|
||||||
identity,
|
identity,
|
||||||
},
|
},
|
||||||
|
|
@ -133,9 +137,18 @@ pub fn DaytimePlayer(
|
||||||
)
|
)
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
let identity: PublicIdentity = identity.into();
|
let identity: PublicIdentity = identity.into();
|
||||||
|
let icon = role.icon().unwrap_or_else(|| role.alignment().icon());
|
||||||
|
let text = role.to_string().to_case(Case::Title);
|
||||||
|
let align_class = role.wolf().then_some("red");
|
||||||
html! {
|
html! {
|
||||||
<Button on_click={on_click} classes={classes!(class, "character")}>
|
<Button on_click={on_click} classes={classes!(class, "character")}>
|
||||||
<Identity ident={identity}/>
|
<div class="day-char">
|
||||||
|
<span class={classes!("headline")}>
|
||||||
|
<Icon source={icon} icon_type={IconType::Small}/>
|
||||||
|
<span class={classes!(align_class)}>{text}</span>
|
||||||
|
</span>
|
||||||
|
<Identity ident={identity}/>
|
||||||
|
</div>
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ use yew::prelude::*;
|
||||||
|
|
||||||
macro_rules! decl_icon {
|
macro_rules! decl_icon {
|
||||||
($($name:ident: $path:literal,)*) => {
|
($($name:ident: $path:literal,)*) => {
|
||||||
|
#[allow(unused)]
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum IconSource {
|
pub enum IconSource {
|
||||||
$(
|
$(
|
||||||
|
|
@ -58,6 +59,9 @@ decl_icon!(
|
||||||
Insomniac: "/img/insomniac.svg",
|
Insomniac: "/img/insomniac.svg",
|
||||||
BlackKnight: "/img/black-knight.svg",
|
BlackKnight: "/img/black-knight.svg",
|
||||||
Mason: "/img/mason.svg",
|
Mason: "/img/mason.svg",
|
||||||
|
NotEqual: "/img/not-equal.svg",
|
||||||
|
Equal: "/img/equal.svg",
|
||||||
|
RedX: "/img/red-x.svg",
|
||||||
);
|
);
|
||||||
|
|
||||||
impl IconSource {
|
impl IconSource {
|
||||||
|
|
|
||||||
|
|
@ -33,16 +33,26 @@ pub fn AdjudicatorResult(AdjudicatorResultProps { killer }: &AdjudicatorResultPr
|
||||||
Killer::Killer => "IS A KILLER",
|
Killer::Killer => "IS A KILLER",
|
||||||
Killer::NotKiller => "IS NOT A KILLER",
|
Killer::NotKiller => "IS NOT A KILLER",
|
||||||
};
|
};
|
||||||
|
let icon = match killer {
|
||||||
|
Killer::Killer => html! {
|
||||||
|
<Icon
|
||||||
|
source={IconSource::Killer}
|
||||||
|
icon_type={IconType::Informational}
|
||||||
|
/>
|
||||||
|
},
|
||||||
|
Killer::NotKiller => html! {
|
||||||
|
<Icon
|
||||||
|
source={IconSource::RedX}
|
||||||
|
icon_type={IconType::Informational}
|
||||||
|
/>
|
||||||
|
},
|
||||||
|
};
|
||||||
html! {
|
html! {
|
||||||
<div class="role-page">
|
<div class="role-page">
|
||||||
<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>{icon}</h4>
|
||||||
source={IconSource::Killer}
|
|
||||||
icon_type={IconType::Informational}
|
|
||||||
inactive={killer.killer().not()}
|
|
||||||
/></h4>
|
|
||||||
<h3 class="yellow">{text}</h3>
|
<h3 class="yellow">{text}</h3>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,8 @@ pub fn ArcanistPage1() -> Html {
|
||||||
<h2>{"PICK TWO PLAYERS"}</h2>
|
<h2>{"PICK TWO PLAYERS"}</h2>
|
||||||
<h4 class="icons">
|
<h4 class="icons">
|
||||||
<Icon source={IconSource::Village} icon_type={IconType::Informational}/>
|
<Icon source={IconSource::Village} icon_type={IconType::Informational}/>
|
||||||
<Icon source={IconSource::Village} icon_type={IconType::Informational}/>
|
// <Icon source={IconSource::Village} icon_type={IconType::Informational}/>
|
||||||
<Icon source={IconSource::Wolves} icon_type={IconType::Informational}/>
|
// <Icon source={IconSource::Wolves} icon_type={IconType::Informational}/>
|
||||||
<Icon source={IconSource::Wolves} icon_type={IconType::Informational}/>
|
<Icon source={IconSource::Wolves} icon_type={IconType::Informational}/>
|
||||||
</h4>
|
</h4>
|
||||||
<h3 class="yellow">{"YOU WILL CHECK IF THEIR ALIGNMENTS ARE THE SAME OR DIFFERENT"}</h3>
|
<h3 class="yellow">{"YOU WILL CHECK IF THEIR ALIGNMENTS ARE THE SAME OR DIFFERENT"}</h3>
|
||||||
|
|
@ -36,20 +36,21 @@ 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::Village} icon_type={IconType::Informational}/>
|
// <Icon source={IconSource::Village} icon_type={IconType::Informational}/>
|
||||||
<Icon source={IconSource::Village} icon_type={IconType::Informational}/>
|
// <Icon source={IconSource::Village} icon_type={IconType::Informational}/>
|
||||||
<span>{"OR"}</span>
|
// <span>{"OR"}</span>
|
||||||
<Icon source={IconSource::Wolves} icon_type={IconType::Informational}/>
|
// <Icon source={IconSource::Wolves} icon_type={IconType::Informational}/>
|
||||||
<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_type={IconType::Informational}/>
|
||||||
<Icon source={IconSource::Wolves} icon_type={IconType::Informational}/>
|
<Icon source={IconSource::Wolves} icon_type={IconType::Informational}/>
|
||||||
{"OR"}
|
// {"OR"}
|
||||||
<Icon source={IconSource::Wolves} icon_type={IconType::Informational}/>
|
// <Icon source={IconSource::Wolves} icon_type={IconType::Informational}/>
|
||||||
<Icon source={IconSource::Village} icon_type={IconType::Informational}/>
|
// <Icon source={IconSource::Village} icon_type={IconType::Informational}/>
|
||||||
</>
|
</>
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
@ -61,7 +62,7 @@ pub fn ArcanistResult(ArcanistResultProps { alignment_eq }: &ArcanistResultProps
|
||||||
<h4 class="icons">
|
<h4 class="icons">
|
||||||
{icons}
|
{icons}
|
||||||
</h4>
|
</h4>
|
||||||
<h3 class="yellow">{text}</h3>
|
<h1 class="yellow">{text}</h1>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,18 +33,26 @@ pub fn PowerSeerResult(PowerSeerResultProps { powerful }: &PowerSeerResultProps)
|
||||||
Powerful::Powerful => "POWERFUL",
|
Powerful::Powerful => "POWERFUL",
|
||||||
Powerful::NotPowerful => "NOT POWERFUL",
|
Powerful::NotPowerful => "NOT POWERFUL",
|
||||||
};
|
};
|
||||||
|
let icon = match powerful {
|
||||||
|
Powerful::Powerful => html! {
|
||||||
|
<Icon
|
||||||
|
source={IconSource::Powerful}
|
||||||
|
icon_type={IconType::Informational}
|
||||||
|
/>
|
||||||
|
},
|
||||||
|
Powerful::NotPowerful => html! {
|
||||||
|
<Icon
|
||||||
|
source={IconSource::RedX}
|
||||||
|
icon_type={IconType::Informational}
|
||||||
|
/>
|
||||||
|
},
|
||||||
|
};
|
||||||
html! {
|
html! {
|
||||||
<div class="role-page">
|
<div class="role-page">
|
||||||
<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>
|
<h4>{icon}</h4>
|
||||||
<Icon
|
|
||||||
source={powerful.icon()}
|
|
||||||
icon_type={IconType::Informational}
|
|
||||||
inactive={powerful.powerful().not()}
|
|
||||||
/>
|
|
||||||
</h4>
|
|
||||||
<h3 class="yellow">{text}</h3>
|
<h3 class="yellow">{text}</h3>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue