beholder target roleblocked sees nothing
slightly nicer game end screen
This commit is contained in:
parent
a2013adea9
commit
ad29c3d59c
|
|
@ -282,6 +282,15 @@ pub enum GameOver {
|
||||||
WolvesWin,
|
WolvesWin,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for GameOver {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
GameOver::VillageWins => f.write_str("village wins"),
|
||||||
|
GameOver::WolvesWin => f.write_str("wolves win"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct Pool<T>
|
pub struct Pool<T>
|
||||||
where
|
where
|
||||||
|
|
|
||||||
|
|
@ -932,7 +932,7 @@ impl Night {
|
||||||
NightState::Active {
|
NightState::Active {
|
||||||
current_result: CurrentResult::Result(current_result),
|
current_result: CurrentResult::Result(current_result),
|
||||||
..
|
..
|
||||||
} => Some(¤t_result),
|
} => Some(current_result),
|
||||||
NightState::Active {
|
NightState::Active {
|
||||||
current_result: CurrentResult::GoBackToSleepAfterShown { .. },
|
current_result: CurrentResult::GoBackToSleepAfterShown { .. },
|
||||||
..
|
..
|
||||||
|
|
|
||||||
|
|
@ -395,10 +395,13 @@ impl Night {
|
||||||
if let Some(result) = self.used_actions.iter().find_map(|(prompt, result, _)| {
|
if let Some(result) = self.used_actions.iter().find_map(|(prompt, result, _)| {
|
||||||
prompt.matches_beholding(*marked).then_some(result)
|
prompt.matches_beholding(*marked).then_some(result)
|
||||||
}) && self.dies_tonight(*marked)?
|
}) && self.dies_tonight(*marked)?
|
||||||
&& !matches!(result, ActionResult::RoleBlocked)
|
|
||||||
{
|
{
|
||||||
Ok(ActionComplete {
|
Ok(ActionComplete {
|
||||||
result: result.clone(),
|
result: if matches!(result, ActionResult::RoleBlocked) {
|
||||||
|
ActionResult::BeholderSawNothing
|
||||||
|
} else {
|
||||||
|
result.clone()
|
||||||
|
},
|
||||||
change: None,
|
change: None,
|
||||||
}
|
}
|
||||||
.into())
|
.into())
|
||||||
|
|
|
||||||
|
|
@ -83,11 +83,13 @@ pub enum StoryActionResult {
|
||||||
Mortician(DiedToTitle),
|
Mortician(DiedToTitle),
|
||||||
Insomniac { visits: Box<[CharacterId]> },
|
Insomniac { visits: Box<[CharacterId]> },
|
||||||
Empath { scapegoat: bool },
|
Empath { scapegoat: bool },
|
||||||
|
BeholderSawNothing,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StoryActionResult {
|
impl StoryActionResult {
|
||||||
pub fn new(result: ActionResult) -> Option<Self> {
|
pub fn new(result: ActionResult) -> Option<Self> {
|
||||||
Some(match result {
|
Some(match result {
|
||||||
|
ActionResult::BeholderSawNothing => Self::BeholderSawNothing,
|
||||||
ActionResult::RoleBlocked => Self::RoleBlocked,
|
ActionResult::RoleBlocked => Self::RoleBlocked,
|
||||||
ActionResult::Seer(alignment) => Self::Seer(alignment),
|
ActionResult::Seer(alignment) => Self::Seer(alignment),
|
||||||
ActionResult::PowerSeer { powerful } => Self::PowerSeer { powerful },
|
ActionResult::PowerSeer { powerful } => Self::PowerSeer { powerful },
|
||||||
|
|
|
||||||
|
|
@ -484,6 +484,7 @@ pub enum ActionResult {
|
||||||
Mortician(DiedToTitle),
|
Mortician(DiedToTitle),
|
||||||
Insomniac(Visits),
|
Insomniac(Visits),
|
||||||
Empath { scapegoat: bool },
|
Empath { scapegoat: bool },
|
||||||
|
BeholderSawNothing,
|
||||||
GoBackToSleep,
|
GoBackToSleep,
|
||||||
Continue,
|
Continue,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1306,7 +1306,10 @@ input {
|
||||||
margin-top: 2%;
|
margin-top: 2%;
|
||||||
font-size: 1.5vw;
|
font-size: 1.5vw;
|
||||||
|
|
||||||
|
height: 100vh;
|
||||||
|
|
||||||
.setup {
|
.setup {
|
||||||
|
height: 85%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
|
@ -1322,6 +1325,7 @@ input {
|
||||||
|
|
||||||
&.final {
|
&.final {
|
||||||
margin-top: 1cm;
|
margin-top: 1cm;
|
||||||
|
margin-bottom: 1cm;
|
||||||
}
|
}
|
||||||
|
|
||||||
& .title {
|
& .title {
|
||||||
|
|
@ -1870,3 +1874,26 @@ input {
|
||||||
font-size: 3rem;
|
font-size: 3rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.victory {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 3vw;
|
||||||
|
height: max-content;
|
||||||
|
gap: 1cm;
|
||||||
|
padding: 1cm;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.end-screen {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ use yew::{html::Scope, prelude::*};
|
||||||
use crate::{
|
use crate::{
|
||||||
callback,
|
callback,
|
||||||
components::{
|
components::{
|
||||||
Button, CoverOfDarkness, Lobby, LobbyPlayerAction, RoleReveal, Settings, Story,
|
Button, CoverOfDarkness, Lobby, LobbyPlayerAction, RoleReveal, Settings, Story, Victory,
|
||||||
action::{ActionResultView, Prompt},
|
action::{ActionResultView, Prompt},
|
||||||
host::{DaytimePlayerList, Setup},
|
host::{DaytimePlayerList, Setup},
|
||||||
},
|
},
|
||||||
|
|
@ -312,15 +312,26 @@ impl Component for Host {
|
||||||
log::trace!("state: {:?}", self.state);
|
log::trace!("state: {:?}", self.state);
|
||||||
let content = match self.state.clone() {
|
let content = match self.state.clone() {
|
||||||
HostState::Story { story, page } => {
|
HostState::Story { story, page } => {
|
||||||
let new_lobby_click = crate::callback::send_message(
|
if let Some(outcome) = story
|
||||||
HostMessage::PostGame(PostGameMessage::NewLobby),
|
.final_village()
|
||||||
self.send.clone(),
|
.ok()
|
||||||
);
|
.and_then(|village| village.is_game_over())
|
||||||
html! {
|
&& self.big_screen
|
||||||
<div class="post-game">
|
{
|
||||||
|
html! {
|
||||||
|
<Victory outcome={outcome}/>
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let new_lobby_click = crate::callback::send_message(
|
||||||
|
HostMessage::PostGame(PostGameMessage::NewLobby),
|
||||||
|
self.send.clone(),
|
||||||
|
);
|
||||||
|
html! {
|
||||||
|
<div class="post-game">
|
||||||
<Story story={story} />
|
<Story story={story} />
|
||||||
<Button on_click={new_lobby_click}>{"new lobby"}</Button>
|
<Button on_click={new_lobby_click}>{"new lobby"}</Button>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HostState::GameOver { result } => {
|
HostState::GameOver { result } => {
|
||||||
|
|
@ -332,15 +343,7 @@ impl Component for Host {
|
||||||
});
|
});
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<CoverOfDarkness
|
<Victory outcome={result} cont={cont}/>
|
||||||
message={match result {
|
|
||||||
GameOver::VillageWins => "village wins",
|
|
||||||
GameOver::WolvesWin => "wolves win",
|
|
||||||
}}
|
|
||||||
next={cont}
|
|
||||||
>
|
|
||||||
{"continue"}
|
|
||||||
</CoverOfDarkness>
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HostState::Disconnected => html! {
|
HostState::Disconnected => html! {
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,8 @@ use yew::prelude::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
components::{Button, CoverOfDarkness, Icon, IconSource, Identity},
|
components::{Button, CoverOfDarkness, Icon, IconSource, Identity},
|
||||||
pages::{
|
pages::{
|
||||||
AdjudicatorResult, ArcanistResult, EmpathResult, GravediggerResultPage, InsomniacResult,
|
AdjudicatorResult, ArcanistResult, BeholderSawNothing, EmpathResult, GravediggerResultPage,
|
||||||
MorticianResultPage, PowerSeerResult, RoleblockPage, SeerResult,
|
InsomniacResult, MorticianResultPage, PowerSeerResult, RoleblockPage, SeerResult,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -58,6 +58,9 @@ pub fn ActionResultView(props: &ActionResultProps) -> Html {
|
||||||
.not()
|
.not()
|
||||||
.then(|| html! {<Button on_click={on_continue}>{"continue"}</Button>});
|
.then(|| html! {<Button on_click={on_continue}>{"continue"}</Button>});
|
||||||
let body = match &props.result {
|
let body = match &props.result {
|
||||||
|
ActionResult::BeholderSawNothing => html! {
|
||||||
|
<BeholderSawNothing />
|
||||||
|
},
|
||||||
ActionResult::PowerSeer { powerful } => {
|
ActionResult::PowerSeer { powerful } => {
|
||||||
html! {
|
html! {
|
||||||
<PowerSeerResult powerful={*powerful}/>
|
<PowerSeerResult powerful={*powerful}/>
|
||||||
|
|
|
||||||
|
|
@ -274,6 +274,9 @@ struct StoryNightResultProps {
|
||||||
#[function_component]
|
#[function_component]
|
||||||
fn StoryNightResult(StoryNightResultProps { result, characters }: &StoryNightResultProps) -> Html {
|
fn StoryNightResult(StoryNightResultProps { result, characters }: &StoryNightResultProps) -> Html {
|
||||||
match result {
|
match result {
|
||||||
|
StoryActionResult::BeholderSawNothing => html!{
|
||||||
|
<span>{"but saw nothing"}</span>
|
||||||
|
},
|
||||||
StoryActionResult::RoleBlocked => html! {
|
StoryActionResult::RoleBlocked => html! {
|
||||||
<span>{"but was role blocked"}</span>
|
<span>{"but was role blocked"}</span>
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
use werewolves_proto::game::GameOver;
|
||||||
|
use yew::prelude::*;
|
||||||
|
|
||||||
|
use crate::components::{Button, Icon, IconSource, IconType};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Properties)]
|
||||||
|
pub struct VictoryProps {
|
||||||
|
pub outcome: GameOver,
|
||||||
|
#[prop_or_default]
|
||||||
|
pub cont: Option<Callback<()>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[function_component]
|
||||||
|
pub fn Victory(VictoryProps { outcome, cont }: &VictoryProps) -> Html {
|
||||||
|
let cont_btn = cont.clone().map(|cont| {
|
||||||
|
html! {
|
||||||
|
<Button on_click={cont}>{"continue"}</Button>
|
||||||
|
}
|
||||||
|
});
|
||||||
|
match outcome {
|
||||||
|
GameOver::WolvesWin => html! {
|
||||||
|
<div class="end-screen">
|
||||||
|
<div class="victory wolves faint">
|
||||||
|
<Icon source={IconSource::Wolves} icon_type={IconType::Informational}/>
|
||||||
|
<h1>{"Wolves Win"}</h1>
|
||||||
|
<Icon source={IconSource::Wolves} icon_type={IconType::Informational}/>
|
||||||
|
</div>
|
||||||
|
{cont_btn}
|
||||||
|
</div>
|
||||||
|
},
|
||||||
|
GameOver::VillageWins => html! {
|
||||||
|
<div class="end-screen">
|
||||||
|
<div class="victory village faint">
|
||||||
|
<Icon source={IconSource::Village} icon_type={IconType::Informational}/>
|
||||||
|
<h1>{"Village Wins"}</h1>
|
||||||
|
<Icon source={IconSource::Village} icon_type={IconType::Informational}/>
|
||||||
|
</div>
|
||||||
|
{cont_btn}
|
||||||
|
</div>
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -14,6 +14,8 @@
|
||||||
// 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 yew::prelude::*;
|
use yew::prelude::*;
|
||||||
|
|
||||||
|
use crate::components::{Icon, IconSource, IconType};
|
||||||
|
|
||||||
#[function_component]
|
#[function_component]
|
||||||
pub fn BeholderPage1() -> Html {
|
pub fn BeholderPage1() -> Html {
|
||||||
html! {
|
html! {
|
||||||
|
|
@ -27,3 +29,17 @@ pub fn BeholderPage1() -> Html {
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[function_component]
|
||||||
|
pub fn BeholderSawNothing() -> Html {
|
||||||
|
html! {
|
||||||
|
<div class="role-page">
|
||||||
|
<h1 class="intel">{"BEHOLDER"}</h1>
|
||||||
|
<div class="information intel faint">
|
||||||
|
<h1>{"YOUR TARGET HAS DIED"}</h1>
|
||||||
|
<h1><Icon source={IconSource::RedX} icon_type={IconType::Informational}/></h1>
|
||||||
|
<h1>{"BUT SAW NOTHING"}</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue