Add in input helper text when navigating using keyboard/gamepads. Fix scrollwheel navigation for ScrollingWindowComponent referencing the wrong variable to add to (after the targeted scroll destination change).

pull/35/head
sigonasr2 10 months ago
parent a97bc7b2f0
commit 9dc2a0a4c2
  1. 12
      Adventures in Lestoria/Adventures in Lestoria.vcxproj
  2. 9
      Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters
  3. 125
      Adventures in Lestoria/InputHelper.cpp
  4. 58
      Adventures in Lestoria/InputHelper.h
  5. 320
      Adventures in Lestoria/Key.cpp
  6. 36
      Adventures in Lestoria/Key.h
  7. 28
      Adventures in Lestoria/LoadGameWindow.cpp
  8. 24
      Adventures in Lestoria/Menu.cpp
  9. 37
      Adventures in Lestoria/Menu.h
  10. 67
      Adventures in Lestoria/MenuType.h
  11. 4
      Adventures in Lestoria/ScrollableWindowComponent.h
  12. 2
      Adventures in Lestoria/Version.h
  13. 9
      Adventures in Lestoria/assets/config/Interface.txt
  14. 10
      Adventures in Lestoria/assets/config/gfx/gfx.txt
  15. 6
      Adventures in Lestoria/assets/config/gfx/themes.txt

@ -370,6 +370,10 @@
</SubType>
</ClInclude>
<ClInclude Include="GameState.h" />
<ClInclude Include="InputHelper.h">
<SubType>
</SubType>
</ClInclude>
<ClInclude Include="InventoryCreator.h">
<SubType>
</SubType>
@ -382,6 +386,10 @@
<SubType>
</SubType>
</ClInclude>
<ClInclude Include="MenuType.h">
<SubType>
</SubType>
</ClInclude>
<ClInclude Include="olcPGEX_SplashScreen.h" />
<ClInclude Include="PlayerMoneyLabel.h">
<SubType>
@ -577,6 +585,10 @@
</SubType>
</ClCompile>
<ClCompile Include="GameState.cpp" />
<ClCompile Include="InputHelper.cpp">
<SubType>
</SubType>
</ClCompile>
<ClCompile Include="InventoryConsumableWindow.cpp" />
<ClCompile Include="InventoryCreator.cpp">
<SubType>

@ -423,6 +423,12 @@
<ClInclude Include="Slider.h">
<Filter>Header Files\Interface</Filter>
</ClInclude>
<ClInclude Include="InputHelper.h">
<Filter>Header Files\Interface</Filter>
</ClInclude>
<ClInclude Include="MenuType.h">
<Filter>Header Files\Interface</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Player.cpp">
@ -725,6 +731,9 @@
<ClCompile Include="Bear.cpp">
<Filter>Source Files\Monster Strategies</Filter>
</ClCompile>
<ClCompile Include="InputHelper.cpp">
<Filter>Source Files\Interface</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="cpp.hint" />

