Skip to content

Commit

Permalink
Merge pull request #278 from TruncateGame/main
Browse files Browse the repository at this point in the history
Production release
  • Loading branch information
bglw authored Aug 25, 2024
2 parents bc99ff8 + 7dc4eae commit 6f5680d
Show file tree
Hide file tree
Showing 46 changed files with 2,155 additions and 391 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion truncate_client/src/app_inner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ pub fn render(outer: &mut OuterApplication, ui: &mut egui::Ui, current_time: Dur
}

if new_game_status.is_none() {
render_native_menu_if_required(outer, ui);
new_game_status = render_native_menu_if_required(outer, ui);
}

let mut send = |msg| {
Expand Down
2 changes: 1 addition & 1 deletion truncate_client/src/app_outer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ impl OuterApplication {
}
}

let theme = Theme::default();
let theme = Theme::day();

{
use egui::FontFamily;
Expand Down
31 changes: 29 additions & 2 deletions truncate_client/src/handle_messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ pub fn handle_server_msg(outer: &mut OuterApplication, ui: &mut egui::Ui) {

while let Ok(msg) = recv() {
match msg {
GameMessage::Ping => {}
GameMessage::Ping | GameMessage::Ack(_) | GameMessage::PleaseLogin => { /* handled at comms layer */
}
GameMessage::JoinedLobby(player_index, id, players, board, token) => {
// If we're already in a lobby, treat this as a lobby update
// (the websocket probably dropped and reconnected)
Expand Down Expand Up @@ -85,6 +86,9 @@ pub fn handle_server_msg(outer: &mut OuterApplication, ui: &mut egui::Ui) {
board,
hand,
changes: _,
game_ends_at,
paused,
remaining_turns,
}) => {
// If we're already in a game, treat this as a game update
// (the websocket probably dropped and reconnected)
Expand All @@ -98,6 +102,9 @@ pub fn handle_server_msg(outer: &mut OuterApplication, ui: &mut egui::Ui) {
board,
hand,
changes: vec![], // TODO: Try get latest changes on reconnect without dupes
game_ends_at,
paused,
remaining_turns,
};
game.apply_new_state(update);
continue;
Expand All @@ -117,6 +124,8 @@ pub fn handle_server_msg(outer: &mut OuterApplication, ui: &mut egui::Ui) {
outer.map_texture.clone(),
outer.theme.clone(),
GameLocation::Online,
game_ends_at,
remaining_turns,
));
}
GameMessage::GameUpdate(state_message) => match &mut outer.game_status {
Expand All @@ -131,6 +140,18 @@ pub fn handle_server_msg(outer: &mut OuterApplication, ui: &mut egui::Ui) {
])
}
},
GameMessage::GameTimingUpdate(state_message) => match &mut outer.game_status {
GameStatus::Active(game) => {
game.apply_new_timing(state_message);
}
_ => {
outer.game_status = GameStatus::HardError(vec![
"Game hit unknown case".into(),
"Received game message".into(),
"while not in a game".into(),
])
}
},
GameMessage::GameEnd(state_message, winner) => {
#[cfg(target_arch = "wasm32")]
{
Expand All @@ -142,6 +163,7 @@ pub fn handle_server_msg(outer: &mut OuterApplication, ui: &mut egui::Ui) {
match &mut outer.game_status {
GameStatus::Active(game) => {
game.apply_new_state(state_message);
game.depot.gameplay.winner = Some(winner as usize);
outer.game_status = GameStatus::Concluded(game.clone(), winner);
}
_ => {}
Expand Down Expand Up @@ -261,7 +283,12 @@ pub fn handle_server_msg(outer: &mut OuterApplication, ui: &mut egui::Ui) {
.map(|(_, i)| i.rules_generation)
.unwrap_or_else(|| GameRules::latest().0);

let mut game = game::Game::new(9, 9, Some(seed.seed as u64), rules_generation);
let mut game = game::Game::new(
9,
9,
Some(seed.seed as u64),
GameRules::generation(rules_generation),
);
if human_starts {
game.add_player("You".into());
game.add_player("Computer".into());
Expand Down
5 changes: 2 additions & 3 deletions truncate_client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,12 +146,11 @@ pub fn backchannel(msg: String) -> String {
next_player,
npc_params,
} => {
let mut game = truncate_core::game::Game::new(3, 3, None, 0);
let mut game = truncate_core::game::Game::new(3, 3, None, rules);
game.board = board;
game.rules = rules;
game.player_turn_count = vec![0; players.len()];
game.players = players;
game.next_player = next_player;
game.next_player = Some(next_player);

game.players[next_player].turn_starts_no_later_than = Some(
instant::SystemTime::now()
Expand Down
11 changes: 6 additions & 5 deletions truncate_client/src/lil_bits/board_editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,9 +266,9 @@ impl<'a> EditorUI<'a> {
Square::Water | Square::Dock(_) => {
EditorDrag::MakeLand
}
Square::Land | Square::Town { .. } => {
EditorDrag::RemoveLand
}
Square::Land
| Square::Town { .. }
| Square::Obelisk => EditorDrag::RemoveLand,
Square::Occupied { .. } => unreachable!(),
Square::Fog => unreachable!(),
},
Expand Down Expand Up @@ -303,7 +303,8 @@ impl<'a> EditorUI<'a> {
ui.ctx()
.memory_mut(|mem| mem.data.remove::<EditorDrag>(Id::NULL));
} else if response.clicked() {
unreachable!("Maybe unreachable? Duplicate above state if not...");
ui.ctx()
.memory_mut(|mem| mem.data.remove::<EditorDrag>(Id::NULL));
};
}
});
Expand All @@ -325,7 +326,7 @@ impl<'a> EditorUI<'a> {

// TODO: Player mirroring won't work for >2 players
let mirrored_state = match new_state {
Square::Water | Square::Land => new_state,
Square::Water | Square::Land | Square::Obelisk => new_state,
Square::Town { player: p, .. } => {
if p == 0 {
Square::Town {
Expand Down
4 changes: 2 additions & 2 deletions truncate_client/src/lil_bits/board_editor_square.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ impl EditorSquareUI {
) -> egui::Response {
let (rect, response) = ui.allocate_exact_size(
egui::vec2(theme.grid_size, theme.grid_size),
egui::Sense::click(),
egui::Sense::hover(),
);
let response = ui.interact(
rect.shrink(theme.tile_margin),
response.id.with("editor_tile"),
egui::Sense::click_and_drag(),
egui::Sense::drag(),
);

let inner_bounds = rect.shrink(theme.tile_margin);
Expand Down
2 changes: 1 addition & 1 deletion truncate_client/src/lil_bits/hand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ impl<'a> HandUI<'a> {
let hovered = matches!(hovered, Some((p, _)) if p == i);
let selected = matches!(selected, Some((p, _)) if p == i);

let color = if gameplay.next_player_number == gameplay.player_number {
let color = if self.active {
aesthetics.player_colors[gameplay.player_number as usize]
} else {
aesthetics.theme.faded
Expand Down
44 changes: 44 additions & 0 deletions truncate_client/src/lil_bits/result_modal/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,15 @@ pub struct ResultModalResigning {
msg: String,
}

#[derive(Clone)]
pub struct ResultModalLoading {}

#[derive(Clone)]
pub enum ResultModalVariant {
Daily(ResultModalDaily),
Unique(ResultModalUnique),
Resigning(ResultModalResigning),
Loading(ResultModalLoading),
}

#[derive(Clone)]
Expand Down Expand Up @@ -134,13 +138,22 @@ impl ResultModalUI {
}),
}
}

pub fn new_resigning(ui: &mut egui::Ui, msg: String) -> Self {
ResultModalUI::seed_animations(ui);

Self {
contents: ResultModalVariant::Resigning(ResultModalResigning { msg }),
}
}

pub fn new_loading(ui: &mut egui::Ui) -> Self {
ResultModalUI::seed_animations(ui);

Self {
contents: ResultModalVariant::Loading(ResultModalLoading {}),
}
}
}

#[derive(Hash)]
Expand Down Expand Up @@ -374,6 +387,25 @@ impl ResultModalUI {
ui,
);
}
ResultModalVariant::Loading(_l) => {
let summary_text = TextHelper::heavy("Loading", 12.0, None, &mut ui);

summary_text.paint_within(
heading_rect.translate(vec2(0.0, -(heading_rect.height() / 2.0 + 8.0))),
Align2::CENTER_BOTTOM,
Color32::WHITE,
ui,
);

let summary_text = TextHelper::heavy("Statistics", 12.0, None, &mut ui);

summary_text.paint_within(
heading_rect.translate(vec2(0.0, heading_rect.height() / 2.0 + 8.0)),
Align2::CENTER_TOP,
Color32::WHITE,
ui,
);
}
}

// Wait for the main text to move out of the way before showing details
Expand Down Expand Up @@ -504,6 +536,18 @@ impl ResultModalUI {
msg = Some(ResultModalAction::Dismiss);
}
}
ResultModalVariant::Loading(_l) => {
ui.add_space(50.0);

let summary_text = TextHelper::heavy("Waiting for", 10.0, None, &mut ui);

summary_text.paint(Color32::WHITE, ui, true);

let summary_text =
TextHelper::heavy("network connection", 10.0, None, &mut ui);

summary_text.paint(Color32::WHITE, ui, true);
}
};

// Paint over everything below the heading stats to fade them in from black
Expand Down
36 changes: 31 additions & 5 deletions truncate_client/src/lil_bits/timer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,11 @@ impl<'a> TimerUI<'a> {
}
}
None => {
if let Some(time) = self.player.time_remaining {
if let Some(mut time) = self.player.time_remaining {
if let Some(paused_time_delta) = self.player.paused_turn_delta {
time = time.saturating_add(Duration::seconds(paused_time_delta));
}

self.time = time;
format!("{}", TimerUI::human_time(self.time.whole_seconds(), false))
} else {
Expand All @@ -131,6 +135,10 @@ impl<'a> TimerUI<'a> {
_ => {}
};

if self.depot.timing.paused {
return format!("Game is paused!");
}

match self.player.turn_starts_no_later_than {
Some(next_turn) => {
let now = self.depot.timing.current_time.as_secs();
Expand Down Expand Up @@ -169,9 +177,16 @@ impl<'a> TimerUI<'a> {
ui.painter()
.rect_filled(bar, timer_rounding, timer_color.diaphanize());

if let (Some(time_remaining), Some(allotted_time)) =
let full_bar = bar.clone();

if let (Some(mut time_remaining), Some(allotted_time)) =
(self.player.time_remaining, self.player.allotted_time)
{
if let Some(paused_time_delta) = self.player.paused_turn_delta {
time_remaining =
time_remaining.saturating_add(Duration::seconds(paused_time_delta));
}

// Paint time remaining sector of bar
let remaining_time_proportion = (self.time / allotted_time) as f32;
if self.right_align {
Expand Down Expand Up @@ -247,8 +262,19 @@ impl<'a> TimerUI<'a> {
}
}

let text = if let Some(ends_at) = self.depot.timing.game_ends_at {
let now = self.depot.timing.current_time.as_secs();
let remaining = ends_at.saturating_sub(now);
let remaining_label = TimerUI::human_time(remaining as i64, false);
format!("{} : {}", remaining_label, &self.player.name)
} else if let Some(turns_remaining) = self.depot.gameplay.remaining_turns {
format!("{} : {}", turns_remaining, &self.player.name)
} else {
self.player.name.clone()
};

// Render the player name
let text = TextHelper::heavy(&self.player.name, font_z, None, ui);
let text = TextHelper::heavy(&text, font_z, None, ui);
let name_size = text.size();
if self.right_align {
let mut pos = bar.right_bottom() + vec2(0.0, 10.0);
Expand All @@ -264,9 +290,9 @@ impl<'a> TimerUI<'a> {

// Render the remaining time
if self.right_align {
text.paint_at(bar.left_bottom() + vec2(0.0, 10.0), timer_color, ui);
text.paint_at(full_bar.left_bottom() + vec2(0.0, 10.0), timer_color, ui);
} else {
let mut pos = bar.right_bottom() + vec2(0.0, 10.0);
let mut pos = full_bar.right_bottom() + vec2(0.0, 10.0);
pos.x -= time_size.x;
text.paint_at(pos, timer_color, ui);
}
Expand Down
4 changes: 4 additions & 0 deletions truncate_client/src/native_comms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ use tokio_tungstenite::{connect_async, tungstenite::protocol::Message};

use truncate_core::messages::{GameMessage, PlayerMessage};

/*
TODO: Implement the pending_messages retry flow from web_comms
*/

pub async fn connect(
connect_addr: String,
tx_game: mpsc::Sender<GameMessage>,
Expand Down
26 changes: 26 additions & 0 deletions truncate_client/src/regions/active_game/actions_menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,32 @@ impl ActiveGame {
}
}

if matches!(self.location, GameLocation::Online) {
ui.add_space(menu_spacing);

let text = if self.depot.timing.paused {
TextHelper::heavy("UNPAUSE", 14.0, None, ui)
} else {
TextHelper::heavy("PAUSE", 14.0, None, ui)
};

if text
.button(
self.depot.aesthetics.theme.button_primary,
self.depot.aesthetics.theme.text,
&self.depot.aesthetics.map_texture,
ui,
)
.clicked()
{
msg = if self.depot.timing.paused {
Some(PlayerMessage::Unpause)
} else {
Some(PlayerMessage::Pause)
};
}
}

// TODO: Resigning is largely implented for multiplayer games as well, but we need to:
// - Resolve why the update isn't being sent from the server
// - Show the confirmation modal inside active_game (we only show it in single player)
Expand Down
11 changes: 8 additions & 3 deletions truncate_client/src/regions/active_game/control_strip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,9 +270,14 @@ impl ActiveGame {
}
let mut hand_ui =
ui.child_ui(hand_alloc, Layout::top_down(Align::LEFT));
let active = self.depot.gameplay.player_number
== self.depot.gameplay.next_player_number;
HandUI::new(&mut self.hand).active(active).render(
let active_hand = self.depot.gameplay.next_player_number.is_none()
|| self
.depot
.gameplay
.next_player_number
.is_some_and(|n| n == self.depot.gameplay.player_number);

HandUI::new(&mut self.hand).active(active_hand).render(
&mut hand_ui,
&mut self.depot,
&mut self.mapped_hand,
Expand Down
Loading

0 comments on commit 6f5680d

Please sign in to comment.