diff --git a/Adventures in Lestoria/ArtificerDisassembleWindow.cpp b/Adventures in Lestoria/ArtificerDisassembleWindow.cpp index 3442c2cb..ba795d4c 100644 --- a/Adventures in Lestoria/ArtificerDisassembleWindow.cpp +++ b/Adventures in Lestoria/ArtificerDisassembleWindow.cpp @@ -109,7 +109,7 @@ void Menu::InitializeArtificerDisassembleWindow(){ EnableDisassemblyDisplay(); RowItemDisplay&item{*DYNAMIC_POINTER_CAST(data.component)}; Component(data.menu.type,"Item Icon")->SetItem(item.GetItem().lock()); - Component(data.menu.type,"Disassembly Result")->SetIcon(GFX.at(item.GetItem().lock()->FragmentName()).Decal()); + Component(data.menu.type,"Disassembly Result")->SetIcon(GFX.at(item.GetItem().lock()->FragmentIcon().value()).Decal()); Component(data.menu.type,"Disassembly Result Title")->SetLabel(item.GetItem().lock()->FragmentName()); Component(data.menu.type,"Fragment Total Count")->SetLabel(std::format("Currently Owned: {}",Inventory::GetItemCount(item.GetItem().lock()->FragmentName()))); return true; @@ -119,7 +119,7 @@ void Menu::InitializeArtificerDisassembleWindow(){ if(childComponent){ RowItemDisplay&item{childComponent.value().get()}; Component(data.menu.type,"Item Icon")->SetItem(item.GetItem().lock()); - Component(data.menu.type,"Disassembly Result")->SetIcon(GFX.at(item.GetItem().lock()->FragmentName()).Decal()); + Component(data.menu.type,"Disassembly Result")->SetIcon(GFX.at(item.GetItem().lock()->FragmentIcon().value()).Decal()); Component(data.menu.type,"Disassembly Result Title")->SetLabel(item.GetItem().lock()->FragmentName()); Component(data.menu.type,"Fragment Total Count")->SetLabel(std::format("Currently Owned: {}",Inventory::GetItemCount(item.GetItem().lock()->FragmentName()))); EnableDisassemblyDisplay(); diff --git a/Adventures in Lestoria/ArtificerRefineWindow.cpp b/Adventures in Lestoria/ArtificerRefineWindow.cpp index da61377f..44bf788a 100644 --- a/Adventures in Lestoria/ArtificerRefineWindow.cpp +++ b/Adventures in Lestoria/ArtificerRefineWindow.cpp @@ -42,13 +42,14 @@ All rights reserved. #include "MenuItemItemButton.h" #include "MenuRefineLabel.h" #include "PlayerMoneyLabel.h" +#include "MenuDecal.h" INCLUDE_game void Menu::InitializeArtificerRefineWindow(){ Menu*const artificerRefineWindow{CreateMenu(ARTIFICER_REFINE,CENTERED,game->GetScreenSize()-vi2d{52,52})}; - auto disassemblyTitleLabel{artificerRefineWindow->ADD("Disassembly Title Label",MenuLabel)(geom2d::rect{{0.f,-16.f},{artificerRefineWindow->size.x,24.f}},"Accessory Disassembly",2.f,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END}; + auto disassemblyTitleLabel{artificerRefineWindow->ADD("Refining Title Label",MenuLabel)(geom2d::rect{{0.f,-16.f},{artificerRefineWindow->size.x,24.f}},"Accessory Refinement",2.f,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END}; auto inventoryLabel{artificerRefineWindow->ADD("Accessory List Label",MenuLabel)(geom2d::rect{{0.f,12.f},{180.f,12.f}},"Choose Accessory:",1.f,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN)END}; @@ -61,10 +62,31 @@ void Menu::InitializeArtificerRefineWindow(){ const auto ResetRefineDisplay{[artificerRefineWindow](){ MenuType menuType{artificerRefineWindow->GetType()}; Component(menuType,"Item Icon")->SetItem(Item::BLANK); - Component(menuType,"Stats Block")->SetItem(Item::BLANK); + Component(menuType,"Stats Block")->Disable(); + Component(menuType,"Refine Cost Label")->Disable(); + Component(menuType,"Fragment Cost Icon")->Disable(); + Component(menuType,"Fragment Label")->Disable(); + Component(menuType,"Fragment Money Cost Label")->Disable(); + Component(menuType,"Fragment Refine Button")->Disable(); }}; const auto EnableRefineDisplay{[artificerRefineWindow](){ MenuType menuType{artificerRefineWindow->GetType()}; + const std::weak_ptr&selectedItem{Component(menuType,"Item Icon")->GetItem()}; + Component(menuType,"Stats Block")->SetItem(selectedItem); + Component(menuType,"Stats Block")->Enable(); + Component(menuType,"Refine Cost Label")->Enable(); + Component(menuType,"Fragment Cost Icon")->Enable(); + Component(menuType,"Fragment Cost Icon")->SetImage(GFX.at(selectedItem.lock()->FragmentIcon().value())); + Component(menuType,"Fragment Label")->Enable(); + Component(menuType,"Fragment Money Cost Label")->Enable(); + Component(menuType,"Fragment Refine Button")->Enable(); + Component(menuType,"Fragment Refine Button")->SetGrayedOut(!selectedItem.lock()->CanBeRefined()); + + const std::string_view fragmentName{selectedItem.lock()->FragmentName()}; + const Pixel fragmentItemDisplayCol{Inventory::GetItemCount(fragmentName)>="Fragment Refine Cost"_i[0]?WHITE:RED}; + const Pixel moneyCostDisplayCol{game->GetPlayer()->GetMoney()>="Fragment Refine Cost"_i[1]?WHITE:RED}; + Component(menuType,"Fragment Label")->SetLabel(std::format("{}{} x{} ({})",fragmentItemDisplayCol.toHTMLColorCode(),fragmentName,"Fragment Refine Cost"_i[0],Inventory::GetItemCount(fragmentName))); + Component(menuType,"Fragment Money Cost Label")->SetLabel(std::format("{}{} gold",moneyCostDisplayCol.toHTMLColorCode(),"Fragment Refine Cost"_i[1])); }}; auto inventoryDisplay{artificerRefineWindow->ADD("Accessory List",RowInventoryScrollableWindowComponent)(geom2d::rect{{0.f,28.f},{artificerRefineWindow->size.x/2-4.f,artificerRefineWindow->size.y-44}},"","",[](MenuFuncData data){ @@ -74,15 +96,15 @@ void Menu::InitializeArtificerRefineWindow(){ return true; },[EnableRefineDisplay](MenuFuncData data){OnHover: RowItemDisplay&item{*DYNAMIC_POINTER_CAST(data.component)}; - EnableRefineDisplay(); Component(data.menu.type,"Item Icon")->SetItem(item.GetItem()); - Component(data.menu.type,"Stats Block")->SetItem(item.GetItem()); + EnableRefineDisplay(); return true; },[ResetRefineDisplay,EnableRefineDisplay](MenuFuncData data){OnMouseOut: ResetRefineDisplay(); auto childComponent{DYNAMIC_POINTER_CAST(data.parentComponent.lock())->GetSelectedChild()}; if(childComponent){ RowItemDisplay&item{childComponent.value().get()}; + Component(data.menu.type,"Item Icon")->SetItem(item.GetItem()); EnableRefineDisplay(); } return true; @@ -92,6 +114,18 @@ void Menu::InitializeArtificerRefineWindow(){ auto statsBlock{artificerRefineWindow->ADD("Stats Block",MenuRefineLabel)(geom2d::rect{{artificerRefineWindow->size.x/2+4.f,104.f},{artificerRefineWindow->size.x/2-4.f,44.f}},Item::BLANK,1.f,ComponentAttr::BACKGROUND|ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::FIXED_WIDTH_FONT|ComponentAttr::FIT_TO_LABEL|ComponentAttr::LEFT_ALIGN)END}; + auto refineCostLabel{artificerRefineWindow->ADD("Refine Cost Label",MenuLabel)(geom2d::rect{{artificerRefineWindow->size.x/2+4.f,152.f},{64.f,20.f}},"Refine Cost:",1.f,ComponentAttr::SHADOW|ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)END}; + + auto fragmentCostIcon{artificerRefineWindow->ADD("Fragment Cost Icon",MenuDecal)(geom2d::rect{{artificerRefineWindow->size.x/2+68.f,152.f},{12.f,12.f}})END}; + auto fragmentDisplayLabel{artificerRefineWindow->ADD("Fragment Label",MenuLabel)(geom2d::rect{{artificerRefineWindow->size.x/2+80.f,152.f},{artificerRefineWindow->size.x/2-60.f,12.f}},"",1.f,ComponentAttr::SHADOW|ComponentAttr::FIT_TO_LABEL|ComponentAttr::LEFT_ALIGN)END}; + auto fragmentMoneyCostLabel{artificerRefineWindow->ADD("Fragment Money Cost Label",MenuLabel)(geom2d::rect{{artificerRefineWindow->size.x/2+80.f,164.f},{artificerRefineWindow->size.x/2-60.f,12.f}},"",1.f,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN)END}; + + auto fragmentRefineButton{artificerRefineWindow->ADD("Fragment Refine Button",MenuComponent)(geom2d::rect{{artificerRefineWindow->size.x/2+96.f,180.f},{artificerRefineWindow->size.x/2-76.f,12.f}},"Refine",[](MenuFuncData data){ + onClick: + + return true; + })END}; + #pragma region Money Display vf2d moneyIconPos{artificerRefineWindow->size.x/2-28.f,artificerRefineWindow->size.y-12.f}; auto moneyIcon=artificerRefineWindow->ADD("Money Icon",MenuIconButton)(geom2d::rect{moneyIconPos,{24,24}},GFX["money.png"].Decal(),DO_NOTHING,IconButtonAttr::NOT_SELECTABLE|IconButtonAttr::NO_OUTLINE|IconButtonAttr::NO_BACKGROUND)END; diff --git a/Adventures in Lestoria/IT.cpp b/Adventures in Lestoria/IT.cpp index 9c45f03c..b400a80c 100644 --- a/Adventures in Lestoria/IT.cpp +++ b/Adventures in Lestoria/IT.cpp @@ -49,9 +49,14 @@ IT::IT(std::string name) itemName=ITEM_CONVERSIONS.at(name); //Convert the item if it's using an old name. } } +IT::IT(std::string_view name) + :IT(std::string(name)){} IT::operator std::string(){ return itemName; } +IT::operator std::string_view(){ + return itemName; +} std::ostream&operator<<(std::ostream&rhs,IT&item){ rhs<&rhs); const bool operator==(const std::weak_ptr&rhs); friend std::ostream&operator<<(std::ostream&rhs,IT&item); diff --git a/Adventures in Lestoria/Item.cpp b/Adventures in Lestoria/Item.cpp index feb1e7f5..d2f6b819 100644 --- a/Adventures in Lestoria/Item.cpp +++ b/Adventures in Lestoria/Item.cpp @@ -405,7 +405,7 @@ void ItemInfo::InitializeItems(){ } } it.img=GFX.at(fragmentName).Decal(); - it.name=fragmentName; + it.fragmentIcon=it.name=fragmentName; it.description="Fragment Description"_S; it.category="Materials"; LOG(std::format("Item Fragment {} generated...",fragmentName)); @@ -1516,4 +1516,8 @@ const std::optional&ItemInfo::FragmentIcon()const{ const Pixel Stats::GetShimmeringColor(){ return PixelLerp({255,196,60},{254,217,133},sin((70*game->GetRunTime())/2.f+0.5f)); +} + +const std::optional&Item::FragmentIcon()const{ + return ITEM_DATA.at(FragmentName()).FragmentIcon(); } \ No newline at end of file diff --git a/Adventures in Lestoria/Item.h b/Adventures in Lestoria/Item.h index 69e19323..89d18389 100644 --- a/Adventures in Lestoria/Item.h +++ b/Adventures in Lestoria/Item.h @@ -266,6 +266,7 @@ public: friend const bool operator==(const IT&lhs,std::shared_ptrrhs){return operator==(rhs,lhs);}; const Pixel GetDisplayNameColor()const; static const bool SelectedEquipIsDifferent(const std::weak_ptrequipAttemptingToEquip,const EquipSlot slotToEquipTo); + const std::optional&FragmentIcon()const; }; class Inventory{ diff --git a/Adventures in Lestoria/MenuComponent.h b/Adventures in Lestoria/MenuComponent.h index 83fe0955..b7820030 100644 --- a/Adventures in Lestoria/MenuComponent.h +++ b/Adventures in Lestoria/MenuComponent.h @@ -81,8 +81,6 @@ class MenuComponent:public IAttributable{ friend class RowItemDisplay; friend class InventoryConsumableWindow; friend class FloatingMenuComponent; - MenuFunc onHover=[](MenuFuncData dat){return true;}; - MenuFunc onMouseOut=[](MenuFuncData dat){return true;}; bool hoverState=false; bool runHoverFunctions=false; private: @@ -136,6 +134,8 @@ protected: virtual void DisableOutsideWindow(); const bool IsEnabledOutsideWindow()const; const bool IsDisabledOutsideWindow()const; + MenuFunc onHover=[](MenuFuncData dat){return true;}; + MenuFunc onMouseOut=[](MenuFuncData dat){return true;}; public: MenuType parentMenu=MenuType::ENUM_END; std::weak_ptrparentComponent{}; diff --git a/Adventures in Lestoria/MenuDecal.h b/Adventures in Lestoria/MenuDecal.h index 76d92c7c..eb3d4899 100644 --- a/Adventures in Lestoria/MenuDecal.h +++ b/Adventures in Lestoria/MenuDecal.h @@ -41,14 +41,17 @@ All rights reserved. class MenuDecal:public MenuComponent{ public: - inline MenuDecal(geom2d::rectrect,Renderable&image,MenuFunc onClick,MenuFunc onHover) + inline MenuDecal(geom2d::rectrect,std::optional>image={},MenuFunc onClick=DO_NOTHING,MenuFunc onHover=DO_NOTHING) :image(image),MenuComponent(rect,"",onClick,ButtonAttr::NONE){ SetHoverFunc(onHover); } inline void DrawDecal(ViewPort&window,bool focused)override{ - window.DrawDecal(rect.pos,image.Decal(),rect.size/image.Sprite()->Size()); + if(image)window.DrawDecal(rect.pos,image.value().get().Decal(),rect.size/image.value().get().Sprite()->Size()); + } + inline void SetImage(Renderable&renderable){ + image=renderable; } private: - const Renderableℑ + std::optional>image; }; \ No newline at end of file diff --git a/Adventures in Lestoria/MenuDefinitions.h b/Adventures in Lestoria/MenuDefinitions.h index 2e12eaf1..fe2442f4 100644 --- a/Adventures in Lestoria/MenuDefinitions.h +++ b/Adventures in Lestoria/MenuDefinitions.h @@ -51,7 +51,7 @@ struct MenuFuncData{ AiL*const game; const std::weak_ptr component; const std::weak_ptr parentComponent={}; - MenuFuncData(Menu&menu,AiL*const game,std::weak_ptr component,std::weak_ptrparentComponent={}); + MenuFuncData(Menu&menu,AiL*const game,std::weak_ptrcomponent,std::weak_ptrparentComponent={}); }; using InputGroupActionDisplayName=std::variant>; diff --git a/Adventures in Lestoria/MenuItemItemButton.h b/Adventures in Lestoria/MenuItemItemButton.h index ba96a122..b0a27438 100644 --- a/Adventures in Lestoria/MenuItemItemButton.h +++ b/Adventures in Lestoria/MenuItemItemButton.h @@ -124,12 +124,12 @@ protected: icon=nullptr; labelNameText=""; labelDescriptionText=""; - return; + }else{ + icon=const_cast(itemRef.lock()->Decal()); + labelNameText=itemRef.lock()->DisplayName(); + labelDescriptionText=itemRef.lock()->Description(compact); } - icon=const_cast(itemRef.lock()->Decal()); - labelNameText=itemRef.lock()->DisplayName(); - labelDescriptionText=itemRef.lock()->Description(compact); if(hideDetails){ std::for_each(labelNameText.begin(),labelNameText.end(),[](char&c){c='?';}); std::for_each(labelDescriptionText.begin(),labelDescriptionText.end(),[](char&c){c='?';}); diff --git a/Adventures in Lestoria/RowInventoryScrollableWindowComponent.h b/Adventures in Lestoria/RowInventoryScrollableWindowComponent.h index dba59f84..8f1044ed 100644 --- a/Adventures in Lestoria/RowInventoryScrollableWindowComponent.h +++ b/Adventures in Lestoria/RowInventoryScrollableWindowComponent.h @@ -41,52 +41,54 @@ All rights reserved. #include "InventoryCreator.h" class RowInventoryScrollableWindowComponent:public InventoryScrollableWindowComponent{ - friend class InventoryCreator; - friend class Menu; - std::weak_ptrselectedComponent; + friend class InventoryCreator; + friend class Menu; + std::weak_ptrselectedComponent; protected: - PriceLabel::PriceLabel priceLabel=PriceLabel::NONE; + PriceLabel::PriceLabel priceLabel=PriceLabel::NONE; public: inline RowInventoryScrollableWindowComponent(geom2d::rectrect,std::string itemNameLabelName,std::string itemDescriptionLabelName,std::functioninventoryButtonClickAction,std::functioninventoryButtonHoverAction,std::functioninventoryButtonMouseOutAction,const InventoryCreator&creator,InventoryWindowOptions options={.padding=8,.size={24,24}},bool inventoryButtonsActive=true,ComponentAttr attributes=ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE) - :InventoryScrollableWindowComponent(rect,itemNameLabelName,itemDescriptionLabelName,inventoryButtonClickAction,inventoryButtonHoverAction,inventoryButtonMouseOutAction,creator,options,inventoryButtonsActive,attributes){} - virtual inline void AfterCreate()override final{ - ScrollableWindowComponent::AfterCreate(); - if(options.size.x>rect.size.x||options.size.y>rect.size.y)ERR(std::format("WARNING! Component {} has Inventory Option Sizes: {} which is not large enough to fit in the component whose size is {}! Please make the component larger or the items smaller.",name,options.size.str(),rect.size.str())); - } + :InventoryScrollableWindowComponent(rect,itemNameLabelName,itemDescriptionLabelName,inventoryButtonClickAction,inventoryButtonHoverAction,inventoryButtonMouseOutAction,creator,options,inventoryButtonsActive,attributes){} + virtual inline void AfterCreate()override final{ + ScrollableWindowComponent::AfterCreate(); + if(options.size.x>rect.size.x||options.size.y>rect.size.y)ERR(std::format("WARNING! Component {} has Inventory Option Sizes: {} which is not large enough to fit in the component whose size is {}! Please make the component larger or the items smaller.",name,options.size.str(),rect.size.str())); + } virtual inline void SetCompactDescriptions(CompactText compact)override final{ - this->compact=compact; - for(std::weak_ptrcomponent:components){ - std::weak_ptritemButton=DYNAMIC_POINTER_CAST(component.lock()); - itemButton.lock()->SetCompactDescriptions(compact); - } - } + this->compact=compact; + for(std::weak_ptrcomponent:components){ + std::weak_ptritemButton=DYNAMIC_POINTER_CAST(component.lock()); + itemButton.lock()->SetCompactDescriptions(compact); + } + } - virtual inline void SetPriceLabelType(PriceLabel::PriceLabel labelType)final{ - this->priceLabel=labelType; - for(std::weak_ptrcomponent:components){ - std::weak_ptritemButton=DYNAMIC_POINTER_CAST(component.lock()); - itemButton.lock()->SetPriceLabelType(labelType); - } - } + virtual inline void SetPriceLabelType(PriceLabel::PriceLabel labelType)final{ + this->priceLabel=labelType; + for(std::weak_ptrcomponent:components){ + std::weak_ptritemButton=DYNAMIC_POINTER_CAST(component.lock()); + itemButton.lock()->SetPriceLabelType(labelType); + } + } - inline void ClearSelectedChild(){ - if(!selectedComponent.expired())selectedComponent.lock()->itemIsSelected=false; - selectedComponent.reset(); - } + inline void ClearSelectedChild(){ + std::weak_ptrpreviousSelectedComponent{selectedComponent}; + if(!selectedComponent.expired())selectedComponent.lock()->itemIsSelected=false; + selectedComponent.reset(); + if(!previousSelectedComponent.expired())previousSelectedComponent.lock()->onMouseOut(MenuFuncData{*Menu::menus[parentMenu],game,Menu::menus[parentMenu]->components[name],previousSelectedComponent.lock()->parentComponent}); //HACK ALERT: It's possible the selected component uses functions that set components via a mouse hover/click. This will fake a mouse out event which hopefully I set a callback to clear any menu states that were set due to mouse hover/click... + } - inline void SelectChild(std::weak_ptrchildComponent){ - selectedComponent=childComponent; - for(std::weak_ptrchild:components){ - RowItemDisplay&rowItem{*DYNAMIC_POINTER_CAST(child)}; - rowItem.itemIsSelected=false; - } - selectedComponent.lock()->itemIsSelected=true; - } + inline void SelectChild(std::weak_ptrchildComponent){ + selectedComponent=childComponent; + for(std::weak_ptrchild:components){ + RowItemDisplay&rowItem{*DYNAMIC_POINTER_CAST(child)}; + rowItem.itemIsSelected=false; + } + selectedComponent.lock()->itemIsSelected=true; + } - inline std::optional>GetSelectedChild()const{ - if(!selectedComponent.expired()){ - return *selectedComponent.lock(); - } - return {}; - } + inline std::optional>GetSelectedChild()const{ + if(!selectedComponent.expired()){ + return *selectedComponent.lock(); + } + return {}; + } }; \ No newline at end of file diff --git a/Adventures in Lestoria/Version.h b/Adventures in Lestoria/Version.h index fa67972c..582db743 100644 --- a/Adventures in Lestoria/Version.h +++ b/Adventures in Lestoria/Version.h @@ -39,7 +39,7 @@ All rights reserved. #define VERSION_MAJOR 1 #define VERSION_MINOR 2 #define VERSION_PATCH 5 -#define VERSION_BUILD 11440 +#define VERSION_BUILD 11461 #define stringify(a) stringify_(a) #define stringify_(a) #a diff --git a/x64/Release/Adventures in Lestoria.exe b/x64/Release/Adventures in Lestoria.exe index 94800c1d..76bcdf38 100644 Binary files a/x64/Release/Adventures in Lestoria.exe and b/x64/Release/Adventures in Lestoria.exe differ