@ -0,0 +1,125 @@
#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 © 2023 The FreeType
Project (www.freetype.org). Please see LICENSE_FT.txt for more information.
All rights reserved.
*/
#pragma endregion
#include "InputHelper.h"
#include "AdventuresInLestoria.h"
#include "Menu.h"
INCLUDE_game
INCLUDE_GFX
INCLUDE_WINDOW_SIZE
InputHelper::InputHelper(){}
void InputHelper::Initialize(MenuInputGroups&inputGroups){
for(auto&data:inputGroups){
this->inputGroups[data.first.GetGroup()]=data.second.first;
}
}
const InputType InputHelper::InputMode()const{
if(Input::UsingGamepad())return CONTROLLER;
if(!Menu::stack.back()->UsingMouseNavigation())return KEY;
return MOUSE;
}
void InputHelper::Draw(){
InputType mode=InputMode();
if(mode==MOUSE)mode=KEY; //We're going to make it so the keyboard controls always show up when navigating using a mouse.
switch(mode){
case CONTROLLER:
case KEY:{
float buttonImgWidth=0.f;
float buttonDescriptionWidth=0.f;
std::vector<std::variant<Decal*,std::string>>buttonImgs; //Store decals for buttons that actually have images, and strings for buttons that have labels.
std::vector<std::string>buttonDescriptions;
#pragma region Populate all buttons to display
for(auto&[group,displayName]:inputGroups){
auto&primaryKey=group.GetPrimaryKey(mode);
if(primaryKey.has_value()){
if(primaryKey.value().HasIcon()){
buttonImgWidth+=primaryKey.value().GetIcon().Sprite()->width+"Interface.InputHelperSpacing"_I;
buttonImgs.push_back(primaryKey.value().GetIcon().Decal());
}else{
buttonImgs.push_back(primaryKey.value().GetDisplayName());
}
vf2d descriptionSize=game->GetTextSizeProp(displayName);
buttonDescriptionWidth+=descriptionSize.x+"Interface.InputHelperSpacing"_I;
buttonDescriptions.push_back(displayName);
}
}
#pragma endregion
float buttonDescriptionScaleX=1.0f;
if(buttonImgWidth+buttonDescriptionWidth>WINDOW_SIZE.x){
buttonDescriptionScaleX=(WINDOW_SIZE.x-buttonImgWidth)/buttonDescriptionWidth;
}
#pragma region Draw all button inputs and descriptions
float xOffset="Interface.InputHelperSpacing"_I;
for(size_t index=0;auto&button:buttonImgs){
if(std::holds_alternative<Decal*>(button)){
Decal*img=std::get<Decal*>(button);
game->DrawDecal(vf2d{xOffset,float(WINDOW_SIZE.y-img->sprite->height)-8},img);
xOffset+=img->sprite->width+"Interface.InputHelperSpacing"_I;
}else
if(std::holds_alternative<std::string>(button)){
std::string label=std::get<std::string>(button);
vf2d textSize=game->GetTextSizeProp(label);
game->FillRectDecal(vf2d{xOffset-2,float(WINDOW_SIZE.y-textSize.y-10)},vf2d{textSize.x+4,textSize.y},"Interface.InputButtonBackCol"_Pixel);
game->FillRectDecal(vf2d{xOffset-1,float(WINDOW_SIZE.y-textSize.y-10)-1.f},vf2d{textSize.x+2,textSize.y},"Interface.InputButtonBackCol"_Pixel);
game->FillRectDecal(vf2d{xOffset-1,float(WINDOW_SIZE.y-textSize.y-10)},vf2d{textSize.x+2,textSize.y+1.f},"Interface.InputButtonBackCol"_Pixel);
game->DrawStringPropDecal(vf2d{xOffset,float(WINDOW_SIZE.y-textSize.y-10)},label,"Interface.InputButtonTextCol"_Pixel);
xOffset+=textSize.x+"Interface.InputHelperSpacing"_I;
}else [[unlikely]]ERR("WARNING! Hit a state where no data is inside of the button! THIS SHOULD NOT BE HAPPENING!");
std::string_view description=buttonDescriptions[index];
vf2d descriptionTextSize=game->GetTextSizeProp(description)*vf2d{buttonDescriptionScaleX,1.f};
game->DrawShadowStringPropDecal(vf2d{xOffset,float(WINDOW_SIZE.y-descriptionTextSize.y-10)},description,WHITE,BLACK,vf2d{buttonDescriptionScaleX,1.f});
xOffset+=descriptionTextSize.x+"Interface.InputHelperSpacing"_I;
index++;
}
#pragma endregion
}break;
[[unlikely]]default:{
ERR(std::format("Invalid Input Mode detected: {}! THIS SHOULD NOT BE HAPPENING!",int(mode)))
}
}
}

@ -0,0 +1,58 @@
#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 © 2023 The FreeType
Project (www.freetype.org). Please see LICENSE_FT.txt for more information.
All rights reserved.
*/
#pragma endregion
#pragma once
#include <variant>
#include <functional>
#include "Key.h"
#include "MenuType.h"
using InputGroupActionDisplayName=std::string;
using ButtonName=std::string;
using MenuInputGroups=std::map<InputEngageGroup,std::pair<InputGroupActionDisplayName,std::variant<ButtonName,std::function<void(MenuType)>>>>;
class InputHelper{
std::map<InputGroup,InputGroupActionDisplayName>inputGroups;
const InputType InputMode()const;
public:
InputHelper();
void Initialize(MenuInputGroups&inputGroups);
void Draw();
};

