From 20d5162cf83a3bbfe1236cc67bfc8455cc139d33 Mon Sep 17 00:00:00 2001
From: Luna <luna+github@sicardi.org>
Date: Sat, 2 Oct 2021 18:53:14 -0400
Subject: [PATCH 1/2] Co-authored-by: Evan Pratten <ewpratten@gmail.com>

---
 game/src/scenes/fsm_error_screen.rs   |   2 +-
 game/src/scenes/how_to_play_screen.rs | 170 ++++++++++++++++++
 game/src/scenes/ingame_scene/hud.rs   |   2 +-
 game/src/scenes/ingame_scene/world.rs |   2 +-
 game/src/scenes/loading_screen.rs     |   2 +-
 game/src/scenes/main_menu_screen.rs   | 248 +++++++++++++++++++++++++-
 game/src/scenes/mod.rs                |  12 +-
 game/src/scenes/options_screen.rs     | 171 ++++++++++++++++++
 game/src/utilities/render_layer.rs    |   4 +-
 9 files changed, 597 insertions(+), 16 deletions(-)
 create mode 100644 game/src/scenes/how_to_play_screen.rs
 create mode 100644 game/src/scenes/options_screen.rs

diff --git a/game/src/scenes/fsm_error_screen.rs b/game/src/scenes/fsm_error_screen.rs
index 7a57148..b6d1709 100644
--- a/game/src/scenes/fsm_error_screen.rs
+++ b/game/src/scenes/fsm_error_screen.rs
@@ -48,7 +48,7 @@ impl Action<Scenes, ScreenError, GameContext> for FsmErrorScreen {
 }
 
 impl ScreenSpaceRender for FsmErrorScreen {
-    fn render_screen_space(&self, raylib: &mut HackedRaylibHandle, config: &GameConfig) {
+    fn render_screen_space(&mut self, raylib: &mut HackedRaylibHandle, config: &GameConfig) {
         raylib.clear_background(Color::RED);
 
         // Render a warning message
diff --git a/game/src/scenes/how_to_play_screen.rs b/game/src/scenes/how_to_play_screen.rs
new file mode 100644
index 0000000..1537345
--- /dev/null
+++ b/game/src/scenes/how_to_play_screen.rs
@@ -0,0 +1,170 @@
+use std::ops::{Div, Sub};
+
+use chrono::{DateTime, Utc};
+use dirty_fsm::{Action, ActionFlag};
+use pkg_version::pkg_version_major;
+use raylib::prelude::*;
+
+use crate::{GameConfig, context::GameContext, utilities::{
+        datastore::{load_texture_from_internal_data, ResourceLoadError},
+        game_version::get_version_string,
+        math::interpolate_exp,
+        non_ref_raylib::HackedRaylibHandle,
+        render_layer::ScreenSpaceRender,
+    }};
+
+use super::{Scenes, ScreenError};
+use tracing::{debug, info, trace};
+
+#[derive(Debug)]
+pub struct HowToPlayScreen {
+    is_btm_pressed: bool //Is back to menu button pressed
+}
+
+impl HowToPlayScreen {
+    /// Construct a new `HowToPlayScreen`
+    pub fn new() -> Self {
+        Self {
+            is_btm_pressed: false
+        }
+    }
+}
+
+impl Action<Scenes, ScreenError, GameContext> for HowToPlayScreen {
+    fn on_register(&mut self) -> Result<(), ScreenError> {
+        debug!("Registered");
+        Ok(())
+    }
+
+    fn on_first_run(&mut self, _context: &GameContext) -> Result<(), ScreenError> {
+        debug!("Running HowToPlayScreen for the first time");
+
+        Ok(())
+    }
+
+    fn execute(
+        &mut self,
+        _delta: &chrono::Duration,
+        context: &GameContext,
+    ) -> Result<dirty_fsm::ActionFlag<Scenes>, ScreenError> {
+        trace!("execute() called on HowToPlayScreen");
+        self.render_screen_space(&mut context.renderer.borrow_mut(), &context.config);
+
+        if self.is_btm_pressed {
+            Ok(ActionFlag::SwitchState(Scenes::MainMenuScreen))
+        }
+        else{
+            Ok(ActionFlag::Continue)
+        }
+    }
+
+    fn on_finish(&mut self, _interrupted: bool) -> Result<(), ScreenError> {
+        debug!("Finished HowToPlayScreen");
+        self.is_btm_pressed = false;
+        Ok(())
+    }
+}
+
+impl ScreenSpaceRender for HowToPlayScreen {
+    fn render_screen_space(
+        &mut self,
+        raylib: &mut crate::utilities::non_ref_raylib::HackedRaylibHandle,
+        config: &GameConfig
+    ) {
+
+        // Render the background
+        raylib.clear_background(Color::BLACK);
+
+        let screen_size = raylib.get_screen_size();
+
+        //Mouse Position
+        let mouse_position: Vector2 = raylib.get_mouse_position();
+
+        let mouse_pressed: bool = raylib.is_mouse_button_pressed(MouseButton::MOUSE_LEFT_BUTTON);
+
+        raylib.draw_text(
+
+            "How to Play",
+            37,
+            80,
+            70,
+            Color::BLUE,
+        );
+
+        raylib.draw_text(
+
+            "How to Play",
+            43,
+            80,
+            70,
+            Color::RED,
+        );
+
+        raylib.draw_text(
+
+            "How to Play",
+            40,
+            80,
+            70,
+            Color::WHITE,
+        );
+
+        //Back to Menu
+        if Rectangle::new(35.0, screen_size.y as f32 - 80.0, 200.0, 40.0).check_collision_point_rec(mouse_position){
+            raylib.draw_text(
+
+                "BACK TO MENU",
+                28,
+                screen_size.y as i32 - 50,
+                25,
+                Color::RED,
+            );
+            raylib.draw_text(
+
+                "BACK TO MENU",
+                22,
+                screen_size.y as i32 - 50,
+                25,
+                Color::BLUE,
+            );
+            raylib.draw_text(
+
+                "BACK TO MENU",
+                25,
+                screen_size.y as i32 - 50,
+                25,
+                Color::WHITE,
+            );
+
+            if mouse_pressed{
+                self.is_btm_pressed = true;
+            }
+        }
+        else {
+            raylib.draw_text(
+
+                "BACK TO MENU",
+                26,
+                screen_size.y as i32 - 50,
+                25,
+                Color::RED,
+            );
+            raylib.draw_text(
+
+                "BACK TO MENU",
+                24,
+                screen_size.y as i32 - 50,
+                25,
+                Color::BLUE,
+            );
+            raylib.draw_text(
+
+                "BACK TO MENU",
+                25,
+                screen_size.y as i32 - 50,
+                25,
+                Color::WHITE,
+            );
+        }
+    }
+}
diff --git a/game/src/scenes/ingame_scene/hud.rs b/game/src/scenes/ingame_scene/hud.rs
index 44d3b3f..bdcd6bd 100644
--- a/game/src/scenes/ingame_scene/hud.rs
+++ b/game/src/scenes/ingame_scene/hud.rs
@@ -4,7 +4,7 @@ use super::InGameScreen;
 
 impl ScreenSpaceRender for InGameScreen {
     fn render_screen_space(
-        &self,
+        &mut self,
         raylib: &mut crate::utilities::non_ref_raylib::HackedRaylibHandle,
         config: &GameConfig
     ) {
diff --git a/game/src/scenes/ingame_scene/world.rs b/game/src/scenes/ingame_scene/world.rs
index 67e4ab5..75c6491 100644
--- a/game/src/scenes/ingame_scene/world.rs
+++ b/game/src/scenes/ingame_scene/world.rs
@@ -10,7 +10,7 @@ use raylib::prelude::*;
 
 impl WorldSpaceRender for InGameScreen {
     fn render_world_space(
-        &self,
+        &mut self,
         raylib: &mut RaylibMode2D<'_, HackedRaylibHandle>,
         config: &GameConfig,
     ) {
diff --git a/game/src/scenes/loading_screen.rs b/game/src/scenes/loading_screen.rs
index 0ccc70b..d5b56cc 100644
--- a/game/src/scenes/loading_screen.rs
+++ b/game/src/scenes/loading_screen.rs
@@ -102,7 +102,7 @@ impl Action<Scenes, ScreenError, GameContext> for LoadingScreen {
 
 impl ScreenSpaceRender for LoadingScreen {
     fn render_screen_space(
-        &self,
+        &mut self,
         raylib: &mut crate::utilities::non_ref_raylib::HackedRaylibHandle,
         config: &GameConfig
     ) {
diff --git a/game/src/scenes/main_menu_screen.rs b/game/src/scenes/main_menu_screen.rs
index cc0f68b..4c5168d 100644
--- a/game/src/scenes/main_menu_screen.rs
+++ b/game/src/scenes/main_menu_screen.rs
@@ -17,12 +17,22 @@ use super::{Scenes, ScreenError};
 use tracing::{debug, info, trace};
 
 #[derive(Debug)]
-pub struct MainMenuScreen {}
+pub struct MainMenuScreen {
+
+    is_start_pressed: bool, //Is start button pressed
+    is_htp_pressed: bool, //Is how to play button pressed
+    is_options_pressed: bool //Is options button pressed
+
+}
 
 impl MainMenuScreen {
     /// Construct a new `MainMenuScreen`
     pub fn new() -> Self {
-        Self {}
+        Self {
+            is_start_pressed: false,
+            is_htp_pressed: false,
+            is_options_pressed: false
+        }
     }
 }
 
@@ -46,23 +56,32 @@ impl Action<Scenes, ScreenError, GameContext> for MainMenuScreen {
         trace!("execute() called on MainMenuScreen");
         self.render_screen_space(&mut context.renderer.borrow_mut(), &context.config);
 
-        // TODO: TEMP
-        if context.renderer.borrow_mut().is_key_pressed(KeyboardKey::KEY_SPACE) {
+        if self.is_start_pressed {
             Ok(ActionFlag::SwitchState(Scenes::InGameScene))
-        } else {
+        }
+        else if self.is_htp_pressed {
+            Ok(ActionFlag::SwitchState(Scenes::HowToPlayScreen))
+        }
+        else if self.is_options_pressed {
+            Ok(ActionFlag::SwitchState(Scenes::OptionsScreen))
+        }
+        else {
             Ok(ActionFlag::Continue)
         }
     }
 
     fn on_finish(&mut self, _interrupted: bool) -> Result<(), ScreenError> {
         debug!("Finished MainMenuScreen");
+        self.is_start_pressed = false;
+        self.is_htp_pressed = false;
+        self.is_options_pressed = false;
         Ok(())
     }
 }
 
 impl ScreenSpaceRender for MainMenuScreen {
     fn render_screen_space(
-        &self,
+        &mut self,
         raylib: &mut crate::utilities::non_ref_raylib::HackedRaylibHandle,
         config: &GameConfig
     ) {
@@ -72,6 +91,11 @@ impl ScreenSpaceRender for MainMenuScreen {
         // Calculate the logo position
         let screen_size = raylib.get_screen_size();
 
+        //Mouse Position
+        let mouse_position: Vector2 = raylib.get_mouse_position();
+
+        let mouse_pressed: bool = raylib.is_mouse_button_pressed(MouseButton::MOUSE_LEFT_BUTTON);
+
         // Only in debug mode, render a debug message
         #[cfg(debug_assertions)]
         {
@@ -83,6 +107,16 @@ impl ScreenSpaceRender for MainMenuScreen {
                 Color::WHITE,
             );
         }
+
+        // Displays mouse position
+        raylib.draw_text(
+            &format!("[{}, {}]", mouse_position.x, mouse_position.y),
+            screen_size.x as i32 - 130,
+            screen_size.y as i32 - 30,
+            25,
+            Color::DARKGRAY,
+        );
+
         // Render the game version info
         raylib.draw_text(
             &format!(
@@ -95,5 +129,207 @@ impl ScreenSpaceRender for MainMenuScreen {
             15,
             Color::WHITE,
         );
+
+        raylib.draw_text(
+
+            &format!("[{}]", config.name),
+            37,
+            80,
+            70,
+            Color::BLUE,
+        );
+
+        raylib.draw_text(
+
+            &format!("[{}]", config.name),
+            43,
+            80,
+            70,
+            Color::RED,
+        );
+
+        raylib.draw_text(
+
+            &format!("[{}]", config.name),
+            40,
+            80,
+            70,
+            Color::WHITE,
+        );
+
+        // Start Game
+        if Rectangle::new(80.0, 300.0, 170.0, 20.0).check_collision_point_rec(mouse_position) {
+            raylib.draw_text(
+
+                "START GAME",
+                83,
+                300,
+                25,
+                Color::RED,
+            );
+            raylib.draw_text(
+
+                "START GAME",
+                77,
+                300,
+                25,
+                Color::BLUE,
+            );
+            raylib.draw_text(
+
+                "START GAME",
+                80,
+                300,
+                25,
+                Color::WHITE,
+            );
+
+            if mouse_pressed{
+                self.is_start_pressed = true;
+            }
+        }
+        else{
+            raylib.draw_text(
+
+                "START GAME",
+                81,
+                300,
+                25,
+                Color::RED,
+            );
+            raylib.draw_text(
+
+                "START GAME",
+                79,
+                300,
+                25,
+                Color::BLUE,
+            );
+            raylib.draw_text(
+
+                "START GAME",
+                80,
+                300,
+                25,
+                Color::WHITE,
+            );
+        }
+
+        // How to Play
+        if Rectangle::new(80.0, 350.0, 170.0, 20.0).check_collision_point_rec(mouse_position) {
+            raylib.draw_text(
+
+                "HOW TO PLAY",
+                83,
+                350,
+                25,
+                Color::RED,
+            );
+            raylib.draw_text(
+
+                "HOW TO PLAY",
+                77,
+                350,
+                25,
+                Color::BLUE,
+            );
+            raylib.draw_text(
+
+                "HOW TO PLAY",
+                80,
+                350,
+                25,
+                Color::WHITE,
+            );
+
+            if mouse_pressed{
+                self.is_htp_pressed = true;
+            }
+        }
+        else{
+            raylib.draw_text(
+
+                "HOW TO PLAY",
+                81,
+                350,
+                25,
+                Color::RED,
+            );
+            raylib.draw_text(
+
+                "HOW TO PLAY",
+                79,
+                350,
+                25,
+                Color::BLUE,
+            );
+            raylib.draw_text(
+
+                "HOW TO PLAY",
+                80,
+                350,
+                25,
+                Color::WHITE,
+            );
+        }
+
+        // OPTIONS
+        if Rectangle::new(80.0, 400.0, 135.0, 20.0).check_collision_point_rec(mouse_position) {
+            raylib.draw_text(
+
+                "OPTIONS",
+                83,
+                400,
+                25,
+                Color::RED,
+            );
+            raylib.draw_text(
+
+                "OPTIONS",
+                77,
+                400,
+                25,
+                Color::BLUE,
+            );
+            raylib.draw_text(
+
+                "OPTIONS",
+                80,
+                400,
+                25,
+                Color::WHITE,
+            );
+
+            if mouse_pressed{
+                self.is_options_pressed = true;
+            }
+
+        }
+        else{
+            raylib.draw_text(
+
+                "OPTIONS",
+                81,
+                400,
+                25,
+                Color::RED,
+            );
+            raylib.draw_text(
+
+                "OPTIONS",
+                79,
+                400,
+                25,
+                Color::BLUE,
+            );
+            raylib.draw_text(
+
+                "OPTIONS",
+                80,
+                400,
+                25,
+                Color::WHITE,
+            );
+        }
     }
 }
diff --git a/game/src/scenes/mod.rs b/game/src/scenes/mod.rs
index d9ec17b..b43e426 100644
--- a/game/src/scenes/mod.rs
+++ b/game/src/scenes/mod.rs
@@ -1,7 +1,4 @@
-use self::{
-    fsm_error_screen::FsmErrorScreen, ingame_scene::InGameScreen, loading_screen::LoadingScreen,
-    main_menu_screen::MainMenuScreen,
-};
+use self::{fsm_error_screen::FsmErrorScreen, options_screen::OptionsScreen, how_to_play_screen::HowToPlayScreen, ingame_scene::InGameScreen, loading_screen::LoadingScreen, main_menu_screen::MainMenuScreen};
 use crate::{
     context::GameContext,
     utilities::{
@@ -16,6 +13,8 @@ pub mod fsm_error_screen;
 pub mod ingame_scene;
 pub mod loading_screen;
 pub mod main_menu_screen;
+pub mod how_to_play_screen;
+pub mod options_screen;
 
 /// Defines all scenes
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Hash)]
@@ -25,6 +24,8 @@ pub enum Scenes {
     LoadingScreen,
     MainMenuScreen,
     InGameScene,
+    HowToPlayScreen,
+    OptionsScreen,
 }
 
 /// Contains any possible errors thrown while rendering
@@ -56,5 +57,8 @@ pub fn build_screen_state_machine(
     )?;
     machine.add_action(Scenes::MainMenuScreen, MainMenuScreen::new())?;
     machine.add_action(Scenes::InGameScene, InGameScreen::new(player_sprite_sheet))?;
+    machine.add_action(Scenes::HowToPlayScreen, HowToPlayScreen::new())?;
+    machine.add_action(Scenes::OptionsScreen, OptionsScreen::new())?;
     Ok(machine)
+
 }
diff --git a/game/src/scenes/options_screen.rs b/game/src/scenes/options_screen.rs
new file mode 100644
index 0000000..bf51602
--- /dev/null
+++ b/game/src/scenes/options_screen.rs
@@ -0,0 +1,171 @@
+use std::ops::{Div, Sub};
+
+use chrono::{DateTime, Utc};
+use dirty_fsm::{Action, ActionFlag};
+use pkg_version::pkg_version_major;
+use raylib::prelude::*;
+
+use crate::{GameConfig, context::GameContext, utilities::{
+        datastore::{load_texture_from_internal_data, ResourceLoadError},
+        game_version::get_version_string,
+        math::interpolate_exp,
+        non_ref_raylib::HackedRaylibHandle,
+        render_layer::ScreenSpaceRender,
+    }};
+
+use super::{Scenes, ScreenError};
+use tracing::{debug, info, trace};
+
+#[derive(Debug)]
+pub struct OptionsScreen {
+    is_btm_pressed: bool //Is back to menu button pressed
+}
+
+impl OptionsScreen {
+    /// Construct a new `OptionsScreen`
+    pub fn new() -> Self {
+        Self {
+            is_btm_pressed: false
+        }
+    }
+}
+
+impl Action<Scenes, ScreenError, GameContext> for OptionsScreen {
+    fn on_register(&mut self) -> Result<(), ScreenError> {
+        debug!("Registered");
+        Ok(())
+    }
+
+    fn on_first_run(&mut self, _context: &GameContext) -> Result<(), ScreenError> {
+        debug!("Running OptionsScreen for the first time");
+
+        Ok(())
+    }
+
+    fn execute(
+        &mut self,
+        _delta: &chrono::Duration,
+        context: &GameContext,
+    ) -> Result<dirty_fsm::ActionFlag<Scenes>, ScreenError> {
+        trace!("execute() called on OptionsScreen");
+        self.render_screen_space(&mut context.renderer.borrow_mut(), &context.config);
+
+        if self.is_btm_pressed {
+            Ok(ActionFlag::SwitchState(Scenes::MainMenuScreen))
+        }
+        else{
+            Ok(ActionFlag::Continue)
+        }
+    }
+
+    fn on_finish(&mut self, _interrupted: bool) -> Result<(), ScreenError> {
+        debug!("Finished OptionsScreen");
+        self.is_btm_pressed = false;
+        Ok(())
+    }
+}
+
+impl ScreenSpaceRender for OptionsScreen {
+    fn render_screen_space(
+        &mut self,
+        raylib: &mut crate::utilities::non_ref_raylib::HackedRaylibHandle,
+        config: &GameConfig
+    ) {
+
+        // Render the background
+        raylib.clear_background(Color::BLACK);
+
+        let screen_size = raylib.get_screen_size();
+
+        //Mouse Position
+        let mouse_position: Vector2 = raylib.get_mouse_position();
+
+        let mouse_pressed: bool = raylib.is_mouse_button_pressed(MouseButton::MOUSE_LEFT_BUTTON);
+
+        raylib.draw_text(
+
+            "Options",
+            37,
+            80,
+            70,
+            Color::BLUE,
+        );
+
+        raylib.draw_text(
+
+            "Options",
+            43,
+            80,
+            70,
+            Color::RED,
+        );
+
+        raylib.draw_text(
+
+            "Options",
+            40,
+            80,
+            70,
+            Color::WHITE,
+        );
+
+        //Back to Menu
+        if Rectangle::new(35.0, screen_size.y as f32 - 80.0, 200.0, 40.0).check_collision_point_rec(mouse_position){
+            raylib.draw_text(
+
+                "BACK TO MENU",
+                28,
+                screen_size.y as i32 - 50,
+                25,
+                Color::RED,
+            );
+            raylib.draw_text(
+
+                "BACK TO MENU",
+                22,
+                screen_size.y as i32 - 50,
+                25,
+                Color::BLUE,
+            );
+            raylib.draw_text(
+
+                "BACK TO MENU",
+                25,
+                screen_size.y as i32 - 50,
+                25,
+                Color::WHITE,
+            );
+
+            if mouse_pressed{
+                self.is_btm_pressed = true;
+
+            }
+        }
+        else {
+            raylib.draw_text(
+
+                "BACK TO MENU",
+                26,
+                screen_size.y as i32 - 50,
+                25,
+                Color::RED,
+            );
+            raylib.draw_text(
+
+                "BACK TO MENU",
+                24,
+                screen_size.y as i32 - 50,
+                25,
+                Color::BLUE,
+            );
+            raylib.draw_text(
+
+                "BACK TO MENU",
+                25,
+                screen_size.y as i32 - 50,
+                25,
+                Color::WHITE,
+            );
+        }
+    }
+}
diff --git a/game/src/utilities/render_layer.rs b/game/src/utilities/render_layer.rs
index 8b5710e..9de55ab 100644
--- a/game/src/utilities/render_layer.rs
+++ b/game/src/utilities/render_layer.rs
@@ -7,9 +7,9 @@ pub trait FrameUpdate {
 }
 
 pub trait ScreenSpaceRender {
-    fn render_screen_space(&self, raylib: &mut HackedRaylibHandle, config: &GameConfig);
+    fn render_screen_space(&mut self, raylib: &mut HackedRaylibHandle, config: &GameConfig);
 }
 
 pub trait WorldSpaceRender {
-    fn render_world_space(&self, raylib: &mut RaylibMode2D<'_, HackedRaylibHandle>, config: &GameConfig);
+    fn render_world_space(&mut self, raylib: &mut RaylibMode2D<'_, HackedRaylibHandle>, config: &GameConfig);
 }

From 42ff4cd7e3341a71905fa5d8189acef55b9bdcec Mon Sep 17 00:00:00 2001
From: Evan Pratten <ewpratten@gmail.com>
Date: Sat, 2 Oct 2021 18:58:13 -0400
Subject: [PATCH 2/2] Fix mutability error

---
 game/src/scenes/pause_screen.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/game/src/scenes/pause_screen.rs b/game/src/scenes/pause_screen.rs
index a496c5a..04c0bac 100644
--- a/game/src/scenes/pause_screen.rs
+++ b/game/src/scenes/pause_screen.rs
@@ -100,7 +100,7 @@ impl Action<Scenes, ScreenError, GameContext> for PauseScreen {
 
 impl ScreenSpaceRender for PauseScreen {
     fn render_screen_space(
-        &self,
+        &mut self,
         raylib: &mut crate::utilities::non_ref_raylib::HackedRaylibHandle,
         config: &GameConfig,
     ) {