Skip to content

Commit 59ff933

Browse files
authored
incidents (#168)
1 parent 9e9aabd commit 59ff933

File tree

110 files changed

+8803
-821
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

110 files changed

+8803
-821
lines changed

client/src/city_ui.rs

+136-22
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,26 @@ use crate::action_buttons::{
44
use crate::client_state::{ActiveDialog, StateUpdate};
55
use crate::collect_ui::CollectResources;
66
use crate::construct_ui::{new_building_positions, ConstructionPayment, ConstructionProject};
7+
use crate::custom_phase_ui::{highlight_structures, StructureHighlight};
78
use crate::happiness_ui::{
89
add_increase_happiness, can_play_increase_happiness, open_increase_happiness_dialog,
910
};
1011
use crate::hex_ui;
11-
use crate::hex_ui::Point;
12-
use crate::layout_ui::draw_scaled_icon;
12+
use crate::layout_ui::{draw_scaled_icon, is_in_circle};
1313
use crate::map_ui::{move_units_buttons, show_map_action_buttons};
1414
use crate::recruit_unit_ui::RecruitAmount;
1515
use crate::render_context::RenderContext;
16+
use crate::select_ui::HighlightType;
17+
use itertools::Itertools;
1618
use macroquad::prelude::*;
1719
use server::city::{City, MoodState};
1820
use server::city_pieces::Building;
1921
use server::collect::possible_resource_collections;
2022
use server::content::custom_actions::CustomActionType;
23+
use server::content::custom_phase_actions::Structure;
2124
use server::game::Game;
2225
use server::playing_actions::PlayingActionType;
26+
use server::position::Position;
2327
use server::resource::ResourceType;
2428
use server::unit::{UnitType, Units};
2529
use std::collections::HashMap;
@@ -241,11 +245,66 @@ pub fn city_labels(game: &Game, city: &City) -> Vec<String> {
241245

242246
pub const BUILDING_SIZE: f32 = 12.0;
243247

244-
pub fn draw_city(rc: &RenderContext, city: &City) {
248+
fn structure_selected(
249+
rc: &RenderContext,
250+
position: Position,
251+
center: Vec2,
252+
size: f32,
253+
h: &StructureHighlight,
254+
) -> Option<StateUpdate> {
255+
draw_circle_lines(center.x, center.y, size, 3., h.highlight_type.color());
256+
if is_mouse_button_pressed(MouseButton::Left) && is_in_circle(rc.mouse_pos(), center, size) {
257+
let ActiveDialog::StructuresRequest(r) = &rc.state.active_dialog else {
258+
panic!("invalid state");
259+
};
260+
if let Some(i) = r
261+
.structures
262+
.iter()
263+
.position(|(pos, s)| s == &h.structure && pos == &position)
264+
{
265+
let mut new = r.clone();
266+
new.structures.remove(i);
267+
return Some(StateUpdate::OpenDialog(ActiveDialog::StructuresRequest(
268+
new,
269+
)));
270+
}
271+
if r.request.choices.contains(&(position, h.structure.clone())) {
272+
let mut new = r.clone();
273+
new.structures.push((position, h.structure.clone()));
274+
return Some(StateUpdate::OpenDialog(ActiveDialog::StructuresRequest(
275+
new,
276+
)));
277+
};
278+
}
279+
None
280+
}
281+
282+
pub fn draw_city(rc: &RenderContext, city: &City) -> Option<StateUpdate> {
245283
let c = hex_ui::center(city.position);
246284
let owner = city.player_index;
247285

248-
if city.is_activated() {
286+
let highlighted = match rc.state.active_dialog {
287+
ActiveDialog::StructuresRequest(ref s) => highlight_structures(
288+
&position_structures(city, &s.structures),
289+
HighlightType::Primary,
290+
)
291+
.into_iter()
292+
.chain(highlight_structures(
293+
&position_structures(city, &s.request.choices),
294+
HighlightType::Secondary,
295+
))
296+
.collect_vec(),
297+
_ => vec![],
298+
};
299+
300+
if let Some(h) = highlighted
301+
.iter()
302+
.find(|s| matches!(s.structure, Structure::CityCenter))
303+
{
304+
if let Some(u) = structure_selected(rc, city.position, c, 15., h) {
305+
return Some(u);
306+
}
307+
} else if city.is_activated() {
249308
draw_circle(c.x, c.y, 18.0, WHITE);
250309
}
251310
draw_circle(c.x, c.y, 15.0, rc.player_color(owner));
@@ -272,29 +331,38 @@ pub fn draw_city(rc: &RenderContext, city: &City) {
272331
rc,
273332
t,
274333
&format!("Happiness: {:?}", city.mood_state),
275-
c.to_vec2() + vec2(-size / 2., -size / 2.),
334+
c + vec2(-size / 2., -size / 2.),
276335
size,
277336
);
278337
}
279338

280-
let mut i = 0;
281-
city.pieces.wonders.iter().for_each(|w| {
282-
let p = hex_ui::rotate_around(c, 20.0, 90 * i);
283-
draw_circle(p.x, p.y, 18.0, rc.player_color(owner));
284-
let size = 20.;
285-
draw_scaled_icon(
286-
rc,
287-
&rc.assets().wonders[&w.name],
288-
&w.name,
289-
p.to_vec2() + vec2(-size / 2., -size / 2.),
290-
size,
291-
);
292-
i += 1;
293-
});
339+
let i = match draw_wonders(rc, city, c, owner, &highlighted) {
340+
Ok(value) => value,
341+
Err(value) => return Some(value),
342+
};
294343

344+
draw_buildings(rc, city, c, &highlighted, i)
345+
}
346+
347+
fn draw_buildings(
348+
rc: &RenderContext,
349+
city: &City,
350+
center: Vec2,
351+
highlighted: &[StructureHighlight],
352+
mut i: usize,
353+
) -> Option<StateUpdate> {
354+
let state = &rc.state;
295355
for player_index in 0..4 {
296356
for b in &city.pieces.buildings(Some(player_index)) {
297-
let p = building_position(city, c, i, *b);
357+
let p = building_position(city, center, i, *b);
358+
if let Some(h) = highlighted
359+
.iter()
360+
.find(|s| matches!(s.structure, Structure::Building(bb) if bb == *b))
361+
{
362+
if let Some(u) = structure_selected(rc, city.position, p, BUILDING_SIZE, h) {
363+
return Some(u);
364+
}
365+
}
298366
draw_circle(p.x, p.y, BUILDING_SIZE, rc.player_color(player_index));
299367
let tooltip = if matches!(state.active_dialog, ActiveDialog::CulturalInfluence(_)) {
300368
""
@@ -305,15 +373,61 @@ pub fn draw_city(rc: &RenderContext, city: &City) {
305373
rc,
306374
&rc.assets().buildings[b],
307375
tooltip,
308-
p.to_vec2() + vec2(-8., -8.),
376+
p + vec2(-8., -8.),
309377
16.,
310378
);
311379
i += 1;
312380
}
313381
}
382+
None
383+
}
384+
385+
#[allow(clippy::result_large_err)]
386+
fn draw_wonders(
387+
rc: &RenderContext,
388+
city: &City,
389+
c: Vec2,
390+
owner: usize,
391+
highlighted: &[StructureHighlight],
392+
) -> Result<usize, StateUpdate> {
393+
let mut i = 0;
394+
for w in &city.pieces.wonders {
395+
let p = hex_ui::rotate_around(c, 20.0, 90 * i);
396+
draw_circle(p.x, p.y, 18.0, rc.player_color(owner));
397+
let size = 20.;
398+
if let Some(h) = highlighted
399+
.iter()
400+
.find(|s| matches!(&s.structure, Structure::Wonder(n) if n == &w.name))
401+
{
402+
if let Some(u) = structure_selected(rc, city.position, p, 18., h) {
403+
return Err(u);
404+
}
405+
}
406+
draw_scaled_icon(
407+
rc,
408+
&rc.assets().wonders[&w.name],
409+
&w.name,
410+
p + vec2(-size / 2., -size / 2.),
411+
size,
412+
);
413+
i += 1;
414+
}
415+
Ok(i)
416+
}
417+
418+
fn position_structures(city: &City, list: &[(Position, Structure)]) -> Vec<Structure> {
419+
list.iter()
420+
.filter_map(|(pos, st)| {
421+
if pos == &city.position {
422+
Some(st.clone())
423+
} else {
424+
None
425+
}
426+
})
427+
.collect_vec()
314428
}
315429

316-
pub fn building_position(city: &City, center: Point, i: usize, building: Building) -> Point {
430+
pub fn building_position(city: &City, center: Vec2, i: usize, building: Building) -> Vec2 {
317431
if matches!(building, Building::Port) {
318432
let r: f32 = city
319433
.position

client/src/client.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
use macroquad::input::{is_mouse_button_pressed, mouse_position, MouseButton};
1+
use macroquad::input::{is_mouse_button_pressed, MouseButton};
22
use macroquad::prelude::clear_background;
33
use macroquad::prelude::*;
44

55
use server::action::Action;
6-
use server::content::custom_phase_actions::CustomPhaseEventAction;
6+
use server::content::custom_phase_actions::CurrentEventResponse;
77
use server::game::Game;
88
use server::position::Position;
99

@@ -167,11 +167,12 @@ fn render_active_dialog(rc: &RenderContext) -> StateUpdate {
167167
ActiveDialog::PaymentRequest(c) => custom_phase_ui::custom_phase_payment_dialog(rc, c),
168168
ActiveDialog::PlayerRequest(r) => custom_phase_ui::player_request_dialog(rc, r),
169169
ActiveDialog::ResourceRewardRequest(p) => custom_phase_ui::payment_reward_dialog(rc, p),
170-
ActiveDialog::AdvanceRewardRequest(r) => {
170+
ActiveDialog::AdvanceRequest(r) => {
171171
custom_phase_ui::advance_reward_dialog(rc, r, &custom_phase_event_origin(rc).name())
172172
}
173173
ActiveDialog::UnitTypeRequest(r) => custom_phase_ui::unit_request_dialog(rc, r),
174174
ActiveDialog::UnitsRequest(r) => custom_phase_ui::select_units_dialog(rc, r),
175+
ActiveDialog::StructuresRequest(r) => custom_phase_ui::select_structures_dialog(rc, r),
175176
ActiveDialog::BoolRequest => custom_phase_ui::bool_request_dialog(rc),
176177
}
177178
}
@@ -189,12 +190,11 @@ fn dialog_chooser(rc: &RenderContext, c: &DialogChooser) -> StateUpdate {
189190

190191
pub fn try_click(rc: &RenderContext) -> StateUpdate {
191192
let game = rc.game;
192-
let state = &rc.state;
193-
let mouse_pos = state.camera.screen_to_world(mouse_position().into());
193+
let mouse_pos = rc.mouse_pos();
194194
let pos = Position::from_coordinate(pixel_to_coordinate(mouse_pos));
195195

196196
if rc.can_control() {
197-
if let ActiveDialog::CulturalInfluence(b) = &state.active_dialog {
197+
if let ActiveDialog::CulturalInfluence(b) = &rc.state.active_dialog {
198198
return influence_ui::hover(rc, mouse_pos, b);
199199
}
200200
}
@@ -227,7 +227,7 @@ fn controlling_player_click(rc: &RenderContext, mouse_pos: Vec2, pos: Position)
227227
ActiveDialog::PositionRequest(r) => {
228228
if r.choices.contains(&pos) {
229229
StateUpdate::Execute(Action::CustomPhaseEvent(
230-
CustomPhaseEventAction::SelectPosition(pos),
230+
CurrentEventResponse::SelectPosition(pos),
231231
))
232232
} else {
233233
StateUpdate::None

client/src/client_state.rs

+23-17
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use crate::assets::Assets;
22
use crate::client::{Features, GameSyncRequest};
33
use crate::collect_ui::CollectResources;
44
use crate::construct_ui::ConstructionPayment;
5-
use crate::custom_phase_ui::UnitsSelection;
5+
use crate::custom_phase_ui::{StructuresSelection, UnitsSelection};
66
use crate::dialog_ui::{BaseOrCustomAction, BaseOrCustomDialog};
77
use crate::event_ui::{custom_phase_event_help, event_help, pay_help};
88
use crate::happiness_ui::IncreaseHappinessConfig;
@@ -17,7 +17,7 @@ use macroquad::prelude::*;
1717
use server::action::Action;
1818
use server::city::{City, MoodState};
1919
use server::content::custom_phase_actions::{
20-
AdvanceRewardRequest, CustomPhaseRequest, PlayerRequest, PositionRequest, UnitTypeRequest,
20+
AdvanceRequest, CurrentEventRequest, PlayerRequest, PositionRequest, UnitTypeRequest,
2121
};
2222
use server::cultural_influence::CulturalInfluenceResolution;
2323
use server::events::EventOrigin;
@@ -60,12 +60,13 @@ pub enum ActiveDialog {
6060
Theaters(Payment),
6161
Taxes(Payment),
6262
ResourceRewardRequest(Payment),
63-
AdvanceRewardRequest(AdvanceRewardRequest),
63+
AdvanceRequest(AdvanceRequest),
6464
PaymentRequest(Vec<Payment>),
6565
PlayerRequest(PlayerRequest),
6666
PositionRequest(PositionRequest),
6767
UnitTypeRequest(UnitTypeRequest),
6868
UnitsRequest(UnitsSelection),
69+
StructuresRequest(StructuresSelection),
6970
BoolRequest,
7071
}
7172

@@ -99,12 +100,13 @@ impl ActiveDialog {
99100
ActiveDialog::Theaters(_) => "theaters",
100101
ActiveDialog::Taxes(_) => "collect taxes",
101102
ActiveDialog::ResourceRewardRequest(_) => "trade route selection",
102-
ActiveDialog::AdvanceRewardRequest(_) => "advance selection",
103+
ActiveDialog::AdvanceRequest(_) => "advance selection",
103104
ActiveDialog::PaymentRequest(_) => "custom phase payment request",
104105
ActiveDialog::PlayerRequest(_) => "custom phase player request",
105106
ActiveDialog::PositionRequest(_) => "custom phase position request",
106107
ActiveDialog::UnitTypeRequest(_) => "custom phase unit request",
107108
ActiveDialog::UnitsRequest(_) => "custom phase units request",
109+
ActiveDialog::StructuresRequest(_) => "custom phase structures request",
108110
ActiveDialog::BoolRequest => "custom phase bool request",
109111
}
110112
}
@@ -174,12 +176,15 @@ impl ActiveDialog {
174176
event_help(rc, &EventOrigin::Advance("Theaters".to_string()), true)
175177
}
176178
ActiveDialog::ResourceRewardRequest(_)
177-
| ActiveDialog::AdvanceRewardRequest(_)
179+
| ActiveDialog::AdvanceRequest(_)
178180
| ActiveDialog::PaymentRequest(_)
179181
| ActiveDialog::BoolRequest => custom_phase_event_help(rc, None),
180182
ActiveDialog::PositionRequest(r) => custom_phase_event_help(rc, r.description.as_ref()),
181183
ActiveDialog::UnitTypeRequest(r) => custom_phase_event_help(rc, r.description.as_ref()),
182184
ActiveDialog::UnitsRequest(r) => custom_phase_event_help(rc, r.description.as_ref()),
185+
ActiveDialog::StructuresRequest(r) => {
186+
custom_phase_event_help(rc, r.request.description.as_ref())
187+
}
183188
ActiveDialog::PlayerRequest(r) => custom_phase_event_help(rc, Some(&r.description)),
184189
}
185190
}
@@ -231,7 +236,7 @@ impl ActiveDialog {
231236
| ActiveDialog::AdvancePayment(_)
232237
| ActiveDialog::ChangeGovernmentType
233238
| ActiveDialog::ChooseAdditionalAdvances(_)
234-
| ActiveDialog::AdvanceRewardRequest(_)
239+
| ActiveDialog::AdvanceRequest(_)
235240
)
236241
}
237242
}
@@ -524,9 +529,9 @@ impl State {
524529

525530
#[must_use]
526531
pub fn game_state_dialog(&self, game: &Game) -> ActiveDialog {
527-
if let Some(e) = &game.current_custom_phase_event() {
532+
if let Some(e) = &game.current_event_handler() {
528533
return match &e.request {
529-
CustomPhaseRequest::Payment(r) => ActiveDialog::PaymentRequest(
534+
CurrentEventRequest::Payment(r) => ActiveDialog::PaymentRequest(
530535
r.iter()
531536
.map(|p| {
532537
Payment::new(
@@ -538,24 +543,25 @@ impl State {
538543
})
539544
.collect(),
540545
),
541-
CustomPhaseRequest::ResourceReward(r) => {
546+
CurrentEventRequest::ResourceReward(r) => {
542547
ActiveDialog::ResourceRewardRequest(Payment::new_gain(&r.reward, &r.name))
543548
}
544-
CustomPhaseRequest::AdvanceReward(r) => {
545-
ActiveDialog::AdvanceRewardRequest(r.clone())
546-
}
547-
CustomPhaseRequest::SelectPosition(r) => ActiveDialog::PositionRequest(r.clone()),
548-
CustomPhaseRequest::SelectUnitType(r) => ActiveDialog::UnitTypeRequest(r.clone()),
549-
CustomPhaseRequest::SelectUnits(r) => {
549+
CurrentEventRequest::SelectAdvance(r) => ActiveDialog::AdvanceRequest(r.clone()),
550+
CurrentEventRequest::SelectPosition(r) => ActiveDialog::PositionRequest(r.clone()),
551+
CurrentEventRequest::SelectUnitType(r) => ActiveDialog::UnitTypeRequest(r.clone()),
552+
CurrentEventRequest::SelectUnits(r) => {
550553
ActiveDialog::UnitsRequest(UnitsSelection::new(
551554
r.player,
552555
r.needed,
553556
r.choices.clone(),
554557
r.description.clone(),
555558
))
556559
}
557-
CustomPhaseRequest::SelectPlayer(r) => ActiveDialog::PlayerRequest(r.clone()),
558-
CustomPhaseRequest::BoolRequest => ActiveDialog::BoolRequest,
560+
CurrentEventRequest::SelectStructures(s) => {
561+
ActiveDialog::StructuresRequest(StructuresSelection::new(s))
562+
}
563+
CurrentEventRequest::SelectPlayer(r) => ActiveDialog::PlayerRequest(r.clone()),
564+
CurrentEventRequest::BoolRequest => ActiveDialog::BoolRequest,
559565
};
560566
}
561567
match &game.state {

0 commit comments

Comments
 (0)