@ -41,6 +41,7 @@ All rights reserved.
#include "olcPGEX_Gamepad.h"
INCLUDE_game
INCLUDE_GFX
bool Input::usingGamepad;
@ -160,18 +161,43 @@ float Input::Analog(){
return 0.f;
}
std::string Input::GetDisplayName(){
return GenericKey::keyLiteral.at({type,key});
std::string Input::GetDisplayName()const{
return GenericKey::keyLiteral.at({type,key}).displayName;
}
const std::string Input::str()const{
std::string outputStr="";
switch(type){
case KEY:{
outputStr=std::format("[Type:KEY,Key:{}]",GetDisplayName());
}break;
case MOUSE:{
outputStr=std::format("[Type:MOUSE,Key:{}]",GetDisplayName());
}break;
case CONTROLLER:{
outputStr=std::format("[Type:CONTROLLER,Key:{}]",GetDisplayName());
}break;
case ANALOG:{
outputStr=std::format("[Type:ANALOG,Key:{}]",GetDisplayName());
}break;
default:{
ERR(std::format("WARNING! Unhandled input type: {}",int(type)))
}
}
return outputStr;
}
InputGroup::InputGroup(){}
void InputGroup::AddKeybind(Input bind){
keys.insert(bind);
keyOrder.push_back(bind);
}
void InputGroup::RemoveKeybind(Input bind){
keys.erase(bind);
size_t erased=keys.erase(bind);
erased+=std::erase(keyOrder,bind);
if(erased!=2)ERR(std::format("WARNING! Could not remove keybind {}",bind.str()));
}
const bool InputGroup::Pressed()const{
@ -214,124 +240,139 @@ std::string InputGroup::GetDisplayName(){
return combinationDisplay;
}
std::map<std::pair<InputType,int>,std::string> GenericKey::keyLiteral={
{{KEY, NONE},""},
{{KEY, A},"A"},
{{KEY, B},"B"},
{{KEY, C},"C"},
{{KEY, D},"D"},
{{KEY, E},"E"},
{{KEY, F},"F"},
{{KEY, G},"G"},
{{KEY, H},"H"},
{{KEY, I},"I"},
{{KEY, J},"J"},
{{KEY, K},"L"},
{{KEY, L},"L"},
{{KEY, M},"M"},
{{KEY, N},"N"},
{{KEY, O},"O"},
{{KEY, P},"P"},
{{KEY, Q},"Q"},
{{KEY, R},"R"},
{{KEY, S},"S"},
{{KEY, T},"T"},
{{KEY, U},"U"},
{{KEY, V},"V"},
{{KEY, W},"W"},
{{KEY, X},"X"},
{{KEY, Y},"Y"},
{{KEY, Z},"Z"},
{{KEY, K0},"0"},
{{KEY, K1},"1"},
{{KEY, K2},"2"},
{{KEY, K3},"3"},
{{KEY, K4},"4"},
{{KEY, K5},"5"},
{{KEY, K6},"6"},
{{KEY, K7},"7"},
{{KEY, K8},"8"},
{{KEY, K9},"9"},
{{KEY, F1},"F1"},
{{KEY, F2},"F2"},
{{KEY, F3},"F3"},
{{KEY, F4},"F4"},
{{KEY, F5},"F5"},
{{KEY, F6},"F6"},
{{KEY, F7},"F7"},
{{KEY, F8},"F8"},
{{KEY, F9},"F9"},
{{KEY, F10},"F10"},
{{KEY, F11},"F11"},
{{KEY, F12},"F12"},
{{KEY, UP},"UP"},
{{KEY, DOWN},"DOWN"},
{{KEY, LEFT},"LEFT"},
{{KEY, RIGHT},"RIGHT"},
{{KEY, SPACE},"SPACE"},
{{KEY, TAB},"TAB"},
{{KEY, SHIFT},"SHIFT"},
{{KEY, CTRL},"CTRL"},
{{KEY, INS},"INS"},
{{KEY, DEL},"DEL"},
{{KEY, HOME},"HOME"},
{{KEY, END},"END"},
{{KEY, PGUP},"PGUP"},
{{KEY, PGDN},"PGDN"},
{{KEY, BACK},"BACK"},
{{KEY, ESCAPE},"ESC"},
{{KEY, RETURN},"ENTER"},
{{KEY, ENTER},"ENTER"},
{{KEY, PAUSE},"PAUSE"},
{{KEY, SCROLL},"SCR LK"},
{{KEY, NP0},"NP0"},
{{KEY, NP1},"NP1"},
{{KEY, NP2},"NP2"},
{{KEY, NP3},"NP3"},
{{KEY, NP4},"NP4"},
{{KEY, NP5},"NP5"},
{{KEY, NP6},"NP6"},
{{KEY, NP7},"NP7"},
{{KEY, NP8},"NP8"},
{{KEY, NP9},"NP9"},
{{KEY, NP_MUL},"NP*"},
{{KEY, NP_DIV},"NP/"},
{{KEY, NP_ADD},"NP+"},
{{KEY, NP_SUB},"NP-"},
{{KEY, NP_DECIMAL},"NP."},
{{KEY, PERIOD},"."},
{{KEY, EQUALS},"="},
{{KEY, COMMA},","},
{{KEY, MINUS},"-"},
{{KEY, OEM_1},";"},
{{KEY, OEM_2},"/"},
{{KEY, OEM_3},"~"},
{{KEY, OEM_4},"["},
{{KEY, OEM_5},"\\"},
{{KEY, OEM_6},"]"},
{{KEY, OEM_7},"\""},
{{KEY, OEM_8},"\\"},
{{KEY, CAPS_LOCK},"CAP LK"},
{{KEY, olc::ENUM_END},""},
{{MOUSE, Mouse::LEFT},"L.MOUSE"},
{{MOUSE, Mouse::RIGHT},"R.MOUSE"},
{{MOUSE, Mouse::MIDDLE},"M.MOUSE"},
{{CONTROLLER, static_cast<int>(GPButtons::FACE_D)},"A/X"},
{{CONTROLLER, static_cast<int>(GPButtons::FACE_L)},"X/Square"},
{{CONTROLLER, static_cast<int>(GPButtons::FACE_R)},"B/Circle"},
{{CONTROLLER, static_cast<int>(GPButtons::FACE_U)},"Y/Triangle"},
{{CONTROLLER, static_cast<int>(GPButtons::L1)},"L1"},
{{CONTROLLER, static_cast<int>(GPButtons::L2)},"L2"},
{{CONTROLLER, static_cast<int>(GPButtons::L3)},"L3"},
{{CONTROLLER, static_cast<int>(GPButtons::R1)},"R1"},
{{CONTROLLER, static_cast<int>(GPButtons::R2)},"R2"},
{{CONTROLLER, static_cast<int>(GPButtons::R3)},"R3"},
{{CONTROLLER, static_cast<int>(GPButtons::SELECT)},"SELECT"},
{{CONTROLLER, static_cast<int>(GPButtons::START)},"START"},
{{CONTROLLER, static_cast<int>(GPButtons::DPAD_L)},"LEFT"},
{{CONTROLLER, static_cast<int>(GPButtons::DPAD_R)},"RIGHT"},
{{CONTROLLER, static_cast<int>(GPButtons::DPAD_U)},"UP"},
{{CONTROLLER, static_cast<int>(GPButtons::DPAD_D)},"DOWN"},
const bool Input::HasIcon()const{
return GenericKey::keyLiteral.at({type,key}).iconName.length()>0;
}
const Renderable&Input::GetIcon()const{
return GFX.at(GenericKey::keyLiteral.at({type,key}).iconName);
}
std::map<std::pair<InputType,int>,GenericKey::KeyInfo> GenericKey::keyLiteral={
{{KEY, NONE},{""}},
{{KEY, A},{"A"}},
{{KEY, B},{"B"}},
{{KEY, C},{"C"}},
{{KEY, D},{"D"}},
{{KEY, E},{"E"}},
{{KEY, F},{"F"}},
{{KEY, G},{"G"}},
{{KEY, H},{"H"}},
{{KEY, I},{"I"}},
{{KEY, J},{"J"}},
{{KEY, K},{"L"}},
{{KEY, L},{"L"}},
{{KEY, M},{"M"}},
{{KEY, N},{"N"}},
{{KEY, O},{"O"}},
{{KEY, P},{"P"}},
{{KEY, Q},{"Q"}},
{{KEY, R},{"R"}},
{{KEY, S},{"S"}},
{{KEY, T},{"T"}},
{{KEY, U},{"U"}},
{{KEY, V},{"V"}},
{{KEY, W},{"W"}},
{{KEY, X},{"X"}},
{{KEY, Y},{"Y"}},
{{KEY, Z},{"Z"}},
{{KEY, K0},{"0"}},
{{KEY, K1},{"1"}},
{{KEY, K2},{"2"}},
{{KEY, K3},{"3"}},
{{KEY, K4},{"4"}},
{{KEY, K5},{"5"}},
{{KEY, K6},{"6"}},
{{KEY, K7},{"7"}},
{{KEY, K8},{"8"}},
{{KEY, K9},{"9"}},
{{KEY, F1},{"F1"}},
{{KEY, F2},{"F2"}},
{{KEY, F3},{"F3"}},
{{KEY, F4},{"F4"}},
{{KEY, F5},{"F5"}},
{{KEY, F6},{"F6"}},
{{KEY, F7},{"F7"}},
{{KEY, F8},{"F8"}},
{{KEY, F9},{"F9"}},
{{KEY, F10},{"F10"}},
{{KEY, F11},{"F11"}},
{{KEY, F12},{"F12"}},
{{KEY, UP},{"UP"}},
{{KEY, DOWN},{"DOWN"}},
{{KEY, LEFT},{"LEFT"}},
{{KEY, RIGHT},{"RIGHT"}},
{{KEY, SPACE},{"SPACE"}},
{{KEY, TAB},{"TAB"}},
{{KEY, SHIFT},{"SHIFT"}},
{{KEY, CTRL},{"CTRL"}},
{{KEY, INS},{"INS"}},
{{KEY, DEL},{"DEL"}},
{{KEY, HOME},{"HOME"}},
{{KEY, END},{"END"}},
{{KEY, PGUP},{"PGUP"}},
{{KEY, PGDN},{"PGDN"}},
{{KEY, BACK},{"BACK"}},
{{KEY, ESCAPE},{"ESC"}},
{{KEY, RETURN},{"ENTER"}},
{{KEY, ENTER},{"ENTER"}},
{{KEY, PAUSE},{"PAUSE"}},
{{KEY, SCROLL},{"SCR LK"}},
{{KEY, NP0},{"NP0"}},
{{KEY, NP1},{"NP1"}},
{{KEY, NP2},{"NP2"}},
{{KEY, NP3},{"NP3"}},
{{KEY, NP4},{"NP4"}},
{{KEY, NP5},{"NP5"}},
{{KEY, NP6},{"NP6"}},
{{KEY, NP7},{"NP7"}},
{{KEY, NP8},{"NP8"}},
{{KEY, NP9},{"NP9"}},
{{KEY, NP_MUL},{"NP*"}},
{{KEY, NP_DIV},{"NP/"}},
{{KEY, NP_ADD},{"NP+"}},
{{KEY, NP_SUB},{"NP-"}},
{{KEY, NP_DECIMAL},{"NP."}},
{{KEY, PERIOD},{"."}},
{{KEY, EQUALS},{"="}},
{{KEY, COMMA},{",{"}},
{{KEY, MINUS},{"-"}},
{{KEY, OEM_1},{";"}},
{{KEY, OEM_2},{"/"}},
{{KEY, OEM_3},{"~"}},
{{KEY, OEM_4},{"["}},
{{KEY, OEM_5},{"\\"}},
{{KEY, OEM_6},{"]"}},
{{KEY, OEM_7},{"\""}},
{{KEY, OEM_8},{"\\"}},
{{KEY, CAPS_LOCK},{"CAP LK"}},
{{KEY, olc::ENUM_END},{""}},
{{MOUSE, Mouse::LEFT},{"L.MOUSE"}},
{{MOUSE, Mouse::RIGHT},{"R.MOUSE"}},
{{MOUSE, Mouse::MIDDLE},{"M.MOUSE"}},
{{CONTROLLER, static_cast<int>(GPButtons::FACE_D)},{"A/X","themes/button_d.png"}},
{{CONTROLLER, static_cast<int>(GPButtons::FACE_L)},{"X/Square","themes/button_l.png"}},
{{CONTROLLER, static_cast<int>(GPButtons::FACE_R)},{"B/Circle","themes/button_r.png"}},
{{CONTROLLER, static_cast<int>(GPButtons::FACE_U)},{"Y/Triangle","themes/button_u.png"}},
{{CONTROLLER, static_cast<int>(GPButtons::L1)},{"L1","themes/button_l1.png"}},
{{CONTROLLER, static_cast<int>(GPButtons::L2)},{"L2","themes/button_l2.png"}},
{{CONTROLLER, static_cast<int>(GPButtons::L3)},{"L3"}},
{{CONTROLLER, static_cast<int>(GPButtons::R1)},{"R1","themes/button_r1.png"}},
{{CONTROLLER, static_cast<int>(GPButtons::R2)},{"R2","themes/button_r2.png"}},
{{CONTROLLER, static_cast<int>(GPButtons::R3)},{"R3"}},
{{CONTROLLER, static_cast<int>(GPButtons::SELECT)},{"SELECT"}},
{{CONTROLLER, static_cast<int>(GPButtons::START)},{"START"}},
{{CONTROLLER, static_cast<int>(GPButtons::DPAD_L)},{"LEFT"}},
{{CONTROLLER, static_cast<int>(GPButtons::DPAD_R)},{"RIGHT"}},
{{CONTROLLER, static_cast<int>(GPButtons::DPAD_U)},{"UP"}},
{{CONTROLLER, static_cast<int>(GPButtons::DPAD_D)},{"DOWN"}},
{{ANALOG, static_cast<int>(GPAxes::LY)},{"Up/Down","themes/button_analogstick_vert.png"}},
{{ANALOG, static_cast<int>(GPAxes::RY)},{"Up/Down","themes/button_analogstick_vert.png"}},
{{ANALOG, static_cast<int>(GPAxes::LX)},{"Right/Left","themes/button_analogstick_horz.png"}},
{{ANALOG, static_cast<int>(GPAxes::RX)},{"Right/Left","themes/button_analogstick_horz.png"}},
{{ANALOG, static_cast<int>(GPAxes::TL)},{"Left Trigger","themes/button_l2.png"}},
{{ANALOG, static_cast<int>(GPAxes::TR)},{"Right Trigger","themes/button_r2.png"}},
{{ANALOG, static_cast<int>(GPAxes::DX)},{"Right/Left","themes/button_analogstick_horz.png"}},
{{ANALOG, static_cast<int>(GPAxes::DY)},{"Up/Down","themes/button_analogstick_vert.png"}},
};
void Input::SetUsingGamepad(const bool usingGamepad){
@ -386,3 +427,40 @@ void Input::StopVibration(){
const bool operator<(const InputGroup&group1,const InputGroup&group2){
return &group1<&group2;
}
const bool operator<(const InputEngageGroup&group1,const InputEngageGroup&group2){
return &group1<&group2;
}
const InputType Input::GetType()const{
return type;
}
const std::optional<Input>InputGroup::GetPrimaryKey(InputType type)const{
if(type==ANALOG)ERR("WARNING! Type cannot be ANALOG! Not supported!");
std::optional<Input>result;
if(keyOrder.size()>0){
auto it=std::find_if(keyOrder.begin(),keyOrder.end(),[&](const Input&input){
return input.GetType()==type
||(type==CONTROLLER&&input.GetType()==ANALOG);
});
if(it!=keyOrder.end())return *it;
}
return result;
}
const bool operator==(const Input&input1,const Input&input2){
return input1.type==input2.type&&input1.key==input2.key;
}
InputEngageGroup::InputEngageGroup(InputGroup&group,EngageType type)
:group(group),type(type){}
const InputEngageGroup::EngageType InputEngageGroup::GetEngageType()const{
return type;
}
InputGroup&InputEngageGroup::GetGroup()const{
return group;
}

@ -39,6 +39,7 @@ All rights reserved.
#include <set>
#include <string>
#include <map>
#include "olcPixelGameEngine.h"
//Future-proof game controller support.
enum InputType{
@ -61,7 +62,7 @@ public:
bool Held();
bool Released();
float Analog();
std::string GetDisplayName();
std::string GetDisplayName()const;
bool operator<(const Input&rhs)const{
return type<rhs.type||(type==rhs.type&&key<rhs.key);
}
@ -69,10 +70,16 @@ public:
static const bool AxesActive();
static void StartVibration();
static void StopVibration();
const InputType GetType()const;
const std::string str()const;
const bool HasIcon()const;
const Renderable&GetIcon()const;
friend const bool operator==(const Input&input1,const Input&input2);
};
class InputGroup{
std::set<Input>keys;
std::vector<Input>keyOrder; //A list of keys inserted in order, for primary key mapping.
public:
InputGroup();
void AddKeybind(Input bind);
@ -82,11 +89,36 @@ public:
const bool Released()const;
const float Analog()const;
std::string GetDisplayName();
const std::optional<Input>GetPrimaryKey(InputType type)const;
};
class InputEngageGroup{
public:
enum EngageType{
Pressed,
Held,
Released,
Analog,
};
private:
InputGroup&group;
EngageType type;
public:
InputEngageGroup(InputGroup&group,EngageType type=Released);
const EngageType GetEngageType()const;
InputGroup&GetGroup()const;
};
class GenericKey{
struct KeyInfo{
std::string displayName;
std::string iconName;
};
public:
static std::map<std::pair<InputType,int>,std::string>keyLiteral; //The displayed text for a given key for a given input type.
static std::map<std::pair<InputType,int>,KeyInfo>keyLiteral; //The displayed text for a given key for a given input type.
};
const bool operator<(const InputGroup&group1,const InputGroup&group2);
const bool operator<(const InputEngageGroup&group1,const InputEngageGroup&group2);
using enum InputEngageGroup::EngageType;

@ -47,6 +47,20 @@ void Menu::InitializeLoadGameWindow(){
loadGameWindow->ADD("Game Files List",ScrollableWindowComponent)(geom2d::rect<float>{{-8,4},{112,116}})END;
loadGameWindow->ADD("Go Back Button",MenuComponent)(geom2d::rect<float>{{24,124},{48,12}},"Back",[](MenuFuncData menu){Menu::CloseMenu();return true;})END;
#pragma region ScrollWindow macro lambda
#define ScrollWindow(amount) \
[](MenuType type){ \
auto scrollWindow=Component<ScrollableWindowComponent>(type,"Game Files List"); \
float scrollAmt=amount*game->GetElapsedTime()*"Interface.AnalogScrollSpeed"_F; \
\
scrollWindow->SetScrollAmount(scrollWindow->GetTargetScrollAmount()-vf2d{0,amount*game->GetElapsedTime()*"Interface.AnalogScrollSpeed"_F}); \
\
/*Height of these buttons is 48.*/ \
scrollWindow->IncreaseSelectionIndex(scrollAmt/48.f); \
}
#pragma endregion
loadGameWindow->SetupKeyboardNavigation(
[](MenuType type,Data&returnData){ //On Open
if(SaveFile::GetSaveFileCount()>0){
@ -56,18 +70,12 @@ void Menu::InitializeLoadGameWindow(){
}
},
{ //Button Key
{game->KEY_BACK,{"Back to Title Screen",[](MenuType type){
{{game->KEY_BACK},{"Back to Title Screen",[](MenuType type){
Component<MenuComponent>(type,"Go Back Button")->Click();
}}},
{game->KEY_SCROLL,{"Scroll Up/Down",[](MenuType type){
auto scrollWindow=Component<ScrollableWindowComponent>(type,"Game Files List");
float scrollAmt=game->KEY_SCROLL.Analog()*game->GetElapsedTime()*"Interface.AnalogScrollSpeed"_F;
scrollWindow->SetScrollAmount(scrollWindow->GetTargetScrollAmount()-vf2d{0,game->KEY_SCROLL.Analog()*game->GetElapsedTime()*"Interface.AnalogScrollSpeed"_F});
//Height of these buttons is 48.
scrollWindow->IncreaseSelectionIndex(scrollAmt/48.f);
}}},
{{game->KEY_SCROLL,Analog},{"Scroll",ScrollWindow(game->KEY_SCROLL.Analog())}},
{{game->KEY_SCROLLUP,Held},{"Scroll Up",ScrollWindow(-1.0f)}},
{{game->KEY_SCROLLDOWN,Held},{"Scroll Down",ScrollWindow(1.0f)}},
}
,{ //Button Navigation Rules
{"Game Files List",{

@ -281,6 +281,10 @@ void Menu::Draw(AiL*game){
draggingComponent->DrawDecal(window,this==Menu::stack.back());
}
}
if(Menu::stack.back()==this){
helpDisplay.Draw();
}
};
void Menu::OpenMenu(MenuType menu,bool cover){
@ -297,7 +301,24 @@ void Menu::KeyboardButtonNavigation(AiL*game,vf2d menuPos){
std::weak_ptr<MenuComponent>prevSelection=selection;
for(auto&[input,data]:inputGroups){
if(input.Released()||input.Analog()!=0.f){
bool activated=false;
switch(input.GetEngageType()){
case Released:{
activated=input.GetGroup().Released();
}break;
case Pressed:{
activated=input.GetGroup().Pressed();
}break;
case Held:{
activated=input.GetGroup().Held();
}break;
case Analog:{
activated=input.GetGroup().Analog()!=0.f;
}break;
[[unlikely]]default:ERR(std::format("WARNING! Unhandled input engage type {}! THIS SHOULD NOT BE HAPPENING!",int(input.GetEngageType())));
}
if(activated){
SetMouseNavigation(false);
auto&action=data.second;
if(std::holds_alternative<ButtonName>(action))Component<MenuComponent>(type,std::get<ButtonName>(action))->Click();
@ -624,6 +645,7 @@ MenuFuncData::MenuFuncData(Menu&menu,AiL*const game,std::weak_ptr<MenuComponent>
void Menu::SetupKeyboardNavigation(MenuDataFunc onOpen,MenuInputGroups inputGroups,ButtonNavigationGroups navigationGroups){
this->onOpenFunc=onOpen;
this->inputGroups=inputGroups;
helpDisplay.Initialize(inputGroups);
this->navigationGroups=navigationGroups;
}

@ -43,7 +43,7 @@ All rights reserved.
#include "Attributable.h"
#include "olcUTIL_Geometry2D.h"
#include "olcPGEX_ViewPort.h"
#include "Key.h"
#include "InputHelper.h"
class AiL;
class MenuComponent;
@ -70,41 +70,8 @@ using MenuFunc=std::function<bool(MenuFuncData)>;
#define DEFAULT_DEPTH -999999
#define STARTING_DEPTH 999999
enum MenuType{
///////////////////////////////////////////////////////////
/*DO NOT REMOVE!!*/ENUM_START,///////////////////////////////
///////////////////////////////////////////////////////////
INVENTORY_CONSUMABLES,
CLASS_INFO,
CLASS_SELECTION,
MAIN_MENU,
OVERWORLD_LEVEL_SELECT,
ITEM_LOADOUT,
LEVEL_COMPLETE,
OVERWORLD_MENU,
CHARACTER_MENU,
INVENTORY,
MERCHANT,
BUY_ITEM,
SELL_ITEM,
BLACKSMITH,
CRAFT_ITEM,
CRAFT_CONSUMABLE,
CONSUMABLE_CRAFT_ITEM,
SAVE_FILE_NAME,
LOAD_GAME,
USER_ID,
///////////////////////////////////////////////////////////
/*DO NOT REMOVE!!*/ENUM_END////////////////////////////////
///////////////////////////////////////////////////////////
};
using InputGroupActionDisplayName=std::string;
using ButtonName=std::string;
using Data=std::variant<ButtonName,std::weak_ptr<MenuComponent>>;
using MenuDataFunc=std::function<void(MenuType,Data&)>;
using MenuInputGroups=std::map<InputGroup,std::pair<InputGroupActionDisplayName,std::variant<ButtonName,std::function<void(MenuType)>>>>;
using ButtonNavigationGroups=std::map<ButtonName,Navigation>;
@ -253,6 +220,8 @@ private:
std::weak_ptr<MenuComponent>selection;
std::weak_ptr<MenuComponent>keyboardSelection;
InputHelper helpDisplay;
static bool MOUSE_NAVIGATION;
bool cover; //A black cover for when a menu pops up to fade out the stuff behind it.
};

@ -0,0 +1,67 @@
#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 © 2023 The FreeType
Project (www.freetype.org). Please see LICENSE_FT.txt for more information.
All rights reserved.
*/
#pragma endregion
#pragma once
enum MenuType{
///////////////////////////////////////////////////////////
/*DO NOT REMOVE!!*/ENUM_START,///////////////////////////////
///////////////////////////////////////////////////////////
INVENTORY_CONSUMABLES,
CLASS_INFO,
CLASS_SELECTION,
MAIN_MENU,
OVERWORLD_LEVEL_SELECT,
ITEM_LOADOUT,
LEVEL_COMPLETE,
OVERWORLD_MENU,
CHARACTER_MENU,
INVENTORY,
MERCHANT,
BUY_ITEM,
SELL_ITEM,
BLACKSMITH,
CRAFT_ITEM,
CRAFT_CONSUMABLE,
CONSUMABLE_CRAFT_ITEM,
SAVE_FILE_NAME,
LOAD_GAME,
USER_ID,
///////////////////////////////////////////////////////////
/*DO NOT REMOVE!!*/ENUM_END////////////////////////////////
///////////////////////////////////////////////////////////
};

@ -160,9 +160,9 @@ protected:
if(game->GetMouseWheel()!=0){
if(game->GetMouseWheel()>0){
SetScrollAmount(GetScrollAmount()+vf2d{0,"ThemeGlobal.MenuScrollWheelSpeed"_F});
SetScrollAmount(GetTargetScrollAmount()+vf2d{0,"ThemeGlobal.MenuScrollWheelSpeed"_F});
}else{
SetScrollAmount(GetScrollAmount()-vf2d{0,"ThemeGlobal.MenuScrollWheelSpeed"_F});
SetScrollAmount(GetTargetScrollAmount()-vf2d{0,"ThemeGlobal.MenuScrollWheelSpeed"_F});
}
}

@ -39,7 +39,7 @@ All rights reserved.
#define VERSION_MAJOR 0
#define VERSION_MINOR 3
#define VERSION_PATCH 0
#define VERSION_BUILD 6119
#define VERSION_BUILD 6155
#define stringify(a) stringify_(a)
#define stringify_(a) #a

@ -5,4 +5,13 @@ Interface
# The size of each side of the 9-patch menu sprite.
9PatchSize = 24,24
# The spacing between inputs and text in the input helper text displayer.
InputHelperSpacing = 4
# The back color of input keys.
InputButtonBackCol = 15,8,47,255
# The text color of input keys.
InputButtonTextCol = 175,199,191,255
}

@ -50,6 +50,16 @@ Images
GFX_FrogTongueEnd = tongue_end.png
GFX_AimingTarget = aiming_target.png
GFX_AimingLine = aiming_line.png
GFX_Button_AnalogStick_Horz = themes/button_analogstick_horz.png
GFX_Button_AnalogStick_Vert = themes/button_analogstick_vert.png
GFX_Button_Face_Down = themes/button_d.png
GFX_Button_Face_Left = themes/button_l.png
GFX_Button_Face_Right = themes/button_r.png
GFX_Button_Face_Up = themes/button_u.png
GFX_Button_Face_L1 = themes/button_l1.png
GFX_Button_Face_L2 = themes/button_l2.png
GFX_Button_Face_R1 = themes/button_r1.png
GFX_Button_Face_R2 = themes/button_r2.png
# Ability Icons
GFX_Warrior_BattleCry_Icon = Ability Icons/battlecry.png

@ -13,12 +13,6 @@ ThemeGlobal
# How far the mouse has to move before mouse mode becomes active from keyboard/controller input mode.
MouseActivationDistance = 8
# The back color of input keys.
InputButtonBackCol = 15,8,47,255
# The text color of input keys.
InputButtonTextCol = 175,199,191
}
Themes

Loading…
Cancel
Save