front-end: Impl Reset button

This commit is contained in:
Stephen Seo 2022-04-25 15:02:18 +09:00
parent d55e43cc6c
commit b26c9ff6d1
2 changed files with 150 additions and 57 deletions

View file

@ -188,6 +188,12 @@
opacity: 1; opacity: 1;
} }
} }
button#resetbutton {
background-color: #C55;
color: #FFF;
grid-row: 2;
grid-column: 8;
}
</style> </style>
</head> </head>
</html> </html>

View file

@ -52,66 +52,62 @@ impl Component for MainMenu {
.link() .link()
.context::<SharedState>(Callback::noop()) .context::<SharedState>(Callback::noop())
.expect("state to be set"); .expect("state to be set");
match shared.game_state.get() { let player_type: Turn;
GameState::MainMenu => { {
let player_type: Turn; let mut rng = get_seeded_random().expect("Random should be available");
{ player_type = if rng.rand_range(0..2) == 0 {
let mut rng = get_seeded_random().expect("Random should be available"); Turn::CyanPlayer
player_type = if rng.rand_range(0..2) == 0 { } else {
Turn::CyanPlayer Turn::MagentaPlayer
} else { };
Turn::MagentaPlayer }
};
}
let easy_player_type = player_type; let easy_player_type = player_type;
let normal_player_type = player_type; let normal_player_type = player_type;
let hard_player_type = player_type; let hard_player_type = player_type;
let onclick_singleplayer_easy = ctx.link().callback(move |_| { let onclick_singleplayer_easy = ctx
MainMenuMessage::SinglePlayer(easy_player_type, AIDifficulty::Easy) .link()
}); .callback(move |_| MainMenuMessage::SinglePlayer(easy_player_type, AIDifficulty::Easy));
let onclick_singleplayer_normal = ctx.link().callback(move |_| { let onclick_singleplayer_normal = ctx.link().callback(move |_| {
MainMenuMessage::SinglePlayer(normal_player_type, AIDifficulty::Normal) MainMenuMessage::SinglePlayer(normal_player_type, AIDifficulty::Normal)
}); });
let onclick_singleplayer_hard = ctx.link().callback(move |_| { let onclick_singleplayer_hard = ctx
MainMenuMessage::SinglePlayer(hard_player_type, AIDifficulty::Hard) .link()
}); .callback(move |_| MainMenuMessage::SinglePlayer(hard_player_type, AIDifficulty::Hard));
let onclick_local_multiplayer = let onclick_local_multiplayer = ctx.link().callback(|_| MainMenuMessage::LocalMultiplayer);
ctx.link().callback(|_| MainMenuMessage::LocalMultiplayer);
let onclick_networked_multiplayer = ctx let onclick_networked_multiplayer = ctx
.link() .link()
.callback(|_| MainMenuMessage::NetworkedMultiplayer); .callback(|_| MainMenuMessage::NetworkedMultiplayer);
html! { let menu_class = if shared.game_state.get() == GameState::MainMenu {
<div class={"menu"} id={"mainmenu"}> "menu"
<b class={"menuText"}>{"Please pick a game mode."}</b> } else {
<div class={"singlePlayerMenu"}> "hidden_menu"
<button class={"menuSinglePlayerEasy"} onclick={onclick_singleplayer_easy}> };
{"Singleplayer Easy"} html! {
</button> <div class={menu_class} id={"mainmenu"}>
<button class={"menuSinglePlayerNormal"} onclick={onclick_singleplayer_normal}> <b class={"menuText"}>{"Please pick a game mode."}</b>
{"Singleplayer Normal"} <div class={"singlePlayerMenu"}>
</button> <button class={"menuSinglePlayerEasy"} onclick={onclick_singleplayer_easy}>
<button class={"menuSinglePlayerHard"} onclick={onclick_singleplayer_hard}> {"Singleplayer Easy"}
{"Singleplayer Hard"} </button>
</button> <button class={"menuSinglePlayerNormal"} onclick={onclick_singleplayer_normal}>
</div> {"Singleplayer Normal"}
<button class={"menuLocalMultiplayer"} onclick={onclick_local_multiplayer}> </button>
{"Local Multiplayer"} <button class={"menuSinglePlayerHard"} onclick={onclick_singleplayer_hard}>
</button> {"Singleplayer Hard"}
<button class={"menuMultiplayer"} onclick={onclick_networked_multiplayer}> </button>
{"Networked Multiplayer"}
</button>
</div>
}
}
_ => html! {
<div class={"hidden_menu"} id={"mainmenu"}>
</div> </div>
}, <button class={"menuLocalMultiplayer"} onclick={onclick_local_multiplayer}>
{"Local Multiplayer"}
</button>
<button class={"menuMultiplayer"} onclick={onclick_networked_multiplayer}>
{"Networked Multiplayer"}
</button>
</div>
} }
} }
@ -129,7 +125,6 @@ impl Component for MainMenu {
.get_element_by_id("mainmenu") .get_element_by_id("mainmenu")
.expect("mainmenu should exist"); .expect("mainmenu should exist");
mainmenu.set_class_name("hidden_menu"); mainmenu.set_class_name("hidden_menu");
mainmenu.set_inner_html("");
match shared.game_state.get() { match shared.game_state.get() {
GameState::SinglePlayer(turn, _) => { GameState::SinglePlayer(turn, _) => {
@ -176,7 +171,7 @@ impl Component for MainMenu {
.expect("Wrapper should be a parent of MainMenu") .expect("Wrapper should be a parent of MainMenu")
.clone() .clone()
.downcast::<Wrapper>() .downcast::<Wrapper>()
.send_message(WrapperMsg::BackendTick); .send_message(WrapperMsg::StartBackendTick);
} }
_ => { _ => {
append_to_info_text( append_to_info_text(
@ -194,6 +189,36 @@ impl Component for MainMenu {
} }
} }
struct ResetButton {}
impl Component for ResetButton {
type Message = ();
type Properties = ();
fn create(_ctx: &Context<Self>) -> Self {
Self {}
}
fn view(&self, ctx: &Context<Self>) -> Html {
let onclick_reset = ctx.link().callback(|_| ());
html! {
<button class={"resetbutton"} id={"resetbutton"} onclick={onclick_reset}>
{"Reset"}
</button>
}
}
fn update(&mut self, ctx: &Context<Self>, _msg: Self::Message) -> bool {
ctx.link()
.get_parent()
.expect("Wrapper should be parent of ResetButton")
.clone()
.downcast::<Wrapper>()
.send_message(WrapperMsg::Reset);
true
}
}
pub struct Slot {} pub struct Slot {}
pub enum SlotMessage { pub enum SlotMessage {
@ -575,6 +600,8 @@ pub enum WrapperMsg {
AIPressed(u8), AIPressed(u8),
AIChoice, AIChoice,
AIChoiceImpl, AIChoiceImpl,
StartBackendTick,
StartBackendTickImpl,
BackendTick, BackendTick,
BackendRequest { place: u8 }, BackendRequest { place: u8 },
BackendResponse(BREnum), BackendResponse(BREnum),
@ -607,6 +634,7 @@ impl Component for Wrapper {
html! { html! {
<div class="wrapper"> <div class="wrapper">
<MainMenu /> <MainMenu />
<ResetButton />
<Slot idx=0 state={shared.board[0].clone()} placed={shared.placed[0].clone()} /> <Slot idx=0 state={shared.board[0].clone()} placed={shared.placed[0].clone()} />
<Slot idx=1 state={shared.board[1].clone()} placed={shared.placed[1].clone()} /> <Slot idx=1 state={shared.board[1].clone()} placed={shared.placed[1].clone()} />
<Slot idx=2 state={shared.board[2].clone()} placed={shared.placed[2].clone()} /> <Slot idx=2 state={shared.board[2].clone()} placed={shared.placed[2].clone()} />
@ -1175,8 +1203,44 @@ impl Component for Wrapper {
} }
} }
} }
WrapperMsg::StartBackendTick => {
self.defer_message(
ctx,
WrapperMsg::StartBackendTickImpl,
BACKEND_TICK_DURATION_MILLIS,
);
}
WrapperMsg::StartBackendTickImpl => {
// If previous id is still stored, request disconnect so that a
// new id can be received
if let Some(id) = self.player_id.take() {
let function = Function::new_no_args(&format!(
"
let xhr = new XMLHttpRequest();
xhr.open('POST', '{}');
xhr.send('{{\"type\": \"disconnect\", \"id\": {}}}');
",
BACKEND_URL, id
));
function.call0(&function).ok();
}
self.do_backend_tick = true;
ctx.link().send_message(WrapperMsg::BackendTick);
}
WrapperMsg::BackendTick => { WrapperMsg::BackendTick => {
if !self.do_backend_tick { if !self.do_backend_tick || shared.game_state.get() == GameState::default() {
// disconnect id if backend tick is to be stopped
if let Some(id) = self.player_id.take() {
let function = Function::new_no_args(&format!(
"
let xhr = new XMLHttpRequest();
xhr.open('POST', '{}');
xhr.send('{{\"type\": \"disconnect\", \"id\": {}}}');
",
BACKEND_URL, id
));
function.call0(&function).ok();
}
return false; return false;
} }
@ -1415,6 +1479,13 @@ impl Component for Wrapper {
self.do_backend_tick = false; self.do_backend_tick = false;
} }
NetworkedGameState::Disconnected => { NetworkedGameState::Disconnected => {
append_to_info_text(
&document,
"info_text0",
"The opponent disconnected",
INFO_TEXT_MAX_ITEMS,
)
.ok();
append_to_info_text( append_to_info_text(
&document, &document,
"info_text1", "info_text1",
@ -1593,6 +1664,22 @@ impl Component for Wrapper {
function.call0(&function).ok(); function.call0(&function).ok();
} }
self.place_request = None; self.place_request = None;
element_remove_class(&document, "mainmenu", "hidden_menu").ok();
element_append_class(&document, "mainmenu", "menu").ok();
append_to_info_text(
&document,
"info_text1",
"<b>Waiting to choose game-mode...</b>",
1,
)
.ok();
append_to_info_text(
&document,
"info_text0",
"Reset button was pressed",
INFO_TEXT_MAX_ITEMS,
)
.ok();
self.do_backend_tick = false; self.do_backend_tick = false;
} }
} // match (msg) } // match (msg)