coc_rs/models/
player.rs

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        // Home Base
263        "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        // Builder Base
299        "Master Engineering",
300        "Hidden Treasures",
301        "High Gear",
302        "Next Generation Model",
303        "Un-Build It",
304        "Champion Builder",
305        // Clan Capital
306        "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        // map it to the order of Self::HERO_ORDER
385        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}