1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
/*
 * This project is licensed under the MIT license.
 * See the LICENSE file in the project root for more information.
 */
use std::collections::HashMap;
use std::{io, thread, time};

///
///An Action is composed of three strings.
///The first one is the text that will be shown to the user.
///The second is what the action will do.  For example, in a PickUp action, it would be the item that would be given to the user.
///The third one is the requirement. This will check if the user  has the item specified, and only if true will proceed.
#[derive(Clone, Debug)]
pub enum Action {
    PickUp(String, String, String),
    Move(String, String, String),
}

#[derive(Clone)]
pub struct Room {
    pub scene: String,
    pub actions: Vec<Action>,
}

pub struct Character {
    pub inventory: HashMap<String, String>,
    pub room: String,
}

pub struct Game {
    pub rooms: HashMap<String, Room>,
    pub character: Character,
}

impl Action {
    pub fn text(&self) -> String {
        match &self {
            &&Action::Move(ref s, _, _) => s.clone(),
            &&Action::PickUp(ref s, _, _) => s.clone(),
        }
    }
}

impl Game {
    pub fn action(&mut self, a: Action) {
        match a {
            Action::PickUp(_, i, r) => {
                if self.character.inventory.contains_key(&r) || &r == "" {
                    self.character.inventory.insert(i.clone(), i);
                    self.clear();
                }
            }
            Action::Move(_, r, i) => {
                if self.character.inventory.contains_key(&i) || &i == "" {
                    self.character.room = r;
                } else {
                    println!("Opening this room requires {}", i);
                    self.clear();
                }
            }
        }
    }

    pub fn render_room(&mut self, r: Room) {
        for c in r.scene.lines() {
            println!("{}", c);
        }
        for (i, a) in r.actions.iter().enumerate() {
            println!("{}. {}\n", i, a.text());
        }
    }

    pub fn clear(&self) {
        print!("{}[2J", 27 as char);
    }

    pub fn play(&mut self) {
        print!(
            "
    :::      :::::::: :::::::::::       ::::::::
  :+: :+:   :+:    :+:    :+:          :+:    :+:
 +:+   +:+  +:+           +:+                +:+
+#++:++#++: +#+           +#+              +#+
+#+     +#+ +#+           +#+            +#+
#+#     #+# #+#    #+#    #+#           #+#
###     ###  ########     ###          ##########
\n"
        );
        println!("Act 2 Text Adventure Engine");
        thread::sleep(time::Duration::from_millis(4000));
        self.clear();
        'outer: loop {
            let rooms = self.rooms.clone();
            let r = rooms.get(&self.character.room).unwrap();
            self.render_room(r.clone());
            let mut s = String::new();
            io::stdin().read_line(&mut s).unwrap();

            match s.chars().nth(0).unwrap().to_digit(10) {
                Some(u) => {
                    let a = match r.actions.iter().nth(u as usize) {
                        Some(x) => x,
                        None => {
                            continue 'outer;
                        }
                    };
                    self.action(a.clone());
                }
                None => continue 'outer,
            }
        }
    }
}