1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
use crate::body::{Body, ClothesItemC};
use crate::error::{RequestClothesOffErr, RequestClothesOnErr};
use crate::inventory::items::ClothesDescription;
use crate::utils::ClothesGroupC;
use crate::utils::event::{MessageQueue, Event};
use std::collections::HashMap;
use std::fmt;
use std::hash::{Hash, Hasher};
mod warmth;
mod wetness;
pub mod fluent;
impl Body {
/// Registers a list of clothes groups.
///
/// # Parameters
/// - `groups`: a list of clothes groups to register. Use [`ClothesGroupBuilder`](crate::body::ClothesGroupBuilder)
/// to create one.
///
/// # Examples
///
///```
/// use crate::zara::body::ClothesGroupBuilder;
///
/// person.body.register_clothes_groups(
/// vec![
/// ClothesGroupBuilder::start()
/// .with_name("Group Name")
/// .bonus_cold_resistance(5)
/// .bonus_water_resistance(12)
/// .includes(
/// vec![
/// ("Jacket", JacketClothes),
/// ("Pants", PantsClothes),
/// //.. and so on
/// ]
/// )
/// .build()
/// ]
/// );
///```
///
/// # Links
/// See [this wiki article](https://github.com/vagrod/zara-rust/wiki/Clothes-groups) for more info.
pub fn register_clothes_groups(&self, groups: Vec<ClothesGroup>) {
let mut b = self.clothes_groups.borrow_mut();
for group in groups {
b.insert(group.name.to_string(), group);
}
}
pub(crate) fn request_clothes_on(&self, item_name: &String, data: &dyn ClothesDescription) -> Result<(), RequestClothesOnErr> {
{
let mut clothes = self.clothes.borrow_mut();
if clothes.contains(item_name) {
return Err(RequestClothesOnErr::AlreadyHaveThisItemOn);
}
clothes.push(item_name.to_string());
let mut cdata = self.clothes_data.borrow_mut();
cdata.insert(item_name.to_string(), ClothesItemC {
cold_resistance: data.cold_resistance(),
water_resistance: data.water_resistance()
});
}
self.refresh_clothes_group();
self.recalculate_warmth_level();
self.queue_message(Event::ClothesOn(item_name.to_string()));
Ok(())
}
pub(crate) fn request_clothes_off(&self, item_name: &String) -> Result<(), RequestClothesOffErr> {
{
let mut clothes = self.clothes.borrow_mut();
match clothes.iter().position(|x| x == item_name) {
Some(ind) => {
clothes.remove(ind);
},
None => {
return Err(RequestClothesOffErr::ItemIsNotOn);
}
}
let mut cdata = self.clothes_data.borrow_mut();
if cdata.contains_key(item_name) {
cdata.remove(item_name);
}
}
self.refresh_clothes_group();
self.recalculate_warmth_level();
self.queue_message(Event::ClothesOff(item_name.to_string()));
Ok(())
}
fn refresh_clothes_group(&self) {
match self.clothes_groups.borrow_mut().iter().find(|(_, group)|
(*group).has_complete(self.clothes.borrow().clone())) {
Some((key, g)) => {
self.clothes_group.replace(Some(ClothesGroupC {
name: key.to_string(),
bonus_cold_resistance: g.bonus_cold_resistance,
bonus_water_resistance: g.bonus_water_resistance
}))
},
None => self.clothes_group.replace(None)
};
}
}
/// Holds the information about clothes item
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Default)]
pub struct ClothesItem {
/// Name of the inventory item
pub name: String,
/// Water resistance value, 0..100
pub water_resistance: usize,
/// Cold resistance value, 0..100
pub cold_resistance: usize
}
impl fmt::Display for ClothesItem {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.name)
}
}
impl ClothesItem {
/// Creates a new clothes item
///
/// # Parameters
/// - `name`: unique name of the inventory item
/// - `water_resistance`: percent 0..100 of the water resistance value
/// - `cold_resistance`: percent 0..100 of the cold resistance value
///
/// # Examples
/// ```
/// use zara::body;
///
/// let o = body::ClothesItem::new(name, 7, 15);
/// ```
///
/// # Links
/// See [this wiki article](https://github.com/vagrod/zara-rust/wiki/Clothes) for more info.
pub fn new(name: String, water_resistance: usize, cold_resistance: usize) -> Self {
ClothesItem {
name,
water_resistance,
cold_resistance
}
}
}
/// Holds the information about clothes group set
#[derive(Clone, PartialEq, Eq, Debug, Default)]
pub struct ClothesGroup {
/// Name of the group
pub name: String,
/// Items that are included in this group
pub items: HashMap<String, ClothesItem>,
/// Group cold resistance bonus, 0..100
pub bonus_cold_resistance: usize,
/// Group water resistance bonus, 0..100
pub bonus_water_resistance: usize
}
impl fmt::Display for ClothesGroup {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}: {} items", self.name, self.items.len())
}
}
impl Hash for ClothesGroup {
fn hash<H: Hasher>(&self, state: &mut H) {
self.name.hash(state);
self.items.iter().for_each(|(key, _)| key.hash(state));
self.bonus_cold_resistance.hash(state);
self.bonus_water_resistance.hash(state);
}
}
impl ClothesGroup {
/// Creates new clothes group set. You can use [`ClothesGroupBuilder`](crate::body::ClothesGroupBuilder)
/// to construct new group.
///
/// # Parameters
/// - `name`: unique name of the group. Will become its key
/// - `items`: a list of inventory items names that form this group
/// - `bonus_cold_resistance`: bonus cold resistance value, 0..100 percents
/// - `bonus_water_resistance`: bonus water resistance value, 0..100 percents
///
/// # Examples
/// ```
/// use zara::body;
///
/// let o = body::ClothesGroup::new(name,
/// vec![
/// ("Pants", Box::new(PantsClothes)),
/// ("Jacket", Box::new(JacketClothes)),
/// // ... and so on
/// ], 5, 7);
/// ```
///
/// # Links
/// See [this wiki article](https://github.com/vagrod/zara-rust/wiki/Clothes-groups) for more info.
pub fn new(name: String, items: Vec<ClothesItem>, bonus_cold_resistance: usize, bonus_water_resistance: usize) -> Self {
let mut items_map = HashMap::new();
for item in items {
items_map.insert(item.name.to_string(), item.clone());
}
ClothesGroup {
name,
items: items_map,
bonus_cold_resistance,
bonus_water_resistance
}
}
/// Returns `true` is this group contains particular clothes item
///
/// # Parameters
/// - `item_name`: unique name of the inventory item
///
/// # Examples
/// ```
/// let value = group.contains(jacket_name);
/// ```
///
/// # Links
/// See [this wiki article](https://github.com/vagrod/zara-rust/wiki/Clothes-groups) for more info.
pub fn contains(&self, item_name: &String) -> bool { self.items.contains_key(item_name) }
/// Returns `true` if given set of clothes has all the items needed for this group
///
/// # Parameters
/// - `items`: a list of inventory items names
///
/// # Examples
/// ```
/// let value = group.has_complete(items_list);
/// ```
///
/// # Links
/// See [this wiki article](https://github.com/vagrod/zara-rust/wiki/Clothes-groups) for more info.
pub fn has_complete(&self, items: Vec<String>) -> bool {
if items.len() == 0 { return false; }
for (key, _) in self.items.iter() {
if items.iter().all(|x| x != key) {
return false;
}
}
true
}
}