diff --git a/Adventures in Lestoria/Audio.cpp b/Adventures in Lestoria/Audio.cpp index a8b76f16..ef5e0fee 100644 --- a/Adventures in Lestoria/Audio.cpp +++ b/Adventures in Lestoria/Audio.cpp @@ -43,7 +43,9 @@ All rights reserved. INCLUDE_game INCLUDE_DATA -float Audio::defaultFadeTime; +float Audio::defaultFadeTime=0.f; +float Audio::sfxVol=1.f; +float Audio::bgmVol=1.f; void Audio::Initialize(){ Engine().SetBackgroundPlay(true); @@ -265,7 +267,7 @@ void Audio::Update(){ float channelVol=track.GetVolume(Self().currentAudioEvent,channelListIndex); Self().prevVolumes.push_back(channelVol); Self().targetVolumes.push_back(channelVol); - Engine().SetVolume(trackID,channelVol); + Engine().SetVolume(trackID,channelVol*GetBGMVolume()); Engine().Play(trackID,Self().playParams.loop); channelListIndex++; } @@ -277,7 +279,7 @@ void Audio::Update(){ Self().fadeToTargetVolumeTime=std::max(0.f,Self().fadeToTargetVolumeTime-game->GetElapsedTime()); for(int counter=0;float&vol:Self().prevVolumes){ const BGM¤tBgm=Self().bgm[Self().currentBGM]; - Engine().SetVolume(currentBgm.GetChannelIDs()[counter],util::lerp(vol,Self().targetVolumes[counter],1-(Self().fadeToTargetVolumeTime/currentBgm.GetFadeTime()))); + Engine().SetVolume(currentBgm.GetChannelIDs()[counter],util::lerp(vol,Self().targetVolumes[counter],1-(Self().fadeToTargetVolumeTime/currentBgm.GetFadeTime()))*GetBGMVolume()); counter++; } } @@ -289,4 +291,22 @@ const bool Audio::BGMFullyLoaded(){ const float&Audio::BGM::GetFadeTime()const{ return fadeTime; +} + +void Audio::SetBGMVolume(float vol){ + bgmVol=vol; + BGM&track=Self().bgm[Self().playParams.sound]; + for(int channelListIndex=0;int trackID:track.GetChannelIDs()){ + float channelVol=track.GetVolume(Self().currentAudioEvent,channelListIndex); + Engine().SetVolume(trackID,channelVol*GetBGMVolume()); + } +} +void Audio::SetSFXVolume(float vol){ + sfxVol=vol; +} +float&Audio::GetBGMVolume(){ + return bgmVol; +} +float&Audio::GetSFXVolume(){ + return sfxVol; } \ No newline at end of file diff --git a/Adventures in Lestoria/Audio.h b/Adventures in Lestoria/Audio.h index 4a80dcf9..df885661 100644 --- a/Adventures in Lestoria/Audio.h +++ b/Adventures in Lestoria/Audio.h @@ -67,6 +67,10 @@ public: static void SetAudioEvent(const Event&eventName); static const bool BGMIsPlaying(); static const bool BGMFullyLoaded(); //Fully loaded means when the audio buffer has finished filling up, which means sound is now playing. + static void SetBGMVolume(float vol); + static void SetSFXVolume(float vol); + static float&GetBGMVolume(); + static float&GetSFXVolume(); private: struct BGMPlayParams{ std::string sound; @@ -79,6 +83,8 @@ private: private: std::mapeventInfo; }; + static float bgmVol; + static float sfxVol; class BGM{ public: void Load(); diff --git a/Adventures in Lestoria/MonsterAttribute.h b/Adventures in Lestoria/MonsterAttribute.h index f5fbe459..2e018792 100644 --- a/Adventures in Lestoria/MonsterAttribute.h +++ b/Adventures in Lestoria/MonsterAttribute.h @@ -93,4 +93,6 @@ enum class Attribute{ BEAR_STOMP_COUNT, PREVIOUS_PHASE, COLLIDED_WITH_PLAYER, //A boolean flag that is set to true when an enemy makes contact with the player. + LAST_BGM_VOLUME, + LAST_SFX_VOLUME, }; \ No newline at end of file diff --git a/Adventures in Lestoria/SettingsWindow.cpp b/Adventures in Lestoria/SettingsWindow.cpp index ed61d28e..5b32e110 100644 --- a/Adventures in Lestoria/SettingsWindow.cpp +++ b/Adventures in Lestoria/SettingsWindow.cpp @@ -44,23 +44,59 @@ All rights reserved. #include "olcUTIL_DataFile.h" #include "Unlock.h" #include "State_OverworldMap.h" +#include "MenuLabel.h" +#include "Slider.h" +#include "Checkbox.h" INCLUDE_DATA INCLUDE_game INCLUDE_WINDOW_SIZE +using A=Attribute; + void Menu::InitializeSettingsWindow(){ vf2d windowSize=WINDOW_SIZE-vf2d{28,28}; Menu*settingsWindow=CreateMenu(SETTINGS,CENTERED,windowSize); - settingsWindow->ADD("Unlock All Button",MenuComponent)(geom2d::rect{{4,4},{72,12}},"Unlock All",[](MenuFuncData data){ + settingsWindow->ADD("Unlock All Button",MenuComponent)(geom2d::rect{{4,windowSize.y-12},{72,12}},"Unlock All",[](MenuFuncData data){ for(auto&cp:State_OverworldMap::connections){ Unlock::UnlockArea(cp.map); } SoundEffect::PlaySFX("Buy Item",SoundEffect::CENTERED); return true; })END; - settingsWindow->ADD("Go Back",MenuComponent)(geom2d::rect{windowSize/2-vf2d{36,16},{72,12}},"Go Back",[](MenuFuncData data){ + + settingsWindow->ADD("Settings Label",MenuLabel)(geom2d::rect{{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; + + settingsWindow->ADD("BGM Slider",Slider)(geom2d::rect{vf2d{windowSize.x/2-64,44},{172,16}},"BGM Volume:",Audio::GetBGMVolume(),[](float val){ + 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; + settingsWindow->ADD("SFX Slider",Slider)(geom2d::rect{vf2d{windowSize.x/2-64,64},{172,16}},"SFX Volume:",Audio::GetSFXVolume(),[](float val){ + 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; + settingsWindow->ADD("Terrain Collision Boxes Checkbox",Checkbox)(geom2d::rect{{windowSize.x/2-88.f,84},{16.f,16.f}},[](ToggleFuncData data){ + return true; + },true)END; + settingsWindow->ADD("Terrain Collision Boxes Label",MenuLabel)(geom2d::rect{{windowSize.x/2-68.f,84},{windowSize.x/2+54.f,16.f}},"Terrain Collision Boxes",1.f,ComponentAttr::SHADOW)END; + settingsWindow->ADD("Keyboard Play Auto-Aim Checkbox",Checkbox)(geom2d::rect{{windowSize.x/2-88.f,104},{16.f,16.f}},[](ToggleFuncData data){ + return true; + },false)END; + settingsWindow->ADD("Keyboard Play Auto-Aim Label",MenuLabel)(geom2d::rect{{windowSize.x/2-68.f,104},{windowSize.x/2+54.f,16.f}},"Keyboard Aim Assist\n (For Keyboard Only Players)",1.f,ComponentAttr::SHADOW)END; + + settingsWindow->ADD("Keyboard Bindings Label",MenuComponent)(geom2d::rect{{28,132.f},vf2d{windowSize.x-32,24}},"Keyboard Bindings",MenuType::ENUM_END,DO_NOTHING,vf2d{1.5f,2.f})END; + settingsWindow->ADD("Controller Bindings Label",MenuComponent)(geom2d::rect{{28,160.f},vf2d{windowSize.x-32,24}},"Controller Bindings",MenuType::ENUM_END,DO_NOTHING,vf2d{1.5f,2.f})END; + + settingsWindow->ADD("Go Back",MenuComponent)(geom2d::rect{vf2d{windowSize.x/2.f,windowSize.y}-vf2d{36,16},{72,12}},"Go Back",[](MenuFuncData data){ Menu::CloseMenu(); return true; })END; diff --git a/Adventures in Lestoria/Slider.h b/Adventures in Lestoria/Slider.h index 8733b907..2797a1f1 100644 --- a/Adventures in Lestoria/Slider.h +++ b/Adventures in Lestoria/Slider.h @@ -47,23 +47,27 @@ INCLUDE_GFX class Slider:public MenuComponent{ bool dragging=false; float&val; //0.f-1.f + float prevVal=0.f; std::pairminMaxDisplayValues; - + std::functiononValChange; +public: //A slider component with a right-aligned label to the left, and a value display on the right-hand side. //valRef is between 0-1. //minMaxDisplayValues are visual only. inline Slider(const geom2d::rect&rect,const std::string&label,float&valRef,const std::pair&minMaxDisplayValues={0,100},const ButtonAttr&attributes=ButtonAttr::NONE) - :MenuComponent(rect,label,DO_NOTHING,attributes),val(valRef),minMaxDisplayValues(minMaxDisplayValues){ + :Slider(rect,label,valRef,[](float val){},minMaxDisplayValues,attributes){} + inline Slider(const geom2d::rect&rect,const std::string&label,float&valRef,std::functiononValChange,const std::pair&minMaxDisplayValues={0,100},const ButtonAttr&attributes=ButtonAttr::NONE) + :MenuComponent(rect,label,DO_NOTHING,attributes),val(valRef),minMaxDisplayValues(minMaxDisplayValues),prevVal(valRef),onValChange(onValChange){ if(minMaxDisplayValues.first>minMaxDisplayValues.second)ERR(std::format("WARNING! The first value provided for component {} is greater than the second! {} > {}",name,minMaxDisplayValues.first,minMaxDisplayValues.second)); } //Gets the absolute X position of the slider. float GetSliderX(){ - return rect.pos.x+rect.size.x*val; + return rect.pos.x+4+(rect.size.x-8)*val; } float GetSliderVal(float x){ - return (x-rect.pos.x)/rect.size.x; + return (x-rect.pos.x+4)/(rect.size.x-8); } int GetValueDisplay(){ @@ -81,7 +85,7 @@ class Slider:public MenuComponent{ if(dragging){ if(Menu::UsingMouseNavigation()){ - val=GetSliderVal(game->GetMouseX()); + val=GetSliderVal(game->GetMouseX()-Menu::menus[parentMenu]->pos.x-8); }else{ if(game->KEY_LEFT.Held()){ val-=1.f*game->GetElapsedTime(); @@ -91,6 +95,10 @@ class Slider:public MenuComponent{ } } val=std::clamp(val,0.f,1.f); + if(abs(prevVal-val)>=0.01f){ + onValChange(int(val*100)/100.f); + prevVal=val; + } if(game->KEY_CONFIRM.Released()||game->GetMouse(Mouse::LEFT).bReleased){ dragging=false; @@ -105,16 +113,24 @@ class Slider:public MenuComponent{ } vf2d labelSize=game->GetTextSizeProp(label); - window.DrawShadowStringPropDecal({rect.pos.x-2-labelSize.x,rect.pos.y+rect.size.y/2-labelSize.y/2},label); - - window.FillRectDecal({rect.pos.x,rect.pos.y+rect.size.y/2-1},{rect.size.x,2}); + window.DrawShadowStringPropDecal(vf2d{rect.pos.x-8-labelSize.x,rect.pos.y+rect.size.y/2-labelSize.y/2},label); - window.DrawRotatedDecal({GetSliderX(),rect.pos.y+rect.size.y/2},GFX["circle.png"].Decal(),0.f,vf2d(GFX["circle.png"].Sprite()->Size())/2.f,{2.f,2.f},backCol); + window.FillRectDecal(vf2d{rect.pos.x+4,rect.pos.y+rect.size.y/2-1}+vf2d{0.f,1.f},{rect.size.x-8,2},BLACK); + window.FillRectDecal(vf2d{rect.pos.x+4,rect.pos.y+rect.size.y/2-1},{rect.size.x-8,2}); + + window.DrawRotatedDecal(vf2d{GetSliderX(),rect.pos.y+rect.size.y/2},GFX["circle.png"].Decal(),0.f,vf2d(GFX["circle.png"].Sprite()->Size())/2.f,{5.f,5.f},BLACK); + window.DrawRotatedDecal(vf2d{GetSliderX(),rect.pos.y+rect.size.y/2},GFX["circle.png"].Decal(),0.f,vf2d(GFX["circle.png"].Sprite()->Size())/2.f,{4.f,4.f},backCol); - std::string valDisplayText=std::to_string(GetValueDisplay()); - vf2d valDisplayTextSize=game->GetTextSize(valDisplayText); + vf2d valDisplayTextSize=game->GetTextSize(std::to_string(minMaxDisplayValues.second)); vf2d valDisplayOutlinePos={rect.pos.x+rect.size.x+2,rect.pos.y}; - window.DrawRectDecal(valDisplayOutlinePos,valDisplayTextSize+vf2d{4,4}); - window.DrawShadowStringDecal(valDisplayOutlinePos+vf2d{2,2},valDisplayText); + Pixel valueBackCol=Menu::themes[Menu::themeSelection].GetButtonCol(); + Pixel valueTextCol=WHITE; + if(grayedOut){ + valueBackCol=GREY; + valueTextCol=VERY_DARK_GREY; + } + + window.FillRectDecal(valDisplayOutlinePos+vf2d{7.f,1.f},valDisplayTextSize+vf2d{4,4},valueBackCol); + window.DrawShadowStringDecal(valDisplayOutlinePos+vf2d{9.f,3.f},std::format("{:03}",GetValueDisplay()),valueTextCol); } }; \ No newline at end of file diff --git a/Adventures in Lestoria/SoundEffect.cpp b/Adventures in Lestoria/SoundEffect.cpp index 6b903a6a..514a01c8 100644 --- a/Adventures in Lestoria/SoundEffect.cpp +++ b/Adventures in Lestoria/SoundEffect.cpp @@ -88,7 +88,7 @@ void SoundEffect::PlaySFX(const std::string_view eventName,const vf2d&pos){ float pitch=util::random(pitchDiff)+sfx.minPitch; if(pos==CENTERED){ - Audio::Engine().Play(operator""_SFX(sfx.filename.c_str(),sfx.filename.length()),sfx.vol,0.0f,pitch); + Audio::Engine().Play(operator""_SFX(sfx.filename.c_str(),sfx.filename.length()),sfx.vol*Audio::GetSFXVolume(),0.0f,pitch); }else{ const float soundActivationRange="Audio.Environmental Audio Activation Range"_F; @@ -97,7 +97,7 @@ void SoundEffect::PlaySFX(const std::string_view eventName,const vf2d&pos){ float distRatio=1-distanceFromPlayer/soundActivationRange; //0-1 where 1 is full volume. float xDistRatio=(pos.x-game->GetPlayer()->GetX())/soundActivationRange; //0-1 where 1 is full volume. - float vol=distRatio*sfx.vol; + float vol=distRatio*sfx.vol*Audio::GetSFXVolume(); float pan=xDistRatio; Audio::Engine().Play(operator""_SFX(sfx.filename.c_str(),sfx.filename.length()),vol,pan,pitch); } diff --git a/Adventures in Lestoria/TODO.txt b/Adventures in Lestoria/TODO.txt index ebfb2fb7..9e8b28ed 100644 --- a/Adventures in Lestoria/TODO.txt +++ b/Adventures in Lestoria/TODO.txt @@ -3,13 +3,15 @@ January 1st Settings Menu - Any settings should be saved to the save file! - Volume Controls - - Play Sound in Background + - Play Sound in Background (Sound while Focused) - Keyboard aim assist (When playing w/keyboard, have the game auto fire for players that don't want to use mouse or cannot) + - Terrain Collision Boxes - Key Configuration -Upon pressing a key, check if the key is bound to another option, if so, remove that bind from the list. Up to two keys may be binded per action. -We have to save keybinds to the save file. + - XP Bar - Implement escape menu during gameplay. diff --git a/Adventures in Lestoria/Version.h b/Adventures in Lestoria/Version.h index c3d7ad8d..872be750 100644 --- a/Adventures in Lestoria/Version.h +++ b/Adventures in Lestoria/Version.h @@ -39,7 +39,7 @@ All rights reserved. #define VERSION_MAJOR 0 #define VERSION_MINOR 3 #define VERSION_PATCH 0 -#define VERSION_BUILD 6718 +#define VERSION_BUILD 6753 #define stringify(a) stringify_(a) #define stringify_(a) #a diff --git a/Adventures in Lestoria/assets/config/audio/events.txt b/Adventures in Lestoria/assets/config/audio/events.txt index dc098684..475131f6 100644 --- a/Adventures in Lestoria/assets/config/audio/events.txt +++ b/Adventures in Lestoria/assets/config/audio/events.txt @@ -17,6 +17,11 @@ Events # Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%) File[0] = button_click2.ogg, 40% } + Change Volume + { + # Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%) + File[0] = changevolume.ogg, 50%, 60%, 60% + } Consume Potion { # Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%) diff --git a/Adventures in Lestoria/assets/config/story/Chapter 1.txt b/Adventures in Lestoria/assets/config/story/Chapter 1.txt index d1639eac..e661a090 100644 --- a/Adventures in Lestoria/assets/config/story/Chapter 1.txt +++ b/Adventures in Lestoria/assets/config/story/Chapter 1.txt @@ -308,7 +308,7 @@ In the middle of the room is some kind of #F2FF00Pillar#FFFFFF which is the same {RIGHT You} On Top of that Pillar lies a red-coloured #FFBF00Stone Cube#FFFFFF. -The Stone Cube seems be emitting light. +The Stone Cube seems to be emitting light. Behind the Cube is a Wall engraved with runes. diff --git a/Adventures in Lestoria/assets/sounds/changevolume.ogg b/Adventures in Lestoria/assets/sounds/changevolume.ogg new file mode 100644 index 00000000..4d5cdfc9 Binary files /dev/null and b/Adventures in Lestoria/assets/sounds/changevolume.ogg differ diff --git a/x64/Release/Adventures in Lestoria.exe b/x64/Release/Adventures in Lestoria.exe index eb6c9a07..09f79be8 100644 Binary files a/x64/Release/Adventures in Lestoria.exe and b/x64/Release/Adventures in Lestoria.exe differ