zara/utils/
mod.rs

1use crate::health::StageLevel;
2use crate::body::{BodyPart, BodyAppliance};
3
4use std::time::{Duration};
5use std::cell::Cell;
6use rand::Rng;
7
8use event::{Dispatcher, Listener};
9use core::ops;
10use std::fmt;
11use std::cmp::Ordering;
12use std::hash::{Hash, Hasher};
13
14pub mod event;
15
16/// Structure for storing all needed frame data for controllers
17/// including events dispatcher
18pub struct FrameC<'a, E: Listener + 'static> {
19    /// Snapshot of the current frame state
20    pub data: &'a FrameSummaryC,
21    /// Events dispatcher
22    pub events: &'a mut Dispatcher<E>
23}
24
25/// Structure for storing frame meta info
26pub struct FrameSummaryC {
27    /// Game time snapshot for this frame
28    pub game_time: GameTimeC,
29    /// Player status snapshot for this frame
30    pub player: PlayerStatusC,
31    /// Environment snapshot for this frame
32    pub environment: EnvironmentC,
33    /// Health snapshot for this frame
34    pub health: HealthC,
35    /// How many game seconds passed since last call
36    pub game_time_delta: f32,
37}
38
39/// Structure that holds game time.
40///
41/// Can be converted from and to `Duration`.
42///
43/// # Properties
44/// - `day`: day of game time (whole number)
45/// - `hour`: day of game time whole number)
46/// - `minute`: day of game time (whole number)
47/// - `second`: day of game time (with floating point)
48/// - `duration`: `Duration` that corresponds to the above values
49/// 
50/// # Links
51/// See [this wiki article](https://github.com/vagrod/zara-rust/wiki/Game-Time) for more info.
52#[derive(Default)]
53pub struct GameTime {
54    /// Day of the game time (whole number)
55    pub day : Cell<u64>,
56    /// Hour of the game time (whole number)
57    pub hour : Cell<u64>,
58    /// Minute of the game time (whole number)
59    pub minute : Cell<u64>,
60    /// Second of the game time (with floating point)
61    pub second : Cell<f64>,
62    /// `Duration` that corresponds to the values contained in other fields
63    pub duration: Cell<Duration>
64}
65impl fmt::Display for GameTime {
66    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67        write!(f, "{}d {}h {}m {:.1}s", self.day.get(), self.hour.get(), self.minute.get(), self.second.get())
68    }
69}
70impl GameTime {
71    /// Creates new zero game time.
72    ///
73    /// # Examples
74    /// ```
75    /// use zara::utils;
76    ///
77    /// let gt = utils::GameTime::new();
78    /// ```
79    /// 
80    /// # Links
81    /// See [this wiki article](https://github.com/vagrod/zara-rust/wiki/Game-Time) for more info.
82    pub fn new() -> Self {
83        GameTime {
84            day: Cell::new(0),
85            hour : Cell::new(0),
86            minute: Cell::new(0),
87            second: Cell::new(0.),
88            duration: Cell::new(Duration::new(0, 0))
89        }
90    }
91
92    /// Creates new `GameTime` object from a given `Duration` object
93    ///
94    /// # Parameters
95    /// - `d`: `Duration` object to create new game time from
96    ///
97    /// # Examples
98    /// ```
99    /// use zara::utils;
100    ///
101    /// let game_time = utils::GameTime::from_duration(duration);
102    /// ```
103    pub fn from_duration(d: Duration) -> GameTime {
104        let gt = GameTime::new();
105
106        gt.update_from_duration(d);
107
108        gt
109    }
110
111    /// Creates new `GameTime` object from its simple representation
112    /// 
113    /// # Examples
114    /// ```
115    /// use zara::utils;
116    ///
117    /// let game_time = utils::GameTime::from_contract(game_time_contract);
118    /// ```
119    pub fn from_contract(gt: GameTimeC) -> Self {
120        GameTime::from_duration(gt.to_duration())
121    }
122
123    /// Creates `GameTimeC` contract from this `GameTime` instance
124    /// 
125    /// # Examples
126    /// ```
127    /// let game_time_contract = game_time.to_contract();
128    /// ```
129    pub fn to_contract(&self) -> GameTimeC {
130        GameTimeC {
131            day: self.day.get(),
132            hour: self.hour.get(),
133            minute: self.minute.get(),
134            second: self.second.get()
135        }
136    }
137
138    /// Adds given `Duration` value to this game time
139    ///
140    /// # Parameters
141    /// - `d`: `Duration` object to add
142    ///
143    /// # Examples
144    /// ```
145    /// game_time.add_duration(duration);
146    /// ```
147    pub fn add_duration(&self, d: Duration) {
148        let new_values = self.duration.get() + d;
149
150        self.update_from_duration(new_values);
151    }
152
153    /// Adds given number of seconds to this game time
154    ///
155    /// # Parameters
156    /// - `value`: seconds to add
157    ///
158    /// # Examples
159    /// ```
160    /// game_time.add_seconds(amount);
161    /// ```
162    pub fn add_seconds(&self, value: f32) {
163        let new_seconds = self.duration.get().as_secs_f64() + value as f64;
164
165        self.update_from_seconds(new_seconds);
166    }
167
168    /// Updates this game time to match a given `GameTime`
169    ///
170    /// # Parameters
171    /// - `new_values`: `GameTime` object to match
172    ///
173    /// # Examples
174    /// ```
175    /// game_time.update_from(duration);
176    /// ```
177    pub fn update_from(&self, new_values: &GameTime) {
178        self.second.set(new_values.second.get());
179        self.minute.set(new_values.minute.get());
180        self.hour.set(new_values.hour.get());
181        self.day.set(new_values.day.get());
182    }
183
184    /// Updates all fields inside this game time to match the given `Duration`
185    ///
186    /// # Parameters
187    /// - `d`: `Duration` object to apply to this game time
188    ///
189    /// # Examples
190    /// ```
191    /// game_time.update_from_duration(duration);
192    /// ```
193    pub fn update_from_duration(&self, d: Duration){
194        let secs_passed_f64 = d.as_secs_f64();
195
196        self.update_from_seconds(secs_passed_f64);
197    }
198
199    /// Updates all fields inside this game time to match the given seconds amount
200    ///
201    /// # Parameters
202    /// - `new_seconds`: amount of seconds
203    ///
204    /// # Examples
205    /// ```
206    /// game_time.update_from_seconds(amount);
207    /// ```
208    pub fn update_from_seconds(&self, new_seconds: f64){
209        let second = new_seconds % 60_f64;
210        let secs_passed = new_seconds;
211        let minutes_passed = ((secs_passed / 60_f64) as u64) as u64;
212        let minute = minutes_passed % 60_u64;
213        let hours_passed = ((minutes_passed / 60_u64) as u64) as u64;
214        let hour = hours_passed % 24_u64;
215        let day = ((hours_passed / 24_u64) as u64) as u64;
216
217        self.day.set(day);
218        self.hour.set(hour);
219        self.minute.set(minute);
220        self.second.set(second);
221        self.duration.set(Duration::from_secs_f64(new_seconds));
222    }
223
224}
225
226/// Structure for storing simple game time slice.ActiveDiseaseC
227/// 
228/// # Links
229/// See [this wiki article](https://github.com/vagrod/zara-rust/wiki/Game-Time) for more info.
230#[derive(Copy, Clone, Debug, Default)]
231pub struct GameTimeC {
232    /// Day value
233    pub day: u64,
234    /// Hour value
235    pub hour: u64,
236    /// Minute value
237    pub minute: u64,
238    /// Second value
239    pub second: f64
240}
241impl Ord for GameTimeC {
242    fn cmp(&self, other: &Self) -> Ordering {
243        self.to_duration().cmp(&other.to_duration())
244    }
245}
246impl Eq for GameTimeC { }
247impl PartialOrd for GameTimeC {
248    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
249        Some(self.cmp(other))
250    }
251}
252impl PartialEq for GameTimeC {
253    fn eq(&self, other: &Self) -> bool {
254        const EPS: f64 = 0.0001;
255
256        self.day == other.day &&
257        self.hour == other.hour &&
258        self.minute == other.minute &&
259        f64::abs(self.second - other.second) < EPS
260    }
261}
262impl fmt::Display for GameTimeC {
263    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
264        write!(f, "{}d {}h {}m {:.1}s", self.day, self.hour, self.minute, self.second)
265    }
266}
267impl Hash for GameTimeC {
268    fn hash<H: Hasher>(&self, state: &mut H) {
269        self.day.hash(state);
270        self.hour.hash(state);
271        self.minute.hash(state);
272
273        state.write_u32((self.second*100_f64) as u32);
274    }
275}
276impl GameTimeC {
277    /// Creates empty (zero) `GameTimeC`
278    /// 
279    /// # Examples
280    /// ```
281    /// use zara::utils;
282    /// 
283    /// let game_time = utils::GameTimeC::empty();
284    /// ```
285    pub fn empty() -> Self {
286        GameTimeC {
287            day: 0,
288            hour: 0,
289            minute: 0,
290            second: 0.
291        }
292    }
293
294    /// Creates new `GameTimeC` with given time values
295    /// 
296    /// # Examples
297    /// ```
298    /// use zara::utils;
299    /// 
300    /// let game_time = utils::GameTimeC::new(0, 5, 52, 34.);
301    /// ```
302    pub fn new(day: u64, hour: u64, minute: u64, second: f64) -> Self {
303        GameTimeC {
304            day,
305            minute,
306            hour,
307            second
308        }
309    }
310
311    /// Returns `f32` that describes duration (in game seconds) of this `GameTimeC` instance
312    /// 
313    /// # Examples
314    /// ```
315    /// let value = game_time.as_secs_f32();
316    /// ```
317    pub fn as_secs_f32(&self) -> f32 {
318        self.second as f32+
319            (self.minute as f32)*60_f32+
320            (self.hour as f32)*60_f32*60_f32+
321            (self.day as f32)*24_f32*60_f32*60_f32
322    }
323
324    /// Returns new `GameTimeC` by adding a given amount of minutes
325    /// to the current one
326    /// 
327    /// # Examples
328    /// ```
329    /// let new_game_time = game_time.add_minutes(12);
330    /// ```
331    pub fn add_minutes(&self, amount: u64) -> GameTimeC {
332        let d= self.to_duration() + Duration::from_secs(amount*60);
333
334        GameTimeC::from_duration(d)
335    }
336
337    /// Returns `Duration` object that describes current `GameTimeC`
338    /// 
339    /// # Examples
340    /// ```
341    /// let d = game_time.to_duration();
342    /// ```
343    pub fn to_duration(&self) -> Duration {
344        Duration::from_secs_f64(
345            self.second+((self.minute*60+self.hour*60*60+self.day*24*60*60) as f64))
346    }
347
348    /// Returns new `GameTimeC` instance based on the given `Duration` object
349    /// 
350    /// # Examples
351    /// ```
352    /// use zara::utils;
353    /// 
354    /// let game_time = utils::GameTimeC::from_duration(d);
355    /// ```
356    pub fn from_duration(d: Duration) -> Self {
357        GameTime::from_duration(d).to_contract()
358    }
359}
360
361impl ops::Add<GameTimeC> for GameTimeC {
362    type Output = GameTimeC;
363
364    fn add(self, _rhs: GameTimeC) -> GameTimeC {
365        let d = self.to_duration() + _rhs.to_duration();
366
367        GameTime::from_duration(d).to_contract()
368    }
369}
370
371impl ops::Sub<GameTimeC> for GameTimeC {
372    type Output = GameTimeC;
373
374    fn sub(self, _rhs: GameTimeC) -> GameTimeC {
375        let d = self.to_duration() - _rhs.to_duration();
376
377        GameTime::from_duration(d).to_contract()
378    }
379}
380
381/// Describes clothes group object simplified contract
382#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Default)]
383pub struct ClothesGroupC {
384    /// Name of the group
385    pub name: String,
386    /// Group bonus cold resistance (0..100)
387    pub bonus_cold_resistance: usize,
388    /// Group bonus water resistance (0..100)
389    pub bonus_water_resistance: usize
390}
391impl fmt::Display for ClothesGroupC {
392    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
393        write!(f, "Group {} data", self.name)
394    }
395}
396
397/// Structure for storing health snapshot
398pub struct HealthC {
399    /// Body temperature (degrees C)
400    pub body_temperature: f32,
401    /// Heart rate (bpm)
402    pub heart_rate: f32,
403    /// Top body pressure (mmHg)
404    pub top_pressure: f32,
405    /// Bottom body pressure (mmHg)
406    pub bottom_pressure: f32,
407    /// Blood level (0..100)
408    pub blood_level: f32,
409    /// Food level (0..100)
410    pub food_level: f32,
411    /// Water level (0..100)
412    pub water_level: f32,
413    /// Stamina level (0..100)
414    pub stamina_level: f32,
415    /// Fatigue level (0..100)
416    pub fatigue_level: f32,
417    /// Oxygen level (0..100)
418    pub oxygen_level: f32,
419    /// List of active (or scheduled) diseases
420    pub diseases: Vec<ActiveDiseaseC>,
421    /// List of active (or scheduled) injuries
422    pub injuries: Vec<ActiveInjuryC>
423}
424impl HealthC {
425    /// Return "healthy" contract instance, with all vitals set to 
426    /// values that describes a healthy individual
427    /// 
428    /// # Examples
429    /// ```
430    /// use zara::utils;
431    /// 
432    /// let o = utils::HealthC::healthy();
433    /// ```
434    pub fn healthy() -> Self {
435        HealthC {
436            blood_level: 100.,
437            body_temperature: 36.6,
438            top_pressure: 120.,
439            bottom_pressure: 70.,
440            food_level: 100.,
441            water_level: 100.,
442            heart_rate: 64.,
443            stamina_level: 100.,
444            fatigue_level: 0.,
445            oxygen_level: 100.,
446            diseases: Vec::new(),
447            injuries: Vec::new()
448        }
449    }
450}
451
452/// Structure for storing active disease simplified contract
453#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Default)]
454pub struct ActiveDiseaseC {
455    /// Name of a disease
456    pub name: String,
457    /// Time when this disease becomes active
458    pub scheduled_time: GameTimeC,
459    /// Time when this disease ends (if ends)
460    pub end_time: Option<GameTimeC>,
461    /// Current disease active level
462    pub current_level: StageLevel,
463    /// Current disease active level progression (0..100)
464    pub current_level_percent: usize,
465    /// Is this disease active now
466    pub is_active: bool,
467    /// Is this disease inverted (healing) now
468    pub is_healing: bool,
469    /// Do this disease needs treatment (or will self-heal)
470    pub needs_treatment: bool
471}
472impl fmt::Display for ActiveDiseaseC {
473    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
474        write!(f, "{} @{}, active={}", self.name, self.scheduled_time, self.is_active)
475    }
476}
477
478/// Structure for storing active injury simplified contract
479#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Default)]
480pub struct ActiveInjuryC {
481    /// Name of the injury
482    pub name: String,
483    /// Time when this injury becomes active
484    pub scheduled_time: GameTimeC,
485    /// Time when this injury ends (if ends)
486    pub end_time: Option<GameTimeC>,
487    /// Current injury active level
488    pub current_level: StageLevel,
489    /// Current injury active level progression (0..100)
490    pub current_level_percent: usize,
491    /// Is this injury active now
492    pub is_active: bool,
493    /// Is this injury inverted (healing) now
494    pub is_healing: bool,
495    /// Do this injury needs treatment (or will self-heal)
496    pub needs_treatment: bool,
497    /// Was blood forcibly stopped for this injury
498    pub is_blood_stopped: bool,
499    /// Body part where this injury resides
500    pub body_part: BodyPart,
501    /// Is this injury a fracture
502    pub is_fracture: bool
503}
504impl fmt::Display for ActiveInjuryC {
505    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
506        write!(f, "{} on {} @{}, fracture={}, active={}", self.name, self.body_part, self.scheduled_time,
507               self.is_fracture, self.is_active)
508    }
509}
510
511/// Describes initial environment information
512/// 
513/// # Links
514/// See [this wiki article](https://github.com/vagrod/zara-rust/wiki/Environment) for more info.
515#[derive(Clone, Debug, Default)]
516pub struct EnvironmentC {
517    /// Wind speed value (m/s)
518    pub wind_speed: f32,
519    /// Temperature, degrees C
520    pub temperature : f32,
521    /// Rain intensity, 0..1
522    pub rain_intensity : f32
523}
524impl fmt::Display for EnvironmentC {
525    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
526        write!(f, "World: temp {:.1}C, wind {:.1} m/s, rain {:.1}", self.temperature, self.wind_speed, self.rain_intensity)
527    }
528}
529impl Eq for EnvironmentC { }
530impl PartialEq for EnvironmentC {
531    fn eq(&self, other: &Self) -> bool {
532        const EPS: f32 = 0.0001;
533
534        f32::abs(self.wind_speed - other.wind_speed) < EPS &&
535        f32::abs(self.temperature - other.temperature) < EPS &&
536        f32::abs(self.rain_intensity - other.rain_intensity) < EPS
537    }
538}
539impl Hash for EnvironmentC {
540    fn hash<H: Hasher>(&self, state: &mut H) {
541        state.write_i32((self.temperature*10_000_f32) as i32);
542        state.write_u32((self.wind_speed*10_000_f32) as u32);
543        state.write_u32((self.rain_intensity*10_000_f32) as u32);
544    }
545}
546impl EnvironmentC {
547    /// Creates new environment description object.
548    ///
549    /// To create an empty (default) environment description,
550    /// use [`empty`] method.
551    ///
552    /// [`empty`]: #method.empty
553    ///
554    /// # Parameters
555    /// - `temperature`: temperature, degrees C
556    /// - `rain_intansity`: rain intensity, 0..1
557    /// - `wind_speed`: m/s
558    ///
559    /// # Examples
560    /// ```
561    /// use zara::utils;
562    ///
563    /// let env = utils::EnvironmentC::new(25., 3., 0.12);
564    /// ```
565    /// 
566    /// # Links
567    /// See [this wiki article](https://github.com/vagrod/zara-rust/wiki/Environment) for more info.
568    pub fn new(temperature: f32, wind_speed: f32, rain_intensity: f32) -> EnvironmentC {
569        EnvironmentC {
570            wind_speed,
571            temperature,
572            rain_intensity
573        }
574    }
575
576    /// Creates default environment description object.
577    ///
578    /// To create environment description with default values (26 degrees C, no rain, no wind),
579    /// use [`new`] method.
580    ///
581    /// [`new`]: #method.new
582    ///
583    /// # Examples
584    /// ```
585    /// use zara::utils;
586    ///
587    /// let env = utils::EnvironmentC::default();
588    /// ```
589    /// 
590    /// # Links
591    /// See [this wiki article](https://github.com/vagrod/zara-rust/wiki/Environment) for more info.
592    pub fn default() -> EnvironmentC { EnvironmentC::new(26., 0., 0.) }
593}
594
595/// Simplified player state for a single frame
596#[derive(Clone, Debug, Default)]
597pub struct PlayerStatusC {
598    /// Is player walking now
599    pub is_walking: bool,
600    /// Is player running now
601    pub is_running: bool,
602    /// Is player swimming now
603    pub is_swimming: bool,
604    /// Is player under the water now
605    pub is_underwater: bool,
606    /// Is player sleeping now
607    pub is_sleeping: bool,
608    /// Last time player slept (if any)
609    pub last_slept: Option<GameTimeC>,
610    /// For how long player slept last time
611    pub last_slept_duration: f32,
612    /// Player's current warmth level (-5..+5 is a comfort zone)
613    pub warmth_level: f32,
614    /// Player's current wetness level (0..100)
615    pub wetness_level: f32,
616    /// Clothes player is wearing now
617    pub clothes: Vec<String>,
618    /// Body appliances player is wearing now
619    pub appliances: Vec<BodyAppliance>,
620    /// Current clothes group (is any)
621    pub clothes_group: Option<ClothesGroupC>,
622    /// Total calculated water resistance value (0..100)
623    pub total_water_resistance: usize,
624    /// Total calculated cold resistance value (0..100)
625    pub total_cold_resistance: usize,
626    /// Player's current inventory weight
627    pub inventory_weight: f32
628}
629impl fmt::Display for PlayerStatusC {
630    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
631        write!(f, "Player status ({} clothes, {} appliances, inventory {:.0}g)", self.clothes.len(),
632               self.appliances.len(), self.inventory_weight)
633    }
634}
635impl Eq for PlayerStatusC { }
636impl PartialEq for PlayerStatusC {
637    fn eq(&self, other: &Self) -> bool {
638        const EPS: f32 = 0.0001;
639
640        self.is_walking == other.is_walking &&
641        self.is_running == other.is_running &&
642        self.is_swimming == other.is_swimming &&
643        self.is_underwater == other.is_underwater &&
644        self.is_sleeping == other.is_sleeping &&
645        self.last_slept == other.last_slept &&
646        self.clothes == other.clothes &&
647        self.appliances == other.appliances &&
648        self.clothes_group == other.clothes_group &&
649        self.total_water_resistance == other.total_water_resistance &&
650        self.total_cold_resistance == other.total_cold_resistance &&
651        f32::abs(self.last_slept_duration - other.last_slept_duration) < EPS &&
652        f32::abs(self.warmth_level - other.warmth_level) < EPS &&
653        f32::abs(self.wetness_level - other.wetness_level) < EPS &&
654        f32::abs(self.inventory_weight - other.inventory_weight) < EPS
655    }
656}
657impl Hash for PlayerStatusC {
658    fn hash<H: Hasher>(&self, state: &mut H) {
659        self.is_walking.hash(state);
660        self.is_running.hash(state);
661        self.is_swimming.hash(state);
662        self.is_underwater.hash(state);
663        self.is_sleeping.hash(state);
664        self.last_slept.hash(state);
665        self.clothes.hash(state);
666        self.appliances.hash(state);
667        self.clothes_group.hash(state);
668        self.total_water_resistance.hash(state);
669        self.total_cold_resistance.hash(state);
670
671        state.write_u32((self.last_slept_duration*10_000_f32) as u32);
672        state.write_i32((self.warmth_level*10_000_f32) as i32);
673        state.write_u32((self.wetness_level*10_000_f32) as u32);
674        state.write_u32((self.inventory_weight*1_000_f32) as u32);
675    }
676}
677
678/// Classic linear lerp
679/// 
680/// # Examples
681/// ```
682/// let value = zara::utils::lerp(0., 5., 0.8);
683/// ```
684pub fn lerp(first: f32, second: f32, by: f32) -> f32 {
685    first * (1. - by) + second * by
686}
687
688/// Clamp both ways
689/// 
690/// # Examples
691/// ```
692/// let value = zara::utils::clamp(101., 0., 100.);
693/// ```
694pub fn clamp(value: f32, floor: f32, ceiling: f32) -> f32 {
695    if value > ceiling {
696        return ceiling;
697    }
698
699    if value < floor {
700        return floor;
701    }
702
703    value
704}
705
706/// Clamps ceiling
707/// 
708/// # Examples
709/// ```
710/// let value = zara::utils::clamp_to(101., 100.);
711/// ```
712pub fn clamp_to(value: f32, ceiling: f32) -> f32 {
713    if value > ceiling {
714        return ceiling;
715    }
716
717    value
718}
719
720/// Clamps floor
721/// 
722/// # Examples
723/// ```
724/// let value = zara::utils::clamp_bottom(-5., 0.);
725/// ```
726pub fn clamp_bottom(value: f32, floor: f32) -> f32 {
727    if value < floor {
728        return floor;
729    }
730
731    value
732}
733
734
735/// Clamps 0..1
736/// 
737/// # Examples
738/// ```
739/// let value = zara::utils::clamp_01(2.3);
740/// ```
741pub fn clamp_01(value: f32) -> f32 {
742    if value > 1. {
743        return 1.;
744    }
745    if value < 0. {
746        return 0.;
747    }
748
749    value
750}
751
752/// Will return `true` is a given probability is satisfied
753/// 
754/// # Examples
755/// ```
756/// if zara::utils::roll_dice(65) {
757///     // ...
758/// }
759/// ```
760pub fn roll_dice(probability: usize) -> bool {
761    if probability == 0 { return false; }
762    if probability >= 100 { return true; }
763
764    let mut rng = rand::thread_rng();
765    let r = rng.gen_range(0..100);
766
767    r < probability
768}
769
770/// Will return a random number between these two
771/// 
772/// # Examples
773/// ```
774/// let value = zara::utils::range(0., 100.);
775/// ```
776pub fn range(a: f32, b: f32) -> f32 {
777    let mut rng = rand::thread_rng();
778
779    rng.gen_range(a..b)
780}