rustorio_engine/
tick.rs

1use std::fmt::Display;
2
3/// The tick is used to keep track of time in the game.
4/// You can advance the game using the [`advance`](Tick::advance) method or similar.
5/// Many functions and building methods require a [`Tick`] to be passed in, which allows them to update their state.
6/// If a function takes a [`&mut Tick`](Tick), then the function will take time.
7/// If a function merely takes a [`&Tick`](Tick), or no [`Tick`]s at all, it will never advance the game time.
8#[derive(Debug)]
9pub struct Tick {
10    /// The current tick number.
11    pub tick: u64,
12    log: bool,
13}
14
15impl Tick {
16    pub(crate) fn start() -> Self {
17        Self { tick: 0, log: true }
18    }
19
20    /// Sets whether or not to log on tick advancement.
21    pub fn log(&mut self, log: bool) {
22        self.log = log;
23    }
24
25    /// Advances the game by one tick.
26    ///
27    /// By default prints the current tick number to the console.
28    /// If you want to disable this, use the [`log`](Tick::log) method.
29    pub fn advance(&mut self) {
30        self.advance_by(1);
31    }
32
33    /// Advances the game by the specified number of ticks.
34    ///
35    /// By default prints the current tick number to the console.
36    /// If you want to disable this, use the [`log`](Tick::log) method.
37    pub fn advance_by(&mut self, ticks: u64) {
38        self.tick = self.tick.checked_add(ticks).expect("Tick overflow. Well done you've found an exploit! Or you would have if `https://github.com/albertsgarde/rustorio/issues/3` hadn't beaten you to it!");
39        if self.log {
40            println!("{self}");
41        }
42    }
43
44    /// Advances the game until the specified tick number is reached.
45    /// Does nothing if the target tick is less than or equal to the current tick.
46    ///
47    /// By default prints the current tick number to the console.
48    /// If you want to disable this, use the [`log`](Tick::log) method.
49    pub fn advance_to_tick(&mut self, target_tick: u64) {
50        if target_tick > self.tick {
51            self.advance_by(target_tick - self.tick);
52        }
53    }
54
55    /// Advances the game until the specified condition is met or the maximum number of ticks has passed.
56    /// Returns `true` if the condition was met, or `false` if the maximum number of ticks was reached first.
57    ///
58    /// By default prints the current tick number to the console every tick.
59    /// If you want to disable this, use the [`log`](Tick::log) method.
60    pub fn advance_until<F>(&mut self, mut condition: F, max_ticks: u64) -> bool
61    where
62        F: FnMut(&Tick) -> bool,
63    {
64        let start_tick = self.tick;
65        while !condition(self) && self.tick - start_tick < max_ticks {
66            self.advance();
67        }
68        self.tick - start_tick < max_ticks
69    }
70
71    /// Returns the current tick number.
72    pub fn cur(&self) -> u64 {
73        self.tick
74    }
75}
76
77impl From<&Tick> for u64 {
78    fn from(tick: &Tick) -> Self {
79        tick.tick
80    }
81}
82
83impl PartialOrd<u64> for &Tick {
84    fn partial_cmp(&self, other: &u64) -> Option<std::cmp::Ordering> {
85        Some(self.tick.cmp(other))
86    }
87}
88
89impl PartialOrd<&Tick> for u64 {
90    fn partial_cmp(&self, other: &&Tick) -> Option<std::cmp::Ordering> {
91        Some(self.cmp(&other.tick))
92    }
93}
94
95impl PartialEq<u64> for &Tick {
96    fn eq(&self, other: &u64) -> bool {
97        self.tick == *other
98    }
99}
100
101impl PartialEq<&Tick> for u64 {
102    fn eq(&self, other: &&Tick) -> bool {
103        *self == other.tick
104    }
105}
106
107impl Display for Tick {
108    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
109        write!(f, "Tick {}", self.tick)
110    }
111}