1use serde::{Deserialize, Serialize};
2
3use super::{badge_urls, clan, labels, leagues, season};
4
5#[derive(Debug, Serialize, Deserialize, Clone)]
6#[serde(rename_all = "camelCase")]
7pub struct Player {
8 pub tag: String,
9 pub name: String,
10 pub town_hall_level: i8,
11 pub town_hall_weapon_level: Option<i8>,
12 pub exp_level: i32,
13 pub trophies: i32,
14 pub best_trophies: i32,
15 pub war_stars: i32,
16 pub attack_wins: i32,
17 pub defense_wins: i32,
18 pub builder_hall_level: Option<i8>,
19 pub versus_trophies: i32,
20 pub best_versus_trophies: i32,
21 pub versus_battle_wins: i32,
22 pub role: Option<clan::Role>,
23 pub war_preference: Option<WarPreference>,
24 pub donations: i32,
25 pub donations_received: i32,
26 pub clan_capital_contributions: i32,
27 pub clan: Option<PlayerClan>,
28 pub league: Option<leagues::League>,
29 pub legend_statistics: Option<LegendStatistics>,
30 pub achievements: Vec<Achievement>,
31 pub versus_battle_win_count: Option<i32>,
32 pub labels: Vec<labels::PlayerLabel>,
33 pub troops: Vec<Troop>,
34 pub heroes: Vec<Hero>,
35 pub spells: Vec<Spell>,
36}
37
38#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
39#[serde(rename_all = "camelCase")]
40pub enum WarPreference {
41 #[serde(rename = "in")]
42 In,
43 #[serde(rename = "out")]
44 Out,
45}
46
47impl WarPreference {
48 #[must_use]
49 pub fn is_opted_in(&self) -> bool {
50 self == &Self::In
51 }
52 #[must_use]
53 pub fn is_opted_out(&self) -> bool {
54 self == &Self::Out
55 }
56}
57
58impl ToString for WarPreference {
59 fn to_string(&self) -> String {
60 match self {
61 Self::In => "in".to_string(),
62 Self::Out => "out".to_string(),
63 }
64 }
65}
66
67#[derive(Debug, Serialize, Deserialize, Clone)]
68#[serde(rename_all = "camelCase")]
69pub struct Hero {
70 pub name: String,
71 pub level: i32,
72 pub max_level: i32,
73 pub village: Village,
74}
75
76#[derive(Debug, Serialize, Deserialize, Clone)]
77#[serde(rename_all = "camelCase")]
78pub struct Achievement {
79 pub name: String,
80 pub stars: i32,
81 pub value: i32,
82 pub target: i32,
83 pub info: String,
84 pub completion_info: Option<String>,
85 pub village: Village,
86}
87
88#[derive(Debug, Serialize, Deserialize, Clone)]
89#[serde(rename_all = "camelCase")]
90pub struct PlayerClan {
91 pub tag: String,
92 pub name: String,
93 pub clan_level: i8,
94 pub badge_urls: badge_urls::BadgeUrls,
95}
96
97#[derive(Debug, Serialize, Deserialize, Clone)]
98#[serde(rename_all = "camelCase")]
99pub struct Spell {
100 pub name: String,
101 pub level: i32,
102 pub max_level: i32,
103 pub village: Village,
104}
105
106#[derive(Debug, Serialize, Deserialize, Clone)]
107#[serde(rename_all = "camelCase")]
108pub struct Troop {
109 pub name: String,
110 pub level: i32,
111 pub max_level: i32,
112 pub village: Village,
113}
114
115#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
116#[serde(rename_all = "camelCase")]
117pub enum Village {
118 #[serde(rename = "builderBase")]
119 BuilderBase,
120
121 #[serde(rename = "home")]
122 HomeVillage,
123
124 #[serde(rename = "clanCapital")]
125 ClanCapital,
126}
127
128impl Village {
129 #[must_use]
130 pub fn is_home(&self) -> bool {
131 self == &Self::HomeVillage
132 }
133 #[must_use]
134 pub fn is_builder_base(&self) -> bool {
135 self == &Self::BuilderBase
136 }
137}
138
139impl ToString for Village {
140 fn to_string(&self) -> String {
141 match self {
142 Self::HomeVillage => "Home Village".to_string(),
143 Self::BuilderBase => "Builder Base".to_string(),
144 Self::ClanCapital => "Clan Capital".to_string(),
145 }
146 }
147}
148
149#[derive(Debug, Serialize, Deserialize)]
150#[serde(rename_all = "camelCase")]
151pub struct PlayerToken {
152 pub tag: String,
153 pub token: String,
154 pub status: String,
155}
156
157#[derive(Debug, Serialize, Deserialize, Clone)]
158#[serde(rename_all = "camelCase")]
159pub struct LegendStatistics {
160 pub legend_trophies: i32,
161 pub previous_season: Option<season::PreviousSeasonData>,
162 pub best_season: Option<season::BestSeasonData>,
163 pub previous_versus_season: Option<season::PreviousVersusSeasonData>,
164 pub best_versus_season: Option<season::BestVersusSeasonData>,
165 pub current_season: season::CurrentSeasonData,
166}
167
168#[cfg(feature = "extra")]
169impl Player {
170 const HOME_TROOP_ORDER: [&'static str; 24] = [
171 "Barbarian",
172 "Archer",
173 "Giant",
174 "Goblin",
175 "Wall Breaker",
176 "Balloon",
177 "Wizard",
178 "Healer",
179 "Dragon",
180 "P.E.K.K.A",
181 "Baby Dragon",
182 "Miner",
183 "Electro Dragon",
184 "Yeti",
185 "Dragon Rider",
186 "Minion",
187 "Hog Rider",
188 "Valkyrie",
189 "Golem",
190 "Witch",
191 "Lava Hound",
192 "Bowler",
193 "Ice Golem",
194 "Headhunter",
195 ];
196
197 const SIEGE_MACHINE_ORDER: [&'static str; 6] = [
198 "Wall Wrecker",
199 "Battle Blimp",
200 "Stone Slammer",
201 "Siege Barracks",
202 "Log Launcher",
203 "Flame Flinger",
204 ];
205
206 const SUPER_TROOP_ORDER: [&'static str; 14] = [
207 "Super Barbarian",
208 "Super Archer",
209 "Super Giant",
210 "Sneaky Goblin",
211 "Super Wall Breaker",
212 "Rocket Balloon",
213 "Super Wizard",
214 "Super Dragon",
215 "Inferno Dragon",
216 "Super Minion",
217 "Super Valkyrie",
218 "Super Witch",
219 "Ice Hound",
220 "Super Bowler",
221 ];
222
223 const BUILDER_TROOP_ORDER: [&'static str; 11] = [
224 "Raged Barbarian",
225 "Sneaky Archer",
226 "Boxer Giant",
227 "Beta Minion",
228 "Bomber",
229 "Baby Dragon",
230 "Cannon Cart",
231 "Night Witch",
232 "Drop Ship",
233 "Super P.E.K.K.A",
234 "Hog Glider",
235 ];
236
237 const SPELL_ORDER: [&'static str; 12] = [
238 "Lightning Spell",
239 "Healing Spell",
240 "Rage Spell",
241 "Jump Spell",
242 "Freeze Spell",
243 "Clone Spell",
244 "Invisibility Spell",
245 "Poison Spell",
246 "Earthquake Spell",
247 "Haste Spell",
248 "Skeleton Spell",
249 "Bat Spell",
250 ];
251
252 const HOME_HERO_ORDER: [&'static str; 4] =
253 ["Barbarian King", "Archer Queen", "Grand Warden", "Royal Champion"];
254
255 const HERO_ORDER: [&'static str; 5] =
256 ["Barbarian King", "Archer Queen", "Grand Warden", "Royal Champion", "Battle Machine"];
257
258 const HERO_PETS_ORDER: [&'static str; 4] =
259 ["L.A.S.S.I", "Electro Owl", "Mighty Yak", "Unicorn"];
260 #[allow(dead_code)]
261 const ACHIEVEMENT_ORDER: [&'static str; 43] = [
262 "Keep Your Account Safe!",
264 "Bigger & Better",
265 "Discover New Troops",
266 "Bigger Coffers",
267 "Gold Grab",
268 "Elixir Escapade",
269 "Heroic Heist",
270 "Well Seasoned",
271 "Nice and Tidy",
272 "Empire Builder",
273 "Clan War Wealth",
274 "Friend in Need",
275 "Sharing is caring",
276 "Siege Sharer",
277 "War Hero",
278 "War League Legend",
279 "Games Champion",
280 "Unbreakable",
281 "Sweet Victory!",
282 "Conqueror",
283 "League All-Star",
284 "Humiliator",
285 "Not So Easy This Time",
286 "Union Buster",
287 "Bust This!",
288 "Wall Buster",
289 "Mortar Mauler",
290 "X-Bow Exterminator",
291 "Firefighter",
292 "Anti-Artillery",
293 "Shattered and Scattered",
294 "Get those Goblins!",
295 "Get those other Goblins!",
296 "Dragon Slayer",
297 "Superb Work",
298 "Master Engineering",
300 "Hidden Treasures",
301 "High Gear",
302 "Next Generation Model",
303 "Un-Build It",
304 "Champion Builder",
305 "Aggressive Capitalism",
307 "Most Valuable Clanmate",
308 ];
309
310 pub fn game_link(&self) -> String {
311 format!(
312 "https://link.clashofclans.com/en?action=OpenPlayerProfile&tag={}",
313 self.tag.replace('#', "")
314 )
315 }
316
317 pub fn clash_of_stats_link(&self) -> String {
318 format!("https://www.clashofstats.com/players/{}/summary", self.tag.replace('#', ""))
319 }
320
321 pub fn chocolate_clash_link(&self) -> String {
322 format!("https://cc.chocolateclash.com/cc_n/member.php?tag={}", self.tag.replace('#', ""))
323 }
324
325 pub fn achievements(&self) -> Vec<Achievement> {
326 Self::ACHIEVEMENT_ORDER
327 .iter()
328 .filter_map(|achievement_name| {
329 self.achievements.iter().find(|achievement| &achievement.name == achievement_name)
330 })
331 .cloned()
332 .collect()
333 }
334
335 pub fn get_achievement(&self, name: &str) -> Option<&Achievement> {
336 self.achievements.iter().find(|achievement| achievement.name == name)
337 }
338
339 pub fn home_troops(&self) -> Vec<Troop> {
340 Self::HOME_TROOP_ORDER
341 .iter()
342 .filter_map(|name| self.troops.iter().find(|troop| &troop.name == name))
343 .cloned()
344 .collect()
345 }
346
347 pub fn super_troops(&self) -> Vec<Troop> {
348 Self::SUPER_TROOP_ORDER
349 .iter()
350 .filter_map(|name| self.troops.iter().find(|troop| &troop.name == name))
351 .cloned()
352 .collect()
353 }
354
355 pub fn builder_troops(&self) -> Vec<Troop> {
356 Self::BUILDER_TROOP_ORDER
357 .iter()
358 .filter_map(|name| self.troops.iter().find(|troop| &troop.name == name))
359 .cloned()
360 .collect()
361 }
362
363 pub fn get_troop(&self, name: &str) -> Option<&Troop> {
364 self.troops.iter().find(|troop| troop.name == name)
365 }
366
367 pub fn siege_machines(&self) -> Vec<Troop> {
368 Self::SIEGE_MACHINE_ORDER
369 .iter()
370 .filter_map(|name| self.troops.iter().find(|troop| &troop.name == name))
371 .cloned()
372 .collect()
373 }
374
375 pub fn home_heroes(&self) -> Vec<Hero> {
376 Self::HOME_HERO_ORDER
377 .iter()
378 .filter_map(|name| self.heroes.iter().find(|hero| &hero.name == name))
379 .cloned()
380 .collect()
381 }
382
383 pub fn heroes(&self) -> Vec<Hero> {
384 Self::HERO_ORDER
386 .iter()
387 .filter_map(|name| self.heroes.iter().find(|hero| &hero.name == name).cloned())
388 .collect()
389 }
390
391 pub fn hero_pets(&self) -> Vec<Troop> {
392 Self::HERO_PETS_ORDER
393 .iter()
394 .filter_map(|name| self.troops.iter().find(|troop| &troop.name == name))
395 .cloned()
396 .collect()
397 }
398
399 pub fn get_hero(&self, name: &str) -> Option<&Hero> {
400 self.heroes.iter().find(|hero| hero.name == name)
401 }
402
403 pub fn get_pet(&self, name: &str) -> Option<&Troop> {
404 self.troops.iter().find(|troop| troop.name == name)
405 }
406
407 pub fn spells(&self) -> Vec<Spell> {
408 Self::SPELL_ORDER
409 .iter()
410 .filter_map(|name| self.spells.iter().find(|spell| &spell.name == name).cloned())
411 .collect()
412 }
413
414 pub fn get_spell(&self, name: &str) -> Option<&Spell> {
415 self.spells.iter().find(|spell| spell.name == name)
416 }
417}