1use crate::race::{Gender, Race, Tribe, get_race_id};
5
6#[repr(u8)]
7#[derive(Debug, Clone, PartialEq, Eq, Hash)]
8pub enum Slot {
10 Head,
12 Hands,
14 Legs,
16 Feet,
18 Body,
20 Earring,
22 Neck,
24 Wrists,
26 RingLeft,
28 RingRight,
30}
31
32pub fn get_slot_abbreviation(slot: Slot) -> &'static str {
34 match slot {
35 Slot::Head => "met",
36 Slot::Hands => "glv",
37 Slot::Legs => "dwn",
38 Slot::Feet => "sho",
39 Slot::Body => "top",
40 Slot::Earring => "ear",
41 Slot::Neck => "nek",
42 Slot::Wrists => "wrs",
43 Slot::RingLeft => "ril",
44 Slot::RingRight => "rir",
45 }
46}
47
48pub fn get_slot_from_id(id: i32) -> Option<Slot> {
51 match id {
52 3 => Some(Slot::Head),
53 4 => Some(Slot::Body),
54 5 => Some(Slot::Hands),
55 7 => Some(Slot::Legs),
56 8 => Some(Slot::Feet),
57 9 => Some(Slot::Earring),
58 10 => Some(Slot::Neck),
59 11 => Some(Slot::Wrists),
60 12 => Some(Slot::RingLeft),
61 13 => Some(Slot::RingRight),
62 _ => None,
63 }
64}
65
66pub fn get_slot_from_abbreviation(abrev: &str) -> Option<Slot> {
69 match abrev {
70 "met" => Some(Slot::Head),
71 "glv" => Some(Slot::Hands),
72 "dwn" => Some(Slot::Legs),
73 "sho" => Some(Slot::Feet),
74 "top" => Some(Slot::Body),
75 "ear" => Some(Slot::Earring),
76 "nek" => Some(Slot::Neck),
77 "wrs" => Some(Slot::Wrists),
78 "ril" => Some(Slot::RingLeft),
79 "rir" => Some(Slot::RingRight),
80 _ => None,
81 }
82}
83
84pub fn build_equipment_path(
86 model_id: i32,
87 race: Race,
88 tribe: Tribe,
89 gender: Gender,
90 slot: Slot,
91) -> String {
92 format!(
93 "chara/equipment/e{:04}/model/c{:04}e{:04}_{}.mdl",
94 model_id,
95 get_race_id(race, tribe, gender).unwrap(),
96 model_id,
97 get_slot_abbreviation(slot)
98 )
99}
100
101#[repr(u8)]
102#[derive(Clone, Copy)]
103pub enum CharacterCategory {
104 Body,
105 Hair,
106 Face,
107 Tail,
108 Ear,
109}
110
111pub fn get_character_category_path(category: CharacterCategory) -> &'static str {
112 match category {
113 CharacterCategory::Body => "body",
114 CharacterCategory::Hair => "hair",
115 CharacterCategory::Face => "face",
116 CharacterCategory::Tail => "tail",
117 CharacterCategory::Ear => "zear",
118 }
119}
120
121pub fn get_character_category_abbreviation(category: CharacterCategory) -> &'static str {
122 match category {
123 CharacterCategory::Body => "top",
124 CharacterCategory::Hair => "hir",
125 CharacterCategory::Face => "fac",
126 CharacterCategory::Tail => "til",
127 CharacterCategory::Ear => "zer",
128 }
129}
130
131pub fn get_character_category_prefix(category: CharacterCategory) -> &'static str {
132 match category {
133 CharacterCategory::Body => "b",
134 CharacterCategory::Hair => "h",
135 CharacterCategory::Face => "f",
136 CharacterCategory::Tail => "t",
137 CharacterCategory::Ear => "z",
138 }
139}
140
141pub fn build_character_path(
143 category: CharacterCategory,
144 body_ver: i32,
145 race: Race,
146 tribe: Tribe,
147 gender: Gender,
148) -> String {
149 let category_path = get_character_category_path(category);
150 let race_id = get_race_id(race, tribe, gender).unwrap();
151 let category_abbreviation = get_character_category_abbreviation(category);
152 let category_prefix = get_character_category_prefix(category);
153 format!(
154 "chara/human/c{race_id:04}/obj/{category_path}/{category_prefix}{body_ver:04}/model/c{race_id:04}{category_prefix}{body_ver:04}_{category_abbreviation}.mdl"
155 )
156}
157
158pub fn build_gear_material_path(gear_id: i32, gear_version: i32, material_name: &str) -> String {
160 format!("chara/equipment/e{gear_id:04}/material/v{gear_version:04}{material_name}")
161}
162
163pub fn build_skin_material_path(race_code: i32, body_code: i32, material_name: &str) -> String {
165 format!("chara/human/c{race_code:04}/obj/body/b{body_code:04}/material/v0001{material_name}")
166}
167
168pub fn build_face_material_path(race_code: i32, face_code: i32, material_name: &str) -> String {
170 format!("chara/human/c{race_code:04}/obj/face/f{face_code:04}/material{material_name}")
171}
172
173pub fn build_hair_material_path(race_code: i32, hair_code: i32, material_name: &str) -> String {
175 format!("chara/human/c{race_code:04}/obj/hair/h{hair_code:04}/material/v0001{material_name}")
176}
177
178pub fn build_ear_material_path(race_code: i32, ear_code: i32, material_name: &str) -> String {
180 format!("chara/human/c{race_code:04}/obj/ear/e{ear_code:04}/material/v0001{material_name}")
181}
182
183pub fn build_tail_material_path(race_code: i32, tail_code: i32, material_name: &str) -> String {
185 format!("chara/human/c{race_code:04}/obj/tail/t{tail_code:04}/material/v0001{material_name}")
186}
187
188pub fn deconstruct_equipment_path(path: &str) -> Option<(i32, Slot)> {
189 let model_id = &path[6..10];
190 let slot_name = &path[11..14];
191
192 Some((
193 model_id.parse().ok()?,
194 get_slot_from_abbreviation(slot_name)?,
195 ))
196}
197
198#[cfg(test)]
199mod tests {
200 use super::*;
201
202 #[test]
203 fn test_equipment_path() {
204 assert_eq!(
205 build_equipment_path(0, Race::Hyur, Tribe::Midlander, Gender::Male, Slot::Body),
206 "chara/equipment/e0000/model/c0101e0000_top.mdl"
207 );
208 }
209
210 #[test]
211 fn test_deconstruct() {
212 assert_eq!(
213 deconstruct_equipment_path("c0101e0000_top.mdl"),
214 Some((0, Slot::Body))
215 );
216 }
217}