Query boats layout
This commit is contained in:
@@ -1,49 +1,159 @@
|
||||
use std::io;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use crossterm::event;
|
||||
use crossterm::event::{Event, KeyCode};
|
||||
use sea_battle_backend::human_player_ws::{ClientMessage, ServerMessage};
|
||||
use sea_battle_backend::utils::Res;
|
||||
use tui::backend::Backend;
|
||||
use tui::{Frame, Terminal};
|
||||
|
||||
use crate::client::Client;
|
||||
use crate::constants::*;
|
||||
use crate::ui_screens::confirm_dialog::confirm;
|
||||
use crate::ui_screens::popup_screen::PopupScreen;
|
||||
use crate::ui_screens::set_boats_layout::SetBoatsLayoutScreen;
|
||||
use crate::ui_screens::ScreenResult;
|
||||
|
||||
enum GameStatus {
|
||||
Pending,
|
||||
WaitingForOpponentBoatsConfig,
|
||||
OpponentReady,
|
||||
Starting,
|
||||
}
|
||||
|
||||
pub struct GameScreen {
|
||||
client: Client,
|
||||
status: GameStatus,
|
||||
opponent_name: Option<String>,
|
||||
}
|
||||
|
||||
impl GameScreen {
|
||||
pub fn new(client: Client) -> Self {
|
||||
Self { client }
|
||||
Self {
|
||||
client,
|
||||
status: GameStatus::Pending,
|
||||
opponent_name: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn show<B: Backend>(
|
||||
mut self,
|
||||
terminal: &mut Terminal<B>,
|
||||
) -> io::Result<ScreenResult> {
|
||||
pub async fn show<B: Backend>(mut self, terminal: &mut Terminal<B>) -> Res<ScreenResult> {
|
||||
let mut last_tick = Instant::now();
|
||||
loop {
|
||||
// Update UI
|
||||
terminal.draw(|f| self.ui(f))?;
|
||||
|
||||
let timeout = TICK_RATE
|
||||
.checked_sub(last_tick.elapsed())
|
||||
.unwrap_or_else(|| Duration::from_secs(0));
|
||||
|
||||
// Handle terminal events
|
||||
if crossterm::event::poll(timeout)? {
|
||||
if let Event::Key(key) = event::read()? {
|
||||
match key.code {
|
||||
KeyCode::Char('q') => return Ok(ScreenResult::Canceled),
|
||||
// Leave game
|
||||
KeyCode::Char('q')
|
||||
if confirm(terminal, "Do you really want to leave game?") =>
|
||||
{
|
||||
return Ok(ScreenResult::Canceled);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle incoming messages
|
||||
while let Some(msg) = self.client.try_recv_next_message().await? {
|
||||
match msg {
|
||||
ServerMessage::SetInviteCode { .. } => unimplemented!(),
|
||||
ServerMessage::InvalidInviteCode => unimplemented!(),
|
||||
ServerMessage::WaitingForAnotherPlayer => unimplemented!(),
|
||||
ServerMessage::OpponentConnected => unimplemented!(),
|
||||
ServerMessage::SetOpponentName { name } => self.opponent_name = Some(name),
|
||||
|
||||
ServerMessage::QueryBoatsLayout { rules } => {
|
||||
match SetBoatsLayoutScreen::new(&rules)
|
||||
.set_confirm_on_cancel(true)
|
||||
.show(terminal)?
|
||||
{
|
||||
ScreenResult::Ok(layout) => {
|
||||
self.client
|
||||
.send_message(&ClientMessage::BoatsLayout { layout })
|
||||
.await?
|
||||
}
|
||||
ScreenResult::Canceled => {
|
||||
return Ok(ScreenResult::Canceled);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ServerMessage::RejectedBoatsLayout { .. } => {
|
||||
PopupScreen::new("Server rejected boats layout!! (is your version of SeaBattle up to date?)")
|
||||
.show(terminal)?;
|
||||
}
|
||||
|
||||
ServerMessage::WaitingForOtherPlayerConfiguration => {
|
||||
self.status = GameStatus::WaitingForOpponentBoatsConfig;
|
||||
}
|
||||
|
||||
ServerMessage::OpponentReady => {
|
||||
self.status = GameStatus::OpponentReady;
|
||||
}
|
||||
|
||||
ServerMessage::GameStarting => {
|
||||
self.status = GameStatus::Starting;
|
||||
}
|
||||
|
||||
ServerMessage::OpponentMustFire { .. } => {}
|
||||
ServerMessage::RequestFire { .. } => {}
|
||||
ServerMessage::FireResult { .. } => {}
|
||||
ServerMessage::OpponentFireResult { .. } => {}
|
||||
ServerMessage::LostGame { .. } => {}
|
||||
ServerMessage::WonGame { .. } => {}
|
||||
ServerMessage::OpponentRequestedRematch => {}
|
||||
ServerMessage::OpponentAcceptedRematch => {}
|
||||
ServerMessage::OpponentRejectedRematch => {}
|
||||
ServerMessage::OpponentLeftGame => {}
|
||||
ServerMessage::OpponentReplacedByBot => {}
|
||||
}
|
||||
}
|
||||
|
||||
if last_tick.elapsed() >= TICK_RATE {
|
||||
last_tick = Instant::now();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn ui<B: Backend>(&mut self, f: &mut Frame<B>) {}
|
||||
fn opponent_name(&self) -> &str {
|
||||
self.opponent_name.as_deref().unwrap_or("opponent")
|
||||
}
|
||||
|
||||
fn ui<B: Backend>(&mut self, f: &mut Frame<B>) {
|
||||
// If game is still starting
|
||||
if matches!(self.status, GameStatus::Pending) {
|
||||
PopupScreen::new("Game is pending...").show_in_frame(f);
|
||||
return;
|
||||
}
|
||||
|
||||
// If game is still starting
|
||||
if matches!(self.status, GameStatus::WaitingForOpponentBoatsConfig) {
|
||||
PopupScreen::new(&format!(
|
||||
"Waiting for boats configuration of {}...",
|
||||
self.opponent_name()
|
||||
))
|
||||
.show_in_frame(f);
|
||||
return;
|
||||
}
|
||||
|
||||
// If game is still starting
|
||||
if matches!(self.status, GameStatus::OpponentReady) {
|
||||
PopupScreen::new(&format!("{} is ready!", self.opponent_name())).show_in_frame(f);
|
||||
return;
|
||||
}
|
||||
|
||||
// If game is still starting
|
||||
if matches!(self.status, GameStatus::Starting) {
|
||||
PopupScreen::new("Game is starting...").show_in_frame(f);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user