maple wolf: show nights til starving
This commit is contained in:
parent
8e1d2e34d0
commit
9b19b51581
|
|
@ -482,7 +482,8 @@ impl Character {
|
||||||
}),
|
}),
|
||||||
Role::MapleWolf { last_kill_on_night } => prompts.push(ActionPrompt::MapleWolf {
|
Role::MapleWolf { last_kill_on_night } => prompts.push(ActionPrompt::MapleWolf {
|
||||||
character_id: self.identity(),
|
character_id: self.identity(),
|
||||||
kill_or_die: last_kill_on_night + MAPLE_WOLF_ABSTAIN_LIMIT.get() == night,
|
nights_til_starvation: (last_kill_on_night + MAPLE_WOLF_ABSTAIN_LIMIT.get())
|
||||||
|
- night,
|
||||||
living_players: village.living_players_excluding(self.character_id()),
|
living_players: village.living_players_excluding(self.character_id()),
|
||||||
marked: None,
|
marked: None,
|
||||||
}),
|
}),
|
||||||
|
|
|
||||||
|
|
@ -108,13 +108,13 @@ impl Night {
|
||||||
Some((
|
Some((
|
||||||
ActionPrompt::MapleWolf {
|
ActionPrompt::MapleWolf {
|
||||||
character_id,
|
character_id,
|
||||||
kill_or_die,
|
nights_til_starvation,
|
||||||
marked,
|
marked,
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
_,
|
_,
|
||||||
)) => {
|
)) => {
|
||||||
if *kill_or_die {
|
if *nights_til_starvation == 0 {
|
||||||
(character_id.character_id, *marked)
|
(character_id.character_id, *marked)
|
||||||
} else {
|
} else {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
|
|
||||||
|
|
@ -238,8 +238,8 @@ impl Night {
|
||||||
}
|
}
|
||||||
ActionPrompt::MapleWolf {
|
ActionPrompt::MapleWolf {
|
||||||
character_id,
|
character_id,
|
||||||
kill_or_die,
|
|
||||||
marked: Some(marked),
|
marked: Some(marked),
|
||||||
|
nights_til_starvation,
|
||||||
..
|
..
|
||||||
} => Ok(ResponseOutcome::ActionComplete(ActionComplete {
|
} => Ok(ResponseOutcome::ActionComplete(ActionComplete {
|
||||||
result: ActionResult::GoBackToSleep,
|
result: ActionResult::GoBackToSleep,
|
||||||
|
|
@ -248,7 +248,7 @@ impl Night {
|
||||||
died_to: DiedTo::MapleWolf {
|
died_to: DiedTo::MapleWolf {
|
||||||
night,
|
night,
|
||||||
source: character_id.character_id,
|
source: character_id.character_id,
|
||||||
starves_if_fails: *kill_or_die,
|
starves_if_fails: *nights_til_starvation == 0,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
})),
|
})),
|
||||||
|
|
|
||||||
|
|
@ -111,7 +111,7 @@ pub enum ActionPrompt {
|
||||||
#[checks(ActionType::Other)]
|
#[checks(ActionType::Other)]
|
||||||
MapleWolf {
|
MapleWolf {
|
||||||
character_id: CharacterIdentity,
|
character_id: CharacterIdentity,
|
||||||
kill_or_die: bool,
|
nights_til_starvation: u8,
|
||||||
living_players: Box<[CharacterIdentity]>,
|
living_players: Box<[CharacterIdentity]>,
|
||||||
marked: Option<CharacterId>,
|
marked: Option<CharacterId>,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -2412,3 +2412,14 @@ li.choice {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.inc-dec {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 20px;
|
||||||
|
|
||||||
|
.inc-dec-content {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,6 @@ pub mod host {
|
||||||
mod host;
|
mod host;
|
||||||
pub use host::*;
|
pub use host::*;
|
||||||
}
|
}
|
||||||
pub mod test_remote;
|
|
||||||
// mod socket;
|
|
||||||
|
|
||||||
const DEBUG_URL: &str = "ws://192.168.1.162:8080/connect/";
|
const DEBUG_URL: &str = "ws://192.168.1.162:8080/connect/";
|
||||||
const LIVE_URL: &str = "wss://wolf.emilis.dev/connect/";
|
const LIVE_URL: &str = "wss://wolf.emilis.dev/connect/";
|
||||||
|
|
|
||||||
|
|
@ -1,70 +0,0 @@
|
||||||
// Copyright (C) 2025 Emilis Bliūdžius
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Affero General Public License as
|
|
||||||
// published by the Free Software Foundation, either version 3 of the
|
|
||||||
// License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU Affero General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Affero General Public License
|
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
use futures::{SinkExt, StreamExt, TryStreamExt, lock::Mutex};
|
|
||||||
use gloo::net::websocket::{Message, futures::WebSocket};
|
|
||||||
use werewolves_proto::message::host::{HostLobbyMessage, HostMessage, ServerToHostMessage};
|
|
||||||
use yew::prelude::*;
|
|
||||||
|
|
||||||
use crate::test_util::TestScreens;
|
|
||||||
|
|
||||||
fn url() -> String {
|
|
||||||
format!(
|
|
||||||
"{}host",
|
|
||||||
option_env!("LOCAL")
|
|
||||||
.map(|_| crate::clients::DEBUG_URL)
|
|
||||||
.unwrap_or(crate::clients::LIVE_URL)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[function_component]
|
|
||||||
pub fn TestClientRemote() -> Html {
|
|
||||||
gloo::utils::document().set_title("werewolves — remote test");
|
|
||||||
let send = use_memo((), |_| Mutex::new(WebSocket::open(url().as_str()).unwrap()));
|
|
||||||
let send_cb = {
|
|
||||||
let send = send.clone();
|
|
||||||
Callback::from(move |msg: ServerToHostMessage| {
|
|
||||||
let send = send.clone();
|
|
||||||
yew::platform::spawn_local(async move {
|
|
||||||
send.lock()
|
|
||||||
.await
|
|
||||||
.send(gloo::net::websocket::Message::Bytes({
|
|
||||||
let mut v = Vec::new();
|
|
||||||
ciborium::into_writer(&HostMessage::Echo(msg.clone()), &mut v).unwrap();
|
|
||||||
v
|
|
||||||
}))
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
loop {
|
|
||||||
match send.lock().await.try_next().await {
|
|
||||||
Ok(Some(Message::Bytes(b))) => {
|
|
||||||
let recv: ServerToHostMessage =
|
|
||||||
ciborium::from_reader(b.as_slice()).unwrap();
|
|
||||||
if recv == msg {
|
|
||||||
log::debug!("recv'd echo");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(_) => panic!("got text message"),
|
|
||||||
Err(err) => panic!("{err}"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})
|
|
||||||
};
|
|
||||||
html! {
|
|
||||||
<TestScreens send={send_cb} />
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -375,14 +375,14 @@ pub fn Prompt(props: &ActionPromptProps) -> Html {
|
||||||
),
|
),
|
||||||
ActionPrompt::MapleWolf {
|
ActionPrompt::MapleWolf {
|
||||||
character_id,
|
character_id,
|
||||||
kill_or_die,
|
nights_til_starvation,
|
||||||
living_players,
|
living_players,
|
||||||
marked,
|
marked,
|
||||||
} => (
|
} => (
|
||||||
Some(character_id),
|
Some(character_id),
|
||||||
living_players,
|
living_players,
|
||||||
marked.iter().cloned().collect(),
|
marked.iter().cloned().collect(),
|
||||||
html! {<>{"maple wolf"} {kill_or_die.then_some(" — starving")}</>},
|
html! {<>{"maple wolf"} {(*nights_til_starvation == 0).then_some(" — starving")}</>},
|
||||||
),
|
),
|
||||||
ActionPrompt::WolfPackKill {
|
ActionPrompt::WolfPackKill {
|
||||||
living_villagers,
|
living_villagers,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
use core::ops::Range;
|
||||||
|
|
||||||
|
// 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 yew::prelude::*;
|
||||||
|
|
||||||
|
use crate::components::Button;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Properties)]
|
||||||
|
pub struct IncDecU8Props {
|
||||||
|
#[prop_or_default]
|
||||||
|
pub children: Html,
|
||||||
|
#[prop_or_default]
|
||||||
|
pub class: yew::Classes,
|
||||||
|
#[prop_or_default]
|
||||||
|
pub button_class: yew::Classes,
|
||||||
|
pub value: u8,
|
||||||
|
pub value_range: Range<u8>,
|
||||||
|
pub on_update: Callback<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[function_component]
|
||||||
|
pub fn IncDecU8(
|
||||||
|
IncDecU8Props {
|
||||||
|
children,
|
||||||
|
class,
|
||||||
|
button_class,
|
||||||
|
value,
|
||||||
|
value_range,
|
||||||
|
on_update,
|
||||||
|
}: &IncDecU8Props,
|
||||||
|
) -> Html {
|
||||||
|
let value_state = use_state(|| *value);
|
||||||
|
let dec_disabled = value_range
|
||||||
|
.clone()
|
||||||
|
.next()
|
||||||
|
.and_then(|start| (start >= *value).then_some(String::from("already at minimum")));
|
||||||
|
let dec = {
|
||||||
|
let current = *value;
|
||||||
|
let on_update = on_update.clone();
|
||||||
|
let value_state = value_state.setter();
|
||||||
|
Callback::from(move |_| {
|
||||||
|
let new = current.saturating_sub(1);
|
||||||
|
on_update.emit(new);
|
||||||
|
value_state.set(new);
|
||||||
|
})
|
||||||
|
};
|
||||||
|
let inc_disabled = value_range
|
||||||
|
.clone()
|
||||||
|
.last()
|
||||||
|
.and_then(|end| (*value >= end).then_some(String::from("already at max value")));
|
||||||
|
let inc = {
|
||||||
|
let current = *value;
|
||||||
|
let on_update = on_update.clone();
|
||||||
|
let value_state = value_state.setter();
|
||||||
|
Callback::from(move |_| {
|
||||||
|
let new = current.saturating_add(1);
|
||||||
|
on_update.emit(new);
|
||||||
|
value_state.set(new);
|
||||||
|
})
|
||||||
|
};
|
||||||
|
html! {
|
||||||
|
<div class={classes!("inc-dec", class.clone())}>
|
||||||
|
<Button
|
||||||
|
on_click={dec}
|
||||||
|
disabled_reason={dec_disabled}
|
||||||
|
classes={button_class.clone()}
|
||||||
|
>
|
||||||
|
{"decrease"}
|
||||||
|
</Button>
|
||||||
|
<div class="inc-dec-content">
|
||||||
|
<span class="inc-dec-count">{*value_state}</span>
|
||||||
|
{children.clone()}
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
on_click={inc}
|
||||||
|
disabled_reason={inc_disabled}
|
||||||
|
classes={button_class.clone()}
|
||||||
|
>
|
||||||
|
{"increase"}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -46,13 +46,9 @@ const BUILD_ID_LONG: &str = werewolves_macros::build_id_long!();
|
||||||
const BUILD_DIRTY: bool = werewolves_macros::build_dirty!();
|
const BUILD_DIRTY: bool = werewolves_macros::build_dirty!();
|
||||||
const BUILD_TIME: &str = werewolves_macros::build_time!();
|
const BUILD_TIME: &str = werewolves_macros::build_time!();
|
||||||
|
|
||||||
use crate::{
|
use crate::clients::{
|
||||||
clients::{
|
client::{Client2, ClientContext},
|
||||||
client::{Client2, ClientContext},
|
host::{Host, HostEvent},
|
||||||
host::{Host, HostEvent},
|
|
||||||
test_remote::TestClientRemote,
|
|
||||||
},
|
|
||||||
test_util::TestScreens,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
@ -70,9 +66,7 @@ fn main() {
|
||||||
let error_callback =
|
let error_callback =
|
||||||
Callback::from(move |err: Option<WerewolfError>| cb_clone.send_message(err));
|
Callback::from(move |err: Option<WerewolfError>| cb_clone.send_message(err));
|
||||||
|
|
||||||
if path.starts_with("/host/test") {
|
if path.starts_with("/host") {
|
||||||
yew::Renderer::<TestClientRemote>::with_root(app_element).render();
|
|
||||||
} else if path.starts_with("/host") {
|
|
||||||
let host = yew::Renderer::<Host>::with_root(app_element).render();
|
let host = yew::Renderer::<Host>::with_root(app_element).render();
|
||||||
if path.starts_with("/host/big") {
|
if path.starts_with("/host/big") {
|
||||||
host.send_message(HostEvent::SetBigScreenState(true));
|
host.send_message(HostEvent::SetBigScreenState(true));
|
||||||
|
|
|
||||||
|
|
@ -109,14 +109,16 @@ impl RolePage for ActionPrompt {
|
||||||
}]),
|
}]),
|
||||||
ActionPrompt::MapleWolf {
|
ActionPrompt::MapleWolf {
|
||||||
character_id,
|
character_id,
|
||||||
kill_or_die,
|
nights_til_starvation,
|
||||||
..
|
..
|
||||||
} => Rc::new([html! {
|
} => [html! {
|
||||||
<>
|
<>
|
||||||
{ident(character_id)}
|
{ident(character_id)}
|
||||||
<MapleWolfPage1 starving={*kill_or_die} />
|
<MapleWolfPage1 nights_til_starvation={*nights_til_starvation} />
|
||||||
</>
|
</>
|
||||||
}]),
|
}]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
ActionPrompt::MasonLeaderRecruit {
|
ActionPrompt::MasonLeaderRecruit {
|
||||||
character_id,
|
character_id,
|
||||||
recruits_left,
|
recruits_left,
|
||||||
|
|
|
||||||
|
|
@ -17,27 +17,45 @@ use yew::prelude::*;
|
||||||
use crate::components::{Icon, IconSource, IconType};
|
use crate::components::{Icon, IconSource, IconType};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Properties)]
|
#[derive(Debug, Clone, Copy, PartialEq, Properties)]
|
||||||
pub struct MapleWolfPage1Props {
|
pub struct MapleWolfPageProps {
|
||||||
pub starving: bool,
|
pub nights_til_starvation: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[function_component]
|
#[function_component]
|
||||||
pub fn MapleWolfPage1(MapleWolfPage1Props { starving }: &MapleWolfPage1Props) -> Html {
|
pub fn MapleWolfPage1(
|
||||||
let starving = starving
|
MapleWolfPageProps {
|
||||||
.then_some(html! {
|
nights_til_starvation,
|
||||||
|
}: &MapleWolfPageProps,
|
||||||
|
) -> Html {
|
||||||
|
let food_state = if *nights_til_starvation == 0 {
|
||||||
|
html! {
|
||||||
<div>
|
<div>
|
||||||
<h3 class="red">{"YOU ARE STARVING"}</h3>
|
<h3 class="red">{"YOU ARE STARVING"}</h3>
|
||||||
<h3>{"IF YOU FAIL TO EAT TONIGHT, YOU WILL DIE"}</h3>
|
<h3>{"IF YOU FAIL TO EAT TONIGHT, YOU WILL DIE"}</h3>
|
||||||
</div>
|
</div>
|
||||||
})
|
}
|
||||||
.unwrap_or_else(|| {
|
} else {
|
||||||
|
let nights = if *nights_til_starvation == 1 {
|
||||||
html! {
|
html! {
|
||||||
<h3>
|
<>
|
||||||
{"IF YOU DON'T EAT FOR TOO LONG, YOU WILL "}
|
<span class="red">{"TOMORROW NIGHT "}</span>
|
||||||
<span class="red">{"STARVE"}</span>
|
</>
|
||||||
</h3>
|
|
||||||
}
|
}
|
||||||
});
|
} else {
|
||||||
|
html! {
|
||||||
|
<>
|
||||||
|
{"IN "}<span class="red">{*nights_til_starvation}</span>{" NIGHTS "}
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
};
|
||||||
|
html! {
|
||||||
|
<h3>
|
||||||
|
{"IF YOU FAIL TO EAT "}
|
||||||
|
{nights}
|
||||||
|
{"YOU WILL "}<span class="yellow">{"STARVE"}</span>
|
||||||
|
</h3>
|
||||||
|
}
|
||||||
|
};
|
||||||
html! {
|
html! {
|
||||||
<div class="role-page">
|
<div class="role-page">
|
||||||
<h1 class="offensive">{"MAPLE WOLF"}</h1>
|
<h1 class="offensive">{"MAPLE WOLF"}</h1>
|
||||||
|
|
@ -48,7 +66,7 @@ pub fn MapleWolfPage1(MapleWolfPage1Props { starving }: &MapleWolfPage1Props) ->
|
||||||
<div class="info-icon-grow">
|
<div class="info-icon-grow">
|
||||||
<Icon source={IconSource::MapleWolf} icon_type={IconType::Fit}/>
|
<Icon source={IconSource::MapleWolf} icon_type={IconType::Fit}/>
|
||||||
</div>
|
</div>
|
||||||
{starving}
|
{food_state}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,10 +21,8 @@ use werewolves_proto::{
|
||||||
diedto::DiedToTitle,
|
diedto::DiedToTitle,
|
||||||
message::{
|
message::{
|
||||||
CharacterIdentity,
|
CharacterIdentity,
|
||||||
host::{HostMessage, ServerToHostMessage},
|
host::ServerToHostMessage,
|
||||||
night::{
|
night::{ActionPrompt, ActionPromptTitle, ActionResult, ActionResultTitle, Visits},
|
||||||
ActionPrompt, ActionPromptTitle, ActionResult, ActionResultTitle, ActionType, Visits,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
role::{Alignment, AlignmentEq, Killer, Powerful, RoleTitle},
|
role::{Alignment, AlignmentEq, Killer, Powerful, RoleTitle},
|
||||||
};
|
};
|
||||||
|
|
@ -304,7 +302,7 @@ impl From<ActionPromptTitle> for TestScreen {
|
||||||
},
|
},
|
||||||
ActionPromptTitle::MapleWolf => ActionPrompt::MapleWolf {
|
ActionPromptTitle::MapleWolf => ActionPrompt::MapleWolf {
|
||||||
character_id: identities(1).into_iter().next().unwrap(),
|
character_id: identities(1).into_iter().next().unwrap(),
|
||||||
kill_or_die: false,
|
nights_til_starvation: 0,
|
||||||
living_players: identities(20),
|
living_players: identities(20),
|
||||||
marked: None,
|
marked: None,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -18,15 +18,15 @@ use core::num::NonZeroU8;
|
||||||
|
|
||||||
use web_sys::HtmlSelectElement;
|
use web_sys::HtmlSelectElement;
|
||||||
use werewolves_proto::{
|
use werewolves_proto::{
|
||||||
message::{
|
message::{host::ServerToHostMessage, night::ActionPrompt},
|
||||||
host::{HostGameMessage, HostMessage, HostNightMessage, ServerToHostMessage},
|
|
||||||
night::ActionPrompt,
|
|
||||||
},
|
|
||||||
player::RoleChange,
|
|
||||||
role::{PreviousGuardianAction, RoleTitle},
|
role::{PreviousGuardianAction, RoleTitle},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{components::Button, pages::RolePage, test_util::identities};
|
use crate::{
|
||||||
|
components::{Button, IncDecU8},
|
||||||
|
pages::RolePage,
|
||||||
|
test_util::identities,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Properties)]
|
#[derive(Debug, Clone, PartialEq, Properties)]
|
||||||
pub struct PromptScreenTestProps {
|
pub struct PromptScreenTestProps {
|
||||||
|
|
@ -47,30 +47,11 @@ pub fn PromptScreenTest(
|
||||||
) -> Html {
|
) -> Html {
|
||||||
let options = match prompt {
|
let options = match prompt {
|
||||||
ActionPrompt::WolvesIntro { wolves } => {
|
ActionPrompt::WolvesIntro { wolves } => {
|
||||||
let dec_disabled = wolves
|
let on_update = {
|
||||||
.is_empty()
|
|
||||||
.then_some(String::from("already have zero wolves"));
|
|
||||||
let dec = {
|
|
||||||
let current = wolves.len();
|
|
||||||
let send = send.clone();
|
let send = send.clone();
|
||||||
Callback::from(move |_| {
|
Callback::from(move |new_count: u8| {
|
||||||
let new_prompt = ActionPrompt::WolvesIntro {
|
let new_prompt = ActionPrompt::WolvesIntro {
|
||||||
wolves: super::identities(current - 1)
|
wolves: super::identities(new_count as _)
|
||||||
.into_iter()
|
|
||||||
.zip(RoleTitle::ALL.into_iter().filter(|w| w.wolf()).cycle())
|
|
||||||
.collect(),
|
|
||||||
};
|
|
||||||
send.emit(ServerToHostMessage::ActionPrompt(new_prompt.clone(), 0));
|
|
||||||
})
|
|
||||||
};
|
|
||||||
let inc_disabled =
|
|
||||||
(wolves.len() + 1 > 0xFF).then_some(String::from("already at max wolves"));
|
|
||||||
let inc = {
|
|
||||||
let current = wolves.len();
|
|
||||||
let send = send.clone();
|
|
||||||
Callback::from(move |_| {
|
|
||||||
let new_prompt = ActionPrompt::WolvesIntro {
|
|
||||||
wolves: super::identities(current + 1)
|
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.zip(RoleTitle::ALL.into_iter().filter(|w| w.wolf()).cycle())
|
.zip(RoleTitle::ALL.into_iter().filter(|w| w.wolf()).cycle())
|
||||||
.collect(),
|
.collect(),
|
||||||
|
|
@ -79,21 +60,13 @@ pub fn PromptScreenTest(
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
html! {
|
html! {
|
||||||
<div class="prompt-number">
|
<IncDecU8
|
||||||
<Button
|
value={wolves.len() as u8}
|
||||||
on_click={dec}
|
value_range={1..0xFF}
|
||||||
disabled_reason={dec_disabled}
|
on_update={on_update}
|
||||||
>
|
>
|
||||||
{"decrease"}
|
{" wolves"}
|
||||||
</Button>
|
</IncDecU8>
|
||||||
<label>{wolves.len()}{" wolves"}</label>
|
|
||||||
<Button
|
|
||||||
on_click={inc}
|
|
||||||
disabled_reason={inc_disabled}
|
|
||||||
>
|
|
||||||
{"increase"}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ActionPrompt::RoleChange { new_role, .. } => {
|
ActionPrompt::RoleChange { new_role, .. } => {
|
||||||
|
|
@ -194,14 +167,16 @@ pub fn PromptScreenTest(
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ActionPrompt::MapleWolf { kill_or_die, .. } => {
|
ActionPrompt::MapleWolf {
|
||||||
let toggle = !*kill_or_die;
|
nights_til_starvation,
|
||||||
let on_toggle = {
|
..
|
||||||
|
} => {
|
||||||
|
let on_update = {
|
||||||
let send = send.clone();
|
let send = send.clone();
|
||||||
Callback::from(move |_| {
|
Callback::from(move |new_nights: u8| {
|
||||||
let new_prompt = ActionPrompt::MapleWolf {
|
let new_prompt = ActionPrompt::MapleWolf {
|
||||||
character_id: super::identity(),
|
character_id: super::identity(),
|
||||||
kill_or_die: toggle,
|
nights_til_starvation: new_nights,
|
||||||
living_players: identities(20),
|
living_players: identities(20),
|
||||||
marked: None,
|
marked: None,
|
||||||
};
|
};
|
||||||
|
|
@ -209,14 +184,15 @@ pub fn PromptScreenTest(
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
let button_text = if toggle {
|
|
||||||
"turn starving"
|
|
||||||
} else {
|
|
||||||
"feed the poor boy"
|
|
||||||
};
|
|
||||||
html! {
|
html! {
|
||||||
<div class="prompt-options">
|
<div class="prompt-options">
|
||||||
<Button on_click={on_toggle}>{button_text}</Button>
|
<IncDecU8
|
||||||
|
value={*nights_til_starvation}
|
||||||
|
value_range={0..0xFF}
|
||||||
|
on_update={on_update}
|
||||||
|
>
|
||||||
|
{" nights"}
|
||||||
|
</IncDecU8>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -284,75 +260,33 @@ pub fn PromptScreenTest(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ActionPrompt::MasonsWake { masons, .. } => {
|
ActionPrompt::MasonsWake { masons, .. } => {
|
||||||
let dec_disabled =
|
let on_update = {
|
||||||
(masons.len() == 1).then_some(String::from("already at min recruits"));
|
|
||||||
let dec = {
|
|
||||||
let current = masons.len();
|
|
||||||
let send = send.clone();
|
let send = send.clone();
|
||||||
Callback::from(move |_| {
|
Callback::from(move |new_count: u8| {
|
||||||
let new_prompt = ActionPrompt::MasonsWake {
|
let new_prompt = ActionPrompt::MasonsWake {
|
||||||
leader: super::identity(),
|
leader: super::identity(),
|
||||||
masons: super::identities(current.saturating_sub(1)),
|
masons: super::identities(new_count as _),
|
||||||
};
|
|
||||||
send.emit(ServerToHostMessage::ActionPrompt(new_prompt.clone(), 0));
|
|
||||||
})
|
|
||||||
};
|
|
||||||
let inc_disabled =
|
|
||||||
(masons.len() > 0xFF).then_some(String::from("already at max wolves"));
|
|
||||||
let inc = {
|
|
||||||
let current = masons.len();
|
|
||||||
let send = send.clone();
|
|
||||||
Callback::from(move |_| {
|
|
||||||
let new_prompt = ActionPrompt::MasonsWake {
|
|
||||||
leader: super::identity(),
|
|
||||||
masons: super::identities(current.saturating_add(1)),
|
|
||||||
};
|
};
|
||||||
send.emit(ServerToHostMessage::ActionPrompt(new_prompt.clone(), 0));
|
send.emit(ServerToHostMessage::ActionPrompt(new_prompt.clone(), 0));
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
html! {
|
html! {
|
||||||
<div class="prompt-number">
|
<IncDecU8
|
||||||
<Button
|
value={masons.len() as u8}
|
||||||
on_click={dec}
|
value_range={1..0xFF}
|
||||||
disabled_reason={dec_disabled}
|
on_update={on_update}
|
||||||
>
|
>
|
||||||
{"decrease"}
|
{" masons"}
|
||||||
</Button>
|
</IncDecU8>
|
||||||
<label>{masons.len()}{" masons"}</label>
|
|
||||||
<Button
|
|
||||||
on_click={inc}
|
|
||||||
disabled_reason={inc_disabled}
|
|
||||||
>
|
|
||||||
{"increase"}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ActionPrompt::MasonLeaderRecruit { recruits_left, .. } => {
|
ActionPrompt::MasonLeaderRecruit { recruits_left, .. } => {
|
||||||
let dec_disabled =
|
let on_update = {
|
||||||
(recruits_left.get() == 1).then_some(String::from("already at min recruits"));
|
|
||||||
let dec = {
|
|
||||||
let current = recruits_left.get();
|
|
||||||
let send = send.clone();
|
let send = send.clone();
|
||||||
Callback::from(move |_| {
|
Callback::from(move |new_count: u8| {
|
||||||
let new_prompt = ActionPrompt::MasonLeaderRecruit {
|
let new_prompt = ActionPrompt::MasonLeaderRecruit {
|
||||||
character_id: super::identity(),
|
character_id: super::identity(),
|
||||||
recruits_left: NonZeroU8::new(current.saturating_sub(1)).unwrap(),
|
recruits_left: NonZeroU8::new(new_count).unwrap(),
|
||||||
potential_recruits: identities(20),
|
|
||||||
marked: None,
|
|
||||||
};
|
|
||||||
send.emit(ServerToHostMessage::ActionPrompt(new_prompt.clone(), 0));
|
|
||||||
})
|
|
||||||
};
|
|
||||||
let inc_disabled =
|
|
||||||
(recruits_left.get() == 0xFF).then_some(String::from("already at max wolves"));
|
|
||||||
let inc = {
|
|
||||||
let current = recruits_left.get();
|
|
||||||
let send = send.clone();
|
|
||||||
Callback::from(move |_| {
|
|
||||||
let new_prompt = ActionPrompt::MasonLeaderRecruit {
|
|
||||||
character_id: super::identity(),
|
|
||||||
recruits_left: NonZeroU8::new(current.saturating_add(1)).unwrap(),
|
|
||||||
potential_recruits: identities(20),
|
potential_recruits: identities(20),
|
||||||
marked: None,
|
marked: None,
|
||||||
};
|
};
|
||||||
|
|
@ -360,21 +294,13 @@ pub fn PromptScreenTest(
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
html! {
|
html! {
|
||||||
<div class="prompt-number">
|
<IncDecU8
|
||||||
<Button
|
value={recruits_left.get()}
|
||||||
on_click={dec}
|
value_range={1..0xFF}
|
||||||
disabled_reason={dec_disabled}
|
on_update={on_update}
|
||||||
>
|
>
|
||||||
{"decrease"}
|
{" recruits"}
|
||||||
</Button>
|
</IncDecU8>
|
||||||
<label>{recruits_left.get()}{" recruits"}</label>
|
|
||||||
<Button
|
|
||||||
on_click={inc}
|
|
||||||
disabled_reason={inc_disabled}
|
|
||||||
>
|
|
||||||
{"increase"}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue