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 tick: u64,
12 log: bool,
13}
14
15impl Tick {
16 pub(crate) const fn start() -> Self {
17 Self {
18 tick: 0,
19 log: false,
20 }
21 }
22
23 /// Sets whether or not to log on tick advancement.
24 pub const fn log(&mut self, log: bool) {
25 self.log = log;
26 }
27
28 /// Advances the game by one tick.
29 ///
30 /// By default prints the current tick number to the console.
31 /// If you want to disable this, use the [`log`](Tick::log) method.
32 pub fn advance(&mut self) {
33 self.advance_by(1);
34 }
35
36 /// Advances the game by the specified number of ticks.
37 ///
38 /// By default prints the current tick number to the console.
39 /// If you want to disable this, use the [`log`](Tick::log) method.
40 pub fn advance_by(&mut self, ticks: u64) {
41 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!");
42 if self.log {
43 println!("{self}");
44 }
45 }
46
47 /// Advances the game until the specified tick number is reached.
48 /// Does nothing if the target tick is less than or equal to the current tick.
49 ///
50 /// By default prints the current tick number to the console.
51 /// If you want to disable this, use the [`log`](Tick::log) method.
52 pub fn advance_to_tick(&mut self, target_tick: u64) {
53 if target_tick > self.tick {
54 self.advance_by(target_tick - self.tick);
55 }
56 }
57
58 /// Advances the game until the specified condition is met or the maximum number of ticks has passed.
59 /// Returns `true` if the condition was met, or `false` if the maximum number of ticks was reached first.
60 ///
61 /// By default prints the current tick number to the console every tick.
62 /// If you want to disable this, use the [`log`](Tick::log) method.
63 pub fn advance_until<F>(&mut self, mut condition: F, max_ticks: u64) -> bool
64 where
65 F: FnMut(&Tick) -> bool,
66 {
67 let start_tick = self.tick;
68 while !condition(self) && self.tick - start_tick < max_ticks {
69 self.advance();
70 }
71 self.tick - start_tick < max_ticks
72 }
73
74 /// Returns the current tick number.
75 pub const fn cur(&self) -> u64 {
76 self.tick
77 }
78}
79
80impl From<&Tick> for u64 {
81 fn from(tick: &Tick) -> Self {
82 tick.tick
83 }
84}
85
86impl PartialOrd<u64> for &Tick {
87 fn partial_cmp(&self, other: &u64) -> Option<std::cmp::Ordering> {
88 Some(self.tick.cmp(other))
89 }
90}
91
92impl PartialOrd<&Tick> for u64 {
93 fn partial_cmp(&self, other: &&Tick) -> Option<std::cmp::Ordering> {
94 Some(self.cmp(&other.tick))
95 }
96}
97
98impl PartialEq<u64> for &Tick {
99 fn eq(&self, other: &u64) -> bool {
100 self.tick == *other
101 }
102}
103
104impl PartialEq<&Tick> for u64 {
105 fn eq(&self, other: &&Tick) -> bool {
106 *self == other.tick
107 }
108}
109
110impl Display for Tick {
111 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
112 write!(f, "Tick {}", self.tick)
113 }
114}