The open source repository for the action RPG game in development by Sig Productions titled 'Adventures in Lestoria'!
https://forums.lestoria.net
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
581 lines
29 KiB
581 lines
29 KiB
#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 "Menu.h"
|
|
#include "MenuComponent.h"
|
|
#include "PopupMenuLabel.h"
|
|
#include "StatLabel.h"
|
|
#include "CharacterRotatingDisplay.h"
|
|
#include "AdventuresInLestoria.h"
|
|
#include "ClassInfo.h"
|
|
#include "MenuItemItemButton.h"
|
|
#include "EquipSlotButton.h"
|
|
#include "Item.h"
|
|
#include "ScrollableWindowComponent.h"
|
|
#include "RowItemDisplay.h"
|
|
#include "SoundEffect.h"
|
|
#include "ProgressBar.h"
|
|
#include <bit>
|
|
|
|
INCLUDE_game
|
|
INCLUDE_GFX
|
|
|
|
void Menu::InitializeCharacterMenuWindow(){
|
|
static bool equipmentWindowOpened=false;
|
|
static int lastEquipButtonOpened=0;
|
|
|
|
vf2d windowSize=game->GetScreenSize()-vf2d{52,52};
|
|
Menu*characterMenuWindow=CreateMenu(CHARACTER_MENU,CENTERED,windowSize);
|
|
|
|
characterMenuWindow->ADD("Character Label",MenuLabel)(geom2d::rect<float>{{0,-4},{float(windowSize.x)-1,24}},"Character",2,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END;
|
|
characterMenuWindow->ADD("Equip Slot Outline",MenuComponent)(geom2d::rect<float>{{0,28},{120,windowSize.y-37}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END;
|
|
characterMenuWindow->ADD("Character Rotating Display",CharacterRotatingDisplay)(geom2d::rect<float>{{118,18},{130,windowSize.y-28}},GFX[classutils::GetClassInfo(game->GetPlayer()->GetClassName()).classFullImgName].Decal())END;
|
|
|
|
characterMenuWindow->ADD("Level Class Display",MenuLabel)(geom2d::rect<float>{vf2d{126.f,windowSize.y-28},{118.f,8.f}},std::format("Lv{} {}",game->GetPlayer()->Level(),game->GetPlayer()->GetClassName()),1.f,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN)END;
|
|
characterMenuWindow->ADD("XP Bar",ProgressBar)(geom2d::rect<float>{vf2d{126.f,10.f+windowSize.y-28},{118.f,8.f}},Pixel{247,183,82},BLACK,game->GetPlayer()->CurrentXP(),game->GetPlayer()->NextLevelXPRequired(),"xp")END;
|
|
|
|
struct AttributeData{
|
|
std::string attrName;
|
|
const std::function<int()>calcFunc;
|
|
};
|
|
|
|
const static std::array<AttributeData,7>displayAttrs{
|
|
AttributeData{"Health",[&]()->int{return game->GetPlayer()->GetMaxHealth();}},
|
|
AttributeData{"Attack",[&]()->int{return game->GetPlayer()->GetAttack();}},
|
|
AttributeData{"Defense",[&]()->int{return game->GetPlayer()->GetStat("Defense");}},
|
|
AttributeData{"Move Spd %",[&]()->int{return ceil(game->GetPlayer()->GetMoveSpdMult()*100);}},
|
|
AttributeData{"CDR",[&]()->int{return ceil(game->GetPlayer()->GetCooldownReductionPct()*100);}},
|
|
AttributeData{"Crit Rate",[&]()->int{return ceil(game->GetPlayer()->GetCritRatePct()*100);}},
|
|
AttributeData{"Crit Dmg",[&]()->int{return ceil(game->GetPlayer()->GetCritDmgPct()*100);}},
|
|
};
|
|
|
|
const static std::array<std::string,8>slotNames{"Helmet","Weapon","Armor","Gloves","Pants","Shoes","Ring 1","Ring 2"};
|
|
|
|
characterMenuWindow->ADD("Equip Selection Outline",MenuComponent)(geom2d::rect<float>{{123,28},{120,windowSize.y-37}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END
|
|
->Disable();
|
|
characterMenuWindow->ADD("Equip List",ScrollableWindowComponent)(geom2d::rect<float>{{123,28},{120,windowSize.y-37-24}})DEPTH -1 END
|
|
->Disable();
|
|
characterMenuWindow->ADD("Equip Selection Bottom Outline",MenuComponent)(geom2d::rect<float>{{123,28+(windowSize.y-37-24)},{120,24}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END
|
|
->Disable();
|
|
auto equipSelectionSelectButton=characterMenuWindow->ADD("Equip Selection Select Button",MenuComponent)(geom2d::rect<float>{{123+12,28+(windowSize.y-37-24)+6},{96,12}},"Select",
|
|
[](MenuFuncData data){
|
|
Component<MenuComponent>(data.component.lock()->parentMenu,"Equip Selection Outline")->Disable();
|
|
Component<ScrollableWindowComponent>(data.component.lock()->parentMenu,"Equip List")->Disable();
|
|
Component<MenuComponent>(data.component.lock()->parentMenu,"Equip Selection Bottom Outline")->Disable();
|
|
Component<MenuComponent>(data.component.lock()->parentMenu,"Equip Selection Select Button")->Disable();
|
|
Component<CharacterRotatingDisplay>(data.component.lock()->parentMenu,"Character Rotating Display")->Enable();
|
|
for(int counter=0;const AttributeData&attribute:displayAttrs){
|
|
std::weak_ptr<StatLabel>statDisplayLabel=Component<StatLabel>(CHARACTER_MENU,"Attribute "+std::string(ItemAttribute::Get(attribute.attrName).Name())+" Label");
|
|
statDisplayLabel.lock()->SetStatChangeAmt(0);
|
|
}
|
|
data.menu.SetSelection(std::string_view(std::format("Equip Slot {}",slotNames[std::bit_width(unsigned(data.menu.I(A::EQUIP_TYPE)))-1])));
|
|
equipmentWindowOpened=false;
|
|
return true;
|
|
})DEPTH 0 END;
|
|
|
|
equipSelectionSelectButton->Disable();
|
|
|
|
const static auto GetLabelText=[](ItemAttribute attribute){
|
|
std::string attrStr=std::string(attribute.Name())+"\n ";
|
|
attrStr+=std::to_string(game->GetPlayer()->GetStat(attribute));
|
|
if(attribute.DisplayAsPercent()){
|
|
attrStr+="%";
|
|
}
|
|
return attrStr;
|
|
};
|
|
|
|
int equipSlot=1;
|
|
for(int i=0;i<8;i++){
|
|
float x=31+(i%2)*33;
|
|
float y=24+(i/2)*28;
|
|
float labelX=0+(i%2)*88;
|
|
float labelY=24+(i/2)*28+36;
|
|
if(i<6){
|
|
y-=8;
|
|
labelY-=8;
|
|
}
|
|
EquipSlot slot=EquipSlot(equipSlot);
|
|
auto equipmentSlot=characterMenuWindow->ADD("Equip Slot "+slotNames[i],EquipSlotButton)(geom2d::rect<float>{{x,y+28},{24,24}},slot,
|
|
[&](MenuFuncData data){
|
|
EquipSlot slot=EquipSlot(data.component.lock()->I(Attribute::EQUIP_TYPE));
|
|
data.menu.I(A::EQUIP_TYPE)=int(slot);
|
|
|
|
const std::vector<std::shared_ptr<Item>>&equips=Inventory::get("Equipment");
|
|
const std::vector<std::shared_ptr<Item>>&accessories=Inventory::get("Accessories");
|
|
std::vector<std::weak_ptr<Item>>availableEquipment;
|
|
std::copy_if(equips.begin(),equips.end(),std::back_inserter(availableEquipment),[&](const std::shared_ptr<Item>it){
|
|
return it->GetEquipSlot()&slot;
|
|
});
|
|
std::copy_if(accessories.begin(),accessories.end(),std::back_inserter(availableEquipment),[&](const std::shared_ptr<Item>it){
|
|
return it->GetEquipSlot()&slot;
|
|
});
|
|
|
|
std::shared_ptr<ScrollableWindowComponent>equipList=Component<ScrollableWindowComponent>(data.component.lock()->parentMenu,"Equip List");
|
|
equipList->RemoveAllComponents();
|
|
for(int counter=0;const std::weak_ptr<Item>it:availableEquipment){
|
|
const static auto OppositeRingSlotDoesNotMatchCurrentEquip=[](std::weak_ptr<RowItemDisplay>comp){
|
|
EquipSlot slot=EquipSlot(comp.lock()->I(Attribute::EQUIP_TYPE));
|
|
std::weak_ptr<Item>otherItem;
|
|
if(slot&EquipSlot::RING1)otherItem=Inventory::GetEquip(EquipSlot::RING2);
|
|
else
|
|
if(slot&EquipSlot::RING2)otherItem=Inventory::GetEquip(EquipSlot::RING1);
|
|
return ISBLANK(otherItem)||(&*comp.lock()->GetItem().lock()!=&*otherItem.lock());
|
|
};
|
|
|
|
auto equip=equipList->ADD("Equip Item "+std::to_string(counter),RowItemDisplay)(geom2d::rect<float>{{2,2+counter*29.f},{120-15,28}},it,
|
|
[](MenuFuncData data){
|
|
std::weak_ptr<RowItemDisplay>comp=DYNAMIC_POINTER_CAST<RowItemDisplay>(data.component.lock());
|
|
if(!comp.expired()){
|
|
if(OppositeRingSlotDoesNotMatchCurrentEquip(comp.lock())){ //If we find that the opposite ring slot is equipped to us, this would be an item swap or the exact same ring, therefore no stat calculations apply.
|
|
Inventory::EquipItem(comp.lock()->GetItem(),EquipSlot(comp.lock()->I(Attribute::EQUIP_TYPE)));
|
|
if(Menu::IsCurrentlyActive(data.menu.GetType())){
|
|
SoundEffect::PlaySFX(comp.lock()->GetItem().lock()->UseSound(),SoundEffect::CENTERED);
|
|
}
|
|
for(std::weak_ptr<MenuComponent>button:DYNAMIC_POINTER_CAST<ScrollableWindowComponent>(data.parentComponent.lock())->GetComponents()){
|
|
std::weak_ptr<RowItemDisplay>comp=DYNAMIC_POINTER_CAST<RowItemDisplay>(button.lock());
|
|
comp.lock()->SetSelected(false);
|
|
}
|
|
comp.lock()->SetSelected(true);
|
|
for(int counter=0;const AttributeData&attribute:displayAttrs){
|
|
std::shared_ptr<StatLabel>statDisplayLabel=Component<StatLabel>(CHARACTER_MENU,"Attribute "+std::string(ItemAttribute::Get(attribute.attrName).Name())+" Label");
|
|
statDisplayLabel->SetStatChangeAmt(0);
|
|
}
|
|
std::shared_ptr<MenuItemItemButton>equipButton=Component<MenuItemItemButton>(CHARACTER_MENU,"Equip Slot "+slotNames[data.parentComponent.lock()->I(A::INDEXED_THEME)]);
|
|
equipButton->SetItem(comp.lock()->GetItem(),false);
|
|
}
|
|
}else{
|
|
ERR("WARNING! Attempting to cast a button that isn't a RowItemDisplay!");
|
|
}
|
|
return true;
|
|
},"Item Name","Item Description")END;
|
|
|
|
equip->SetHoverFunc(
|
|
[&](MenuFuncData data){
|
|
std::weak_ptr<RowItemDisplay>button=DYNAMIC_POINTER_CAST<RowItemDisplay>(data.component.lock());
|
|
if(!button.expired()){
|
|
const std::weak_ptr<Item>buttonItem=button.lock()->GetItem();
|
|
std::vector<float>statsBeforeEquip;
|
|
EquipSlot slot=EquipSlot(button.lock()->I(Attribute::EQUIP_TYPE));
|
|
for(const AttributeData&attribute:displayAttrs){
|
|
statsBeforeEquip.push_back(attribute.calcFunc());
|
|
}
|
|
|
|
int healthBeforeEquip=game->GetPlayer()->GetHealth();
|
|
int manaBeforeEquip=game->GetPlayer()->GetMana();
|
|
|
|
std::weak_ptr<Item>equippedItem=Inventory::GetEquip(slot);
|
|
std::weak_ptr<Item>otherItem;
|
|
if(slot&EquipSlot::RING1)otherItem=Inventory::GetEquip(EquipSlot::RING2);
|
|
else
|
|
if(slot&EquipSlot::RING2)otherItem=Inventory::GetEquip(EquipSlot::RING1);
|
|
if(OppositeRingSlotDoesNotMatchCurrentEquip(button.lock())){ //If we find that the opposite ring slot is equipped to us, this would be an item swap or the exact same ring, therefore no stat calculations apply.
|
|
Inventory::EquipItem(buttonItem,slot);
|
|
for(int counter=0;const AttributeData&attribute:displayAttrs){
|
|
std::weak_ptr<StatLabel>statDisplayLabel=Component<StatLabel>(CHARACTER_MENU,"Attribute "+std::string(ItemAttribute::Get(attribute.attrName).Name())+" Label");
|
|
int statChangeAmt=attribute.calcFunc()-statsBeforeEquip[counter];
|
|
statDisplayLabel.lock()->SetStatChangeAmt(statChangeAmt);
|
|
counter++;
|
|
}
|
|
Inventory::UnequipItem(slot);
|
|
if(!ISBLANK(equippedItem)){
|
|
Inventory::EquipItem(equippedItem,slot);
|
|
game->GetPlayer()->Heal(healthBeforeEquip-game->GetPlayer()->GetHealth(),true);
|
|
game->GetPlayer()->RestoreMana(manaBeforeEquip-game->GetPlayer()->GetMana(),true);
|
|
}
|
|
if(!ISBLANK(otherItem)){
|
|
if(slot==EquipSlot::RING1)Inventory::EquipItem(otherItem,EquipSlot::RING2);
|
|
else
|
|
if(slot==EquipSlot::RING2)Inventory::EquipItem(otherItem,EquipSlot::RING1);
|
|
}
|
|
}
|
|
}else{
|
|
ERR("WARNING! Attempting to cast a button that isn't a RowItemDisplay!");
|
|
}
|
|
return true;
|
|
});
|
|
equip->SetMouseOutFunc(
|
|
[](MenuFuncData data){
|
|
for(int counter=0;const AttributeData&attribute:displayAttrs){
|
|
std::weak_ptr<StatLabel>statDisplayLabel=Component<StatLabel>(CHARACTER_MENU,"Attribute "+std::string(ItemAttribute::Get(attribute.attrName).Name())+" Label");
|
|
statDisplayLabel.lock()->SetStatChangeAmt(0);
|
|
counter++;
|
|
}
|
|
return true;
|
|
});
|
|
|
|
equip->SetShowQuantity(false);
|
|
equip->SetSelectionType(SelectionType::NONE);
|
|
|
|
equip->I(Attribute::EQUIP_TYPE)=int(slot);
|
|
if(Inventory::GetEquip(slot)==it){
|
|
equip->SetSelected(true);
|
|
}
|
|
equip->SetCompactDescriptions(NON_COMPACT);
|
|
|
|
counter++;
|
|
}
|
|
|
|
equipList->I(Attribute::INDEXED_THEME)=data.component.lock()->I(Attribute::INDEXED_THEME);
|
|
Component<MenuComponent>(data.component.lock()->parentMenu,"Equip Selection Outline")->Enable();
|
|
equipList->Enable();
|
|
Component<MenuComponent>(data.component.lock()->parentMenu,"Equip Selection Bottom Outline")->Enable();
|
|
Component<MenuComponent>(data.component.lock()->parentMenu,"Equip Selection Select Button")->Enable();
|
|
Component<CharacterRotatingDisplay>(data.component.lock()->parentMenu,"Character Rotating Display")->Disable();
|
|
equipmentWindowOpened=true;
|
|
|
|
auto equipmentList=equipList->GetComponents();
|
|
auto itemEquipped=std::find_if(equipmentList.begin(),equipmentList.end(),[&](std::weak_ptr<MenuComponent>&component){
|
|
return !ISBLANK(Inventory::GetEquip(slot))&&&*DYNAMIC_POINTER_CAST<RowItemDisplay>(component)->GetItem().lock()==&*Inventory::GetEquip(slot).lock();
|
|
});
|
|
if(itemEquipped!=equipmentList.end()){
|
|
data.menu.SetSelection(*itemEquipped,true,true);
|
|
if(Menu::UsingMouseNavigation()){
|
|
equipList->HandleOutsideDisabledButtonSelection(*itemEquipped);
|
|
}
|
|
data.menu.I(A::ITEM_SLOT)=equipList->GetComponentIndex(*itemEquipped);
|
|
}else
|
|
if(equipmentList.size()>0){
|
|
data.menu.SetSelection(equipmentList[0],true,true);
|
|
if(Menu::UsingMouseNavigation()){
|
|
equipList->HandleOutsideDisabledButtonSelection(equipmentList[0]);
|
|
}
|
|
data.menu.I(A::ITEM_SLOT)=0;
|
|
}else{
|
|
data.menu.SetSelection("Equip Selection Select Button"sv);
|
|
}
|
|
|
|
return true;
|
|
},[](MenuFuncData data){//On Mouse Hover
|
|
EquipSlot slot=DYNAMIC_POINTER_CAST<EquipSlotButton>(data.component.lock())->GetSlot();
|
|
const std::weak_ptr<Item>equip=Inventory::GetEquip(slot);
|
|
if(!ISBLANK(equip)){
|
|
Component<CharacterRotatingDisplay>(data.component.lock()->parentMenu,"Character Rotating Display")->Disable();
|
|
}
|
|
return true;
|
|
},[](MenuFuncData data){//On Mouse Out
|
|
if(!equipmentWindowOpened){
|
|
Component<MenuLabel>(data.component.lock()->parentMenu,"Item Equip Description")->SetLabel("");
|
|
Component<MenuLabel>(data.component.lock()->parentMenu,"Item Equip Name")->Disable();
|
|
Component<MenuLabel>(data.component.lock()->parentMenu,"Item Equip Description")->Disable();
|
|
Component<CharacterRotatingDisplay>(data.component.lock()->parentMenu,"Character Rotating Display")->Enable();
|
|
}
|
|
return true;
|
|
},"Item Equip Name","Item Equip Description")END;
|
|
|
|
equipmentSlot->I(Attribute::EQUIP_TYPE)=int(slot);
|
|
equipmentSlot->I(Attribute::INDEXED_THEME)=i;
|
|
equipmentSlot->SetShowQuantity(false);
|
|
equipmentSlot->SetCompactDescriptions(false);
|
|
equipSlot<<=1;
|
|
characterMenuWindow->ADD("Equip Label "+slotNames[i],PopupMenuLabel)(geom2d::rect<float>{{labelX,labelY},{24,16}},slotNames[i],vf2d{0.5,1.f},ComponentAttr::SHADOW)END;
|
|
Menu::AddEquipStatListener(equipmentSlot);
|
|
}
|
|
|
|
characterMenuWindow->ADD("Stat Display Outline",MenuComponent)(geom2d::rect<float>{{245,28},{62,windowSize.y-37}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END;
|
|
|
|
int yOffset=0;
|
|
for(const AttributeData&attribute:displayAttrs){
|
|
std::string attrStr=GetLabelText(ItemAttribute::Get(attribute.attrName));
|
|
auto attrLabel=characterMenuWindow->ADD("Attribute "+std::string(ItemAttribute::Get(attribute.attrName).Name())+" Label",StatLabel)(geom2d::rect<float>{{245,28+2+float(yOffset)},{62,18}},ItemAttribute::Get(attribute.attrName),attribute.calcFunc,1,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN|ComponentAttr::FIT_TO_LABEL)END;
|
|
//Menu::AddEquipStatListener(attrLabel);
|
|
yOffset+=20;
|
|
}
|
|
|
|
characterMenuWindow->ADD("Back button",MenuComponent)(geom2d::rect<float>{{windowSize.x/2-64,windowSize.y-4.f},{128,12}},"Back",[](MenuFuncData data){Menu::stack.pop_back();return true;})END;
|
|
|
|
auto itemNameDisplay=characterMenuWindow->ADD("Item Name",MenuLabel)(geom2d::rect<float>{{0,28},{120,12}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::SHADOW|ComponentAttr::FIT_TO_LABEL)END;
|
|
auto itemDescriptionDisplay=characterMenuWindow->ADD("Item Description",MenuLabel)(geom2d::rect<float>{{0,40},{120,windowSize.y-49}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::SHADOW)END;
|
|
auto itemEquipNameDisplay=characterMenuWindow->ADD("Item Equip Name",MenuLabel)(geom2d::rect<float>{{123,28},{120,12}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::SHADOW|ComponentAttr::FIT_TO_LABEL)END;
|
|
auto itemEquipDescriptionDisplay=characterMenuWindow->ADD("Item Equip Description",MenuLabel)(geom2d::rect<float>{{123,40},{120,windowSize.y-49}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::SHADOW)END;
|
|
|
|
itemNameDisplay->Disable();
|
|
itemDescriptionDisplay->Disable();
|
|
itemEquipNameDisplay->Disable();
|
|
itemEquipDescriptionDisplay->Disable();
|
|
|
|
characterMenuWindow->SetupKeyboardNavigation(
|
|
[](MenuType type,Data&returnData){ //On Open
|
|
returnData=std::format("Equip Slot {}",slotNames[0]);
|
|
},
|
|
{ //Button Key
|
|
{{game->KEY_SHOULDER,Pressed},{"Scroll",[](MenuType type){}}},
|
|
{{game->KEY_SCROLL,Analog},{"Scroll",[](MenuType type){}}},
|
|
{{game->KEY_MOUSE_RIGHT,Pressed},{[](MenuFuncData data){
|
|
if(!data.menu.GetSelection().expired()&&
|
|
data.menu.GetSelection().lock()->GetName().starts_with("Equip Slot ")){
|
|
EquipSlot slot=EquipSlot(data.menu.GetSelection().lock()->I(Attribute::EQUIP_TYPE));
|
|
if(!ISBLANK(Inventory::GetEquip(slot))){
|
|
return "Unequip";
|
|
}
|
|
}
|
|
return "";
|
|
},[](MenuType type){
|
|
if(!Menu::menus[type]->GetSelection().expired()&&
|
|
Menu::menus[type]->GetSelection().lock()->GetName().starts_with("Equip Slot ")){
|
|
EquipSlot slot=EquipSlot(Menu::menus[type]->GetSelection().lock()->I(Attribute::EQUIP_TYPE));
|
|
if(!ISBLANK(Inventory::GetEquip(slot))){
|
|
Inventory::UnequipItem(slot);
|
|
if(slot&EquipSlot::RING1||slot&EquipSlot::RING2){
|
|
SoundEffect::PlaySFX("Unequip Accessory",SoundEffect::CENTERED);
|
|
}else{
|
|
SoundEffect::PlaySFX("Unequip Armor",SoundEffect::CENTERED);
|
|
}
|
|
}
|
|
}
|
|
}}},
|
|
{{game->KEY_FACELEFT,Pressed},{[](MenuFuncData data){
|
|
if(!data.menu.GetSelection().expired()&&
|
|
data.menu.GetSelection().lock()->GetName().starts_with("Equip Slot ")){
|
|
EquipSlot slot=EquipSlot(data.menu.GetSelection().lock()->I(Attribute::EQUIP_TYPE));
|
|
if(!ISBLANK(Inventory::GetEquip(slot))){
|
|
return "Unequip";
|
|
}
|
|
}
|
|
return "";
|
|
},[](MenuType type){
|
|
if(!Menu::menus[type]->GetSelection().expired()&&
|
|
Menu::menus[type]->GetSelection().lock()->GetName().starts_with("Equip Slot ")){
|
|
EquipSlot slot=EquipSlot(Menu::menus[type]->GetSelection().lock()->I(Attribute::EQUIP_TYPE));
|
|
if(!ISBLANK(Inventory::GetEquip(slot))){
|
|
Inventory::UnequipItem(slot);
|
|
if(slot&EquipSlot::RING1||slot&EquipSlot::RING2){
|
|
SoundEffect::PlaySFX("Unequip Accessory",SoundEffect::CENTERED);
|
|
}else{
|
|
SoundEffect::PlaySFX("Unequip Armor",SoundEffect::CENTERED);
|
|
}
|
|
}
|
|
}
|
|
}}},
|
|
{game->KEY_BACK,{"Back",[](MenuType type){
|
|
if(!Menu::menus[type]->GetSelection().expired()&&
|
|
!Menu::menus[type]->GetSelection().lock()->parentComponent.expired()&&
|
|
Menu::menus[type]->GetSelection().lock()->parentComponent.lock()->GetName()=="Equip List"){
|
|
Component<MenuComponent>(type,"Equip Selection Select Button")->Click();
|
|
}else{
|
|
Component<MenuComponent>(type,"Back button")->Click();
|
|
}
|
|
}}},
|
|
{game->KEY_CONFIRM,{"Select",[](MenuType type){}}},
|
|
{{game->KEY_SCROLLVERT,Analog,InputEngageGroup::NOT_VISIBLE},{"Scroll",[](MenuType type){
|
|
if(!Menu::menus[type]->GetSelection().expired()&&
|
|
!Menu::menus[type]->GetSelection().lock()->parentComponent.expired()&&
|
|
Menu::menus[type]->GetSelection().lock()->parentComponent.lock()->GetName()=="Equip List"){
|
|
float scrollAmt=0.f;
|
|
if(game->KEY_SCROLLVERT.AnalogDAS()>0.f)scrollAmt=1.f;
|
|
else if(game->KEY_SCROLLVERT.AnalogDAS()<0.f)scrollAmt=-1.f;
|
|
Menu::menus[type]->GetSelection().lock()->parentComponent.lock()->IncreaseSelectionIndex(scrollAmt);
|
|
}
|
|
}}},
|
|
{{game->KEY_FASTSCROLLUP,PressedDAS,InputEngageGroup::NOT_VISIBLE},{"Scroll",[](MenuType type){
|
|
if(!Menu::menus[type]->GetSelection().expired()&&
|
|
!Menu::menus[type]->GetSelection().lock()->parentComponent.expired()&&
|
|
Menu::menus[type]->GetSelection().lock()->parentComponent.lock()->GetName()=="Equip List"){
|
|
Menu::menus[type]->GetSelection().lock()->parentComponent.lock()->IncreaseSelectionIndex(-3.f);
|
|
}
|
|
}}},
|
|
{{game->KEY_FASTSCROLLDOWN,PressedDAS,InputEngageGroup::NOT_VISIBLE},{"Scroll",[](MenuType type){
|
|
if(!Menu::menus[type]->GetSelection().expired()&&
|
|
!Menu::menus[type]->GetSelection().lock()->parentComponent.expired()&&
|
|
Menu::menus[type]->GetSelection().lock()->parentComponent.lock()->GetName()=="Equip List"){
|
|
Menu::menus[type]->GetSelection().lock()->parentComponent.lock()->IncreaseSelectionIndex(3.f);
|
|
}
|
|
}}},
|
|
{{game->KEY_FASTSCROLLUP,PressedDAS,InputEngageGroup::NOT_VISIBLE},{"Scroll",[](MenuType type){
|
|
if(!Menu::menus[type]->GetSelection().expired()&&
|
|
!Menu::menus[type]->GetSelection().lock()->parentComponent.expired()&&
|
|
Menu::menus[type]->GetSelection().lock()->parentComponent.lock()->GetName()=="Equip List"){
|
|
Menu::menus[type]->GetSelection().lock()->parentComponent.lock()->IncreaseSelectionIndex(-3.f);
|
|
}
|
|
}}},
|
|
}
|
|
,{ //Button Navigation Rules
|
|
{"Equip List",{
|
|
.up=[](MenuType type,Data&returnData){
|
|
if(!Menu::menus[type]->GetSelection().expired()){
|
|
auto selection=Menu::menus[type]->GetSelection().lock();
|
|
size_t index=Component<ScrollableWindowComponent>(type,"Equip List")->GetComponentIndex(selection);
|
|
index--;
|
|
if(index>=Component<ScrollableWindowComponent>(type,"Equip List")->GetComponents().size()){
|
|
returnData="Equip Selection Select Button";
|
|
}else{
|
|
returnData=Component<ScrollableWindowComponent>(type,"Equip List")->GetComponents()[index];
|
|
}
|
|
}
|
|
},
|
|
.down=[](MenuType type,Data&returnData){
|
|
if(!Menu::menus[type]->GetSelection().expired()){
|
|
auto selection=Menu::menus[type]->GetSelection().lock();
|
|
size_t index=Component<ScrollableWindowComponent>(type,"Equip List")->GetComponentIndex(selection);
|
|
index++;
|
|
if(index>=Component<ScrollableWindowComponent>(type,"Equip List")->GetComponents().size()){
|
|
returnData="Equip Selection Select Button";
|
|
}else{
|
|
returnData=Component<ScrollableWindowComponent>(type,"Equip List")->GetComponents()[index];
|
|
}
|
|
}
|
|
},
|
|
.left=[](MenuType type,Data&returnData){
|
|
auto equipList=Component<ScrollableWindowComponent>(type,"Equip List")->GetComponents();
|
|
returnData=std::format("Equip Slot {}",slotNames[std::bit_width(unsigned(Menu::menus[type]->I(A::EQUIP_TYPE)))-1]);
|
|
},
|
|
.right=[](MenuType type,Data&returnData){
|
|
auto equipList=Component<ScrollableWindowComponent>(type,"Equip List")->GetComponents();
|
|
returnData=std::format("Equip Slot {}",slotNames[std::bit_width(unsigned(Menu::menus[type]->I(A::EQUIP_TYPE)))-1]);
|
|
}
|
|
}},
|
|
{"Equip Selection Select Button",{
|
|
.up=[](MenuType type,Data&returnData){
|
|
auto equipList=Component<ScrollableWindowComponent>(type,"Equip List")->GetComponents();
|
|
returnData="Equip Selection Select Button";
|
|
if(equipList.size()>0){
|
|
returnData=equipList.back();
|
|
}
|
|
},
|
|
.down=[](MenuType type,Data&returnData){
|
|
auto equipList=Component<ScrollableWindowComponent>(type,"Equip List")->GetComponents();
|
|
returnData="Equip Selection Select Button";
|
|
if(equipList.size()>0){
|
|
returnData=equipList.front();
|
|
}
|
|
},
|
|
.left=[](MenuType type,Data&returnData){
|
|
auto equipList=Component<ScrollableWindowComponent>(type,"Equip List")->GetComponents();
|
|
returnData=std::format("Equip Slot {}",slotNames[std::bit_width(unsigned(Menu::menus[type]->I(A::EQUIP_TYPE)))-1]);
|
|
},
|
|
.right=[](MenuType type,Data&returnData){
|
|
auto equipList=Component<ScrollableWindowComponent>(type,"Equip List")->GetComponents();
|
|
returnData=std::format("Equip Slot {}",slotNames[std::bit_width(unsigned(Menu::menus[type]->I(A::EQUIP_TYPE)))-1]);
|
|
}
|
|
}},
|
|
{std::format("Equip Slot {}", slotNames[0]),{
|
|
.up="Back button",
|
|
.down=std::format("Equip Slot {}", slotNames[2]),
|
|
.left=[&](MenuType type,Data&returnData){
|
|
if(equipmentWindowOpened){
|
|
returnData=Component<ScrollableWindowComponent>(type,"Equip List")->GetComponents()[unsigned(Menu::menus[type]->I(A::ITEM_SLOT))];
|
|
}else{
|
|
returnData=std::format("Equip Slot {}",slotNames[1]);
|
|
}
|
|
},
|
|
.right=std::format("Equip Slot {}", slotNames[1]),}},
|
|
{std::format("Equip Slot {}", slotNames[1]),{
|
|
.up="Back button",
|
|
.down=std::format("Equip Slot {}", slotNames[3]),
|
|
.left=std::format("Equip Slot {}", slotNames[0]),
|
|
.right=[](MenuType type,Data&returnData){
|
|
if(equipmentWindowOpened){
|
|
returnData=Component<ScrollableWindowComponent>(type,"Equip List")->GetComponents()[unsigned(Menu::menus[type]->I(A::ITEM_SLOT))];
|
|
}else{
|
|
returnData=std::format("Equip Slot {}",slotNames[0]);
|
|
}
|
|
},}},
|
|
{std::format("Equip Slot {}", slotNames[2]),{
|
|
.up=std::format("Equip Slot {}", slotNames[0]),
|
|
.down=std::format("Equip Slot {}", slotNames[4]),
|
|
.left=[](MenuType type,Data&returnData){
|
|
if(equipmentWindowOpened){
|
|
returnData=Component<ScrollableWindowComponent>(type,"Equip List")->GetComponents()[unsigned(Menu::menus[type]->I(A::ITEM_SLOT))];
|
|
}else{
|
|
returnData=std::format("Equip Slot {}",slotNames[3]);
|
|
}
|
|
},
|
|
.right=std::format("Equip Slot {}", slotNames[3]),}},
|
|
{std::format("Equip Slot {}", slotNames[3]),{
|
|
.up=std::format("Equip Slot {}", slotNames[1]),
|
|
.down=std::format("Equip Slot {}", slotNames[5]),
|
|
.left=std::format("Equip Slot {}", slotNames[2]),
|
|
.right=[](MenuType type,Data&returnData){
|
|
if(equipmentWindowOpened){
|
|
returnData=Component<ScrollableWindowComponent>(type,"Equip List")->GetComponents()[unsigned(Menu::menus[type]->I(A::ITEM_SLOT))];
|
|
}else{
|
|
returnData=std::format("Equip Slot {}",slotNames[2]);
|
|
}
|
|
},}},
|
|
{std::format("Equip Slot {}", slotNames[4]),{
|
|
.up=std::format("Equip Slot {}", slotNames[2]),
|
|
.down=std::format("Equip Slot {}", slotNames[6]),
|
|
.left=[](MenuType type,Data&returnData){
|
|
if(equipmentWindowOpened){
|
|
returnData=Component<ScrollableWindowComponent>(type,"Equip List")->GetComponents()[unsigned(Menu::menus[type]->I(A::ITEM_SLOT))];
|
|
}else{
|
|
returnData=std::format("Equip Slot {}",slotNames[5]);
|
|
}
|
|
},
|
|
.right=std::format("Equip Slot {}", slotNames[5]),
|
|
}},
|
|
{std::format("Equip Slot {}", slotNames[5]),{
|
|
.up=std::format("Equip Slot {}", slotNames[3]),
|
|
.down=std::format("Equip Slot {}", slotNames[7]),
|
|
.left=std::format("Equip Slot {}", slotNames[4]),
|
|
.right=[](MenuType type,Data&returnData){
|
|
if(equipmentWindowOpened){
|
|
returnData=Component<ScrollableWindowComponent>(type,"Equip List")->GetComponents()[unsigned(Menu::menus[type]->I(A::ITEM_SLOT))];
|
|
}else{
|
|
returnData=std::format("Equip Slot {}",slotNames[4]);
|
|
}
|
|
},}},
|
|
{std::format("Equip Slot {}", slotNames[6]),{
|
|
.up=std::format("Equip Slot {}", slotNames[4]),
|
|
.down="Back button",
|
|
.left=[](MenuType type,Data&returnData){
|
|
if(equipmentWindowOpened){
|
|
returnData=Component<ScrollableWindowComponent>(type,"Equip List")->GetComponents()[unsigned(Menu::menus[type]->I(A::ITEM_SLOT))];
|
|
}else{
|
|
returnData=std::format("Equip Slot {}",slotNames[7]);
|
|
}
|
|
},
|
|
.right=std::format("Equip Slot {}",slotNames[7]),
|
|
}},
|
|
{std::format("Equip Slot {}", slotNames[7]),{
|
|
.up=std::format("Equip Slot {}", slotNames[5]),
|
|
.down="Back button",
|
|
.left=std::format("Equip Slot {}",slotNames[6]),
|
|
.right=[](MenuType type,Data&returnData){
|
|
if(equipmentWindowOpened){
|
|
returnData=Component<ScrollableWindowComponent>(type,"Equip List")->GetComponents()[unsigned(Menu::menus[type]->I(A::ITEM_SLOT))];
|
|
}else{
|
|
returnData=std::format("Equip Slot {}",slotNames[6]);
|
|
}
|
|
},}},
|
|
{"Back button",{
|
|
.up=std::format("Equip Slot {}", slotNames[7]),
|
|
.down=std::format("Equip Slot {}", slotNames[0]),
|
|
.left=std::format("Equip Slot {}", slotNames[7]),
|
|
.right=std::format("Equip Slot {}",slotNames[6]),
|
|
}},
|
|
});
|
|
} |