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}