Skip to content

Commit e0ee8a0

Browse files
authored
add skin (#67)
* build in release mode * fix raze city * cleanup local client * fix raze city * add skin * add skin * add skin * add skin for advances * add skin for advances * add skin for advances * add skin for advances * add skin for advances
1 parent 4a656f9 commit e0ee8a0

29 files changed

+689
-421
lines changed

client/assets/HTOWERT.TTF

90.6 KB
Binary file not shown.

client/assets/button_background.png

5.49 KB
Loading
10.5 KB
Loading
5.9 KB
Loading

client/assets/window_background.png

13 KB
Loading

client/src/advance_ui.rs

+121-78
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1+
use crate::client_state::{ActiveDialog, ShownPlayer, StateUpdate};
2+
use crate::dialog_ui::dialog;
3+
use crate::payment_ui::{payment_dialog, HasPayment, Payment, ResourcePayment};
4+
use crate::resource_ui::{new_resource_map, ResourceType};
5+
use crate::select_ui::HasCountSelectableObject;
16
use itertools::Itertools;
27
use macroquad::hash;
3-
use macroquad::math::{bool, vec2};
4-
use std::cmp::min;
5-
use std::collections::HashMap;
6-
8+
use macroquad::math::{bool, vec2, Vec2};
9+
use macroquad::ui::widgets::Checkbox;
710
use server::action::Action;
811
use server::advance::{Advance, Bonus};
912
use server::content::advances;
@@ -13,12 +16,8 @@ use server::player::Player;
1316
use server::playing_actions::PlayingAction;
1417
use server::resource_pile::AdvancePaymentOptions;
1518
use server::status_phase::{StatusPhaseAction, StatusPhaseState};
16-
17-
use crate::client_state::{ActiveDialog, ShownPlayer, StateUpdate};
18-
use crate::dialog_ui::dialog;
19-
use crate::payment_ui::{payment_dialog, HasPayment, Payment, ResourcePayment};
20-
use crate::resource_ui::{new_resource_map, ResourceType};
21-
use crate::select_ui::HasCountSelectableObject;
19+
use std::cmp::min;
20+
use std::collections::HashMap;
2221

2322
#[derive(Clone)]
2423
pub struct AdvancePayment {
@@ -80,83 +79,120 @@ impl HasPayment for AdvancePayment {
8079
}
8180

8281
pub fn show_advance_menu(game: &Game, player: &ShownPlayer) -> StateUpdate {
83-
show_generic_advance_menu("Advances", game, player, |name| {
82+
show_generic_advance_menu("Advances", game, player, |a| {
8483
StateUpdate::SetDialog(ActiveDialog::AdvancePayment(AdvancePayment::new(
8584
game,
8685
player.index,
87-
name,
86+
a.name.as_str(),
8887
)))
8988
})
9089
}
9190

9291
pub fn show_free_advance_menu(game: &Game, player: &ShownPlayer) -> StateUpdate {
93-
show_generic_advance_menu("Select a free advance", game, player, |name| {
94-
StateUpdate::status_phase(StatusPhaseAction::FreeAdvance(name.to_string()))
92+
show_generic_advance_menu("Select a free advance", game, player, |a| {
93+
if can_advance(game, player, a) {
94+
return StateUpdate::execute_with_confirm(
95+
description(game.get_player(player.index), a),
96+
Action::StatusPhase(StatusPhaseAction::FreeAdvance(a.name.clone())),
97+
);
98+
}
99+
advance_info(game, player, a)
95100
})
96101
}
97102

103+
fn advance_info(game: &Game, player: &ShownPlayer, a: &Advance) -> StateUpdate {
104+
StateUpdate::execute_with_cancel(description(game.get_player(player.index), a))
105+
}
106+
98107
pub fn show_generic_advance_menu(
99108
title: &str,
100109
game: &Game,
101110
player: &ShownPlayer,
102-
new_update: impl Fn(&str) -> StateUpdate,
111+
new_update: impl Fn(&Advance) -> StateUpdate,
103112
) -> StateUpdate {
104113
dialog(player, title, |ui| {
105114
let p = player.get(game);
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-
}
140-
} else {
141-
ui.label(None, &desc);
142-
};
115+
116+
for advances in groups() {
117+
let pos = group_pos(&advances[0]);
118+
for (i, a) in advances.into_iter().enumerate() {
119+
let pos = pos * vec2(140., 210.) + vec2(0., i as f32 * 35.);
120+
let name = &a.name;
121+
let can_advance = can_advance(game, player, &a);
122+
123+
if can_advance || p.has_advance(name) {
124+
let mut data = p.has_advance(name);
125+
Checkbox::new(hash!(name))
126+
// .label(name)
127+
.pos(pos + vec2(60., 50.))
128+
.size(vec2(0., 0.))
129+
.ui(ui, &mut data);
130+
if data != p.has_advance(name) {
131+
return new_update(&a);
132+
}
143133
}
144-
});
134+
// Button::new(name.clone()).position(pos + vec2(0., 0.)).ui(ui);
135+
ui.label(pos + vec2(0., 0.), name);
136+
}
145137
}
146-
update
138+
StateUpdate::None
147139
})
148140
}
149141

150-
fn description(p: &Player, a: &Advance) -> String {
142+
fn can_advance(game: &Game, player: &ShownPlayer, a: &Advance) -> bool {
143+
let name = &a.name;
144+
let p = player.get(game);
145+
if player.can_play_action {
146+
p.can_advance(name)
147+
} else if player.can_control
148+
&& matches!(
149+
game.state,
150+
GameState::StatusPhase(StatusPhaseState::FreeAdvance)
151+
)
152+
{
153+
p.can_advance_free(name)
154+
} else {
155+
false
156+
}
157+
}
158+
159+
fn groups() -> Vec<Vec<Advance>> {
160+
let mut current_group = None;
161+
advances::get_all()
162+
.into_iter()
163+
.chunk_by(|a| {
164+
if a.required.is_none() {
165+
current_group = Some(a.name.clone());
166+
a.name.clone()
167+
} else {
168+
current_group.as_ref().unwrap().clone()
169+
}
170+
})
171+
.into_iter()
172+
.map(|(_k, a)| a.collect::<Vec<_>>())
173+
.collect::<Vec<_>>()
174+
}
175+
176+
fn group_pos(advance: &Advance) -> Vec2 {
177+
match advance.name.as_str() {
178+
"Farming" => vec2(0., 0.),
179+
"Mining" => vec2(1., 0.),
180+
"Fishing" => vec2(2., 0.),
181+
"Philosophy" => vec2(3., 0.),
182+
"Tactics" => vec2(4., 0.),
183+
"Math" => vec2(2., 1.),
184+
"Voting" => vec2(3., 1.),
185+
"Dogma" => vec2(5., 1.),
186+
_ => panic!("Unknown advance: {}", advance.name),
187+
}
188+
}
189+
190+
fn description(p: &Player, a: &Advance) -> Vec<String> {
151191
let name = &a.name;
152192
let desc = &a.description;
153193

154-
let mut parts = vec![];
155-
parts.push(if p.has_advance(name) {
156-
format!("+ {name}")
157-
} else {
158-
format!(" {name}")
159-
});
194+
let mut parts: Vec<String> = vec![];
195+
parts.push(name.clone());
160196
parts.push(desc.clone());
161197
parts.push(format!("Cost: {}", p.advance_cost(name)));
162198
if let Some(r) = &a.required {
@@ -181,25 +217,32 @@ fn description(p: &Player, a: &Advance) -> String {
181217
parts.push(format!("Unlocks: {u}"));
182218
}
183219

184-
parts.join(", ")
220+
parts
185221
}
186222

187-
pub fn pay_advance_dialog(ap: &AdvancePayment, player: &ShownPlayer) -> StateUpdate {
188-
payment_dialog(
189-
player,
190-
&format!("Pay for advance {}", ap.name),
191-
ap,
192-
AdvancePayment::valid,
193-
|ap| {
194-
StateUpdate::Execute(Action::Playing(PlayingAction::Advance {
195-
advance: ap.name.to_string(),
196-
payment: ap.payment.to_resource_pile(),
197-
}))
198-
},
199-
|ap, r| ap.payment.get(r).selectable.max > 0,
200-
|ap, r| add(ap, r, 1),
201-
|ap, r| add(ap, r, -1),
202-
)
223+
pub fn pay_advance_dialog(ap: &AdvancePayment, player: &ShownPlayer, game: &Game) -> StateUpdate {
224+
let a = advances::get_advance_by_name(ap.name.as_str()).unwrap();
225+
226+
if can_advance(game, player, &a) {
227+
payment_dialog(
228+
player,
229+
&format!("Pay for advance {}", ap.name),
230+
description(game.get_player(player.index), &a),
231+
ap,
232+
AdvancePayment::valid,
233+
|ap| {
234+
StateUpdate::Execute(Action::Playing(PlayingAction::Advance {
235+
advance: ap.name.to_string(),
236+
payment: ap.payment.to_resource_pile(),
237+
}))
238+
},
239+
|ap, r| ap.payment.get(r).selectable.max > 0,
240+
|ap, r| add(ap, r, 1),
241+
|ap, r| add(ap, r, -1),
242+
)
243+
} else {
244+
advance_info(game, player, &a)
245+
}
203246
}
204247

205248
fn add(ap: &AdvancePayment, r: ResourceType, i: i32) -> StateUpdate {

client/src/assets.rs

+108-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
use crate::client::Features;
2-
use macroquad::prelude::{load_texture, Texture2D};
2+
use macroquad::prelude::{load_texture, load_ttf_font, Color, Image, RectOffset, Texture2D};
3+
use macroquad::ui::{root_ui, Skin};
34
use server::map::Terrain;
45
use server::unit::UnitType;
56
use std::collections::HashMap;
67

78
pub struct Assets {
89
pub terrain: HashMap<Terrain, Texture2D>,
910
pub units: HashMap<UnitType, Texture2D>,
11+
pub skin: Skin,
1012
// pub cities: HashMap<CityType, Texture2D>,
1113
// pub resources: HashMap<Resource, Texture2D>,
1214
}
@@ -16,6 +18,7 @@ impl Assets {
1618
Self {
1719
terrain: Self::terrain(features).await,
1820
units: HashMap::new(),
21+
skin: Self::skin(features).await,
1922
// cities: HashMap::new(),
2023
// resources: HashMap::new(),
2124
}
@@ -31,9 +34,111 @@ impl Assets {
3134
(Terrain::Forest, "forest.png"),
3235
(Terrain::Water, "water.png"),
3336
] {
34-
let url = &features.assets_url;
35-
map.insert(t, load_texture(&format!("{url}{f}")).await.unwrap());
37+
map.insert(t, load_texture(&features.get_asset(f)).await.unwrap());
3638
}
3739
map
3840
}
41+
42+
async fn skin(features: &Features) -> Skin {
43+
let font = load_ttf_font(&features.get_asset("HTOWERT.TTF"))
44+
.await
45+
.unwrap();
46+
let image =
47+
Image::from_file_with_format(include_bytes!("../assets/button_background.png"), None)
48+
.unwrap();
49+
let label_style = root_ui()
50+
.style_builder()
51+
.background(image.clone())
52+
.background_margin(RectOffset::new(37.0, 37.0, 5.0, 5.0))
53+
.margin(RectOffset::new(10.0, 10.0, 0.0, 0.0))
54+
.with_font(&font)
55+
.unwrap()
56+
.text_color(Color::from_rgba(180, 180, 120, 255))
57+
.font_size(20)
58+
.build();
59+
60+
let window_style = root_ui()
61+
.style_builder()
62+
.background(
63+
Image::from_file_with_format(
64+
include_bytes!("../assets/window_background.png"),
65+
None,
66+
)
67+
.unwrap(),
68+
)
69+
.background_margin(RectOffset::new(20.0, 20.0, 10.0, 10.0))
70+
.margin(RectOffset::new(-20.0, -30.0, 0.0, 0.0))
71+
.build();
72+
73+
let button_style = root_ui()
74+
.style_builder()
75+
.background(image)
76+
.background_margin(RectOffset::new(37.0, 37.0, 5.0, 5.0))
77+
.margin(RectOffset::new(10.0, 10.0, 0.0, 0.0))
78+
.background_hovered(
79+
Image::from_file_with_format(
80+
include_bytes!("../assets/button_hovered_background.png"),
81+
None,
82+
)
83+
.unwrap(),
84+
)
85+
.background_clicked(
86+
Image::from_file_with_format(
87+
include_bytes!("../assets/button_clicked_background.png"),
88+
None,
89+
)
90+
.unwrap(),
91+
)
92+
.with_font(&font)
93+
.unwrap()
94+
.text_color(Color::from_rgba(180, 180, 100, 255))
95+
.font_size(20)
96+
.build();
97+
98+
let editbox_style = root_ui()
99+
.style_builder()
100+
.background_margin(RectOffset::new(0., 0., 0., 0.))
101+
.with_font(&font)
102+
.unwrap()
103+
.text_color(Color::from_rgba(120, 120, 120, 255))
104+
.color_selected(Color::from_rgba(190, 190, 190, 255))
105+
.font_size(50)
106+
.build();
107+
108+
// let checkbox_style = root_ui()
109+
// .style_builder()
110+
// .background(
111+
// Image::from_file_with_format(
112+
// include_bytes!("../examples/ui_assets/checkbox_background.png"),
113+
// None,
114+
// )
115+
// .unwrap(),
116+
// )
117+
// .background_hovered(
118+
// Image::from_file_with_format(
119+
// include_bytes!("../examples/ui_assets/checkbox_hovered_background.png"),
120+
// None,
121+
// )
122+
// .unwrap(),
123+
// )
124+
// .background_clicked(
125+
// Image::from_file_with_format(
126+
// include_bytes!("../examples/ui_assets/checkbox_clicked_background.png"),
127+
// None,
128+
// )
129+
// .unwrap(),
130+
// )
131+
// .build();
132+
133+
Skin {
134+
editbox_style,
135+
window_style,
136+
button_style,
137+
window_titlebar_style: label_style.clone(),
138+
label_style,
139+
// checkbox_style,
140+
title_height: 30.,
141+
..root_ui().default_skin()
142+
}
143+
}
39144
}

0 commit comments

Comments
 (0)