1use crate::data::link_context::LinkContext;
2use crate::data::linkable::Linkable;
3use crate::models::flavor_texts::FlavorTexts;
4use crate::models::generation::GenerationId;
5use crate::models::item_category::{ItemCategory, ItemCategoryId};
6use crate::models::item_flag::{ItemFlag, ItemFlagId};
7use crate::models::item_fling_effect::{ItemFlingEffect, ItemFlingEffectId};
8use crate::models::localized_effects::LocalizedEffects;
9use crate::models::localized_names::LocalizedStrings;
10use crate::traits::has_identifier::HasIdentifier;
11use crate::traits::has_localized_names::HasLocalizedNames;
12use serde::{Deserialize, Serialize};
13use std::collections::HashMap;
14use std::sync::Arc;
15
16pub type ItemId = u16;
17
18#[derive(Debug)]
19pub struct Item {
20 pub id: ItemId,
21 pub identifier: String,
22 pub names: LocalizedStrings,
23 pub flavor_texts: FlavorTexts,
24 pub effects: LocalizedEffects,
25 pub category: Arc<ItemCategory>,
26 pub cost: u32,
27 pub fling_power: Option<u8>,
28 pub fling_effect: Option<Arc<ItemFlingEffect>>,
29 pub flags: Vec<Arc<ItemFlag>>,
30 pub game_indices: ItemGameIndices,
31}
32
33#[derive(Debug, Clone, Serialize, Deserialize)]
34pub struct ItemGameIndices(HashMap<GenerationId, u16>);
35
36impl ItemGameIndices {
37 pub fn new(indices: HashMap<GenerationId, u16>) -> Self {
38 Self(indices)
39 }
40}
41
42#[derive(Debug, Clone, Serialize, Deserialize)]
43pub struct UnlinkedItem {
44 pub id: ItemId,
45 pub identifier: String,
46 pub names: LocalizedStrings,
47 pub flavor_texts: FlavorTexts,
48 pub effects: LocalizedEffects,
49 pub category_id: ItemCategoryId,
50 pub cost: u32,
51 pub fling_power: Option<u8>,
52 pub fling_effect_id: Option<ItemFlingEffectId>,
53 pub flag_ids: Vec<ItemFlagId>,
54 pub game_indices: ItemGameIndices,
55}
56
57impl Linkable for UnlinkedItem {
58 type Linked = Arc<Item>;
59
60 fn link(&self, context: &LinkContext) -> Self::Linked {
61 let category = context
62 .item_categories
63 .get(&self.category_id)
64 .unwrap_or_else(|| {
65 panic!(
66 "No item category '{}' found for item '{}'",
67 self.category_id, self.id
68 )
69 })
70 .clone();
71
72 let fling_effect = self.fling_effect_id.map(|effect_id| {
73 context
74 .item_fling_effects
75 .get(&effect_id)
76 .unwrap_or_else(|| {
77 panic!(
78 "No item fling effect '{}' found for item '{}'",
79 effect_id, self.id
80 )
81 })
82 .clone()
83 });
84
85 let flags = self
86 .flag_ids
87 .iter()
88 .map(|flag_id| {
89 context
90 .item_flags
91 .get(flag_id)
92 .unwrap_or_else(|| {
93 panic!("No item flag '{}' found for item '{}'", flag_id, self.id)
94 })
95 .clone()
96 })
97 .collect();
98
99 let item = Item {
100 id: self.id,
101 identifier: self.identifier.clone(),
102 names: self.names.clone(),
103 flavor_texts: self.flavor_texts.clone(),
104 effects: self.effects.clone(),
105 category,
106 cost: self.cost,
107 fling_power: self.fling_power,
108 fling_effect,
109 flags,
110 game_indices: self.game_indices.clone(),
111 };
112
113 Arc::new(item)
114 }
115}
116
117impl HasLocalizedNames for Item {
118 fn localized_names(&self) -> &LocalizedStrings {
119 &self.names
120 }
121}
122
123impl HasIdentifier for Item {
124 fn identifier(&self) -> &str {
125 &self.identifier
126 }
127}