Skip to content

Commit

Permalink
UI improvements (#65)
Browse files Browse the repository at this point in the history
* improve advance ui

* improve advance ui

* improve player status

* cleanup

* complete objectives

* play action cards

* fix collect

* fix port pos

* fix port pos

* group advances

* cleanup

* add debug info

* clippy
  • Loading branch information
zeitlinger authored Oct 4, 2024
1 parent 5c8fd75 commit 5eb4bce
Show file tree
Hide file tree
Showing 17 changed files with 219 additions and 107 deletions.
117 changes: 87 additions & 30 deletions client/src/advance_ui.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
use itertools::Itertools;
use macroquad::hash;
use macroquad::math::{bool, vec2};
use std::cmp::min;
use std::collections::HashMap;

use macroquad::math::bool;

use server::action::Action;
use server::content::advances::get_all;
use server::advance::{Advance, Bonus};
use server::content::advances;
use server::game::Game;
use server::game::GameState;
use server::player::Player;
use server::playing_actions::PlayingAction;
use server::resource_pile::AdvancePaymentOptions;
use server::status_phase::{StatusPhaseAction, StatusPhaseState};

use crate::client_state::{ActiveDialog, ShownPlayer, StateUpdate};
use crate::dialog_ui::dialog;
use crate::dialog_ui::full_dialog;
use crate::payment_ui::{payment_dialog, HasPayment, Payment, ResourcePayment};
use crate::resource_ui::{new_resource_map, ResourceType};
use crate::select_ui::HasCountSelectableObject;
Expand Down Expand Up @@ -77,56 +80,110 @@ impl HasPayment for AdvancePayment {
}

pub fn show_advance_menu(game: &Game, player: &ShownPlayer) -> StateUpdate {
show_generic_advance_menu("Advances", game, player, true, |name| {
show_generic_advance_menu("Advances", game, player, |name| {
StateUpdate::SetDialog(ActiveDialog::AdvancePayment(AdvancePayment::new(
game,
player.index,
&name,
name,
)))
})
}

pub fn show_free_advance_menu(game: &Game, player: &ShownPlayer) -> StateUpdate {
show_generic_advance_menu("Select a free advance", game, player, false, |name| {
StateUpdate::status_phase(StatusPhaseAction::FreeAdvance(name))
show_generic_advance_menu("Select a free advance", game, player, |name| {
StateUpdate::status_phase(StatusPhaseAction::FreeAdvance(name.to_string()))
})
}

pub fn show_generic_advance_menu(
title: &str,
game: &Game,
player: &ShownPlayer,
close_button: bool,
new_update: impl Fn(String) -> StateUpdate,
new_update: impl Fn(&str) -> StateUpdate,
) -> StateUpdate {
dialog(title, close_button, |ui| {
full_dialog(title, |ui| {
let p = player.get(game);
for a in get_all() {
let name = a.name;
if player.can_play_action {
if p.has_advance(&name) {
ui.label(None, &name);
} else {
let can = if matches!(
game.state,
GameState::StatusPhase(StatusPhaseState::FreeAdvance)
) {
p.can_advance_free(&name)
let mut update = StateUpdate::None;
let mut current_group = None;
for (_a, list) in &advances::get_all().iter().chunk_by(|a| {
if a.required.is_none() {
current_group = Some(&a.name);
&a.name
} else {
current_group.unwrap()
}
}) {
let advances = list.collect::<Vec<_>>();
ui.group(hash!(&advances[0].name), vec2(1500., 90.), |ui| {
for a in advances {
let name = &a.name;
let can_advance = if player.can_play_action {
p.can_advance(name)
} else if player.can_control
&& matches!(
game.state,
GameState::StatusPhase(StatusPhaseState::FreeAdvance)
)
{
p.can_advance_free(name)
} else {
false
};

let desc = description(p, a);
if p.has_advance(name) {
ui.label(None, &desc);
} else if can_advance {
if ui.button(None, desc) {
update = new_update(name);
}
} else {
player.can_control && p.can_advance(&name)
ui.label(None, &desc);
};
if can && ui.button(None, name.clone()) {
return new_update(name);
}
}
} else if p.has_advance(&name) {
ui.label(None, &name);
}
});
}
StateUpdate::None
update
})
}

fn description(p: &Player, a: &Advance) -> String {
let name = &a.name;
let desc = &a.description;

let mut parts = vec![];
parts.push(if p.has_advance(name) {
format!("+ {name}")
} else {
format!(" {name}")
});
parts.push(desc.clone());
parts.push(format!("Cost: {}", p.advance_cost(name)));
if let Some(r) = &a.required {
parts.push(format!("Required: {r}"));
}
if let Some(c) = &a.contradicting {
parts.push(format!("Contradicts: {c}"));
}
if let Some(b) = &a.bonus {
parts.push(format!(
"Bonus: {}",
match b {
Bonus::MoodToken => "Mood Token",
Bonus::CultureToken => "Culture Token",
}
));
}
if let Some(g) = &a.government {
parts.push(format!("Government: {g}"));
}
if let Some(u) = &a.unlocked_building {
parts.push(format!("Unlocks: {u}"));
}

parts.join(", ")
}

pub fn pay_advance_dialog(ap: &AdvancePayment, player: &ShownPlayer) -> StateUpdate {
payment_dialog(
player,
Expand Down
14 changes: 6 additions & 8 deletions client/src/city_ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,14 +177,12 @@ pub fn draw_city(owner: &Player, city: &City, state: &State) {
for player_index in 0..4 {
for b in &city.pieces.buildings(Some(player_index)) {
let p = if matches!(b, Building::Port) {
hex_ui::rotate_around_rad(
c,
60.0,
city.position
.coordinate()
.directions_to(city.port_position.unwrap().coordinate())[0]
.to_radians_pointy(),
)
let r: f32 = city
.position
.coordinate()
.directions_to(city.port_position.unwrap().coordinate())[0]
.to_radians_pointy();
hex_ui::rotate_around_rad(c, 60.0, r * -1.0 + std::f32::consts::PI / 3.0)
} else {
hex_ui::rotate_around(c, 20.0, 90 * i)
};
Expand Down
27 changes: 7 additions & 20 deletions client/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ use server::position::Position;
use server::status_phase::StatusPhaseAction;

use crate::advance_ui::{pay_advance_dialog, show_advance_menu, show_free_advance_menu};
use crate::client_state::{
ActiveDialog, PendingUpdate, ShownPlayer, State, StateUpdate, StateUpdates,
};
use crate::client_state::{ActiveDialog, ShownPlayer, State, StateUpdate, StateUpdates};
use crate::collect_ui::{click_collect_option, collect_resources_dialog};
use crate::construct_ui::pay_construction_dialog;
use crate::dialog_ui::active_dialog_window;
Expand All @@ -20,8 +18,8 @@ use crate::happiness_ui::{
use crate::hex_ui::pixel_to_coordinate;
use crate::log_ui::show_log;
use crate::map_ui::{draw_map, show_tile_menu};
use crate::player_ui::{show_global_controls, show_globals, show_resources, show_wonders};
use crate::{combat_ui, influence_ui, move_ui, recruit_unit_ui, status_phase_ui};
use crate::player_ui::{show_global_controls, show_globals, show_player_status, show_wonders};
use crate::{combat_ui, dialog_ui, influence_ui, move_ui, recruit_unit_ui, status_phase_ui};

pub async fn init(features: &Features) -> State {
State::new(features).await
Expand Down Expand Up @@ -56,7 +54,7 @@ fn render(game: &Game, state: &State, features: &Features) -> StateUpdate {
let mut updates = StateUpdates::new();
let update = show_globals(game, player);
updates.add(update);
show_resources(game, player_index);
show_player_status(game, player_index);
show_wonders(game, player_index);

if root_ui().button(vec2(1200., 100.), "Advances") {
Expand All @@ -83,7 +81,7 @@ fn render(game: &Game, state: &State, features: &Features) -> StateUpdate {
}
if player.can_control {
if let Some(u) = &state.pending_update {
updates.add(show_pending_update(u, player));
updates.add(dialog_ui::show_pending_update(u, player));
return updates.result();
}
}
Expand Down Expand Up @@ -117,6 +115,7 @@ fn render(game: &Game, state: &State, features: &Features) -> StateUpdate {
//status phase
ActiveDialog::FreeAdvance => show_free_advance_menu(game, player),
ActiveDialog::RazeSize1City => status_phase_ui::raze_city_dialog(player),
ActiveDialog::CompleteObjectives => status_phase_ui::complete_objectives_dialog(player),
ActiveDialog::DetermineFirstPlayer => {
status_phase_ui::determine_first_player_dialog(game, player)
}
Expand All @@ -128,6 +127,7 @@ fn render(game: &Game, state: &State, features: &Features) -> StateUpdate {
}

//combat
ActiveDialog::PlayActionCard => combat_ui::play_action_card_dialog(player),
ActiveDialog::PlaceSettler => combat_ui::place_settler_dialog(player),
ActiveDialog::Retreat => combat_ui::retreat_dialog(player),
ActiveDialog::RemoveCasualties(s) => combat_ui::remove_casualties_dialog(game, s, player),
Expand All @@ -138,19 +138,6 @@ fn render(game: &Game, state: &State, features: &Features) -> StateUpdate {
updates.result()
}

fn show_pending_update(update: &PendingUpdate, player: &ShownPlayer) -> StateUpdate {
active_dialog_window(player, "Are you sure?", |ui| {
ui.label(None, &format!("Warning: {}", update.warning.join(", ")));
if ui.button(None, "OK") {
return StateUpdate::ResolvePendingUpdate(true);
}
if ui.button(None, "Cancel") {
return StateUpdate::ResolvePendingUpdate(false);
}
StateUpdate::None
})
}

pub fn try_click(game: &Game, state: &State, player: &ShownPlayer) -> StateUpdate {
if !is_mouse_button_pressed(MouseButton::Left) {
return StateUpdate::None;
Expand Down
19 changes: 6 additions & 13 deletions client/src/client_state.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use macroquad::prelude::*;

use server::action::Action;
use server::city::{City, MoodState};
use server::combat::{active_attackers, active_defenders, CombatPhase};
Expand Down Expand Up @@ -40,11 +39,13 @@ pub enum ActiveDialog {
// status phase
FreeAdvance,
RazeSize1City,
CompleteObjectives,
DetermineFirstPlayer,
ChangeGovernmentType,
ChooseAdditionalAdvances(ChooseAdditionalAdvances),

// combat
PlayActionCard,
PlaceSettler,
Retreat,
RemoveCasualties(RemoveCasualtiesSelection),
Expand All @@ -69,9 +70,11 @@ impl ActiveDialog {
ActiveDialog::CulturalInfluenceResolution(_) => "cultural influence resolution",
ActiveDialog::FreeAdvance => "free advance",
ActiveDialog::RazeSize1City => "raze size 1 city",
ActiveDialog::CompleteObjectives => "complete objectives",
ActiveDialog::DetermineFirstPlayer => "determine first player",
ActiveDialog::ChangeGovernmentType => "change government type",
ActiveDialog::ChooseAdditionalAdvances(_) => "choose additional advances",
ActiveDialog::PlayActionCard => "play action card",
ActiveDialog::PlaceSettler => "place settler",
ActiveDialog::Retreat => "retreat",
ActiveDialog::RemoveCasualties(_) => "remove casualties",
Expand Down Expand Up @@ -322,25 +325,15 @@ impl State {
ActiveDialog::CulturalInfluenceResolution(c.clone())
}
GameState::StatusPhase(state) => match state {
StatusPhaseState::CompleteObjectives => {
// todo implement
// self.execute_status_phase(game, StatusPhaseAction::CompleteObjectives(vec![]))
ActiveDialog::None
}
StatusPhaseState::CompleteObjectives => ActiveDialog::CompleteObjectives,
StatusPhaseState::FreeAdvance => ActiveDialog::FreeAdvance,
StatusPhaseState::RaseSize1City => ActiveDialog::RazeSize1City,
StatusPhaseState::ChangeGovernmentType => ActiveDialog::ChangeGovernmentType,
StatusPhaseState::DetermineFirstPlayer => ActiveDialog::DetermineFirstPlayer,
},
GameState::PlaceSettler { .. } => ActiveDialog::PlaceSettler,
GameState::Combat(c) => match c.phase {
CombatPhase::PlayActionCard(_) => {
// self.update(
// game,
// StateUpdate::Execute(Action::Combat(CombatAction::PlayActionCard(None))),
// );
ActiveDialog::None
} //todo implement
CombatPhase::PlayActionCard(_) => ActiveDialog::PlayActionCard,
CombatPhase::RemoveCasualties {
player, casualties, ..
} => {
Expand Down
15 changes: 7 additions & 8 deletions client/src/collect_ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,13 +103,16 @@ pub fn possible_resource_collections(
.into_iter()
.chain(iter::once(city_pos))
.filter_map(|pos| {
if city.port_position.is_some_and(|p| p == pos) {
if city
.port_position
.is_some_and(|p| p == pos && !is_blocked(game, player_index, p))
{
return Some((pos, PORT_CHOICES.to_vec()));
}
if let Some(t) = game.map.tiles.get(&pos) {
if let Some(option) = collect_options
.get(t)
.filter(|_| pos == city_pos || !is_blocked(game, pos))
.filter(|_| pos == city_pos || !is_blocked(game, player_index, pos))
{
return Some((pos, option.clone()));
}
Expand Down Expand Up @@ -172,10 +175,6 @@ pub fn draw_resource_collect_tile(state: &State, pos: Position) {
};
}

fn is_blocked(game: &Game, pos: Position) -> bool {
//todo also look for enemy units
if game.get_any_city(pos).is_some() {
return true;
}
false
fn is_blocked(game: &Game, player_index: usize, pos: Position) -> bool {
game.get_any_city(pos).is_some() || game.enemy_player(player_index, pos).is_some()
}
9 changes: 9 additions & 0 deletions client/src/combat_ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,12 @@ pub fn remove_casualties_dialog(
|_| StateUpdate::None,
)
}

pub fn play_action_card_dialog(player: &ShownPlayer) -> StateUpdate {
active_dialog_window(player, "Play action card", |ui| {
if ui.button(None, "None") {
return StateUpdate::Execute(Action::Combat(CombatAction::PlayActionCard(None)));
}
StateUpdate::None
})
}
Loading

0 comments on commit 5eb4bce

Please sign in to comment.