Display timeout in game UI
This commit is contained in:
parent
b4772aa88e
commit
9162c5eb24
@ -12,6 +12,7 @@ use tui::{Frame, Terminal};
|
|||||||
|
|
||||||
use sea_battle_backend::data::{Coordinates, CurrentGameMapStatus, CurrentGameStatus};
|
use sea_battle_backend::data::{Coordinates, CurrentGameMapStatus, CurrentGameStatus};
|
||||||
use sea_battle_backend::human_player_ws::{ClientMessage, ServerMessage};
|
use sea_battle_backend::human_player_ws::{ClientMessage, ServerMessage};
|
||||||
|
use sea_battle_backend::utils::time_utils::time;
|
||||||
use sea_battle_backend::utils::Res;
|
use sea_battle_backend::utils::Res;
|
||||||
|
|
||||||
use crate::client::Client;
|
use crate::client::Client;
|
||||||
@ -95,6 +96,7 @@ pub struct GameScreen {
|
|||||||
invite_code: Option<String>,
|
invite_code: Option<String>,
|
||||||
status: GameStatus,
|
status: GameStatus,
|
||||||
opponent_name: Option<String>,
|
opponent_name: Option<String>,
|
||||||
|
game_last_update: u64,
|
||||||
game: CurrentGameStatus,
|
game: CurrentGameStatus,
|
||||||
curr_shoot_position: Coordinates,
|
curr_shoot_position: Coordinates,
|
||||||
last_opponent_fire_position: Coordinates,
|
last_opponent_fire_position: Coordinates,
|
||||||
@ -108,6 +110,7 @@ impl GameScreen {
|
|||||||
invite_code: None,
|
invite_code: None,
|
||||||
status: GameStatus::Connecting,
|
status: GameStatus::Connecting,
|
||||||
opponent_name: None,
|
opponent_name: None,
|
||||||
|
game_last_update: 0,
|
||||||
game: Default::default(),
|
game: Default::default(),
|
||||||
curr_shoot_position: Coordinates::new(0, 0),
|
curr_shoot_position: Coordinates::new(0, 0),
|
||||||
last_opponent_fire_position: Coordinates::invalid(),
|
last_opponent_fire_position: Coordinates::invalid(),
|
||||||
@ -288,11 +291,13 @@ impl GameScreen {
|
|||||||
|
|
||||||
ServerMessage::OpponentMustFire { status } => {
|
ServerMessage::OpponentMustFire { status } => {
|
||||||
self.status = GameStatus::OpponentMustFire;
|
self.status = GameStatus::OpponentMustFire;
|
||||||
|
self.game_last_update = time();
|
||||||
self.game = status;
|
self.game = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerMessage::RequestFire { status } => {
|
ServerMessage::RequestFire { status } => {
|
||||||
self.status = GameStatus::MustFire;
|
self.status = GameStatus::MustFire;
|
||||||
|
self.game_last_update = time();
|
||||||
self.game = status;
|
self.game = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -303,11 +308,13 @@ impl GameScreen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ServerMessage::LostGame { status } => {
|
ServerMessage::LostGame { status } => {
|
||||||
|
self.game_last_update = time();
|
||||||
self.game = status;
|
self.game = status;
|
||||||
self.status = GameStatus::LostGame;
|
self.status = GameStatus::LostGame;
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerMessage::WonGame { status } => {
|
ServerMessage::WonGame { status } => {
|
||||||
|
self.game_last_update = time();
|
||||||
self.game = status;
|
self.game = status;
|
||||||
self.status = GameStatus::WonGame;
|
self.status = GameStatus::WonGame;
|
||||||
}
|
}
|
||||||
@ -476,6 +483,17 @@ impl GameScreen {
|
|||||||
return HashMap::default();
|
return HashMap::default();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add timeout (if required)
|
||||||
|
let mut timeout_str = String::new();
|
||||||
|
if self.status == GameStatus::MustFire || self.status == GameStatus::OpponentMustFire {
|
||||||
|
if let Some(remaining) = self.game.remaining_time_for_strike {
|
||||||
|
let timeout = self.game_last_update + remaining;
|
||||||
|
if time() < timeout {
|
||||||
|
timeout_str = format!(" {} seconds left", timeout - time());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Draw main ui (default play UI)
|
// Draw main ui (default play UI)
|
||||||
let player_map = self
|
let player_map = self
|
||||||
.player_map(&self.game.your_map, false)
|
.player_map(&self.game.your_map, false)
|
||||||
@ -519,8 +537,10 @@ impl GameScreen {
|
|||||||
|
|
||||||
let buttons_width = buttons.iter().fold(0, |a, b| a + b.estimated_size().0 + 4);
|
let buttons_width = buttons.iter().fold(0, |a, b| a + b.estimated_size().0 + 4);
|
||||||
|
|
||||||
let max_width = max(maps_width, status_text.len() as u16).max(buttons_width);
|
let max_width = max(maps_width, status_text.len() as u16)
|
||||||
let total_height = 3 + maps_height + 3;
|
.max(buttons_width)
|
||||||
|
.max(timeout_str.len() as u16);
|
||||||
|
let total_height = 3 + 1 + maps_height + 3;
|
||||||
|
|
||||||
// Check if frame is too small
|
// Check if frame is too small
|
||||||
if max_width > f.size().width || total_height > f.size().height {
|
if max_width > f.size().width || total_height > f.size().height {
|
||||||
@ -531,7 +551,8 @@ impl GameScreen {
|
|||||||
let chunks = Layout::default()
|
let chunks = Layout::default()
|
||||||
.direction(Direction::Vertical)
|
.direction(Direction::Vertical)
|
||||||
.constraints([
|
.constraints([
|
||||||
Constraint::Length(3),
|
Constraint::Length(2),
|
||||||
|
Constraint::Length(2),
|
||||||
Constraint::Length(maps_height),
|
Constraint::Length(maps_height),
|
||||||
Constraint::Length(3),
|
Constraint::Length(3),
|
||||||
])
|
])
|
||||||
@ -541,6 +562,10 @@ impl GameScreen {
|
|||||||
let paragraph = Paragraph::new(status_text.as_str());
|
let paragraph = Paragraph::new(status_text.as_str());
|
||||||
f.render_widget(paragraph, centered_text(&status_text, &chunks[0]));
|
f.render_widget(paragraph, centered_text(&status_text, &chunks[0]));
|
||||||
|
|
||||||
|
// Render timeout
|
||||||
|
let paragraph = Paragraph::new(timeout_str.as_str());
|
||||||
|
f.render_widget(paragraph, centered_text(&timeout_str, &chunks[1]));
|
||||||
|
|
||||||
// Render maps
|
// Render maps
|
||||||
if show_both_maps {
|
if show_both_maps {
|
||||||
let maps_chunks = Layout::default()
|
let maps_chunks = Layout::default()
|
||||||
@ -550,16 +575,16 @@ impl GameScreen {
|
|||||||
Constraint::Length(3),
|
Constraint::Length(3),
|
||||||
Constraint::Length(opponent_map_size.0),
|
Constraint::Length(opponent_map_size.0),
|
||||||
])
|
])
|
||||||
.split(chunks[1]);
|
.split(chunks[2]);
|
||||||
|
|
||||||
f.render_widget(player_map, maps_chunks[0]);
|
f.render_widget(player_map, maps_chunks[0]);
|
||||||
f.render_widget(opponent_map, maps_chunks[2]);
|
f.render_widget(opponent_map, maps_chunks[2]);
|
||||||
} else {
|
} else {
|
||||||
// Render a single map
|
// Render a single map
|
||||||
if self.can_fire() {
|
if self.can_fire() {
|
||||||
f.render_widget(opponent_map, chunks[1]);
|
f.render_widget(opponent_map, chunks[2]);
|
||||||
} else {
|
} else {
|
||||||
f.render_widget(player_map, chunks[1]);
|
f.render_widget(player_map, chunks[2]);
|
||||||
drop(opponent_map);
|
drop(opponent_map);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -573,7 +598,7 @@ impl GameScreen {
|
|||||||
.map(|_| Constraint::Percentage(100 / buttons.len() as u16))
|
.map(|_| Constraint::Percentage(100 / buttons.len() as u16))
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
)
|
)
|
||||||
.split(chunks[2]);
|
.split(chunks[3]);
|
||||||
|
|
||||||
for (idx, b) in buttons.into_iter().enumerate() {
|
for (idx, b) in buttons.into_iter().enumerate() {
|
||||||
let target = centered_rect_size(
|
let target = centered_rect_size(
|
||||||
|
@ -78,6 +78,7 @@ impl PrintableMap for PrintableCurrentGameMapStatus {
|
|||||||
|
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, Default)]
|
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, Default)]
|
||||||
pub struct CurrentGameStatus {
|
pub struct CurrentGameStatus {
|
||||||
|
pub remaining_time_for_strike: Option<u64>,
|
||||||
pub rules: GameRules,
|
pub rules: GameRules,
|
||||||
pub your_map: CurrentGameMapStatus,
|
pub your_map: CurrentGameMapStatus,
|
||||||
pub opponent_map: CurrentGameMapStatus,
|
pub opponent_map: CurrentGameMapStatus,
|
||||||
|
@ -257,6 +257,9 @@ impl Game {
|
|||||||
/// Get current game status for a specific player
|
/// Get current game status for a specific player
|
||||||
fn get_game_status_for_player(&self, id: usize) -> CurrentGameStatus {
|
fn get_game_status_for_player(&self, id: usize) -> CurrentGameStatus {
|
||||||
CurrentGameStatus {
|
CurrentGameStatus {
|
||||||
|
remaining_time_for_strike: self.rules.strike_timeout.map(|v| {
|
||||||
|
((self.curr_strike_request_started + v) as i64 - time() as i64).max(0) as u64
|
||||||
|
}),
|
||||||
rules: self.rules.clone(),
|
rules: self.rules.clone(),
|
||||||
your_map: self.player_map(id).current_map_status(false),
|
your_map: self.player_map(id).current_map_status(false),
|
||||||
opponent_map: self
|
opponent_map: self
|
||||||
|
Loading…
Reference in New Issue
Block a user