Make gear appear unstackable in inventories while other items remain stackable. Each individual piece of gear can now have its own stats.

pull/28/head
sigonasr2 11 months ago
parent f987e51324
commit c528d89b85
  1. 4
      Crawler/BlacksmithCraftingWindow.cpp
  2. 9
      Crawler/CharacterMenuWindow.cpp
  3. 5
      Crawler/Crawler.cpp
  4. 4
      Crawler/Crawler.vcxproj
  5. 3
      Crawler/Crawler.vcxproj.filters
  6. 20
      Crawler/InventoryCreator.cpp
  7. 88
      Crawler/Item.cpp
  8. 14
      Crawler/Item.h
  9. 58
      Crawler/ItemMenuLabel.h
  10. 2
      Crawler/MenuItemButton.h
  11. 2
      Crawler/MenuItemItemButton.h
  12. 10
      Crawler/Merchant.cpp
  13. 2
      Crawler/Merchant.h
  14. 3
      Crawler/MerchantWindow.cpp
  15. 11
      Crawler/SellItemWindow.cpp
  16. 1
      Crawler/TODO.txt
  17. 2
      Crawler/Version.h

@ -57,8 +57,8 @@ void Menu::InitializeBlacksmithCraftingWindow(){
std::vector<std::weak_ptr<Item>>armorInventory; std::vector<std::weak_ptr<Item>>armorInventory;
#pragma region Build Equipment Lists #pragma region Build Equipment Lists
std::for_each(Inventory::get("Equipment").begin(),Inventory::get("Equipment").end(),[&](const std::shared_ptr<Item> item){ std::for_each(Inventory::get("Equipment").begin(),Inventory::get("Equipment").end(),[&](const std::weak_ptr<Item> item){
switch(item.get()->GetEquipSlot()){ switch(item.lock()->GetEquipSlot()){
case EquipSlot::WEAPON:{ case EquipSlot::WEAPON:{
weaponInventory.push_back(item); weaponInventory.push_back(item);
}break; }break;

@ -122,7 +122,7 @@ void Menu::InitializeCharacterMenuWindow(){
const std::vector<std::shared_ptr<Item>>&equips=Inventory::get("Equipment"); const std::vector<std::shared_ptr<Item>>&equips=Inventory::get("Equipment");
const std::vector<std::shared_ptr<Item>>&accessories=Inventory::get("Accessories"); const std::vector<std::shared_ptr<Item>>&accessories=Inventory::get("Accessories");
std::vector<std::shared_ptr<Item>>availableEquipment; std::vector<std::weak_ptr<Item>>availableEquipment;
std::copy_if(equips.begin(),equips.end(),std::back_inserter(availableEquipment),[&](const std::shared_ptr<Item>it){ std::copy_if(equips.begin(),equips.end(),std::back_inserter(availableEquipment),[&](const std::shared_ptr<Item>it){
return it->GetEquipSlot()&slot; return it->GetEquipSlot()&slot;
}); });
@ -132,9 +132,8 @@ void Menu::InitializeCharacterMenuWindow(){
ScrollableWindowComponent*equipList=Component<ScrollableWindowComponent>(data.component->parentMenu,"Equip List"); ScrollableWindowComponent*equipList=Component<ScrollableWindowComponent>(data.component->parentMenu,"Equip List");
equipList->RemoveAllComponents(); equipList->RemoveAllComponents();
for(int counter=0;const std::shared_ptr<Item>it:availableEquipment){ for(int counter=0;const std::weak_ptr<Item>it:availableEquipment){
std::weak_ptr<Item>itemInvRef=Inventory::GetItem(it->ActualName()); 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)({{2,2+counter*29.f},{120-15,28}},itemInvRef,
[](MenuFuncData data){ [](MenuFuncData data){
RowItemDisplay*comp=DYNAMIC_CAST<RowItemDisplay*>(data.component); RowItemDisplay*comp=DYNAMIC_CAST<RowItemDisplay*>(data.component);
if(comp!=nullptr){ if(comp!=nullptr){
@ -201,7 +200,7 @@ void Menu::InitializeCharacterMenuWindow(){
equip->SetSelectionType(SelectionType::NONE); equip->SetSelectionType(SelectionType::NONE);
equip->I(Attribute::EQUIP_TYPE)=int(slot); equip->I(Attribute::EQUIP_TYPE)=int(slot);
if(Inventory::GetEquip(slot)==itemInvRef){ if(Inventory::GetEquip(slot)==it){
equip->SetSelected(true); equip->SetSelected(true);
} }
equip->SetCompactDescriptions(NON_COMPACT); equip->SetCompactDescriptions(NON_COMPACT);

@ -200,8 +200,11 @@ bool Crawler::OnUserCreate(){
Inventory::AddItem("Copper Shoes"); Inventory::AddItem("Copper Shoes");
Inventory::AddItem("Shell Helmet"); Inventory::AddItem("Shell Helmet");
Inventory::AddItem("Shell Armor"); Inventory::AddItem("Shell Armor");
Inventory::AddItem("Shell Armor");
Inventory::AddItem("Shell Armor");
Inventory::AddItem("Bone Armor"); Inventory::AddItem("Bone Armor");
Inventory::AddItem("Shell Gloves"); Inventory::AddItem("Shell Gloves");
Inventory::AddItem("Shell Gloves",3);
Inventory::AddItem("Shell Shoes"); Inventory::AddItem("Shell Shoes");
Inventory::AddItem("Bone Pants"); Inventory::AddItem("Bone Pants");
Inventory::AddItem("Bone Gloves"); Inventory::AddItem("Bone Gloves");
@ -2350,7 +2353,7 @@ const std::weak_ptr<Item>Crawler::GetLoadoutItem(int slot){
void Crawler::SetLoadoutItem(int slot,std::string itemName){ 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(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){ if(Inventory::GetItemCount(itemName)>0){
loadout[slot]=Inventory::CopyItem(itemName); loadout[slot]=Inventory::CopyItem(itemName)[0];
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. 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; InputGroup*inputGroup=nullptr;
switch(slot){ switch(slot){

@ -351,6 +351,10 @@
<SubType> <SubType>
</SubType> </SubType>
</ClInclude> </ClInclude>
<ClInclude Include="ItemMenuLabel.h">
<SubType>
</SubType>
</ClInclude>
<ClInclude Include="PlayerMoneyLabel.h"> <ClInclude Include="PlayerMoneyLabel.h">
<SubType> <SubType>
</SubType> </SubType>

@ -387,6 +387,9 @@
<ClInclude Include="RequiredMaterialsList.h"> <ClInclude Include="RequiredMaterialsList.h">
<Filter>Header Files\Interface</Filter> <Filter>Header Files\Interface</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="ItemMenuLabel.h">
<Filter>Header Files\Interface</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="Player.cpp"> <ClCompile Include="Player.cpp">

@ -139,22 +139,22 @@ std::function<void(InventoryScrollableWindowComponent&component,ITCategory cat)>
#pragma region Row Player Weapons Updates #pragma region Row Player Weapons Updates
std::function<void(InventoryScrollableWindowComponent&component,ITCategory cat)> InventoryCreator::RowPlayerWeapons_InventorySlotsUpdate= std::function<void(InventoryScrollableWindowComponent&component,ITCategory cat)> InventoryCreator::RowPlayerWeapons_InventorySlotsUpdate=
[](InventoryScrollableWindowComponent&component,ITCategory cat){ [](InventoryScrollableWindowComponent&component,ITCategory cat){
std::vector<std::shared_ptr<Item>>weapons; std::vector<std::weak_ptr<Item>>weapons;
std::copy_if(Inventory::get("Equipment").begin(),Inventory::get("Equipment").end(),std::back_inserter(weapons),[](std::shared_ptr<Item> item){return item.get()->IsWeapon();}); std::copy_if(Inventory::get("Equipment").begin(),Inventory::get("Equipment").end(),std::back_inserter(weapons),[](std::weak_ptr<Item> item){return item.lock()->IsWeapon();});
component.RemoveAllComponents(); component.RemoveAllComponents();
component.AddButtonOnSlotUpdate(cat); component.AddButtonOnSlotUpdate(cat);
}; };
std::function<void(InventoryScrollableWindowComponent&component,ITCategory cat)> InventoryCreator::RowPlayerWeapons_AddButtonOnSlotUpdate= std::function<void(InventoryScrollableWindowComponent&component,ITCategory cat)> InventoryCreator::RowPlayerWeapons_AddButtonOnSlotUpdate=
[](InventoryScrollableWindowComponent&component,ITCategory cat){ [](InventoryScrollableWindowComponent&component,ITCategory cat){
std::vector<std::shared_ptr<Item>>weapons; std::vector<std::weak_ptr<Item>>weapons;
std::copy_if(Inventory::get("Equipment").begin(),Inventory::get("Equipment").end(),std::back_inserter(weapons),[](std::shared_ptr<Item> item){return item.get()->IsWeapon();}); std::copy_if(Inventory::get("Equipment").begin(),Inventory::get("Equipment").end(),std::back_inserter(weapons),[](std::weak_ptr<Item> item){return item.lock()->IsWeapon();});
RowInventoryScrollableWindowComponent*c=DYNAMIC_CAST<RowInventoryScrollableWindowComponent*>(&component); RowInventoryScrollableWindowComponent*c=DYNAMIC_CAST<RowInventoryScrollableWindowComponent*>(&component);
vf2d buttonSize=c->options.size; vf2d buttonSize=c->options.size;
vf2d totalSpacing={c->options.padding+buttonSize.x,c->options.padding+buttonSize.y}; vf2d totalSpacing={c->options.padding+buttonSize.x,c->options.padding+buttonSize.y};
for(std::shared_ptr<Item> weapon:weapons){ for(std::weak_ptr<Item> weapon:weapons){
size_t invSize=c->components.size()+1; size_t invSize=c->components.size()+1;
int invWidth=int(c->rect.size.x/(float(c->options.size.x)+c->options.padding)); int invWidth=int(c->rect.size.x/(float(c->options.size.x)+c->options.padding));
int x=int((invSize-1)%invWidth); int x=int((invSize-1)%invWidth);
@ -173,22 +173,22 @@ std::function<void(InventoryScrollableWindowComponent&component,ITCategory cat)>
#pragma region Row Player Armor Updates #pragma region Row Player Armor Updates
std::function<void(InventoryScrollableWindowComponent&component,ITCategory cat)> InventoryCreator::RowPlayerArmor_InventorySlotsUpdate= std::function<void(InventoryScrollableWindowComponent&component,ITCategory cat)> InventoryCreator::RowPlayerArmor_InventorySlotsUpdate=
[](InventoryScrollableWindowComponent&component,ITCategory cat){ [](InventoryScrollableWindowComponent&component,ITCategory cat){
std::vector<std::shared_ptr<Item>>armor; std::vector<std::weak_ptr<Item>>armor;
std::copy_if(Inventory::get("Equipment").begin(),Inventory::get("Equipment").end(),std::back_inserter(armor),[](std::shared_ptr<Item> item){return item.get()->IsArmor();}); std::copy_if(Inventory::get("Equipment").begin(),Inventory::get("Equipment").end(),std::back_inserter(armor),[](std::weak_ptr<Item> item){return item.lock()->IsArmor();});
component.RemoveAllComponents(); component.RemoveAllComponents();
component.AddButtonOnSlotUpdate(cat); component.AddButtonOnSlotUpdate(cat);
}; };
std::function<void(InventoryScrollableWindowComponent&component,ITCategory cat)> InventoryCreator::RowPlayerArmor_AddButtonOnSlotUpdate= std::function<void(InventoryScrollableWindowComponent&component,ITCategory cat)> InventoryCreator::RowPlayerArmor_AddButtonOnSlotUpdate=
[](InventoryScrollableWindowComponent&component,ITCategory cat){ [](InventoryScrollableWindowComponent&component,ITCategory cat){
std::vector<std::shared_ptr<Item>>armor; std::vector<std::weak_ptr<Item>>armor;
std::copy_if(Inventory::get("Equipment").begin(),Inventory::get("Equipment").end(),std::back_inserter(armor),[](std::shared_ptr<Item> item){return item.get()->IsArmor();}); std::copy_if(Inventory::get("Equipment").begin(),Inventory::get("Equipment").end(),std::back_inserter(armor),[](std::weak_ptr<Item> item){return item.lock()->IsArmor();});
RowInventoryScrollableWindowComponent*c=DYNAMIC_CAST<RowInventoryScrollableWindowComponent*>(&component); RowInventoryScrollableWindowComponent*c=DYNAMIC_CAST<RowInventoryScrollableWindowComponent*>(&component);
vf2d buttonSize=c->options.size; vf2d buttonSize=c->options.size;
vf2d totalSpacing={c->options.padding+buttonSize.x,c->options.padding+buttonSize.y}; vf2d totalSpacing={c->options.padding+buttonSize.x,c->options.padding+buttonSize.y};
for(std::shared_ptr<Item> armor:armor){ for(std::weak_ptr<Item> armor:armor){
size_t invSize=c->components.size()+1; size_t invSize=c->components.size()+1;
int invWidth=int(c->rect.size.x/(float(c->options.size.x)+c->options.padding)); int invWidth=int(c->rect.size.x/(float(c->options.size.x)+c->options.padding));
int x=int((invSize-1)%invWidth); int x=int((invSize-1)%invWidth);

@ -42,6 +42,7 @@ All rights reserved.
#include "Menu.h" #include "Menu.h"
#include "Ability.h" #include "Ability.h"
#include "AttributableStat.h" #include "AttributableStat.h"
#include <numeric>
INCLUDE_game INCLUDE_game
INCLUDE_DATA INCLUDE_DATA
@ -51,7 +52,7 @@ safemap<std::string,ItemInfo>ITEM_DATA;
safemap<std::string,ItemScript>ITEM_SCRIPTS; safemap<std::string,ItemScript>ITEM_SCRIPTS;
safemap<std::string,std::set<std::string>>ITEM_CATEGORIES; safemap<std::string,std::set<std::string>>ITEM_CATEGORIES;
std::shared_ptr<Item>Item::BLANK=std::make_shared<Item>(); std::shared_ptr<Item>Item::BLANK=std::make_shared<Item>();
std::map<IT,std::shared_ptr<Item>>Inventory::_inventory; std::multimap<IT,std::shared_ptr<Item>>Inventory::_inventory;
std::map<ITCategory,std::vector<std::shared_ptr<Item>>>Inventory::sortedInv; std::map<ITCategory,std::vector<std::shared_ptr<Item>>>Inventory::sortedInv;
std::vector<ItemOverlay>ItemOverlay::items; std::vector<ItemOverlay>ItemOverlay::items;
std::map<std::string,ItemSet>ItemSet::sets; std::map<std::string,ItemSet>ItemSet::sets;
@ -358,31 +359,52 @@ Item::Item(uint32_t amt,IT item,uint8_t enhancementLevel)
void Inventory::AddItem(IT it,uint32_t amt,bool monsterDrop){ void Inventory::AddItem(IT it,uint32_t amt,bool monsterDrop){
if(!ITEM_DATA.count(it))ERR("Item "<<std::quoted(it)<<" does not exist in Item Database!"); if(!ITEM_DATA.count(it))ERR("Item "<<std::quoted(it)<<" does not exist in Item Database!");
if(ITEM_DATA[it].IsEquippable()){ //Do not stack equips!
for(uint32_t i=0;i<amt;i++){
InsertIntoSortedInv((*_inventory.insert({it,std::make_shared<Item>(amt,it)})).second);
}
goto SkipAddingStackableItem;
}
else
//There are two places to manipulate items in (Both the sorted inventory and the actual inventory) //There are two places to manipulate items in (Both the sorted inventory and the actual inventory)
if(!_inventory.count(it)){ if(!_inventory.count(it)){
_inventory[it]=std::make_shared<Item>(amt,it); InsertIntoSortedInv((*_inventory.insert({it,std::make_shared<Item>(amt,it)})).second);
InsertIntoSortedInv(it);
}else{ }else{
_inventory.at(it)->amt+=amt; auto inventory=_inventory.equal_range(it);
std::accumulate(inventory.first,inventory.second,0,[&](int counter,std::pair<IT,std::shared_ptr<Item>>item){
(*item.second).amt+=amt;
if(counter>=1)ERR("WARNING! We should not have more than 1 instance of a stackable item!");
return counter+1;
});
} }
SkipAddingStackableItem:
InsertIntoStageInventoryCategory(it,amt,monsterDrop); InsertIntoStageInventoryCategory(it,amt,monsterDrop);
} }
std::shared_ptr<Item>Inventory::CopyItem(IT it){ std::vector<std::shared_ptr<Item>>Inventory::CopyItem(IT it){
if(!_inventory.count(it))return std::make_shared<Item>(*Item::BLANK); if(!_inventory.count(it))return{};
return std::make_shared<Item>(*_inventory.at(it)); std::vector<std::shared_ptr<Item>>copiedItems;
auto inventory=_inventory.equal_range(it);
std::for_each(inventory.first,inventory.second,[&](std::pair<IT,std::shared_ptr<Item>>it){copiedItems.push_back(std::make_shared<Item>(*it.second));});
return copiedItems;
} }
std::weak_ptr<Item>Inventory::GetItem(IT it){ std::vector<std::weak_ptr<Item>>Inventory::GetItem(IT it){
if(!_inventory.count(it))return Item::BLANK; if(!_inventory.count(it))return{};
return _inventory.at(it); std::vector<std::weak_ptr<Item>>items;
auto inventory=_inventory.equal_range(it);
std::for_each(inventory.first,inventory.second,[&](std::pair<IT,std::shared_ptr<Item>>it){items.push_back(it.second);});
return items;
} }
uint32_t Inventory::GetItemCount(IT it){ uint32_t Inventory::GetItemCount(IT it){
if(!_inventory.count(it)){ if(!_inventory.count(it)){
return 0; return 0;
}else{ }else{
return _inventory.at(it)->Amt(); auto inventory=_inventory.equal_range(it);
return std::accumulate(inventory.first,inventory.second,0,[](int val,std::pair<IT,std::shared_ptr<Item>>it){return val+(*it.second).Amt();});
} }
} }
@ -392,14 +414,14 @@ bool Inventory::UseItem(IT it,uint32_t amt){
//There are two places to manipulate items in (Both the sorted inventory and the actual inventory) //There are two places to manipulate items in (Both the sorted inventory and the actual inventory)
for(uint32_t i=0;i<amt;i++){ for(uint32_t i=0;i<amt;i++){
if(ExecuteAction(it)){ if(ExecuteAction(it)){
return RemoveItem(it); return RemoveItem(GetItem(it)[0]);
} }
} }
return false; return false;
} }
//Returns true if the item has been consumed completely and there are 0 remaining of that type in our inventory. //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){ bool Inventory::RemoveItem(std::weak_ptr<Item>itemRef,ITCategory inventory,uint32_t amt){
#pragma region Calculate Inventory to Manipulate #pragma region Calculate Inventory to Manipulate
std::vector<std::shared_ptr<Item>>&inv=sortedInv.at(inventory); std::vector<std::shared_ptr<Item>>&inv=sortedInv.at(inventory);
bool eraseFromLootWindow=false; bool eraseFromLootWindow=false;
@ -412,13 +434,13 @@ bool Inventory::RemoveItem(IT it,ITCategory inventory,uint32_t amt){
eraseFromLootWindow=true; eraseFromLootWindow=true;
} }
int count=0; int count=0;
for(std::shared_ptr<Item>item:inv){ for(std::weak_ptr<Item>item:inv){
if(item==it)break; if(item==itemRef)break;
count++; count++;
} }
#pragma endregion #pragma endregion
uint32_t itemAmt=GetItemCount(it); uint32_t itemAmt=GetItemCount(itemRef.lock()->ActualName());
if(inventory=="Monster Loot"||inventory=="Stage Loot"){ if(inventory=="Monster Loot"||inventory=="Stage Loot"){
itemAmt=inv.at(count)->Amt(); itemAmt=inv.at(count)->Amt();
} }
@ -429,7 +451,7 @@ bool Inventory::RemoveItem(IT it,ITCategory inventory,uint32_t amt){
if (amt>=itemAmt){ if (amt>=itemAmt){
inv.erase(inv.begin()+count); //Clears it from the detected sorted inventory as well! 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!!! 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); _inventory.erase(itemRef.lock()->ActualName());
} }
//Callback for GUI inventories. //Callback for GUI inventories.
@ -437,28 +459,28 @@ bool Inventory::RemoveItem(IT it,ITCategory inventory,uint32_t amt){
return true; return true;
}else{ }else{
if(!eraseFromLootWindow){ if(!eraseFromLootWindow){
_inventory.at(it)->amt-=amt; itemRef.lock()->amt-=amt;
}else{ }else{
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. itemRef.lock()->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; return false;
} }
} }
//Returns true if the item has been consumed completely and there are 0 remaining of that type in our inventory. //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,uint32_t amt){ bool Inventory::RemoveItem(std::weak_ptr<Item>itemRef,uint32_t amt){
ITCategory cat = ITEM_DATA[it].category; ITCategory cat = itemRef.lock()->Category();
return RemoveItem(it, cat, amt); return RemoveItem(itemRef, cat, amt);
} }
const std::vector<std::shared_ptr<Item>>&Inventory::get(ITCategory itemCategory){ const std::vector<std::shared_ptr<Item>>&Inventory::get(ITCategory itemCategory){
return sortedInv.at(itemCategory); return sortedInv.at(itemCategory);
} }
void Inventory::InsertIntoSortedInv(IT item){ void Inventory::InsertIntoSortedInv(std::shared_ptr<Item>itemRef){
sortedInv.at(ITEM_DATA[item].category).push_back(_inventory[item]); sortedInv.at(itemRef->Category()).push_back(itemRef);
//This should be a callback to menus that we need to update the interface with another item slot since a new one has appeared. //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); Menu::InventorySlotsUpdated(itemRef->Category());
} }
void Inventory::InsertIntoStageInventoryCategory(IT item,uint32_t amt,bool monsterDrop){ void Inventory::InsertIntoStageInventoryCategory(IT item,uint32_t amt,bool monsterDrop){
@ -467,7 +489,7 @@ void Inventory::InsertIntoStageInventoryCategory(IT item,uint32_t amt,bool monst
stageInventoryCategory="Monster Loot"; stageInventoryCategory="Monster Loot";
} }
std::vector<std::shared_ptr<Item>>&inv=sortedInv.at(stageInventoryCategory); std::vector<std::shared_ptr<Item>>&inv=sortedInv.at(stageInventoryCategory);
std::vector<std::shared_ptr<Item>>::iterator it=std::find(inv.begin(),inv.end(),std::make_shared<Item>(amt,item)); std::vector<std::shared_ptr<Item>>::iterator it=std::find(inv.begin(),inv.end(),std::make_shared<Item>(amt,item)); //Uses operator== to compare if this item does exist in a stage/monster loot inventory already. We just make an in-place shared pointer of an item to compare with.
if(it!=inv.end()){ if(it!=inv.end()){
(*it)->amt+=amt; (*it)->amt+=amt;
}else{ }else{
@ -491,8 +513,8 @@ bool Inventory::SwapItems(ITCategory itemCategory,uint32_t slot1,uint32_t slot2)
//The inventory is too small, so expand out blank slots to accomodate. //The inventory is too small, so expand out blank slots to accomodate.
inv.resize(largestSlot+size_t(1)); inv.resize(largestSlot+size_t(1));
} }
std::shared_ptr<Item>item1=inv.at(slot1); std::weak_ptr<Item>item1=inv.at(slot1);
std::shared_ptr<Item>item2=inv.at(slot2); std::weak_ptr<Item>item2=inv.at(slot2);
std::swap(item1,item2); std::swap(item1,item2);
return true; return true;
} }
@ -609,7 +631,7 @@ void Inventory::Clear(ITCategory itemCategory){
if(itemCategory=="Monster Loot"||itemCategory=="Stage Loot"){//These do not affect the actual inventory, we just clear the lists. 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,itemCategory,uint32_t(itemQuantity));
} }
} }
@ -707,7 +729,7 @@ EquipSlot Inventory::GetSlotEquippedIn(const std::weak_ptr<Item>it){
EquipSlot slot=EquipSlot(i); EquipSlot slot=EquipSlot(i);
std::weak_ptr<Item>equip=GetEquip(slot); std::weak_ptr<Item>equip=GetEquip(slot);
if(equip.expired())continue; if(equip.expired())continue;
if(equip.lock()->ActualName()==it.lock()->ActualName())return slot; if(&*equip.lock()==&*it.lock())return slot;
} }
return EquipSlot::NONE; return EquipSlot::NONE;
}; };
@ -782,7 +804,7 @@ void Item::EnhanceItem(uint8_t qty){
const CraftingRequirement&consumedResources=GetEnhancementInfo()[EnhancementLevel()].craftingRequirement; const CraftingRequirement&consumedResources=GetEnhancementInfo()[EnhancementLevel()].craftingRequirement;
for(const auto&[name,amt]:consumedResources.GetItems()){ for(const auto&[name,amt]:consumedResources.GetItems()){
Inventory::RemoveItem(name,amt); Inventory::RemoveItem(Inventory::GetItem(name)[0],amt);
} }
game->GetPlayer()->SetMoney(game->GetPlayer()->GetMoney()-consumedResources.GetCost()); game->GetPlayer()->SetMoney(game->GetPlayer()->GetMoney()-consumedResources.GetCost());
}else{ //This is a craftable, so we have to give the player the item they crafted. }else{ //This is a craftable, so we have to give the player the item they crafted.
@ -791,7 +813,7 @@ void Item::EnhanceItem(uint8_t qty){
const CraftingRequirement&consumedResources=GetEnhancementInfo()[1].craftingRequirement; const CraftingRequirement&consumedResources=GetEnhancementInfo()[1].craftingRequirement;
for(const auto&[name,amt]:consumedResources.GetItems()){ for(const auto&[name,amt]:consumedResources.GetItems()){
Inventory::RemoveItem(name,amt); Inventory::RemoveItem(Inventory::GetItem(name)[0],amt);
} }
game->GetPlayer()->SetMoney(game->GetPlayer()->GetMoney()-consumedResources.GetCost()); game->GetPlayer()->SetMoney(game->GetPlayer()->GetMoney()-consumedResources.GetCost());
} }
@ -871,7 +893,7 @@ void Item::SetAmt(uint32_t newAmt){
} }
const std::weak_ptr<Item>Inventory::GetInventorySlot(ITCategory itemCategory,size_t slot){ const std::weak_ptr<Item>Inventory::GetInventorySlot(ITCategory itemCategory,size_t slot){
return GetItem(get(itemCategory).at(slot)->ActualName()); return GetItem(get(itemCategory).at(slot)->ActualName())[0];
} }
bool Item::IsBlank(std::shared_ptr<Item>item){ bool Item::IsBlank(std::shared_ptr<Item>item){

@ -153,7 +153,7 @@ class Item{
friend class Crawler; friend class Crawler;
friend class Menu; friend class Menu;
friend void Merchant::PurchaseItem(IT item,uint32_t amt); friend void Merchant::PurchaseItem(IT item,uint32_t amt);
friend void Merchant::SellItem(IT item,uint32_t amt); friend void Merchant::SellItem(std::weak_ptr<Item>,uint32_t amt);
private: private:
//The amount in the current item stack. //The amount in the current item stack.
uint32_t amt; uint32_t amt;
@ -220,12 +220,12 @@ public:
static void AddItem(IT it,uint32_t amt=1,bool monsterDrop=false); static void AddItem(IT it,uint32_t amt=1,bool monsterDrop=false);
//Returns the actual amount available in your main inventory. //Returns the actual amount available in your main inventory.
static uint32_t GetItemCount(IT it); static uint32_t GetItemCount(IT it);
static std::shared_ptr<Item>CopyItem(IT it); static std::vector<std::shared_ptr<Item>>CopyItem(IT it);
static std::weak_ptr<Item>GetItem(IT it); static std::vector<std::weak_ptr<Item>>GetItem(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. //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 UseItem(IT it,uint32_t amt=1);
static bool RemoveItem(IT it,ITCategory inventory,uint32_t amt = 1); static bool RemoveItem(std::weak_ptr<Item>itemRef,ITCategory inventory,uint32_t amt = 1);
static bool RemoveItem(IT it,uint32_t amt=1); static bool RemoveItem(std::weak_ptr<Item>itemRef,uint32_t amt=1);
static const std::vector<std::shared_ptr<Item>>&get(ITCategory itemCategory); static const std::vector<std::shared_ptr<Item>>&get(ITCategory itemCategory);
static const std::weak_ptr<Item>GetInventorySlot(ITCategory itemCategory,size_t slot); static const std::weak_ptr<Item>GetInventorySlot(ITCategory itemCategory,size_t slot);
static void Clear(ITCategory itemCategory); static void Clear(ITCategory itemCategory);
@ -242,10 +242,10 @@ public:
return true; return true;
} }
private: private:
static void InsertIntoSortedInv(IT item); static void InsertIntoSortedInv(std::shared_ptr<Item>itemRef);
static void InsertIntoStageInventoryCategory(IT item,uint32_t amt,bool monsterDrop); static void InsertIntoStageInventoryCategory(IT item,uint32_t amt,bool monsterDrop);
static bool ExecuteAction(IT item); static bool ExecuteAction(IT item);
static std::map<IT,std::shared_ptr<Item>>_inventory; static std::multimap<IT,std::shared_ptr<Item>>_inventory;
static std::map<EquipSlot,std::weak_ptr<Item>>equipment; static std::map<EquipSlot,std::weak_ptr<Item>>equipment;
//Only contains "1" of every item, as this is a map to index items and not the actual storage of items! //Only contains "1" of every item, as this is a map to index items and not the actual storage of items!
static std::map<ITCategory,std::vector<std::shared_ptr<Item>>>sortedInv; static std::map<ITCategory,std::vector<std::shared_ptr<Item>>>sortedInv;

@ -0,0 +1,58 @@
#pragma region License
/*
License (OLC-3)
~~~~~~~~~~~~~~~
Copyright 2018 - 2022 OneLoneCoder.com
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions or derivations of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions or derivative works in binary form must reproduce the above
copyright notice. This list of conditions and the following disclaimer must be
reproduced in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may
be used to endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
Portions of this software are copyright © 2023 The FreeType
Project (www.freetype.org). Please see LICENSE_FT.txt for more information.
All rights reserved.
*/
#pragma endregion
#pragma once
#include "MenuLabel.h"
#include "Item.h"
class ItemMenuLabel:public MenuLabel{
private:
std::weak_ptr<Item>itemRef;
public:
inline ItemMenuLabel(geom2d::rect<float>rect,std::string label,std::weak_ptr<Item>itemRef,std::function<void(std::string_view newLabel)>onLabelChangeFunc,float scale=1,ComponentAttr attributes=ComponentAttr::NONE)
:MenuLabel(rect,label,onLabelChangeFunc,scale,attributes),itemRef(itemRef){}
inline ItemMenuLabel(geom2d::rect<float>rect,std::string label,std::weak_ptr<Item>itemRef,float scale=1,ComponentAttr attributes=ComponentAttr::NONE)
:MenuLabel(rect,label,scale,attributes),itemRef(itemRef){}
inline const std::weak_ptr<Item>GetItem()const{
return itemRef;
}
inline void SetItem(std::weak_ptr<Item>itemRef){
this->itemRef=itemRef;
}
};

@ -74,7 +74,7 @@ public:
SetMouseOutFunc(onMouseOut); SetMouseOutFunc(onMouseOut);
} }
inline std::weak_ptr<Item>GetItem(){ inline std::weak_ptr<Item>GetItem(){
return Inventory::GetItem(invRef.at(inventoryIndex)->ActualName()); return invRef.at(inventoryIndex);
} }
//Returns true if the item has been consumed completely and there are 0 remaining of that type in our inventory. //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){ inline bool UseItem(uint32_t amt=1){

@ -153,7 +153,7 @@ protected:
virtual inline void DrawDecal(ViewPort&window,bool focused)override{ virtual inline void DrawDecal(ViewPort&window,bool focused)override{
MenuIconButton::DrawDecal(window,focused); MenuIconButton::DrawDecal(window,focused);
if(valid&&!hideQty){ if(valid&&!hideQty){
if(!ISBLANK(itemRef)){ if(!ISBLANK(itemRef)&&!itemRef.lock()->IsEquippable()){
std::string quantityText="x"+std::to_string(itemRef.lock()->Amt()); std::string quantityText="x"+std::to_string(itemRef.lock()->Amt());
vf2d quantityTextScale=rect.size/48.f; vf2d quantityTextScale=rect.size/48.f;
vf2d textSize=vf2d(game->GetTextSizeProp(quantityText))*quantityTextScale; vf2d textSize=vf2d(game->GetTextSizeProp(quantityText))*quantityTextScale;

@ -185,8 +185,8 @@ void Merchant::PurchaseItem(IT item,uint32_t amt){
Inventory::AddItem(item,amt); Inventory::AddItem(item,amt);
game->GetPlayer()->SetMoney(game->GetPlayer()->GetMoney()-totalCost); game->GetPlayer()->SetMoney(game->GetPlayer()->GetMoney()-totalCost);
}; };
void Merchant::SellItem(IT item,uint32_t amt){ void Merchant::SellItem(std::weak_ptr<Item>item,uint32_t amt){
sellFunctionPrimed.Validate(item,amt); sellFunctionPrimed.Validate(item.lock()->ActualName(),amt);
uint32_t totalCost=0U; uint32_t totalCost=0U;
bool itemFound=false; bool itemFound=false;
@ -199,10 +199,10 @@ void Merchant::SellItem(IT item,uint32_t amt){
break; break;
} }
} }
if(!itemFound&&ITEM_DATA[item].CanBePurchased()){ if(!itemFound&&item.lock()->CanBePurchased()){
AddItem(item,amt); //This may not be a feature we include in future versions of the game. For now let's allow it. AddItem(item.lock()->ActualName(),amt); //This may not be a feature we include in future versions of the game. For now let's allow it.
} }
totalCost=ITEM_DATA[item].GetSellValue()*amt; totalCost=item.lock()->SellValue()*amt;
Inventory::RemoveItem(item,amt); Inventory::RemoveItem(item,amt);
game->GetPlayer()->SetMoney(game->GetPlayer()->GetMoney()+totalCost); game->GetPlayer()->SetMoney(game->GetPlayer()->GetMoney()+totalCost);

@ -55,7 +55,7 @@ public:
bool CanPurchaseItem(IT item,uint32_t amt=1U)const; bool CanPurchaseItem(IT item,uint32_t amt=1U)const;
bool CanSellItem(IT item,uint32_t amt=1U)const; bool CanSellItem(IT item,uint32_t amt=1U)const;
void PurchaseItem(IT item,uint32_t amt=1U); void PurchaseItem(IT item,uint32_t amt=1U);
void SellItem(IT item,uint32_t amt=1U); void SellItem(std::weak_ptr<Item>,uint32_t amt=1U);
public: public:
static void Initialize(); static void Initialize();
static Merchant&AddMerchant(Chapter chapter); static Merchant&AddMerchant(Chapter chapter);

@ -42,6 +42,7 @@ All rights reserved.
#include "MenuItemItemButton.h" #include "MenuItemItemButton.h"
#include "MenuComponent.h" #include "MenuComponent.h"
#include "PlayerMoneyLabel.h" #include "PlayerMoneyLabel.h"
#include "ItemMenuLabel.h"
INCLUDE_game INCLUDE_game
INCLUDE_ITEM_CATEGORIES INCLUDE_ITEM_CATEGORIES
@ -153,7 +154,7 @@ void Menu::InitializeMerchantWindow(){
[](MenuFuncData data){ [](MenuFuncData data){
RowItemDisplay*item=DYNAMIC_CAST<RowItemDisplay*>(data.component); RowItemDisplay*item=DYNAMIC_CAST<RowItemDisplay*>(data.component);
if(item->GetItem().lock()->CanBeSold()){ if(item->GetItem().lock()->CanBeSold()){
Component<MenuLabel>(SELL_ITEM,"Item Sell Header")->S(A::ITEM_NAME)=item->GetItem().lock()->ActualName(); Component<ItemMenuLabel>(SELL_ITEM,"Item Sell Header")->SetItem(item->GetItem());
Component<MenuLabel>(SELL_ITEM,"Price per item Amount Label")->SetLabel(std::to_string(item->GetItem().lock()->SellValue())); Component<MenuLabel>(SELL_ITEM,"Price per item Amount Label")->SetLabel(std::to_string(item->GetItem().lock()->SellValue()));
Component<MenuLabel>(SELL_ITEM,"Amount to sell Amount Label")->SetLabel("1"); Component<MenuLabel>(SELL_ITEM,"Amount to sell Amount Label")->SetLabel("1");
Component<MenuLabel>(SELL_ITEM,"Total Price Amount Label")->SetLabel(std::to_string(item->GetItem().lock()->SellValue())); Component<MenuLabel>(SELL_ITEM,"Total Price Amount Label")->SetLabel(std::to_string(item->GetItem().lock()->SellValue()));

@ -37,7 +37,7 @@ All rights reserved.
#pragma endregion #pragma endregion
#include "Menu.h" #include "Menu.h"
#include "MenuLabel.h" #include "ItemMenuLabel.h"
using A=Attribute; using A=Attribute;
@ -52,8 +52,8 @@ void Menu::InitializeSellItemWindow(){
Component<MenuLabel>(SELL_ITEM,"Amount to sell Amount Label")->SetLabel(std::to_string(qty)); Component<MenuLabel>(SELL_ITEM,"Amount to sell Amount Label")->SetLabel(std::to_string(qty));
Merchant&merchant=Merchant::GetCurrentTravelingMerchant(); Merchant&merchant=Merchant::GetCurrentTravelingMerchant();
const std::string&item=Component<MenuLabel>(SELL_ITEM,"Item Sell Header")->GetString(A::ITEM_NAME); const std::weak_ptr<Item>item=Component<ItemMenuLabel>(SELL_ITEM,"Item Sell Header")->GetItem();
bool canSell=merchant.CanSellItem(item,GetQuantity()); bool canSell=merchant.CanSellItem(item.lock()->ActualName(),GetQuantity());
std::string colorCode=""; std::string colorCode="";
if(!canSell)colorCode="#FF0000"; if(!canSell)colorCode="#FF0000";
@ -61,7 +61,7 @@ void Menu::InitializeSellItemWindow(){
Component<MenuComponent>(SELL_ITEM,"Sell Button")->SetGrayedOut(!canSell); Component<MenuComponent>(SELL_ITEM,"Sell Button")->SetGrayedOut(!canSell);
}; };
sellItemWindow->ADD("Item Sell Header",MenuLabel)({{2,2},{188,12}},"Selling ",1,ComponentAttr::OUTLINE|ComponentAttr::BACKGROUND|ComponentAttr::SHADOW|ComponentAttr::FIT_TO_LABEL)END; 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("Price Per Item Label",MenuLabel)({{4,18},{188,12}},"Price Per Item",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)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("Amount to Sell Label",MenuLabel)({{4,34},{188,12}},"Amount to Sell",1.0f,ComponentAttr::LEFT_ALIGN|ComponentAttr::SHADOW)END;
@ -83,8 +83,7 @@ void Menu::InitializeSellItemWindow(){
sellItemWindow->ADD("Sell Button",MenuComponent)({{sellItemWindow->size.x/2+18,70},{64,12}},"Sell",[&](MenuFuncData data){ sellItemWindow->ADD("Sell Button",MenuComponent)({{sellItemWindow->size.x/2+18,70},{64,12}},"Sell",[&](MenuFuncData data){
Merchant&merchant=Merchant::GetCurrentTravelingMerchant(); Merchant&merchant=Merchant::GetCurrentTravelingMerchant();
const std::string&item=Component<MenuLabel>(SELL_ITEM,"Item Sell Header")->GetString(A::ITEM_NAME); merchant.SellItem(Component<ItemMenuLabel>(SELL_ITEM,"Item Sell Header")->GetItem(),GetQuantity());
merchant.SellItem(item,GetQuantity());
Menu::CloseMenu(); Menu::CloseMenu();
return true; return true;
})END; })END;

@ -1,6 +1,5 @@
January 1st January 1st
=========== ===========
Blacksmith Item Crafting Screen
Randomized Item Stats Randomized Item Stats
- Get Item may return multiples of the same item. - Get Item may return multiples of the same item.
- Removing an item with multiples require a specific item to be selected. - Removing an item with multiples require a specific item to be selected.

@ -39,7 +39,7 @@ All rights reserved.
#define VERSION_MAJOR 0 #define VERSION_MAJOR 0
#define VERSION_MINOR 2 #define VERSION_MINOR 2
#define VERSION_PATCH 1 #define VERSION_PATCH 1
#define VERSION_BUILD 5079 #define VERSION_BUILD 5110
#define stringify(a) stringify_(a) #define stringify(a) stringify_(a)
#define stringify_(a) #a #define stringify_(a) #a

Loading…
Cancel
Save