poke_data/models/
pokemon.rs

1use crate::data::link_context::LinkContext;
2use crate::data::linkable::Linkable;
3use crate::models::base_stats::BaseStats;
4use crate::models::encounter::Encounter;
5use crate::models::generation::GenerationId;
6use crate::models::pokemon::ability::{
7    PokemonAbilitiesPast, PokemonAbility, UnlinkedPokemonAbilitiesPast, UnlinkedPokemonAbility,
8};
9use crate::models::pokemon::moveset::{Moveset, UnlinkedMoveset};
10use crate::models::pokemon::wild_item::{PokemonWildItems, UnlinkedPokemonWildItems};
11use crate::models::pokemon_form::{PokemonForm, PokemonFormId};
12use crate::models::species::{Species, SpeciesId};
13use crate::models::version::VersionId;
14use crate::traits::has_identifier::HasIdentifier;
15use crate::types::pokemon_type::Type;
16use serde::{Deserialize, Serialize};
17use std::collections::HashMap;
18use std::sync::Arc;
19
20pub mod ability;
21pub mod moveset;
22pub mod wild_item;
23
24pub type PokemonId = u16;
25
26#[derive(Debug)]
27pub struct Pokemon {
28    pub id: PokemonId,
29    pub identifier: String,
30    pub species: Arc<Species>,
31    types: Vec<Type>,
32    /// The last generation this Pokémon had the specified type combination
33    past_types: HashMap<GenerationId, Vec<Type>>,
34    /// Height of this Pokémon in decimeters
35    pub height: u16,
36    /// Weight of this Pokémon in hectograms
37    pub weight: u16,
38    pub base_stats: BaseStats,
39    pub base_experience: u16,
40    pub order: Option<u16>,
41    pub is_default: bool,
42    abilities: Vec<PokemonAbility>,
43    past_abilities: PokemonAbilitiesPast,
44    pub moveset: Moveset,
45    pub encounters: HashMap<VersionId, Vec<Arc<Encounter>>>,
46    pub default_form: Option<Arc<PokemonForm>>,
47    pub forms: Vec<Arc<PokemonForm>>,
48    pub wild_items: PokemonWildItems,
49}
50
51impl Pokemon {
52    pub fn get_types(&self, generation_id: GenerationId) -> &Vec<Type> {
53        if self.past_types.is_empty() {
54            return &self.types;
55        }
56
57        match self
58            .past_types
59            .keys()
60            .filter(|key| generation_id <= **key)
61            .max()
62        {
63            Some(latest_applicable_gen) => &self.past_types[latest_applicable_gen],
64            None => &self.types,
65        }
66    }
67
68    pub fn get_abilities(&self, generation_id: GenerationId) -> Vec<PokemonAbility> {
69        if self.past_abilities.is_empty() {
70            return self.abilities.clone();
71        }
72
73        match self
74            .past_abilities
75            .get_map()
76            .keys()
77            .filter(|key| generation_id <= **key)
78            .max()
79        {
80            Some(latest_applicable_gen) => {
81                let past_abilities = self
82                    .past_abilities
83                    .get_abilities(latest_applicable_gen)
84                    .unwrap();
85
86                let mut abilities: Vec<PokemonAbility> = self
87                    .abilities
88                    .iter()
89                    .filter_map(|ability| {
90                        if let Some(past_ability) = past_abilities
91                            .iter()
92                            .find(|past_ability| past_ability.slot == ability.slot)
93                        {
94                            past_ability.to_ability()
95                        } else {
96                            Some(ability.clone())
97                        }
98                    })
99                    .collect();
100
101                past_abilities.iter().for_each(|past_ability| {
102                    if !abilities
103                        .iter()
104                        .any(|ability| ability.slot == past_ability.slot)
105                    {
106                        if let Some(past_pokemon_ability) = past_ability.to_ability() {
107                            abilities.push(past_pokemon_ability);
108                        }
109                    }
110                });
111
112                abilities
113            }
114            None => self.abilities.clone(),
115        }
116    }
117}
118
119#[derive(Debug, Clone, Serialize, Deserialize)]
120pub struct UnlinkedPokemon {
121    pub id: PokemonId,
122    pub identifier: String,
123    pub species_id: SpeciesId,
124    pub types: Vec<Type>,
125    pub past_types: HashMap<GenerationId, Vec<Type>>,
126    pub height: u16,
127    pub weight: u16,
128    pub base_stats: BaseStats,
129    pub base_experience: u16,
130    pub order: Option<u16>,
131    pub is_default: bool,
132    pub abilities: Vec<UnlinkedPokemonAbility>,
133    pub past_abilities: UnlinkedPokemonAbilitiesPast,
134    pub moveset: UnlinkedMoveset,
135    pub form_ids: Vec<PokemonFormId>,
136    pub wild_items: UnlinkedPokemonWildItems,
137}
138
139impl Linkable for UnlinkedPokemon {
140    type Linked = Arc<Pokemon>;
141
142    fn link(&self, context: &LinkContext) -> Self::Linked {
143        let species = context
144            .species
145            .get(&self.species_id)
146            .unwrap_or_else(|| {
147                panic!(
148                    "No species '{}' found for pokemon '{}'",
149                    self.species_id, self.id
150                )
151            })
152            .clone();
153
154        let abilities = self.abilities.link(context);
155        let past_abilities = self.past_abilities.link(context);
156        let moveset = self.moveset.link(context);
157
158        let relevant_encounters: Vec<Arc<Encounter>> = context
159            .encounters
160            .iter()
161            .filter_map(|(_, encounter)| {
162                if encounter.pokemon_id == self.id {
163                    Some(encounter.clone())
164                } else {
165                    None
166                }
167            })
168            .collect();
169
170        let encounters = relevant_encounters.iter().fold(
171            HashMap::new(),
172            |mut acc: HashMap<VersionId, Vec<Arc<Encounter>>>, encounter| {
173                acc.entry(encounter.version.id)
174                    .or_default()
175                    .push(encounter.clone());
176                acc
177            },
178        );
179
180        let forms: Vec<Arc<PokemonForm>> = self
181            .form_ids
182            .iter()
183            .map(|form_id| {
184                context
185                    .pokemon_forms
186                    .get(form_id)
187                    .unwrap_or_else(|| {
188                        panic!(
189                            "No pokemon form '{}' found for pokemon '{}'",
190                            form_id, self.id
191                        )
192                    })
193                    .clone()
194            })
195            .collect();
196
197        let default_form = forms.iter().find(|form| form.is_default).cloned();
198
199        let wild_items = self.wild_items.link(context);
200
201        let pokemon = Pokemon {
202            id: self.id,
203            identifier: self.identifier.clone(),
204            species,
205            types: self.types.clone(),
206            past_types: self.past_types.clone(),
207            height: self.height,
208            weight: self.weight,
209            base_stats: self.base_stats.clone(),
210            base_experience: self.base_experience,
211            order: self.order,
212            is_default: self.is_default,
213            abilities,
214            past_abilities,
215            moveset,
216            encounters,
217            default_form,
218            forms,
219            wild_items,
220        };
221
222        Arc::new(pokemon)
223    }
224}
225
226impl HasIdentifier for Pokemon {
227    fn identifier(&self) -> &str {
228        &self.identifier
229    }
230}