1use std::{collections::HashMap, io, io::BufReader};
2
3#[cfg(feature = "serde")]
4use serde::{Deserialize, Serialize};
5
6use super::Definition;
7use crate::{extension::ReadExt, util};
8
9#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
12#[derive(Clone, Eq, PartialEq, Debug, Default)]
13pub struct ItemDefinition {
14 pub id: u16,
15 pub name: String,
16 pub stackable: bool,
17 pub cost: i32,
18 pub members_only: bool,
19 pub options: [String; 5],
20 pub interface_options: [String; 5],
21 pub tradable: bool,
22 pub noted_id: Option<u16>,
23 pub noted_template: Option<u16>,
24 pub stack_ids: Option<[u16; 10]>,
25 pub stack_count: Option<[u16; 10]>,
26 pub team: u8,
27 pub bought_link: Option<u16>,
28 pub bought_tempalte: Option<u16>,
29 pub shift_click_drop_index: Option<u8>,
30 pub params: HashMap<u32, String>,
31 pub inventory_model_data: InventoryModelData,
32 pub character_model_data: CharacterModelData,
33}
34
35#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
36#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
37pub struct InventoryModelData {
38 pub inventory_model: u16,
39 pub zoom2d: u16,
40 pub x_an2d: u16,
41 pub y_an2d: u16,
42 pub z_an2d: u16,
43 pub x_offset2d: u16,
44 pub y_offset2d: u16,
45 pub resize_x: u16,
46 pub resize_y: u16,
47 pub resize_z: u16,
48 pub color_find: Vec<u16>,
49 pub color_replace: Vec<u16>,
50 pub texture_find: Vec<u16>,
51 pub texture_replace: Vec<u16>,
52 pub ambient: i8,
53 pub contrast: i8,
54}
55
56#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
57#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
58pub struct CharacterModelData {
59 pub male_model10: Option<u16>,
60 pub male_model_offset: u8,
61 pub male_model1: Option<u16>,
62 pub female_model10: Option<u16>,
63 pub female_model_offset: u8,
64 pub female_model1: Option<u16>,
65 pub male_model12: Option<u16>,
66 pub female_model12: Option<u16>,
67 pub male_head_model1: Option<u16>,
68 pub female_head_model1: Option<u16>,
69 pub male_head_model2: Option<u16>,
70 pub female_head_model2: Option<u16>,
71}
72
73impl Definition for ItemDefinition {
74 fn new(id: u16, buffer: &[u8]) -> crate::Result<Self> {
75 let mut reader = BufReader::new(buffer);
76 let item_def = decode_buffer(id, &mut reader)?;
77
78 Ok(item_def)
79 }
80}
81
82fn decode_buffer(id: u16, reader: &mut BufReader<&[u8]>) -> io::Result<ItemDefinition> {
83 let mut item_def = ItemDefinition {
84 id,
85 inventory_model_data: InventoryModelData {
86 resize_x: 128,
87 resize_y: 128,
88 resize_z: 128,
89 zoom2d: 2000,
90 ..InventoryModelData::default()
91 },
92 options: [
93 "".to_string(),
94 "".to_string(),
95 "Take".to_string(),
96 "".to_string(),
97 "".to_string(),
98 ],
99 interface_options: [
100 "".to_string(),
101 "".to_string(),
102 "".to_string(),
103 "".to_string(),
104 "Drop".to_string(),
105 ],
106 ..ItemDefinition::default()
107 };
108
109 loop {
110 let opcode = reader.read_u8()?;
111
112 match opcode {
113 0 => break,
114 1 => {
115 item_def.inventory_model_data.inventory_model = reader.read_u16()?;
116 }
117 2 => {
118 item_def.name = reader.read_string()?;
119 }
120 4 => {
121 item_def.inventory_model_data.zoom2d = reader.read_u16()?;
122 }
123 5 => {
124 item_def.inventory_model_data.x_an2d = reader.read_u16()?;
125 }
126 6 => {
127 item_def.inventory_model_data.y_an2d = reader.read_u16()?;
128 }
129 7 => {
130 item_def.inventory_model_data.x_offset2d = reader.read_u16()?;
131 }
132 8 => {
133 item_def.inventory_model_data.y_offset2d = reader.read_u16()?;
134 }
135 11 => {
136 item_def.stackable = true;
137 }
138 12 => {
139 item_def.cost = reader.read_i32()?;
140 }
141 16 => item_def.members_only = true,
142 23 => {
143 item_def.character_model_data.male_model10 = Some(reader.read_u16()?);
144 item_def.character_model_data.male_model_offset = reader.read_u8()?;
145 }
146 24 => {
147 item_def.character_model_data.male_model1 = Some(reader.read_u16()?);
148 }
149 25 => {
150 item_def.character_model_data.female_model10 = Some(reader.read_u16()?);
151 item_def.character_model_data.female_model_offset = reader.read_u8()?;
152 }
153 26 => {
154 item_def.character_model_data.female_model1 = Some(reader.read_u16()?);
155 }
156 30..=34 => {
157 item_def.options[opcode as usize - 30] = reader.read_string()?;
158 }
159 35..=39 => {
160 item_def.interface_options[opcode as usize - 35] = reader.read_string()?;
161 }
162 40 => {
163 let len = reader.read_u8()? as usize;
164 item_def.inventory_model_data.color_find = Vec::with_capacity(len);
165 item_def.inventory_model_data.color_replace = Vec::with_capacity(len);
166 for _ in 0..len {
167 item_def
168 .inventory_model_data
169 .color_find
170 .push(reader.read_u16()?);
171 item_def
172 .inventory_model_data
173 .color_replace
174 .push(reader.read_u16()?);
175 }
176 }
177 41 => {
178 let len = reader.read_u8()? as usize;
179 item_def.inventory_model_data.texture_find = Vec::with_capacity(len);
180 item_def.inventory_model_data.texture_replace = Vec::with_capacity(len);
181 for _ in 0..len {
182 item_def
183 .inventory_model_data
184 .texture_find
185 .push(reader.read_u16()?);
186 item_def
187 .inventory_model_data
188 .texture_replace
189 .push(reader.read_u16()?);
190 }
191 }
192 42 => {
193 item_def.shift_click_drop_index = Some(reader.read_u8()?);
194 }
195 65 => {
196 item_def.tradable = true;
197 }
198 78 => {
199 item_def.character_model_data.male_model12 = Some(reader.read_u16()?);
200 }
201 79 => {
202 item_def.character_model_data.female_model12 = Some(reader.read_u16()?);
203 }
204 90 => {
205 item_def.character_model_data.male_head_model1 = Some(reader.read_u16()?);
206 }
207 91 => {
208 item_def.character_model_data.female_head_model1 = Some(reader.read_u16()?);
209 }
210 92 => {
211 item_def.character_model_data.male_head_model2 = Some(reader.read_u16()?);
212 }
213 93 => {
214 item_def.character_model_data.female_head_model2 = Some(reader.read_u16()?);
215 }
216 95 => {
217 item_def.inventory_model_data.z_an2d = reader.read_u16()?;
218 }
219 97 => {
220 item_def.noted_id = Some(reader.read_u16()?);
221 }
222 98 => {
223 item_def.noted_template = Some(reader.read_u16()?);
224 item_def.stackable = true;
225 }
226 100..=109 => {
227 item_def.stack_ids = Some([0; 10]);
228 item_def.stack_count = Some([0; 10]);
229 match item_def.stack_ids {
230 Some(mut stack_ids) => {
231 stack_ids[opcode as usize - 100] = reader.read_u16()?;
232 }
233 _ => unreachable!(),
234 }
235 match item_def.stack_count {
236 Some(mut stack_count) => {
237 stack_count[opcode as usize - 100] = reader.read_u16()?;
238 }
239 _ => unreachable!(),
240 }
241 }
242 110 => {
243 item_def.inventory_model_data.resize_x = reader.read_u16()?;
244 }
245 111 => {
246 item_def.inventory_model_data.resize_y = reader.read_u16()?;
247 }
248 112 => {
249 item_def.inventory_model_data.resize_z = reader.read_u16()?;
250 }
251 113 => {
252 item_def.inventory_model_data.ambient = reader.read_i8()?;
253 }
254 114 => {
255 item_def.inventory_model_data.contrast = reader.read_i8()?;
256 }
257 115 => {
258 item_def.team = reader.read_u8()?;
259 }
260 139 => {
261 item_def.bought_link = Some(reader.read_u16()?);
262 }
263 140 => {
264 item_def.bought_tempalte = Some(reader.read_u16()?);
265 }
266 148 | 149 => {
267 reader.read_u16()?;
268 }
269 249 => {
270 item_def.params = util::read_parameters(reader)?;
271 }
272 _ => unreachable!(),
273 }
274 }
275
276 Ok(item_def)
277}