kingslayer/input/
parser.rs

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}