diff --git a/src/main.rs b/src/main.rs index 6b6fa3e..24332be 100644 --- a/src/main.rs +++ b/src/main.rs @@ -34,6 +34,18 @@ fn print (mut s: &str) { println! ("{}", s); } +fn print_help () { + print ("All commands are ASCII and case-insensitive."); + print ("Commands should start with a verb like LOOK."); + print ("e.g. `look table`"); + print ("Single-word verbs are better, e.g. prefer `hint` over `give me a hint`"); + print ("When in doubt, try generic verbs like `look` or `use` over specific verbs like `actuate`, `type`, or `consolidate`."); +} + +fn print_undetected_item () { + print ("That ITEM does not exist in this ROOM, or you have not detected it."); +} + fn read_input () -> Result { { let mut stdout = stdout (); @@ -53,13 +65,199 @@ fn read_input () -> Result { #[derive (Debug, PartialEq)] enum PlayerAction { + Quit, + Help, + Hint, Nonsense, + Wait, + Look (ItemName), + LookAround, } -fn parse_input (_s: &str) -> PlayerAction { +#[derive (Clone, Copy, Debug, PartialEq)] +enum ItemName { + Nonsense, + + Door, + EmergencyExit, + Keypad, + Note, + Table, +} + +fn item_name_display (x: ItemName) -> &'static str { + match x { + Nonsense => "NONSENSE", + + Door => "DOOR", + EmergencyExit => "EMERGENCY EXIT", + Keypad => "KEYPAD", + Note => "NOTE", + Table => "TABLE", + } +} + +fn parse_input (s: &str) -> PlayerAction { + let s = s.to_lowercase (); + + if s == "quit" || s == "quit game" { + return PlayerAction::Quit; + } + + if s == "look" || s == "look around" { + return PlayerAction::LookAround; + } + + if let Some (rest) = s.strip_prefix ("look at the ") { + return PlayerAction::Look (parse_item_name (rest)); + } + + if let Some (rest) = s.strip_prefix ("look at ") { + return PlayerAction::Look (parse_item_name (rest)); + } + + if let Some (rest) = s.strip_prefix ("look ") { + return PlayerAction::Look (parse_item_name (rest)); + } + + if let Some (rest) = s.strip_prefix ("examine ") { + return PlayerAction::Look (parse_item_name (rest)); + } + + if s == "do nothing" { + return PlayerAction::Wait; + } + if s == "wait" { + return PlayerAction::Wait; + } + + if s == "help" { + return PlayerAction::Help; + } + if s == "hint" { + return PlayerAction::Hint; + } + PlayerAction::Nonsense } +fn parse_item_name (s: &str) -> ItemName { + if s == "door" { + return ItemName::Door; + } + + if s == "emergency exit" { + return ItemName::EmergencyExit; + } + + if s == "keypad" { + return ItemName::Keypad; + } + + if s == "note" { + return ItemName::Note; + } + + if s == "table" { + return ItemName::Table; + } + + ItemName::Nonsense +} + +#[derive (Default)] +struct StateRoom1 { + detected_keypad: bool, + detected_note: bool, +} + +#[derive (Default)] +struct State { + quitting: bool, + room_1: StateRoom1, +} + +fn room_1 (state: &mut State) -> Result <()> { + let input = read_input ()?; + let action = parse_input (&input); + + match action { + PlayerAction::Quit => { + print ("Bye."); + state.quitting = true; + } + PlayerAction::Help => { + print_help (); + }, + PlayerAction::Hint => { + print ("Hint for this room: Try using the `help` command."); + }, + PlayerAction::Nonsense => { + print ("I couldn't understand that. Try `help` or `hint`."); + print ("`hint` may contain spoilers. `help` will not."); + }, + PlayerAction::Wait => { + print ("You wait around a bit. You can hear humming from the electrical lights, and the distant rumble of the building's HVAC system. The room smells faintly of fresh paint. Nothing has changed."); + }, + PlayerAction::LookAround => { + print ("You are in a small room. In one corner is a TABLE. Obvious exits are a locked DOOR, and an EMERGENCY EXIT."); + } + PlayerAction::Look (item_name) => { + match item_name { + ItemName::Nonsense => { + print_undetected_item (); + }, + ItemName::Door => { + print ("You examine the DOOR. It is firmly locked, and you don't have any lock-picking tools. On the DOOR is an electronic KEYPAD."); + state.room_1.detected_keypad = true; + }, + ItemName::EmergencyExit => { + print ("The EMERGENCY EXIT reads, \"Emergency exit. Push bar to open. Alarm will sound. Door will unlock in 15 seconds.\". The EMERGENCY EXIT is period-accurate for an American Wal-Mart c. 2020 C.E."); + }, + ItemName::Keypad => { + if state.room_1.detected_keypad { + print ("The DOOR is locked by an electronic KEYPAD. A soft amber power light indicates that the KEYPAD is likely functional. The KEYPAD buttons are the digits 0-9, Enter, and Clear. Experience tells you that the key code is likely 4 or 5 digits long."); + } + else { + print_undetected_item (); + } + }, + ItemName::Note => { + if state.room_1.detected_note { + for x in [ + "You pick up the NOTE and read it.", + "", + "Welcome to SEROTONIN DEPOSITORY.", + "As you play, keep in mind:", + "- LOOKing at ITEMS is not always safe", + "- TAKEing an item may be bad long-term", + "- WAITing counts as an action", + "- LOOKing AROUND is always safe", + "- Other NOTEs may contain non-truths", + "The code for this first KEYPAD is 1234.", + "", + " -- Phayle Sayf", + "", + "You notice that the NOTE is _not_ period-accurate.", + ].into_iter () { + print (x); + } + } + else { + print_undetected_item (); + } + }, + ItemName::Table => { + print ("You look at the TABLE. Your instincts tell you that it is period-accurate. Upon the TABLE sits a NOTE."); + state.room_1.detected_note = true; + }, + } + }, + } + + Ok (()) +} + fn main () -> Result <()> { print ("Welcome to SEROTONIN DEPOSITORY, the only adventure game ever made."); print (""); @@ -74,10 +272,14 @@ fn main () -> Result <()> { } print (""); - print ("You are in a small room. In one corner is a TABLE. The door behind you is locked. Obvious exits are a DOOR locked by a KEYPAD, and an EMERGENCY EXIT."); - let input = read_input ()?; - let _action = parse_input (&input); + let mut state = State::default (); + + print ("You are in a small room. In one corner is a TABLE."); + + while ! state.quitting { + room_1 (&mut state)?; + } Ok (()) } @@ -86,10 +288,20 @@ fn main () -> Result <()> { mod test { #[test] fn parse_input () { - use super::PlayerAction::*; + use super::{ + ItemName, + PlayerAction::*, + }; for (input, expected) in [ ("", Nonsense), + ("look at the table", Look (ItemName::Table)), + ("look at table", Look (ItemName::Table)), + ("look table", Look (ItemName::Table)), + ("LOOK TABLE", Look (ItemName::Table)), + ("wait", Wait), + ("help", Help), + ("hint", Hint), ].into_iter () { let actual = super::parse_input (input); assert_eq! (actual, expected);