# 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 "AccessoryRowItemDisplay.h"
# include "SoundEffect.h"
# include "ProgressBar.h"
# include "MenuItemLabel.h"
# ifndef __EMSCRIPTEN__
# include "steam/isteamuserstats.h"
# endif
INCLUDE_game
INCLUDE_GFX
namespace CharacterMenuWindow {
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 ( ) - > GetDefense ( ) ; } } ,
AttributeData { " Move Spd % " , [ ] ( ) - > int { return round ( game - > GetPlayer ( ) - > GetMoveSpdMult ( ) * 100 ) ; } } ,
AttributeData { " CDR " , [ ] ( ) - > int { return round ( game - > GetPlayer ( ) - > GetCooldownReductionPct ( ) * 100 ) ; } } ,
AttributeData { " Crit Rate " , [ ] ( ) - > int { return round ( game - > GetPlayer ( ) - > GetCritRatePct ( ) * 100 ) ; } } ,
AttributeData { " Crit Dmg " , [ ] ( ) - > int { return round ( game - > GetPlayer ( ) - > GetCritDmgPct ( ) * 100 ) ; } } ,
} ;
const static std : : array < std : : string , 8 > slotNames { " Helmet " , " Weapon " , " Armor " , " Gloves " , " Pants " , " Shoes " , " Ring 1 " , " Ring 2 " } ;
template < class T >
std : : shared_ptr < RowItemDisplay > GenerateItemDisplay ( std : : shared_ptr < ScrollableWindowComponent > parent , int invIndex , const std : : weak_ptr < Item > it ) {
auto component = parent - > ADD ( " Equip Item " + std : : to_string ( invIndex ) , T ) ( geom2d : : rect < float > { { 2 , 2 + invIndex * 29.f } , { 120 - 15 , 28 } } , it ,
[ & ] ( MenuFuncData data ) {
std : : weak_ptr < T > comp = DYNAMIC_POINTER_CAST < T > ( data . component . lock ( ) ) ;
if ( ! comp . expired ( ) ) {
if ( Item : : SelectedEquipIsDifferent ( comp . lock ( ) - > GetItem ( ) , EquipSlot ( comp . lock ( ) - > I ( Attribute : : EQUIP_TYPE ) ) ) ) { //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 ) ) ) ;
# pragma region Fully Decked Out Achievement
STEAMUSERSTATS (
datafile & unlock = DATA . GetProperty ( " Achievement.Equip Unlocks.Fully Decked Out " ) ;
if ( Inventory : : EquipsFullyMaxedOut ( unlock [ " Weapon Max Level " ] . GetInt ( ) , unlock [ " Armor Max Level " ] . GetInt ( ) ) ) {
SteamUserStats ( ) - > SetAchievement ( unlock [ " API Name " ] . GetString ( ) . c_str ( ) ) ;
SteamUserStats ( ) - > StoreStats ( ) ;
}
)
# pragma endregion
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 < T > comp = DYNAMIC_POINTER_CAST < T > ( 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 ;
} , " " , " " ) END ;
return component ;
}
} ;
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 * 0.5f ) - 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 ;
//Don't load this graphical element if testing mode is enabled.
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 Outline " , MenuComponent ) ( geom2d : : rect < float > { { windowSize . x * 0.5f + 4.f , - 4 } , { float ( windowSize . x * 0.5f ) - 4 , 24 } } , " " , DO_NOTHING , ButtonAttr : : UNSELECTABLE ) END ;
characterMenuWindow - > ADD ( " Level Class Display " , MenuLabel ) ( geom2d : : rect < float > { vf2d { windowSize . x * 0.5f + 10.f , 0.f } , { 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 { windowSize . x * 0.5f + 10.f , 10.f } , { 118.f , 8.f } } , Pixel { 247 , 183 , 82 } , BLACK , game - > GetPlayer ( ) - > CurrentXP ( ) , game - > GetPlayer ( ) - > NextLevelXPRequired ( ) , " xp " ) END ;
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 CharacterMenuWindow : : AttributeData & attribute : CharacterMenuWindow : : 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 {} " , CharacterMenuWindow : : 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 ( ) - > GetEquipStat ( 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 " + CharacterMenuWindow : : slotNames [ i ] , EquipSlotButton ) ( geom2d : : rect < float > { { x , y + 28 } , { 24 , 24 } } , slot ,
[ & ] ( MenuFuncData data ) {
if ( game - > GetCurrentMap ( ) . GetMapType ( ) ! = Map : : MapType : : HUB & & game - > GetCurrentMap ( ) . GetMapType ( ) ! = Map : : MapType : : WORLD_MAP ) {
game - > AddNotification ( AiL : : Notification { " Cannot change equipment in a stage! " , 5.f , YELLOW } ) ;
return false ;
}
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 ) {
std : : shared_ptr < RowItemDisplay > equip ;
const bool isAccessorySlot = slot & ( EquipSlot : : RING1 | EquipSlot : : RING2 ) ;
if ( isAccessorySlot ) {
equip = CharacterMenuWindow : : GenerateItemDisplay < AccessoryRowItemDisplay > ( equipList , counter , it ) ;
} else {
equip = CharacterMenuWindow : : GenerateItemDisplay < RowItemDisplay > ( equipList , counter , it ) ;
}
equip - > SetHoverFunc (
[ & ] ( MenuFuncData data ) {
if ( ! data . component . lock ( ) - > GetSubcomponentParent ( ) . expired ( ) ) return true ;
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 CharacterMenuWindow : : AttributeData & attribute : CharacterMenuWindow : : 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 ( Item : : SelectedEquipIsDifferent ( button . lock ( ) - > GetItem ( ) , slot ) ) { //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 CharacterMenuWindow : : AttributeData & attribute : CharacterMenuWindow : : 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 ) ;
}
}
Component < MenuItemLabel > ( data . menu . GetType ( ) , " Item Name " ) - > SetItem ( buttonItem ) ;
Component < MenuItemLabel > ( data . menu . GetType ( ) , " Item Description " ) - > SetItem ( buttonItem ) ;
Component < MenuItemLabel > ( data . menu . GetType ( ) , " Item Name " ) - > Enable ( ) ;
Component < MenuItemLabel > ( data . menu . GetType ( ) , " Item Description " ) - > Enable ( ) ;
} else {
ERR ( " WARNING! Attempting to cast a button that isn't a RowItemDisplay! " ) ;
}
return true ;
} ) ;
equip - > SetMouseOutFunc (
[ ] ( MenuFuncData data ) {
for ( int counter = 0 ; const CharacterMenuWindow : : AttributeData & attribute : CharacterMenuWindow : : displayAttrs ) {
std : : weak_ptr < StatLabel > statDisplayLabel = Component < StatLabel > ( CHARACTER_MENU , " Attribute " + std : : string ( ItemAttribute : : Get ( attribute . attrName ) . Name ( ) ) + " Label " ) ;
statDisplayLabel . lock ( ) - > SetStatChangeAmt ( 0 ) ;
counter + + ;
}
Component < MenuItemLabel > ( data . menu . GetType ( ) , " Item Name " ) - > Disable ( ) ;
Component < MenuItemLabel > ( data . menu . GetType ( ) , " Item Description " ) - > Disable ( ) ;
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 ) ) & & component . lock ( ) - > GetSubcomponentParent ( ) . expired ( ) & & & * 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 " + CharacterMenuWindow : : slotNames [ i ] , PopupMenuLabel ) ( geom2d : : rect < float > { { labelX , labelY } , { 24 , 16 } } , CharacterMenuWindow : : 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 CharacterMenuWindow : : AttributeData & attribute : CharacterMenuWindow : : 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 ;
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 " , MenuItemLabel ) ( geom2d : : rect < float > { { 0 , 28 } , { 120 , 12 } } , std : : weak_ptr < Item > { } , ITEM_NAME , 1.f , ComponentAttr : : BACKGROUND | ComponentAttr : : LEFT_ALIGN | ComponentAttr : : OUTLINE | ComponentAttr : : SHADOW | ComponentAttr : : FIT_TO_LABEL ) END ;
auto itemDescriptionDisplay = characterMenuWindow - > ADD ( " Item Description " , MenuItemLabel ) ( geom2d : : rect < float > { { 0 , 40 } , { 120 , windowSize . y - 49 } } , std : : weak_ptr < Item > { } , ITEM_DESCRIPTION , 1.f , 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 {} " , CharacterMenuWindow : : slotNames [ 0 ] ) ;
} ,
{ //Button Key
{ { game - > KEY_SHOULDER2 , Pressed } , { " Scroll " , [ ] ( MenuType type ) { } } } ,
{ { 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 " ) | |
Menu : : menus [ type ] - > GetSelection ( ) . lock ( ) - > GetName ( ) = = " Equip Selection Select Button " ) {
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 ) ;
}
} } } ,
{ game - > KEY_SELECT , { [ ] ( MenuFuncData data ) {
if ( ! data . menu . GetSelection ( ) . expired ( ) & &
! data . menu . GetSelection ( ) . lock ( ) - > parentComponent . expired ( ) & &
data . menu . GetSelection ( ) . lock ( ) - > parentComponent . lock ( ) - > GetName ( ) = = " Equip List "
& & data . component . lock ( ) - > GetSubcomponentParent ( ) . expired ( )
& & EquipSlot ( data . menu . I ( A : : EQUIP_TYPE ) ) & ( EquipSlot : : RING1 | EquipSlot : : RING2 ) ) {
if ( DYNAMIC_POINTER_CAST < AccessoryRowItemDisplay > ( data . menu . GetSelection ( ) . lock ( ) ) - > GetItem ( ) . lock ( ) - > IsLocked ( ) ) {
return " Unlock " ;
} else {
return " Lock " ;
}
}
return " " ;
} , [ ] ( 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 ( ) - > GetSubcomponentParent ( ) . expired ( ) ) {
DYNAMIC_POINTER_CAST < AccessoryRowItemDisplay > ( Menu : : menus [ type ] - > GetSelection ( ) . lock ( ) ) - > GetLockButton ( ) . lock ( ) - > Click ( ) ;
}
} } } ,
}
, { //Button Navigation Rules
{ " Equip List " , {
. up = [ ] ( MenuType type , Data & returnData ) {
Menu : : ScrollUp ( type , " Equip List " , returnData , " Equip Selection Select Button " ) ;
} ,
. down = [ ] ( MenuType type , Data & returnData ) {
Menu : : ScrollDown ( type , " Equip List " , returnData , " Equip Selection Select Button " ) ;
} ,
. left = [ ] ( MenuType type , Data & returnData ) {
auto equipList = Component < ScrollableWindowComponent > ( type , " Equip List " ) - > GetComponents ( ) ;
returnData = std : : format ( " Equip Slot {} " , CharacterMenuWindow : : 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 {} " , CharacterMenuWindow : : 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 {} " , CharacterMenuWindow : : 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 {} " , CharacterMenuWindow : : slotNames [ std : : bit_width ( unsigned ( Menu : : menus [ type ] - > I ( A : : EQUIP_TYPE ) ) ) - 1 ] ) ;
}
} } ,
{ std : : format ( " Equip Slot {} " , CharacterMenuWindow : : slotNames [ 0 ] ) , {
. up = " Back button " ,
. down = std : : format ( " Equip Slot {} " , CharacterMenuWindow : : 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 {} " , CharacterMenuWindow : : slotNames [ 1 ] ) ;
}
} ,
. right = std : : format ( " Equip Slot {} " , CharacterMenuWindow : : slotNames [ 1 ] ) , } } ,
{ std : : format ( " Equip Slot {} " , CharacterMenuWindow : : slotNames [ 1 ] ) , {
. up = " Back button " ,
. down = std : : format ( " Equip Slot {} " , CharacterMenuWindow : : slotNames [ 3 ] ) ,
. left = std : : format ( " Equip Slot {} " , CharacterMenuWindow : : 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 {} " , CharacterMenuWindow : : slotNames [ 0 ] ) ;
}
} , } } ,
{ std : : format ( " Equip Slot {} " , CharacterMenuWindow : : slotNames [ 2 ] ) , {
. up = std : : format ( " Equip Slot {} " , CharacterMenuWindow : : slotNames [ 0 ] ) ,
. down = std : : format ( " Equip Slot {} " , CharacterMenuWindow : : 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 {} " , CharacterMenuWindow : : slotNames [ 3 ] ) ;
}
} ,
. right = std : : format ( " Equip Slot {} " , CharacterMenuWindow : : slotNames [ 3 ] ) , } } ,
{ std : : format ( " Equip Slot {} " , CharacterMenuWindow : : slotNames [ 3 ] ) , {
. up = std : : format ( " Equip Slot {} " , CharacterMenuWindow : : slotNames [ 1 ] ) ,
. down = std : : format ( " Equip Slot {} " , CharacterMenuWindow : : slotNames [ 5 ] ) ,
. left = std : : format ( " Equip Slot {} " , CharacterMenuWindow : : 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 {} " , CharacterMenuWindow : : slotNames [ 2 ] ) ;
}
} , } } ,
{ std : : format ( " Equip Slot {} " , CharacterMenuWindow : : slotNames [ 4 ] ) , {
. up = std : : format ( " Equip Slot {} " , CharacterMenuWindow : : slotNames [ 2 ] ) ,
. down = std : : format ( " Equip Slot {} " , CharacterMenuWindow : : 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 {} " , CharacterMenuWindow : : slotNames [ 5 ] ) ;
}
} ,
. right = std : : format ( " Equip Slot {} " , CharacterMenuWindow : : slotNames [ 5 ] ) ,
} } ,
{ std : : format ( " Equip Slot {} " , CharacterMenuWindow : : slotNames [ 5 ] ) , {
. up = std : : format ( " Equip Slot {} " , CharacterMenuWindow : : slotNames [ 3 ] ) ,
. down = std : : format ( " Equip Slot {} " , CharacterMenuWindow : : slotNames [ 7 ] ) ,
. left = std : : format ( " Equip Slot {} " , CharacterMenuWindow : : 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 {} " , CharacterMenuWindow : : slotNames [ 4 ] ) ;
}
} , } } ,
{ std : : format ( " Equip Slot {} " , CharacterMenuWindow : : slotNames [ 6 ] ) , {
. up = std : : format ( " Equip Slot {} " , CharacterMenuWindow : : 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 {} " , CharacterMenuWindow : : slotNames [ 7 ] ) ;
}
} ,
. right = std : : format ( " Equip Slot {} " , CharacterMenuWindow : : slotNames [ 7 ] ) ,
} } ,
{ std : : format ( " Equip Slot {} " , CharacterMenuWindow : : slotNames [ 7 ] ) , {
. up = std : : format ( " Equip Slot {} " , CharacterMenuWindow : : slotNames [ 5 ] ) ,
. down = " Back button " ,
. left = std : : format ( " Equip Slot {} " , CharacterMenuWindow : : 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 {} " , CharacterMenuWindow : : slotNames [ 6 ] ) ;
}
} , } } ,
{ " Back button " , {
. up = std : : format ( " Equip Slot {} " , CharacterMenuWindow : : slotNames [ 7 ] ) ,
. down = std : : format ( " Equip Slot {} " , CharacterMenuWindow : : slotNames [ 0 ] ) ,
. left = std : : format ( " Equip Slot {} " , CharacterMenuWindow : : slotNames [ 7 ] ) ,
. right = std : : format ( " Equip Slot {} " , CharacterMenuWindow : : slotNames [ 6 ] ) ,
} } ,
} ) ;
}