1use crate::{
2 cli::Cli,
3 input::CmdTokens,
4 player::Player,
5 types::{Action, CmdResult},
6 world::World,
7};
8
9#[derive(Debug)]
10pub struct Parser;
11
12impl Parser {
13 fn parse_attack(
14 verb: &str,
15 words: &CmdTokens,
16 world: &mut World,
17 player: &mut Player,
18 ) -> CmdResult {
19 if let Some(obj) = words.obj() {
20 if let Some(obj_prep) = words.obj_prep() {
21 if words.prep() == Some(&String::from("with")) {
22 let res = world.harm_enemy(obj, player.attack_with(obj_prep));
23 if res.is_active() {
24 player.engage_combat()
25 }
26 res
27 } else {
28 CmdResult::no_comprendo()
29 }
30 } else if player.main_hand().is_some() {
31 let res = world.harm_enemy(obj, player.attack_main());
32 if res.is_active() {
33 player.engage_combat()
34 }
35 res
36 } else {
37 CmdResult::do_what(&format!("{} the {} with", verb, obj))
38 .with_request_input(CmdTokens::new(verb).with_obj(obj).with_prep("with"))
39 }
40 } else {
41 CmdResult::do_what_prep(verb, words.prep(), words.obj_prep())
42 }
43 }
44
45 fn parse_close(
46 verb: &str,
47 words: &CmdTokens,
48 world: &mut World,
49 player: &mut Player,
50 ) -> CmdResult {
51 if let Some(obj) = words.obj() {
52 if let Some(res) = player.close(obj) {
53 res
54 } else {
55 world.close(obj)
56 }
57 } else {
58 CmdResult::do_what(verb)
59 }
60 }
61
62 fn parse_don(verb: &str, words: &CmdTokens, player: &mut Player) -> CmdResult {
63 if let Some(obj) = words.obj() {
64 player.don_armor(obj)
65 } else {
66 CmdResult::do_what(verb)
67 }
68 }
69
70 fn parse_drop(
71 verb: &str,
72 words: &CmdTokens,
73 world: &mut World,
74 player: &mut Player,
75 ) -> CmdResult {
76 if let Some(obj) = words.obj() {
77 world.insert(obj, player.remove(obj))
78 } else {
79 CmdResult::do_what(verb)
80 }
81 }
82
83 fn parse_equip(verb: &str, words: &CmdTokens, player: &mut Player) -> CmdResult {
84 if let Some(obj) = words.obj() {
85 player.equip(obj)
86 } else {
87 CmdResult::do_what(verb)
88 }
89 }
90
91 fn parse_hail(words: &CmdTokens, world: &mut World) -> CmdResult {
92 if let Some(obj) = words.obj() {
93 world.hail(obj)
94 } else {
95 CmdResult::new(Action::Passive, "Hello, sailor!")
96 }
97 }
98
99 fn parse_increase(words: &CmdTokens, player: &mut Player) -> CmdResult {
100 if let Some(obj) = words.obj() {
101 player.increase_ability_score(obj)
102 } else {
103 CmdResult::do_what(
104 "increase?
105 \r(strength, dexterity, constitution, intellect, wisdom, charisma)",
106 )
107 }
108 }
109
110 fn parse_move(verb: &str, words: &CmdTokens, world: &mut World) -> CmdResult {
111 if let Some(obj) = words.obj() {
112 world.move_room(obj)
113 } else {
114 CmdResult::new(Action::Passive, format!("Where do you want to {}?", verb))
115 .with_request_input(CmdTokens::new(verb))
116 }
117 }
118
119 fn parse_unlock(verb: &str, words: &CmdTokens, world: &mut World) -> CmdResult {
120 if let Some(obj) = words.obj() {
121 world.unlock(obj)
122 } else {
123 CmdResult::do_what(verb)
124 }
125 }
126
127 fn parse_open(
128 verb: &str,
129 words: &CmdTokens,
130 world: &mut World,
131 player: &mut Player,
132 ) -> CmdResult {
133 if let Some(obj) = words.obj() {
134 if let Some(res) = player.open(obj) {
135 res
136 } else {
137 world.open(obj)
138 }
139 } else {
140 CmdResult::do_what(verb)
141 }
142 }
143
144 fn parse_put(
145 words: &CmdTokens,
146 verb: &str,
147 world: &mut World,
148 player: &mut Player,
149 ) -> CmdResult {
150 if let Some(prep) = words.prep() {
151 match prep {
152 "in" | "inside" => {
153 if let Some(obj) = words.obj() {
154 if let Some(obj_prep) = words.obj_prep() {
155 if player.has(obj_prep) {
156 player.insert_into(obj, obj_prep)
157 } else {
158 let (res, rejected_item) =
159 world.insert_into(obj, obj_prep, player.remove(obj));
160 if let Some(item) = rejected_item {
161 player.take_back(item);
162 }
163 res
164 }
165 } else {
166 CmdResult::do_what(&format!("place in the {}", obj)).with_request_input(
167 CmdTokens::new("place").with_obj(obj).with_prep("in"),
168 )
169 }
170 } else {
171 CmdResult::do_what(verb)
172 }
173 }
174 "on" => {
175 if let Some(obj_prep) = words.obj_prep() {
176 player.don_armor(obj_prep)
177 } else {
178 CmdResult::do_what(&format!("{} on", verb))
179 }
180 }
181 _ => CmdResult::no_comprendo(),
182 }
183 } else if let Some(obj) = words.obj() {
184 CmdResult::do_what(&format!("{} the {} in", verb, obj))
185 .with_request_input(CmdTokens::new("put").with_obj(obj).with_prep("in"))
186 } else {
187 CmdResult::do_what_prep(verb, words.prep(), words.obj_prep())
188 }
189 }
190
191 fn parse_take(
192 verb: &str,
193 words: &CmdTokens,
194 world: &mut World,
195 player: &mut Player,
196 ) -> CmdResult {
197 if let Some(obj) = words.obj() {
198 if let Some(prep) = words.prep() {
199 if prep == "from" || prep == "out" || prep == "in" {
200 if let Some(obj_prep) = words.obj_prep() {
201 if player.has(obj_prep) {
202 player.take_from_self(obj, obj_prep)
203 } else {
204 player.take_item_from(world.give_from(obj, obj_prep))
205 }
206 } else {
207 CmdResult::do_what(&format!("{} the {} from", verb, obj))
208 .with_request_input(
209 CmdTokens::new("take").with_obj(obj).with_prep("from"),
210 )
211 }
212 } else {
213 CmdResult::no_comprendo()
214 }
215 } else if obj == "all" || obj.len() >= 4 && obj.starts_with("all ") {
216 player.take_all(world.give_all())
217 } else {
218 player.take(obj, world.give(obj))
219 }
220 } else {
221 CmdResult::do_what_prep(verb, words.prep(), words.obj_prep())
222 }
223 }
224
225 fn parse_x(verb: &str, words: &CmdTokens, world: &mut World, player: &mut Player) -> CmdResult {
226 if let Some(obj) = words.obj() {
227 if let Some(s) = player.inspect(obj) {
228 s
229 } else if let Some(s) = world.inspect(obj) {
230 s
231 } else {
232 CmdResult::no_item_here(obj)
233 }
234 } else {
235 CmdResult::do_what(verb)
236 }
237 }
238
239 pub fn parse(words: &CmdTokens, world: &mut World, player: &mut Player) -> CmdResult {
240 if let (Some(verb), Some(short_verb)) = words.short_verb() {
241 match short_verb {
242 "north" | "south" | "east" | "west" | "northeast" | "northwest" | "southeast"
243 | "southwest" | "up" | "down" => world.move_room(verb),
244 "enter" | "go" | "move" | "exit" => Parser::parse_move(verb, words, world),
245 "c" | "stat" | "stats" => player.info(),
246 "i" | "invent" => player.print_inventory(),
247 "l" | "look" => world.look(),
248 "attack" | "cut" | "hit" | "kill" | "slay" => {
249 Parser::parse_attack(verb, words, world, player)
250 }
251 "heal" | "rest" | "sleep" => player.rest(),
252 "hail" | "talk" | "hi" | "hello" | "greet" => Parser::parse_hail(words, world),
253 "cast" | "use" => {
254 CmdResult::new(Action::Passive, String::from("TODO: cast something"))
255 }
256 "close" => Parser::parse_close(verb, words, world, player),
257 "don" | "wear" => Parser::parse_don(verb, words, player),
258 "draw" | "equip" | "hold" => Parser::parse_equip(verb, words, player),
259 "drop" | "remove" | "throw" => Parser::parse_drop(verb, words, world, player),
260 "examin" | "inspec" | "read" | "search" | "x" => {
261 Parser::parse_x(verb, words, world, player)
262 }
263 "get" | "take" => Parser::parse_take(verb, words, world, player),
264 "increa" => Parser::parse_increase(words, player),
265 "lock" => CmdResult::new(Action::Passive, String::from("TODO: lock something")),
266 "open" => Parser::parse_open(verb, words, world, player),
267 "insert" | "place" | "put" => Parser::parse_put(words, verb, world, player),
268 "unlock" | "pick" => Parser::parse_unlock(verb, words, world),
269 "wait" | "z" => Player::wait(),
270 "help" => Cli::help(),
271 _ => CmdResult::new(
272 Action::Failed,
273 format!("I do not know the word \"{}\".", verb),
274 ),
275 }
276 } else {
277 CmdResult::no_comprendo()
278 }
279 }
280}