1use crate::data::link_context::LinkContext;
2use crate::data::linkable::Linkable;
3use crate::models::contest_effect::{ContestEffect, ContestEffectId};
4use crate::models::contest_type::{ContestType, ContestTypeId};
5use crate::models::damage_class::{DamageClass, DamageClassId};
6use crate::models::flavor_texts::FlavorTexts;
7use crate::models::generation::{Generation, GenerationId};
8use crate::models::localized_names::LocalizedStrings;
9use crate::models::pokemon_move::changelog::{PokemonMoveChangelog, UnlinkedPokemonMoveChangelog};
10use crate::models::pokemon_move::meta::{PokemonMoveMeta, UnlinkedPokemonMoveMeta};
11use crate::models::pokemon_move_effect::{PokemonMoveEffect, PokemonMoveEffectId};
12use crate::models::pokemon_move_flag::{PokemonMoveFlag, PokemonMoveFlagId};
13use crate::models::pokemon_move_target::{PokemonMoveTarget, PokemonMoveTargetId};
14use crate::models::super_contest_effect::{SuperContestEffect, SuperContestEffectId};
15use crate::models::version_group::VersionGroupId;
16use crate::traits::has_identifier::HasIdentifier;
17use crate::traits::has_localized_names::HasLocalizedNames;
18use crate::types::pokemon_type::Type;
19use serde::{Deserialize, Serialize};
20use std::collections::HashMap;
21use std::sync::Arc;
22
23pub mod changelog;
24pub mod meta;
25
26pub type PokemonMoveId = u16;
27
28#[derive(Debug)]
29pub struct PokemonMove {
30 pub id: PokemonMoveId,
31 pub identifier: String,
32 pub names: LocalizedStrings,
33 pub flavor_texts: FlavorTexts,
34 pub generation: Arc<Generation>,
35 pub pokemon_type: Type,
36 pub power: Option<u8>,
37 pub pp: Option<u8>,
38 pub accuracy: Option<u8>,
39 pub priority: i8,
40 pub target: Arc<PokemonMoveTarget>,
41 pub damage_class: Arc<DamageClass>,
42 pub effect: Option<Arc<PokemonMoveEffect>>,
43 pub effect_chance: Option<u8>,
44 pub contest_type: Option<Arc<ContestType>>,
45 pub contest_effect: Option<Arc<ContestEffect>>,
46 pub super_contest_effect: Option<Arc<SuperContestEffect>>,
47 pub changelogs: HashMap<VersionGroupId, PokemonMoveChangelog>,
48 pub flags: Vec<Arc<PokemonMoveFlag>>,
49 pub meta_data: Option<PokemonMoveMeta>,
50}
51
52#[derive(Debug, Clone, Serialize, Deserialize)]
53pub struct UnlinkedPokemonMove {
54 pub id: PokemonMoveId,
55 pub identifier: String,
56 pub names: LocalizedStrings,
57 pub flavor_texts: FlavorTexts,
58 pub generation_id: GenerationId,
59 pub pokemon_type: Type,
60 pub power: Option<u8>,
61 pub pp: Option<u8>,
62 pub accuracy: Option<u8>,
63 pub priority: i8,
64 pub target_id: PokemonMoveTargetId,
65 pub damage_class_id: DamageClassId,
66 pub effect_id: Option<PokemonMoveEffectId>,
67 pub effect_chance: Option<u8>,
68 pub contest_type_id: Option<ContestTypeId>,
69 pub contest_effect_id: Option<ContestEffectId>,
70 pub super_contest_effect_id: Option<SuperContestEffectId>,
71 pub changelogs: HashMap<VersionGroupId, UnlinkedPokemonMoveChangelog>,
72 pub flag_ids: Vec<PokemonMoveFlagId>,
73 pub meta_data: Option<UnlinkedPokemonMoveMeta>,
74}
75
76impl Linkable for UnlinkedPokemonMove {
77 type Linked = Arc<PokemonMove>;
78
79 fn link(&self, context: &LinkContext) -> Self::Linked {
80 let generation = context
81 .generations
82 .get(&self.generation_id)
83 .unwrap_or_else(|| {
84 panic!(
85 "No generation '{}' found for move '{}'",
86 self.generation_id, self.id
87 )
88 })
89 .clone();
90
91 let target = context
92 .move_targets
93 .get(&self.target_id)
94 .unwrap_or_else(|| {
95 panic!(
96 "No move target '{}' found for move '{}'",
97 self.target_id, self.id
98 )
99 })
100 .clone();
101
102 let damage_class = context
103 .damage_classes
104 .get(&self.damage_class_id)
105 .unwrap_or_else(|| {
106 panic!(
107 "No move damage class '{}' found for move '{}'",
108 self.damage_class_id, self.id
109 )
110 })
111 .clone();
112
113 let effect = self.effect_id.map(|effect_id| {
114 context
115 .move_effects
116 .get(&effect_id)
117 .unwrap_or_else(|| {
118 panic!(
119 "No move effect '{}' found for move '{}'",
120 effect_id, self.id
121 )
122 })
123 .clone()
124 });
125
126 let contest_type = self.contest_type_id.map(|contest_type_id| {
127 context
128 .contest_types
129 .get(&contest_type_id)
130 .unwrap_or_else(|| {
131 panic!(
132 "No contest type '{}' found for move '{}'",
133 contest_type_id, self.id
134 )
135 })
136 .clone()
137 });
138
139 let contest_effect = self.contest_effect_id.map(|contest_effect_id| {
140 context
141 .contest_effects
142 .get(&contest_effect_id)
143 .unwrap_or_else(|| {
144 panic!(
145 "No contest effect '{}' found for move '{}'",
146 contest_effect_id, self.id
147 )
148 })
149 .clone()
150 });
151
152 let super_contest_effect = self.super_contest_effect_id.map(|super_contest_effect_id| {
153 context
154 .super_contest_effects
155 .get(&super_contest_effect_id)
156 .unwrap_or_else(|| {
157 panic!(
158 "No super contest effect '{}' found for move '{}'",
159 super_contest_effect_id, self.id
160 )
161 })
162 .clone()
163 });
164
165 let changelogs = self
166 .changelogs
167 .iter()
168 .map(|(version_group_id, changelog)| (*version_group_id, changelog.link(context)))
169 .collect();
170
171 let flags = self
172 .flag_ids
173 .iter()
174 .map(|flag_id| {
175 context
176 .move_flags
177 .get(flag_id)
178 .unwrap_or_else(|| {
179 panic!("No move flag '{}' found for move '{}'", flag_id, self.id)
180 })
181 .clone()
182 })
183 .collect();
184
185 let meta_data = self.meta_data.clone().map(|data| data.link(context));
186
187 let pokemon_move = PokemonMove {
188 id: self.id,
189 identifier: self.identifier.clone(),
190 names: self.names.clone(),
191 flavor_texts: self.flavor_texts.clone(),
192 generation,
193 pokemon_type: self.pokemon_type,
194 power: self.power,
195 pp: self.pp,
196 accuracy: self.accuracy,
197 priority: self.priority,
198 target,
199 damage_class,
200 effect,
201 effect_chance: self.effect_chance,
202 contest_type,
203 contest_effect,
204 super_contest_effect,
205 changelogs,
206 flags,
207 meta_data,
208 };
209
210 Arc::new(pokemon_move)
211 }
212}
213
214impl HasIdentifier for PokemonMove {
215 fn identifier(&self) -> &str {
216 &self.identifier
217 }
218}
219
220impl HasLocalizedNames for PokemonMove {
221 fn localized_names(&self) -> &LocalizedStrings {
222 &self.names
223 }
224}