rust_warrior/
game.rs

1//! where it all starts
2
3use std::env;
4use std::fs;
5
6use crate::{engine, floor::Floor, profile::Profile, starter, ui, Player};
7
8/// This is exposed to the [`Player`](crate::player::Player) to get things
9/// started. Their profile is loaded (from .profile) and then the
10/// [`engine`](crate::engine) is fired up. If the current level is
11/// completed successfully, then the README.md file and their profile are
12/// updated.
13pub struct Game {
14    pub profile: Profile,
15}
16
17impl Default for Game {
18    fn default() -> Game {
19        // TODO: epic mode?
20        let profile = load_profile();
21
22        Game { profile }
23    }
24}
25
26impl Game {
27    pub fn new() -> Game {
28        Game::default()
29    }
30
31    /// The main entry point when playing the game.
32    ///
33    /// After loading the player profile and initializing the current
34    /// level, the game consists of repeatedly calling `play_turn`
35    /// on the player's `Player` instance.
36    pub fn play(player_generator: fn() -> Box<dyn Player + Send + Sync>) {
37        let mut game = Game::new();
38        game.start(player_generator);
39    }
40
41    fn start(&mut self, player_generator: fn() -> Box<dyn Player + Send + Sync>) {
42        let level;
43        if self.profile.maximus_oxidus {
44            println!("Now that you have earned the title Maximus Oxidus, you may choose to hone your skills on any level.");
45            level = ui::select_level();
46            starter::write_readme(&self.profile, level, None);
47            println!("See (updated) README.md for level {} instructions.", level);
48        } else {
49            level = self.profile.level;
50        }
51        println!("Starting Level {}", level);
52        let floor = Floor::load(level);
53        match engine::start(
54            self.profile.name.clone(),
55            self.profile.level,
56            floor,
57            player_generator,
58        ) {
59            Ok(_) => {
60                self.level_completed();
61            }
62            Err(err) => {
63                println!("{}", err);
64            }
65        }
66    }
67
68    fn level_completed(&mut self) {
69        // TODO: tally points
70        if self.profile.maximus_oxidus {
71            println!("Success! You have found the stairs.");
72        } else if Floor::exists(self.profile.level + 1) {
73            println!("Success! You have found the stairs.");
74            if env::var("NO_PROMPT").is_ok() {
75                return;
76            }
77            if ui::ask("Would you like to continue on to the next level?") {
78                self.profile.increment_level();
79                starter::write_readme(&self.profile, self.profile.level, None);
80                starter::write_profile(&self.profile, None);
81                println!("See (updated) README.md for your next instructions.");
82            } else {
83                // TODO: "Try to earn more points next time."
84                println!("Staying on current level.");
85            }
86        } else {
87            println!("CONGRATULATIONS! You have climbed to the top of the tower and have earned the title Maximus Oxidus.");
88            self.profile.maximus_oxidus = true;
89            starter::write_profile(&self.profile, None);
90        }
91    }
92}
93
94fn load_profile() -> Profile {
95    let contents = fs::read_to_string(".profile").expect("error loading .profile");
96    Profile::from_toml(&contents)
97}