Skip to main content

rust_warrior/
warrior.rs

1//! contains the interface exposed to the player for controlling the Warrior
2
3use crate::{
4    actions::{Action, Direction},
5    floor::Tile,
6};
7use std::cell::RefCell;
8
9/// An interface the player can interact with to control the Warrior in the
10/// game. An instance is passed to [`Player`](crate::player::Player) via the
11/// `play_turn` method.
12/// The player must pick one [`Action`](crate::actions::Action) to perform
13/// each turn. Not all abilities are an `Action`.
14/// Warrior abilities are unlocked as the player progresses through the levels.
15///
16/// ### Level Guide
17///
18/// **Level 1**
19///
20/// Available abilities:
21///
22/// * [`walk`](crate::warrior::Warrior::walk)
23///
24/// **Level 2**
25///
26/// New abilities unlocked at this level:
27///
28/// * [`check`](crate::warrior::Warrior::check)
29/// * [`attack`](crate::warrior::Warrior::attack)
30///
31/// **Level 3**
32///
33/// New abilities unlocked at this level:
34///
35/// * [`health`](crate::warrior::Warrior::health)
36/// * [`rest`](crate::warrior::Warrior::rest)
37///
38/// **Level 4**
39///
40/// *No new abilities unlocked at this level!*
41///
42/// **Level 5**
43///
44/// New abilities unlocked at this level:
45///
46/// * [`rescue`](crate::warrior::Warrior::rescue)
47///
48/// **Level 6**
49///
50/// The following abilities now have a *directional* counterpart:
51///
52/// * `walk` -> [`walk_toward`](crate::warrior::Warrior::walk_toward)
53/// * `check` -> [`check_toward`](crate::warrior::Warrior::check_toward)
54/// * `attack` -> [`attack_toward`](crate::warrior::Warrior::attack_toward)
55/// * `rescue` -> [`rescue_toward`](crate::warrior::Warrior::rescue_toward)
56///
57/// **Level 7**
58///
59/// New abilities unlocked at this level:
60///
61/// * [`pivot`](crate::warrior::Warrior::pivot)
62///
63/// **Level 8**
64///
65/// New abilities (and *directional* counterparts) unlocked at this level:
66///
67/// * [`look`](crate::warrior::Warrior::look) -> [`look_toward`](crate::warrior::Warrior::look_toward)
68/// * [`shoot`](crate::warrior::Warrior::shoot) -> [`shoot_toward`](crate::warrior::Warrior::shoot_toward)
69///
70/// **Level 9**
71///
72/// *No new abilities unlocked at this level!*
73pub struct Warrior {
74    level: usize,
75    ahead: Vec<Tile>,
76    behind: Vec<Tile>,
77    health: i32,
78    facing: Direction,
79    action: RefCell<Option<Action>>,
80    warnings: RefCell<Vec<String>>,
81}
82
83impl Warrior {
84    pub fn new(
85        level: usize,
86        ahead: Vec<Tile>,
87        behind: Vec<Tile>,
88        health: i32,
89        facing: Direction,
90    ) -> Warrior {
91        Warrior {
92            level,
93            ahead,
94            behind,
95            health,
96            facing,
97            action: RefCell::new(None),
98            warnings: RefCell::new(Vec::new()),
99        }
100    }
101
102    /// Walk forward one tile.
103    /// This is an [`Action`](crate::actions::Action).
104    /// This ability is available at **Level 1**.
105    pub fn walk(&self) {
106        self.perform_walk(Direction::Forward);
107    }
108
109    /// Walk one tile toward specified `direction`.
110    /// This is an [`Action`](crate::actions::Action).
111    /// This ability is unlocked at **Level 6**.
112    pub fn walk_toward(&self, direction: Direction) {
113        if self.level < 6 {
114            panic!("You have not yet learned `walk_toward`! Perhaps you meant `walk`?")
115        }
116        self.perform_walk(direction);
117    }
118
119    // private helper for `walk` and `walk_toward`
120    fn perform_walk(&self, direction: Direction) {
121        self.perform(Action::Walk(direction));
122    }
123
124    /// Check the tile in front of the Warrior.
125    /// Returns a [`Tile`](crate::Tile).
126    /// This ability is unlocked at **Level 2**.
127    pub fn check(&self) -> Tile {
128        if self.level < 2 {
129            panic!("You have not yet learned `check`!");
130        }
131        self.perform_check(Direction::Forward)
132    }
133
134    /// Check the tile toward specified `direction`.
135    /// Returns a [`Tile`](crate::Tile).
136    /// This ability is unlocked at **Level 6**.
137    pub fn check_toward(&self, direction: Direction) -> Tile {
138        if self.level < 6 {
139            panic!("You have not yet learned `check_toward`! Perhaps you meant `check`?")
140        }
141        self.perform_check(direction)
142    }
143
144    // private helper for `check` and `check_toward`
145    fn perform_check(&self, direction: Direction) -> Tile {
146        match direction {
147            Direction::Forward => match self.ahead.first() {
148                Some(tile) => *tile,
149                None => Tile::Wall,
150            },
151            Direction::Backward => match self.behind.first() {
152                Some(tile) => *tile,
153                None => Tile::Wall,
154            },
155        }
156    }
157
158    /// Check three tiles in front of the Warrior.
159    /// Returns a vector of up to three [`Tile`](crate::Tile)s.
160    /// This ability is unlocked at **Level 8**.
161    pub fn look(&self) -> &Vec<Tile> {
162        if self.level < 8 {
163            panic!("You have not yet learned `look`!")
164        }
165        self.look_toward(Direction::Forward)
166    }
167
168    /// Check three tiles toward specified `direction`.
169    /// Returns a vector of up to three [`Tile`](crate::Tile)s.
170    /// This ability is unlocked at **Level 8**.
171    pub fn look_toward(&self, direction: Direction) -> &Vec<Tile> {
172        if self.level < 8 {
173            panic!("You have not yet learned `look_toward`!")
174        }
175        match direction {
176            Direction::Forward => &self.ahead,
177            Direction::Backward => &self.behind,
178        }
179    }
180
181    /// Attempt to attack an enemy in the tile in front of the Warrior.
182    /// This is an [`Action`](crate::actions::Action).
183    /// This ability is unlocked at **Level 2**.
184    pub fn attack(&self) {
185        if self.level < 2 {
186            panic!("You have not yet learned `attack`!");
187        }
188        self.perform_attack(Direction::Forward);
189    }
190
191    /// Attempt to attack an enemy one tile away in specified `direction`.
192    /// This is an [`Action`](crate::actions::Action).
193    /// This ability is unlocked at **Level 6**.
194    pub fn attack_toward(&self, direction: Direction) {
195        if self.level < 6 {
196            panic!("You have not yet learned `attack_toward`! Perhaps you meant `attack`?")
197        }
198        self.perform_attack(direction);
199    }
200
201    // private helper for `attack` and `attack_toward`
202    fn perform_attack(&self, direction: Direction) {
203        self.perform(Action::Attack(direction));
204    }
205
206    /// Check the current health of the Warrior.
207    /// This ability is unlocked at **Level 3**.
208    pub fn health(&self) -> i32 {
209        if self.level < 3 {
210            panic!("You have not yet learned `health`!");
211        }
212        self.health
213    }
214
215    /// Rest and regain 10% of the Warrior's HP.
216    /// This is an [`Action`](crate::actions::Action).
217    /// This ability is unlocked at **Level 3**.
218    pub fn rest(&self) {
219        if self.level < 3 {
220            panic!("You have not yet learned `rest`!");
221        }
222        self.perform(Action::Rest);
223    }
224
225    /// Attempt to rescue a Captive in front of the Warrior.
226    /// This is an [`Action`](crate::actions::Action).
227    /// This ability is unlocked at **Level 5**.
228    pub fn rescue(&self) {
229        if self.level < 5 {
230            panic!("You have not yet learned `rescue`!");
231        }
232        self.perform_rescue(Direction::Forward);
233    }
234
235    /// Attempt to rescue a Captive one tile away in specified `direction`.
236    /// This is an [`Action`](crate::actions::Action).
237    /// This ability is unlocked at **Level 6**.
238    pub fn rescue_toward(&self, direction: Direction) {
239        if self.level < 6 {
240            panic!("You have not yet learned `rescue_toward`! Perhaps you meant `rescue`?")
241        }
242        self.perform_rescue(direction);
243    }
244
245    // private helper for `rescue` and `rescue_toward`
246    fn perform_rescue(&self, direction: Direction) {
247        self.perform(Action::Rescue(direction));
248    }
249
250    /// Rotate 180 degrees.
251    /// This is an [`Action`](crate::actions::Action).
252    /// This ability is unlocked at **Level 7**.
253    pub fn pivot(&self) {
254        if self.level < 7 {
255            panic!("You have not yet learned `pivot`!")
256        }
257        let direction = match self.facing {
258            Direction::Forward => Direction::Backward,
259            Direction::Backward => Direction::Forward,
260        };
261        self.perform(Action::Pivot(direction));
262    }
263
264    /// Fire an arrow up to three tiles in front of the Warrior.
265    /// This is an [`Action`](crate::actions::Action).
266    /// This ability is unlocked at **Level 8**.
267    pub fn shoot(&self) {
268        if self.level < 8 {
269            panic!("You have not yet learned `shoot`!")
270        }
271        self.shoot_toward(Direction::Forward);
272    }
273
274    /// Fire an arrow up to three tiles toward specified `direction`.
275    /// This is an [`Action`](crate::actions::Action).
276    /// This ability is unlocked at **Level 8**.
277    pub fn shoot_toward(&self, direction: Direction) {
278        if self.level < 8 {
279            panic!("You have not yet learned `shoot_toward`!")
280        }
281        self.perform(Action::Shoot(direction));
282    }
283
284    /// Some [`Action`](crate::actions::Action) the Warrior has performed;
285    /// None if no action has been performed.
286    pub fn action(&self) -> Option<Action> {
287        *self.action.borrow()
288    }
289
290    fn perform(&self, action: Action) {
291        if let Some(prev) = *self.action.borrow() {
292            let warnings = &mut *self.warnings.borrow_mut();
293            warnings.push(format!("WARNING: Already performed action: {:?}", prev));
294            warnings.push(format!(
295                "WARNING: Unable to perform additional action: {:?}",
296                action
297            ));
298            return;
299        }
300
301        *self.action.borrow_mut() = Some(action);
302    }
303
304    pub fn warnings(&self) -> Vec<String> {
305        let warnings = &*self.warnings.borrow();
306        warnings.clone()
307    }
308}