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}