# pragma region License
/*
License ( OLC - 3 )
~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
Copyright 2024 Joshua Sigona < sigonasr2 @ gmail . com >
Redistribution and use in source and binary forms , with or without modification ,
are permitted provided that the following conditions are met :
1. Redistributions or derivations of source code must retain the above copyright
notice , this list of conditions and the following disclaimer .
2. Redistributions or derivative works in binary form must reproduce the above
copyright notice . This list of conditions and the following disclaimer must be
reproduced in the documentation and / or other materials provided with the distribution .
3. Neither the name of the copyright holder nor the names of its contributors may
be used to endorse or promote products derived from this software without specific
prior written permission .
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS IS " AND ANY
EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT
SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT ,
INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT LIMITED
TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR
BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN
CONTRACT , STRICT LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE .
Portions of this software are copyright © 2024 The FreeType
Project ( www . freetype . org ) . Please see LICENSE_FT . txt for more information .
All rights reserved .
*/
# pragma endregion
# include "AdventuresInLestoria.h"
# include "Menu.h"
# include "MenuComponent.h"
# include "SoundEffect.h"
# include "DEFINES.h"
# include "olcUTIL_DataFile.h"
# include "Unlock.h"
# include "State_OverworldMap.h"
# include "MenuLabel.h"
# include "Slider.h"
# include "Checkbox.h"
# include "InputDisplayComponent.h"
# include "GameSettings.h"
# include "MenuIconButton.h"
# include "ScrollableWindowComponent.h"
INCLUDE_DATA
INCLUDE_game
INCLUDE_WINDOW_SIZE
using A = Attribute ;
# define UNLOCK_ALL_BUTTON
# undef UNLOCK_ALL_BUTTON //Comment out to enable unlock all button.
void Menu : : InitializeSettingsWindow ( ) {
vf2d windowSize = WINDOW_SIZE - vf2d { 28 , 28 } ;
Menu * settingsWindow = CreateMenu ( SETTINGS , CENTERED , windowSize ) ;
# pragma region Unlock All Button
# ifdef UNLOCK_ALL_BUTTON
settingsWindow - > ADD ( " Unlock All Button " , MenuComponent ) ( geom2d : : rect < float > { { 4 , windowSize . y - 20 } , { 72 , 12 } } , " Unlock All " , [ ] ( MenuFuncData data ) {
if ( Menu : : IsCurrentlyActive ( SETTINGS ) ) {
for ( auto & cp : State_OverworldMap : : connections ) {
Unlock : : UnlockArea ( cp . map ) ;
}
SoundEffect : : PlaySFX ( " Buy Item " , SoundEffect : : CENTERED ) ;
}
return true ;
} ) END ;
# endif
# pragma endregion
settingsWindow - > ADD ( " Settings Label " , MenuLabel ) ( geom2d : : rect < float > { { 4 , 4 } , vf2d { windowSize . x - 8 , 24 } } , " Game Settings " , 2.f , ComponentAttr : : BACKGROUND | ComponentAttr : : OUTLINE | ComponentAttr : : SHADOW ) END ;
settingsWindow - > F ( A : : LAST_BGM_VOLUME ) = 1.f ;
settingsWindow - > F ( A : : LAST_SFX_VOLUME ) = 1.f ;
//windowsize.y-20
auto settingsList = settingsWindow - > ADD ( " Settings Scroll List " , ScrollableWindowComponent ) ( geom2d : : rect < float > { { 4 , 32 } , { windowSize . x - 8 , windowSize . y - 56 } } ) END ;
settingsList - > ADD ( " BGM Slider " , Slider ) ( geom2d : : rect < float > { vf2d { windowSize . x / 2 - 64 , 0 } , { 172 , 16 } } , " BGM Volume: " , Audio : : GetBGMVolume ( ) , [ ] ( float val ) {
if ( Menu : : IsCurrentlyActive ( SETTINGS ) ) {
if ( abs ( Menu : : menus [ SETTINGS ] - > F ( A : : LAST_BGM_VOLUME ) - val ) > = 0.04f ) {
SoundEffect : : PlaySFX ( " Change Volume " , SoundEffect : : CENTERED ) ;
Menu : : menus [ SETTINGS ] - > F ( A : : LAST_BGM_VOLUME ) = val ;
}
Audio : : SetBGMVolume ( val ) ;
}
} ) END ;
settingsList - > ADD ( " SFX Slider " , Slider ) ( geom2d : : rect < float > { vf2d { windowSize . x / 2 - 64 , 20 } , { 172 , 16 } } , " SFX Volume: " , Audio : : GetSFXVolume ( ) , [ ] ( float val ) {
if ( Menu : : IsCurrentlyActive ( SETTINGS ) ) {
if ( abs ( Menu : : menus [ SETTINGS ] - > F ( A : : LAST_SFX_VOLUME ) - val ) > = 0.04f ) {
SoundEffect : : PlaySFX ( " Change Volume " , SoundEffect : : CENTERED ) ;
Menu : : menus [ SETTINGS ] - > F ( A : : LAST_SFX_VOLUME ) = val ;
}
}
} ) END ;
settingsList - > ADD ( " Show Max HP Checkbox " , Checkbox ) ( geom2d : : rect < float > { { 4.f , 40 } , { 16.f , 16.f } } , [ ] ( ToggleFuncData data ) {
GameSettings : : SetMaxHealthDisplay ( data . checked ) ;
return true ;
} , false ) END ;
settingsList - > ADD ( " Show Max HP Label " , MenuLabel ) ( geom2d : : rect < float > { { 22.f , 40 } , { windowSize . x / 2 - 24.f , 16.f } } , " Show Max Health " , 1.f , ComponentAttr : : SHADOW | ComponentAttr : : LEFT_ALIGN ) END ;
settingsList - > ADD ( " Show Max Mana Checkbox " , Checkbox ) ( geom2d : : rect < float > { { windowSize . x / 2 + 4.f , 40 } , { 16.f , 16.f } } , [ ] ( ToggleFuncData data ) {
GameSettings : : SetMaxManaDisplay ( data . checked ) ;
return true ;
} , false ) END ;
settingsList - > ADD ( " Show Max Mana Label " , MenuLabel ) ( geom2d : : rect < float > { { windowSize . x / 2 + 22.f , 40 } , { windowSize . x / 2 - 24.f , 16.f } } , " Show Max Mana " , 1.f , ComponentAttr : : SHADOW | ComponentAttr : : LEFT_ALIGN ) END ;
settingsList - > ADD ( " Screen Shake Checkbox " , Checkbox ) ( geom2d : : rect < float > { { 4.f , 60 } , { 16.f , 16.f } } , [ ] ( ToggleFuncData data ) {
GameSettings : : SetScreenShake ( data . checked ) ;
return true ;
} , true ) END ;
settingsList - > ADD ( " Screen Shake Label " , MenuLabel ) ( geom2d : : rect < float > { { 22.f , 60 } , { windowSize . x / 2 - 24.f , 16.f } } , " Screen Shake " , 1.f , ComponentAttr : : SHADOW | ComponentAttr : : LEFT_ALIGN ) END ;
settingsList - > ADD ( " Controller Rumble Checkbox " , Checkbox ) ( geom2d : : rect < float > { { 4.f , 80 } , { 16.f , 16.f } } , [ ] ( ToggleFuncData data ) {
if ( Menu : : IsCurrentlyActive ( SETTINGS ) ) {
GameSettings : : SetRumble ( data . checked ) ;
if ( GameSettings : : RumbleEnabled ( GameSettings : : OVERRIDE ) ) {
Input : : StartVibration ( GameSettings : : OVERRIDE ) ;
data . component . lock ( ) - > F ( A : : RUMBLE_TIMER ) = 0.3f ;
} else {
Input : : StopVibration ( ) ;
}
}
return true ;
} , true ) END ;
settingsList - > ADD ( " Controller Rumble Label " , MenuLabel ) ( geom2d : : rect < float > { { 22.f , 80 } , { windowSize . x / 2 - 24.f , 16.f } } , " Gamepad Rumble " , 1.f , ComponentAttr : : SHADOW | ComponentAttr : : LEFT_ALIGN ) END ;
settingsList - > ADD ( " Terrain Collision Boxes Checkbox " , Checkbox ) ( geom2d : : rect < float > { { windowSize . x / 2 + 4.f , 60 } , { 16.f , 16.f } } , [ ] ( ToggleFuncData data ) {
GameSettings : : SetTerrainCollisionBoxes ( data . checked ) ;
return true ;
} , true ) END ;
settingsList - > ADD ( " Terrain Collision Boxes Label " , MenuLabel ) ( geom2d : : rect < float > { { windowSize . x / 2 + 22.f , 60 } , { windowSize . x / 2 - 36.f , 16.f } } , " Terrain Collision Boxes " , 1.f , ComponentAttr : : SHADOW | ComponentAttr : : LEFT_ALIGN ) END ;
settingsList - > ADD ( " Keyboard Play Auto-Aim Checkbox " , Checkbox ) ( geom2d : : rect < float > { { windowSize . x / 2 + 4.f , 80 } , { 16.f , 16.f } } , [ ] ( ToggleFuncData data ) {
GameSettings : : SetKeyboardAutoAim ( data . checked ) ;
return true ;
} , false ) END ;
settingsList - > ADD ( " Keyboard Play Auto-Aim Label " , MenuLabel ) ( geom2d : : rect < float > { { windowSize . x / 2 + 22.f , 80 } , { windowSize . x / 2 - 36.f , 16.f } } , " Aim Assist \n (No Mouse Players) " , 1.f , ComponentAttr : : SHADOW | ComponentAttr : : LEFT_ALIGN ) END ;
auto fullscreenToggle = settingsList - > ADD ( " Fullscreen Toggle Checkbox " , Checkbox ) ( geom2d : : rect < float > { { windowSize . x / 2 + 4.f , 100 } , { 16.f , 16.f } } , [ ] ( ToggleFuncData data ) {
if ( data . checked ) { //When going to fullscreen mode, the windowed mode positioning needs to be saved to be restored later.
GameSettings : : SetWindowPos ( game - > GetActualWindowPos ( ) ) ;
}
if ( ! Menu : : UsingMouseNavigation ( ) ) { //This prevents the fullscreen toggle from losing focus upon a window resize.
Menu : : IgnoreNextMouseNavigationAttempt ( ) ;
}
game - > SetFullscreen ( data . checked , GameSettings : : GetWindowPos ( ) ) ;
return true ;
} , game - > IsFullscreen ( ) ) END ;
auto fullscreenToggleLabel = settingsList - > ADD ( " Fullscreen Toggle Label " , MenuLabel ) ( geom2d : : rect < float > { { windowSize . x / 2 + 22.f , 100 } , { windowSize . x / 2 - 36.f , 16.f } } , " Fullscreen " , 1.f , ComponentAttr : : SHADOW | ComponentAttr : : LEFT_ALIGN ) END ;
# ifdef __EMSCRIPTEN__
fullscreenToggle - > Disable ( ) ;
fullscreenToggleLabel - > Disable ( ) ;
# endif
settingsList - > ADD ( " Button Set Toggle Box " , MenuIconButton ) ( geom2d : : rect < float > { { windowSize . x / 8.f , 100 } , { windowSize . x / 4.f , 16.f } } , GFX [ " themes/xb.png " ] . Decal ( ) , [ ] ( MenuFuncData data ) {
switch ( GameSettings : : GetIconType ( ) ) {
case IconType : : XB : {
GameSettings : : SetIconType ( IconType : : PS ) ;
DYNAMIC_POINTER_CAST < MenuIconButton > ( data . component ) - > SetIcon ( GFX [ " themes/ps.png " ] . Decal ( ) ) ;
} break ;
case IconType : : PS : {
GameSettings : : SetIconType ( IconType : : XB_REVERSED ) ;
DYNAMIC_POINTER_CAST < MenuIconButton > ( data . component ) - > SetIcon ( GFX [ " themes/xb_reversed.png " ] . Decal ( ) ) ;
} break ;
case IconType : : XB_REVERSED : {
GameSettings : : SetIconType ( IconType : : XB ) ;
DYNAMIC_POINTER_CAST < MenuIconButton > ( data . component ) - > SetIcon ( GFX [ " themes/xb.png " ] . Decal ( ) ) ;
} break ;
default : {
ERR ( std : : format ( " WARNING! Unhandled icon type {}! " , int ( GameSettings : : GetIconType ( ) ) ) ) ;
}
}
if ( Menu : : IsCurrentlyActive ( data . menu . GetType ( ) ) ) {
SoundEffect : : PlaySFX ( " Button Click " , SoundEffect : : CENTERED ) ;
}
return true ;
} ) END ;
# pragma region Setup all input displays as keyboard controls.
//NOTE: We are shadowing code from InputKeyboardWindow! If at some point the retrival method for getting input displays changes, we likely will be changing the code here as well!
auto ChangeKeybindDisplayType = [ & ] ( InputType inputType ) {
const int menuRowCount = DATA . GetProperty ( " Inputs.Menu Input Names " ) . GetValueCount ( ) % 2 = = 0 ? DATA . GetProperty ( " Inputs.Menu Input Names " ) . GetValueCount ( ) / 2 : DATA . GetProperty ( " Inputs.Menu Input Names " ) . GetValueCount ( ) / 2 + 1 ;
const int menuColCount = 2 ;
for ( int row = 0 ; row < menuRowCount ; row + + ) {
for ( int col = 0 ; col < menuColCount ; col + + ) {
if ( DATA . GetProperty ( " Inputs.Menu Input Names " ) . GetValueCount ( ) % 2 = = 1 & & col = = 1 & & row = = menuRowCount - 1 ) continue ; //We only continue on a blank space when we have an odd number of elements.
Component < InputDisplayComponent > ( INPUT_KEY_DISPLAY , std : : format ( " Input_{}_{} Input Displayer " , row , col ) ) - > SetKeyType ( inputType ) ;
}
}
const int ingameControlsRowCount = DATA . GetProperty ( " Inputs.Gameplay Input Names " ) . GetValueCount ( ) % 2 = = 0 ? DATA . GetProperty ( " Inputs.Gameplay Input Names " ) . GetValueCount ( ) / 2 : DATA . GetProperty ( " Inputs.Gameplay Input Names " ) . GetValueCount ( ) / 2 + 1 ;
const int ingameControlsColCount = 2 ;
for ( int row = 0 ; row < ingameControlsRowCount ; row + + ) {
for ( int col = 0 ; col < ingameControlsColCount ; col + + ) {
if ( DATA . GetProperty ( " Inputs.Gameplay Input Names " ) . GetValueCount ( ) % 2 = = 1 & & col = = 1 & & row = = ingameControlsRowCount - 1 ) continue ; //We only continue on a blank space when we have an odd number of elements.
Component < InputDisplayComponent > ( INPUT_KEY_DISPLAY , std : : format ( " Input_{}_{} Gameplay Input Displayer " , row , col ) ) - > SetKeyType ( inputType ) ;
}
}
} ;
# pragma endregion
settingsList - > ADD ( " Keyboard Bindings Button " , MenuComponent ) ( geom2d : : rect < float > { { 28 , 120.f } , vf2d { settingsList - > rect . size . x - 12 - 56 , 24 } } , " Keyboard Bindings " , [ & ] ( MenuFuncData data ) {
ChangeKeybindDisplayType ( KEY ) ;
Component < MenuLabel > ( INPUT_KEY_DISPLAY , " Keyboard Mapping Label " ) - > SetLabel ( " Keyboard Mappings " ) ;
Menu : : OpenMenu ( INPUT_KEY_DISPLAY ) ;
return true ;
} , vf2d { 1.5f , 2.f } ) END ;
settingsList - > ADD ( " Controller Bindings Button " , MenuComponent ) ( geom2d : : rect < float > { { 28 , 148.f } , vf2d { settingsList - > rect . size . x - 12 - 56 , 24 } } , " Controller Bindings " , [ & ] ( MenuFuncData data ) {
ChangeKeybindDisplayType ( CONTROLLER ) ;
Component < MenuLabel > ( INPUT_KEY_DISPLAY , " Keyboard Mapping Label " ) - > SetLabel ( " Controller Mappings " ) ;
Menu : : OpenMenu ( INPUT_KEY_DISPLAY ) ;
return true ;
} , vf2d { 1.5f , 2.f } ) END ;
settingsWindow - > ADD ( " Go Back " , MenuComponent ) ( geom2d : : rect < float > { vf2d { windowSize . x / 2.f , windowSize . y - 12 } - vf2d { 36 , 8 } , { 72 , 12 } } , " Go Back " , [ ] ( MenuFuncData data ) {
Menu : : CloseMenu ( ) ;
return true ;
} ) END ;
settingsWindow - > SetupKeyboardNavigation (
[ ] ( MenuType type , Data & returnData ) { //On Open
returnData = " BGM Slider " ;
} ,
{ //Button Key
{ game - > KEY_SCROLL , { " Navigate " , [ ] ( MenuType type ) { } } } ,
{ game - > KEY_BACK , { " Back " , [ ] ( MenuType type ) {
Menu : : CloseMenu ( ) ;
} } } ,
{ game - > KEY_CONFIRM , { " Select " , [ ] ( MenuType type ) { } } } ,
}
, { //Button Navigation Rules
{ " BGM Slider " , {
. up = " Go Back " ,
. down = " SFX Slider " , } } ,
{ " SFX Slider " , {
. up = " BGM Slider " ,
. down = " Show Max Mana Checkbox " , } } ,
{ " Show Max HP Checkbox " , {
. up = " SFX Slider " ,
. down = " Screen Shake Checkbox " ,
. left = " Show Max Mana Checkbox " ,
. right = " Show Max Mana Checkbox " , } } ,
{ " Show Max Mana Checkbox " , {
. up = " SFX Slider " ,
. down = " Terrain Collision Boxes Checkbox " ,
. left = " Show Max HP Checkbox " ,
. right = " Show Max HP Checkbox " , } } ,
{ " Terrain Collision Boxes Checkbox " , {
. up = " Show Max Mana Checkbox " ,
. down = " Keyboard Play Auto-Aim Checkbox " ,
. left = " Screen Shake Checkbox " ,
. right = " Screen Shake Checkbox " , } } ,
{ " Keyboard Play Auto-Aim Checkbox " , {
. up = " Terrain Collision Boxes Checkbox " ,
. down = " Fullscreen Toggle Checkbox " ,
. left = " Controller Rumble Checkbox " ,
. right = " Controller Rumble Checkbox " , } } ,
{ " Screen Shake Checkbox " , {
. up = " Show Max HP Checkbox " ,
. down = " Controller Rumble Checkbox " ,
. left = " Terrain Collision Boxes Checkbox " ,
. right = " Terrain Collision Boxes Checkbox " , } } ,
{ " Controller Rumble Checkbox " , {
. up = " Screen Shake Checkbox " ,
. down = " Button Set Toggle Box " ,
. left = " Keyboard Play Auto-Aim Checkbox " ,
. right = " Keyboard Play Auto-Aim Checkbox " , } } ,
{ " Button Set Toggle Box " , {
. up = " Controller Rumble Checkbox " ,
. down = " Keyboard Bindings Button " ,
. left = " Fullscreen Toggle Checkbox " ,
. right = " Fullscreen Toggle Checkbox " , } } ,
{ " Fullscreen Toggle Checkbox " , {
. up = " Keyboard Play Auto-Aim Checkbox " ,
. down = " Keyboard Bindings Button " ,
. left = " Button Set Toggle Box " ,
. right = " Button Set Toggle Box " , } } ,
{ " Keyboard Bindings Button " , {
# ifdef __EMSCRIPTEN__
. up = " Button Set Toggle Box " ,
# else
. up = " Fullscreen Toggle Checkbox " ,
# endif
. down = " Controller Bindings Button " , } } ,
{ " Controller Bindings Button " , {
. up = " Keyboard Bindings Button " ,
. down = " Go Back " , } } ,
{ " Go Back " , {
. up = " Controller Bindings Button " ,
. down = " BGM Slider " , } } ,
} ) ;
}