diff --git a/client/src/advance_ui.rs b/client/src/advance_ui.rs index 8851cdff..bca5ca93 100644 --- a/client/src/advance_ui.rs +++ b/client/src/advance_ui.rs @@ -12,7 +12,7 @@ use server::resource_pile::AdvancePaymentOptions; use server::status_phase::{StatusPhaseAction, StatusPhaseState}; use crate::client_state::{ActiveDialog, ShownPlayer, StateUpdate}; -use crate::dialog_ui::dialog_window; +use crate::dialog_ui::dialog; use crate::payment_ui::{payment_dialog, HasPayment, Payment, ResourcePayment}; use crate::resource_ui::{new_resource_map, ResourceType}; use crate::select_ui::HasCountSelectableObject; @@ -99,24 +99,28 @@ pub fn show_generic_advance_menu( close_button: bool, new_update: impl Fn(String) -> StateUpdate, ) -> StateUpdate { - dialog_window(player, title, close_button, |ui| { + dialog(title, close_button, |ui| { + let p = player.get(game); for a in get_all() { let name = a.name; - let p = player.get(game); - 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) + if player.can_play_action { + if p.has_advance(&name) { + ui.label(None, &name); } else { - player.can_control && p.can_advance(&name) - }; - if can && ui.button(None, name.clone()) { - return new_update(name); + let can = if matches!( + game.state, + GameState::StatusPhase(StatusPhaseState::FreeAdvance) + ) { + p.can_advance_free(&name) + } else { + player.can_control && p.can_advance(&name) + }; + if can && ui.button(None, name.clone()) { + return new_update(name); + } } + } else if p.has_advance(&name) { + ui.label(None, &name); } } StateUpdate::None diff --git a/client/src/city_ui.rs b/client/src/city_ui.rs index 8200eac5..475de69c 100644 --- a/client/src/city_ui.rs +++ b/client/src/city_ui.rs @@ -168,27 +168,28 @@ pub fn draw_city(owner: &Player, city: &City, state: &State) { let mut i = 0; city.pieces.wonders.iter().for_each(|w| { - let p = hex_ui::rotate_around(c, 30.0, 90 * i); - draw_text( - &w.name, - p.x - 10.0, - p.y + 10.0, - 40.0, - player_ui::player_color(owner.index), - ); + let p = hex_ui::rotate_around(c, 20.0, 90 * i); + draw_circle(p.x, p.y, 18.0, player_ui::player_color(owner.index)); + draw_text(&w.name, p.x - 10.0, p.y + 10.0, 40.0, BLACK); i += 1; }); for player_index in 0..4 { for b in &city.pieces.buildings(Some(player_index)) { - let p = hex_ui::rotate_around(c, 30.0, 90 * i); - draw_text( - building_symbol(b), - p.x - 10.0, - p.y + 10.0, - 40.0, - player_ui::player_color(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(), + ) + } else { + hex_ui::rotate_around(c, 20.0, 90 * i) + }; + draw_circle(p.x, p.y, 12.0, player_ui::player_color(player_index)); + draw_text(building_symbol(b), p.x - 7.0, p.y + 8.0, 30.0, BLACK); i += 1; } } diff --git a/client/src/dialog_ui.rs b/client/src/dialog_ui.rs index c02d1721..47329d19 100644 --- a/client/src/dialog_ui.rs +++ b/client/src/dialog_ui.rs @@ -9,7 +9,13 @@ pub fn active_dialog_window(player: &ShownPlayer, title: &str, f: F) -> State where F: FnOnce(&mut Ui) -> StateUpdate, { - dialog_window(player, title, false, f) + dialog(title, false, |ui| { + if player.can_control { + f(ui) + } else { + StateUpdate::None + } + }) } pub fn closeable_dialog_window(title: &str, f: F) -> StateUpdate @@ -19,20 +25,7 @@ where dialog(title, true, f) } -pub fn dialog_window(player: &ShownPlayer, title: &str, close_button: bool, f: F) -> StateUpdate -where - F: FnOnce(&mut Ui) -> StateUpdate, -{ - dialog(title, close_button, |ui| { - if player.can_control { - f(ui) - } else { - StateUpdate::None - } - }) -} - -fn dialog(title: &str, close_button: bool, f: F) -> StateUpdate +pub fn dialog(title: &str, close_button: bool, f: F) -> StateUpdate where F: FnOnce(&mut Ui) -> StateUpdate, { @@ -40,6 +33,7 @@ where .titlebar(true) .movable(false) .label(title) + .movable(true) .close_button(close_button); let ui = &mut root_ui(); diff --git a/client/src/hex_ui.rs b/client/src/hex_ui.rs index 2445fb8b..7ed8c3bf 100644 --- a/client/src/hex_ui.rs +++ b/client/src/hex_ui.rs @@ -55,7 +55,10 @@ pub fn pixel_to_coordinate(x: f32, y: f32) -> Coordinate { } pub fn rotate_around(center: Point, radius: f32, angle_deg: i32) -> Point { - let angle_rad = PI / 180.0 * (angle_deg as f32); + rotate_around_rad(center, radius, PI / 180.0 * (angle_deg as f32)) +} + +pub fn rotate_around_rad(center: Point, radius: f32, angle_rad: f32) -> Point { Point { x: center.x + radius * f32::cos(angle_rad), y: center.y + radius * f32::sin(angle_rad), diff --git a/client/src/local_client.rs b/client/src/local_client.rs index 05048668..247e62bf 100644 --- a/client/src/local_client.rs +++ b/client/src/local_client.rs @@ -99,6 +99,25 @@ pub fn setup_local_game() -> Game { .get_city_mut(Position::from_offset("A1")) .unwrap() .increase_mood_state(); + game.players[player_index1] + .get_city_mut(Position::from_offset("C2")) + .unwrap() + .pieces + .academy = Some(1); + game.players[player_index1] + .get_city_mut(Position::from_offset("C2")) + .unwrap() + .pieces + .port = Some(1); + game.players[player_index1] + .get_city_mut(Position::from_offset("C2")) + .unwrap() + .port_position = Some(Position::from_offset("D2")); + game.players[player_index1] + .get_city_mut(Position::from_offset("C2")) + .unwrap() + .pieces + .wonders = vec![game.wonders_left.pop().unwrap()]; game.players[player_index1] .get_city_mut(Position::from_offset("C2")) .unwrap() diff --git a/client/src/log_ui.rs b/client/src/log_ui.rs index 8ad80ee6..440fa842 100644 --- a/client/src/log_ui.rs +++ b/client/src/log_ui.rs @@ -1,3 +1,4 @@ +use macroquad::ui::Ui; use server::game::Game; use crate::client_state::StateUpdate; @@ -6,9 +7,25 @@ use crate::dialog_ui::closeable_dialog_window; pub fn show_log(game: &Game) -> StateUpdate { closeable_dialog_window("Log", |ui| { game.log.iter().for_each(|l| { - ui.label(None, l); + multiline(ui, l); }); - StateUpdate::None }) } + +fn multiline(ui: &mut Ui, text: &str) { + let mut line = String::new(); + text.split(' ').for_each(|s| { + if line.len() + s.len() > 100 { + ui.label(None, &line); + line = String::new(); + } + if !line.is_empty() { + line.push(' '); + } + line.push_str(s); + }); + if !line.is_empty() { + ui.label(None, &line); + } +} diff --git a/client/src/map_ui.rs b/client/src/map_ui.rs index 0cc12f13..02632e1a 100644 --- a/client/src/map_ui.rs +++ b/client/src/map_ui.rs @@ -2,6 +2,7 @@ use itertools::Itertools; use macroquad::math::vec2; use macroquad::prelude::*; use macroquad::ui::Ui; +use std::ops::{Add, Mul, Sub}; use server::action::Action; use server::combat::Combat; @@ -94,11 +95,15 @@ fn alpha(game: &Game, state: &State, pos: Position) -> f32 { fn draw_combat_arrow(c: &Combat) { let from = hex_ui::center(c.attacker_position); let to = hex_ui::center(c.defender_position); - draw_line(from.x, from.y, to.x, to.y, 10., BLACK); + let to_vec = vec2(to.x, to.y); + let from_vec = vec2(from.x, from.y); + let end = from_vec.add(to_vec.sub(from_vec).mul(0.7)); + draw_line(from.x, from.y, end.x, end.y, 10., BLACK); + let angle = from_vec.sub(to_vec).normalize(); draw_triangle( - vec2(to.x, to.y), - vec2(to.x + 30., to.y + 30.), - vec2(to.x - 30., to.y + 30.), + to_vec.add(angle.rotate(vec2(10., 0.))), + to_vec.add(angle.rotate(vec2(30., 30.))), + to_vec.add(angle.rotate(vec2(30., -30.))), BLACK, ); } diff --git a/client/src/move_ui.rs b/client/src/move_ui.rs index 06122976..9ee8916e 100644 --- a/client/src/move_ui.rs +++ b/client/src/move_ui.rs @@ -45,7 +45,9 @@ pub fn move_units_dialog(game: &Game, sel: &MoveSelection, player: &ShownPlayer) } fn update_possible_destinations(game: &Game, mut sel: MoveSelection) -> StateUpdate { - if let Some(start) = sel.start { + if sel.units.is_empty() { + sel.destinations.clear(); + } else if let Some(start) = sel.start { sel.destinations = possible_destinations(game, start, sel.player_index, &sel.units); } else { sel.destinations.clear(); diff --git a/client/src/unit_ui.rs b/client/src/unit_ui.rs index abac594c..72d463cd 100644 --- a/client/src/unit_ui.rs +++ b/client/src/unit_ui.rs @@ -1,7 +1,7 @@ -use std::collections::{HashMap, HashSet}; - +use macroquad::color::BLACK; use macroquad::math::u32; use macroquad::prelude::draw_text; +use macroquad::shapes::draw_circle; use macroquad::ui::Ui; use server::game::Game; @@ -13,21 +13,15 @@ use crate::dialog_ui::active_dialog_window; use crate::select_ui::{confirm_update, ConfirmSelection}; use crate::{hex_ui, player_ui}; +use itertools::Itertools; + pub fn draw_unit(unit: &Unit, index: u32) { let c = hex_ui::center(unit.position); - let r = if unit.unit_type == UnitType::Settler { - 25. - } else { - 40. - }; - let p = hex_ui::rotate_around(c, r, (90 * index) as i32 + 45); - draw_text( - unit_symbol(unit), - p.x - 7.0, - p.y + 7.0, - 25.0, - player_ui::player_color(unit.player_index), - ); + let r = 40.0; + let p = hex_ui::rotate_around(c, r, (40 * index) as i32 + 45); + draw_circle(p.x, p.y, 11.0, BLACK); + draw_circle(p.x, p.y, 9.0, player_ui::player_color(unit.player_index)); + draw_text(unit_symbol(unit), p.x - 5.0, p.y + 5.0, 20.0, BLACK); } fn unit_symbol(unit: &Unit) -> &str { @@ -52,22 +46,17 @@ pub fn non_leader_names() -> [(UnitType, &'static str); 5] { } pub fn draw_units(game: &Game) { - for p in &game.players { - let mut positions: HashSet<&Position> = HashSet::new(); - let mut city_unit_index: HashMap = HashMap::new(); - let mut settler_index: HashMap = HashMap::new(); - for unit in &p.units { - let map = if unit.unit_type == UnitType::Settler { - &mut settler_index - } else { - &mut city_unit_index - }; - let e = map.entry(unit.position).or_default(); - *e += 1; - draw_unit(unit, *e); - - if positions.insert(&unit.position) {} - } + for (_pos, units) in &game + .players + .iter() + .flat_map(|p| &p.units) + .sorted_by_key(|u| u.position) + .chunk_by(|a| a.position) + { + let vec = units.collect::>(); + vec.iter().enumerate().for_each(|(i, u)| { + draw_unit(u, i.try_into().unwrap()); + }); } }