diff --git a/Crawler/CharacterMenuWindow.cpp b/Crawler/CharacterMenuWindow.cpp index 9daac4e4..63c40239 100644 --- a/Crawler/CharacterMenuWindow.cpp +++ b/Crawler/CharacterMenuWindow.cpp @@ -121,20 +121,20 @@ void Menu::InitializeCharacterMenuWindow(){ [&](MenuFuncData data){ EquipSlot slot=EquipSlot(data.component->I(Attribute::EQUIP_TYPE)); - std::vector&equips=Inventory::get("Equipment"); - std::vector&accessories=Inventory::get("Accessories"); - std::vectoravailableEquipment; - std::copy_if(equips.begin(),equips.end(),std::back_inserter(availableEquipment),[&](Item&it){ - return it.GetEquipSlot()&slot; + std::vector>&equips=Inventory::get("Equipment"); + std::vector>&accessories=Inventory::get("Accessories"); + std::vector>availableEquipment; + std::copy_if(equips.begin(),equips.end(),std::back_inserter(availableEquipment),[&](std::shared_ptrit){ + return it->GetEquipSlot()&slot; }); - std::copy_if(accessories.begin(),accessories.end(),std::back_inserter(availableEquipment),[&](Item&it){ - return it.GetEquipSlot()&slot; + std::copy_if(accessories.begin(),accessories.end(),std::back_inserter(availableEquipment),[&](std::shared_ptrit){ + return it->GetEquipSlot()&slot; }); ScrollableWindowComponent*equipList=Component(data.component->parentMenu,"Equip List"); equipList->RemoveAllComponents(); - for(int counter=0;Item&it:availableEquipment){ - Item&itemInvRef=Inventory::GetItem(it.ActualName()); + for(int counter=0;const std::shared_ptrit:availableEquipment){ + std::weak_ptritemInvRef=Inventory::GetItem(it->ActualName()); auto equip=equipList->ADD("Equip Item "+std::to_string(counter),RowItemDisplay)({{2,2+counter*29.f},{120-15,28}},itemInvRef, [](MenuFuncData data){ RowItemDisplay*comp=dynamic_cast(data.component); @@ -165,13 +165,13 @@ void Menu::InitializeCharacterMenuWindow(){ [&](MenuFuncData data){ RowItemDisplay*button=dynamic_cast(data.component); if(button!=nullptr){ - const Item&buttonItem=button->GetItem(); + const std::weak_ptrbuttonItem=button->GetItem(); std::vectorstatsBeforeEquip; EquipSlot slot=EquipSlot(button->I(Attribute::EQUIP_TYPE)); for(ItemAttribute attribute:displayAttrs){ statsBeforeEquip.push_back(game->GetPlayer()->GetStat(attribute)); } - Item*equippedItem=Inventory::GetEquip(slot); + std::weak_ptrequippedItem=Inventory::GetEquip(slot); Inventory::EquipItem(buttonItem,slot); for(int counter=0;ItemAttribute attribute:displayAttrs){ StatLabel*statDisplayLabel=Component(CHARACTER_MENU,"Attribute "+ItemAttributable::GetDisplayInfo(attribute).name+" Label"); @@ -180,8 +180,8 @@ void Menu::InitializeCharacterMenuWindow(){ counter++; } Inventory::UnequipItem(slot); - if(*equippedItem!=Item::BLANK){ - Inventory::EquipItem(*equippedItem,slot); + if(!ISBLANK(equippedItem)){ + Inventory::EquipItem(equippedItem,slot); } }else{ ERR("WARNING! Attempting to cast a button that isn't a RowItemDisplay!"); @@ -202,7 +202,7 @@ void Menu::InitializeCharacterMenuWindow(){ equip->SetSelectionType(SelectionType::NONE); equip->I(Attribute::EQUIP_TYPE)=int(slot); - if(Inventory::GetEquip(slot)==&itemInvRef){ + if(Inventory::GetEquip(slot)==itemInvRef){ equip->SetSelected(true); } equip->SetCompactDescriptions(false); diff --git a/Crawler/Crawler.cpp b/Crawler/Crawler.cpp index 1e621a3b..27bbcb0a 100644 --- a/Crawler/Crawler.cpp +++ b/Crawler/Crawler.cpp @@ -1242,7 +1242,7 @@ void Crawler::RenderHud(){ if("debug_player_info"_I){ DrawShadowStringDecal({0,128},player->GetPos().str()); DrawShadowStringDecal({0,136},"Spd: "+std::to_string(player->GetMoveSpdMult())); - DrawShadowStringDecal({0,92},"Loadout Slot 1 Qty: "+std::to_string(GetLoadoutItem(0).Amt())); + 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)); }} @@ -1303,16 +1303,19 @@ void Crawler::RenderCooldowns(){ } if(loadoutSlot!=-1){ - uint32_t itemAmt=GetLoadoutItem(loadoutSlot).Amt(); - if(itemAmt>0){ - std::string amtString="x"+std::to_string(itemAmt); - vf2d qtySize=vf2d{GetTextSize(amtString)}*vf2d{0.5f,0.75f}; - DrawShadowStringDecal(pos+vf2d{20,20}-qtySize/2,amtString,WHITE,BLACK,{0.5f,0.75f}); - }else{ - DrawDecal(pos,GFX["square_skill_overlay_icon_empty.png"].Decal(),{1,1},DARK_RED); - shortNameCol=RED; - manaCostShadowCol=DARK_RED; - keyDisplayCol=RED; + const std::weak_ptrloadoutItem=GetLoadoutItem(loadoutSlot); + if(!loadoutItem.expired()&&loadoutItem.lock()->it!=nullptr){ + uint32_t itemAmt=loadoutItem.lock()->Amt(); + if(itemAmt>0){ + std::string amtString="x"+std::to_string(itemAmt); + vf2d qtySize=vf2d{GetTextSize(amtString)}*vf2d{0.5f,0.75f}; + DrawShadowStringDecal(pos+vf2d{20,20}-qtySize/2,amtString,WHITE,BLACK,{0.5f,0.75f}); + }else{ + DrawDecal(pos,GFX["square_skill_overlay_icon_empty.png"].Decal(),{1,1},DARK_RED); + shortNameCol=RED; + manaCostShadowCol=DARK_RED; + keyDisplayCol=RED; + } } } @@ -2210,7 +2213,7 @@ void Crawler::SetChapter(int chapter){ this->chapter=chapter; } -Item&Crawler::GetLoadoutItem(int slot){ +const std::weak_ptrCrawler::GetLoadoutItem(int slot){ if(slot<0||slot>loadout.size()-1)ERR("Invalid inventory slot "+std::to_string(slot)+", please choose a slot in range (0-"+std::to_string(loadout.size()-1)+")."); return loadout[slot]; } @@ -2218,8 +2221,8 @@ Item&Crawler::GetLoadoutItem(int slot){ void Crawler::SetLoadoutItem(int slot,std::string itemName){ if(slot<0||slot>loadout.size()-1)ERR("Invalid inventory slot "+std::to_string(slot)+", please choose a slot in range (0-"+std::to_string(loadout.size()-1)+")."); if(Inventory::GetItemCount(itemName)>0){ - GetLoadoutItem(slot)=Inventory::CopyItem(itemName); - GetLoadoutItem(slot).amt=std::min((uint32_t)"Player.Item Loadout Limit"_I,GetLoadoutItem(slot).Amt()); //We are only allowed to have up to 10 maximum of an item on a journey. + loadout[slot]=Inventory::CopyItem(itemName); + GetLoadoutItem(slot).lock()->amt=std::min((uint32_t)"Player.Item Loadout Limit"_I,GetLoadoutItem(slot).lock()->Amt()); //We are only allowed to have up to 10 maximum of an item on a journey. InputGroup*inputGroup=nullptr; switch(slot){ case 0:{ @@ -2232,16 +2235,15 @@ void Crawler::SetLoadoutItem(int slot,std::string itemName){ inputGroup=&Player::KEY_ITEM3; }break; } - Ability itemAbility{itemName,"","","Item.Item Cooldown Time"_F,0,inputGroup,"items/"+itemName+".png",VERY_DARK_RED,DARK_RED,PrecastData{GetLoadoutItem(slot).CastTime(),0,0},true}; + Ability itemAbility{itemName,"","","Item.Item Cooldown Time"_F,0,inputGroup,"items/"+itemName+".png",VERY_DARK_RED,DARK_RED,PrecastData{GetLoadoutItem(slot).lock()->CastTime(),0,0},true}; switch(slot){ case 0:{ itemAbility.action=[&](Player*p,vf2d pos={}){ - bool itemUsed=game->UseLoadoutItem(0); - - return itemUsed; + return game->UseLoadoutItem(0); }; game->GetPlayer()->SetItem1UseFunc(itemAbility); + Component(MenuType::ITEM_LOADOUT,"Loadout Item 1")->SetItem(loadout[slot]); Component(MenuType::ITEM_LOADOUT,"Loadout Item 1")->UpdateIcon(); }break; case 1:{ @@ -2249,6 +2251,7 @@ void Crawler::SetLoadoutItem(int slot,std::string itemName){ return game->UseLoadoutItem(1); }; game->GetPlayer()->SetItem2UseFunc(itemAbility); + Component(MenuType::ITEM_LOADOUT,"Loadout Item 2")->SetItem(loadout[slot]); Component(MenuType::ITEM_LOADOUT,"Loadout Item 2")->UpdateIcon(); }break; case 2:{ @@ -2256,6 +2259,7 @@ void Crawler::SetLoadoutItem(int slot,std::string itemName){ return game->UseLoadoutItem(2); }; game->GetPlayer()->SetItem3UseFunc(itemAbility); + Component(MenuType::ITEM_LOADOUT,"Loadout Item 3")->SetItem(loadout[slot]); Component(MenuType::ITEM_LOADOUT,"Loadout Item 3")->UpdateIcon(); }break; } @@ -2267,9 +2271,9 @@ void Crawler::SetLoadoutItem(int slot,std::string itemName){ bool Crawler::UseLoadoutItem(int slot){ if(slot<0||slot>loadout.size()-1)ERR("Invalid inventory slot "+std::to_string(slot)+", please choose a slot in range (0-"+std::to_string(loadout.size()-1)+")."); - if(GetLoadoutItem(slot).Amt()>0){ - Inventory::UseItem(GetLoadoutItem(slot).ActualName()); - GetLoadoutItem(slot).amt--; + if(GetLoadoutItem(slot).lock()->Amt()>0){ + Inventory::UseItem(GetLoadoutItem(slot).lock()->ActualName()); + GetLoadoutItem(slot).lock()->amt--; return true; } return false; @@ -2277,7 +2281,7 @@ bool Crawler::UseLoadoutItem(int slot){ void Crawler::ClearLoadoutItem(int slot){ if(slot<0||slot>loadout.size()-1)ERR("Invalid inventory slot "+std::to_string(slot)+", please choose a slot in range (0-"+std::to_string(loadout.size()-1)+")."); - loadout[slot].it=nullptr; + loadout[slot].reset(); InputGroup*inputGroup=nullptr; switch(slot){ case 0:{ @@ -2294,18 +2298,17 @@ void Crawler::ClearLoadoutItem(int slot){ switch(slot){ case 0:{ itemAbility.action=[&](Player*p,vf2d pos={}){ - bool itemUsed=game->UseLoadoutItem(0); - - return itemUsed; + return game->UseLoadoutItem(0); }; game->GetPlayer()->SetItem1UseFunc(itemAbility); + Component(MenuType::ITEM_LOADOUT,"Loadout Item 1")->SetItem(Item::BLANK); Component(MenuType::ITEM_LOADOUT,"Loadout Item 1")->UpdateIcon(); }break; case 1:{ itemAbility.action=[&](Player*p,vf2d pos={}){ return game->UseLoadoutItem(1); }; - game->GetPlayer()->SetItem2UseFunc(itemAbility); + Component(MenuType::ITEM_LOADOUT,"Loadout Item 2")->SetItem(Item::BLANK); Component(MenuType::ITEM_LOADOUT,"Loadout Item 2")->UpdateIcon(); }break; case 2:{ @@ -2313,6 +2316,7 @@ void Crawler::ClearLoadoutItem(int slot){ return game->UseLoadoutItem(2); }; game->GetPlayer()->SetItem3UseFunc(itemAbility); + Component(MenuType::ITEM_LOADOUT,"Loadout Item 3")->SetItem(Item::BLANK); Component(MenuType::ITEM_LOADOUT,"Loadout Item 3")->UpdateIcon(); }break; } diff --git a/Crawler/Crawler.h b/Crawler/Crawler.h index 2e10b659..9f259f96 100644 --- a/Crawler/Crawler.h +++ b/Crawler/Crawler.h @@ -106,7 +106,7 @@ private: bool encounterStarted=false; int totalBossEncounterMobs=0; int chapter=1; //We start at chapter 1. - std::arrayloadout; + std::array,3>loadout; float fadeOutDuration=0; float fadeOutTotalTime=0; float fadeInDuration=0; @@ -195,7 +195,7 @@ public: MapTag GetCurrentMap(); int GetCurrentChapter(); void SetChapter(int chapter); - Item&GetLoadoutItem(int slot); + const std::weak_ptrGetLoadoutItem(int slot); void SetLoadoutItem(int slot,std::string itemName); //Returns true if the item can be used (we have >0 of it) bool UseLoadoutItem(int slot); diff --git a/Crawler/EquipSlotButton.h b/Crawler/EquipSlotButton.h index 52a66bcd..c65d8563 100644 --- a/Crawler/EquipSlotButton.h +++ b/Crawler/EquipSlotButton.h @@ -50,9 +50,9 @@ public: inline EquipSlotButton(geom2d::rectrect,EquipSlot slot,MenuType menuDest,MenuFunc onClick,MenuFunc onHover,MenuFunc onMouseOut,std::string itemNameLabelName="",std::string itemDescriptionLabelName="") :MenuItemItemButton(rect,Item::BLANK,menuDest,onClick,onHover,onMouseOut,itemNameLabelName,itemDescriptionLabelName),slot(slot){} inline void OnEquipStatsUpdate()override{ - Item&equip=*Inventory::GetEquip(slot); - if(!equip.IsBlank()){ - icon=const_cast(equip.Decal()); + const std::weak_ptrequip=Inventory::GetEquip(slot); + if(!ISBLANK(equip)){ + icon=const_cast(equip.lock()->Decal()); SetItem(equip); }else{ icon=nullptr; diff --git a/Crawler/InventoryConsumableWindow.cpp b/Crawler/InventoryConsumableWindow.cpp index 7f56edd5..2432d10b 100644 --- a/Crawler/InventoryConsumableWindow.cpp +++ b/Crawler/InventoryConsumableWindow.cpp @@ -75,7 +75,7 @@ void Menu::InitializeConsumableInventoryWindow(){ } } button->selected=data.menu.I(A::LOADOUT_SLOT); - data.game->SetLoadoutItem(button->selected,button->GetItem().ActualName()); + data.game->SetLoadoutItem(button->selected,button->GetItem().lock()->ActualName()); return true; })END; Menu::AddInventoryListener(consumableWindow,"Consumables"); diff --git a/Crawler/InventoryScrollableWindowComponent.h b/Crawler/InventoryScrollableWindowComponent.h index 356765e8..93288265 100644 --- a/Crawler/InventoryScrollableWindowComponent.h +++ b/Crawler/InventoryScrollableWindowComponent.h @@ -110,9 +110,10 @@ protected: for(int j=i;jparentMenu]->components.at(components[j]->name)=components[size_t(j+1)]; - components[j]=components[size_t(j+1)]; + std::swap(components[j]->inventoryIndex,components[size_t(j+1)]->inventoryIndex); + std::swap(components[j],components[size_t(j+1)]); } - MenuComponent*lastButton=Menu::menus[components[components.size()-1]->parentMenu]->components.at(components[components.size()-1]->name); + MenuComponent*lastButton=components[components.size()-1]; //Now we have to fix up the keyboard button list. RemoveButton(lastButton); i--; //Subtract one from the index so we don't accidently skip slots. diff --git a/Crawler/Item.cpp b/Crawler/Item.cpp index a549edc8..4b9f5fdb 100644 --- a/Crawler/Item.cpp +++ b/Crawler/Item.cpp @@ -49,20 +49,21 @@ INCLUDE_GFX safemapITEM_DATA; safemapITEM_SCRIPTS; safemap>ITEM_CATEGORIES; -Item Item::BLANK; -std::mapInventory::_inventory; -std::map>Inventory::sortedInv; +std::shared_ptrItem::BLANK=std::make_shared(); +std::map>Inventory::_inventory; +std::map>>Inventory::sortedInv; std::vectorItemOverlay::items; std::mapItemSet::sets; -std::mapInventory::equipment; +std::map>Inventory::equipment; std::mapItemInfo::nameToEquipSlot; +int Item::IsBlankStaticCallCounter=0; ItemInfo::ItemInfo() :customProps({nullptr,nullptr}),img(nullptr){} void ItemInfo::InitializeItems(){ for(int i=int(EquipSlot::HELMET);i<=int(EquipSlot::RING2);i<<=1){ - Inventory::equipment[EquipSlot(i)]=&Item::BLANK; + Inventory::equipment[EquipSlot(i)]=Item::BLANK; } nameToEquipSlot["Helmet"]=EquipSlot::HELMET; @@ -251,20 +252,20 @@ void Inventory::AddItem(IT it,uint32_t amt,bool monsterDrop){ if(!ITEM_DATA.count(it))ERR("Item "<(amt,it); InsertIntoSortedInv(it); }else{ - _inventory.at(it).amt+=amt; + _inventory.at(it)->amt+=amt; } InsertIntoStageInventoryCategory(it,amt,monsterDrop); } -Item Inventory::CopyItem(IT it){ - if(!_inventory.count(it))return Item::BLANK; - return _inventory.at(it); +std::shared_ptrInventory::CopyItem(IT it){ + if(!_inventory.count(it))return std::make_shared(*Item::BLANK); + return std::make_shared(*_inventory.at(it)); } -Item&Inventory::GetItem(IT it){ +std::weak_ptrInventory::GetItem(IT it){ if(!_inventory.count(it))return Item::BLANK; return _inventory.at(it); } @@ -273,7 +274,7 @@ uint32_t Inventory::GetItemCount(IT it){ if(!_inventory.count(it)){ return 0; }else{ - return _inventory.at(it).Amt(); + return _inventory.at(it)->Amt(); } } @@ -292,7 +293,7 @@ bool Inventory::UseItem(IT it,uint32_t amt){ //Returns true if the item has been consumed completely and there are 0 remaining of that type in our inventory. bool Inventory::RemoveItem(IT it,ITCategory inventory,uint32_t amt){ #pragma region Calculate Inventory to Manipulate - std::vector&inv=sortedInv.at(inventory); + std::vector>&inv=sortedInv.at(inventory); bool eraseFromLootWindow=false; if(inventory=="Monster Loot") { inv=sortedInv.at("Monster Loot"); @@ -303,7 +304,7 @@ bool Inventory::RemoveItem(IT it,ITCategory inventory,uint32_t amt){ eraseFromLootWindow=true; } int count=0; - for(Item&item:inv){ + for(std::shared_ptritem:inv){ if(item==it)break; count++; } @@ -311,27 +312,26 @@ bool Inventory::RemoveItem(IT it,ITCategory inventory,uint32_t amt){ uint32_t itemAmt=GetItemCount(it); if(inventory=="Monster Loot"||inventory=="Stage Loot"){ - itemAmt=inv.at(count).Amt(); + itemAmt=inv.at(count)->Amt(); } //There are two places to manipulate items in (Both the sorted inventory and the actual inventory) if (!itemAmt)return false; if (amt>=itemAmt){ - - if(!eraseFromLootWindow){ + inv.erase(inv.begin()+count); //Clears it from the detected sorted inventory as well! + if(!eraseFromLootWindow){ //We must clear out the item AFTER we've updated context-sensitive inventories because they may be borrowing a ref from this structure!!! _inventory.erase(it); - }else{ - inv.erase(inv.begin()+count); } + //Callback for GUI inventories. Menu::InventorySlotsUpdated(inventory); return true; }else{ if(!eraseFromLootWindow){ - _inventory.at(it).amt-=amt; + _inventory.at(it)->amt-=amt; }else{ - inv.at(count).amt-=amt; + inv.at(count)->amt-=amt; //Don't touch the sorted inventory unless this is monster loot or stage loot because there's only "1" of this item in the entry list. } return false; } @@ -343,12 +343,12 @@ bool Inventory::RemoveItem(IT it,uint32_t amt){ return RemoveItem(it, cat, amt); } -std::vector&Inventory::get(ITCategory itemCategory){ +std::vector>&Inventory::get(ITCategory itemCategory){ return sortedInv.at(itemCategory); } void Inventory::InsertIntoSortedInv(IT item){ - sortedInv.at(ITEM_DATA[item].category).push_back(Item{1,item}); + sortedInv.at(ITEM_DATA[item].category).push_back(_inventory[item]); //This should be a callback to menus that we need to update the interface with another item slot since a new one has appeared. Menu::InventorySlotsUpdated(ITEM_DATA[item].category); } @@ -358,12 +358,12 @@ void Inventory::InsertIntoStageInventoryCategory(IT item,uint32_t amt,bool monst if(monsterDrop){ stageInventoryCategory="Monster Loot"; } - std::vector&inv=sortedInv.at(stageInventoryCategory); - std::vector::iterator it=std::find(inv.begin(),inv.end(),Item{amt,item}); + std::vector>&inv=sortedInv.at(stageInventoryCategory); + std::vector>::iterator it=std::find(inv.begin(),inv.end(),std::make_shared(amt,item)); if(it!=inv.end()){ - (*it).amt+=amt; + (*it)->amt+=amt; }else{ - inv.push_back(Item{amt,item}); + inv.push_back(std::make_shared(amt,item)); } Menu::InventorySlotsUpdated(stageInventoryCategory); } @@ -377,14 +377,14 @@ bool Inventory::ExecuteAction(IT item){ } bool Inventory::SwapItems(ITCategory itemCategory,uint32_t slot1,uint32_t slot2){ - std::vector&inv=sortedInv.at(itemCategory); + std::vector>&inv=sortedInv.at(itemCategory); int largestSlot=std::max(slot1,slot2); if(inv.size()<=largestSlot){ //The inventory is too small, so expand out blank slots to accomodate. inv.resize(largestSlot+size_t(1)); } - Item&item1=inv.at(slot1); - Item&item2=inv.at(slot2); + std::shared_ptritem1=inv.at(slot1); + std::shared_ptritem2=inv.at(slot2); std::swap(item1,item2); return true; } @@ -393,11 +393,11 @@ uint32_t Item::Amt()const{ return amt; }; const std::string&Item::ActualName()const{ - if(IsBlank())return ""; + if(_IsBlank())return ""; return it->Name(); }; const std::string Item::DisplayName()const{ - if(IsBlank())return ""; + if(_IsBlank())return ""; std::string name=ActualName(); if(IsEquippable()&&EnhancementLevel()>0){ name+=" [+"+std::to_string(EnhancementLevel())+"]"; @@ -465,28 +465,22 @@ const ItemScript&ItemInfo::OnUseAction()const{ }; const bool Item::IsBlank()const{ + if(Item::IsBlankStaticCallCounter!=1)ERR("WARNING! You should not call the IsBlank() function directly! Use ISBLANK() macro instead!") + Item::IsBlankStaticCallCounter--; return amt==0||it==nullptr; } void Inventory::Clear(ITCategory itemCategory){ - std::vectoritemList=get(itemCategory); //We have to make a copy here because RemoveItem() will modify the list provided by get() inline. - for(Item&item:itemList){ - size_t itemQuantity=GetItemCount(item.ActualName());//Normally we want to clear all the items that are actually in our inventory...But... + std::vector>itemList=get(itemCategory); //We have to make a copy here because RemoveItem() will modify the list provided by get() inline. + for(std::shared_ptr&item:itemList){ + size_t itemQuantity=GetItemCount(item->ActualName());//Normally we want to clear all the items that are actually in our inventory...But... if(itemCategory=="Monster Loot"||itemCategory=="Stage Loot"){//These do not affect the actual inventory, we just clear the lists. - itemQuantity=item.Amt(); + itemQuantity=item->Amt(); } - RemoveItem(item.ActualName(),itemCategory,uint32_t(itemQuantity)); + RemoveItem(item->ActualName(),itemCategory,uint32_t(itemQuantity)); } } -const bool Item::operator==(const Item&rhs)const{ - return it==rhs.it; -} - -const bool Item::operator==(const IT&rhs)const{ - return it->Name()==rhs; -} - ItemOverlay::ItemOverlay(ItemInfo item) :it(item),width("ItemDrop.Item Drop Scale"_F*24+4+game->GetTextSizeProp(item.Name()).x*0.5f){ xOffset=-width; @@ -564,28 +558,28 @@ void ItemSet::AddSetBonus(std::string setName,int pieceCount,Stats&bonuses){ sets[setName].setBonusBreakpoints.push_back({pieceCount,bonuses}); } -void Inventory::EquipItem(const Item&it,EquipSlot slot){ - if(!(it.it->slot&slot))return; +void Inventory::EquipItem(const std::weak_ptrit,EquipSlot slot){ + if(!(it.lock()->it->slot&slot))return; EquipSlot equippedSlot=GetSlotEquippedIn(it); if(equippedSlot!=EquipSlot::NONE)UnequipItem(equippedSlot); - if(GetEquip(slot)!=nullptr)UnequipItem(slot); - Inventory::equipment[slot]=const_cast(&it); + if(!GetEquip(slot).expired())UnequipItem(slot); + Inventory::equipment[slot]=it; PlayerStats::RecalculateEquipStats(); }; void Inventory::UnequipItem(EquipSlot slot){ - Inventory::equipment[slot]=&Item::BLANK; + Inventory::equipment[slot]=Item::BLANK; PlayerStats::RecalculateEquipStats(); }; -EquipSlot Inventory::GetSlotEquippedIn(const Item&it){ +EquipSlot Inventory::GetSlotEquippedIn(const std::weak_ptrit){ for(int i=int(EquipSlot::HELMET);i<=int(EquipSlot::RING2);i<<=1){ EquipSlot slot=EquipSlot(i); - Item*equip=GetEquip(slot); - if(equip==nullptr)continue; - if(equip->ActualName()==it.ActualName())return slot; + std::weak_ptrequip=GetEquip(slot); + if(equip.expired())continue; + if(equip.lock()->ActualName()==it.lock()->ActualName())return slot; } return EquipSlot::NONE; }; -Item*Inventory::GetEquip(EquipSlot slot){ +std::weak_ptrInventory::GetEquip(EquipSlot slot){ return Inventory::equipment[slot]; } const EquipSlot Item::GetEquipSlot()const{ @@ -657,10 +651,10 @@ const std::mapInventory::GetEquippedItemSets(){ std::mapsetCounts; for(int i=int(EquipSlot::HELMET);i<=int(EquipSlot::RING2);i<<=1){ EquipSlot slot=EquipSlot(i); - Item*equip=Inventory::GetEquip(slot); - if(equip->IsBlank())continue; - if(equip->ItemSet()){ - setCounts[*equip->ItemSet().value()]++; + std::weak_ptrequip=Inventory::GetEquip(slot); + if(ISBLANK(equip))continue; + if(equip.lock()->ItemSet()){ + setCounts[*equip.lock()->ItemSet().value()]++; } } return setCounts; @@ -713,11 +707,24 @@ const bool Item::CanBePurchased()const{ return it->CanBePurchased(); } - void Item::SetAmt(uint32_t newAmt){ amt=newAmt; } -const Item&Inventory::GetInventorySlot(ITCategory itemCategory,size_t slot){ - return GetItem(get(itemCategory)[slot].ActualName()); -} \ No newline at end of file +const std::weak_ptrInventory::GetInventorySlot(ITCategory itemCategory,size_t slot){ + return GetItem(get(itemCategory).at(slot)->ActualName()); +} + +bool Item::IsBlank(std::shared_ptritem){ + Item::IsBlankStaticCallCounter++; + return item->IsBlank(); +}; +bool Item::IsBlank(std::weak_ptritem){ + if(!item.expired())Item::IsBlankStaticCallCounter++;else return true; + return item.lock()->IsBlank(); +}; + +const bool Item::_IsBlank()const{ + Item::IsBlankStaticCallCounter++; + return IsBlank(); +}; \ No newline at end of file diff --git a/Crawler/Item.h b/Crawler/Item.h index ae7a833c..4b2ecbd2 100644 --- a/Crawler/Item.h +++ b/Crawler/Item.h @@ -138,6 +138,8 @@ private: uint8_t enhancementLevel; ItemInfo*it; void SetAmt(uint32_t newAmt); + static int IsBlankStaticCallCounter; + const bool _IsBlank()const; public: Item(); Item(uint32_t amt,IT item,uint8_t enhancementLevel=0); @@ -154,18 +156,27 @@ public: const ItemScript&OnUseAction()const; const float CastTime()const; const float CooldownTime()const; + //Use ISBLANK macro instead!! This should not be called directly!! const bool IsBlank()const; const uint8_t EnhancementLevel()const; void EnhanceItem(); - static Item BLANK; - const bool operator==(const Item&rhs)const; - const bool operator==(const IT&rhs)const; + static std::shared_ptrBLANK; const std::optionalItemSet()const; const bool IsEquippable()const; const uint32_t BuyValue()const; const uint32_t SellValue()const; const bool CanBeSold()const; const bool CanBePurchased()const; + //Use ISBLANK macro instead!! This should not be called directly!! + static bool IsBlank(std::shared_ptritem); + //Use ISBLANK macro instead!! This should not be called directly!! + static bool IsBlank(std::weak_ptritem); + friend const bool operator==(std::shared_ptrlhs,std::shared_ptrrhs){return lhs->it==rhs->it;}; + friend const bool operator==(std::shared_ptrlhs,const IT&rhs){return lhs->ActualName()==rhs;}; + friend const bool operator==(std::weak_ptrlhs,std::weak_ptrrhs){return !lhs.expired()&&!rhs.expired()&&lhs.lock()->it==rhs.lock()->it;}; + friend const bool operator==(std::weak_ptrlhs,const IT&rhs){return !lhs.expired()&&lhs.lock()->ActualName()==rhs;}; + friend const bool operator==(const IT&lhs,std::weak_ptrrhs){return operator==(rhs,lhs);}; + friend const bool operator==(const IT&lhs,std::shared_ptrrhs){return operator==(rhs,lhs);}; }; class Inventory{ @@ -175,19 +186,19 @@ public: static void AddItem(IT it,uint32_t amt=1,bool monsterDrop=false); //Returns the actual amount available in your main inventory. static uint32_t GetItemCount(IT it); - static Item CopyItem(IT it); - static Item&GetItem(IT it); + static std::shared_ptrCopyItem(IT it); + static std::weak_ptrGetItem(IT it); //Auto-executes its use function and removes the amt specified from the inventory. Multiple amounts will cause the item to execute its useFunc multiple times. static bool UseItem(IT it,uint32_t amt=1); static bool RemoveItem(IT it,ITCategory inventory,uint32_t amt = 1); static bool RemoveItem(IT it,uint32_t amt=1); - static std::vector&get(ITCategory itemCategory); - static const Item&GetInventorySlot(ITCategory itemCategory,size_t slot); + static std::vector>&get(ITCategory itemCategory); + static const std::weak_ptrGetInventorySlot(ITCategory itemCategory,size_t slot); static void Clear(ITCategory itemCategory); - static void EquipItem(const Item&it,EquipSlot slot); + static void EquipItem(const std::weak_ptrit,EquipSlot slot); static void UnequipItem(EquipSlot slot); - static EquipSlot GetSlotEquippedIn(const Item&it); - static Item*GetEquip(EquipSlot slot); + static EquipSlot GetSlotEquippedIn(const std::weak_ptrit); + static std::weak_ptrGetEquip(EquipSlot slot); static const std::mapGetEquippedItemSets(); static bool SwapItems(ITCategory itemCategory,uint32_t slot1,uint32_t slot2); @@ -200,10 +211,10 @@ private: static void InsertIntoSortedInv(IT item); static void InsertIntoStageInventoryCategory(IT item,uint32_t amt,bool monsterDrop); static bool ExecuteAction(IT item); - static std::map_inventory; - static std::mapequipment; + static std::map>_inventory; + static std::map>equipment; //Only contains "1" of every item, as this is a map to index items and not the actual storage of items! - static std::map>sortedInv; + static std::map>>sortedInv; }; class ItemProps{ @@ -274,4 +285,6 @@ public: static void Update(); static void Draw(); void ResetTimer(); -}; \ No newline at end of file +}; + +#define ISBLANK(itemRef) Item::IsBlank(itemRef) \ No newline at end of file diff --git a/Crawler/ItemLoadoutWindow.cpp b/Crawler/ItemLoadoutWindow.cpp index 50e47f3c..b02680bf 100644 --- a/Crawler/ItemLoadoutWindow.cpp +++ b/Crawler/ItemLoadoutWindow.cpp @@ -50,7 +50,6 @@ 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; float buttonBorderPadding=64; diff --git a/Crawler/MenuComponent.h b/Crawler/MenuComponent.h index 59d9f602..2db261a8 100644 --- a/Crawler/MenuComponent.h +++ b/Crawler/MenuComponent.h @@ -109,6 +109,7 @@ protected: bool valid=true; //If set to false, this would cause the component to be removed. bool fitToLabel=false; //Will shrink text horizontally to fit the size of the label if the display text is too large. bool grayedOut=false; //If turned on, a button will appear grayed out and unresponsive. + int inventoryIndex=0; vf2d labelScaling={1,1}; virtual void Update(Crawler*game); virtual void DrawDecal(ViewPort&window,bool focused); diff --git a/Crawler/MenuItemButton.h b/Crawler/MenuItemButton.h index cefbfe40..b29f8954 100644 --- a/Crawler/MenuItemButton.h +++ b/Crawler/MenuItemButton.h @@ -50,40 +50,52 @@ INCLUDE_game INCLUDE_ITEM_DATA class MenuItemButton:public MenuIconButton{ + friend class InventoryScrollableWindowComponent; private: - std::vector&invRef; - int inventoryIndex=0; + std::vector>&invRef; MenuType itemDescriptionMenu; std::string itemNameLabelName; std::string itemDescriptionLabelName; CompactText compact=COMPACT; public: int selected=-1; //0-2 representing which loadout slot this item consumes. -1 means not selected. - inline MenuItemButton(geom2d::rectrect,std::vector&invRef,int invIndex,MenuFunc onClick,MenuType itemDescriptionMenu,std::string itemNameLabelName,std::string itemDescriptionLabelName,IconButtonAttr attributes=IconButtonAttr::SELECTABLE) - :MenuIconButton(rect,invRef.size()>invIndex?const_cast(invRef[invIndex].Decal()):nullptr,onClick,attributes),invRef(invRef),inventoryIndex(invIndex),itemDescriptionMenu(itemDescriptionMenu),itemNameLabelName(itemNameLabelName),itemDescriptionLabelName(itemDescriptionLabelName){ + inline MenuItemButton(geom2d::rectrect,std::vector>&invRef,int invIndex,MenuFunc onClick,MenuType itemDescriptionMenu,std::string itemNameLabelName,std::string itemDescriptionLabelName,IconButtonAttr attributes=IconButtonAttr::SELECTABLE) + :MenuIconButton(rect,invRef.size()>invIndex?const_cast(invRef[invIndex]->Decal()):nullptr,onClick,attributes),invRef(invRef),itemDescriptionMenu(itemDescriptionMenu),itemNameLabelName(itemNameLabelName),itemDescriptionLabelName(itemDescriptionLabelName){ draggable=false; + inventoryIndex=invIndex; valid=invRef.size()>invIndex; } - inline MenuItemButton(geom2d::rectrect,std::vector&invRef,int invIndex,MenuFunc onClick,MenuFunc onHover,MenuFunc onMouseOut,MenuType itemDescriptionMenu,std::string itemNameLabelName,std::string itemDescriptionLabelName,IconButtonAttr attributes=IconButtonAttr::SELECTABLE) - :MenuIconButton(rect,invRef.size()>invIndex?const_cast(invRef[invIndex].Decal()):nullptr,onClick,attributes),invRef(invRef),inventoryIndex(invIndex),itemDescriptionMenu(itemDescriptionMenu),itemNameLabelName(itemNameLabelName),itemDescriptionLabelName(itemDescriptionLabelName){ + inline MenuItemButton(geom2d::rectrect,std::vector>&invRef,int invIndex,MenuFunc onClick,MenuFunc onHover,MenuFunc onMouseOut,MenuType itemDescriptionMenu,std::string itemNameLabelName,std::string itemDescriptionLabelName,IconButtonAttr attributes=IconButtonAttr::SELECTABLE) + :MenuIconButton(rect,invRef.size()>invIndex?const_cast(invRef[invIndex]->Decal()):nullptr,onClick,attributes),invRef(invRef),itemDescriptionMenu(itemDescriptionMenu),itemNameLabelName(itemNameLabelName),itemDescriptionLabelName(itemDescriptionLabelName){ draggable=false; + inventoryIndex=invIndex; runHoverFunctions=true; valid=invRef.size()>invIndex; SetHoverFunc(onHover); SetMouseOutFunc(onMouseOut); } - inline Item&GetItem(){ - return Inventory::GetItem(invRef.at(inventoryIndex).ActualName()); + inline std::weak_ptrGetItem(){ + return Inventory::GetItem(invRef.at(inventoryIndex)->ActualName()); } //Returns true if the item has been consumed completely and there are 0 remaining of that type in our inventory. inline bool UseItem(uint32_t amt=1){ if(invRef.size()<=inventoryIndex)return false; - return Inventory::UseItem(invRef.at(inventoryIndex).ActualName(),amt); + return Inventory::UseItem(invRef.at(inventoryIndex)->ActualName(),amt); } inline void SetCompactDescriptions(bool compact){ if(compact)this->compact=COMPACT; else this->compact=NON_COMPACT; } + inline virtual void Update(Crawler*game)override{ + MenuIconButton::Update(game); + valid=invRef.size()>inventoryIndex&&ITEM_DATA.count(invRef[inventoryIndex]->ActualName())&&invRef[inventoryIndex]->Amt()>0; + if(!valid){ + icon=nullptr; + } + if(hovered){ + UpdateLabel(); + } + } protected: virtual inline void OnMouseOut()override{ if(itemNameLabelName!=""){ @@ -94,13 +106,13 @@ protected: } } void UpdateLabel(){ - if(invRef[inventoryIndex].IsBlank())return; + if(ISBLANK(invRef[inventoryIndex]))return; std::string labelNameText; std::string labelDescriptionText; if(valid){ - icon=const_cast(invRef[inventoryIndex].Decal()); - labelNameText=invRef[inventoryIndex].DisplayName(); - labelDescriptionText=invRef[inventoryIndex].Description(compact); + icon=const_cast(invRef[inventoryIndex]->Decal()); + labelNameText=invRef[inventoryIndex]->DisplayName(); + labelDescriptionText=invRef[inventoryIndex]->Description(compact); }else{ icon=nullptr; labelNameText=""; @@ -118,23 +130,15 @@ protected: virtual inline void OnHover()override{ UpdateLabel(); } - virtual inline void Update(Crawler*game)override{ - MenuIconButton::Update(game); - valid=invRef.size()>inventoryIndex&&ITEM_DATA.count(invRef[inventoryIndex].ActualName()); - - if(hovered){ - UpdateLabel(); - } - } virtual inline void DrawDecal(ViewPort&window,bool focused)override{ MenuIconButton::DrawDecal(window,focused); if(selected!=-1){ drawutil::DrawCrosshairDecalViewPort(window,{rect.pos,rect.size},0); } if(valid){ - int itemQuantity=Inventory::GetItemCount(invRef.at(inventoryIndex).ActualName()); //Normally we'd retrieve how many of this item we have from our inventory...However Monster Loot and Stage Loot inventories are special and hold their own inventory counts... + int itemQuantity=Inventory::GetItemCount(invRef.at(inventoryIndex)->ActualName()); //Normally we'd retrieve how many of this item we have from our inventory...However Monster Loot and Stage Loot inventories are special and hold their own inventory counts... if(&invRef==&Inventory::get("Monster Loot")||&invRef==&Inventory::get("Stage Loot")){ - itemQuantity=invRef.at(inventoryIndex).Amt(); //So the item quantity comes from the stack itself and not our main inventory. + itemQuantity=invRef.at(inventoryIndex)->Amt(); //So the item quantity comes from the stack itself and not our main inventory. } std::string quantityText="x"+std::to_string(itemQuantity); vf2d quantityTextScale=rect.size/48.f; @@ -158,7 +162,7 @@ protected: inline bool DropDraggableItem(MenuComponent*draggable)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; - ITCategory cat=draggedItem->invRef.at(draggedItem->inventoryIndex).Category(); + ITCategory cat=draggedItem->invRef.at(draggedItem->inventoryIndex)->Category(); return Inventory::SwapItems(cat,draggedItem->inventoryIndex,inventoryIndex); } }; diff --git a/Crawler/MenuItemItemButton.h b/Crawler/MenuItemItemButton.h index 68eb8c77..1bb8f327 100644 --- a/Crawler/MenuItemItemButton.h +++ b/Crawler/MenuItemItemButton.h @@ -50,30 +50,30 @@ INCLUDE_ITEM_DATA class MenuItemItemButton:public MenuIconButton{ private: - std::reference_wrapperitemRef; + std::weak_ptritemRef; std::string itemNameLabelName; std::string itemDescriptionLabelName; bool hideQty=false; CompactText compact=COMPACT; public: - inline MenuItemItemButton(geom2d::rectrect,const Item&itemRef,MenuType menuDest,MenuFunc onClick,std::string itemNameLabelName,std::string itemDescriptionLabelName,IconButtonAttr attributes=IconButtonAttr::SELECTABLE) - :MenuIconButton(rect,(!itemRef.IsBlank())?const_cast(itemRef.Decal()):nullptr,menuDest,onClick,attributes),itemRef(itemRef),itemNameLabelName(itemNameLabelName),itemDescriptionLabelName(itemDescriptionLabelName){ + inline MenuItemItemButton(geom2d::rectrect,const std::weak_ptritemRef,MenuType menuDest,MenuFunc onClick,std::string itemNameLabelName,std::string itemDescriptionLabelName,IconButtonAttr attributes=IconButtonAttr::SELECTABLE) + :MenuIconButton(rect,!ISBLANK(itemRef)?const_cast(itemRef.lock()->Decal()):nullptr,menuDest,onClick,attributes),itemRef(itemRef),itemNameLabelName(itemNameLabelName),itemDescriptionLabelName(itemDescriptionLabelName){ draggable=false; - valid=!itemRef.IsBlank(); + valid=!ISBLANK(itemRef); } - inline MenuItemItemButton(geom2d::rectrect,const Item&itemRef,MenuType menuDest,MenuFunc onClick,MenuFunc onHover,MenuFunc onMouseOut,std::string itemNameLabelName="",std::string itemDescriptionLabelName="",IconButtonAttr attributes=IconButtonAttr::SELECTABLE) - :MenuIconButton(rect,(!itemRef.IsBlank())?const_cast(itemRef.Decal()):nullptr,menuDest,onClick,attributes),itemRef(itemRef),itemNameLabelName(itemNameLabelName),itemDescriptionLabelName(itemDescriptionLabelName){ + inline MenuItemItemButton(geom2d::rectrect,const std::weak_ptritemRef,MenuType menuDest,MenuFunc onClick,MenuFunc onHover,MenuFunc onMouseOut,std::string itemNameLabelName="",std::string itemDescriptionLabelName="",IconButtonAttr attributes=IconButtonAttr::SELECTABLE) + :MenuIconButton(rect,!ISBLANK(itemRef)?const_cast(itemRef.lock()->Decal()):nullptr,menuDest,onClick,attributes),itemRef(itemRef),itemNameLabelName(itemNameLabelName),itemDescriptionLabelName(itemDescriptionLabelName){ runHoverFunctions=true; draggable=false; - valid=!itemRef.IsBlank(); + valid=!ISBLANK(itemRef); SetHoverFunc(onHover); SetMouseOutFunc(onMouseOut); } - inline const Item&GetItem(){ - return itemRef.get(); + inline const std::weak_ptrGetItem(){ + return itemRef; } - inline const Item&SetItem(const Item&newItem){ - return itemRef=std::reference_wrapper(newItem); + inline const std::weak_ptrSetItem(const std::weak_ptrnewItem){ + return itemRef=newItem; } inline void SetShowQuantity(bool show){ this->hideQty=!show; @@ -83,11 +83,11 @@ public: else this->compact=NON_COMPACT; } inline void UpdateIcon(){ - if(itemRef.get().IsBlank()){ + if(ISBLANK(itemRef)){ icon=nullptr; return; } - icon=const_cast(itemRef.get().Decal()); + icon=const_cast(itemRef.lock()->Decal()); } protected: virtual inline void OnMouseOut()override{ @@ -105,16 +105,16 @@ protected: std::string labelNameText; std::string labelDescriptionText; - if(itemRef.get().IsBlank()){ + if(ISBLANK(itemRef)){ icon=nullptr; labelNameText=""; labelDescriptionText=""; return; } - icon=const_cast(itemRef.get().Decal()); - labelNameText=itemRef.get().DisplayName(); - labelDescriptionText=itemRef.get().Description(compact); + icon=const_cast(itemRef.lock()->Decal()); + labelNameText=itemRef.lock()->DisplayName(); + labelDescriptionText=itemRef.lock()->Description(compact); if(itemNameLabelName!=""){ Component(parentMenu,itemNameLabelName)->label=labelNameText; Component(parentMenu,itemNameLabelName)->Enable(true); @@ -126,8 +126,11 @@ protected: } virtual inline void Update(Crawler*game)override{ MenuIconButton::Update(game); - valid=!itemRef.get().IsBlank(); - + valid=!ISBLANK(itemRef); + + if(!valid){ + icon=nullptr; + } if(hovered){ UpdateLabel(); } @@ -135,11 +138,11 @@ protected: virtual inline void DrawDecal(ViewPort&window,bool focused)override{ MenuIconButton::DrawDecal(window,focused); if(valid&&!hideQty){ - std::string quantityText="x"+std::to_string(itemRef.get().Amt()); + std::string quantityText="x"+std::to_string(itemRef.lock()->Amt()); vf2d quantityTextScale=rect.size/48.f; vf2d textSize=vf2d(game->GetTextSizeProp(quantityText))*quantityTextScale; vf2d drawPos=rect.pos+rect.size-textSize; - if(itemRef.get().Amt()!=INFINITE){ + if(itemRef.lock()->Amt()!=INFINITE){ window.DrawShadowStringDecal(drawPos,quantityText,WHITE,BLACK,quantityTextScale); } } diff --git a/Crawler/Merchant.cpp b/Crawler/Merchant.cpp index a2adb62b..5ad7ec93 100644 --- a/Crawler/Merchant.cpp +++ b/Crawler/Merchant.cpp @@ -44,7 +44,7 @@ INCLUDE_game INCLUDE_ITEM_CATEGORIES std::map>Merchant::merchants; -std::map>Merchant::sortedItems; +std::map>>Merchant::sortedItems; MerchantFunctionPrimingData Merchant::purchaseFunctionPrimed("CanPurchaseItem()"); MerchantFunctionPrimingData Merchant::sellFunctionPrimed("CanSellItem()"); Merchant Merchant::travelingMerchant; @@ -58,11 +58,11 @@ const std::string&Merchant::GetDisplayName()const{ return displayName; } -const std::vector&Merchant::GetShopItems()const{ +const std::vector>&Merchant::GetShopItems()const{ return shopItems; } -const std::vector&Merchant::GetShopItems(ITCategory category){ +const std::vector>&Merchant::GetShopItems(ITCategory category){ return sortedItems[category]; } @@ -72,7 +72,7 @@ Merchant&Merchant::AddMerchant(Chapter chapter){ } void Merchant::AddItem(IT item,uint32_t amt,uint8_t enhancementLevel){ - shopItems.push_back(Item{amt,item,enhancementLevel}); + shopItems.push_back(std::make_shared(amt,item,enhancementLevel)); if(&GetCurrentTravelingMerchant()==this){ UpdateSortedItemsList(); Menu::MerchantInventorySlotsUpdated(ITEM_DATA[item].Category()); @@ -84,8 +84,8 @@ void Merchant::UpdateSortedItemsList(){ for(auto&[key,items]:ITEM_CATEGORIES){ sortedItems[key].clear(); } - std::for_each(merchant.shopItems.begin(),merchant.shopItems.end(),[](const Item&item){ - sortedItems[item.Category()].push_back(const_cast(&item)); + std::for_each(merchant.shopItems.begin(),merchant.shopItems.end(),[](const std::shared_ptritem){ + sortedItems[item->Category()].push_back(item); }); } @@ -132,11 +132,11 @@ void Merchant::Initialize(){ } bool Merchant::CanPurchaseItem(IT item,uint32_t amt)const{ bool itemAvailable=false; - const Item*foundItem=nullptr; - for(const Item&it:shopItems){ - if(it==item&&it.Amt()>=amt&&it.CanBePurchased()){ + std::weak_ptrfoundItem; + for(const std::shared_ptrit:shopItems){ + if(it==item&&it->Amt()>=amt&&it->CanBePurchased()){ itemAvailable=true; - foundItem=⁢ + foundItem=it; break; } } @@ -145,8 +145,8 @@ bool Merchant::CanPurchaseItem(IT item,uint32_t amt)const{ purchaseFunctionPrimed.item=item; return purchaseFunctionPrimed= itemAvailable&& - foundItem!=nullptr&& - game->GetPlayer()->GetMoney()>=foundItem->BuyValue()*amt; + !foundItem.expired()&& + game->GetPlayer()->GetMoney()>=foundItem.lock()->BuyValue()*amt; }; bool Merchant::CanSellItem(IT item,uint32_t amt)const{ const ItemInfo&it=ITEM_DATA[item]; @@ -161,12 +161,12 @@ void Merchant::PurchaseItem(IT item,uint32_t amt){ purchaseFunctionPrimed.Validate(item,amt); uint32_t totalCost=0U; - for(Item&it:shopItems){ + for(std::shared_ptrit:shopItems){ if(it==item){ - if(it.Amt()!=INFINITE){ - it.SetAmt(it.Amt()-amt); + if(it->Amt()!=INFINITE){ + it->SetAmt(it->Amt()-amt); } - totalCost=it.BuyValue()*amt; + totalCost=it->BuyValue()*amt; break; } } @@ -181,10 +181,10 @@ void Merchant::SellItem(IT item,uint32_t amt){ uint32_t totalCost=0U; bool itemFound=false; - for(Item&it:shopItems){ + for(std::shared_ptrit:shopItems){ if(it==item){ - if(it.Amt()!=INFINITE){ - it.SetAmt(it.Amt()+amt); + if(it->Amt()!=INFINITE){ + it->SetAmt(it->Amt()+amt); } itemFound=true; break; diff --git a/Crawler/Merchant.h b/Crawler/Merchant.h index f110b035..a2b244f7 100644 --- a/Crawler/Merchant.h +++ b/Crawler/Merchant.h @@ -49,8 +49,8 @@ public: static void RandomizeTravelingMerchant(); static Merchant&GetCurrentTravelingMerchant(); const std::string&GetDisplayName()const; - const std::vector&GetShopItems()const; - const static std::vector&GetShopItems(ITCategory category); + const std::vector>&GetShopItems()const; + const static std::vector>&GetShopItems(ITCategory category); void AddItem(IT item,uint32_t amt=1,uint8_t enhancementLevel=0U); bool CanPurchaseItem(IT item,uint32_t amt=1U)const; bool CanSellItem(IT item,uint32_t amt=1U)const; @@ -66,7 +66,7 @@ private: static const Merchant&GetRandomMerchant(Chapter chapter); static std::map>merchants; std::string displayName; - std::vectorshopItems; - static std::map>sortedItems; + std::vector>shopItems; + static std::map>>sortedItems; static void UpdateSortedItemsList(); }; \ No newline at end of file diff --git a/Crawler/MerchantWindow.cpp b/Crawler/MerchantWindow.cpp index 8e644b41..749d0bf5 100644 --- a/Crawler/MerchantWindow.cpp +++ b/Crawler/MerchantWindow.cpp @@ -64,18 +64,18 @@ void Menu::InitializeMerchantWindow(){ auto inventoryDisplay=merchantWindow->ADD("Merchant Inventory Display",RowMerchantInventoryScrollableWindowComponent)({{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().ActualName(); - Component(BUY_ITEM,"Price per item Amount Label")->SetLabel(std::to_string(item->GetItem().BuyValue())); + 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())); Component(BUY_ITEM,"Amount to buy Amount Label")->SetLabel("1"); - Component(BUY_ITEM,"Total Price Amount Label")->SetLabel(std::to_string(item->GetItem().BuyValue())); + Component(BUY_ITEM,"Total Price Amount Label")->SetLabel(std::to_string(item->GetItem().lock()->BuyValue())); Merchant&merchant=Merchant::GetCurrentTravelingMerchant(); - bool canPurchase=merchant.CanPurchaseItem(item->GetItem().ActualName(),1); + bool canPurchase=merchant.CanPurchaseItem(item->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().BuyValue())); - Component(BUY_ITEM,"Item Purchase Header")->SetLabel("Buying "+item->GetItem().DisplayName()); - Component(BUY_ITEM,"Purchase Button")->SetGrayedOut(!merchant.CanPurchaseItem(item->GetItem().ActualName(),1)); + 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)); Menu::OpenMenu(BUY_ITEM); return true; }, diff --git a/Crawler/Player.cpp b/Crawler/Player.cpp index 3fc20751..641d75f5 100644 --- a/Crawler/Player.cpp +++ b/Crawler/Player.cpp @@ -870,10 +870,10 @@ void PlayerStats::RecalculateEquipStats(){ baseStats.copyTo(equipStats); for(int i=int(EquipSlot::HELMET);i<=int(EquipSlot::RING2);i<<=1){ EquipSlot slot=EquipSlot(i); - Item*equip=Inventory::GetEquip(slot); - if(equip->IsBlank())continue; + std::weak_ptrequip=Inventory::GetEquip(slot); + if(ISBLANK(equip))continue; for(ItemAttribute a=ItemAttribute(int(ItemAttribute::ENUM_START)+1);aGetStats().A_Read(a); + equipStats.A(a)+=equip.lock()->GetStats().A_Read(a); } } diff --git a/Crawler/RowItemDisplay.h b/Crawler/RowItemDisplay.h index b2273763..2cb6e5f3 100644 --- a/Crawler/RowItemDisplay.h +++ b/Crawler/RowItemDisplay.h @@ -43,30 +43,30 @@ All rights reserved. INCLUDE_game class RowItemDisplay:public MenuComponent{ - std::reference_wrapperitemRef; + std::weak_ptritemRef; std::string itemNameLabelName; std::string itemDescriptionLabelName; CompactText compact=NON_COMPACT; bool showQuantity=true; public: - inline RowItemDisplay(geom2d::rectrect,const Item&itemRef,MenuFunc onClick,std::string itemNameLabelName,std::string itemDescriptionLabelName,ButtonAttr attributes=ButtonAttr::NONE) + inline RowItemDisplay(geom2d::rectrect,const std::weak_ptritemRef,MenuFunc onClick,std::string itemNameLabelName,std::string itemDescriptionLabelName,ButtonAttr attributes=ButtonAttr::NONE) :MenuComponent(rect,"",onClick,attributes),itemNameLabelName(itemNameLabelName),itemDescriptionLabelName(itemDescriptionLabelName),itemRef(itemRef){ - if(itemRef.IsEquippable())SetShowQuantity(false); + if(itemRef.lock()->IsEquippable())SetShowQuantity(false); } virtual inline void DrawDecal(ViewPort&window,bool focused)final{ MenuComponent::DrawDecal(window,focused); float scaleFactor=(rect.size.y-4)/24; vf2d iconSize=vf2d{scaleFactor,scaleFactor}*24.f; - window.DrawDecal(rect.pos+vf2d{2,2},const_cast(itemRef.get().Decal()),{scaleFactor,scaleFactor}); + window.DrawDecal(rect.pos+vf2d{2,2},const_cast(itemRef.lock()->Decal()),{scaleFactor,scaleFactor}); window.DrawRectDecal(rect.pos+vf2d{2,2},iconSize); - std::string itemName=itemRef.get().DisplayName(); + std::string itemName=itemRef.lock()->DisplayName(); vf2d scaledSize={std::min(1.f,(rect.size.x-6-iconSize.x)/game->GetTextSizeProp(itemName).x),1}; window.DrawShadowStringPropDecal(rect.pos+vf2d{4,4}+vf2d{iconSize.x,iconSize.y/2-4},itemName,WHITE,BLACK,scaledSize); - if(showQuantity&&itemRef.get().Amt()!=INFINITE){ - std::string quantityText=std::format("x{}",itemRef.get().Amt()); + if(showQuantity&&itemRef.lock()->Amt()!=INFINITE){ + std::string quantityText=std::format("x{}",itemRef.lock()->Amt()); float qtyTextScale=0.75f; vf2d qtyTextSize=vf2d(game->GetTextSizeProp(quantityText))*qtyTextScale; window.DrawShadowStringPropDecal(rect.pos+rect.size-vf2d{1,1}+vf2d{-qtyTextSize.x,-qtyTextSize.y},quantityText,WHITE,BLACK,{qtyTextScale,qtyTextScale}); @@ -78,7 +78,8 @@ public: } virtual inline void Update(Crawler*game)override{ MenuComponent::Update(game); - + valid=!ISBLANK(itemRef)&&itemRef.lock()->Amt()>0; + if(hovered){ UpdateLabel(); } @@ -98,19 +99,19 @@ public: virtual inline void SetShowQuantity(bool showQuantity){ this->showQuantity=showQuantity; } - virtual inline const Item&GetItem(){ + virtual inline const std::weak_ptrGetItem(){ return itemRef; } - virtual inline void SetItem(const Item&itemRef){ - this->itemRef=std::reference_wrapper(itemRef); + virtual inline void SetItem(const std::weak_ptritemRef){ + this->itemRef=itemRef; } void UpdateLabel(){ - if(itemRef.get().IsBlank())return; + if(ISBLANK(itemRef))return; std::string labelNameText; std::string labelDescriptionText; if(valid){ - labelNameText=itemRef.get().DisplayName(); - labelDescriptionText=itemRef.get().Description(compact); + labelNameText=itemRef.lock()->DisplayName(); + labelDescriptionText=itemRef.lock()->Description(compact); }else{ labelNameText=""; labelDescriptionText=""; diff --git a/Crawler/RowMerchantInventoryScrollableWindowComponent.h b/Crawler/RowMerchantInventoryScrollableWindowComponent.h index ef673cb2..dd612675 100644 --- a/Crawler/RowMerchantInventoryScrollableWindowComponent.h +++ b/Crawler/RowMerchantInventoryScrollableWindowComponent.h @@ -45,7 +45,7 @@ public: virtual inline void OnInventorySlotsUpdate(ITCategory cat)override{ - const std::vector&merchantInv=Merchant::GetCurrentTravelingMerchant().GetShopItems(); + const std::vector>&merchantInv=Merchant::GetCurrentTravelingMerchant().GetShopItems(); //We only want to refresh the inventory slots if the component count no longer matches what's actually in our inventory. if(components.size()&merchantInv=Merchant::GetCurrentTravelingMerchant().GetShopItems(); + const std::vector>&merchantInv=Merchant::GetCurrentTravelingMerchant().GetShopItems(); size_t invSize=merchantInv.size(); int invWidth=int(rect.size.x/(float(options.size.x)+options.padding)); int x=int((invSize-1)%invWidth); diff --git a/Crawler/ScrollableWindowComponent.h b/Crawler/ScrollableWindowComponent.h index edef1f79..88c76bf8 100644 --- a/Crawler/ScrollableWindowComponent.h +++ b/Crawler/ScrollableWindowComponent.h @@ -76,7 +76,8 @@ public: size_t removedCount=0; removedCount+=std::erase(buttonList,button); removedCount+=std::erase(keyboardButtonList,button); - if(removedCount!=2){ + 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){ @@ -89,8 +90,9 @@ public: ERR("WARNING! Attempted to erase key "<originalPos.y<<" from button map, but the list still exists!") } } - Menu::menus[button->parentMenu]->components.erase(button->GetName()); - components.erase(std::find(components.begin(),components.end(),button)); + auto componentSearchResults=std::find(components.begin(),components.end(),button); + if(componentSearchResults==components.end())ERR("Could not find Component"<GetName())<<" inside the component list!"); + components.erase(componentSearchResults); Menu::menus[button->parentMenu]->RecalculateComponentCount(); delete button; CalculateBounds(); diff --git a/Crawler/Version.h b/Crawler/Version.h index 611d828d..040da977 100644 --- a/Crawler/Version.h +++ b/Crawler/Version.h @@ -39,7 +39,7 @@ All rights reserved. #define VERSION_MAJOR 0 #define VERSION_MINOR 2 #define VERSION_PATCH 1 -#define VERSION_BUILD 4463 +#define VERSION_BUILD 4521 #define stringify(a) stringify_(a) #define stringify_(a) #a