poke_data/models/
location_area.rs

1use crate::data::link_context::LinkContext;
2use crate::data::linkable::Linkable;
3use crate::models::encounter::Encounter;
4use crate::models::encounter_method::EncounterMethodId;
5use crate::models::localized_names::LocalizedStrings;
6use crate::models::location::{Location, LocationId};
7use crate::models::version::VersionId;
8use crate::traits::has_localized_names::HasLocalizedNames;
9use serde::{Deserialize, Serialize};
10use std::collections::HashMap;
11use std::sync::Arc;
12
13pub type LocationAreaId = u16;
14
15#[derive(Debug)]
16pub struct LocationArea {
17    pub id: LocationAreaId,
18    pub identifier: Option<String>,
19    pub names: LocalizedStrings,
20    pub location: Arc<Location>,
21    pub game_index: u16,
22    pub encounter_rates: LocationAreaEncounterRates,
23    pub encounters: HashMap<VersionId, Vec<Arc<Encounter>>>,
24}
25
26#[derive(Debug, Clone, Serialize, Deserialize)]
27pub struct LocationAreaEncounterRates(Vec<LocationAreaEncounterRate>);
28
29impl LocationAreaEncounterRates {
30    pub fn new(rates: Vec<LocationAreaEncounterRate>) -> Self {
31        Self(rates)
32    }
33}
34
35#[derive(Debug, Clone, Serialize, Deserialize)]
36pub struct LocationAreaEncounterRate {
37    pub encounter_method_id: EncounterMethodId,
38    pub version_id: VersionId,
39    pub rate: u8,
40}
41
42#[derive(Debug, Clone, Serialize, Deserialize)]
43pub struct UnlinkedLocationArea {
44    pub id: LocationAreaId,
45    pub identifier: Option<String>,
46    pub names: LocalizedStrings,
47    pub location_id: LocationId,
48    pub game_index: u16,
49    pub encounter_rates: LocationAreaEncounterRates,
50}
51
52impl Linkable for UnlinkedLocationArea {
53    type Linked = Arc<LocationArea>;
54
55    fn link(&self, context: &LinkContext) -> Self::Linked {
56        let location = context
57            .locations
58            .get(&self.location_id)
59            .unwrap_or_else(|| {
60                panic!(
61                    "No location '{}' found for location area '{}'",
62                    self.location_id, self.id
63                )
64            })
65            .clone();
66
67        let relevant_encounters: Vec<Arc<Encounter>> = context
68            .encounters
69            .iter()
70            .filter_map(|(_, encounter)| {
71                if encounter.location_area_id == self.id {
72                    Some(encounter.clone())
73                } else {
74                    None
75                }
76            })
77            .collect();
78
79        let encounters = relevant_encounters.iter().fold(
80            HashMap::new(),
81            |mut acc: HashMap<VersionId, Vec<Arc<Encounter>>>, encounter| {
82                acc.entry(encounter.version.id)
83                    .or_default()
84                    .push(encounter.clone());
85                acc
86            },
87        );
88
89        let location_area = LocationArea {
90            id: self.id,
91            identifier: self.identifier.clone(),
92            names: self.names.clone(),
93            location,
94            game_index: self.game_index,
95            encounter_rates: self.encounter_rates.clone(),
96            encounters,
97        };
98
99        Arc::new(location_area)
100    }
101}
102
103impl HasLocalizedNames for LocationArea {
104    fn localized_names(&self) -> &LocalizedStrings {
105        &self.names
106    }
107}