Skip to content

Commit 5eb4bce

Browse files
authored
UI improvements (#65)
* 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
1 parent 5c8fd75 commit 5eb4bce

17 files changed

+219
-107
lines changed

client/src/advance_ui.rs

+87-30
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
1+
use itertools::Itertools;
2+
use macroquad::hash;
3+
use macroquad::math::{bool, vec2};
14
use std::cmp::min;
25
use std::collections::HashMap;
36

4-
use macroquad::math::bool;
5-
67
use server::action::Action;
7-
use server::content::advances::get_all;
8+
use server::advance::{Advance, Bonus};
9+
use server::content::advances;
810
use server::game::Game;
911
use server::game::GameState;
12+
use server::player::Player;
1013
use server::playing_actions::PlayingAction;
1114
use server::resource_pile::AdvancePaymentOptions;
1215
use server::status_phase::{StatusPhaseAction, StatusPhaseState};
1316

1417
use crate::client_state::{ActiveDialog, ShownPlayer, StateUpdate};
15-
use crate::dialog_ui::dialog;
18+
use crate::dialog_ui::full_dialog;
1619
use crate::payment_ui::{payment_dialog, HasPayment, Payment, ResourcePayment};
1720
use crate::resource_ui::{new_resource_map, ResourceType};
1821
use crate::select_ui::HasCountSelectableObject;
@@ -77,56 +80,110 @@ impl HasPayment for AdvancePayment {
7780
}
7881

7982
pub fn show_advance_menu(game: &Game, player: &ShownPlayer) -> StateUpdate {
80-
show_generic_advance_menu("Advances", game, player, true, |name| {
83+
show_generic_advance_menu("Advances", game, player, |name| {
8184
StateUpdate::SetDialog(ActiveDialog::AdvancePayment(AdvancePayment::new(
8285
game,
8386
player.index,
84-
&name,
87+
name,
8588
)))
8689
})
8790
}
8891

8992
pub fn show_free_advance_menu(game: &Game, player: &ShownPlayer) -> StateUpdate {
90-
show_generic_advance_menu("Select a free advance", game, player, false, |name| {
91-
StateUpdate::status_phase(StatusPhaseAction::FreeAdvance(name))
93+
show_generic_advance_menu("Select a free advance", game, player, |name| {
94+
StateUpdate::status_phase(StatusPhaseAction::FreeAdvance(name.to_string()))
9295
})
9396
}
9497

9598
pub fn show_generic_advance_menu(
9699
title: &str,
97100
game: &Game,
98101
player: &ShownPlayer,
99-
close_button: bool,
100-
new_update: impl Fn(String) -> StateUpdate,
102+
new_update: impl Fn(&str) -> StateUpdate,
101103
) -> StateUpdate {
102-
dialog(title, close_button, |ui| {
104+
full_dialog(title, |ui| {
103105
let p = player.get(game);
104-
for a in get_all() {
105-
let name = a.name;
106-
if player.can_play_action {
107-
if p.has_advance(&name) {
108-
ui.label(None, &name);
109-
} else {
110-
let can = if matches!(
111-
game.state,
112-
GameState::StatusPhase(StatusPhaseState::FreeAdvance)
113-
) {
114-
p.can_advance_free(&name)
106+
let mut update = StateUpdate::None;
107+
let mut current_group = None;
108+
for (_a, list) in &advances::get_all().iter().chunk_by(|a| {
109+
if a.required.is_none() {
110+
current_group = Some(&a.name);
111+
&a.name
112+
} else {
113+
current_group.unwrap()
114+
}
115+
}) {
116+
let advances = list.collect::<Vec<_>>();
117+
ui.group(hash!(&advances[0].name), vec2(1500., 90.), |ui| {
118+
for a in advances {
119+
let name = &a.name;
120+
let can_advance = if player.can_play_action {
121+
p.can_advance(name)
122+
} else if player.can_control
123+
&& matches!(
124+
game.state,
125+
GameState::StatusPhase(StatusPhaseState::FreeAdvance)
126+
)
127+
{
128+
p.can_advance_free(name)
129+
} else {
130+
false
131+
};
132+
133+
let desc = description(p, a);
134+
if p.has_advance(name) {
135+
ui.label(None, &desc);
136+
} else if can_advance {
137+
if ui.button(None, desc) {
138+
update = new_update(name);
139+
}
115140
} else {
116-
player.can_control && p.can_advance(&name)
141+
ui.label(None, &desc);
117142
};
118-
if can && ui.button(None, name.clone()) {
119-
return new_update(name);
120-
}
121143
}
122-
} else if p.has_advance(&name) {
123-
ui.label(None, &name);
124-
}
144+
});
125145
}
126-
StateUpdate::None
146+
update
127147
})
128148
}
129149

150+
fn description(p: &Player, a: &Advance) -> String {
151+
let name = &a.name;
152+
let desc = &a.description;
153+
154+
let mut parts = vec![];
155+
parts.push(if p.has_advance(name) {
156+
format!("+ {name}")
157+
} else {
158+
format!(" {name}")
159+
});
160+
parts.push(desc.clone());
161+
parts.push(format!("Cost: {}", p.advance_cost(name)));
162+
if let Some(r) = &a.required {
163+
parts.push(format!("Required: {r}"));
164+
}
165+
if let Some(c) = &a.contradicting {
166+
parts.push(format!("Contradicts: {c}"));
167+
}
168+
if let Some(b) = &a.bonus {
169+
parts.push(format!(
170+
"Bonus: {}",
171+
match b {
172+
Bonus::MoodToken => "Mood Token",
173+
Bonus::CultureToken => "Culture Token",
174+
}
175+
));
176+
}
177+
if let Some(g) = &a.government {
178+
parts.push(format!("Government: {g}"));
179+
}
180+
if let Some(u) = &a.unlocked_building {
181+
parts.push(format!("Unlocks: {u}"));
182+
}
183+
184+
parts.join(", ")
185+
}
186+
130187
pub fn pay_advance_dialog(ap: &AdvancePayment, player: &ShownPlayer) -> StateUpdate {
131188
payment_dialog(
132189
player,

client/src/city_ui.rs

+6-8
Original file line numberDiff line numberDiff line change
@@ -177,14 +177,12 @@ pub fn draw_city(owner: &Player, city: &City, state: &State) {
177177
for player_index in 0..4 {
178178
for b in &city.pieces.buildings(Some(player_index)) {
179179
let p = if matches!(b, Building::Port) {
180-
hex_ui::rotate_around_rad(
181-
c,
182-
60.0,
183-
city.position
184-
.coordinate()
185-
.directions_to(city.port_position.unwrap().coordinate())[0]
186-
.to_radians_pointy(),
187-
)
180+
let r: f32 = city
181+
.position
182+
.coordinate()
183+
.directions_to(city.port_position.unwrap().coordinate())[0]
184+
.to_radians_pointy();
185+
hex_ui::rotate_around_rad(c, 60.0, r * -1.0 + std::f32::consts::PI / 3.0)
188186
} else {
189187
hex_ui::rotate_around(c, 20.0, 90 * i)
190188
};

client/src/client.rs

+7-20
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@ use server::position::Position;
88
use server::status_phase::StatusPhaseAction;
99

1010
use crate::advance_ui::{pay_advance_dialog, show_advance_menu, show_free_advance_menu};
11-
use crate::client_state::{
12-
ActiveDialog, PendingUpdate, ShownPlayer, State, StateUpdate, StateUpdates,
13-
};
11+
use crate::client_state::{ActiveDialog, ShownPlayer, State, StateUpdate, StateUpdates};
1412
use crate::collect_ui::{click_collect_option, collect_resources_dialog};
1513
use crate::construct_ui::pay_construction_dialog;
1614
use crate::dialog_ui::active_dialog_window;
@@ -20,8 +18,8 @@ use crate::happiness_ui::{
2018
use crate::hex_ui::pixel_to_coordinate;
2119
use crate::log_ui::show_log;
2220
use crate::map_ui::{draw_map, show_tile_menu};
23-
use crate::player_ui::{show_global_controls, show_globals, show_resources, show_wonders};
24-
use crate::{combat_ui, influence_ui, move_ui, recruit_unit_ui, status_phase_ui};
21+
use crate::player_ui::{show_global_controls, show_globals, show_player_status, show_wonders};
22+
use crate::{combat_ui, dialog_ui, influence_ui, move_ui, recruit_unit_ui, status_phase_ui};
2523

2624
pub async fn init(features: &Features) -> State {
2725
State::new(features).await
@@ -56,7 +54,7 @@ fn render(game: &Game, state: &State, features: &Features) -> StateUpdate {
5654
let mut updates = StateUpdates::new();
5755
let update = show_globals(game, player);
5856
updates.add(update);
59-
show_resources(game, player_index);
57+
show_player_status(game, player_index);
6058
show_wonders(game, player_index);
6159

6260
if root_ui().button(vec2(1200., 100.), "Advances") {
@@ -83,7 +81,7 @@ fn render(game: &Game, state: &State, features: &Features) -> StateUpdate {
8381
}
8482
if player.can_control {
8583
if let Some(u) = &state.pending_update {
86-
updates.add(show_pending_update(u, player));
84+
updates.add(dialog_ui::show_pending_update(u, player));
8785
return updates.result();
8886
}
8987
}
@@ -117,6 +115,7 @@ fn render(game: &Game, state: &State, features: &Features) -> StateUpdate {
117115
//status phase
118116
ActiveDialog::FreeAdvance => show_free_advance_menu(game, player),
119117
ActiveDialog::RazeSize1City => status_phase_ui::raze_city_dialog(player),
118+
ActiveDialog::CompleteObjectives => status_phase_ui::complete_objectives_dialog(player),
120119
ActiveDialog::DetermineFirstPlayer => {
121120
status_phase_ui::determine_first_player_dialog(game, player)
122121
}
@@ -128,6 +127,7 @@ fn render(game: &Game, state: &State, features: &Features) -> StateUpdate {
128127
}
129128

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

141-
fn show_pending_update(update: &PendingUpdate, player: &ShownPlayer) -> StateUpdate {
142-
active_dialog_window(player, "Are you sure?", |ui| {
143-
ui.label(None, &format!("Warning: {}", update.warning.join(", ")));
144-
if ui.button(None, "OK") {
145-
return StateUpdate::ResolvePendingUpdate(true);
146-
}
147-
if ui.button(None, "Cancel") {
148-
return StateUpdate::ResolvePendingUpdate(false);
149-
}
150-
StateUpdate::None
151-
})
152-
}
153-
154141
pub fn try_click(game: &Game, state: &State, player: &ShownPlayer) -> StateUpdate {
155142
if !is_mouse_button_pressed(MouseButton::Left) {
156143
return StateUpdate::None;

client/src/client_state.rs

+6-13
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use macroquad::prelude::*;
2-
32
use server::action::Action;
43
use server::city::{City, MoodState};
54
use server::combat::{active_attackers, active_defenders, CombatPhase};
@@ -40,11 +39,13 @@ pub enum ActiveDialog {
4039
// status phase
4140
FreeAdvance,
4241
RazeSize1City,
42+
CompleteObjectives,
4343
DetermineFirstPlayer,
4444
ChangeGovernmentType,
4545
ChooseAdditionalAdvances(ChooseAdditionalAdvances),
4646

4747
// combat
48+
PlayActionCard,
4849
PlaceSettler,
4950
Retreat,
5051
RemoveCasualties(RemoveCasualtiesSelection),
@@ -69,9 +70,11 @@ impl ActiveDialog {
6970
ActiveDialog::CulturalInfluenceResolution(_) => "cultural influence resolution",
7071
ActiveDialog::FreeAdvance => "free advance",
7172
ActiveDialog::RazeSize1City => "raze size 1 city",
73+
ActiveDialog::CompleteObjectives => "complete objectives",
7274
ActiveDialog::DetermineFirstPlayer => "determine first player",
7375
ActiveDialog::ChangeGovernmentType => "change government type",
7476
ActiveDialog::ChooseAdditionalAdvances(_) => "choose additional advances",
77+
ActiveDialog::PlayActionCard => "play action card",
7578
ActiveDialog::PlaceSettler => "place settler",
7679
ActiveDialog::Retreat => "retreat",
7780
ActiveDialog::RemoveCasualties(_) => "remove casualties",
@@ -322,25 +325,15 @@ impl State {
322325
ActiveDialog::CulturalInfluenceResolution(c.clone())
323326
}
324327
GameState::StatusPhase(state) => match state {
325-
StatusPhaseState::CompleteObjectives => {
326-
// todo implement
327-
// self.execute_status_phase(game, StatusPhaseAction::CompleteObjectives(vec![]))
328-
ActiveDialog::None
329-
}
328+
StatusPhaseState::CompleteObjectives => ActiveDialog::CompleteObjectives,
330329
StatusPhaseState::FreeAdvance => ActiveDialog::FreeAdvance,
331330
StatusPhaseState::RaseSize1City => ActiveDialog::RazeSize1City,
332331
StatusPhaseState::ChangeGovernmentType => ActiveDialog::ChangeGovernmentType,
333332
StatusPhaseState::DetermineFirstPlayer => ActiveDialog::DetermineFirstPlayer,
334333
},
335334
GameState::PlaceSettler { .. } => ActiveDialog::PlaceSettler,
336335
GameState::Combat(c) => match c.phase {
337-
CombatPhase::PlayActionCard(_) => {
338-
// self.update(
339-
// game,
340-
// StateUpdate::Execute(Action::Combat(CombatAction::PlayActionCard(None))),
341-
// );
342-
ActiveDialog::None
343-
} //todo implement
336+
CombatPhase::PlayActionCard(_) => ActiveDialog::PlayActionCard,
344337
CombatPhase::RemoveCasualties {
345338
player, casualties, ..
346339
} => {

client/src/collect_ui.rs

+7-8
Original file line numberDiff line numberDiff line change
@@ -103,13 +103,16 @@ pub fn possible_resource_collections(
103103
.into_iter()
104104
.chain(iter::once(city_pos))
105105
.filter_map(|pos| {
106-
if city.port_position.is_some_and(|p| p == pos) {
106+
if city
107+
.port_position
108+
.is_some_and(|p| p == pos && !is_blocked(game, player_index, p))
109+
{
107110
return Some((pos, PORT_CHOICES.to_vec()));
108111
}
109112
if let Some(t) = game.map.tiles.get(&pos) {
110113
if let Some(option) = collect_options
111114
.get(t)
112-
.filter(|_| pos == city_pos || !is_blocked(game, pos))
115+
.filter(|_| pos == city_pos || !is_blocked(game, player_index, pos))
113116
{
114117
return Some((pos, option.clone()));
115118
}
@@ -172,10 +175,6 @@ pub fn draw_resource_collect_tile(state: &State, pos: Position) {
172175
};
173176
}
174177

175-
fn is_blocked(game: &Game, pos: Position) -> bool {
176-
//todo also look for enemy units
177-
if game.get_any_city(pos).is_some() {
178-
return true;
179-
}
180-
false
178+
fn is_blocked(game: &Game, player_index: usize, pos: Position) -> bool {
179+
game.get_any_city(pos).is_some() || game.enemy_player(player_index, pos).is_some()
181180
}

client/src/combat_ui.rs

+9
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,12 @@ pub fn remove_casualties_dialog(
101101
|_| StateUpdate::None,
102102
)
103103
}
104+
105+
pub fn play_action_card_dialog(player: &ShownPlayer) -> StateUpdate {
106+
active_dialog_window(player, "Play action card", |ui| {
107+
if ui.button(None, "None") {
108+
return StateUpdate::Execute(Action::Combat(CombatAction::PlayActionCard(None)));
109+
}
110+
StateUpdate::None
111+
})
112+
}

0 commit comments

Comments
 (0)