Skip to content

Commit da78096

Browse files
authored
custom actions (#156)
1 parent 2028ed1 commit da78096

File tree

192 files changed

+5052
-3855
lines changed

Some content is hidden

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

192 files changed

+5052
-3855
lines changed

client/assets/stadium-svgrepo-com.png

10.1 KB
Loading

client/assets/tax-svgrepo-com.png

12.6 KB
Loading

client/src/action_buttons.rs

+79-31
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
1+
use crate::city_ui::{IconAction, IconActionVec};
12
use crate::client_state::{ActiveDialog, StateUpdate};
23
use crate::dialog_ui::{BaseOrCustomAction, BaseOrCustomDialog};
3-
use crate::happiness_ui::{can_play_increase_happiness, open_increase_happiness_dialog};
4+
use crate::event_ui::event_help;
5+
use crate::happiness_ui::{
6+
can_play_increase_happiness, can_play_influence_culture, open_increase_happiness_dialog,
7+
};
48
use crate::layout_ui::{bottom_left_texture, icon_pos};
59
use crate::move_ui::MoveIntent;
10+
use crate::payment_ui::Payment;
611
use crate::render_context::RenderContext;
712
use server::action::Action;
8-
use server::content::advances::get_advance;
13+
use server::city::City;
14+
use server::content::advances_culture::{sports_options, theaters_options};
15+
use server::content::advances_economy::tax_options;
916
use server::content::custom_actions::{CustomAction, CustomActionType};
1017
use server::game::GameState;
1118
use server::playing_actions::{PlayingAction, PlayingActionType};
@@ -36,35 +43,64 @@ pub fn action_buttons(rc: &RenderContext) -> StateUpdate {
3643
{
3744
return StateUpdate::OpenDialog(ActiveDialog::AdvanceMenu);
3845
}
39-
if rc.can_play_action(PlayingActionType::InfluenceCultureAttempt)
46+
if can_play_influence_culture(rc)
4047
&& bottom_left_texture(
4148
rc,
4249
&assets.resources[&ResourceType::CultureTokens],
4350
icon_pos(1, -2),
4451
"Cultural Influence",
4552
)
4653
{
47-
return StateUpdate::OpenDialog(ActiveDialog::CulturalInfluence);
54+
return base_or_custom_action(
55+
rc,
56+
PlayingActionType::InfluenceCultureAttempt,
57+
"Influence culture",
58+
&[("Arts", CustomActionType::ArtsInfluenceCultureAttempt)],
59+
ActiveDialog::CulturalInfluence,
60+
);
4861
}
49-
for (i, a) in game
50-
.get_available_custom_actions(rc.shown_player.index)
51-
.iter()
52-
.enumerate()
53-
{
54-
if let Some(action) = generic_custom_action(a) {
62+
let mut i = 0;
63+
for (a, origin) in &game.get_available_custom_actions(rc.shown_player.index) {
64+
if let Some(action) = generic_custom_action(rc, a, None) {
5565
if bottom_left_texture(
5666
rc,
5767
&assets.custom_actions[a],
5868
icon_pos(i as i8, -1),
59-
&custom_action_tooltip(a),
69+
&event_help(rc, origin, false)[0],
6070
) {
61-
return StateUpdate::execute(Action::Playing(PlayingAction::Custom(action)));
71+
return action;
6272
}
73+
i += 1;
74+
}
75+
}
76+
for (i, (icon, tooltip, action)) in custom_action_buttons(rc, None).iter().enumerate() {
77+
if bottom_left_texture(rc, icon, icon_pos(i as i8, -1), tooltip) {
78+
return action();
6379
}
6480
}
6581
StateUpdate::None
6682
}
6783

84+
pub fn custom_action_buttons<'a>(
85+
rc: &'a RenderContext,
86+
city: Option<&'a City>,
87+
) -> IconActionVec<'a> {
88+
rc.game
89+
.get_available_custom_actions(rc.shown_player.index)
90+
.into_iter()
91+
.filter_map(|(a, origin)| {
92+
generic_custom_action(rc, &a, city).map(|action| {
93+
let a: IconAction<'a> = (
94+
&rc.assets().custom_actions[&a],
95+
event_help(rc, &origin, false)[0].clone(),
96+
Box::new(move || action.clone()),
97+
);
98+
a
99+
})
100+
})
101+
.collect()
102+
}
103+
68104
fn global_move(rc: &RenderContext) -> StateUpdate {
69105
let pos = rc.state.focused_tile;
70106
StateUpdate::move_units(
@@ -78,24 +114,40 @@ fn global_move(rc: &RenderContext) -> StateUpdate {
78114
)
79115
}
80116

81-
fn custom_action_tooltip(custom_action_type: &CustomActionType) -> String {
82-
match custom_action_type {
83-
CustomActionType::ConstructWonder => "Construct a wonder".to_string(),
84-
CustomActionType::AbsolutePower => get_advance("Absolute Power").description,
85-
CustomActionType::VotingIncreaseHappiness => get_advance("Voting").description,
86-
CustomActionType::FreeEconomyCollect => get_advance("Free Economy").description,
117+
fn generic_custom_action(
118+
rc: &RenderContext,
119+
custom_action_type: &CustomActionType,
120+
city: Option<&City>,
121+
) -> Option<StateUpdate> {
122+
if let Some(city) = city {
123+
if matches!(custom_action_type, CustomActionType::Sports) {
124+
if let Some(options) = sports_options(city) {
125+
return Some(StateUpdate::OpenDialog(ActiveDialog::Sports((
126+
Payment::new_gain(&options, "Increase happiness using sports"),
127+
city.position,
128+
))));
129+
}
130+
}
87131
}
88-
}
89132

90-
fn generic_custom_action(custom_action_type: &CustomActionType) -> Option<CustomAction> {
91133
match custom_action_type {
92134
CustomActionType::ConstructWonder
135+
| CustomActionType::ArtsInfluenceCultureAttempt
93136
| CustomActionType::VotingIncreaseHappiness
94-
| CustomActionType::FreeEconomyCollect => {
137+
| CustomActionType::FreeEconomyCollect
138+
| CustomActionType::Sports => {
95139
// handled explicitly
96140
None
97141
}
98-
CustomActionType::AbsolutePower => Some(CustomAction::ForcedLabor),
142+
CustomActionType::AbsolutePower => Some(StateUpdate::execute(Action::Playing(
143+
PlayingAction::Custom(CustomAction::AbsolutePower),
144+
))),
145+
CustomActionType::Taxes => Some(StateUpdate::OpenDialog(ActiveDialog::Taxes(
146+
Payment::new_gain(&tax_options(rc.shown_player), "Collect taxes"),
147+
))),
148+
CustomActionType::Theaters => Some(StateUpdate::OpenDialog(ActiveDialog::Theaters(
149+
Payment::new_gain(&theaters_options(), "Convert Resources"),
150+
))),
99151
}
100152
}
101153

@@ -108,8 +160,7 @@ pub fn base_or_custom_available(
108160
|| (rc.game.state == GameState::Playing
109161
&& rc
110162
.game
111-
.get_available_custom_actions(rc.shown_player.index)
112-
.contains(custom))
163+
.is_custom_action_available(rc.shown_player.index, custom))
113164
}
114165

115166
pub fn base_or_custom_action(
@@ -128,17 +179,14 @@ pub fn base_or_custom_action(
128179
None
129180
};
130181

131-
let special = rc
132-
.game
133-
.get_available_custom_actions(rc.shown_player.index)
182+
let special = custom
134183
.iter()
135-
.find(|a| custom.iter().any(|(_, b)| **a == *b))
136-
.map(|a| {
137-
let advance = custom.iter().find(|(_, b)| *b == *a).unwrap().0;
184+
.find(|(_, a)| rc.game.is_custom_action_available(rc.shown_player.index, a))
185+
.map(|(advance, a)| {
138186
let dialog = execute(BaseOrCustomDialog {
139187
custom: BaseOrCustomAction::Custom {
140188
custom: a.clone(),
141-
advance: advance.to_string(),
189+
advance: (*advance).to_string(),
142190
},
143191
title: format!("{title} with {advance}"),
144192
});

client/src/assets.rs

+20-4
Original file line numberDiff line numberDiff line change
@@ -216,10 +216,26 @@ impl Assets {
216216
}
217217

218218
fn custom_actions() -> HashMap<CustomActionType, Texture2D> {
219-
[(
220-
CustomActionType::AbsolutePower,
221-
load_png(include_bytes!("../assets/slavery-whip-svgrepo-com.png")),
222-
)]
219+
[
220+
(
221+
CustomActionType::AbsolutePower,
222+
load_png(include_bytes!("../assets/slavery-whip-svgrepo-com.png")),
223+
),
224+
(
225+
CustomActionType::Taxes,
226+
load_png(include_bytes!("../assets/tax-svgrepo-com.png")),
227+
),
228+
(
229+
CustomActionType::Theaters,
230+
load_png(include_bytes!(
231+
"../assets/temple-building-with-columns-svgrepo-com.png"
232+
)),
233+
),
234+
(
235+
CustomActionType::Sports,
236+
load_png(include_bytes!("../assets/stadium-svgrepo-com.png")),
237+
),
238+
]
223239
.iter()
224240
.cloned()
225241
.collect()

client/src/city_ui.rs

+15-10
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
use crate::action_buttons::{base_or_custom_action, base_or_custom_available};
1+
use crate::action_buttons::{
2+
base_or_custom_action, base_or_custom_available, custom_action_buttons,
3+
};
24
use crate::client_state::{ActiveDialog, StateUpdate};
35
use crate::collect_ui::CollectResources;
46
use crate::construct_ui::{new_building_positions, ConstructionPayment, ConstructionProject};
@@ -42,6 +44,7 @@ pub fn show_city_menu<'a>(rc: &'a RenderContext, city: &'a City) -> StateUpdate
4244
move_units_buttons(rc, city.position),
4345
building_icons(rc, city),
4446
wonder_icons(rc, city),
47+
custom_action_buttons(rc, Some(city)),
4548
]
4649
.into_iter()
4750
.flatten()
@@ -70,7 +73,7 @@ fn increase_happiness_button<'a>(rc: &'a RenderContext, city: &'a City) -> Optio
7073
}
7174

7275
fn wonder_icons<'a>(rc: &'a RenderContext, city: &'a City) -> IconActionVec<'a> {
73-
if !rc.can_play_action(PlayingActionType::Construct) {
76+
if !city.can_activate() || !rc.can_play_action(PlayingActionType::Construct) {
7477
// is this the right thing to check?
7578
return vec![];
7679
}
@@ -102,7 +105,7 @@ fn wonder_icons<'a>(rc: &'a RenderContext, city: &'a City) -> IconActionVec<'a>
102105
}
103106

104107
fn building_icons<'a>(rc: &'a RenderContext, city: &'a City) -> IconActionVec<'a> {
105-
if !rc.can_play_action(PlayingActionType::Construct) {
108+
if !city.can_activate() || !rc.can_play_action(PlayingActionType::Construct) {
106109
return vec![];
107110
}
108111
let owner = rc.shown_player;
@@ -144,7 +147,7 @@ fn building_icons<'a>(rc: &'a RenderContext, city: &'a City) -> IconActionVec<'a
144147
}
145148

146149
fn recruit_button<'a>(rc: &'a RenderContext, city: &'a City) -> Option<IconAction<'a>> {
147-
if !rc.can_play_action(PlayingActionType::Recruit) {
150+
if !city.can_activate() || !rc.can_play_action(PlayingActionType::Recruit) {
148151
return None;
149152
}
150153
Some((
@@ -164,11 +167,13 @@ fn recruit_button<'a>(rc: &'a RenderContext, city: &'a City) -> Option<IconActio
164167
}
165168

166169
fn collect_resources_button<'a>(rc: &'a RenderContext, city: &'a City) -> Option<IconAction<'a>> {
167-
if !base_or_custom_available(
168-
rc,
169-
PlayingActionType::Collect,
170-
&CustomActionType::FreeEconomyCollect,
171-
) {
170+
if !city.can_activate()
171+
|| !base_or_custom_available(
172+
rc,
173+
PlayingActionType::Collect,
174+
&CustomActionType::FreeEconomyCollect,
175+
)
176+
{
172177
return None;
173178
}
174179
Some((
@@ -291,7 +296,7 @@ pub fn draw_city(rc: &RenderContext, city: &City) {
291296
BUILDING_SIZE,
292297
player_ui::player_color(player_index),
293298
);
294-
let tooltip = if matches!(state.active_dialog, ActiveDialog::CulturalInfluence) {
299+
let tooltip = if matches!(state.active_dialog, ActiveDialog::CulturalInfluence(_)) {
295300
""
296301
} else {
297302
b.name()

client/src/client.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ fn render_active_dialog(rc: &RenderContext) -> StateUpdate {
129129
match &state.active_dialog {
130130
ActiveDialog::None
131131
| ActiveDialog::WaitingForUpdate
132-
| ActiveDialog::CulturalInfluence
132+
| ActiveDialog::CulturalInfluence(_)
133133
| ActiveDialog::PlaceSettler => StateUpdate::None,
134134
ActiveDialog::DialogChooser(d) => dialog_chooser(rc, d),
135135
ActiveDialog::Log => show_log(rc),
@@ -163,6 +163,10 @@ fn render_active_dialog(rc: &RenderContext) -> StateUpdate {
163163
ActiveDialog::Retreat => combat_ui::retreat_dialog(rc),
164164
ActiveDialog::RemoveCasualties(s) => combat_ui::remove_casualties_dialog(rc, s),
165165

166+
ActiveDialog::Sports((p, pos)) => custom_actions_ui::sports(rc, p, *pos),
167+
ActiveDialog::Taxes(p) => custom_actions_ui::taxes(rc, p),
168+
ActiveDialog::Theaters(p) => custom_actions_ui::theaters(rc, p),
169+
166170
ActiveDialog::CustomPhasePaymentRequest(c) => {
167171
custom_actions_ui::custom_phase_payment_dialog(rc, c)
168172
}
@@ -193,8 +197,8 @@ pub fn try_click(rc: &RenderContext) -> StateUpdate {
193197
let pos = Position::from_coordinate(pixel_to_coordinate(mouse_pos));
194198

195199
if rc.can_control() {
196-
if let ActiveDialog::CulturalInfluence = state.active_dialog {
197-
return influence_ui::hover(rc, mouse_pos);
200+
if let ActiveDialog::CulturalInfluence(b) = &state.active_dialog {
201+
return influence_ui::hover(rc, mouse_pos, b);
198202
}
199203
}
200204

0 commit comments

Comments
 (0)