poke_data/models/
pokemon.rs1use 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 past_types: HashMap<GenerationId, Vec<Type>>,
34 pub height: u16,
36 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}