#include "Item.h" #include "safemap.h" #include "DEFINES.h" #include "Crawler.h" #include "Menu.h" INCLUDE_game INCLUDE_DATA INCLUDE_GFX safemap<std::string,ItemInfo>ITEM_DATA; safemap<std::string,ItemScript>ITEM_SCRIPTS; safemap<std::string,std::set<std::string>>ITEM_CATEGORIES; Item Item::BLANK; std::map<IT,Item>Inventory::_inventory; std::map<ITCategory,std::vector<IT>>Inventory::sortedInv; ItemInfo::ItemInfo() :customProps({nullptr,nullptr}),img(nullptr){} void ItemInfo::InitializeItems(){ InitializeScripts(); for(auto&key:DATA["ItemCategory"].GetKeys()){ ITEM_CATEGORIES[key.first]; Inventory::sortedInv[key.first]; Menu::inventoryListeners[key.first]; } for(auto&key:DATA["ItemDatabase"].GetKeys()){ std::string imgPath="assets/"+"item_img_directory"_S+key.first+".png"; Renderable&img=GFX["item_img_directory"_S+key.first+".png"]; img.Load(imgPath); std::string scriptName="",description="",category=""; for(auto&itemKey:DATA["ItemDatabase"][key.first].GetKeys()){ std::string keyName=itemKey.first; if(keyName=="Description"){ description=DATA["ItemDatabase"][key.first][keyName].GetString(); }else if(keyName=="ItemCategory"){ category=DATA["ItemDatabase"][key.first][keyName].GetString(); }else if(keyName=="ItemScript"){ scriptName=DATA["ItemDatabase"][key.first][keyName].GetString(); }else{ //THis is a custom override modifier for a script. NO-OP } } if(scriptName!=""){ if(!ITEM_SCRIPTS.count(scriptName)){ std::cout<<"Could not load script "<<scriptName<<" for Item "<<key.first<<"!"<<std::endl; throw; } } ItemInfo&it=ITEM_DATA[key.first]; it.name=key.first; it.description=description; it.category=category; if(!ITEM_CATEGORIES.count(it.category)){ std::cout<<"WARNING! Tried to add item "<<it.name<<" to category "<<it.category<<" which does not exist!"<<std::endl; throw; } ITEM_CATEGORIES.at(it.category).insert(it.name); it.img=img.Decal(); ItemProps&props=it.customProps; if(scriptName!=""){ props.scriptProps=&DATA["ItemScript"][scriptName]; props.customProps=&DATA["ItemDatabase"][key.first]; } it.useFunc=scriptName; } ITEM_DATA.SetInitialized(); ITEM_CATEGORIES.SetInitialized(); Menu::inventoryListeners.SetInitialized(); std::cout<<ITEM_DATA.size()<<" items have been loaded."<<std::endl; std::cout<<ITEM_CATEGORIES.size()<<" item categories have been loaded."<<std::endl; } ItemProps::ItemProps(utils::datafile*scriptProps,utils::datafile*customProps) :scriptProps(scriptProps),customProps(customProps){} int ItemProps::GetIntProp(std::string prop){ if(customProps->HasProperty(prop)) return (*customProps)[prop].GetInt(); else return (*scriptProps)[prop].GetInt(); }; float ItemProps::GetFloatProp(std::string prop){ if(customProps->HasProperty(prop)) return (*customProps)[prop].GetReal(); else return (*scriptProps)[prop].GetReal(); }; std::string ItemProps::GetStringProp(std::string prop){ if(customProps->HasProperty(prop)) return (*customProps)[prop].GetString(); else return (*scriptProps)[prop].GetString(); }; void ItemInfo::InitializeScripts(){ ITEM_SCRIPTS["Restore"]=[](Crawler*game,ItemProps props){ game->GetPlayer()->Heal(props.GetIntProp("HP Restore")); game->GetPlayer()->Heal(game->GetPlayer()->GetMaxHealth()*props.GetIntProp("HP % Restore")/100.f); game->GetPlayer()->RestoreMana(props.GetIntProp("MP Restore")); game->GetPlayer()->RestoreMana(game->GetPlayer()->GetMaxMana()*props.GetIntProp("MP % Restore")/100.f); return true; }; ITEM_SCRIPTS.SetInitialized(); std::cout<<ITEM_SCRIPTS.size()<<" item scripts have been loaded."<<std::endl; } Item::Item() :amt(0),it(nullptr){} Item::Item(uint32_t amt,IT item) :amt(amt),it(&ITEM_DATA.at(item)){} void Inventory::AddItem(IT it,uint32_t amt){ //There are two places to manipulate items in (Both the sorted inventory and the actual inventory) if(!_inventory.count(it)){ _inventory[it]=Item{amt,it}; InsertIntoSortedInv(it); }else{ _inventory.at(it).amt+=amt; } } Item Inventory::GetItem(IT it){ if(!_inventory.count(it))return Item::BLANK; return _inventory.at(it); } uint32_t Inventory::GetItemCount(IT it){ if(!_inventory.count(it)){ return 0; }else{ return _inventory.at(it).Amt(); } } void Inventory::UseItem(IT it,uint32_t amt){ if(!_inventory.count(it))return; //There are two places to manipulate items in (Both the sorted inventory and the actual inventory) for(int i=0;i<amt;i++){ if(ExecuteAction(it)){ RemoveItem(it); } } } void Inventory::RemoveItem(IT it,uint32_t amt){ //There are two places to manipulate items in (Both the sorted inventory and the actual inventory) if(!_inventory.count(it))return; if(amt>=_inventory.at(it).Amt()){ int count=0; std::vector<IT>&sortedList=sortedInv.at(_inventory.at(it).Category()); for(std::string&itemName:sortedList){ if(itemName==it)break; count++; } sortedList.erase(sortedList.begin()+count); _inventory.erase(it); ITCategory cat=ITEM_DATA[it].category; //Callback for GUI inventories. Menu::InventorySlotsUpdated(cat); }else{ _inventory.at(it).amt-=amt; } } std::vector<IT>&Inventory::get(ITCategory itemCategory){ return sortedInv.at(itemCategory); } void Inventory::InsertIntoSortedInv(IT item){ sortedInv.at(ITEM_DATA[item].category).push_back(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); } bool Inventory::ExecuteAction(IT item){ if(ITEM_SCRIPTS.count(ITEM_DATA.at(item).useFunc)){ return ITEM_SCRIPTS.at(ITEM_DATA.at(item).useFunc)(game,ITEM_DATA[item].customProps); }else{ return false; } } bool Inventory::SwapItems(ITCategory itemCategory,uint32_t slot1,uint32_t slot2){ std::vector<IT>&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)); } IT&item1=inv.at(slot1); IT&item2=inv.at(slot2); std::swap(item1,item2); return true; } uint32_t Item::Amt(){ return amt; }; std::string Item::Name(){ return it->Name(); }; std::string Item::Description(){ return it->Description(); }; ITCategory Item::Category(){ return it->Category(); }; Decal*Item::Decal(){ return it->Decal(); }; ItemScript&Item::OnUseAction(){ return it->OnUseAction(); }; std::string ItemInfo::Name(){ return name; }; std::string ItemInfo::Description(){ return description; }; ITCategory ItemInfo::Category(){ return category; }; Decal*ItemInfo::Decal(){ return img; }; ItemScript&ItemInfo::OnUseAction(){ return ITEM_SCRIPTS.at(useFunc); }; bool Item::IsBlank(){ return amt==0||it==nullptr; }