# 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 <EFBFBD> 2024 The FreeType
Project ( www . freetype . org ) . Please see LICENSE_FT . txt for more information .
All rights reserved .
*/
# pragma endregion
# include "Menu.h"
# include "AdventuresInLestoria.h"
# include "RowInventoryScrollableWindowComponent.h"
# include "MenuItemItemButton.h"
# include "MenuItemLabel.h"
# include "MenuDecal.h"
# include "PlayerMoneyLabel.h"
# include "SoundEffect.h"
INCLUDE_game
void Menu : : InitializeArtificerEnchantWindow ( ) {
Menu * artificerEnchantWindow = CreateMenu ( ARTIFICER_ENCHANT , CENTERED , game - > GetScreenSize ( ) - vi2d { 52 , 52 } ) ;
auto enchantingTitleLabel { artificerEnchantWindow - > ADD ( " Enchanting Title Label " , MenuLabel ) ( geom2d : : rect < float > { { 0.f , - 16.f } , { artificerEnchantWindow - > size . x , 24.f } } , " Accessory Enchanting " , 2.f , ComponentAttr : : SHADOW | ComponentAttr : : OUTLINE | ComponentAttr : : BACKGROUND ) END } ;
auto inventoryLabel { artificerEnchantWindow - > ADD ( " Accessory List Label " , MenuLabel ) ( geom2d : : rect < float > { { 0.f , 12.f } , { 180.f , 12.f } } , " Choose Accessory: " , 1.f , ComponentAttr : : SHADOW | ComponentAttr : : LEFT_ALIGN ) END } ;
auto itemIcon { artificerEnchantWindow - > ADD ( " Item Icon " , MenuItemItemButton ) ( geom2d : : rect < float > ( { artificerEnchantWindow - > size . x / 2 + 4.f , 16.f } , { 48 , 48 } ) , Item : : BLANK , DO_NOTHING , " " , " Item Description " , IconButtonAttr : : NOT_SELECTABLE ) END } ;
itemIcon - > SetIconScale ( { 2.f , 2.f } ) ;
itemIcon - > SetCompactDescriptions ( true ) ;
auto accessoryDescription { artificerEnchantWindow - > ADD ( " Item Description " , MenuLabel ) ( geom2d : : rect < float > { { artificerEnchantWindow - > size . x / 2 + 56.f , 16.f } , { artificerEnchantWindow - > size . x / 2 - 40.f , 72.f } } , " " , 0.5f , ComponentAttr : : BACKGROUND | ComponentAttr : : OUTLINE | ComponentAttr : : SHADOW | ComponentAttr : : LEFT_ALIGN ) END } ;
const auto ResetEnchantDisplay { [ artificerEnchantWindow ] ( ) {
MenuType menuType { artificerEnchantWindow - > GetType ( ) } ;
Component < MenuItemItemButton > ( menuType , " Item Icon " ) - > SetItem ( Item : : BLANK ) ;
Component < ScrollableWindowComponent > ( menuType , " Enchant Container " ) - > Disable ( ) ;
Component < MenuLabel > ( menuType , " Enchant List Header " ) - > Disable ( ) ;
Component < MenuLabel > ( menuType , " Enchant Cost Label " ) - > Disable ( ) ;
Component < MenuDecal > ( menuType , " Fragment Cost Icon " ) - > Disable ( ) ;
Component < MenuLabel > ( menuType , " Fragment Label " ) - > Disable ( ) ;
Component < MenuLabel > ( menuType , " Fragment Money Cost Label " ) - > Disable ( ) ;
Component < MenuComponent > ( menuType , " Fragment Enchant Button " ) - > Disable ( ) ;
} } ;
const auto EnableEnchantDisplay { [ artificerEnchantWindow ] ( ) {
MenuType menuType { artificerEnchantWindow - > GetType ( ) } ;
const std : : weak_ptr < Item > & selectedItem { Component < MenuItemItemButton > ( menuType , " Item Icon " ) - > GetItem ( ) } ;
std : : vector < ItemEnchantInfo > availableEnchants { ItemEnchant : : GetAvailableEnchants ( ) } ;
std : : sort ( availableEnchants . begin ( ) , availableEnchants . end ( ) , [ ] ( const ItemEnchantInfo & enchant1 , const ItemEnchantInfo & enchant2 ) {
return enchant1 . Category ( ) ! = enchant2 . Category ( ) ? int ( enchant1 . Category ( ) ) < int ( enchant2 . Category ( ) ) : enchant1 . Name ( ) < enchant2 . Name ( ) ;
} ) ;
std : : string enchantList { std : : accumulate ( availableEnchants . begin ( ) , availableEnchants . end ( ) , " " s , [ ] ( const std : : string & acc , const ItemEnchantInfo & enchant ) {
return std : : format ( " {}{}{}#FFFFFF \n " , acc , enchant . DisplayCol ( ) . toHTMLColorCode ( ) , enchant . Name ( ) ) ;
} ) } ;
Component < ScrollableWindowComponent > ( menuType , " Enchant Container " ) - > Enable ( ) ;
Component < MenuLabel > ( menuType , " Enchant List " ) - > SetLabel ( enchantList ) ;
Component < MenuLabel > ( menuType , " Enchant List Header " ) - > Enable ( ) ;
Component < MenuLabel > ( menuType , " Enchant Cost Label " ) - > Enable ( ) ;
Component < MenuDecal > ( menuType , " Fragment Cost Icon " ) - > Enable ( ) ;
Component < MenuDecal > ( menuType , " Fragment Cost Icon " ) - > SetImage ( GFX . at ( selectedItem . lock ( ) - > FragmentIcon ( ) . value ( ) ) ) ;
Component < MenuLabel > ( menuType , " Fragment Label " ) - > Enable ( ) ;
Component < MenuLabel > ( menuType , " Fragment Money Cost Label " ) - > Enable ( ) ;
Component < MenuComponent > ( menuType , " Fragment Enchant Button " ) - > Enable ( ) ;
Component < MenuComponent > ( menuType , " Fragment Enchant Button " ) - > SetGrayedOut ( ! selectedItem . lock ( ) - > CanBeEnchanted ( ) ) ;
const std : : string_view fragmentName { selectedItem . lock ( ) - > FragmentName ( ) } ;
const Pixel fragmentItemDisplayCol { Inventory : : GetItemCount ( fragmentName ) > = " Fragment Enchant Cost " _i [ 0 ] ? WHITE : RED } ;
const Pixel moneyCostDisplayCol { game - > GetPlayer ( ) - > GetMoney ( ) > = " Fragment Enchant Cost " _i [ 1 ] ? WHITE : RED } ;
Component < MenuLabel > ( menuType , " Fragment Label " ) - > SetLabel ( std : : format ( " {}{} x{} ({}) " , fragmentItemDisplayCol . toHTMLColorCode ( ) , fragmentName , " Fragment Enchant Cost " _i [ 0 ] , Inventory : : GetItemCount ( fragmentName ) ) ) ;
Component < MenuLabel > ( menuType , " Fragment Money Cost Label " ) - > SetLabel ( std : : format ( " {}{} gold " , moneyCostDisplayCol . toHTMLColorCode ( ) , " Fragment Enchant Cost " _i [ 1 ] ) ) ;
} } ;
auto inventoryDisplay { artificerEnchantWindow - > ADD ( " Accessory List " , RowInventoryScrollableWindowComponent ) ( geom2d : : rect < float > { { 0.f , 28.f } , { artificerEnchantWindow - > size . x / 2 - 4.f , artificerEnchantWindow - > size . y - 44 } } , " " , " " , [ ] ( MenuFuncData data ) {
OnClick :
RowItemDisplay & item { * DYNAMIC_POINTER_CAST < RowItemDisplay > ( data . component ) } ;
DYNAMIC_POINTER_CAST < RowInventoryScrollableWindowComponent > ( data . parentComponent . lock ( ) ) - > SelectChild ( DYNAMIC_POINTER_CAST < RowItemDisplay > ( data . component ) ) ;
return true ;
} , [ EnableEnchantDisplay ] ( MenuFuncData data ) { OnHover :
RowItemDisplay & item { * DYNAMIC_POINTER_CAST < RowItemDisplay > ( data . component ) } ;
Component < MenuItemItemButton > ( data . menu . type , " Item Icon " ) - > SetItem ( item . GetItem ( ) ) ;
EnableEnchantDisplay ( ) ;
return true ;
} , [ ResetEnchantDisplay , EnableEnchantDisplay ] ( MenuFuncData data ) { OnMouseOut :
ResetEnchantDisplay ( ) ;
auto childComponent { DYNAMIC_POINTER_CAST < RowInventoryScrollableWindowComponent > ( data . parentComponent . lock ( ) ) - > GetSelectedChild ( ) } ;
if ( childComponent ) {
RowItemDisplay & item { childComponent . value ( ) . get ( ) } ;
Component < MenuItemItemButton > ( data . menu . type , " Item Icon " ) - > SetItem ( item . GetItem ( ) ) ;
EnableEnchantDisplay ( ) ;
}
return true ;
} ,
InventoryCreator : : RowPlayer_InventoryUpdate ,
InventoryWindowOptions { . padding = 1 , . size = { artificerEnchantWindow - > size . x / 2 - 5.f - 12.f , 28 } } ) END } ;
auto enchantListHeaderLabel { artificerEnchantWindow - > ADD ( " Enchant List Header " , MenuLabel ) ( geom2d : : rect < float > { { artificerEnchantWindow - > size . x / 2 + 4.f , 92.f } , { artificerEnchantWindow - > size . x / 2 + 12.f , 12.f } } , " Possible Enchantments: " , 1.f , ComponentAttr : : FIT_TO_LABEL | ComponentAttr : : BACKGROUND | ComponentAttr : : OUTLINE | ComponentAttr : : SHADOW ) END } ;
auto enchantContainer { artificerEnchantWindow - > ADD ( " Enchant Container " , ScrollableWindowComponent ) ( geom2d : : rect < float > { { artificerEnchantWindow - > size . x / 2 + 4.f , 104.f } , { artificerEnchantWindow - > size . x / 2 + 12.f , 44.f } } ) END } ;
auto enchantList { enchantContainer - > ADD ( " Enchant List " , MenuLabel ) ( geom2d : : rect < float > { { 0.f , 2.f } , { enchantContainer - > GetSize ( ) . x - 12.f , 0.f } } , " " , 1.f , ComponentAttr : : CENTER | ComponentAttr : : SHADOW ) END } ;
auto enchantCostLabel { artificerEnchantWindow - > ADD ( " Enchant Cost Label " , MenuLabel ) ( geom2d : : rect < float > { { artificerEnchantWindow - > size . x / 2 + 4.f , 152.f } , { 64.f , 20.f } } , " Enchant Cost: " , 1.f , ComponentAttr : : SHADOW | ComponentAttr : : BACKGROUND | ComponentAttr : : OUTLINE ) END } ;
auto fragmentCostIcon { artificerEnchantWindow - > ADD ( " Fragment Cost Icon " , MenuDecal ) ( geom2d : : rect < float > { { artificerEnchantWindow - > size . x / 2 + 68.f , 152.f } , { 12.f , 12.f } } ) END } ;
auto fragmentDisplayLabel { artificerEnchantWindow - > ADD ( " Fragment Label " , MenuLabel ) ( geom2d : : rect < float > { { artificerEnchantWindow - > size . x / 2 + 80.f , 152.f } , { artificerEnchantWindow - > size . x / 2 - 60.f , 12.f } } , " " , 1.f , ComponentAttr : : SHADOW | ComponentAttr : : FIT_TO_LABEL | ComponentAttr : : LEFT_ALIGN ) END } ;
auto fragmentMoneyCostLabel { artificerEnchantWindow - > ADD ( " Fragment Money Cost Label " , MenuLabel ) ( geom2d : : rect < float > { { artificerEnchantWindow - > size . x / 2 + 80.f , 164.f } , { artificerEnchantWindow - > size . x / 2 - 60.f , 12.f } } , " " , 1.f , ComponentAttr : : SHADOW | ComponentAttr : : LEFT_ALIGN ) END } ;
auto fragmentEnchantButton { artificerEnchantWindow - > ADD ( " Fragment Enchant Button " , MenuComponent ) ( geom2d : : rect < float > { { artificerEnchantWindow - > size . x / 2 + 96.f , 180.f } , { artificerEnchantWindow - > size . x / 2 - 80.f , 12.f } } , " Enchant " , [ EnableEnchantDisplay ] ( MenuFuncData data ) {
onClick :
EnableEnchantDisplay ( ) ; //Refresh the current display contents.
SoundEffect : : PlaySFX ( " Enchant Item " , SoundEffect : : CENTERED ) ;
std : : weak_ptr < Item > item { Component < MenuItemItemButton > ( data . menu . type , " Item Icon " ) - > GetItem ( ) } ;
std : : optional < ItemEnchant > previousEnchant { item . lock ( ) - > GetEnchant ( ) } ;
data . menu . ANY ( A : : ENCHANT ) = { } ;
if ( previousEnchant . has_value ( ) ) data . menu . ANY ( A : : ENCHANT ) = previousEnchant . value ( ) ;
Component < MenuIconButton > ( ARTIFICER_ENCHANT_CONFIRM , " Old Item Icon " ) - > SetIcon ( item . lock ( ) - > Icon ( ) . Decal ( ) ) ;
Component < MenuItemLabel > ( ARTIFICER_ENCHANT_CONFIRM , " Old Item Description " ) - > SetItem ( * item . lock ( ) ) ;
item . lock ( ) - > ApplyRandomEnchant ( ) ;
const ItemEnchant & newEnchant { item . lock ( ) - > GetEnchant ( ) . value ( ) } ;
Component < MenuIconButton > ( ARTIFICER_ENCHANT_CONFIRM , " New Item Icon " ) - > SetIcon ( item . lock ( ) - > Icon ( ) . Decal ( ) ) ;
Component < MenuItemLabel > ( ARTIFICER_ENCHANT_CONFIRM , " New Item Description " ) - > SetItem ( item . lock ( ) ) ;
Menu : : OpenMenu ( ARTIFICER_ENCHANT_CONFIRM , true ) ;
return true ;
} ) END } ;
# pragma region Money Display
vf2d moneyIconPos { artificerEnchantWindow - > size . x / 2 - 28.f , artificerEnchantWindow - > size . y - 12.f } ;
auto moneyIcon = artificerEnchantWindow - > ADD ( " Money Icon " , MenuIconButton ) ( geom2d : : rect < float > { moneyIconPos , { 24 , 24 } } , GFX [ " money.png " ] . Decal ( ) , DO_NOTHING , IconButtonAttr : : NOT_SELECTABLE | IconButtonAttr : : NO_OUTLINE | IconButtonAttr : : NO_BACKGROUND ) END ;
std : : string moneyText = std : : to_string ( game - > GetPlayer ( ) - > GetMoney ( ) ) ;
vf2d moneyTextSize = game - > GetTextSizeProp ( moneyText ) * 2 ;
auto moneyDisplay = artificerEnchantWindow - > ADD ( " Money Label " , PlayerMoneyLabel ) ( geom2d : : rect < float > { moneyIconPos + vf2d { 26.f , 4.f } , moneyTextSize } , 2 , 1.85f , ComponentAttr : : SHADOW | ComponentAttr : : LEFT_ALIGN | ComponentAttr : : FIT_TO_LABEL ) END ;
Player : : AddMoneyListener ( moneyDisplay ) ;
# pragma endregion
auto backButton { artificerEnchantWindow - > ADD ( " Back " , MenuComponent ) ( geom2d : : rect < float > { { 0.f , artificerEnchantWindow - > size . y - 12.f } , { 96.f , 16.f } } , " Back " , [ ] ( MenuFuncData data ) {
Menu : : CloseMenu ( ) ;
return true ;
} ) END } ;
ResetEnchantDisplay ( ) ;
Menu : : AddInventoryListener ( inventoryDisplay , " Accessories " ) ;
artificerEnchantWindow - > SetupKeyboardNavigation (
[ ] ( MenuType type , Data & returnData ) { //On Open
auto & items { Component < RowInventoryScrollableWindowComponent > ( type , " Accessory List " ) - > GetComponents ( ) } ;
if ( Component < RowInventoryScrollableWindowComponent > ( type , " Accessory List " ) - > GetSelectedChild ( ) ) returnData = Component < RowInventoryScrollableWindowComponent > ( type , " Accessory List " ) - > GetSelectedChild ( ) . value ( ) . get ( ) . GetName ( ) ;
else if ( items . size ( ) > 0 ) returnData = items [ 0 ] ;
else returnData = " Back " ;
} ,
{ //Button Key
{ game - > KEY_SCROLL , { " Navigate " , [ ] ( MenuType type ) { } } } ,
{ game - > KEY_BACK , { " Stay " , [ ] ( MenuType type ) {
Menu : : CloseMenu ( ) ;
} } } ,
{ game - > KEY_CONFIRM , { " Select " , [ ] ( MenuType type ) { } } } ,
{ { game - > KEY_SHOULDER2 , Pressed } , { " Scroll Up/Down " , [ ] ( MenuType type ) { } } } ,
{ { game - > KEY_SHOULDER , Pressed } , { " Scroll Up/Down " , [ ] ( MenuType type ) { } } } ,
{ { game - > KEY_FASTSCROLLUP , PressedDAS } , { " Scroll " , [ ] ( MenuType type ) {
Menu : : menus [ type ] - > GetSelection ( ) . lock ( ) - > parentComponent . lock ( ) - > DecreaseSelectionIndex ( 3.f ) ;
} } } ,
{ { game - > KEY_FASTSCROLLDOWN , PressedDAS } , { " Scroll " , [ ] ( MenuType type ) {
Menu : : menus [ type ] - > GetSelection ( ) . lock ( ) - > parentComponent . lock ( ) - > IncreaseSelectionIndex ( 3.f ) ;
} } } ,
{ { game - > KEY_SCROLLVERT_R , Analog , InputEngageGroup : : NOT_VISIBLE } , { " Scroll Enchants " , [ ] ( MenuType type ) {
Component < ScrollableWindowComponent > ( type , " Enchant Container " ) - > Scroll ( game - > KEY_SCROLLVERT . Analog ( ) ) ;
} } } ,
}
, { //Button Navigation Rules
{ " Accessory List " , {
. up = [ & ] ( MenuType type , Data & returnData ) {
Menu : : ScrollUp ( type , " Accessory List " , returnData , " Back " ) ;
} ,
. down = [ & ] ( MenuType type , Data & returnData ) {
Menu : : ScrollDown ( type , " Accessory List " , returnData , " Back " ) ;
} ,
. left = " Back " ,
. right = [ & ] ( MenuType type , Data & returnData ) {
Menu : : menus [ type ] - > GetSelection ( ) . lock ( ) - > Click ( ) ;
returnData = " Fragment Enchant Button " ;
} , } } ,
{ " Back " , {
. up = [ & ] ( MenuType type , Data & returnData ) {
returnData = Component < RowInventoryScrollableWindowComponent > ( type , " Accessory List " ) - > GetComponents ( ) . back ( ) . lock ( ) - > GetName ( ) ;
} ,
. down = [ & ] ( MenuType type , Data & returnData ) {
returnData = Component < RowInventoryScrollableWindowComponent > ( type , " Accessory List " ) - > GetComponents ( ) . front ( ) . lock ( ) - > GetName ( ) ;
} ,
. left = " Fragment Enchant Button " ,
. right = " Fragment Enchant Button " , } } ,
{ " Fragment Enchant Button " , {
. up = [ & ] ( MenuType type , Data & returnData ) {
returnData = Component < RowInventoryScrollableWindowComponent > ( type , " Accessory List " ) - > GetComponents ( ) . back ( ) . lock ( ) - > GetName ( ) ;
} ,
. down = [ & ] ( MenuType type , Data & returnData ) {
returnData = Component < RowInventoryScrollableWindowComponent > ( type , " Accessory List " ) - > GetComponents ( ) . front ( ) . lock ( ) - > GetName ( ) ;
} ,
. left = [ & ] ( MenuType type , Data & returnData ) {
if ( Component < RowInventoryScrollableWindowComponent > ( type , " Accessory List " ) - > GetSelectedChild ( ) ) returnData = Component < RowInventoryScrollableWindowComponent > ( type , " Accessory List " ) - > GetSelectedChild ( ) . value ( ) . get ( ) . GetName ( ) ;
else returnData = " Back " ;
} ,
. right = " Back " , } } ,
}
) ;
}