diff --git a/src/gui.rs b/src/gui.rs index 6640b63..c098dd6 100644 --- a/src/gui.rs +++ b/src/gui.rs @@ -1,9 +1,21 @@ -use crate::{ - game_log::GameLog, CombatStats, InBackpack, Map, Name, Player, Position, State, Viewshed, -}; +use crate::components::{CombatStats, InBackpack, Name, Player, Position, Viewshed}; +use crate::{game_log::GameLog, Map, RunState, State}; use rltk::{Point, Rltk, VirtualKeyCode, RGB}; use specs::prelude::*; +#[derive(PartialEq, Copy, Clone)] +pub enum MainMenuSelection { + NewGame, + LoadGame, + Quit, +} + +#[derive(PartialEq, Copy, Clone)] +pub enum MainMenuResult { + NoSelection { selected: MainMenuSelection }, + Selected { selected: MainMenuSelection }, +} + pub fn draw_ui(ecs: &World, ctx: &mut Rltk) { ctx.draw_box( 0, @@ -395,3 +407,113 @@ pub fn ranged_target( (ItemMenuResult::NoResponse, None) } + +pub fn main_menu(gs: &mut State, ctx: &mut Rltk) -> MainMenuResult { + let runstate = gs.ecs.fetch::(); + + ctx.print_color_centered( + 15, + RGB::named(rltk::YELLOW), + RGB::named(rltk::BLACK), + "Rust Roguelike Tutorial", + ); + + if let RunState::MainMenu { + menu_selection: selection, + } = *runstate + { + if selection == MainMenuSelection::NewGame { + ctx.print_color_centered( + 24, + RGB::named(rltk::MAGENTA), + RGB::named(rltk::BLACK), + "Begin New Game", + ); + } else { + ctx.print_color_centered( + 24, + RGB::named(rltk::WHITE), + RGB::named(rltk::BLACK), + "Begin New Game", + ); + } + + if selection == MainMenuSelection::LoadGame { + ctx.print_color_centered( + 25, + RGB::named(rltk::MAGENTA), + RGB::named(rltk::BLACK), + "Load Game", + ); + } else { + ctx.print_color_centered( + 25, + RGB::named(rltk::WHITE), + RGB::named(rltk::BLACK), + "Load Game", + ); + } + + if selection == MainMenuSelection::Quit { + ctx.print_color_centered( + 26, + RGB::named(rltk::MAGENTA), + RGB::named(rltk::BLACK), + "Quit", + ); + } else { + ctx.print_color_centered(26, RGB::named(rltk::WHITE), RGB::named(rltk::BLACK), "Quit"); + } + + match ctx.key { + None => { + return MainMenuResult::NoSelection { + selected: selection, + } + } + Some(key) => match key { + VirtualKeyCode::Escape => { + return MainMenuResult::NoSelection { + selected: selection, + } + } + VirtualKeyCode::Up => { + let newselection; + match selection { + MainMenuSelection::NewGame => newselection = MainMenuSelection::Quit, + MainMenuSelection::LoadGame => newselection = MainMenuSelection::NewGame, + MainMenuSelection::Quit => newselection = MainMenuSelection::LoadGame, + } + return MainMenuResult::NoSelection { + selected: newselection, + }; + } + VirtualKeyCode::Down => { + let newselection; + match selection { + MainMenuSelection::NewGame => newselection = MainMenuSelection::LoadGame, + MainMenuSelection::LoadGame => newselection = MainMenuSelection::Quit, + MainMenuSelection::Quit => newselection = MainMenuSelection::NewGame, + } + return MainMenuResult::NoSelection { + selected: newselection, + }; + } + VirtualKeyCode::Return => { + return MainMenuResult::Selected { + selected: selection, + } + } + _ => { + return MainMenuResult::NoSelection { + selected: selection, + } + } + }, + } + } + + MainMenuResult::NoSelection { + selected: MainMenuSelection::NewGame, + } +} diff --git a/src/main.rs b/src/main.rs index 31e3cf2..abea450 100644 --- a/src/main.rs +++ b/src/main.rs @@ -48,7 +48,13 @@ pub enum RunState { MonsterTurn, ShowInventory, ShowDropItem, - ShowTargeting { range: i32, item: Entity }, + ShowTargeting { + range: i32, + item: Entity, + }, + MainMenu { + menu_selection: gui::MainMenuSelection, + }, } pub struct State { @@ -91,34 +97,39 @@ impl State { impl GameState for State { fn tick(&mut self, ctx: &mut Rltk) { - ctx.cls(); - - // Draw the UI - draw_map(&self.ecs, ctx); - { - let positions = self.ecs.read_storage::(); - let renderables = self.ecs.read_storage::(); - let map = self.ecs.fetch::(); - - let mut data: Vec<_> = (&positions, &renderables).join().collect(); - data.sort_by(|&a, &b| b.1.render_order.cmp(&a.1.render_order)); - for (pos, render) in data.iter() { - let idx = map.xy_idx(pos.x, pos.y); - - if map.visible_tiles[idx] { - ctx.set(pos.x, pos.y, render.fg, render.bg, render.glyph) - } - } - - gui::draw_ui(&self.ecs, ctx); - } - let mut newrunstate; { let runstate = self.ecs.fetch::(); newrunstate = *runstate; } + ctx.cls(); + + match newrunstate { + RunState::MainMenu { .. } => {} + _ => { + // Draw the UI + draw_map(&self.ecs, ctx); + { + let positions = self.ecs.read_storage::(); + let renderables = self.ecs.read_storage::(); + let map = self.ecs.fetch::(); + + let mut data: Vec<_> = (&positions, &renderables).join().collect(); + data.sort_by(|&a, &b| b.1.render_order.cmp(&a.1.render_order)); + for (pos, render) in data.iter() { + let idx = map.xy_idx(pos.x, pos.y); + + if map.visible_tiles[idx] { + ctx.set(pos.x, pos.y, render.fg, render.bg, render.glyph) + } + } + + gui::draw_ui(&self.ecs, ctx); + } + } + } + match newrunstate { RunState::PreRun => { self.run_systems(); @@ -212,6 +223,23 @@ impl GameState for State { } } } + RunState::MainMenu { .. } => { + let result = gui::main_menu(self, ctx); + match result { + gui::MainMenuResult::NoSelection { selected } => { + newrunstate = RunState::MainMenu { + menu_selection: selected, + } + } + gui::MainMenuResult::Selected { selected } => match selected { + gui::MainMenuSelection::NewGame => newrunstate = RunState::PreRun, + gui::MainMenuSelection::LoadGame => newrunstate = RunState::PreRun, + gui::MainMenuSelection::Quit => { + ::std::process::exit(0); + } + }, + } + } } {