binary choice for shapeshift, added better shapeshift handling
This commit is contained in:
parent
09039c21c1
commit
e704fdca8b
|
|
@ -343,6 +343,57 @@ impl Night {
|
|||
Ok(new_village)
|
||||
}
|
||||
|
||||
fn apply_shapeshift(&mut self, source: &CharacterId) -> Result<ActionResult> {
|
||||
if let Some(kill_target) = self.changes.iter().find_map(|c| match c {
|
||||
NightChange::Kill {
|
||||
target,
|
||||
died_to: DiedTo::Wolfpack { night: _ },
|
||||
} => Some(target.clone()),
|
||||
_ => None,
|
||||
}) {
|
||||
if self.changes.iter().any(|c| match c {
|
||||
NightChange::Protection {
|
||||
target,
|
||||
protection: _,
|
||||
} => target == &kill_target,
|
||||
_ => false,
|
||||
}) {
|
||||
// there is protection, so the kill doesn't happen -> no shapeshift
|
||||
return Ok(ActionResult::GoBackToSleep);
|
||||
}
|
||||
if let Some(kill) = self.changes.iter_mut().find(|c| {
|
||||
matches!(
|
||||
c,
|
||||
NightChange::Kill {
|
||||
target: _,
|
||||
died_to: DiedTo::Wolfpack { night: _ }
|
||||
}
|
||||
)
|
||||
}) {
|
||||
*kill = NightChange::Kill {
|
||||
target: source.clone(),
|
||||
died_to: DiedTo::Shapeshift {
|
||||
into: kill_target.clone(),
|
||||
night: NonZeroU8::new(self.night).unwrap(),
|
||||
},
|
||||
}
|
||||
}
|
||||
self.changes.push(NightChange::Shapeshift {
|
||||
source: source.clone(),
|
||||
});
|
||||
self.action_queue.push_front((
|
||||
ActionPrompt::RoleChange {
|
||||
new_role: RoleTitle::Werewolf,
|
||||
},
|
||||
self.village
|
||||
.find_by_character_id(&kill_target)
|
||||
.unwrap()
|
||||
.clone(),
|
||||
));
|
||||
}
|
||||
Ok(ActionResult::GoBackToSleep)
|
||||
}
|
||||
|
||||
pub fn received_response(&mut self, resp: ActionResponse) -> Result<ActionResult> {
|
||||
if let (
|
||||
NightState::Active {
|
||||
|
|
@ -367,6 +418,10 @@ impl Night {
|
|||
} => current_result.replace(result.clone()),
|
||||
NightState::Complete => return Err(GameError::NightOver),
|
||||
};
|
||||
if let NightChange::Shapeshift { source } = &change {
|
||||
// needs to be resolved _now_
|
||||
return self.apply_shapeshift(source);
|
||||
}
|
||||
self.changes.push(change);
|
||||
Ok(result)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -118,10 +118,7 @@ pub enum ActionResult {
|
|||
Seer(Alignment),
|
||||
Arcanist { same: bool },
|
||||
GraveDigger(Option<RoleTitle>),
|
||||
WolvesMustBeUnanimous,
|
||||
WaitForOthersToVote,
|
||||
GoBackToSleep,
|
||||
RoleRevealDone,
|
||||
WolvesIntroDone,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,6 +36,9 @@ impl CharacterId {
|
|||
pub fn new() -> Self {
|
||||
Self(uuid::Uuid::new_v4())
|
||||
}
|
||||
pub const fn from_u128(v: u128) -> Self {
|
||||
Self(uuid::Uuid::from_u128(v))
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for CharacterId {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
use yew::prelude::*;
|
||||
|
||||
use crate::components::Button;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Properties)]
|
||||
pub struct BinaryChoiceProps {
|
||||
pub on_chosen: Callback<bool>,
|
||||
#[prop_or_default]
|
||||
pub children: Html,
|
||||
}
|
||||
|
||||
#[function_component]
|
||||
pub fn BinaryChoice(
|
||||
BinaryChoiceProps {
|
||||
on_chosen,
|
||||
children,
|
||||
}: &BinaryChoiceProps,
|
||||
) -> Html {
|
||||
let on_chosen_yes = on_chosen.clone();
|
||||
let yes = move |_| on_chosen_yes.emit(true);
|
||||
let on_chosen = on_chosen.clone();
|
||||
let no = move |_| on_chosen.emit(false);
|
||||
html! {
|
||||
<div class="column-list">
|
||||
{children.clone()}
|
||||
<div class="row-list">
|
||||
<Button on_click={yes}>{"yes"}</Button>
|
||||
<Button on_click={no}>{"no"}</Button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
use core::ops::Not;
|
||||
use core::{num::NonZeroU8, ops::Not};
|
||||
|
||||
use werewolves_proto::{
|
||||
message::{
|
||||
|
|
@ -12,7 +12,7 @@ use yew::prelude::*;
|
|||
|
||||
use crate::components::{
|
||||
Identity,
|
||||
action::{SingleTarget, TargetSelection, WolvesIntro},
|
||||
action::{BinaryChoice, SingleTarget, TargetSelection, WolvesIntro},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Properties)]
|
||||
|
|
@ -162,7 +162,19 @@ pub fn Prompt(props: &ActionPromptProps) -> Html {
|
|||
</div>
|
||||
}
|
||||
}
|
||||
ActionPrompt::Shapeshifter => todo!(),
|
||||
ActionPrompt::Shapeshifter => {
|
||||
let on_complete = props.on_complete.clone();
|
||||
let on_select = move |shift| {
|
||||
on_complete.emit(HostMessage::InGame(HostGameMessage::Night(
|
||||
HostNightMessage::ActionResponse(ActionResponse::Shapeshifter(shift)),
|
||||
)));
|
||||
};
|
||||
html! {
|
||||
<BinaryChoice on_chosen={on_select}>
|
||||
<h2>{"shapeshift?"}</h2>
|
||||
</BinaryChoice>
|
||||
}
|
||||
}
|
||||
ActionPrompt::AlphaWolf { living_villagers } => {
|
||||
let on_complete = props.on_complete.clone();
|
||||
let on_select = props.big_screen.not().then(|| {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
use core::ops::Not;
|
||||
|
||||
use convert_case::{Case, Casing};
|
||||
use werewolves_proto::{
|
||||
message::{
|
||||
PublicIdentity,
|
||||
host::{HostGameMessage, HostMessage, HostNightMessage},
|
||||
night::{ActionPrompt, ActionResponse, ActionResult},
|
||||
night::ActionResult,
|
||||
},
|
||||
role::Alignment,
|
||||
};
|
||||
|
|
@ -58,10 +59,30 @@ pub fn ActionResultView(props: &ActionResultProps) -> Html {
|
|||
{cont}
|
||||
</div>
|
||||
},
|
||||
ActionResult::Arcanist { same } => todo!(),
|
||||
ActionResult::GraveDigger(role_title) => todo!(),
|
||||
ActionResult::WolvesMustBeUnanimous => todo!(),
|
||||
ActionResult::WaitForOthersToVote => todo!(),
|
||||
ActionResult::Arcanist { same } => {
|
||||
let outcome = if *same { "same" } else { "different" };
|
||||
html! {
|
||||
<div class="result">
|
||||
{ident}
|
||||
<h2>{"the alignments are:"}</h2>
|
||||
<p>{outcome}</p>
|
||||
{cont}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
ActionResult::GraveDigger(role_title) => {
|
||||
let dig = role_title
|
||||
.map(|r| r.to_string().to_case(Case::Title))
|
||||
.unwrap_or_else(|| String::from("an empty grave"));
|
||||
html! {
|
||||
<div class="result">
|
||||
{ident}
|
||||
<h2>{"you see:"}</h2>
|
||||
<p>{dig}</p>
|
||||
{cont}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
ActionResult::GoBackToSleep => {
|
||||
let next = props.big_screen.not().then(|| {
|
||||
let on_complete = props.on_complete.clone();
|
||||
|
|
@ -77,7 +98,6 @@ pub fn ActionResultView(props: &ActionResultProps) -> Html {
|
|||
</CoverOfDarkness>
|
||||
}
|
||||
}
|
||||
ActionResult::RoleRevealDone => todo!(),
|
||||
ActionResult::WolvesIntroDone => {
|
||||
let on_complete = props.on_complete.clone();
|
||||
let next = props.big_screen.not().then(|| {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use core::{fmt::Debug, marker::PhantomData, ops::Not};
|
||||
use core::fmt::Debug;
|
||||
|
||||
use werewolves_proto::{message::Target, player::CharacterId};
|
||||
use yew::prelude::*;
|
||||
|
|
@ -93,7 +93,7 @@ impl Component for SingleTarget {
|
|||
if self.selected.len() > 1 {
|
||||
None
|
||||
} else {
|
||||
let selected = self.selected.iter().next().cloned();
|
||||
let selected = self.selected.first().cloned();
|
||||
let on_click = on_click.clone();
|
||||
Some(Callback::from(move |_| on_click.emit(selected.clone())))
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue