From c0ae0697b7341783c797e4b626e8d6dea06028ba Mon Sep 17 00:00:00 2001 From: sigonasr2 Date: Tue, 16 Jan 2024 00:20:30 -0600 Subject: [PATCH] Move to smart pointers for menu component system. --- .../AdventuresInLestoria.cpp | 11 +- .../BlacksmithCraftingWindow.cpp | 48 +-- Adventures in Lestoria/BuyItemWindow.cpp | 22 +- .../CharacterInfoWindow.cpp | 20 +- .../CharacterMenuWindow.cpp | 126 ++++--- .../ClassSelectionWindow.cpp | 28 +- .../ConsumableCraftItemWindow.cpp | 22 +- .../ConsumableCraftingWindow.cpp | 32 +- Adventures in Lestoria/CraftItemWindow.cpp | 18 +- ...untersSpawnListScrollableWindowComponent.h | 5 +- Adventures in Lestoria/Error.h | 8 + .../InventoryConsumableWindow.cpp | 32 +- Adventures in Lestoria/InventoryCreator.cpp | 10 +- .../InventoryScrollableWindowComponent.h | 10 +- Adventures in Lestoria/InventoryWindow.cpp | 36 +- Adventures in Lestoria/ItemLoadoutWindow.cpp | 14 +- .../LevelCompleteWindow.cpp | 28 +- Adventures in Lestoria/LoadGameWindow.cpp | 6 +- Adventures in Lestoria/MainMenuWindow.cpp | 6 +- Adventures in Lestoria/Menu.cpp | 331 +++++------------- Adventures in Lestoria/Menu.h | 78 +---- .../MenuAnimatedIconToggleButton.h | 6 +- Adventures in Lestoria/MenuComponent.cpp | 44 +-- Adventures in Lestoria/MenuComponent.h | 8 +- Adventures in Lestoria/MenuItemButton.h | 8 +- Adventures in Lestoria/MerchantWindow.cpp | 82 ++--- .../OverworldMapLevelWindow.cpp | 16 +- .../OverworldMenuWindow.cpp | 10 +- Adventures in Lestoria/Player.cpp | 16 +- Adventures in Lestoria/Player.h | 4 +- .../RowInventoryScrollableWindowComponent.h | 12 +- Adventures in Lestoria/SaveFile.cpp | 6 +- Adventures in Lestoria/SaveFileWindow.cpp | 8 +- .../ScrollableWindowComponent.h | 116 +++--- Adventures in Lestoria/SellItemWindow.cpp | 22 +- Adventures in Lestoria/TODO.txt | 1 + Adventures in Lestoria/Toggleable.h | 18 +- Adventures in Lestoria/UserIDMenu.cpp | 8 +- Adventures in Lestoria/Version.h | 2 +- 39 files changed, 518 insertions(+), 760 deletions(-) diff --git a/Adventures in Lestoria/AdventuresInLestoria.cpp b/Adventures in Lestoria/AdventuresInLestoria.cpp index f5a7fb59..c2c2cae4 100644 --- a/Adventures in Lestoria/AdventuresInLestoria.cpp +++ b/Adventures in Lestoria/AdventuresInLestoria.cpp @@ -1462,7 +1462,6 @@ void AiL::RenderHud(){ if(!ISBLANK(GetLoadoutItem(0))){ DrawShadowStringDecal({0,92},"Loadout Slot 1 Qty: "+std::to_string(GetLoadoutItem(0).lock()->Amt())); } - DrawShadowStringDecal({0,1},"Selection: "+Menu::menus[INVENTORY_CONSUMABLES]->selection.str()); DrawShadowStringDecal({0,12},"Button Hold Time: "+std::to_string(Menu::menus[INVENTORY_CONSUMABLES]->buttonHoldTime)); } #endif @@ -2077,7 +2076,7 @@ void AiL::ChangePlayerClass(Class cl){ uint8_t levelCap=player->levelCap; uint32_t totalXPEarned=player->totalXPEarned; uint32_t currentLevelXP=player->currentLevelXP; - std::setmoneyListeners=Player::moneyListeners; + std::vector>moneyListeners=Player::moneyListeners; EntityStats previousStats=player->stats; size_t cooldownSoundInstance=player->cooldownSoundInstance; switch(cl){ @@ -2550,8 +2549,8 @@ const MapName&AiL::GetCurrentMapName()const{ void AiL::ValidateGameStatus(){ if(IToggleable::uninitializedToggleGroupItems.size()>0){ - for(IToggleable*item:IToggleable::uninitializedToggleGroupItems){ - std::cout<<"\tUninitialized Toggle Item Ptr: 0x"<item:IToggleable::uninitializedToggleGroupItems){ + std::cout<<"\tUninitialized Toggle Item Ptr: 0x"<chapter=chapter; - for(MenuComponent*component:Menu::chapterListeners){ - component->OnChapterUpdate(chapter); + for(std::weak_ptrcomponent:Menu::chapterListeners){ + component.lock()->OnChapterUpdate(chapter); } } diff --git a/Adventures in Lestoria/BlacksmithCraftingWindow.cpp b/Adventures in Lestoria/BlacksmithCraftingWindow.cpp index 5bb0c090..4e96f069 100644 --- a/Adventures in Lestoria/BlacksmithCraftingWindow.cpp +++ b/Adventures in Lestoria/BlacksmithCraftingWindow.cpp @@ -72,29 +72,29 @@ void Menu::InitializeBlacksmithCraftingWindow(){ }); #pragma endregion - auto weaponTab=blacksmithWindow->ADD("Weapon Tab",MenuComponent)({{2,0},{blacksmithWindow->size.x/2-4,24}},"Weapon",[](MenuFuncData data){ + auto weaponTab=blacksmithWindow->ADD("Weapon Tab",MenuComponent)(geom2d::rect{{2,0},{blacksmithWindow->size.x/2-4,24}},"Weapon",[](MenuFuncData data){ Component(BLACKSMITH,"Armor Tab")->selected=false; Component(BLACKSMITH,"Weapon Inventory Display")->Enable(true); Component(BLACKSMITH,"Armor Inventory Display")->Enable(false); - data.component->selected=true; + data.component.lock()->selected=true; return true; })END; weaponTab->selected=true; weaponTab->selectionType=SelectionType::HIGHLIGHT; - auto armorTab=blacksmithWindow->ADD("Armor Tab",MenuComponent)({{blacksmithWindow->size.x/2+2,0},{blacksmithWindow->size.x/2-4,24}},"Armor",[](MenuFuncData data){ + auto armorTab=blacksmithWindow->ADD("Armor Tab",MenuComponent)(geom2d::rect{{blacksmithWindow->size.x/2+2,0},{blacksmithWindow->size.x/2-4,24}},"Armor",[](MenuFuncData data){ Component(BLACKSMITH,"Weapon Tab")->selected=false; Component(BLACKSMITH,"Weapon Inventory Display")->Enable(false); Component(BLACKSMITH,"Armor Inventory Display")->Enable(true); - data.component->selected=true; + data.component.lock()->selected=true; return true; })END; armorTab->selectionType=SelectionType::HIGHLIGHT; #pragma region Weapon Inventory Display - auto weaponsDisplay=blacksmithWindow->ADD("Weapon Inventory Display",RowInventoryScrollableWindowComponent)({{2,28},{220,blacksmithWindow->size.y-44}},"Item Name Label","Item Description Label", + auto weaponsDisplay=blacksmithWindow->ADD("Weapon Inventory Display",RowInventoryScrollableWindowComponent)(geom2d::rect{{2,28},{220,blacksmithWindow->size.y-44}},"Item Name Label","Item Description Label", [](MenuFuncData data){ - RowItemDisplay*comp=DYNAMIC_CAST(data.component); - const std::weak_ptritem=comp->GetItem(); + std::weak_ptrcomp=DYNAMIC_POINTER_CAST(data.component.lock()); + const std::weak_ptritem=comp.lock()->GetItem(); std::string label=""; if(item.lock()->EnhancementIsPossible()&&item.lock()->GetEnhancementInfo().size()>item.lock()->EnhancementLevel()+1){ @@ -109,8 +109,8 @@ void Menu::InitializeBlacksmithCraftingWindow(){ return true; }, [](MenuFuncData data){ - RowItemDisplay*rowItem=DYNAMIC_CAST(data.component); - Component(BLACKSMITH,"Item Icon")->SetItem(rowItem->GetItem()); + std::weak_ptrrowItem=DYNAMIC_POINTER_CAST(data.component.lock()); + Component(BLACKSMITH,"Item Icon")->SetItem(rowItem.lock()->GetItem()); return true; }, [](MenuFuncData data){ @@ -118,18 +118,18 @@ void Menu::InitializeBlacksmithCraftingWindow(){ return true; }, InventoryCreator::RowPlayerWeapons_InventoryUpdate, - {.padding=1,.size={207,28}} + InventoryWindowOptions{.padding=1,.size={207,28}} )END; AddInventoryListener(weaponsDisplay,"Equipment"); weaponsDisplay->SetCompactDescriptions(CRAFTING_INFO); #pragma endregion #pragma region Armor Inventory Display - auto armorDisplay=blacksmithWindow->ADD("Armor Inventory Display",RowInventoryScrollableWindowComponent)({{2,28},{220,blacksmithWindow->size.y-44}},"Item Name Label","Item Description Label", + auto armorDisplay=blacksmithWindow->ADD("Armor Inventory Display",RowInventoryScrollableWindowComponent)(geom2d::rect{{2,28},{220,blacksmithWindow->size.y-44}},"Item Name Label","Item Description Label", [](MenuFuncData data){ Menu::OpenMenu(CRAFT_ITEM); - RowItemDisplay*comp=DYNAMIC_CAST(data.component); - const std::weak_ptritem=comp->GetItem(); + std::weak_ptrcomp=DYNAMIC_POINTER_CAST(data.component.lock()); + const std::weak_ptritem=comp.lock()->GetItem(); std::string label=""; if(item.lock()->EnhancementIsPossible()&&item.lock()->GetEnhancementInfo().size()>item.lock()->EnhancementLevel()+1){ @@ -143,8 +143,8 @@ void Menu::InitializeBlacksmithCraftingWindow(){ return true; }, [](MenuFuncData data){ - RowItemDisplay*rowItem=DYNAMIC_CAST(data.component); - Component(BLACKSMITH,"Item Icon")->SetItem(rowItem->GetItem()); + std::weak_ptrrowItem=DYNAMIC_POINTER_CAST(data.component.lock()); + Component(BLACKSMITH,"Item Icon")->SetItem(rowItem.lock()->GetItem()); return true; }, [](MenuFuncData data){ @@ -152,7 +152,7 @@ void Menu::InitializeBlacksmithCraftingWindow(){ return true; }, InventoryCreator::RowPlayerArmor_InventoryUpdate, - {.padding=1,.size={207,28}} + InventoryWindowOptions{.padding=1,.size={207,28}} )END; AddInventoryListener(armorDisplay,"Equipment"); armorDisplay->Enable(false); @@ -161,25 +161,25 @@ void Menu::InitializeBlacksmithCraftingWindow(){ #pragma region Inventory Description float inventoryDescriptionWidth=blacksmithWindow->pos.x+blacksmithWindow->size.x-26-224; - blacksmithWindow->ADD("Item Description Outline",MenuLabel)({{224,28},{inventoryDescriptionWidth,blacksmithWindow->size.y-44}},"",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; - blacksmithWindow->ADD("Item Icon",MenuItemItemButton)({{226+inventoryDescriptionWidth/2-24,30},{48,48}},Item::BLANK,MenuType::ENUM_END,DO_NOTHING,"","",IconButtonAttr::NOT_SELECTABLE)END; - blacksmithWindow->ADD("Item Name Label",MenuLabel)({{226,84},{inventoryDescriptionWidth-6,12}},"",0.75f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; - blacksmithWindow->ADD("Item Description Label",MenuLabel)({{226,94},{inventoryDescriptionWidth-6,blacksmithWindow->size.y-44-66}},"",0.5f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; + blacksmithWindow->ADD("Item Description Outline",MenuLabel)(geom2d::rect{{224,28},{inventoryDescriptionWidth,blacksmithWindow->size.y-44}},"",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; + blacksmithWindow->ADD("Item Icon",MenuItemItemButton)(geom2d::rect{{226+inventoryDescriptionWidth/2-24,30},{48,48}},Item::BLANK,MenuType::ENUM_END,DO_NOTHING,"","",IconButtonAttr::NOT_SELECTABLE)END; + blacksmithWindow->ADD("Item Name Label",MenuLabel)(geom2d::rect{{226,84},{inventoryDescriptionWidth-6,12}},"",0.75f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; + blacksmithWindow->ADD("Item Description Label",MenuLabel)(geom2d::rect{{226,94},{inventoryDescriptionWidth-6,blacksmithWindow->size.y-44-66}},"",0.5f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; #pragma endregion #pragma region Money Display vf2d moneyIconPos={224+inventoryDescriptionWidth-24,28+blacksmithWindow->size.y-44+6}; - auto moneyIcon=blacksmithWindow->ADD("Money Icon",MenuIconButton)({moneyIconPos,{24,24}},GFX["money.png"].Decal(),DO_NOTHING,IconButtonAttr::NOT_SELECTABLE|IconButtonAttr::NO_OUTLINE|IconButtonAttr::NO_BACKGROUND)END; + auto moneyIcon=blacksmithWindow->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; std::string moneyText=std::to_string(game->GetPlayer()->GetMoney()); vf2d moneyTextSize=game->GetTextSizeProp(moneyText)*2; - auto moneyDisplay=blacksmithWindow->ADD("Money Label",PlayerMoneyLabel)({moneyIconPos-vf2d{2+moneyTextSize.x,-2},moneyTextSize},2,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN|ComponentAttr::FIT_TO_LABEL)END; + auto moneyDisplay=blacksmithWindow->ADD("Money Label",PlayerMoneyLabel)(geom2d::rect{moneyIconPos-vf2d{2+moneyTextSize.x,-2},moneyTextSize},2,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN|ComponentAttr::FIT_TO_LABEL)END; moneyDisplay->SetRightAlignment(true); Player::AddMoneyListener(moneyDisplay); #pragma endregion - blacksmithWindow->ADD("Leave Button",MenuComponent)({{blacksmithWindow->size.x/2-48,28+blacksmithWindow->size.y-44+6},{96,24}},"Leave",MenuType::ENUM_END, + blacksmithWindow->ADD("Leave Button",MenuComponent)(geom2d::rect{{blacksmithWindow->size.x/2-48,28+blacksmithWindow->size.y-44+6},{96,24}},"Leave",MenuType::ENUM_END, [](MenuFuncData data){ Menu::CloseMenu(); return true; - },{2,2})END; + },vf2d{2,2})END; } \ No newline at end of file diff --git a/Adventures in Lestoria/BuyItemWindow.cpp b/Adventures in Lestoria/BuyItemWindow.cpp index a640fad0..7c1456fc 100644 --- a/Adventures in Lestoria/BuyItemWindow.cpp +++ b/Adventures in Lestoria/BuyItemWindow.cpp @@ -62,27 +62,27 @@ void Menu::InitializeBuyItemWindow(){ Component(BUY_ITEM,"Purchase Button")->SetGrayedOut(!canPurchase); }; - buyItemWindow->ADD("Item Purchase Header",MenuLabel)({{2,2},{188,12}},"Buying ",1,ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND|ComponentAttr::SHADOW|ComponentAttr::FIT_TO_LABEL)END; + buyItemWindow->ADD("Item Purchase Header",MenuLabel)(geom2d::rect{{2,2},{188,12}},"Buying ",1.f,ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND|ComponentAttr::SHADOW|ComponentAttr::FIT_TO_LABEL)END; - buyItemWindow->ADD("Price Per Item Label",MenuLabel)({{4,18},{188,12}},"Price Per Item",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; - buyItemWindow->ADD("Amount to Buy Label",MenuLabel)({{4,34},{188,12}},"Amount to Buy",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; - buyItemWindow->ADD("Price Label",MenuLabel)({{4,50},{188,12}},"Total Cost",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; + buyItemWindow->ADD("Price Per Item Label",MenuLabel)(geom2d::rect{{4,18},{188,12}},"Price Per Item",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; + buyItemWindow->ADD("Amount to Buy Label",MenuLabel)(geom2d::rect{{4,34},{188,12}},"Amount to Buy",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; + buyItemWindow->ADD("Price Label",MenuLabel)(geom2d::rect{{4,50},{188,12}},"Total Cost",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; - buyItemWindow->ADD("Price per item Amount Label",MenuLabel)({{buyItemWindow->size.x/2+28,18},{72,12}},"0",1.0f,ComponentAttr::SHADOW|ComponentAttr::FIT_TO_LABEL)END; - buyItemWindow->ADD("Amount to buy Amount Label",MenuLabel)({{buyItemWindow->size.x/2+48,34},{32,12}},"0",1.0f,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::FIT_TO_LABEL)END; + buyItemWindow->ADD("Price per item Amount Label",MenuLabel)(geom2d::rect{{buyItemWindow->size.x/2+28,18},{72,12}},"0",1.0f,ComponentAttr::SHADOW|ComponentAttr::FIT_TO_LABEL)END; + buyItemWindow->ADD("Amount to buy Amount Label",MenuLabel)(geom2d::rect{{buyItemWindow->size.x/2+48,34},{32,12}},"0",1.0f,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::FIT_TO_LABEL)END; - buyItemWindow->ADD("Increase buy amount Button",MenuComponent)({{buyItemWindow->size.x/2+80+2,34},{12,12}},"+",[&](MenuFuncData data){ + buyItemWindow->ADD("Increase buy amount Button",MenuComponent)(geom2d::rect{{buyItemWindow->size.x/2+80+2,34},{12,12}},"+",[&](MenuFuncData data){ UpdateMenu(GetQuantity()+1); return true; })END; - buyItemWindow->ADD("Decrease buy amount Button",MenuComponent)({{buyItemWindow->size.x/2+48-14,34},{12,12}},"-",[](MenuFuncData data){ + buyItemWindow->ADD("Decrease buy amount Button",MenuComponent)(geom2d::rect{{buyItemWindow->size.x/2+48-14,34},{12,12}},"-",[](MenuFuncData data){ UpdateMenu(GetQuantity()-1); return true; })END; - buyItemWindow->ADD("Total Price Amount Label",MenuLabel)({{buyItemWindow->size.x/2+28,50},{72,12}},"0",1.0f,ComponentAttr::SHADOW|ComponentAttr::FIT_TO_LABEL)END; + buyItemWindow->ADD("Total Price Amount Label",MenuLabel)(geom2d::rect{{buyItemWindow->size.x/2+28,50},{72,12}},"0",1.0f,ComponentAttr::SHADOW|ComponentAttr::FIT_TO_LABEL)END; - buyItemWindow->ADD("Purchase Button",MenuComponent)({{buyItemWindow->size.x/2+18,70},{64,12}},"Purchase",[&](MenuFuncData data){ + buyItemWindow->ADD("Purchase Button",MenuComponent)(geom2d::rect{{buyItemWindow->size.x/2+18,70},{64,12}},"Purchase",[&](MenuFuncData data){ Merchant&merchant=Merchant::GetCurrentTravelingMerchant(); const std::string&item=Component(BUY_ITEM,"Item Purchase Header")->GetString(A::ITEM_NAME); merchant.PurchaseItem(item,GetQuantity()); @@ -90,7 +90,7 @@ void Menu::InitializeBuyItemWindow(){ Menu::CloseMenu(); return true; })END; - buyItemWindow->ADD("Cancel Button",MenuComponent)({{buyItemWindow->size.x/2-82,70},{64,12}},"Cancel",[](MenuFuncData data){ + buyItemWindow->ADD("Cancel Button",MenuComponent)(geom2d::rect{{buyItemWindow->size.x/2-82,70},{64,12}},"Cancel",[](MenuFuncData data){ Menu::CloseMenu(); return true; })END; diff --git a/Adventures in Lestoria/CharacterInfoWindow.cpp b/Adventures in Lestoria/CharacterInfoWindow.cpp index 57c16b48..6ab52082 100644 --- a/Adventures in Lestoria/CharacterInfoWindow.cpp +++ b/Adventures in Lestoria/CharacterInfoWindow.cpp @@ -53,23 +53,23 @@ void Menu::InitializeClassInfoWindow(){ Menu*classSelectionWindow=Menu::menus[CLASS_SELECTION]; ClassInfo data=classutils::GetClassInfo(classSelectionWindow->S(A::CLASS_SELECTION)); - auto label=classInfoWindow->ADD("Class Name",MenuLabel)({{0,0},{classInfoWindow->size.x-1,24}},data.className,2,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; + auto label=classInfoWindow->ADD("Class Name",MenuLabel)(geom2d::rect{{0,0},{classInfoWindow->size.x-1,24}},data.className,2,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; - classInfoWindow->ADD("Rotating Character Display",CharacterRotatingDisplay)({{15,48},{72,120}},GFX[data.classFullImgName].Decal())END; + classInfoWindow->ADD("Rotating Character Display",CharacterRotatingDisplay)(geom2d::rect{{15,48},{72,120}},GFX[data.classFullImgName].Decal())END; vf2d healthDisplayLabelPos={classInfoWindow->size.x/3,label->GetPos().y+24}; vf2d labelSize={2*classInfoWindow->size.x/3-1,16}; - classInfoWindow->ADD("Base Stats Text",MenuLabel)({{0,label->GetPos().y+24},{classInfoWindow->size.x/3,labelSize.y}},"Base Stats",1,ComponentAttr::SHADOW|ComponentAttr::OUTLINE)END; - classInfoWindow->ADD("Health Display Text",MenuLabel)({healthDisplayLabelPos+vf2d{0,16*0},labelSize},"Health: "+std::to_string(data.baseHealth)+" + "+std::to_string(data.healthGrowthRate).substr(0,3)+" per level",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE)END; - classInfoWindow->ADD("Attack Display Text",MenuLabel)({healthDisplayLabelPos+vf2d{0,16*1},labelSize},"Attack: "+std::to_string(data.baseAtk)+" + "+std::to_string(data.atkGrowthRate).substr(0,3)+" per level",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE)END; + classInfoWindow->ADD("Base Stats Text",MenuLabel)(geom2d::rect{{0,label->GetPos().y+24},{classInfoWindow->size.x/3,labelSize.y}},"Base Stats",1,ComponentAttr::SHADOW|ComponentAttr::OUTLINE)END; + classInfoWindow->ADD("Health Display Text",MenuLabel)(geom2d::rect{healthDisplayLabelPos+vf2d{0,16*0},labelSize},"Health: "+std::to_string(data.baseHealth)+" + "+std::to_string(data.healthGrowthRate).substr(0,3)+" per level",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE)END; + classInfoWindow->ADD("Attack Display Text",MenuLabel)(geom2d::rect{healthDisplayLabelPos+vf2d{0,16*1},labelSize},"Attack: "+std::to_string(data.baseAtk)+" + "+std::to_string(data.atkGrowthRate).substr(0,3)+" per level",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE)END; vf2d abilityIconOffsets = {0,32}; - classInfoWindow->ADD("Ability 1 Display",CharacterAbilityPreviewComponent)({healthDisplayLabelPos+vf2d{0,32*0}+abilityIconOffsets,labelSize*vf2d{1,2}},data.ability1)END; - classInfoWindow->ADD("Ability 2 Display",CharacterAbilityPreviewComponent)({healthDisplayLabelPos+vf2d{0,32*1}+abilityIconOffsets,labelSize*vf2d{1,2}},data.ability2)END; - classInfoWindow->ADD("Ability 3 Display",CharacterAbilityPreviewComponent)({healthDisplayLabelPos+vf2d{0,32*2}+abilityIconOffsets,labelSize*vf2d{1,2}},data.ability3)END; - classInfoWindow->ADD("Right Click Ability Display",CharacterAbilityPreviewComponent)({healthDisplayLabelPos+vf2d{0,32*3}+abilityIconOffsets,labelSize*vf2d{1,2}},data.rightClickAbility)END; + classInfoWindow->ADD("Ability 1 Display",CharacterAbilityPreviewComponent)(geom2d::rect{healthDisplayLabelPos+vf2d{0,32*0}+abilityIconOffsets,labelSize*vf2d{1,2}},data.ability1)END; + classInfoWindow->ADD("Ability 2 Display",CharacterAbilityPreviewComponent)(geom2d::rect{healthDisplayLabelPos+vf2d{0,32*1}+abilityIconOffsets,labelSize*vf2d{1,2}},data.ability2)END; + classInfoWindow->ADD("Ability 3 Display",CharacterAbilityPreviewComponent)(geom2d::rect{healthDisplayLabelPos+vf2d{0,32*2}+abilityIconOffsets,labelSize*vf2d{1,2}},data.ability3)END; + classInfoWindow->ADD("Right Click Ability Display",CharacterAbilityPreviewComponent)(geom2d::rect{healthDisplayLabelPos+vf2d{0,32*3}+abilityIconOffsets,labelSize*vf2d{1,2}},data.rightClickAbility)END; - classInfoWindow->ADD("Back Button",MenuComponent)({{classInfoWindow->center().x/2,healthDisplayLabelPos.y+32*4+abilityIconOffsets.y+12},{classInfoWindow->size.x/2,16}},"Back",[](MenuFuncData data){Menu::CloseMenu();return true;})END; + classInfoWindow->ADD("Back Button",MenuComponent)(geom2d::rect{{classInfoWindow->center().x/2,healthDisplayLabelPos.y+32*4+abilityIconOffsets.y+12},{classInfoWindow->size.x/2,16}},"Back",[](MenuFuncData data){Menu::CloseMenu();return true;})END; } \ No newline at end of file diff --git a/Adventures in Lestoria/CharacterMenuWindow.cpp b/Adventures in Lestoria/CharacterMenuWindow.cpp index b160a4c4..56ba231e 100644 --- a/Adventures in Lestoria/CharacterMenuWindow.cpp +++ b/Adventures in Lestoria/CharacterMenuWindow.cpp @@ -58,9 +58,9 @@ void Menu::InitializeCharacterMenuWindow(){ vf2d windowSize=game->GetScreenSize()-vf2d{52,52}; Menu*characterMenuWindow=CreateMenu(CHARACTER_MENU,CENTERED,windowSize); - characterMenuWindow->ADD("Character Label",MenuLabel)({{0,-4},{float(windowSize.x)-1,24}},"Character",2,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; - characterMenuWindow->ADD("Equip Slot Outline",MenuComponent)({{0,28},{120,windowSize.y-37}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END; - characterMenuWindow->ADD("Character Rotating Display",CharacterRotatingDisplay)({{135,28},{90,windowSize.y-48}},GFX[classutils::GetClassInfo(game->GetPlayer()->GetClassName()).classFullImgName].Decal())END; + characterMenuWindow->ADD("Character Label",MenuLabel)(geom2d::rect{{0,-4},{float(windowSize.x)-1,24}},"Character",2,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; + characterMenuWindow->ADD("Equip Slot Outline",MenuComponent)(geom2d::rect{{0,28},{120,windowSize.y-37}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END; + characterMenuWindow->ADD("Character Rotating Display",CharacterRotatingDisplay)(geom2d::rect{{135,28},{90,windowSize.y-48}},GFX[classutils::GetClassInfo(game->GetPlayer()->GetClassName()).classFullImgName].Decal())END; const static std::arraydisplayAttrs{ "Health", @@ -73,22 +73,22 @@ void Menu::InitializeCharacterMenuWindow(){ }; - characterMenuWindow->ADD("Equip Selection Outline",MenuComponent)({{123,28},{120,windowSize.y-37}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END + characterMenuWindow->ADD("Equip Selection Outline",MenuComponent)(geom2d::rect{{123,28},{120,windowSize.y-37}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END ->Enable(false); - characterMenuWindow->ADD("Equip List",ScrollableWindowComponent)({{123,28},{120,windowSize.y-37-24}})DEPTH -1 END + characterMenuWindow->ADD("Equip List",ScrollableWindowComponent)(geom2d::rect{{123,28},{120,windowSize.y-37-24}})DEPTH -1 END ->Enable(false); - characterMenuWindow->ADD("Equip Selection Bottom Outline",MenuComponent)({{123,28+(windowSize.y-37-24)},{120,24}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END + characterMenuWindow->ADD("Equip Selection Bottom Outline",MenuComponent)(geom2d::rect{{123,28+(windowSize.y-37-24)},{120,24}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END ->Enable(false); - auto equipSelectionSelectButton=characterMenuWindow->ADD("Equip Selection Select Button",MenuComponent)({{123+12,28+(windowSize.y-37-24)+6},{96,12}},"Select", + auto equipSelectionSelectButton=characterMenuWindow->ADD("Equip Selection Select Button",MenuComponent)(geom2d::rect{{123+12,28+(windowSize.y-37-24)+6},{96,12}},"Select", [](MenuFuncData data){ - Component(data.component->parentMenu,"Equip Selection Outline")->Enable(false); - Component(data.component->parentMenu,"Equip List")->Enable(false); - Component(data.component->parentMenu,"Equip Selection Bottom Outline")->Enable(false); - Component(data.component->parentMenu,"Equip Selection Select Button")->Enable(false); - Component(data.component->parentMenu,"Character Rotating Display")->Enable(true); + Component(data.component.lock()->parentMenu,"Equip Selection Outline")->Enable(false); + Component(data.component.lock()->parentMenu,"Equip List")->Enable(false); + Component(data.component.lock()->parentMenu,"Equip Selection Bottom Outline")->Enable(false); + Component(data.component.lock()->parentMenu,"Equip Selection Select Button")->Enable(false); + Component(data.component.lock()->parentMenu,"Character Rotating Display")->Enable(true); for(int counter=0;const std::string&attribute:displayAttrs){ - StatLabel*statDisplayLabel=Component(CHARACTER_MENU,"Attribute "+std::string(ItemAttribute::Get(attribute).Name())+" Label"); - statDisplayLabel->SetStatChangeAmt(0); + std::weak_ptrstatDisplayLabel=Component(CHARACTER_MENU,"Attribute "+std::string(ItemAttribute::Get(attribute).Name())+" Label"); + statDisplayLabel.lock()->SetStatChangeAmt(0); } equipmentWindowOpened=false; return true; @@ -117,9 +117,9 @@ void Menu::InitializeCharacterMenuWindow(){ } const static std::arrayslotNames{"Helmet","Weapon","Armor","Gloves","Pants","Shoes","Ring 1","Ring 2"}; EquipSlot slot=EquipSlot(equipSlot); - auto equipmentSlot=characterMenuWindow->ADD("Equip Slot "+slotNames[i],EquipSlotButton)({{x,y+28},{24,24}},slot,MenuType::ENUM_END, + auto equipmentSlot=characterMenuWindow->ADD("Equip Slot "+slotNames[i],EquipSlotButton)(geom2d::rect{{x,y+28},{24,24}},slot,MenuType::ENUM_END, [&](MenuFuncData data){ - EquipSlot slot=EquipSlot(data.component->I(Attribute::EQUIP_TYPE)); + EquipSlot slot=EquipSlot(data.component.lock()->I(Attribute::EQUIP_TYPE)); const std::vector>&equips=Inventory::get("Equipment"); const std::vector>&accessories=Inventory::get("Accessories"); @@ -131,40 +131,36 @@ void Menu::InitializeCharacterMenuWindow(){ return it->GetEquipSlot()&slot; }); - ScrollableWindowComponent*equipList=Component(data.component->parentMenu,"Equip List"); + std::shared_ptrequipList=Component(data.component.lock()->parentMenu,"Equip List"); equipList->RemoveAllComponents(); for(int counter=0;const std::weak_ptrit:availableEquipment){ - const static auto OppositeRingSlotDoesNotMatchCurrentEquip=[](RowItemDisplay*comp){ - EquipSlot slot=EquipSlot(comp->I(Attribute::EQUIP_TYPE)); + const static auto OppositeRingSlotDoesNotMatchCurrentEquip=[](std::weak_ptrcomp){ + EquipSlot slot=EquipSlot(comp.lock()->I(Attribute::EQUIP_TYPE)); std::weak_ptrotherItem; if(slot&EquipSlot::RING1)otherItem=Inventory::GetEquip(EquipSlot::RING2); else if(slot&EquipSlot::RING2)otherItem=Inventory::GetEquip(EquipSlot::RING1); - return ISBLANK(otherItem)||(&*comp->GetItem().lock()!=&*otherItem.lock()); + return ISBLANK(otherItem)||(&*comp.lock()->GetItem().lock()!=&*otherItem.lock()); }; - auto equip=equipList->ADD("Equip Item "+std::to_string(counter),RowItemDisplay)({{2,2+counter*29.f},{120-15,28}},it, + auto equip=equipList->ADD("Equip Item "+std::to_string(counter),RowItemDisplay)(geom2d::rect{{2,2+counter*29.f},{120-15,28}},it, [](MenuFuncData data){ - RowItemDisplay*comp=DYNAMIC_CAST(data.component); - if(comp!=nullptr){ - if(OppositeRingSlotDoesNotMatchCurrentEquip(comp)){ //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->GetItem(),EquipSlot(comp->I(Attribute::EQUIP_TYPE))); - SoundEffect::PlaySFX(comp->GetItem().lock()->UseSound(),SoundEffect::CENTERED); - for(MenuComponent*button:((ScrollableWindowComponent*)data.parentComponent)->GetComponents()){ - RowItemDisplay*comp=DYNAMIC_CAST(button); - if(comp!=nullptr){ - comp->SetSelected(false); - }else{ - ERR("WARNING! Attempting to cast a button that isn't a RowItemDisplay!"); - } + std::weak_ptrcomp=DYNAMIC_POINTER_CAST(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))); + SoundEffect::PlaySFX(comp.lock()->GetItem().lock()->UseSound(),SoundEffect::CENTERED); + for(std::weak_ptrbutton:DYNAMIC_POINTER_CAST(data.parentComponent.lock())->GetComponents()){ + std::weak_ptrcomp=DYNAMIC_POINTER_CAST(button.lock()); + comp.lock()->SetSelected(false); } - comp->SetSelected(true); + comp.lock()->SetSelected(true); for(int counter=0;const std::string&attribute:displayAttrs){ - StatLabel*statDisplayLabel=Component(CHARACTER_MENU,"Attribute "+std::string(ItemAttribute::Get(attribute).Name())+" Label"); + std::shared_ptrstatDisplayLabel=Component(CHARACTER_MENU,"Attribute "+std::string(ItemAttribute::Get(attribute).Name())+" Label"); statDisplayLabel->SetStatChangeAmt(0); } - MenuItemItemButton*equipButton=Component(CHARACTER_MENU,"Equip Slot "+slotNames[data.parentComponent->I(A::INDEXED_THEME)]); - equipButton->SetItem(comp->GetItem(),false); + std::shared_ptrequipButton=Component(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!"); @@ -174,11 +170,11 @@ void Menu::InitializeCharacterMenuWindow(){ equip->SetHoverFunc( [&](MenuFuncData data){ - RowItemDisplay*button=DYNAMIC_CAST(data.component); - if(button!=nullptr){ - const std::weak_ptrbuttonItem=button->GetItem(); + std::weak_ptrbutton=DYNAMIC_POINTER_CAST(data.component.lock()); + if(!button.expired()){ + const std::weak_ptrbuttonItem=button.lock()->GetItem(); std::vectorstatsBeforeEquip; - EquipSlot slot=EquipSlot(button->I(Attribute::EQUIP_TYPE)); + EquipSlot slot=EquipSlot(button.lock()->I(Attribute::EQUIP_TYPE)); for(const std::string&attribute:displayAttrs){ statsBeforeEquip.push_back(game->GetPlayer()->GetStat(attribute)); } @@ -188,12 +184,12 @@ void Menu::InitializeCharacterMenuWindow(){ if(slot==EquipSlot::RING1)otherItem=Inventory::GetEquip(EquipSlot::RING2); else if(slot==EquipSlot::RING2)otherItem=Inventory::GetEquip(EquipSlot::RING1); - if(OppositeRingSlotDoesNotMatchCurrentEquip(button)){ //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. + 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 std::string&attribute:displayAttrs){ - StatLabel*statDisplayLabel=Component(CHARACTER_MENU,"Attribute "+std::string(ItemAttribute::Get(attribute).Name())+" Label"); + std::weak_ptrstatDisplayLabel=Component(CHARACTER_MENU,"Attribute "+std::string(ItemAttribute::Get(attribute).Name())+" Label"); int statChangeAmt=game->GetPlayer()->GetStat(attribute)-statsBeforeEquip[counter]; - statDisplayLabel->SetStatChangeAmt(statChangeAmt); + statDisplayLabel.lock()->SetStatChangeAmt(statChangeAmt); counter++; } Inventory::UnequipItem(slot); @@ -214,8 +210,8 @@ void Menu::InitializeCharacterMenuWindow(){ equip->SetMouseOutFunc( [](MenuFuncData data){ for(int counter=0;const std::string&attribute:displayAttrs){ - StatLabel*statDisplayLabel=Component(CHARACTER_MENU,"Attribute "+std::string(ItemAttribute::Get(attribute).Name())+" Label"); - statDisplayLabel->SetStatChangeAmt(0); + std::weak_ptrstatDisplayLabel=Component(CHARACTER_MENU,"Attribute "+std::string(ItemAttribute::Get(attribute).Name())+" Label"); + statDisplayLabel.lock()->SetStatChangeAmt(0); counter++; } return true; @@ -232,27 +228,27 @@ void Menu::InitializeCharacterMenuWindow(){ counter++; } - equipList->I(Attribute::INDEXED_THEME)=data.component->I(Attribute::INDEXED_THEME); - Component(data.component->parentMenu,"Equip Selection Outline")->Enable(true); + equipList->I(Attribute::INDEXED_THEME)=data.component.lock()->I(Attribute::INDEXED_THEME); + Component(data.component.lock()->parentMenu,"Equip Selection Outline")->Enable(true); equipList->Enable(true); - Component(data.component->parentMenu,"Equip Selection Bottom Outline")->Enable(true); - Component(data.component->parentMenu,"Equip Selection Select Button")->Enable(true); - Component(data.component->parentMenu,"Character Rotating Display")->Enable(false); + Component(data.component.lock()->parentMenu,"Equip Selection Bottom Outline")->Enable(true); + Component(data.component.lock()->parentMenu,"Equip Selection Select Button")->Enable(true); + Component(data.component.lock()->parentMenu,"Character Rotating Display")->Enable(false); equipmentWindowOpened=true; return true; },[](MenuFuncData data){//On Mouse Hover - EquipSlot slot=DYNAMIC_CAST(data.component)->GetSlot(); + EquipSlot slot=DYNAMIC_POINTER_CAST(data.component.lock())->GetSlot(); const std::weak_ptrequip=Inventory::GetEquip(slot); if(!ISBLANK(equip)){ - Component(data.component->parentMenu,"Character Rotating Display")->Enable(false); + Component(data.component.lock()->parentMenu,"Character Rotating Display")->Enable(false); } return true; },[](MenuFuncData data){//On Mouse Out if(!equipmentWindowOpened){ - Component(data.component->parentMenu,"Item Equip Description")->SetLabel(""); - Component(data.component->parentMenu,"Item Equip Name")->Enable(false); - Component(data.component->parentMenu,"Item Equip Description")->Enable(false); - Component(data.component->parentMenu,"Character Rotating Display")->Enable(true); + Component(data.component.lock()->parentMenu,"Item Equip Description")->SetLabel(""); + Component(data.component.lock()->parentMenu,"Item Equip Name")->Enable(false); + Component(data.component.lock()->parentMenu,"Item Equip Description")->Enable(false); + Component(data.component.lock()->parentMenu,"Character Rotating Display")->Enable(true); } return true; },"Item Equip Name","Item Equip Description")END; @@ -262,26 +258,26 @@ void Menu::InitializeCharacterMenuWindow(){ equipmentSlot->SetShowQuantity(false); equipmentSlot->SetCompactDescriptions(false); equipSlot<<=1; - characterMenuWindow->ADD("Equip Label "+slotNames[i],PopupMenuLabel)({{labelX,labelY},{24,16}},slotNames[i],{0.5,1},ComponentAttr::SHADOW)END; + characterMenuWindow->ADD("Equip Label "+slotNames[i],PopupMenuLabel)(geom2d::rect{{labelX,labelY},{24,16}},slotNames[i],vf2d{0.5,1.f},ComponentAttr::SHADOW)END; Menu::AddEquipStatListener(equipmentSlot); } - characterMenuWindow->ADD("Stat Display Outline",MenuComponent)({{245,28},{62,windowSize.y-37}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END; + characterMenuWindow->ADD("Stat Display Outline",MenuComponent)(geom2d::rect{{245,28},{62,windowSize.y-37}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END; int yOffset=0; for(const std::string&attribute:displayAttrs){ std::string attrStr=GetLabelText(ItemAttribute::Get(attribute)); - auto attrLabel=characterMenuWindow->ADD("Attribute "+std::string(ItemAttribute::Get(attribute).Name())+" Label",StatLabel)({{245,28+2+float(yOffset)},{62,18}},ItemAttribute::Get(attribute),1,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN)END; + auto attrLabel=characterMenuWindow->ADD("Attribute "+std::string(ItemAttribute::Get(attribute).Name())+" Label",StatLabel)(geom2d::rect{{245,28+2+float(yOffset)},{62,18}},ItemAttribute::Get(attribute),1,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN)END; Menu::AddEquipStatListener(attrLabel); yOffset+=20; } - characterMenuWindow->ADD("Back button",MenuComponent)({{windowSize.x/2-64,windowSize.y},{128,12}},"Back",[](MenuFuncData data){Menu::stack.pop_back();return true;})END; + characterMenuWindow->ADD("Back button",MenuComponent)(geom2d::rect{{windowSize.x/2-64,windowSize.y},{128,12}},"Back",[](MenuFuncData data){Menu::stack.pop_back();return true;})END; - auto itemNameDisplay=characterMenuWindow->ADD("Item Name",MenuLabel)({{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)({{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)({{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)({{123,40},{120,windowSize.y-49}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::SHADOW)END; + auto itemNameDisplay=characterMenuWindow->ADD("Item Name",MenuLabel)(geom2d::rect{{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{{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{{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{{123,40},{120,windowSize.y-49}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::SHADOW)END; itemNameDisplay->Enable(false); itemDescriptionDisplay->Enable(false); diff --git a/Adventures in Lestoria/ClassSelectionWindow.cpp b/Adventures in Lestoria/ClassSelectionWindow.cpp index d7d4fdf4..98ffd2d6 100644 --- a/Adventures in Lestoria/ClassSelectionWindow.cpp +++ b/Adventures in Lestoria/ClassSelectionWindow.cpp @@ -53,16 +53,16 @@ void Menu::InitializeClassSelectionWindow(){ vf2d outlineSize=classSelectionWindow->size-vf2d{13,13}; - classSelectionWindow->ADD("Class Selection Title Label",MenuLabel)({{4,20},{outlineSize.x,32}},"Choose a Character Class",2,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; + classSelectionWindow->ADD("Class Selection Title Label",MenuLabel)(geom2d::rect{{4,20},{outlineSize.x,32}},"Choose a Character Class",2,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; - auto outline=classSelectionWindow->ADD("Outline Border",MenuLabel)({{4,4},outlineSize},"",1,ComponentAttr::OUTLINE)END; + auto outline=classSelectionWindow->ADD("Outline Border",MenuLabel)(geom2d::rect{{4,4},outlineSize},"",1,ComponentAttr::OUTLINE)END; vf2d navigationButtonSize={24*2.5f,16}; - classSelectionWindow->ADD("Back Button",MenuComponent)({{4+2,outlineSize.y+4-navigationButtonSize.y-2},navigationButtonSize},"Back",[](MenuFuncData data){Menu::CloseMenu();return true;})END; + classSelectionWindow->ADD("Back Button",MenuComponent)(geom2d::rect{{4+2,outlineSize.y+4-navigationButtonSize.y-2},navigationButtonSize},"Back",[](MenuFuncData data){Menu::CloseMenu();return true;})END; - classSelectionWindow->ADD("Confirm",MenuComponent)({{outlineSize.x+4-navigationButtonSize.x-2,outlineSize.y+4-navigationButtonSize.y-2},navigationButtonSize},"Confirm",[](MenuFuncData data){ - std::string selectedClass=data.component->S(A::CLASS_SELECTION); + classSelectionWindow->ADD("Confirm",MenuComponent)(geom2d::rect{{outlineSize.x+4-navigationButtonSize.x-2,outlineSize.y+4-navigationButtonSize.y-2},navigationButtonSize},"Confirm",[](MenuFuncData data){ + std::string selectedClass=data.component.lock()->S(A::CLASS_SELECTION); data.game->ChangePlayerClass(classutils::StringToClass(selectedClass)); GameState::ChangeState(States::OVERWORLD_MAP); return true; @@ -93,7 +93,7 @@ void Menu::InitializeClassSelectionWindow(){ Witch::walk_s, }; - std::vectortoggleGroup; + std::vector>toggleGroup; for(int i=0;i<6;i++){ std::string className=classNames[i]; @@ -109,19 +109,19 @@ void Menu::InitializeClassSelectionWindow(){ vf2d backgroundSize={floor(outlineSize.y/3-buttonPadding.y*3),outlineSize.y/3-buttonPadding.y*3}; //The floor is for fixing a small pixel rounding bug. - classSelectionWindow->ADD(className+" Background",MenuLabel)({backgroundOffsetPos,backgroundSize},"",1,ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; - classSelectionWindow->ADD(className+" Button",MenuComponent)({offsetPos,buttonSize},"Info",CLASS_INFO, + classSelectionWindow->ADD(className+" Background",MenuLabel)(geom2d::rect{backgroundOffsetPos,backgroundSize},"",1,ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; + classSelectionWindow->ADD(className+" Button",MenuComponent)(geom2d::rect{offsetPos,buttonSize},"Info",CLASS_INFO, [](MenuFuncData data){ - data.menu.S(A::CLASS_SELECTION)=data.component->S(A::CLASS_SELECTION); + data.menu.S(A::CLASS_SELECTION)=data.component.lock()->S(A::CLASS_SELECTION); delete Menu::menus[CLASS_INFO]; Menu::InitializeClassInfoWindow(); return true; })END ->S(A::CLASS_SELECTION)=className; - classSelectionWindow->ADD(className+" Label",MenuLabel)({backgroundOffsetPos,buttonSize},className,1,ComponentAttr::SHADOW)END; - auto classSprite=classSelectionWindow->ADD(className+" Icon",MenuAnimatedIconToggleButton)({backgroundOffsetPos+vf2d{0,12},backgroundSize+vf2d{0,-buttonSize.y-12}},classAnimationName,[](MenuFuncData data){ + classSelectionWindow->ADD(className+" Label",MenuLabel)(geom2d::rect{backgroundOffsetPos,buttonSize},className,1,ComponentAttr::SHADOW)END; + auto classSprite=classSelectionWindow->ADD(className+" Icon",MenuAnimatedIconToggleButton)(geom2d::rect{backgroundOffsetPos+vf2d{0,12},backgroundSize+vf2d{0,-buttonSize.y-12}},classAnimationName,[](MenuFuncData data){ data.menu.components["Confirm"]->Enable(true); - data.menu.components["Confirm"]->S(A::CLASS_SELECTION)=data.component->S(A::CLASS_SELECTION); + data.menu.components["Confirm"]->S(A::CLASS_SELECTION)=data.component.lock()->S(A::CLASS_SELECTION); return true; })END; @@ -130,7 +130,7 @@ void Menu::InitializeClassSelectionWindow(){ toggleGroup.push_back(classSprite); } - for(IToggleable*item:toggleGroup){ - item->SetToggleGroup(toggleGroup); + for(std::weak_ptritem:toggleGroup){ + item.lock()->SetToggleGroup(toggleGroup); } } \ No newline at end of file diff --git a/Adventures in Lestoria/ConsumableCraftItemWindow.cpp b/Adventures in Lestoria/ConsumableCraftItemWindow.cpp index 0a25ad48..ec1d4801 100644 --- a/Adventures in Lestoria/ConsumableCraftItemWindow.cpp +++ b/Adventures in Lestoria/ConsumableCraftItemWindow.cpp @@ -47,7 +47,7 @@ using A=Attribute; void Menu::InitializeConsumableCraftItemWindow(){ Menu*consumableCraftItemWindow=CreateMenu(CONSUMABLE_CRAFT_ITEM,CENTERED,{240,96}); - consumableCraftItemWindow->ADD("Item Name Header",MenuLabel)({{2,-4},{consumableCraftItemWindow->size.x-4,12}},"Item Name",1.0f,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; + consumableCraftItemWindow->ADD("Item Name Header",MenuLabel)(geom2d::rect{{2,-4},{consumableCraftItemWindow->size.x-4,12}},"Item Name",1.0f,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; static auto GetQuantity=[&](){ return std::stoi(Component(CONSUMABLE_CRAFT_ITEM,"Amount to Craft Amount Label")->GetLabel()); @@ -65,28 +65,28 @@ void Menu::InitializeConsumableCraftItemWindow(){ Component(CONSUMABLE_CRAFT_ITEM,"Craft Button")->SetGrayedOut(!canCraft); }; - consumableCraftItemWindow->ADD("Amount to Craft Label",MenuLabel)({{4,34},{188,12}},"Craft Amount",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; - consumableCraftItemWindow->ADD("Amount to Craft Amount Label",MenuLabel)({{consumableCraftItemWindow->size.x/2+48,34},{32,12}},"1" + consumableCraftItemWindow->ADD("Amount to Craft Label",MenuLabel)(geom2d::rect{{4,34},{188,12}},"Craft Amount",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; + consumableCraftItemWindow->ADD("Amount to Craft Amount Label",MenuLabel)(geom2d::rect{{consumableCraftItemWindow->size.x/2+48,34},{32,12}},"1" ,UpdateMenu,1.0f,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::FIT_TO_LABEL)END; - consumableCraftItemWindow->ADD("Increase Craft amount Button",MenuComponent)({{consumableCraftItemWindow->size.x/2+80+2,34},{12,12}},"+",[&](MenuFuncData data){ + consumableCraftItemWindow->ADD("Increase Craft amount Button",MenuComponent)(geom2d::rect{{consumableCraftItemWindow->size.x/2+80+2,34},{12,12}},"+",[&](MenuFuncData data){ uint8_t qty=std::clamp(GetQuantity()+1,1,99); Component(CONSUMABLE_CRAFT_ITEM,"Amount to Craft Amount Label")->SetLabel(std::to_string(qty)); return true; })END; - consumableCraftItemWindow->ADD("Decrease Craft amount Button",MenuComponent)({{consumableCraftItemWindow->size.x/2+48-14,34},{12,12}},"-",[](MenuFuncData data){ + consumableCraftItemWindow->ADD("Decrease Craft amount Button",MenuComponent)(geom2d::rect{{consumableCraftItemWindow->size.x/2+48-14,34},{12,12}},"-",[](MenuFuncData data){ uint8_t qty=std::clamp(GetQuantity()-1,1,99); Component(CONSUMABLE_CRAFT_ITEM,"Amount to Craft Amount Label")->SetLabel(std::to_string(qty)); return true; })END; - consumableCraftItemWindow->ADD("Materials Requirement Outline",MenuComponent)({{2,86-18},{consumableCraftItemWindow->size.x-4,26}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END; - consumableCraftItemWindow->ADD("Required Materials Label",MenuLabel)({{4,80-18},{consumableCraftItemWindow->size.x-8,0}},"Required Materials",1.0f,ComponentAttr::SHADOW)END; + consumableCraftItemWindow->ADD("Materials Requirement Outline",MenuComponent)(geom2d::rect{{2,86-18},{consumableCraftItemWindow->size.x-4,26}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END; + consumableCraftItemWindow->ADD("Required Materials Label",MenuLabel)(geom2d::rect{{4,80-18},{consumableCraftItemWindow->size.x-8,0}},"Required Materials",1.0f,ComponentAttr::SHADOW)END; - consumableCraftItemWindow->ADD("Required Materials List",RequiredMaterialsList)({{4,88-18},{consumableCraftItemWindow->size.x-8,22}},Item::BLANK)END; + consumableCraftItemWindow->ADD("Required Materials List",RequiredMaterialsList)(geom2d::rect{{4,88-18},{consumableCraftItemWindow->size.x-8,22}},Item::BLANK)END; - consumableCraftItemWindow->ADD("Back Button",MenuComponent)({{36,116-18},{48,12}},"Back",[](MenuFuncData data){Menu::CloseMenu();return true;})END; - consumableCraftItemWindow->ADD("Craft Button",MenuComponent)({{consumableCraftItemWindow->size.x-84,116-18},{48,12}},"Craft",[](MenuFuncData data){ + consumableCraftItemWindow->ADD("Back Button",MenuComponent)(geom2d::rect{{36,116-18},{48,12}},"Back",[](MenuFuncData data){Menu::CloseMenu();return true;})END; + consumableCraftItemWindow->ADD("Craft Button",MenuComponent)(geom2d::rect{{consumableCraftItemWindow->size.x-84,116-18},{48,12}},"Craft",[](MenuFuncData data){ const std::weak_ptritem=Component(CONSUMABLE_CRAFT_ITEM,"Required Materials List")->GetItem(); uint8_t qty=stoi(Component(CONSUMABLE_CRAFT_ITEM,"Amount to Craft Amount Label")->GetLabel()); @@ -95,7 +95,7 @@ void Menu::InitializeConsumableCraftItemWindow(){ item.lock()->EnhanceItem(qty); } } - data.component->SetGrayedOut(!item.lock()->CanEnhanceItem(qty)); + data.component.lock()->SetGrayedOut(!item.lock()->CanEnhanceItem(qty)); return true; })END; } \ No newline at end of file diff --git a/Adventures in Lestoria/ConsumableCraftingWindow.cpp b/Adventures in Lestoria/ConsumableCraftingWindow.cpp index 5f4052fe..a224ce6a 100644 --- a/Adventures in Lestoria/ConsumableCraftingWindow.cpp +++ b/Adventures in Lestoria/ConsumableCraftingWindow.cpp @@ -53,10 +53,10 @@ void Menu::InitializeConsumableCraftingWindow(){ Menu*consumableCraftingWindow=CreateMenu(CRAFT_CONSUMABLE,CENTERED,game->GetScreenSize()-vi2d{52,52}); #pragma region Craftables Inventory Display - auto craftingItemsDisplay=consumableCraftingWindow->ADD("Crafting Inventory Display",RowInventoryScrollableWindowComponent)({{2,28},{220,consumableCraftingWindow->size.y-44}},"Item Name Label","Item Description Label", + auto craftingItemsDisplay=consumableCraftingWindow->ADD("Crafting Inventory Display",RowInventoryScrollableWindowComponent)(geom2d::rect{{2,28},{220,consumableCraftingWindow->size.y-44}},"Item Name Label","Item Description Label", [](MenuFuncData data){ - RowItemDisplay*comp=DYNAMIC_CAST(data.component); - const std::weak_ptritem=comp->GetItem(); + std::weak_ptrcomp=DYNAMIC_POINTER_CAST(data.component.lock()); + const std::weak_ptritem=comp.lock()->GetItem(); Component(CONSUMABLE_CRAFT_ITEM,"Item Name Header")->GetString(A::ITEM_NAME)=item.lock()->ActualName(); Component(CONSUMABLE_CRAFT_ITEM,"Amount to Craft Amount Label")->SetLabel("1"); Component(CONSUMABLE_CRAFT_ITEM,"Item Name Header")->SetLabel(std::format("Crafting {}",item.lock()->DisplayName())); @@ -68,13 +68,13 @@ void Menu::InitializeConsumableCraftingWindow(){ return true; }, [](MenuFuncData data){ - RowItemDisplay*rowItem=DYNAMIC_CAST(data.component); - if(rowItem->GetItem().lock()->GetEnhancementInfo().AvailableChapter()<=game->GetCurrentChapter()){ + std::weak_ptrrowItem=DYNAMIC_POINTER_CAST(data.component.lock()); + if(rowItem.lock()->GetItem().lock()->GetEnhancementInfo().AvailableChapter()<=game->GetCurrentChapter()){ Component(CRAFT_CONSUMABLE,"Item Icon")->SetHideDetails(false); }else{ Component(CRAFT_CONSUMABLE,"Item Icon")->SetHideDetails(true); } - Component(CRAFT_CONSUMABLE,"Item Icon")->SetItem(rowItem->GetItem()); + Component(CRAFT_CONSUMABLE,"Item Icon")->SetItem(rowItem.lock()->GetItem()); return true; }, [](MenuFuncData data){ @@ -82,7 +82,7 @@ void Menu::InitializeConsumableCraftingWindow(){ return true; }, InventoryCreator::RowPlayerWeapons_InventoryUpdate, - {.padding=1,.size={207,28}} + InventoryWindowOptions{.padding=1,.size={207,28}} )END; craftingItemsDisplay->SetCompactDescriptions(CRAFTING_INFO); @@ -96,7 +96,7 @@ void Menu::InitializeConsumableCraftingWindow(){ int x=int((invSize-1)%invWidth); int y=int((invSize-1)/invWidth); int itemIndex=y*invWidth+x; - auto newItem=craftingItemsDisplay->ADD("item_Craftables_"+std::to_string(itemIndex),RowItemDisplay)({totalSpacing*vf2d{float(x),float(y)},buttonSize},item,craftingItemsDisplay->inventoryButtonClickAction,craftingItemsDisplay->itemNameLabelName,craftingItemsDisplay->itemDescriptionLabelName,craftingItemsDisplay->inventoryButtonsActive?ButtonAttr::NONE:ButtonAttr::UNSELECTABLE)END; + auto newItem=craftingItemsDisplay->ADD("item_Craftables_"+std::to_string(itemIndex),RowItemDisplay)(geom2d::rect{totalSpacing*vf2d{float(x),float(y)},buttonSize},item,craftingItemsDisplay->inventoryButtonClickAction,craftingItemsDisplay->itemNameLabelName,craftingItemsDisplay->itemDescriptionLabelName,craftingItemsDisplay->inventoryButtonsActive?ButtonAttr::NONE:ButtonAttr::UNSELECTABLE)END; newItem->SetShowQuantity(false); newItem->SetCompactDescriptions(craftingItemsDisplay->compact); newItem->SetPriceLabelType(craftingItemsDisplay->priceLabel); @@ -111,26 +111,26 @@ void Menu::InitializeConsumableCraftingWindow(){ #pragma region Inventory Description float inventoryDescriptionWidth=consumableCraftingWindow->pos.x+consumableCraftingWindow->size.x-26-224; - consumableCraftingWindow->ADD("Item Description Outline",MenuLabel)({{224,28},{inventoryDescriptionWidth,consumableCraftingWindow->size.y-44}},"",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; - consumableCraftingWindow->ADD("Item Icon",MenuItemItemButton)({{226+inventoryDescriptionWidth/2-24,30},{48,48}},Item::BLANK,MenuType::ENUM_END,DO_NOTHING,"","",IconButtonAttr::NOT_SELECTABLE)END + consumableCraftingWindow->ADD("Item Description Outline",MenuLabel)(geom2d::rect{{224,28},{inventoryDescriptionWidth,consumableCraftingWindow->size.y-44}},"",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; + consumableCraftingWindow->ADD("Item Icon",MenuItemItemButton)(geom2d::rect{{226+inventoryDescriptionWidth/2-24,30},{48,48}},Item::BLANK,MenuType::ENUM_END,DO_NOTHING,"","",IconButtonAttr::NOT_SELECTABLE)END ->SetShowQuantity(false); - consumableCraftingWindow->ADD("Item Name Label",MenuLabel)({{226,84},{inventoryDescriptionWidth-6,12}},"",0.75f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; - consumableCraftingWindow->ADD("Item Description Label",MenuLabel)({{226,94},{inventoryDescriptionWidth-6,consumableCraftingWindow->size.y-44-66}},"",0.5f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; + consumableCraftingWindow->ADD("Item Name Label",MenuLabel)(geom2d::rect{{226,84},{inventoryDescriptionWidth-6,12}},"",0.75f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; + consumableCraftingWindow->ADD("Item Description Label",MenuLabel)(geom2d::rect{{226,94},{inventoryDescriptionWidth-6,consumableCraftingWindow->size.y-44-66}},"",0.5f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; #pragma endregion #pragma region Money Display vf2d moneyIconPos={224+inventoryDescriptionWidth-24,28+consumableCraftingWindow->size.y-44+6}; - auto moneyIcon=consumableCraftingWindow->ADD("Money Icon",MenuIconButton)({moneyIconPos,{24,24}},GFX["money.png"].Decal(),DO_NOTHING,IconButtonAttr::NOT_SELECTABLE|IconButtonAttr::NO_OUTLINE|IconButtonAttr::NO_BACKGROUND)END; + auto moneyIcon=consumableCraftingWindow->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; std::string moneyText=std::to_string(game->GetPlayer()->GetMoney()); vf2d moneyTextSize=game->GetTextSizeProp(moneyText)*2; - auto moneyDisplay=consumableCraftingWindow->ADD("Money Label",PlayerMoneyLabel)({moneyIconPos-vf2d{2+moneyTextSize.x,-2},moneyTextSize},2,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN|ComponentAttr::FIT_TO_LABEL)END; + auto moneyDisplay=consumableCraftingWindow->ADD("Money Label",PlayerMoneyLabel)(geom2d::rect{moneyIconPos-vf2d{2+moneyTextSize.x,-2},moneyTextSize},2,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN|ComponentAttr::FIT_TO_LABEL)END; moneyDisplay->SetRightAlignment(true); Player::AddMoneyListener(moneyDisplay); #pragma endregion - consumableCraftingWindow->ADD("Leave Button",MenuComponent)({{consumableCraftingWindow->size.x/2-48,28+consumableCraftingWindow->size.y-44+6},{96,24}},"Leave",MenuType::ENUM_END, + consumableCraftingWindow->ADD("Leave Button",MenuComponent)(geom2d::rect{{consumableCraftingWindow->size.x/2-48,28+consumableCraftingWindow->size.y-44+6},{96,24}},"Leave",MenuType::ENUM_END, [](MenuFuncData data){ Menu::CloseMenu(); return true; - },{2,2})END; + },vf2d{2.f,2.f})END; } \ No newline at end of file diff --git a/Adventures in Lestoria/CraftItemWindow.cpp b/Adventures in Lestoria/CraftItemWindow.cpp index b17d3e2d..2d5dffcc 100644 --- a/Adventures in Lestoria/CraftItemWindow.cpp +++ b/Adventures in Lestoria/CraftItemWindow.cpp @@ -43,19 +43,19 @@ All rights reserved. void Menu::InitializeCraftItemWindow(){ Menu*craftItemWindow=CreateMenu(CRAFT_ITEM,CENTERED,{240,120}); - craftItemWindow->ADD("Item Name Header",MenuLabel)({{2,-16},{craftItemWindow->size.x-4,12}},"Item Name",1.0f,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; + craftItemWindow->ADD("Item Name Header",MenuLabel)(geom2d::rect{{2,-16},{craftItemWindow->size.x-4,12}},"Item Name",1.0f,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; - craftItemWindow->ADD("Enhancement Level Header",MenuLabel)({{2,0},{craftItemWindow->size.x-4,12}},"Level X ->#00AA00 Y",1.f,ComponentAttr::SHADOW|ComponentAttr::FIXED_WIDTH_FONT)END; + craftItemWindow->ADD("Enhancement Level Header",MenuLabel)(geom2d::rect{{2,0},{craftItemWindow->size.x-4,12}},"Level X ->#00AA00 Y",1.f,ComponentAttr::SHADOW|ComponentAttr::FIXED_WIDTH_FONT)END; - craftItemWindow->ADD("Enhancement Stats Label",EnhancementStatsLabel)({{2,16},{craftItemWindow->size.x-4,72}},Item::BLANK,1.f)END; + craftItemWindow->ADD("Enhancement Stats Label",EnhancementStatsLabel)(geom2d::rect{{2,16},{craftItemWindow->size.x-4,72}},Item::BLANK,1.f)END; - craftItemWindow->ADD("Materials Requirement Outline",MenuComponent)({{2,86},{craftItemWindow->size.x-4,26}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END; - craftItemWindow->ADD("Required Materials Label",MenuLabel)({{4,80},{craftItemWindow->size.x-8,0}},"Required Materials",1.0f,ComponentAttr::SHADOW)END; + craftItemWindow->ADD("Materials Requirement Outline",MenuComponent)(geom2d::rect{{2,86},{craftItemWindow->size.x-4,26}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END; + craftItemWindow->ADD("Required Materials Label",MenuLabel)(geom2d::rect{{4,80},{craftItemWindow->size.x-8,0}},"Required Materials",1.0f,ComponentAttr::SHADOW)END; - craftItemWindow->ADD("Required Materials List",RequiredMaterialsList)({{4,88},{craftItemWindow->size.x-8,22}},Item::BLANK)END; + craftItemWindow->ADD("Required Materials List",RequiredMaterialsList)(geom2d::rect{{4,88},{craftItemWindow->size.x-8,22}},Item::BLANK)END; - craftItemWindow->ADD("Back Button",MenuComponent)({{36,116},{48,12}},"Back",[](MenuFuncData data){Menu::CloseMenu();return true;})END; - craftItemWindow->ADD("Craft Button",MenuComponent)({{craftItemWindow->size.x-84,116},{48,12}},"Craft",[](MenuFuncData data){ + craftItemWindow->ADD("Back Button",MenuComponent)(geom2d::rect{{36,116},{48,12}},"Back",[](MenuFuncData data){Menu::CloseMenu();return true;})END; + craftItemWindow->ADD("Craft Button",MenuComponent)(geom2d::rect{{craftItemWindow->size.x-84,116},{48,12}},"Craft",[](MenuFuncData data){ const std::weak_ptritem=Component(data.menu.GetType(),"Enhancement Stats Label")->GetItem(); if(item.lock()->CanEnhanceItem()){ item.lock()->EnhanceItem(); @@ -65,7 +65,7 @@ void Menu::InitializeCraftItemWindow(){ label=std::format("Level {} ->#00AA00 {}",item.lock()->EnhancementLevel(),item.lock()->EnhancementLevel()+1); } Component(data.menu.GetType(),"Enhancement Level Header")->SetLabel(label); - data.component->SetGrayedOut(!item.lock()->CanEnhanceItem()); + data.component.lock()->SetGrayedOut(!item.lock()->CanEnhanceItem()); return true; })END; } \ No newline at end of file diff --git a/Adventures in Lestoria/EncountersSpawnListScrollableWindowComponent.h b/Adventures in Lestoria/EncountersSpawnListScrollableWindowComponent.h index 23fde223..2ae83294 100644 --- a/Adventures in Lestoria/EncountersSpawnListScrollableWindowComponent.h +++ b/Adventures in Lestoria/EncountersSpawnListScrollableWindowComponent.h @@ -54,15 +54,14 @@ public: virtual inline void UpdateSpawns(std::vector&spawns){ Menu::menus.at(parentMenu)->components.erase_if([&](auto key){ if(key.first.starts_with("Spawn ")){ - std::erase_if(components,[&](MenuComponent*component){return key.second==component;}); - delete key.second; + std::erase_if(components,[&](std::weak_ptrcomponent){return &*key.second==&*component.lock();}); return true; } return false;}); int offsetY=0; vf2d parentSize=Menu::menus.at(OVERWORLD_LEVEL_SELECT)->size; for(std::string spawn:spawns){ - ADD("Spawn "+spawn,SpawnEncounterLabel)({vf2d{0,float(offsetY)},{parentSize.x,12}},MONSTER_DATA.at(spawn).GetDisplayName(),spawn)END; + ADD("Spawn "+spawn,SpawnEncounterLabel)(geom2d::rect{vf2d{0,float(offsetY)},{parentSize.x,12}},MONSTER_DATA.at(spawn).GetDisplayName(),spawn)END; offsetY+=14; } } diff --git a/Adventures in Lestoria/Error.h b/Adventures in Lestoria/Error.h index 66e8124c..f795ce65 100644 --- a/Adventures in Lestoria/Error.h +++ b/Adventures in Lestoria/Error.h @@ -40,6 +40,7 @@ All rights reserved. #include #include #include +#include #ifndef __EMSCRIPTEN__ #include #endif @@ -82,4 +83,11 @@ type DYNAMIC_CAST(auto variable){ type pointer=dynamic_cast(variable); if(pointer==nullptr)ERR("Could not dynamic cast to type "< +std::shared_ptrDYNAMIC_POINTER_CAST(auto variable){ + std::shared_ptrpointer=std::dynamic_pointer_cast(variable); + if(pointer)ERR("Could not dynamic cast to type "<I(A::LOADOUT_SLOT)=0; - auto consumableWindow=inventoryWindow->ADD("inventory",InventoryScrollableWindowComponent)({{0,15},{windowSize.x,96.f}},"itemName","itemDescription", + auto consumableWindow=inventoryWindow->ADD("inventory",InventoryScrollableWindowComponent)(geom2d::rect{{0,15},{windowSize.x,96.f}},"itemName","itemDescription", [&](MenuFuncData data){ - MenuItemButton*button=(MenuItemButton*)data.component; + std::weak_ptrbutton=DYNAMIC_POINTER_CAST(data.component.lock()); data.game->ClearLoadoutItem(data.menu.I(A::LOADOUT_SLOT)); - for(MenuComponent*component:data.parentComponent->GetComponents()){ //HACK ALERT! If we are accessing a parent component, it's because we are dealing with a scrolling window component, which has sub-components. So this should be a safe cast to make. - if(component->GetName().starts_with("item")){ - MenuItemButton*button2=DYNAMIC_CAST(component);//HACK ALERT! This is probably an item since we populated item lists using this name for the components. So we assume these are MenuItemButton classes. - if(button2==nullptr)ERR("Could not cast item to a MenuItemButton*!"); - if(button2==button){ - if(button2->selected!=-1){ - data.game->ClearLoadoutItem(button2->selected); + for(std::weak_ptrcomponent:data.parentComponent.lock()->GetComponents()){ //HACK ALERT! If we are accessing a parent component, it's because we are dealing with a scrolling window component, which has sub-components. So this should be a safe cast to make. + if(component.lock()->GetName().starts_with("item")){ + std::weak_ptrbutton2=DYNAMIC_POINTER_CAST(component.lock());//HACK ALERT! This is probably an item since we populated item lists using this name for the components. So we assume these are MenuItemButton classes. + if(button2.expired())ERR("Could not cast item to a MenuItemButton*!"); + if(&*button2.lock()==&*button.lock()){ + if(button2.lock()->selected!=-1){ + data.game->ClearLoadoutItem(button2.lock()->selected); } - button2->selected=-1; + button2.lock()->selected=-1; } - if(button2->selected==data.menu.I(A::LOADOUT_SLOT)){ - button2->selected=-1; + if(button2.lock()->selected==data.menu.I(A::LOADOUT_SLOT)){ + button2.lock()->selected=-1; } } } - button->selected=data.menu.I(A::LOADOUT_SLOT); - data.game->SetLoadoutItem(button->selected,button->GetItem().lock()->ActualName()); + button.lock()->selected=data.menu.I(A::LOADOUT_SLOT); + data.game->SetLoadoutItem(button.lock()->selected,button.lock()->GetItem().lock()->ActualName()); return true; },InventoryCreator::Player_InventoryUpdate)END; Menu::AddInventoryListener(consumableWindow,"Consumables"); //We don't have to actually populate the inventory list because now when an item gets added, it will automatically add the correct component in for us. - inventoryWindow->ADD("Inventory Type Label",MenuLabel)({{0,-5},{windowSize.x-1,18}},"Consumables",2,ComponentAttr::SHADOW|ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)END; + inventoryWindow->ADD("Inventory Type Label",MenuLabel)(geom2d::rect{{0,-5},{windowSize.x-1,18}},"Consumables",2,ComponentAttr::SHADOW|ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)END; inventoryWindow->ADD("itemName",MenuLabel)(geom2d::rect(vf2d{2,90.f},{windowSize.x-4,windowSize.y-108}),"",1,ComponentAttr::SHADOW)END; inventoryWindow->ADD("itemDescription",MenuLabel)(geom2d::rect(vf2d{2,117.f},{windowSize.x-4,windowSize.y-108}),"",1,ComponentAttr::SHADOW)END; - auto okButton=inventoryWindow->ADD("OK Button",MenuComponent)({{windowSize.x/2-24,173.f},{48,12}},"Ok",[](MenuFuncData data){Menu::CloseMenu();return true;})END; + auto okButton=inventoryWindow->ADD("OK Button",MenuComponent)(geom2d::rect{{windowSize.x/2-24,173.f},{48,12}},"Ok",[](MenuFuncData data){Menu::CloseMenu();return true;})END; } \ No newline at end of file diff --git a/Adventures in Lestoria/InventoryCreator.cpp b/Adventures in Lestoria/InventoryCreator.cpp index 8c7e27c7..dd45d6e7 100644 --- a/Adventures in Lestoria/InventoryCreator.cpp +++ b/Adventures in Lestoria/InventoryCreator.cpp @@ -72,7 +72,7 @@ std::function vf2d buttonSize=component.options.size; int totalSpacing=component.options.padding+buttonSize.x; - component.ADD("item_"+cat+"_"+std::to_string(itemIndex),MenuItemButton)({{float(totalSpacing*x),float(totalSpacing*y)},buttonSize},Inventory::get(cat),itemIndex,component.inventoryButtonClickAction,component.inventoryButtonHoverAction,component.inventoryButtonMouseOutAction,component.parentMenu,component.itemNameLabelName,component.itemDescriptionLabelName,component.inventoryButtonsActive?IconButtonAttr::SELECTABLE:IconButtonAttr::NOT_SELECTABLE)END + component.ADD("item_"+cat+"_"+std::to_string(itemIndex),MenuItemButton)(geom2d::rect{{float(totalSpacing*x),float(totalSpacing*y)},buttonSize},Inventory::get(cat),itemIndex,component.inventoryButtonClickAction,component.inventoryButtonHoverAction,component.inventoryButtonMouseOutAction,component.parentMenu,component.itemNameLabelName,component.itemDescriptionLabelName,component.inventoryButtonsActive?IconButtonAttr::SELECTABLE:IconButtonAttr::NOT_SELECTABLE)END ->SetCompactDescriptions(component.compact); }; #pragma endregion @@ -91,7 +91,7 @@ std::function vf2d buttonSize=c->options.size; vf2d totalSpacing={c->options.padding+buttonSize.x,c->options.padding+buttonSize.y}; - auto newItem=c->ADD("item_"+cat+"_"+std::to_string(itemIndex),RowItemDisplay)({totalSpacing*vf2d{float(x),float(y)},buttonSize},Inventory::GetInventorySlot(cat,itemIndex),c->inventoryButtonClickAction,c->itemNameLabelName,c->itemDescriptionLabelName,c->inventoryButtonsActive?ButtonAttr::NONE:ButtonAttr::UNSELECTABLE)END; + auto newItem=c->ADD("item_"+cat+"_"+std::to_string(itemIndex),RowItemDisplay)(geom2d::rect{totalSpacing*vf2d{float(x),float(y)},buttonSize},Inventory::GetInventorySlot(cat,itemIndex),c->inventoryButtonClickAction,c->itemNameLabelName,c->itemDescriptionLabelName,c->inventoryButtonsActive?ButtonAttr::NONE:ButtonAttr::UNSELECTABLE)END; newItem->SetCompactDescriptions(c->compact); newItem->SetPriceLabelType(c->priceLabel); newItem->SetHoverFunc(c->inventoryButtonHoverAction); @@ -128,7 +128,7 @@ std::function vf2d buttonSize=c->options.size; vf2d totalSpacing={c->options.padding+buttonSize.x,c->options.padding+buttonSize.y}; - auto newItem=c->ADD("merchant_item_"+cat+"_"+std::to_string(itemIndex),RowItemDisplay)({totalSpacing*vf2d{float(x),float(y)},buttonSize},Merchant::GetCurrentTravelingMerchant().GetShopItems()[itemIndex],c->inventoryButtonClickAction,c->itemNameLabelName,c->itemDescriptionLabelName,c->inventoryButtonsActive?ButtonAttr::NONE:ButtonAttr::UNSELECTABLE)END; + auto newItem=c->ADD("merchant_item_"+cat+"_"+std::to_string(itemIndex),RowItemDisplay)(geom2d::rect{totalSpacing*vf2d{float(x),float(y)},buttonSize},Merchant::GetCurrentTravelingMerchant().GetShopItems()[itemIndex],c->inventoryButtonClickAction,c->itemNameLabelName,c->itemDescriptionLabelName,c->inventoryButtonsActive?ButtonAttr::NONE:ButtonAttr::UNSELECTABLE)END; newItem->SetCompactDescriptions(c->compact); newItem->SetPriceLabelType(c->priceLabel); newItem->SetHoverFunc(c->inventoryButtonHoverAction); @@ -160,7 +160,7 @@ std::function int x=int((invSize-1)%invWidth); int y=int((invSize-1)/invWidth); int itemIndex=y*invWidth+x; - auto newItem=c->ADD("item_Weapon_"+std::to_string(itemIndex),RowItemDisplay)({totalSpacing*vf2d{float(x),float(y)},buttonSize},weapon,c->inventoryButtonClickAction,c->itemNameLabelName,c->itemDescriptionLabelName,c->inventoryButtonsActive?ButtonAttr::NONE:ButtonAttr::UNSELECTABLE)END; + auto newItem=c->ADD("item_Weapon_"+std::to_string(itemIndex),RowItemDisplay)(geom2d::rect{totalSpacing*vf2d{float(x),float(y)},buttonSize},weapon,c->inventoryButtonClickAction,c->itemNameLabelName,c->itemDescriptionLabelName,c->inventoryButtonsActive?ButtonAttr::NONE:ButtonAttr::UNSELECTABLE)END; newItem->SetCompactDescriptions(c->compact); newItem->SetPriceLabelType(c->priceLabel); newItem->SetHoverFunc(c->inventoryButtonHoverAction); @@ -194,7 +194,7 @@ std::function int x=int((invSize-1)%invWidth); int y=int((invSize-1)/invWidth); int itemIndex=y*invWidth+x; - auto newItem=c->ADD("item_Armor_"+std::to_string(itemIndex),RowItemDisplay)({totalSpacing*vf2d{float(x),float(y)},buttonSize},armor,c->inventoryButtonClickAction,c->itemNameLabelName,c->itemDescriptionLabelName,c->inventoryButtonsActive?ButtonAttr::NONE:ButtonAttr::UNSELECTABLE)END; + auto newItem=c->ADD("item_Armor_"+std::to_string(itemIndex),RowItemDisplay)(geom2d::rect{totalSpacing*vf2d{float(x),float(y)},buttonSize},armor,c->inventoryButtonClickAction,c->itemNameLabelName,c->itemDescriptionLabelName,c->inventoryButtonsActive?ButtonAttr::NONE:ButtonAttr::UNSELECTABLE)END; newItem->SetCompactDescriptions(c->compact); newItem->SetPriceLabelType(c->priceLabel); newItem->SetHoverFunc(c->inventoryButtonHoverAction); diff --git a/Adventures in Lestoria/InventoryScrollableWindowComponent.h b/Adventures in Lestoria/InventoryScrollableWindowComponent.h index 71777c7a..2b82d84d 100644 --- a/Adventures in Lestoria/InventoryScrollableWindowComponent.h +++ b/Adventures in Lestoria/InventoryScrollableWindowComponent.h @@ -80,8 +80,8 @@ public: virtual inline void Update(AiL*game)override{ ScrollableWindowComponent::Update(game); bool noneHovered=true; - for(MenuComponent*component:components){ - if(component->hovered){ + for(std::weak_ptrcomponent:components){ + if(component.lock()->hovered){ noneHovered=false; break; } @@ -93,9 +93,9 @@ public: } virtual inline void SetCompactDescriptions(CompactText compact){ this->compact=compact; - for(MenuComponent*component:components){ - MenuItemButton*itemButton=DYNAMIC_CAST(component); - itemButton->SetCompactDescriptions(compact); + for(std::weak_ptrcomponent:components){ + std::weak_ptritemButton=DYNAMIC_POINTER_CAST(component.lock()); + itemButton.lock()->SetCompactDescriptions(compact); } } protected: diff --git a/Adventures in Lestoria/InventoryWindow.cpp b/Adventures in Lestoria/InventoryWindow.cpp index 0e2fd053..621b26ff 100644 --- a/Adventures in Lestoria/InventoryWindow.cpp +++ b/Adventures in Lestoria/InventoryWindow.cpp @@ -58,8 +58,8 @@ using ButtonAttr::UNSELECTABLE_VIA_KEYBOARD; void Menu::InitializeInventoryWindow(){ Menu*inventoryWindow=CreateMenu(INVENTORY,CENTERED,game->GetScreenSize()-vi2d{52,52}); - inventoryWindow->ADD("Inventory Label",MenuLabel)({{0,0},{inventoryWindow->size.x-1,24}},"Inventory",2,SHADOW|OUTLINE|BACKGROUND)END; - inventoryWindow->ADD("Inventory Tabs Outline",MenuComponent)({{0,28},{72,inventoryWindow->size.y-44}},"",DO_NOTHING,UNSELECTABLE)END; + inventoryWindow->ADD("Inventory Label",MenuLabel)(geom2d::rect{{0,0},{inventoryWindow->size.x-1,24}},"Inventory",2,SHADOW|OUTLINE|BACKGROUND)END; + inventoryWindow->ADD("Inventory Tabs Outline",MenuComponent)(geom2d::rect{{0,28},{72,inventoryWindow->size.y-44}},"",DO_NOTHING,UNSELECTABLE)END; std::vector>categories; for(auto&[category,items]:ITEM_CATEGORIES){ @@ -75,22 +75,22 @@ void Menu::InitializeInventoryWindow(){ float buttonWidth=64; float textScaling=std::min(1.f,buttonWidth/textWidth); - auto button=inventoryWindow->ADD(category+" Inventory Tab",MenuComponent)({{2,30+yOffset},{68,16}},category,MenuType::ENUM_END, + auto button=inventoryWindow->ADD(category+" Inventory Tab",MenuComponent)(geom2d::rect{{2,30+yOffset},{68,16}},category,MenuType::ENUM_END, [&](MenuFuncData data){ //Close the old inventory window and show the proper one. Component(data.menu.GetType(),"Inventory Display - "+data.menu.S(A::LAST_INVENTORY_TYPE_OPENED))->Enable(false); Component(data.menu.GetType(),data.menu.S(A::LAST_INVENTORY_TYPE_OPENED)+" Inventory Tab")->SetSelected(false); - Component(data.menu.GetType(),"Inventory Display - "+data.component->S(A::CATEGORY_NAME))->Enable(true); - Component(data.menu.GetType(),data.component->S(A::CATEGORY_NAME)+" Inventory Tab")->SetSelected(true); - data.menu.S(A::LAST_INVENTORY_TYPE_OPENED)=data.component->S(A::CATEGORY_NAME); + Component(data.menu.GetType(),"Inventory Display - "+data.component.lock()->S(A::CATEGORY_NAME))->Enable(true); + Component(data.menu.GetType(),data.component.lock()->S(A::CATEGORY_NAME)+" Inventory Tab")->SetSelected(true); + data.menu.S(A::LAST_INVENTORY_TYPE_OPENED)=data.component.lock()->S(A::CATEGORY_NAME); return true; - },{textScaling,1.f})END; + },vf2d{textScaling,1.f})END; button->SetSelectionType(HIGHLIGHT); button->S(A::CATEGORY_NAME)=category; - auto inventoryDisplay=inventoryWindow->ADD("Inventory Display - "+category,RowInventoryScrollableWindowComponent)({{72,28},{150,inventoryWindow->size.y-44}},"Item Name Label","Item Description Label",DO_NOTHING, + auto inventoryDisplay=inventoryWindow->ADD("Inventory Display - "+category,RowInventoryScrollableWindowComponent)(geom2d::rect{{72,28},{150,inventoryWindow->size.y-44}},"Item Name Label","Item Description Label",DO_NOTHING, [](MenuFuncData data){ - Component(data.menu.GetType(),"Item Icon")->SetItem(DYNAMIC_CAST(data.component)->GetItem()); + Component(data.menu.GetType(),"Item Icon")->SetItem(DYNAMIC_POINTER_CAST(data.component.lock())->GetItem()); return true; }, [](MenuFuncData data){ @@ -98,7 +98,7 @@ void Menu::InitializeInventoryWindow(){ return true; }, InventoryCreator::RowPlayer_InventoryUpdate, - {.padding=1,.size={137,28}})END; + InventoryWindowOptions{.padding=1,.size={137,28}})END; if(first){ inventoryWindow->S(A::LAST_INVENTORY_TYPE_OPENED)=category; @@ -116,25 +116,25 @@ void Menu::InitializeInventoryWindow(){ #pragma region Inventory Description float inventoryDescriptionWidth=inventoryWindow->pos.x+inventoryWindow->size.x-26-224; - inventoryWindow->ADD("Item Description Outline",MenuLabel)({{224,28},{inventoryDescriptionWidth,inventoryWindow->size.y-44}},"",1,LEFT_ALIGN|OUTLINE|BACKGROUND)END; - inventoryWindow->ADD("Item Icon",MenuItemItemButton)({{226+inventoryDescriptionWidth/2-24,30},{48,48}},Item::BLANK,MenuType::ENUM_END,DO_NOTHING,"","",IconButtonAttr::NOT_SELECTABLE)END; - inventoryWindow->ADD("Item Name Label",MenuLabel)({{226,84},{inventoryDescriptionWidth-6,12}},"",0.75f,LEFT_ALIGN|SHADOW)END; - inventoryWindow->ADD("Item Description Label",MenuLabel)({{226,94},{inventoryDescriptionWidth-6,inventoryWindow->size.y-44-66}},"",0.5f,LEFT_ALIGN|SHADOW)END; + inventoryWindow->ADD("Item Description Outline",MenuLabel)(geom2d::rect{{224,28},{inventoryDescriptionWidth,inventoryWindow->size.y-44}},"",1,LEFT_ALIGN|OUTLINE|BACKGROUND)END; + inventoryWindow->ADD("Item Icon",MenuItemItemButton)(geom2d::rect{{226+inventoryDescriptionWidth/2-24,30},{48,48}},Item::BLANK,MenuType::ENUM_END,DO_NOTHING,"","",IconButtonAttr::NOT_SELECTABLE)END; + inventoryWindow->ADD("Item Name Label",MenuLabel)(geom2d::rect{{226,84},{inventoryDescriptionWidth-6,12}},"",0.75f,LEFT_ALIGN|SHADOW)END; + inventoryWindow->ADD("Item Description Label",MenuLabel)(geom2d::rect{{226,94},{inventoryDescriptionWidth-6,inventoryWindow->size.y-44-66}},"",0.5f,LEFT_ALIGN|SHADOW)END; #pragma endregion #pragma region Money Display vf2d moneyIconPos={224+inventoryDescriptionWidth-24,28+inventoryWindow->size.y-44+6}; - auto moneyIcon=inventoryWindow->ADD("Money Icon",MenuIconButton)({moneyIconPos,{24,24}},GFX["money.png"].Decal(),DO_NOTHING,IconButtonAttr::NOT_SELECTABLE|IconButtonAttr::NO_OUTLINE|IconButtonAttr::NO_BACKGROUND)END; + auto moneyIcon=inventoryWindow->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; std::string moneyText=std::to_string(game->GetPlayer()->GetMoney()); vf2d moneyTextSize=game->GetTextSizeProp(moneyText)*2; - auto moneyDisplay=inventoryWindow->ADD("Money Label",PlayerMoneyLabel)({moneyIconPos-vf2d{2+moneyTextSize.x,-2},moneyTextSize},2,SHADOW|LEFT_ALIGN|FIT_TO_LABEL)END; + auto moneyDisplay=inventoryWindow->ADD("Money Label",PlayerMoneyLabel)(geom2d::rect{moneyIconPos-vf2d{2+moneyTextSize.x,-2},moneyTextSize},2,SHADOW|LEFT_ALIGN|FIT_TO_LABEL)END; moneyDisplay->SetRightAlignment(true); Player::AddMoneyListener(moneyDisplay); #pragma endregion - inventoryWindow->ADD("Back Button",MenuComponent)({{inventoryWindow->size.x/2-48,28+inventoryWindow->size.y-44+6},{96,24}},"Back",MenuType::ENUM_END, + inventoryWindow->ADD("Back Button",MenuComponent)(geom2d::rect{{inventoryWindow->size.x/2-48,28+inventoryWindow->size.y-44+6},{96,24}},"Back",MenuType::ENUM_END, [](MenuFuncData data){ Menu::CloseMenu(); return true; - },{2,2})END; + },vf2d{2.f,2.f})END; } \ No newline at end of file diff --git a/Adventures in Lestoria/ItemLoadoutWindow.cpp b/Adventures in Lestoria/ItemLoadoutWindow.cpp index 7be5001e..682104d4 100644 --- a/Adventures in Lestoria/ItemLoadoutWindow.cpp +++ b/Adventures in Lestoria/ItemLoadoutWindow.cpp @@ -50,29 +50,29 @@ void Menu::InitializeItemLoadoutWindow(){ float itemLoadoutWindowWidth=(game->GetScreenSize().x-5.f); - itemLoadoutWindow->ADD("Loadout Label",MenuLabel)({{0,24},{itemLoadoutWindowWidth,24}},"Loadout",2,ComponentAttr::SHADOW|ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)END; + itemLoadoutWindow->ADD("Loadout Label",MenuLabel)(geom2d::rect{{0,24},{itemLoadoutWindowWidth,24}},"Loadout",2,ComponentAttr::SHADOW|ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)END; float buttonBorderPadding=64; - itemLoadoutWindow->ADD("Loadout Item 1",MenuItemItemButton)({{64,96},{48,48}},game->GetLoadoutItem(0),INVENTORY_CONSUMABLES,[](MenuFuncData data){Menu::menus.at(INVENTORY_CONSUMABLES)->I(A::LOADOUT_SLOT)=0; return true;},[](MenuFuncData data){return true;},[](MenuFuncData data){ + itemLoadoutWindow->ADD("Loadout Item 1",MenuItemItemButton)(geom2d::rect{{64,96},{48,48}},game->GetLoadoutItem(0),INVENTORY_CONSUMABLES,[](MenuFuncData data){Menu::menus.at(INVENTORY_CONSUMABLES)->I(A::LOADOUT_SLOT)=0; return true;},[](MenuFuncData data){return true;},[](MenuFuncData data){ Component(ITEM_LOADOUT,"Item Name Label")->SetLabel(""); Component(ITEM_LOADOUT,"Item Description")->SetLabel(""); return true; },"Item Name Label","Item Description")END; - itemLoadoutWindow->ADD("Loadout Item 2",MenuItemItemButton)({{itemLoadoutWindowWidth/2-24,96},{48,48}},game->GetLoadoutItem(1),INVENTORY_CONSUMABLES,[](MenuFuncData data){Menu::menus.at(INVENTORY_CONSUMABLES)->I(A::LOADOUT_SLOT)=1;return true;},[](MenuFuncData data){return true;},[](MenuFuncData data){ + itemLoadoutWindow->ADD("Loadout Item 2",MenuItemItemButton)(geom2d::rect{{itemLoadoutWindowWidth/2-24,96},{48,48}},game->GetLoadoutItem(1),INVENTORY_CONSUMABLES,[](MenuFuncData data){Menu::menus.at(INVENTORY_CONSUMABLES)->I(A::LOADOUT_SLOT)=1;return true;},[](MenuFuncData data){return true;},[](MenuFuncData data){ Component(ITEM_LOADOUT,"Item Name Label")->SetLabel(""); Component(ITEM_LOADOUT,"Item Description")->SetLabel(""); return true; },"Item Name Label","Item Description")END; - itemLoadoutWindow->ADD("Loadout Item 3",MenuItemItemButton)({{itemLoadoutWindowWidth-48-64,96},{48,48}},game->GetLoadoutItem(2),INVENTORY_CONSUMABLES,[](MenuFuncData data){Menu::menus.at(INVENTORY_CONSUMABLES)->I(A::LOADOUT_SLOT)=2;return true;},[](MenuFuncData data){return true;},[](MenuFuncData data){ + itemLoadoutWindow->ADD("Loadout Item 3",MenuItemItemButton)(geom2d::rect{{itemLoadoutWindowWidth-48-64,96},{48,48}},game->GetLoadoutItem(2),INVENTORY_CONSUMABLES,[](MenuFuncData data){Menu::menus.at(INVENTORY_CONSUMABLES)->I(A::LOADOUT_SLOT)=2;return true;},[](MenuFuncData data){return true;},[](MenuFuncData data){ Component(ITEM_LOADOUT,"Item Name Label")->SetLabel(""); Component(ITEM_LOADOUT,"Item Description")->SetLabel(""); return true; },"Item Name Label","Item Description")END; - itemLoadoutWindow->ADD("Item Name Label",MenuLabel)({{0,158},{itemLoadoutWindowWidth,12}},"",1,ComponentAttr::SHADOW)END; - itemLoadoutWindow->ADD("Item Description",MenuLabel)({{0,170},{itemLoadoutWindowWidth,24}},"",1,ComponentAttr::SHADOW)END; + itemLoadoutWindow->ADD("Item Name Label",MenuLabel)(geom2d::rect{{0,158},{itemLoadoutWindowWidth,12}},"",1,ComponentAttr::SHADOW)END; + itemLoadoutWindow->ADD("Item Description",MenuLabel)(geom2d::rect{{0,170},{itemLoadoutWindowWidth,24}},"",1,ComponentAttr::SHADOW)END; - itemLoadoutWindow->ADD("Start Level Button",MenuComponent)({{itemLoadoutWindowWidth/2-32,214},{64,16}},"Start",[](MenuFuncData data){State_OverworldMap::StartLevel();return true;})END; + itemLoadoutWindow->ADD("Start Level Button",MenuComponent)(geom2d::rect{{itemLoadoutWindowWidth/2-32,214},{64,16}},"Start",[](MenuFuncData data){State_OverworldMap::StartLevel();return true;})END; } \ No newline at end of file diff --git a/Adventures in Lestoria/LevelCompleteWindow.cpp b/Adventures in Lestoria/LevelCompleteWindow.cpp index 16bf286a..8858645d 100644 --- a/Adventures in Lestoria/LevelCompleteWindow.cpp +++ b/Adventures in Lestoria/LevelCompleteWindow.cpp @@ -51,16 +51,16 @@ void Menu::InitializeLevelCompleteWindow(){ Menu*levelCompleteWindow=Menu::CreateMenu(LEVEL_COMPLETE,windowSize.pos,windowSize.size); - levelCompleteWindow->ADD("Stage Complete Label",MenuLabel)({{0,4},{windowSize.size.x-1.f,20}},"Stage Completed",2,ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND|ComponentAttr::SHADOW)END; + levelCompleteWindow->ADD("Stage Complete Label",MenuLabel)(geom2d::rect{{0,4},{windowSize.size.x-1.f,20}},"Stage Completed",2,ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND|ComponentAttr::SHADOW)END; - levelCompleteWindow->ADD("Monster Loot Outline",MenuComponent)({{0,32},{windowSize.size.x-80.f,72}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END; - levelCompleteWindow->ADD("Monster Loot Label",MenuLabel)({{0,32},{windowSize.size.x-80.f,12}},"Monster Loot",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE)END; - auto monsterLootWindow=levelCompleteWindow->ADD("Monster Loot Window",InventoryScrollableWindowComponent)({{0,44},{windowSize.size.x-80.f,60}},"Monster Loot Popup Item Name","Monster Loot Popup Item Description",DO_NOTHING,InventoryCreator::Player_InventoryUpdate)END; + levelCompleteWindow->ADD("Monster Loot Outline",MenuComponent)(geom2d::rect{{0,32},{windowSize.size.x-80.f,72}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END; + levelCompleteWindow->ADD("Monster Loot Label",MenuLabel)(geom2d::rect{{0,32},{windowSize.size.x-80.f,12}},"Monster Loot",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE)END; + auto monsterLootWindow=levelCompleteWindow->ADD("Monster Loot Window",InventoryScrollableWindowComponent)(geom2d::rect{{0,44},{windowSize.size.x-80.f,60}},"Monster Loot Popup Item Name","Monster Loot Popup Item Description",DO_NOTHING,InventoryCreator::Player_InventoryUpdate)END; Menu::AddInventoryListener(monsterLootWindow,"Monster Loot"); - levelCompleteWindow->ADD("Stage Loot Outline",MenuComponent)({{0,108},{windowSize.size.x-80.f,72}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END; - levelCompleteWindow->ADD("Stage Loot Label",MenuLabel)({{0,108},{windowSize.size.x-80.f,12}},"Stage Loot",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE)END; - auto stageLootWindow=levelCompleteWindow->ADD("Stage Loot Window",InventoryScrollableWindowComponent)({{0,120},{windowSize.size.x-80.f,60}},"Stage Loot Popup Item Name","Stage Loot Popup Item Description",DO_NOTHING,InventoryCreator::Player_InventoryUpdate)END; + levelCompleteWindow->ADD("Stage Loot Outline",MenuComponent)(geom2d::rect{{0,108},{windowSize.size.x-80.f,72}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END; + levelCompleteWindow->ADD("Stage Loot Label",MenuLabel)(geom2d::rect{{0,108},{windowSize.size.x-80.f,12}},"Stage Loot",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE)END; + auto stageLootWindow=levelCompleteWindow->ADD("Stage Loot Window",InventoryScrollableWindowComponent)(geom2d::rect{{0,120},{windowSize.size.x-80.f,60}},"Stage Loot Popup Item Name","Stage Loot Popup Item Description",DO_NOTHING,InventoryCreator::Player_InventoryUpdate)END; Menu::AddInventoryListener(stageLootWindow,"Stage Loot"); auto nextButtonAction=[](MenuFuncData data){ @@ -69,13 +69,13 @@ void Menu::InitializeLevelCompleteWindow(){ return true; }; - levelCompleteWindow->ADD("Level Details Outline",MenuComponent)({{windowSize.size.x-72.f,32},{71,72}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END; - levelCompleteWindow->ADD("Level EXP Gain Outline",MenuLabel)({{windowSize.size.x-72.f,104},{71,36}},"+ Exp",1,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; - levelCompleteWindow->ADD("Next Button",MenuComponent)({{windowSize.size.x-72.f,144},{71,32}},"Next",nextButtonAction)END; + levelCompleteWindow->ADD("Level Details Outline",MenuComponent)(geom2d::rect{{windowSize.size.x-72.f,32},{71,72}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END; + levelCompleteWindow->ADD("Level EXP Gain Outline",MenuLabel)(geom2d::rect{{windowSize.size.x-72.f,104},{71,36}},"+ Exp",1,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; + levelCompleteWindow->ADD("Next Button",MenuComponent)(geom2d::rect{{windowSize.size.x-72.f,144},{71,32}},"Next",nextButtonAction)END; - levelCompleteWindow->ADD("Monster Loot Popup Item Name",PopupMenuLabel)({{0,108},{windowSize.size.x-80.f,12}},"",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; - levelCompleteWindow->ADD("Monster Loot Popup Item Description",PopupMenuLabel)({{0,120},{windowSize.size.x-80.f,60}},"",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; + levelCompleteWindow->ADD("Monster Loot Popup Item Name",PopupMenuLabel)(geom2d::rect{{0,108},{windowSize.size.x-80.f,12}},"",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; + levelCompleteWindow->ADD("Monster Loot Popup Item Description",PopupMenuLabel)(geom2d::rect{{0,120},{windowSize.size.x-80.f,60}},"",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; - levelCompleteWindow->ADD("Stage Loot Popup Item Name",PopupMenuLabel)({{0,32},{windowSize.size.x-80.f,12}},"",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; - levelCompleteWindow->ADD("Stage Loot Popup Item Description",PopupMenuLabel)({{0,44},{windowSize.size.x-80.f,60}},"",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; + levelCompleteWindow->ADD("Stage Loot Popup Item Name",PopupMenuLabel)(geom2d::rect{{0,32},{windowSize.size.x-80.f,12}},"",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; + levelCompleteWindow->ADD("Stage Loot Popup Item Description",PopupMenuLabel)(geom2d::rect{{0,44},{windowSize.size.x-80.f,60}},"",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; } \ No newline at end of file diff --git a/Adventures in Lestoria/LoadGameWindow.cpp b/Adventures in Lestoria/LoadGameWindow.cpp index 200ba9a2..faeaf73f 100644 --- a/Adventures in Lestoria/LoadGameWindow.cpp +++ b/Adventures in Lestoria/LoadGameWindow.cpp @@ -42,7 +42,7 @@ All rights reserved. void Menu::InitializeLoadGameWindow(){ Menu*loadGameWindow=CreateMenu(LOAD_GAME,CENTERED,vi2d{96,120}); - loadGameWindow->ADD("Game Files Label",MenuLabel)({{-8,-12},{112,12}},"Load Game",1.0f,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; - loadGameWindow->ADD("Game Files List",ScrollableWindowComponent)({{-8,4},{112,116}})END; - loadGameWindow->ADD("Go Back Button",MenuComponent)({{24,124},{48,12}},"Back",[](MenuFuncData menu){Menu::CloseMenu();return true;})END; + loadGameWindow->ADD("Game Files Label",MenuLabel)(geom2d::rect{{-8,-12},{112,12}},"Load Game",1.0f,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; + loadGameWindow->ADD("Game Files List",ScrollableWindowComponent)(geom2d::rect{{-8,4},{112,116}})END; + loadGameWindow->ADD("Go Back Button",MenuComponent)(geom2d::rect{{24,124},{48,12}},"Back",[](MenuFuncData menu){Menu::CloseMenu();return true;})END; } \ No newline at end of file diff --git a/Adventures in Lestoria/MainMenuWindow.cpp b/Adventures in Lestoria/MainMenuWindow.cpp index 89578e58..e06b9f34 100644 --- a/Adventures in Lestoria/MainMenuWindow.cpp +++ b/Adventures in Lestoria/MainMenuWindow.cpp @@ -47,7 +47,7 @@ using A=Attribute; void Menu::InitializeMainMenuWindow(){ Menu*mainMenuWindow=CreateMenu(MAIN_MENU,vi2d{132,120},vi2d{96,96}); - mainMenuWindow->ADD("New Game Button",MenuComponent)({{12,4},{72,24}},"New Game",[&](MenuFuncData data){ + mainMenuWindow->ADD("New Game Button",MenuComponent)(geom2d::rect{{12,4},{72,24}},"New Game",[&](MenuFuncData data){ game->TextEntryEnable(true); #ifdef __EMSCRIPTEN__ data.menu.S(A::NEXT_MENU)="New Game"; @@ -61,7 +61,7 @@ void Menu::InitializeMainMenuWindow(){ #endif return true; })END; - mainMenuWindow->ADD("Load Game Button",MenuComponent)({{12,36},{72,24}},"Load Game",[](MenuFuncData data){ + mainMenuWindow->ADD("Load Game Button",MenuComponent)(geom2d::rect{{12,36},{72,24}},"Load Game",[](MenuFuncData data){ #ifdef __EMSCRIPTEN__ data.menu.S(A::NEXT_MENU)="Load Game"; if(SaveFile::GetUserID().length()==0){ @@ -77,7 +77,7 @@ void Menu::InitializeMainMenuWindow(){ #endif return true; })END; - mainMenuWindow->ADD("Quit Game Button",MenuComponent)({{12,68},{72,24}},"Quit Game",[](MenuFuncData data){ + mainMenuWindow->ADD("Quit Game Button",MenuComponent)(geom2d::rect{{12,68},{72,24}},"Quit Game",[](MenuFuncData data){ game->EndGame(); return true; })END; diff --git a/Adventures in Lestoria/Menu.cpp b/Adventures in Lestoria/Menu.cpp index 1daa3da9..bfc14d02 100644 --- a/Adventures in Lestoria/Menu.cpp +++ b/Adventures in Lestoria/Menu.cpp @@ -53,12 +53,11 @@ std::vectorMenu::stack; std::mapMenu::menus; std::string Menu::themeSelection="BlueDefault"; safeunorderedmapMenu::themes; -safemap>Menu::inventoryListeners; -safemap>Menu::merchantInventoryListeners; -std::vectorMenu::equipStatListeners; -std::vectorMenu::chapterListeners; +safemap>>Menu::inventoryListeners; +safemap>>Menu::merchantInventoryListeners; +std::vector>Menu::equipStatListeners; +std::vector>Menu::chapterListeners; const vf2d Menu::CENTERED = {-456,-456}; -std::vectorMenu::unhandledComponents; ////////////////////////////////////////////////////////////////////////////////////////////////// ///__///////////////////////////////////////////////////////////////////////////////////////////// //| |//////////////////////////////////////////////////////////////////////////////////////////// @@ -85,12 +84,6 @@ Menu::Menu(vf2d pos,vf2d size) this->window=ViewPort::rectViewPort({-24,-24},this->size+vi2d{48,48},this->pos); } -Menu::~Menu(){ - for(auto&[key,value]:components){ - delete value; - } -} - void Menu::InitializeMenus(){ #define MAX_MENUS 32 stack.reserve(MAX_MENUS); @@ -119,28 +112,11 @@ void Menu::InitializeMenus(){ if(menus.count(type)==0){ ERR("WARNING! Menu Type "<buttons.SetInitialized(); - menus[type]->keyboardButtons.SetInitialized(); for(auto&[key,value]:menus[type]->components){ - MenuComponent*component=value; - component->AfterCreate(); + value->AfterCreate(); } if(menus.size()>MAX_MENUS)ERR("WARNING! Exceeded maximum expected menu count of "<0){ - std::cout<<"WARNING! There are "<parentMenu<<" Label: "<label<memoryLeakInfo.first<<" // Last Component: "<memoryLeakInfo.second<IsFocused()||selection==vi2d{-1,-1}||buttons[selection.y][selection.x]->disabled)return; - if(buttons[selection.y][selection.x]->draggable){ + if(!game->IsFocused()||selection.expired()||selection.lock()->disabled)return; + + if(selection.lock()->draggable){ if(buttonHoldTime<"ThemeGlobal.MenuHoldTime"_F){ CheckClickAndPerformMenuSelect(game); }else{ - draggingComponent=buttons[selection.y][selection.x]->PickUpDraggableItem(); + draggingComponent=std::move(selection.lock()->PickUpDraggableItem()); buttonHoldTime=0; } }else{ @@ -171,12 +148,12 @@ void Menu::HoverMenuSelect(AiL*game){ } void Menu::MenuSelect(AiL*game){ - if(!game->IsFocused()||selection==vi2d{-1,-1}||(buttons[selection.y][selection.x]->disabled||buttons[selection.y][selection.x]->grayedOut))return; - bool buttonStillValid=buttons[selection.y][selection.x]->onClick(MenuFuncData{*this,game,buttons[selection.y][selection.x],(ScrollableWindowComponent*)buttons[selection.y][selection.x]->parentComponent}); + if(!game->IsFocused()||selection.expired()||(selection.lock()->disabled||selection.lock()->grayedOut))return; + bool buttonStillValid=selection.lock()->onClick(MenuFuncData{*this,game,selection,DYNAMIC_POINTER_CAST(selection.lock()->parentComponent.lock())}); if(buttonStillValid){ - if(buttons[selection.y][selection.x]->menuDest!=MenuType::ENUM_END){ + if(selection.lock()->menuDest!=MenuType::ENUM_END){ if(stack.size()<32){ - stack.push_back(menus[buttons[selection.y][selection.x]->menuDest]);//Navigate to the next menu. + stack.push_back(menus[selection.lock()->menuDest]);//Navigate to the next menu. }else{ ERR("WARNING! Exceeded menu stack size limit!") } @@ -185,10 +162,7 @@ void Menu::MenuSelect(AiL*game){ } void Menu::Update(AiL*game){ - if(buttons.count(selection.y)==0)selection={-1,-1}; - if(selection.x<0||selection.x>=buttons[selection.y].size()){selection={-1,-1};} - - if(draggingComponent==nullptr){ + if(draggingComponent){ HoverMenuSelect(game); } @@ -196,11 +170,9 @@ void Menu::Update(AiL*game){ SetMouseNavigation(true); } - for(auto&[key,value]:buttons){ - for(auto&button:value){ - if(!button->disabled){ - button->hovered=false; - } + for(auto&[key,button]:components){ + if(!button->disabled){ + button->hovered=false; } } @@ -208,64 +180,54 @@ void Menu::Update(AiL*game){ if(!UsingMouseNavigation()){ if(!game->IsTextEntryEnabled()){ - if(selection!=vi2d{-1,-1}){ - buttons[selection.y][selection.x]->hovered=true; + if(!selection.expired()){ + selection.lock()->hovered=true; itemHovered=true; } } }else{ - selection={-1,-1}; - for(auto&[key,value]:buttons){ - int index=0; - for(auto&button:value){ - if(!button->disabled&&!button->grayedOut){ - if(button->GetHoverState(game)){ - button->hovered=true; + selection={}; + for(auto&[key,component]:components){ + if(component->selectable){ + if(!component->disabled&&!component->grayedOut){ + if(component->GetHoverState(game)){ + component->hovered=true; itemHovered=true; - selection.y=key; - selection.x=index; + selection=component; } } - index++; } } } - if(itemHovered&&draggingComponent==nullptr&&selection!=vi2d{-1,-1}&&!UsingMouseNavigation()&&(game->KEY_CONFIRM.Held())){ + if(itemHovered&&draggingComponent&&!selection.expired()&&!UsingMouseNavigation()&&(game->KEY_CONFIRM.Held())){ buttonHoldTime+=game->GetElapsedTime(); }else{ buttonHoldTime=0; } - if(draggingComponent!=nullptr){ - MenuComponent*selectedComponent=nullptr; - if(selection!=vi2d{-1,-1}){ - selectedComponent=buttons[selection.y][selection.x]; - } - - + if(draggingComponent){ auto ClearDraggingComponent=[&](){ - delete draggingComponent; //We know we allocated a new instance of this, so we will now free it. - draggingComponent=nullptr; + draggingComponent={}; }; if(!UsingMouseNavigation()){ if(!game->IsTextEntryEnabled()){ if(game->KEY_CONFIRM.Released()){ - if(selectedComponent==nullptr){//Dropping over an empty area. + if(selection.expired()){//Dropping over an empty area. ClearDraggingComponent(); }else - if(selectedComponent->DropDraggableItem(draggingComponent)){ + if(selection.lock()->DropDraggableItem(std::move(draggingComponent))){ ClearDraggingComponent(); } } } }else{ if(game->KEY_CONFIRM.Released()){ - if(selectedComponent==nullptr){//Dropping over an empty area. + if(selection.expired()){//Dropping over an empty area. ClearDraggingComponent(); }else - if(selectedComponent->DropDraggableItem(draggingComponent)){ + if(selection.lock()->DropDraggableItem(std::move(draggingComponent))){ ClearDraggingComponent(); } } @@ -276,29 +238,11 @@ void Menu::Update(AiL*game){ KeyboardButtonNavigation(game,pos); } - for(auto&[key,value]:buttons){ - for(auto&button:value){ - if(button->renderInMain){ - button->_BeforeUpdate(game); - } - } - } - for(auto&component:displayComponents){ - if(component->renderInMain){ - component->_BeforeUpdate(game); - } + for(auto&[key,component]:components){ + component->_BeforeUpdate(game); } - for(auto&[key,value]:buttons){ - for(auto&button:value){ - if(button->renderInMain){ - button->_Update(game); - } - } - } - for(auto&component:displayComponents){ - if(component->renderInMain){ - component->_Update(game); - } + for(auto&[key,component]:components){ + component->_Update(game); } }; @@ -309,9 +253,8 @@ void Menu::Draw(AiL*game){ DrawTiledWindowBackground(game,pos,size,GetRenderColor()); } - std::vectorallComponents; - std::copy(displayComponents.begin(),displayComponents.end(),std::back_inserter(allComponents)); - std::for_each(buttons.begin(),buttons.end(),[&](auto&pair){std::copy(pair.second.begin(),pair.second.end(),std::back_inserter(allComponents));}); + std::vector>allComponents; + std::for_each(components.begin(),components.end(),[&](auto&pair){allComponents.push_back(pair.second);}); std::sort(allComponents.begin(),allComponents.end(),[](MenuComponent*c1,MenuComponent*c2){return c1->depth>c2->depth;}); if(GetCurrentTheme().IsScaled()){ @@ -321,23 +264,22 @@ void Menu::Draw(AiL*game){ } for(const auto&component:allComponents){ - if(component->renderInMain){ - component->_DrawDecal(window,this==Menu::stack.back()); + if(!component.expired()&&component.lock()->renderInMain){ + component.lock()->_DrawDecal(window,this==Menu::stack.back()); } } - if(draggingComponent!=nullptr){ + if(draggingComponent){ vf2d offsetPos=draggingComponent->rect.pos; if(!UsingMouseNavigation()){ - MenuComponent*selectedComponent=buttons[selection.y][selection.x]; vf2d drawOffset{}; - if(selectedComponent->parentComponent!=nullptr){ - ScrollableWindowComponent*scrollableComponent=DYNAMIC_CAST(selectedComponent->parentComponent); - if(scrollableComponent!=nullptr){ - drawOffset+=scrollableComponent->GetScrollAmount(); + if(!selection.expired()){ + if(!selection.lock()->parentComponent.expired()){ + std::weak_ptrscrollableComponent=DYNAMIC_POINTER_CAST(selection.lock()->parentComponent.lock()); + drawOffset+=scrollableComponent.lock()->GetScrollAmount(); } + draggingComponent->V(A::DRAW_OFFSET)=drawOffset+pos-offsetPos+selection.lock()->rect.pos+vi2d{1,-4}; } - draggingComponent->V(A::DRAW_OFFSET)=drawOffset+pos-offsetPos+selectedComponent->rect.pos+vi2d{1,-4}; draggingComponent->DrawDecal(window,this==Menu::stack.back()); }else{ draggingComponent->V(A::DRAW_OFFSET)-offsetPos+game->GetMousePos(); @@ -352,132 +294,19 @@ void Menu::OpenMenu(MenuType menu,bool cover){ } void Menu::KeyboardButtonNavigation(AiL*game,vf2d menuPos){ - vi2d prevSelection=selection; - if(game->RightPressed()){ - if(selection==vi2d{-1,-1})return; - SetMouseNavigation(false); - selection.x=(size_t(selection.x)+1)%keyboardButtons[selection.y].size(); - } - if(game->LeftPressed()){ - if(selection==vi2d{-1,-1})return; - selection.x--; - SetMouseNavigation(false); - if(selection.x<0)selection.x+=int32_t(keyboardButtons[selection.y].size()); - } - if(game->DownPressed()||game->UpPressed()){ - if(game->DownPressed()){ - SetMouseNavigation(false); - bool found=false; - bool selectedItem=false; - if(selection==vi2d{-1,-1}){ - //Highlight first item. - for(auto&[key,value]:keyboardButtons){ - selection.y=key; - break; - } - }else{ - for(auto&[key,value]:keyboardButtons){ - if(found){ //Once we discover the previous element, the next element becomes our next selection. - int previousButtonX=int(keyboardButtons[selection.y][selection.x]->rect.pos.x); - selection.y=key; - int index=0; - for(auto&button:value){ //Try to match a button in the same column as this button first. - if(previousButtonX==button->rect.pos.x){ - selection.x=index; - break; - } - index++; - } - selectedItem=true; - break; - } - if(key==selection.y - //It's entirely possible this button was selected from the button selection list and may be out-of-bounds here. - &&selection.x>=0&&selection.xUpPressed()){ - SetMouseNavigation(false); - if(selection==vi2d{-1,-1}){ - //Highlight last item. - for(auto&[key,value]:keyboardButtons){ - selection.y=key; - } - }else{ - int prevInd=-1; - for(auto&[key,value]:keyboardButtons){ - if(key==selection.y&& - //It's entirely possible this button was selected from the button selection list and may be out-of-bounds here. - selection.x>=0&&selection.xrect.pos.x); - selection.y=prevInd; - int index=0; - for(auto&button:keyboardButtons[prevInd]){ //Try to match a button in the same column as this button first. - if(previousButtonX==button->rect.pos.x){ - selection.x=index; - break; - } - index++; - } - }else{ //Since we didn't find it, it means we're at the top of the list or the list is empty. Go to the last element and use that one. - int lastInd=-1; - for(auto&[key,value]:keyboardButtons){ - lastInd=key; - } - selection.y=lastInd; - } - } - } - //In both cases, we should clamp the X index to make sure it's still valid. - if(selection.y!=-1){ - selection.x=std::clamp(selection.x,0,int(keyboardButtons[selection.y].size())-1); - }else{ - selection.x=-1; - } - } + std::weak_ptrprevSelection=selection; + if(game->KEY_CONFIRM.Pressed()){ SetMouseNavigation(game->GetMouse(0).bPressed); //If a click occurs we use mouse controls. - if(!UsingMouseNavigation()){ - buttonHoldTime=0; - //Key presses automatically highlight the first button if it's not highlighted. - if(selection==vi2d{-1,-1}&&buttons.size()>0){ - //Find the first possible button entry in the map... - int firstInd=-1; - for(auto&[key,value]:buttons){ - if(buttons[key].size()>0){ - firstInd=key; - break; - } - } - if(firstInd!=-1){ //This means we found a valid menu item. If we didn't find one don't highlight any menu item... - selection={0,firstInd}; - } - } - }else{ - buttonHoldTime=0; - } + buttonHoldTime=0; } - if(prevSelection!=selection){ - if(selection!=vi2d{-1,-1}&&(buttons[selection.y][selection.x]->disabled||buttons[selection.y][selection.x]->grayedOut)){ + if(&*prevSelection.lock()!=&*selection.lock()){ + if(!selection.expired()&&(selection.lock()->disabled||selection.lock()->grayedOut)){ bool handled=false; if(!UsingMouseNavigation()){ //Let's transfer some information about our selection being off the screen. Our intention with keyboard controls is that the screen will scroll to the correct location instead. //If we return false, then we handled it ourselves, no need to go back to the previous selection. - if(HandleOutsideDisabledButtonSelection(buttons[selection.y][selection.x])){ + if(HandleOutsideDisabledButtonSelection(selection)){ handled=true; } } @@ -572,9 +401,9 @@ Pixel Menu::GetRenderColor(){ return col; } -bool Menu::HandleOutsideDisabledButtonSelection(MenuComponent*disabledButton){ - if(disabledButton->parentComponent!=nullptr){ - return disabledButton->parentComponent->HandleOutsideDisabledButtonSelection(disabledButton); +bool Menu::HandleOutsideDisabledButtonSelection(std::weak_ptrdisabledButton){ + if(!disabledButton.expired()){ + return disabledButton.lock()->parentComponent.lock()->HandleOutsideDisabledButtonSelection(disabledButton); }else{ return false; } @@ -595,25 +424,25 @@ void Menu::SetMouseNavigation(bool mouseNavigation){ void Menu::InventorySlotsUpdated(ITCategory cat){ //Update the inventory with a new inventory slot, since there's one additional item to interact with now. - for(MenuComponent*component:inventoryListeners.at(cat)){ - InventoryScrollableWindowComponent*comp=DYNAMIC_CAST(component); //HACK ALERT! We're assuming that these must be these classes otherwise they have no reason to even be using these listeners. Make sure that the lowest base class that requires these implements these functions!!! - comp->OnInventorySlotsUpdate(cat); + for(std::weak_ptrcomponent:inventoryListeners.at(cat)){ + std::weak_ptrcomp=DYNAMIC_POINTER_CAST(component.lock()); //HACK ALERT! We're assuming that these must be these classes otherwise they have no reason to even be using these listeners. Make sure that the lowest base class that requires these implements these functions!!! + comp.lock()->OnInventorySlotsUpdate(cat); } } void Menu::MerchantInventorySlotsUpdated(ITCategory cat){ //Update the inventory with a new inventory slot, since there's one additional item to interact with now. - for(MenuComponent*component:merchantInventoryListeners.at(cat)){ - InventoryScrollableWindowComponent*comp=DYNAMIC_CAST(component); //HACK ALERT! We're assuming that these must be these classes otherwise they have no reason to even be using these listeners. Make sure that the lowest base class that requires these implements these functions!!! - comp->OnInventorySlotsUpdate(cat); + for(std::weak_ptrcomponent:merchantInventoryListeners.at(cat)){ + std::weak_ptrcomp=DYNAMIC_POINTER_CAST(component.lock()); //HACK ALERT! We're assuming that these must be these classes otherwise they have no reason to even be using these listeners. Make sure that the lowest base class that requires these implements these functions!!! + comp.lock()->OnInventorySlotsUpdate(cat); } } -void Menu::AddInventoryListener(MenuComponent*component,ITCategory category){ +void Menu::AddInventoryListener(std::weak_ptrcomponent,ITCategory category){ if(inventoryListeners.count(category)){ - std::vector&listenerList=inventoryListeners.at(category); - if(std::find(listenerList.begin(),listenerList.end(),component)!=listenerList.end()){ - ERR("WARNING! Component "<name<<" has already been added to the "<>&listenerList=inventoryListeners.at(category); + if(std::find(listenerList.begin(),listenerList.end(),[&](auto&ptr){return &*ptr.lock()==&*component.lock();})!=listenerList.end()){ + ERR("WARNING! Component "<name<<" has already been added to the "<component,ITCategory category){ if(merchantInventoryListeners.count(category)){ - std::vector&listenerList=merchantInventoryListeners.at(category); - if(std::find(listenerList.begin(),listenerList.end(),component)!=listenerList.end()){ - ERR("WARNING! Component "<name<<" has already been added to the "<>&listenerList=merchantInventoryListeners.at(category); + if(std::find(listenerList.begin(),listenerList.end(),[&](auto&ptr){return &*ptr.lock()==&*component.lock();})!=listenerList.end()){ + ERR("WARNING! Component "<name<<" has already been added to the "<name<<" has already been added to the Equip Stat listener list! There should not be any duplicates!!") +void Menu::AddEquipStatListener(std::weak_ptrcomponent){ + if(std::find(equipStatListeners.begin(),equipStatListeners.end(),[&](auto&ptr){return &*ptr.lock()==&*component.lock();})!=equipStatListeners.end()){ + ERR("WARNING! Component "<name<<" has already been added to the Equip Stat listener list! There should not be any duplicates!!") } equipStatListeners.push_back(component); } @@ -676,10 +505,8 @@ bool Menu::IsMenuOpen(){ void Menu::CleanupAllMenus(){ for(auto&[key,value]:Menu::menus){ Menu*menu=value; - for(auto&componentKey:menu->components){ - MenuComponent*component=componentKey.second; + for(auto&[name,component]:menu->components){ component->Cleanup(); - delete component; } menu->components.Reset(); menu->Cleanup(); @@ -702,7 +529,7 @@ void Menu::DrawThemedWindow(vf2d menuPos,vf2d size,Pixel renderColor){ void Menu::RecalculateComponentCount(){ - componentCount=displayComponents.size()+buttons.size(); + componentCount=components.size(); } const MenuType Menu::GetType()const{ @@ -714,13 +541,13 @@ void Menu::LockInListeners(){ merchantInventoryListeners.SetInitialized(); } -void Menu::AddChapterListener(MenuComponent*component){ - if(std::find(chapterListeners.begin(),chapterListeners.end(),component)!=chapterListeners.end()){ - ERR("WARNING! Component "<name<<" has already been added to the Chapter listener list! There should not be any duplicates!!") +void Menu::AddChapterListener(std::weak_ptrcomponent){ + if(std::find(chapterListeners.begin(),chapterListeners.end(),[&](auto&ptr){return &*ptr.lock()==&*component.lock();})!=chapterListeners.end()){ + ERR("WARNING! Component "<name<<" has already been added to the Chapter listener list! There should not be any duplicates!!") } chapterListeners.push_back(component); } -MenuFuncData::MenuFuncData(Menu&menu,AiL*const game,MenuComponent*const component,ScrollableWindowComponent*const parentComponent) +MenuFuncData::MenuFuncData(Menu&menu,AiL*const game,std::weak_ptrcomponent,std::weak_ptrparentComponent) :menu(menu),game(game),component(component),parentComponent(parentComponent){} \ No newline at end of file diff --git a/Adventures in Lestoria/Menu.h b/Adventures in Lestoria/Menu.h index b5fca742..90282157 100644 --- a/Adventures in Lestoria/Menu.h +++ b/Adventures in Lestoria/Menu.h @@ -49,7 +49,7 @@ class MenuComponent; class ScrollableWindowComponent; //Add a component to a menu using this macro. Follow-up with END at the end of it. -#define ADD(key,componentType) _AddComponent(key,NEW componentType +#define ADD(key,componentType) _AddComponent(key,std::make_shared #define END ) #define DEPTH , @@ -112,62 +112,28 @@ class Menu:public IAttributable{ friend class EntityStats; float buttonHoldTime=0; - vi2d selection={-1,-1}; + std::weak_ptrselection; vi2d lastActiveMousePos={}; int componentCount=0; - MenuComponent*draggingComponent=nullptr; + std::unique_ptrdraggingComponent; ViewPort window; - static safemap>inventoryListeners; //All menu components that care about inventory updates subscribe to this list indirectly (See Menu::AddInventoryListener()). - static safemap>merchantInventoryListeners; //All menu components that care about merchant inventory updates subscribe to this list indirectly (See Menu::AddMerchantInventoryListener()). - static std::vectorequipStatListeners; //All menu components that care about stat/equip updates subscribe to this list indirectly (See Menu::AddStatListener()). - static std::vectorchapterListeners; //All menu components that care about story chapter updates subscribe to this list indirectly (See Menu::AddChapterListener()). + static safemap>>inventoryListeners; //All menu components that care about inventory updates subscribe to this list indirectly (See Menu::AddInventoryListener()). + static safemap>>merchantInventoryListeners; //All menu components that care about merchant inventory updates subscribe to this list indirectly (See Menu::AddMerchantInventoryListener()). + static std::vector>equipStatListeners; //All menu components that care about stat/equip updates subscribe to this list indirectly (See Menu::AddStatListener()). + static std::vector>chapterListeners; //All menu components that care about story chapter updates subscribe to this list indirectly (See Menu::AddChapterListener()). public: //The constructor is private. Use CreateMenu() instead! Menu()=default; - ~Menu(); //DO NOT USE DIRECTLY! You should be utilizing the ADD macro for adding components. template - T*_AddComponent(std::string componentKey,T*component,int depth=DEFAULT_DEPTH){ + std::shared_ptr_AddComponent(std::string componentKey,std::shared_ptrcomponent,int depth=DEFAULT_DEPTH){ component->parentMenu=type; if(depth==DEFAULT_DEPTH){ component->depth=STARTING_DEPTH-componentCount; }else{ component->depth=depth; } - if(component->selectable){ - buttons.Unlock(); - if(buttons.count(int(component->rect.pos.y))){ - buttons.at(int(component->rect.pos.y)).push_back(component); - }else{ - buttons[int(component->rect.pos.y)].push_back(component); - } - if(component->selectableViaKeyboard){ - keyboardButtons.Unlock(); - if(keyboardButtons.count(int(component->rect.pos.y))){ - keyboardButtons.at(int(component->rect.pos.y)).push_back(component); - }else{ - keyboardButtons[int(component->rect.pos.y)].push_back(component); - } - } - - //We must lock the values before calling sort. Sort seems to try and create new accesses. - buttons.SetInitialized(); - keyboardButtons.SetInitialized(); - - //We make an assumption that menu components are supposed to be in left-to-right order. Sometimes we may add things out-of-order, so this fixes the problem by sorting the items afterwards. - std::sort(buttons[int(component->rect.pos.y)].begin(),buttons[int(component->rect.pos.y)].end(),[](auto c1,auto c2){ - return c1->GetPos().xGetPos().x; - }); - if(keyboardButtons.count(int(component->rect.pos.y))){ //Keyboard buttons may not necessarily contain this key...Let's be sure. - std::sort(keyboardButtons[int(component->rect.pos.y)].begin(),keyboardButtons[int(component->rect.pos.y)].end(),[](auto c1,auto c2){ - return c1->GetPos().xGetPos().x; - }); - } - }else{ - displayComponents.push_back(component); - } - RecalculateComponentCount(); if(components.count(componentKey)){ @@ -178,7 +144,6 @@ public: components[componentKey]=component; components.SetInitialized(); lastRegisteredComponent=componentKey; - std::erase_if(Menu::unhandledComponents,[&](auto b1){return b1==component;}); return component; } @@ -194,27 +159,23 @@ public: static std::vectorstack; static std::string themeSelection; static safeunorderedmapthemes; - static std::vectorunhandledComponents; //This list contains MenuComponents that are created and haven't been assigned via _AddComponent. If we get to the end of menu initialization and there are any components in this vector, we have leaked memory and will report this. static const vf2d CENTERED; static bool IsMenuOpen(); const MenuType GetType()const; - safemapcomponents; //A friendly way to interrogate any component we are interested in. - std::vectordisplayComponents; //Components that are only for displaying purposes. + safemap>components; //A friendly way to interrogate any component we are interested in. static std::mapmenus; vf2d pos; //Specify the upper-left corner of the window. Using CENTERED will always put this where the upper-left corner would center the window. vf2d size; //Size in tiles (24x24), every menu will be tile-based - safemap>buttons; //Buttons are stored in rows followed by their column order. - safemap>keyboardButtons; //Button ordered storage for keyboard/menu static Theme&GetCurrentTheme(); static bool UsingMouseNavigation(); void SetMouseNavigation(bool mouseNavigation); static void InventorySlotsUpdated(ITCategory cat); //Called whenever the player's inventory gets modified. static void MerchantInventorySlotsUpdated(ITCategory cat); //Called whenever a traveling merchant's inventory item gets updated. - static void AddInventoryListener(MenuComponent*component,ITCategory category); //Adds a component to be in a given listener category. - static void AddMerchantInventoryListener(MenuComponent*component,ITCategory category); //Adds a component to be in a given listener category. - static void AddEquipStatListener(MenuComponent*component); //Adds a component to be in an equip stat listener. Will receive updates whenever stats are updated via equips. - static void AddChapterListener(MenuComponent*component); //Adds a component to be in a chapter listener. Will receive updates anytime the chapter in-game changes. + static void AddInventoryListener(std::weak_ptrcomponent,ITCategory category); //Adds a component to be in a given listener category. + static void AddMerchantInventoryListener(std::weak_ptrcomponent,ITCategory category); //Adds a component to be in a given listener category. + static void AddEquipStatListener(std::weak_ptrcomponent); //Adds a component to be in an equip stat listener. Will receive updates whenever stats are updated via equips. + static void AddChapterListener(std::weak_ptrcomponent); //Adds a component to be in a chapter listener. Will receive updates anytime the chapter in-game changes. vf2d center(); //Returns the last menu type created and last registered component, in case a component is detected as memory leaking, provides this information to each component for safety. static std::pairGetMemoryLeakReportInfo(); @@ -242,7 +203,7 @@ private: static void DrawTiledWindowBorder(AiL*game,vf2d menuPos,vf2d size,Pixel renderColor); //This triggers if we use a keyboard/controller input to try and select some off-screen menu item. We should ideally follow the menu cursor. - bool HandleOutsideDisabledButtonSelection(MenuComponent*disabledButton); + bool HandleOutsideDisabledButtonSelection(std::weak_ptrdisabledButton); Pixel GetRenderColor(); MenuType type; @@ -252,17 +213,16 @@ private: }; template -T*Component(MenuType menu,std::string componentName){ - T*tmp=DYNAMIC_CAST(Menu::menus[menu]->components[componentName]); - return tmp; +std::shared_ptrComponent(MenuType menu,std::string componentName){ + return DYNAMIC_POINTER_CAST(Menu::menus[menu]->components[componentName]); } struct MenuFuncData{ Menu&menu; AiL*const game; - MenuComponent*const component; - ScrollableWindowComponent*const parentComponent=nullptr; - MenuFuncData(Menu&menu,AiL*const game,MenuComponent*const component,ScrollableWindowComponent*const parentComponent=nullptr); + const std::weak_ptr component; + const std::weak_ptr parentComponent={}; + MenuFuncData(Menu&menu,AiL*const game,std::weak_ptr component,std::weak_ptrparentComponent={}); }; using MenuFunc=std::function; \ No newline at end of file diff --git a/Adventures in Lestoria/MenuAnimatedIconToggleButton.h b/Adventures in Lestoria/MenuAnimatedIconToggleButton.h index 213d025a..17b46f27 100644 --- a/Adventures in Lestoria/MenuAnimatedIconToggleButton.h +++ b/Adventures in Lestoria/MenuAnimatedIconToggleButton.h @@ -51,9 +51,9 @@ private: public: inline MenuAnimatedIconToggleButton(geom2d::rectrect,std::string animation,MenuFunc onClick) :MenuAnimatedIconButton(rect,animation,[](MenuFuncData data){ - MenuAnimatedIconToggleButton*button=(MenuAnimatedIconToggleButton*)data.component; - button->Select(); - button->_onClick(data); + std::weak_ptrbutton=DYNAMIC_POINTER_CAST(data.component.lock()); + button.lock()->Select(); + button.lock()->_onClick(data); return true; }),_onClick(onClick){} protected: diff --git a/Adventures in Lestoria/MenuComponent.cpp b/Adventures in Lestoria/MenuComponent.cpp index e4834552..a739edbc 100644 --- a/Adventures in Lestoria/MenuComponent.cpp +++ b/Adventures in Lestoria/MenuComponent.cpp @@ -45,9 +45,7 @@ INCLUDE_game using A=Attribute; MenuComponent::MenuComponent(geom2d::rectrect,std::string label,MenuFunc onClick,ButtonAttr attributes) - :rect(rect),originalPos(rect.pos),label(label),menuDest(MenuType::ENUM_END),onClick(onClick),hoverEffect(0),selectable(!(attributes&ButtonAttr::UNSELECTABLE)),selectableViaKeyboard(!(attributes&ButtonAttr::UNSELECTABLE_VIA_KEYBOARD)),memoryLeakInfo(Menu::GetMemoryLeakReportInfo()),fitToLabel(attributes&ButtonAttr::FIT_TO_LABEL){ - Menu::unhandledComponents.push_back(this); -} + :rect(rect),originalPos(rect.pos),label(label),menuDest(MenuType::ENUM_END),onClick(onClick),hoverEffect(0),selectable(!(attributes&ButtonAttr::UNSELECTABLE)),selectableViaKeyboard(!(attributes&ButtonAttr::UNSELECTABLE_VIA_KEYBOARD)),memoryLeakInfo(Menu::GetMemoryLeakReportInfo()),fitToLabel(attributes&ButtonAttr::FIT_TO_LABEL){} MenuComponent::MenuComponent(geom2d::rectrect,std::string label,MenuType menuDest,MenuFunc onClick,ButtonAttr attributes) :MenuComponent(rect,label,onClick,attributes){ @@ -61,19 +59,7 @@ MenuComponent::MenuComponent(geom2d::rectrect,std::string label,MenuType this->labelScaling=labelScaling; } -MenuComponent::~MenuComponent(){ - Menu*pMenu=Menu::menus[parentMenu]; - for(auto key:pMenu->buttons){ - std::vector&components=key.second; - std::erase_if(components,[&](MenuComponent*component){return component==this;}); - } - for(auto key:pMenu->keyboardButtons){ - std::vector&components=key.second; - std::erase_if(components,[&](MenuComponent*component){return component==this;}); - } - std::erase_if(pMenu->displayComponents,[&](MenuComponent*component){return component==this;}); - //pMenu->components.erase(this->name); //We're not going to do this here because we are in the middle of a loop for another menu component when cleaning up. -} +MenuComponent::~MenuComponent(){} void MenuComponent::AfterCreate(){} @@ -146,17 +132,17 @@ void MenuComponent::_DrawDecal(ViewPort&window,bool focused){ } } -MenuComponent*MenuComponent::PickUpDraggableItem(){ - return nullptr; +std::unique_ptrMenuComponent::PickUpDraggableItem(){ + return {}; } -bool MenuComponent::DropDraggableItem(MenuComponent*draggable){ +bool MenuComponent::DropDraggableItem(std::unique_ptrdraggable){ return false; } bool MenuComponent::GetHoverState(AiL*game){ - if(parentComponent!=nullptr){ - return parentComponent->GetHoverState(game,this); + if(!parentComponent.expired()){ + return parentComponent.lock()->GetHoverState(game,this); }else{ vf2d parentWindowPos=Menu::menus[parentMenu]->pos; return geom2d::overlaps(geom2d::rect{rect.pos+parentWindowPos,rect.size},game->GetMousePos()); @@ -168,22 +154,22 @@ bool MenuComponent::GetHoverState(AiL*game,MenuComponent*child){ } bool MenuComponent::PointWithinParent(MenuComponent*child,vi2d drawPos){ - if(parentComponent!=nullptr){ - return parentComponent->PointWithinParent(child,drawPos); + if(!parentComponent.expired()){ + return parentComponent.lock()->PointWithinParent(child,drawPos); }else{ return true; } } bool MenuComponent::PointWithinParent(MenuComponent*child,geom2d::rect drawRect){ - if(parentComponent!=nullptr){ - return parentComponent->PointWithinParent(child,drawRect); + if(!parentComponent.expired()){ + return parentComponent.lock()->PointWithinParent(child,drawRect); }else{ return true; } } -bool MenuComponent::HandleOutsideDisabledButtonSelection(MenuComponent*disabledButton){ +bool MenuComponent::HandleOutsideDisabledButtonSelection(std::weak_ptrdisabledButton){ return false; }; @@ -225,7 +211,7 @@ void MenuComponent::_OnMouseOut(){ if(runHoverFunctions){ if(hoverState){ hoverState=false; - onMouseOut(MenuFuncData{*Menu::menus[parentMenu],game,this,(ScrollableWindowComponent*)(parentComponent)}); + onMouseOut(MenuFuncData{*Menu::menus[parentMenu],game,std::make_shared(*this),DYNAMIC_POINTER_CAST(parentComponent.lock())}); OnMouseOut(); } } @@ -235,7 +221,7 @@ void MenuComponent::_OnHover(){ if(hovered){ if(runHoverFunctions&&!hoverState){ hoverState=true; - onHover(MenuFuncData{*Menu::menus[parentMenu],game,this,(ScrollableWindowComponent*)(parentComponent)}); + onHover(MenuFuncData{*Menu::menus[parentMenu],game,std::make_shared(*this),DYNAMIC_POINTER_CAST(parentComponent.lock())}); OnHover(); } } @@ -259,5 +245,5 @@ void MenuComponent::OnPlayerMoneyUpdate(uint32_t newMoney){} void MenuComponent::OnChapterUpdate(uint8_t newChapter){} void MenuComponent::Click(){ - onClick(MenuFuncData{*Menu::menus[parentMenu],game,this}); + onClick(MenuFuncData{*Menu::menus[parentMenu],game,std::make_shared(*this)}); } \ No newline at end of file diff --git a/Adventures in Lestoria/MenuComponent.h b/Adventures in Lestoria/MenuComponent.h index f421c23e..c846219b 100644 --- a/Adventures in Lestoria/MenuComponent.h +++ b/Adventures in Lestoria/MenuComponent.h @@ -126,7 +126,7 @@ protected: virtual void OnHover(); public: MenuType parentMenu=MenuType::ENUM_END; - MenuComponent*parentComponent=nullptr; + std::weak_ptrparentComponent{}; MenuComponent(geom2d::rectrect,std::string label,MenuFunc onClick,ButtonAttr attributes=ButtonAttr::NONE); MenuComponent(geom2d::rectrect,std::string label,MenuType menuDest,MenuFunc onClick,ButtonAttr attributes=ButtonAttr::NONE); MenuComponent(geom2d::rectrect,std::string label,MenuType menuDest,MenuFunc onClick,vf2d labelScaling,ButtonAttr attributes=ButtonAttr::NONE); @@ -135,11 +135,11 @@ public: const vf2d&GetSize()const; //We picked up a draggable component, we should make a copy and return it here. If a nullptr is returned here, the pickup is not allowed. //WARNING!!! This allocates a brand new component when successful!!! Be prepared to clear it! - virtual MenuComponent*PickUpDraggableItem(); + virtual std::unique_ptrPickUpDraggableItem(); //We are attempting to drop draggable onto this item. If it's not allowed, return false. - virtual bool DropDraggableItem(MenuComponent*draggable); + virtual bool DropDraggableItem(std::unique_ptrdraggable); //A notification that a button outside the region has been selected. Return false if it's not allowed. - virtual bool HandleOutsideDisabledButtonSelection(MenuComponent*disabledButton); + virtual bool HandleOutsideDisabledButtonSelection(std::weak_ptrdisabledButton); //Called whenever equipment and base stats are updated, notifying a component that numbers that may be displayed have changed. virtual void OnEquipStatsUpdate(); virtual const std::string&GetLabel()const; diff --git a/Adventures in Lestoria/MenuItemButton.h b/Adventures in Lestoria/MenuItemButton.h index 7c024169..3eb9db3c 100644 --- a/Adventures in Lestoria/MenuItemButton.h +++ b/Adventures in Lestoria/MenuItemButton.h @@ -147,9 +147,9 @@ protected: } } } - inline MenuComponent*PickUpDraggableItem()override final{ + inline std::unique_ptrPickUpDraggableItem()override final{ if(valid){ - MenuItemButton*pickUp=NEW MenuItemButton(rect,invRef,inventoryIndex,onClick,itemDescriptionMenu,itemNameLabelName,itemDescriptionLabelName); + std::unique_ptrpickUp=std::make_unique(rect,invRef,inventoryIndex,onClick,itemDescriptionMenu,itemNameLabelName,itemDescriptionLabelName); valid=false; return pickUp; }else{ @@ -157,9 +157,9 @@ protected: } } - inline bool DropDraggableItem(MenuComponent*draggable)override final{ + inline bool DropDraggableItem(std::unique_ptrdraggable)override final{ //HACK Warning! We're making a bold assumption that every component that is draggable is of the same type! This may change in the future.... - MenuItemButton*draggedItem=(MenuItemButton*)draggable; + MenuItemButton*draggedItem=DYNAMIC_CAST(draggable.get()); ITCategory cat=draggedItem->invRef.at(draggedItem->inventoryIndex)->Category(); return Inventory::SwapItems(cat,draggedItem->inventoryIndex,inventoryIndex); } diff --git a/Adventures in Lestoria/MerchantWindow.cpp b/Adventures in Lestoria/MerchantWindow.cpp index 218fe2e2..fcfccd4e 100644 --- a/Adventures in Lestoria/MerchantWindow.cpp +++ b/Adventures in Lestoria/MerchantWindow.cpp @@ -61,7 +61,7 @@ void Menu::InitializeMerchantWindow(){ } std::sort(categories.begin(),categories.end(),[](std::pair&cat1,std::pair&cat2){return cat1.secondADD("Buy Tab",MenuComponent)({{2,0},{merchantWindow->size.x/2-4,24}},"Buy",[](MenuFuncData data){ + auto buyTab=merchantWindow->ADD("Buy Tab",MenuComponent)(geom2d::rect{{2,0},{merchantWindow->size.x/2-4,24}},"Buy",[](MenuFuncData data){ Component(MERCHANT,"Merchant Inventory Display")->Enable(true); Component(MERCHANT,"Sell Tab")->selected=false; Component(MERCHANT,"Inventory Tabs Outline")->Enable(false); @@ -71,13 +71,13 @@ void Menu::InitializeMerchantWindow(){ } Component(data.menu.GetType(),"Inventory Display - "+data.menu.S(A::LAST_INVENTORY_TYPE_OPENED))->Enable(false); Component(data.menu.GetType(),data.menu.S(A::LAST_INVENTORY_TYPE_OPENED)+" Inventory Tab")->Enable(false); - data.component->selected=true; + data.component.lock()->selected=true; return true; })END; buyTab->selected=true; buyTab->selectionType=SelectionType::HIGHLIGHT; - auto sellTab=merchantWindow->ADD("Sell Tab",MenuComponent)({{merchantWindow->size.x/2+2,0},{merchantWindow->size.x/2-4,24}},"Sell",[](MenuFuncData data){ + auto sellTab=merchantWindow->ADD("Sell Tab",MenuComponent)(geom2d::rect{{merchantWindow->size.x/2+2,0},{merchantWindow->size.x/2-4,24}},"Sell",[](MenuFuncData data){ Component(MERCHANT,"Merchant Inventory Display")->Enable(false); Component(MERCHANT,"Buy Tab")->selected=false; Component(MERCHANT,"Inventory Tabs Outline")->Enable(true); @@ -87,31 +87,31 @@ void Menu::InitializeMerchantWindow(){ } Component(data.menu.GetType(),"Inventory Display - "+data.menu.S(A::LAST_INVENTORY_TYPE_OPENED))->Enable(true); Component(data.menu.GetType(),data.menu.S(A::LAST_INVENTORY_TYPE_OPENED)+" Inventory Tab")->Enable(true); - data.component->selected=true; + data.component.lock()->selected=true; return true; })END; sellTab->selectionType=SelectionType::HIGHLIGHT; - auto inventoryDisplay=merchantWindow->ADD("Merchant Inventory Display",RowInventoryScrollableWindowComponent)({{2,28},{220,merchantWindow->size.y-44}},"Item Name Label","Item Description Label", + auto inventoryDisplay=merchantWindow->ADD("Merchant Inventory Display",RowInventoryScrollableWindowComponent)(geom2d::rect{{2,28},{220,merchantWindow->size.y-44}},"Item Name Label","Item Description Label", [](MenuFuncData data){ - RowItemDisplay*item=DYNAMIC_CAST(data.component); - Component(BUY_ITEM,"Item Purchase Header")->S(A::ITEM_NAME)=item->GetItem().lock()->ActualName(); - Component(BUY_ITEM,"Price per item Amount Label")->SetLabel(std::to_string(item->GetItem().lock()->BuyValue())); + std::weak_ptritem=DYNAMIC_POINTER_CAST(data.component.lock()); + Component(BUY_ITEM,"Item Purchase Header")->S(A::ITEM_NAME)=item.lock()->GetItem().lock()->ActualName(); + Component(BUY_ITEM,"Price per item Amount Label")->SetLabel(std::to_string(item.lock()->GetItem().lock()->BuyValue())); Component(BUY_ITEM,"Amount to buy Amount Label")->SetLabel("1"); - Component(BUY_ITEM,"Total Price Amount Label")->SetLabel(std::to_string(item->GetItem().lock()->BuyValue())); + Component(BUY_ITEM,"Total Price Amount Label")->SetLabel(std::to_string(item.lock()->GetItem().lock()->BuyValue())); Merchant&merchant=Merchant::GetCurrentTravelingMerchant(); - bool canPurchase=merchant.CanPurchaseItem(item->GetItem().lock()->ActualName(),1); + bool canPurchase=merchant.CanPurchaseItem(item.lock()->GetItem().lock()->ActualName(),1); std::string colorCode=""; if(!canPurchase)colorCode="#FF0000"; - Component(BUY_ITEM,"Total Price Amount Label")->SetLabel(colorCode+std::to_string(item->GetItem().lock()->BuyValue())); - Component(BUY_ITEM,"Item Purchase Header")->SetLabel("Buying "+item->GetItem().lock()->DisplayName()); - Component(BUY_ITEM,"Purchase Button")->SetGrayedOut(!merchant.CanPurchaseItem(item->GetItem().lock()->ActualName(),1)); + Component(BUY_ITEM,"Total Price Amount Label")->SetLabel(colorCode+std::to_string(item.lock()->GetItem().lock()->BuyValue())); + Component(BUY_ITEM,"Item Purchase Header")->SetLabel("Buying "+item.lock()->GetItem().lock()->DisplayName()); + Component(BUY_ITEM,"Purchase Button")->SetGrayedOut(!merchant.CanPurchaseItem(item.lock()->GetItem().lock()->ActualName(),1)); Menu::OpenMenu(BUY_ITEM); return true; }, [](MenuFuncData data){ - Component(data.menu.GetType(),"Item Icon")->SetItem(DYNAMIC_CAST(data.component)->GetItem()); + Component(data.menu.GetType(),"Item Icon")->SetItem(DYNAMIC_POINTER_CAST(data.component.lock())->GetItem()); return true; }, [](MenuFuncData data){ @@ -119,14 +119,14 @@ void Menu::InitializeMerchantWindow(){ return true; }, InventoryCreator::RowMerchant_InventoryUpdate, - {.padding=1,.size={220-13,28}})END; + InventoryWindowOptions{.padding=1,.size={220-13,28}})END; inventoryDisplay->SetPriceLabelType(PriceLabel::BUY_LABEL); for(auto&[category,items]:ITEM_CATEGORIES){ Menu::AddMerchantInventoryListener(inventoryDisplay,category); } - merchantWindow->ADD("Inventory Tabs Outline",MenuComponent)({{0,28},{72,merchantWindow->size.y-44}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END; + merchantWindow->ADD("Inventory Tabs Outline",MenuComponent)(geom2d::rect{{0,28},{72,merchantWindow->size.y-44}},"",DO_NOTHING,ButtonAttr::UNSELECTABLE)END; std::sort(categories.begin(),categories.end(),[](std::pair&cat1,std::pair&cat2){return cat1.secondADD(category+" Inventory Tab",MenuComponent)({{2,30+yOffset},{68,16}},category,MenuType::ENUM_END, + auto button=merchantWindow->ADD(category+" Inventory Tab",MenuComponent)(geom2d::rect{{2,30+yOffset},{68,16}},category,MenuType::ENUM_END, [&](MenuFuncData data){ //Close the old inventory window and show the proper one. Component(data.menu.GetType(),"Inventory Display - "+data.menu.S(A::LAST_INVENTORY_TYPE_OPENED))->Enable(false); Component(data.menu.GetType(),data.menu.S(A::LAST_INVENTORY_TYPE_OPENED)+" Inventory Tab")->SetSelected(false); - Component(data.menu.GetType(),"Inventory Display - "+data.component->S(A::CATEGORY_NAME))->Enable(true); - Component(data.menu.GetType(),data.component->S(A::CATEGORY_NAME)+" Inventory Tab")->SetSelected(true); - data.menu.S(A::LAST_INVENTORY_TYPE_OPENED)=data.component->S(A::CATEGORY_NAME); + Component(data.menu.GetType(),"Inventory Display - "+data.component.lock()->S(A::CATEGORY_NAME))->Enable(true); + Component(data.menu.GetType(),data.component.lock()->S(A::CATEGORY_NAME)+" Inventory Tab")->SetSelected(true); + data.menu.S(A::LAST_INVENTORY_TYPE_OPENED)=data.component.lock()->S(A::CATEGORY_NAME); return true; - },{textScaling,1.f})END; + },vf2d{textScaling,1.f})END; button->SetSelectionType(HIGHLIGHT); button->S(A::CATEGORY_NAME)=category; - auto inventoryDisplay=merchantWindow->ADD("Inventory Display - "+category,RowInventoryScrollableWindowComponent)({{72,28},{150,merchantWindow->size.y-44}},"Item Name Label","Item Description Label", + auto inventoryDisplay=merchantWindow->ADD("Inventory Display - "+category,RowInventoryScrollableWindowComponent)(geom2d::rect{{72,28},{150,merchantWindow->size.y-44}},"Item Name Label","Item Description Label", [](MenuFuncData data){ - RowItemDisplay*item=DYNAMIC_CAST(data.component); - if(item->GetItem().lock()->CanBeSold()){ - Component(SELL_ITEM,"Item Sell Header")->SetItem(item->GetItem()); - Component(SELL_ITEM,"Price per item Amount Label")->SetLabel(std::to_string(item->GetItem().lock()->SellValue())); + std::weak_ptritem=DYNAMIC_POINTER_CAST(data.component.lock()); + if(item.lock()->GetItem().lock()->CanBeSold()){ + Component(SELL_ITEM,"Item Sell Header")->SetItem(item.lock()->GetItem()); + Component(SELL_ITEM,"Price per item Amount Label")->SetLabel(std::to_string(item.lock()->GetItem().lock()->SellValue())); Component(SELL_ITEM,"Amount to sell Amount Label")->SetLabel("1"); - Component(SELL_ITEM,"Total Price Amount Label")->SetLabel(std::to_string(item->GetItem().lock()->SellValue())); + Component(SELL_ITEM,"Total Price Amount Label")->SetLabel(std::to_string(item.lock()->GetItem().lock()->SellValue())); Merchant&merchant=Merchant::GetCurrentTravelingMerchant(); - bool canPurchase=merchant.CanSellItem(item->GetItem(),1); + bool canPurchase=merchant.CanSellItem(item.lock()->GetItem(),1); std::string colorCode=""; if(!canPurchase)colorCode="#FF0000"; - Component(SELL_ITEM,"Total Price Amount Label")->SetLabel(colorCode+std::to_string(item->GetItem().lock()->SellValue())); - Component(SELL_ITEM,"Item Sell Header")->SetLabel("Selling "+item->GetItem().lock()->DisplayName()); - Component(SELL_ITEM,"Sell Button")->SetGrayedOut(!merchant.CanSellItem(item->GetItem(),1)); + Component(SELL_ITEM,"Total Price Amount Label")->SetLabel(colorCode+std::to_string(item.lock()->GetItem().lock()->SellValue())); + Component(SELL_ITEM,"Item Sell Header")->SetLabel("Selling "+item.lock()->GetItem().lock()->DisplayName()); + Component(SELL_ITEM,"Sell Button")->SetGrayedOut(!merchant.CanSellItem(item.lock()->GetItem(),1)); Menu::OpenMenu(SELL_ITEM); } return true; }, [](MenuFuncData data){ - Component(data.menu.GetType(),"Item Icon")->SetItem(DYNAMIC_CAST(data.component)->GetItem()); + Component(data.menu.GetType(),"Item Icon")->SetItem(DYNAMIC_POINTER_CAST(data.component.lock())->GetItem()); return true; }, [](MenuFuncData data){ @@ -179,7 +179,7 @@ void Menu::InitializeMerchantWindow(){ return true; }, InventoryCreator::RowPlayer_InventoryUpdate, - {.padding=1,.size={137,28}})END; + InventoryWindowOptions{.padding=1,.size={137,28}})END; inventoryDisplay->SetPriceLabelType(PriceLabel::SELL_LABEL); if(first){ @@ -198,27 +198,27 @@ void Menu::InitializeMerchantWindow(){ #pragma region Inventory Description float inventoryDescriptionWidth=merchantWindow->pos.x+merchantWindow->size.x-26-224; - merchantWindow->ADD("Item Description Outline",MenuLabel)({{224,28},{inventoryDescriptionWidth,merchantWindow->size.y-44}},"",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; - merchantWindow->ADD("Item Icon",MenuItemItemButton)({{226+inventoryDescriptionWidth/2-24,30},{48,48}},Item::BLANK,MenuType::ENUM_END,DO_NOTHING,"","",IconButtonAttr::NOT_SELECTABLE)END; - merchantWindow->ADD("Item Name Label",MenuLabel)({{226,84},{inventoryDescriptionWidth-6,12}},"",0.75f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; - merchantWindow->ADD("Item Description Label",MenuLabel)({{226,94},{inventoryDescriptionWidth-6,merchantWindow->size.y-44-66}},"",0.5f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; + merchantWindow->ADD("Item Description Outline",MenuLabel)(geom2d::rect{{224,28},{inventoryDescriptionWidth,merchantWindow->size.y-44}},"",1,ComponentAttr::LEFT_ALIGN|ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND)END; + merchantWindow->ADD("Item Icon",MenuItemItemButton)(geom2d::rect{{226+inventoryDescriptionWidth/2-24,30},{48,48}},Item::BLANK,MenuType::ENUM_END,DO_NOTHING,"","",IconButtonAttr::NOT_SELECTABLE)END; + merchantWindow->ADD("Item Name Label",MenuLabel)(geom2d::rect{{226,84},{inventoryDescriptionWidth-6,12}},"",0.75f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; + merchantWindow->ADD("Item Description Label",MenuLabel)(geom2d::rect{{226,94},{inventoryDescriptionWidth-6,merchantWindow->size.y-44-66}},"",0.5f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; #pragma endregion #pragma region Money Display vf2d moneyIconPos={224+inventoryDescriptionWidth-24,28+merchantWindow->size.y-44+6}; - auto moneyIcon=merchantWindow->ADD("Money Icon",MenuIconButton)({moneyIconPos,{24,24}},GFX["money.png"].Decal(),DO_NOTHING,IconButtonAttr::NOT_SELECTABLE|IconButtonAttr::NO_OUTLINE|IconButtonAttr::NO_BACKGROUND)END; + auto moneyIcon=merchantWindow->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; std::string moneyText=std::to_string(game->GetPlayer()->GetMoney()); vf2d moneyTextSize=game->GetTextSizeProp(moneyText)*2; - auto moneyDisplay=merchantWindow->ADD("Money Label",PlayerMoneyLabel)({moneyIconPos-vf2d{2+moneyTextSize.x,-2},moneyTextSize},2,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN|ComponentAttr::FIT_TO_LABEL)END; + auto moneyDisplay=merchantWindow->ADD("Money Label",PlayerMoneyLabel)(geom2d::rect{moneyIconPos-vf2d{2+moneyTextSize.x,-2},moneyTextSize},2,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN|ComponentAttr::FIT_TO_LABEL)END; moneyDisplay->SetRightAlignment(true); Player::AddMoneyListener(moneyDisplay); #pragma endregion - merchantWindow->ADD("Leave Button",MenuComponent)({{merchantWindow->size.x/2-48,28+merchantWindow->size.y-44+6},{96,24}},"Leave",MenuType::ENUM_END, + merchantWindow->ADD("Leave Button",MenuComponent)(geom2d::rect{{merchantWindow->size.x/2-48,28+merchantWindow->size.y-44+6},{96,24}},"Leave",MenuType::ENUM_END, [](MenuFuncData data){ Menu::CloseMenu(); return true; - },{2,2})END; + },vf2d{2,2})END; buyTab->onClick(MenuFuncData{*merchantWindow,game,buyTab}); } \ No newline at end of file diff --git a/Adventures in Lestoria/OverworldMapLevelWindow.cpp b/Adventures in Lestoria/OverworldMapLevelWindow.cpp index dfac481a..e9c8ea3d 100644 --- a/Adventures in Lestoria/OverworldMapLevelWindow.cpp +++ b/Adventures in Lestoria/OverworldMapLevelWindow.cpp @@ -52,14 +52,14 @@ void Menu::InitializeOverworldMapLevelWindow(){ vf2d windowSize={game->GetScreenSize().x/3.f-24,float(game->GetScreenSize().y)-48}; Menu*levelSelectWindow=CreateMenu(OVERWORLD_LEVEL_SELECT,{game->GetScreenSize().x-game->GetScreenSize().x/3.f,24},windowSize); - levelSelectWindow->ADD("Panel 1 Back",MenuLabel)({{0,0},{windowSize.x-1,44}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)END; - levelSelectWindow->ADD("Chapter Label",MenuLabel)({{0,4},{windowSize.x,16}},"Chapter",1,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN)DEPTH -1 END; - levelSelectWindow->ADD("Stage Label",MenuLabel)({{0,24},{windowSize.x,16}},"Stage",1,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN)DEPTH -1 END; + levelSelectWindow->ADD("Panel 1 Back",MenuLabel)(geom2d::rect{{0,0},{windowSize.x-1,44}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)END; + levelSelectWindow->ADD("Chapter Label",MenuLabel)(geom2d::rect{{0,4},{windowSize.x,16}},"Chapter",1,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN)DEPTH -1 END; + levelSelectWindow->ADD("Stage Label",MenuLabel)(geom2d::rect{{0,24},{windowSize.x,16}},"Stage",1,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN)DEPTH -1 END; - levelSelectWindow->ADD("Panel 2 Back",MenuLabel)({{0,52},{windowSize.x-1,96}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)END; - levelSelectWindow->ADD("Encounters Label",MenuLabel)({{0,52},{windowSize.x-1,12}},"Encounters:",1,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN)END; - levelSelectWindow->ADD("Spawns List",EncountersSpawnListScrollableWindowComponent)({{1,64},{windowSize.x-2,84}},ComponentAttr::BACKGROUND)END; + levelSelectWindow->ADD("Panel 2 Back",MenuLabel)(geom2d::rect{{0,52},{windowSize.x-1,96}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)END; + levelSelectWindow->ADD("Encounters Label",MenuLabel)(geom2d::rect{{0,52},{windowSize.x-1,12}},"Encounters:",1,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN)END; + levelSelectWindow->ADD("Spawns List",EncountersSpawnListScrollableWindowComponent)(geom2d::rect{{1,64},{windowSize.x-2,84}},ComponentAttr::BACKGROUND)END; - levelSelectWindow->ADD("Change Loadout Button",MenuComponent)({{0,152},{windowSize.x-1,12}},"Change Loadout",ITEM_LOADOUT,[](MenuFuncData data){return true;})END; - levelSelectWindow->ADD("Enter Button",MenuComponent)({{0,166},{windowSize.x-1,16}},"Enter",[](MenuFuncData data){State_OverworldMap::StartLevel();return true;})END; + levelSelectWindow->ADD("Change Loadout Button",MenuComponent)(geom2d::rect{{0,152},{windowSize.x-1,12}},"Change Loadout",ITEM_LOADOUT,[](MenuFuncData data){return true;})END; + levelSelectWindow->ADD("Enter Button",MenuComponent)(geom2d::rect{{0,166},{windowSize.x-1,16}},"Enter",[](MenuFuncData data){State_OverworldMap::StartLevel();return true;})END; } \ No newline at end of file diff --git a/Adventures in Lestoria/OverworldMenuWindow.cpp b/Adventures in Lestoria/OverworldMenuWindow.cpp index 57fc7975..450c63f5 100644 --- a/Adventures in Lestoria/OverworldMenuWindow.cpp +++ b/Adventures in Lestoria/OverworldMenuWindow.cpp @@ -48,16 +48,16 @@ INCLUDE_GFX void Menu::InitializeOverworldMenuWindow(){ Menu*overworldMenuWindow=CreateMenu(OVERWORLD_MENU,CENTERED,vi2d{96,164}); - overworldMenuWindow->ADD("Resume Button",MenuComponent)({{4,12+28*0},{88,24}},"Resume",[](MenuFuncData data){Menu::CloseMenu();return true;})END; - overworldMenuWindow->ADD("Character Button",MenuComponent)({{4,12+28*1},{88,24}},"Character", + overworldMenuWindow->ADD("Resume Button",MenuComponent)(geom2d::rect{{4,12+28*0},{88,24}},"Resume",[](MenuFuncData data){Menu::CloseMenu();return true;})END; + overworldMenuWindow->ADD("Character Button",MenuComponent)(geom2d::rect{{4,12+28*1},{88,24}},"Character", [](MenuFuncData data){ Component(CHARACTER_MENU,"Character Rotating Display")->SetIcon(GFX[classutils::GetClassInfo(game->GetPlayer()->GetClassName()).classFullImgName].Decal()); Menu::OpenMenu(CHARACTER_MENU); return true; })END; - overworldMenuWindow->ADD("Inventory Button",MenuComponent)({{4,12+28*2},{88,24}},"Inventory",[](MenuFuncData data){Menu::OpenMenu(INVENTORY);return true;})END; - overworldMenuWindow->ADD("Settings Button",MenuComponent)({{4,12+28*3},{88,24}},"Settings",[](MenuFuncData data){/*Menu::OpenMenu(SETTINGS_MENU);*/return true;})END; - overworldMenuWindow->ADD("Quit Button",MenuComponent)({{4,12+28*4},{88,24}},"Quit Game",[](MenuFuncData data){ + overworldMenuWindow->ADD("Inventory Button",MenuComponent)(geom2d::rect{{4,12+28*2},{88,24}},"Inventory",[](MenuFuncData data){Menu::OpenMenu(INVENTORY);return true;})END; + overworldMenuWindow->ADD("Settings Button",MenuComponent)(geom2d::rect{{4,12+28*3},{88,24}},"Settings",[](MenuFuncData data){/*Menu::OpenMenu(SETTINGS_MENU);*/return true;})END; + overworldMenuWindow->ADD("Quit Button",MenuComponent)(geom2d::rect{{4,12+28*4},{88,24}},"Quit Game",[](MenuFuncData data){ Menu::CloseAllMenus(); SaveFile::SaveGame(); game->ResetGame(); diff --git a/Adventures in Lestoria/Player.cpp b/Adventures in Lestoria/Player.cpp index ae25ca6e..04d0dd51 100644 --- a/Adventures in Lestoria/Player.cpp +++ b/Adventures in Lestoria/Player.cpp @@ -73,7 +73,7 @@ InputGroup Player::KEY_ITEM1; InputGroup Player::KEY_ITEM2; InputGroup Player::KEY_ITEM3; -std::setPlayer::moneyListeners; +std::vector>Player::moneyListeners; Player::Player() :lastReleasedMovementKey(DOWN),facingDirection(DOWN),state(State::NORMAL){ @@ -1020,8 +1020,8 @@ void EntityStats::RecalculateEquipStats(){ equipStats.A(key)+=setStats.A_Read(key); } } - for(MenuComponent*component:Menu::equipStatListeners){ - component->OnEquipStatsUpdate(); + for(std::weak_ptrcomponent:Menu::equipStatListeners){ + component.lock()->OnEquipStatsUpdate(); } } @@ -1065,12 +1065,14 @@ uint32_t Player::GetMoney()const{ void Player::SetMoney(uint32_t newMoney){ money=newMoney; for(auto&component:moneyListeners){ - component->OnPlayerMoneyUpdate(newMoney); + component.lock()->OnPlayerMoneyUpdate(newMoney); } } -void Player::AddMoneyListener(MenuComponent*component){ - if(moneyListeners.count(component))ERR("WARNING! Trying to add a second copy of component "<GetName())); - moneyListeners.insert(component); +void Player::AddMoneyListener(std::weak_ptrcomponent){ + if(std::find(moneyListeners.begin(),moneyListeners.end(),[&](auto&ptr){return &*ptr.lock()==&*component.lock();})!=moneyListeners.end()){ + ERR("WARNING! Component "<GetName()<<" has already been added to the Chapter listener list! There should not be any duplicates!!") + } + moneyListeners.push_back(component); } diff --git a/Adventures in Lestoria/Player.h b/Adventures in Lestoria/Player.h index e45ef650..cd3919a3 100644 --- a/Adventures in Lestoria/Player.h +++ b/Adventures in Lestoria/Player.h @@ -217,9 +217,9 @@ public: void PerformHPRecovery(); static InputGroup KEY_ABILITY1, KEY_ABILITY2, KEY_ABILITY3, KEY_ABILITY4, KEY_DEFENSIVE, KEY_ITEM1, KEY_ITEM2, KEY_ITEM3; - static std::setmoneyListeners; + static std::vector>moneyListeners; - static void AddMoneyListener(MenuComponent*component); + static void AddMoneyListener(std::weak_ptrcomponent); uint32_t GetMoney()const; void SetMoney(uint32_t newMoney); void AddXP(const uint32_t xpGain); diff --git a/Adventures in Lestoria/RowInventoryScrollableWindowComponent.h b/Adventures in Lestoria/RowInventoryScrollableWindowComponent.h index f8212bcd..ced09e09 100644 --- a/Adventures in Lestoria/RowInventoryScrollableWindowComponent.h +++ b/Adventures in Lestoria/RowInventoryScrollableWindowComponent.h @@ -51,17 +51,17 @@ public: virtual inline void SetCompactDescriptions(CompactText compact)override final{ this->compact=compact; - for(MenuComponent*component:components){ - RowItemDisplay*itemButton=DYNAMIC_CAST(component); - itemButton->SetCompactDescriptions(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(MenuComponent*component:components){ - RowItemDisplay*itemButton=DYNAMIC_CAST(component); - itemButton->SetPriceLabelType(labelType); + for(std::weak_ptrcomponent:components){ + std::weak_ptritemButton=DYNAMIC_POINTER_CAST(component.lock()); + itemButton.lock()->SetPriceLabelType(labelType); } } }; \ No newline at end of file diff --git a/Adventures in Lestoria/SaveFile.cpp b/Adventures in Lestoria/SaveFile.cpp index df178431..bb0be149 100644 --- a/Adventures in Lestoria/SaveFile.cpp +++ b/Adventures in Lestoria/SaveFile.cpp @@ -223,9 +223,9 @@ const void SaveFile::UpdateSaveGameData(){ float offsetY=0; for(size_t i=0;iADD(std::format("Load File Button - Save {}",i),LoadFileButton)({{0,offsetY},{gameFilesList->GetSize().x-13,48}},metadata[std::format("save{}",i)],i,[](MenuFuncData data){ - LoadFileButton*comp=DYNAMIC_CAST(data.component); - saveFileID=comp->getSaveFileID(); + gameFilesList->ADD(std::format("Load File Button - Save {}",i),LoadFileButton)(geom2d::rect{{0,offsetY},{gameFilesList->GetSize().x-13,48}},metadata[std::format("save{}",i)],i,[](MenuFuncData data){ + std::weak_ptrcomp=DYNAMIC_POINTER_CAST(data.component.lock()); + saveFileID=comp.lock()->getSaveFileID(); SaveFile::LoadGame(); return true; },ButtonAttr::NONE)END; diff --git a/Adventures in Lestoria/SaveFileWindow.cpp b/Adventures in Lestoria/SaveFileWindow.cpp index e34553b3..5112ebe1 100644 --- a/Adventures in Lestoria/SaveFileWindow.cpp +++ b/Adventures in Lestoria/SaveFileWindow.cpp @@ -42,10 +42,10 @@ All rights reserved. void Menu::InitializeSaveFileWindow(){ Menu*saveFileWindow=CreateMenu(SAVE_FILE_NAME,CENTERED,vi2d{96,96}); - saveFileWindow->ADD("Save File Name Entry Label",MenuLabel)({{-8,0},{112,36}},"Save File Name:",1.0f,ComponentAttr::SHADOW)END; - saveFileWindow->ADD("Save File Name Text Entry",TextEntryLabel)({{-8,36},{112,24}},TEXTCHANGE_DONOTHING,false,16U,2.f,ComponentAttr::FIT_TO_LABEL|ComponentAttr::OUTLINE|ComponentAttr::SHADOW|ComponentAttr::BACKGROUND)END; - saveFileWindow->ADD("Back Button",MenuComponent)({{-8,68},{48,12}},"Back",[](MenuFuncData data){Menu::CloseMenu();game->TextEntryEnable(false);return true;})END; - saveFileWindow->ADD("Continue Button",MenuComponent)({{56,68},{48,12}},"Begin",MenuType::CLASS_SELECTION,[](MenuFuncData data){ + saveFileWindow->ADD("Save File Name Entry Label",MenuLabel)(geom2d::rect{{-8,0},{112,36}},"Save File Name:",1.0f,ComponentAttr::SHADOW)END; + saveFileWindow->ADD("Save File Name Text Entry",TextEntryLabel)(geom2d::rect{{-8,36},{112,24}},TEXTCHANGE_DONOTHING,false,16U,2.f,ComponentAttr::FIT_TO_LABEL|ComponentAttr::OUTLINE|ComponentAttr::SHADOW|ComponentAttr::BACKGROUND)END; + saveFileWindow->ADD("Back Button",MenuComponent)(geom2d::rect{{-8,68},{48,12}},"Back",[](MenuFuncData data){Menu::CloseMenu();game->TextEntryEnable(false);return true;})END; + saveFileWindow->ADD("Continue Button",MenuComponent)(geom2d::rect{{56,68},{48,12}},"Begin",MenuType::CLASS_SELECTION,[](MenuFuncData data){ SaveFile::SetSaveFileName(game->TextEntryGetString()); SaveFile::SetSaveFileID(SaveFile::GetSaveFileCount()); game->TextEntryEnable(false); diff --git a/Adventures in Lestoria/ScrollableWindowComponent.h b/Adventures in Lestoria/ScrollableWindowComponent.h index 67d2df58..3306597d 100644 --- a/Adventures in Lestoria/ScrollableWindowComponent.h +++ b/Adventures in Lestoria/ScrollableWindowComponent.h @@ -43,12 +43,12 @@ All rights reserved. using A=Attribute; -class ScrollableWindowComponent:public MenuComponent{ +class ScrollableWindowComponent:public MenuComponent,std::enable_shared_from_this{ protected: ViewPort subWindow; - std::vectorcomponents; - MenuComponent*upButton=nullptr; - MenuComponent*downButton=nullptr; + std::vector>components; + std::weak_ptrupButton; + std::weak_ptrdownButton; geom2d::rectbounds; //It's for the scrollbar. float scrollBarHeight=0; float scrollBarTop=0; @@ -56,8 +56,8 @@ protected: float scrollBarHoverTime=0; vf2d scrollOffset; protected: - inline bool OnScreen(MenuComponent*component){ - return geom2d::overlaps(geom2d::rect{{},rect.size},geom2d::rect{component->rect.pos+vf2d{2,2},component->rect.size-vf2d{2,2}}); + inline bool OnScreen(std::weak_ptrcomponent){ + return geom2d::overlaps(geom2d::rect{{},rect.size},geom2d::rect{component.lock()->rect.pos+vf2d{2,2},component.lock()->rect.size-vf2d{2,2}}); } public: inline ScrollableWindowComponent(geom2d::rectrect,ComponentAttr attributes=ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE) @@ -70,37 +70,17 @@ public: RemoveButton(components.back()); } } - virtual inline void RemoveButton(MenuComponent*button){ - std::vector&buttonList=Menu::menus[button->parentMenu]->buttons.at(int(button->originalPos.y)); - std::vector&keyboardButtonList=Menu::menus[button->parentMenu]->keyboardButtons.at(int(button->originalPos.y)); - size_t removedCount=0; - removedCount+=std::erase(buttonList,button); - removedCount+=std::erase(keyboardButtonList,button); - removedCount+=Menu::menus[button->parentMenu]->components.erase(button->GetName()); - if(removedCount!=3){ - std::cout<<"WARNING! Attempted to remove buttons from button listing, but not found!"; - } - if(buttonList.size()==0){ - if(!Menu::menus[button->parentMenu]->buttons.erase(int(button->originalPos.y))){ - ERR("WARNING! Attempted to erase key "<originalPos.y<<" from button map, but the list still exists!") - } - } - if(keyboardButtonList.size()==0){ - if(!Menu::menus[button->parentMenu]->keyboardButtons.erase(int(button->originalPos.y))){ - ERR("WARNING! Attempted to erase key "<originalPos.y<<" from button map, but the list still exists!") - } - } - auto componentSearchResults=std::find(components.begin(),components.end(),button); - if(componentSearchResults==components.end())ERR("Could not find Component"<GetName())<<" inside the component list!"); + virtual inline void RemoveButton(std::weak_ptrbutton){ + auto componentSearchResults=std::find(components.begin(),components.end(),[&](const std::weak_ptr&ptr){return &*ptr.lock()==&*button.lock();}); + if(componentSearchResults==components.end())ERR("Could not find Component"<GetName())<<" inside the component list!"); components.erase(componentSearchResults); - Menu::menus[button->parentMenu]->RecalculateComponentCount(); - delete button; + Menu::menus[button.lock()->parentMenu]->RecalculateComponentCount(); CalculateBounds(); } virtual inline void SetScrollAmount(vf2d scrollOffset){ this->scrollOffset=scrollOffset; - for(MenuComponent*component:components){ - component->rect.pos=component->originalPos+scrollOffset; + for(std::weak_ptrcomponent:components){ + component.lock()->rect.pos=component.lock()->originalPos+scrollOffset; } } virtual inline vf2d GetScrollAmount(){ @@ -109,16 +89,16 @@ public: protected: virtual inline void AfterCreate()override{ //Let's use the internal name of this component to add unique names for sub-components. - upButton=Menu::menus[parentMenu]->ADD(name+vf2d(rect.pos+vf2d{rect.size.x-12,0}).str()+"_"+vf2d(12,12).str(),MenuComponent)({rect.pos+vf2d{rect.size.x-12,0},{12,12}},"^",[&](MenuFuncData dat){SetScrollAmount(GetScrollAmount()+vf2d{0,"ThemeGlobal.MenuButtonScrollSpeed"_F});return true;},ButtonAttr::UNSELECTABLE_VIA_KEYBOARD)DEPTH depth-1 END; - downButton=Menu::menus[parentMenu]->ADD(name+vf2d(rect.pos+rect.size-vf2d{12,12}).str()+"_"+vf2d(12,12).str(),MenuComponent)({rect.pos+rect.size-vf2d{12,12},{12,12}},"v",[&](MenuFuncData dat){SetScrollAmount(GetScrollAmount()-vf2d{0,"ThemeGlobal.MenuButtonScrollSpeed"_F});return true;},ButtonAttr::UNSELECTABLE_VIA_KEYBOARD)DEPTH depth-1 END; + upButton=Menu::menus[parentMenu]->ADD(name+vf2d(rect.pos+vf2d{rect.size.x-12,0}).str()+"_"+vf2d(12,12).str(),MenuComponent)(geom2d::rect{rect.pos+vf2d{rect.size.x-12,0},{12,12}},"^",[&](MenuFuncData dat){SetScrollAmount(GetScrollAmount()+vf2d{0,"ThemeGlobal.MenuButtonScrollSpeed"_F});return true;},ButtonAttr::UNSELECTABLE_VIA_KEYBOARD)DEPTH depth-1 END; + downButton=Menu::menus[parentMenu]->ADD(name+vf2d(rect.pos+rect.size-vf2d{12,12}).str()+"_"+vf2d(12,12).str(),MenuComponent)(geom2d::rect{rect.pos+rect.size-vf2d{12,12},{12,12}},"v",[&](MenuFuncData dat){SetScrollAmount(GetScrollAmount()-vf2d{0,"ThemeGlobal.MenuButtonScrollSpeed"_F});return true;},ButtonAttr::UNSELECTABLE_VIA_KEYBOARD)DEPTH depth-1 END; subWindow=ViewPort::rectViewPort({},rect.size,Menu::menus[parentMenu]->pos+rect.pos); - if(upButton){upButton->Enable(!disabled);} - if(downButton){downButton->Enable(!disabled);} + if(!upButton.expired()){upButton.lock()->Enable(!disabled);} + if(!downButton.expired()){downButton.lock()->Enable(!disabled);} } virtual inline void BeforeUpdate(AiL*game)override{ MenuComponent::BeforeUpdate(game); - for(MenuComponent*component:components){ - component->_BeforeUpdate(game); + for(std::weak_ptrcomponent:components){ + component.lock()->_BeforeUpdate(game); } } virtual inline void Update(AiL*game)override{ @@ -165,17 +145,17 @@ protected: SetScrollAmount({GetScrollAmount().x,0}); } - std::sort(components.begin(),components.end(),[](MenuComponent*c1,MenuComponent*c2){return c1->depth>c2->depth;}); - for(MenuComponent*component:components){ - component->disabled=!OnScreen(component); - component->_Update(game); + std::sort(components.begin(),components.end(),[](std::weak_ptrc1,std::weak_ptrc2){return c1.lock()->depth>c2.lock()->depth;}); + for(std::weak_ptrcomponent:components){ + component.lock()->disabled=!OnScreen(component.lock()); + component.lock()->_Update(game); } - upButton->disabled=false; - downButton->disabled=false; + upButton.lock()->disabled=false; + downButton.lock()->disabled=false; if(geom2d::contains(rect,bounds)){//This means we have no reason to show a scrollbar. - upButton->disabled=true; - downButton->disabled=true; + upButton.lock()->disabled=true; + downButton.lock()->disabled=true; } } inline void DrawScrollbar(ViewPort&window,vf2d parentPos,bool focused){ @@ -198,8 +178,8 @@ protected: if(border){ window.DrawRectDecal(rect.pos,rect.size); } - for(MenuComponent*component:components){ - component->_DrawDecal(subWindow,focused); + for(std::weak_ptrcomponent:components){ + component.lock()->_DrawDecal(subWindow,focused); } if(!geom2d::contains(rect,bounds)){ DrawScrollbar(window,{},focused); @@ -212,33 +192,33 @@ protected: //Calculates the bounds of all components. inline void CalculateBounds(){ bounds={}; - for(MenuComponent*component:components){ - if(component->rect.pos.xrect.pos.x; + for(std::weak_ptrcomponent:components){ + if(component.lock()->rect.pos.xrect.pos.x; bounds.size.x+=sizeIncrease; - bounds.pos.x=component->rect.pos.x; + bounds.pos.x=component.lock()->rect.pos.x; } - if(component->rect.right().start.x>bounds.right().start.x){ - float sizeIncrease=component->rect.right().start.x-bounds.right().start.x; + if(component.lock()->rect.right().start.x>bounds.right().start.x){ + float sizeIncrease=component.lock()->rect.right().start.x-bounds.right().start.x; bounds.size.x+=sizeIncrease; } - if(component->rect.pos.yrect.pos.y; + if(component.lock()->rect.pos.yrect.pos.y; bounds.size.y+=sizeIncrease; - bounds.pos.y=component->rect.pos.y; + bounds.pos.y=component.lock()->rect.pos.y; } - if(component->rect.bottom().start.y>bounds.bottom().start.y){ - float sizeIncrease=component->rect.bottom().start.y-bounds.bottom().start.y; + if(component.lock()->rect.bottom().start.y>bounds.bottom().start.y){ + float sizeIncrease=component.lock()->rect.bottom().start.y-bounds.bottom().start.y; bounds.size.y+=sizeIncrease; } } } public: template - T* _AddComponent(std::string key,T*button){ + std::shared_ptr _AddComponent(std::string key,std::shared_ptrbutton){ components.push_back(button); button->renderInMain=false; //Now we are in control! - button->parentComponent=this; + button->parentComponent=shared_from_this(); button->disabled=disabled; CalculateBounds(); @@ -252,21 +232,21 @@ public: virtual inline bool PointWithinParent(MenuComponent*child,geom2d::rect drawRect)override{ return geom2d::overlaps(geom2d::rect{Menu::menus[parentMenu]->pos+rect.pos,rect.size},drawRect); } - virtual inline bool HandleOutsideDisabledButtonSelection(MenuComponent*disabledButton)override{ + virtual inline bool HandleOutsideDisabledButtonSelection(std::weak_ptrdisabledButton)override{ //Set the offset so the center is highlighted by this button. - SetScrollAmount(vf2d{GetScrollAmount().x,-disabledButton->rect.pos.y+disabledButton->rect.size.y}); + SetScrollAmount(vf2d{GetScrollAmount().x,-disabledButton.lock()->rect.pos.y+disabledButton.lock()->rect.size.y}); return true; }; virtual void Cleanup()override{} - inline std::vector&GetComponents(){ + inline std::vector>&GetComponents(){ return components; } virtual inline void Enable(bool enabled)override final{ disabled=!enabled; - for(MenuComponent*component:components){ - component->Enable(enabled); + for(std::weak_ptrcomponent:components){ + component.lock()->Enable(enabled); } - if(upButton){upButton->Enable(enabled);} - if(downButton){downButton->Enable(enabled);} + if(upButton.lock()){upButton.lock()->Enable(enabled);} + if(downButton.lock()){downButton.lock()->Enable(enabled);} }; }; \ No newline at end of file diff --git a/Adventures in Lestoria/SellItemWindow.cpp b/Adventures in Lestoria/SellItemWindow.cpp index 1e768cdc..cc9a2888 100644 --- a/Adventures in Lestoria/SellItemWindow.cpp +++ b/Adventures in Lestoria/SellItemWindow.cpp @@ -62,34 +62,34 @@ void Menu::InitializeSellItemWindow(){ Component(SELL_ITEM,"Sell Button")->SetGrayedOut(!canSell); }; - sellItemWindow->ADD("Item Sell Header",ItemMenuLabel)({{2,2},{188,12}},"Selling {}",Item::BLANK,1,ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND|ComponentAttr::SHADOW|ComponentAttr::FIT_TO_LABEL)END; + sellItemWindow->ADD("Item Sell Header",ItemMenuLabel)(geom2d::rect{{2,2},{188,12}},"Selling {}",Item::BLANK,1,ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND|ComponentAttr::SHADOW|ComponentAttr::FIT_TO_LABEL)END; - sellItemWindow->ADD("Price Per Item Label",MenuLabel)({{4,18},{188,12}},"Price Per Item",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; - sellItemWindow->ADD("Amount to Sell Label",MenuLabel)({{4,34},{188,12}},"Amount to Sell",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; - sellItemWindow->ADD("Price Label",MenuLabel)({{4,50},{188,12}},"Total Price",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; + sellItemWindow->ADD("Price Per Item Label",MenuLabel)(geom2d::rect{{4,18},{188,12}},"Price Per Item",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; + sellItemWindow->ADD("Amount to Sell Label",MenuLabel)(geom2d::rect{{4,34},{188,12}},"Amount to Sell",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; + sellItemWindow->ADD("Price Label",MenuLabel)(geom2d::rect{{4,50},{188,12}},"Total Price",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END; - sellItemWindow->ADD("Price per item Amount Label",MenuLabel)({{sellItemWindow->size.x/2+28,18},{72,12}},"0",1.0f,ComponentAttr::SHADOW|ComponentAttr::FIT_TO_LABEL)END; - sellItemWindow->ADD("Amount to sell Amount Label",MenuLabel)({{sellItemWindow->size.x/2+48,34},{32,12}},"0",1.0f,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::FIT_TO_LABEL)END; + sellItemWindow->ADD("Price per item Amount Label",MenuLabel)(geom2d::rect{{sellItemWindow->size.x/2+28,18},{72,12}},"0",1.0f,ComponentAttr::SHADOW|ComponentAttr::FIT_TO_LABEL)END; + sellItemWindow->ADD("Amount to sell Amount Label",MenuLabel)(geom2d::rect{{sellItemWindow->size.x/2+48,34},{32,12}},"0",1.0f,ComponentAttr::SHADOW|ComponentAttr::OUTLINE|ComponentAttr::FIT_TO_LABEL)END; - sellItemWindow->ADD("Increase sell amount Button",MenuComponent)({{sellItemWindow->size.x/2+80+2,34},{12,12}},"+",[&](MenuFuncData data){ + sellItemWindow->ADD("Increase sell amount Button",MenuComponent)(geom2d::rect{{sellItemWindow->size.x/2+80+2,34},{12,12}},"+",[&](MenuFuncData data){ UpdateMenu(GetQuantity()+1); return true; })END; - sellItemWindow->ADD("Decrease sell amount Button",MenuComponent)({{sellItemWindow->size.x/2+48-14,34},{12,12}},"-",[](MenuFuncData data){ + sellItemWindow->ADD("Decrease sell amount Button",MenuComponent)(geom2d::rect{{sellItemWindow->size.x/2+48-14,34},{12,12}},"-",[](MenuFuncData data){ UpdateMenu(GetQuantity()-1); return true; })END; - sellItemWindow->ADD("Total Price Amount Label",MenuLabel)({{sellItemWindow->size.x/2+28,50},{72,12}},"0",1.0f,ComponentAttr::SHADOW|ComponentAttr::FIT_TO_LABEL)END; + sellItemWindow->ADD("Total Price Amount Label",MenuLabel)(geom2d::rect{{sellItemWindow->size.x/2+28,50},{72,12}},"0",1.0f,ComponentAttr::SHADOW|ComponentAttr::FIT_TO_LABEL)END; - sellItemWindow->ADD("Sell Button",MenuComponent)({{sellItemWindow->size.x/2+18,70},{64,12}},"Sell",[&](MenuFuncData data){ + sellItemWindow->ADD("Sell Button",MenuComponent)(geom2d::rect{{sellItemWindow->size.x/2+18,70},{64,12}},"Sell",[&](MenuFuncData data){ Merchant&merchant=Merchant::GetCurrentTravelingMerchant(); merchant.SellItem(Component(SELL_ITEM,"Item Sell Header")->GetItem(),GetQuantity()); SoundEffect::PlaySFX("Sell Item",SoundEffect::CENTERED); Menu::CloseMenu(); return true; })END; - sellItemWindow->ADD("Cancel Button",MenuComponent)({{sellItemWindow->size.x/2-82,70},{64,12}},"Cancel",[](MenuFuncData data){ + sellItemWindow->ADD("Cancel Button",MenuComponent)(geom2d::rect{{sellItemWindow->size.x/2-82,70},{64,12}},"Cancel",[](MenuFuncData data){ Menu::CloseMenu(); return true; })END; diff --git a/Adventures in Lestoria/TODO.txt b/Adventures in Lestoria/TODO.txt index 66385e0f..bc699c08 100644 --- a/Adventures in Lestoria/TODO.txt +++ b/Adventures in Lestoria/TODO.txt @@ -1,5 +1,6 @@ January 1st =========== +Fix Listeners so they do not leak! (Add a proper listener class and have all listeners inherit from it.) The Hub / NPC Interactions Settings Menu - Any settings should be saved to the save file! diff --git a/Adventures in Lestoria/Toggleable.h b/Adventures in Lestoria/Toggleable.h index aec2648d..3aefdcbe 100644 --- a/Adventures in Lestoria/Toggleable.h +++ b/Adventures in Lestoria/Toggleable.h @@ -37,15 +37,15 @@ All rights reserved. #pragma endregion #pragma once -class IToggleable{ +class IToggleable:public std::enable_shared_from_this{ friend class AiL; public: - inline std::vectorGetToggleGroup(){ + inline std::vector>GetToggleGroup(){ return toggleGroup; } inline void Select(){ - for(IToggleable*item:toggleGroup){ - item->selected=false; + for(std::weak_ptritem:toggleGroup){ + item.lock()->selected=false; } selected=true; } @@ -57,14 +57,14 @@ public: ERR("WARNING! Toggle group for this component was set twice for some reason! THIS SHOULD NOT BE HAPPENING!") } toggleGroupInitialized=true; - std::erase_if(uninitializedToggleGroupItems,[&](IToggleable*item){return this==item;}); + std::erase_if(uninitializedToggleGroupItems,[&](std::weak_ptritem){return this==&*item.lock();}); } - inline void SetToggleGroup(std::vectortoggleGroup){ + inline void SetToggleGroup(std::vector>toggleGroup){ this->toggleGroup=toggleGroup; SetToggleGroup(); } inline IToggleable(){ - uninitializedToggleGroupItems.push_back(this); + uninitializedToggleGroupItems.push_back(shared_from_this()); #ifdef _DEBUG if("debug_toggleable_items"_I){ std::cout<<"\tInitialized Toggle Item Ptr: 0x"<toggleGroup; + std::vector>toggleGroup; private: bool selected=false; bool toggleGroupInitialized=false; - inline static std::vectoruninitializedToggleGroupItems; + inline static std::vector>uninitializedToggleGroupItems; }; \ No newline at end of file diff --git a/Adventures in Lestoria/UserIDMenu.cpp b/Adventures in Lestoria/UserIDMenu.cpp index 7825b4f4..d95e37db 100644 --- a/Adventures in Lestoria/UserIDMenu.cpp +++ b/Adventures in Lestoria/UserIDMenu.cpp @@ -46,15 +46,15 @@ using A=Attribute; void Menu::InitializeUserIDWindow(){ Menu*userIDWindow=CreateMenu(USER_ID,CENTERED,vi2d{168,120}); - userIDWindow->ADD("User ID Creation Explanation",MenuLabel)({{0,-4},{168,92}},"user_id_message"_FS+"\n\n"+"user_id_message2"_FS,1.f,ComponentAttr::SHADOW|ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)END; - userIDWindow->ADD("User ID Input",TextEntryLabel)({{36,94},{96,12}},[](std::string_view newLabel){ + userIDWindow->ADD("User ID Creation Explanation",MenuLabel)(geom2d::rect{{0,-4},{168,92}},"user_id_message"_FS+"\n\n"+"user_id_message2"_FS,1.f,ComponentAttr::SHADOW|ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)END; + userIDWindow->ADD("User ID Input",TextEntryLabel)(geom2d::rect{{36,94},{96,12}},[](std::string_view newLabel){ Component(USER_ID,"Submit Button")->SetGrayedOut(newLabel.length()==0); },true,24U,1.f,ComponentAttr::BACKGROUND|ComponentAttr::FIT_TO_LABEL|ComponentAttr::OUTLINE|ComponentAttr::SHADOW)END; - userIDWindow->ADD("Back Button",MenuComponent)({{18,110},{48,12}},"Back",[](MenuFuncData data){ + userIDWindow->ADD("Back Button",MenuComponent)(geom2d::rect{{18,110},{48,12}},"Back",[](MenuFuncData data){ Menu::CloseMenu(); return true; })END; - userIDWindow->ADD("Submit Button",MenuComponent)({{102,110},{48,12}},"Submit",[](MenuFuncData data){ + userIDWindow->ADD("Submit Button",MenuComponent)(geom2d::rect{{102,110},{48,12}},"Submit",[](MenuFuncData data){ SaveFile::SetUserID(Component(USER_ID,"User ID Input")->GetLabel()); if(Menu::menus[MAIN_MENU]->S(A::NEXT_MENU)=="New Game"){ Menu::CloseMenu(); diff --git a/Adventures in Lestoria/Version.h b/Adventures in Lestoria/Version.h index 5efbaa46..caedf674 100644 --- a/Adventures in Lestoria/Version.h +++ b/Adventures in Lestoria/Version.h @@ -39,7 +39,7 @@ All rights reserved. #define VERSION_MAJOR 0 #define VERSION_MINOR 2 #define VERSION_PATCH 1 -#define VERSION_BUILD 5870 +#define VERSION_BUILD 5929 #define stringify(a) stringify_(a) #define stringify_(a) #a