Implemented ability to craft weapons/armor. Sorting all equipment by tier / type. Fixed bug with not properly setting available chapter for crafting on items with multiple enhancement levels. Fixed bugs related to adding crafting to weapons / armor (side effects applied directly to consumable items), fix stage loot/monster loot displays not properly updating when collecting items. Made old items properly convert to newer item names when being read in (constructor for the IT data type is no longer an enum and instead does the conversion automatically). This type now has implicit conversion from a std::string so is still a highly flexible typing like before. Release build 6677.

pull/35/head
sigonasr2 10 months ago
parent d904ef7e91
commit 0aea7beb83
  1. 10
      Adventures in Lestoria/Adventures in Lestoria.vcxproj
  2. 9
      Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters
  3. 29
      Adventures in Lestoria/AdventuresInLestoria.cpp
  4. 25
      Adventures in Lestoria/BlacksmithCraftingWindow.cpp
  5. 6
      Adventures in Lestoria/CraftItemWindow.cpp
  6. 3
      Adventures in Lestoria/DEFINES.h
  7. 9
      Adventures in Lestoria/EnhancementStatsLabel.h
  8. 8
      Adventures in Lestoria/FunctionPriming.h
  9. 70
      Adventures in Lestoria/IT.cpp
  10. 32
      Adventures in Lestoria/IT.h
  11. 12
      Adventures in Lestoria/InventoryCreator.cpp
  12. 76
      Adventures in Lestoria/Item.cpp
  13. 16
      Adventures in Lestoria/Item.h
  14. 1
      Adventures in Lestoria/LevelCompleteWindow.cpp
  15. 1
      Adventures in Lestoria/Merchant.h
  16. 14
      Adventures in Lestoria/Player.h
  17. 4
      Adventures in Lestoria/RequiredMaterialsList.h
  18. 4
      Adventures in Lestoria/State_GameHub.cpp
  19. 1
      Adventures in Lestoria/TODO.txt
  20. 2
      Adventures in Lestoria/Version.h
  21. 2
      Adventures in Lestoria/assets/config/items/Weapons.txt
  22. 5
      Adventures in Lestoria/assets/config/items/items.txt
  23. BIN
      x64/Release/Adventures in Lestoria.exe

@ -359,15 +359,15 @@
<SubType>
</SubType>
</ClInclude>
<ClInclude Include="ItemMapData.h">
<ClInclude Include="IT.h">
<SubType>
</SubType>
</ClInclude>
<ClInclude Include="ItemMenuLabel.h">
<ClInclude Include="ItemMapData.h">
<SubType>
</SubType>
</ClInclude>
<ClInclude Include="ItemNameConverter.h">
<ClInclude Include="ItemMenuLabel.h">
<SubType>
</SubType>
</ClInclude>
@ -599,6 +599,10 @@
<SubType>
</SubType>
</ClCompile>
<ClCompile Include="IT.cpp">
<SubType>
</SubType>
</ClCompile>
<ClCompile Include="Item.cpp" />
<ClCompile Include="ItemDrop.cpp" />
<ClCompile Include="ItemLoadoutWindow.cpp" />

@ -423,9 +423,6 @@
<ClInclude Include="MenuType.h">
<Filter>Header Files\Interface</Filter>
</ClInclude>
<ClInclude Include="ItemNameConverter.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ItemMapData.h">
<Filter>Header Files</Filter>
</ClInclude>
@ -447,6 +444,9 @@
<ClInclude Include="State_GameHub.h">
<Filter>Header Files\State</Filter>
</ClInclude>
<ClInclude Include="IT.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Player.cpp">
@ -776,6 +776,9 @@
<ClCompile Include="ShermanWindow.cpp">
<Filter>Source Files\Interface</Filter>
</ClCompile>
<ClCompile Include="IT.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="cpp.hint" />

@ -243,33 +243,8 @@ bool AiL::OnUserCreate(){
Menu::InitializeMenus();
Inventory::AddItem("Minor Health Potion",16);
Inventory::AddItem("Bandages",10);
Inventory::AddItem("Green Slime Remains",40);
Inventory::AddItem("Blue Slime Remains",22);
Inventory::AddItem("Copper Armor");
Inventory::AddItem("Copper Pants");
Inventory::AddItem("Copper Helmet");
Inventory::AddItem("Copper Shoes");
Inventory::AddItem("Shell Helmet");
Inventory::AddItem("Shell Armor");
Inventory::AddItem("Shell Armor");
Inventory::AddItem("Shell Armor");
Inventory::AddItem("Bone Armor");
Inventory::AddItem("Shell Gloves");
Inventory::AddItem("Shell Gloves",3);
Inventory::AddItem("Shell Shoes");
Inventory::AddItem("Bone Pants");
Inventory::AddItem("Bone Gloves");
Inventory::AddItem("Elixir of Bear Strength",3);
Inventory::AddItem("Leather Helmet");
Inventory::AddItem("Leather Pants");
Inventory::AddItem("Leather Gloves");
Inventory::AddItem("Leather Shoes");
Inventory::AddItem("Wooden Sword");
Inventory::AddItem("Laser Sword");
Inventory::AddItem("Shell Sword");
Inventory::AddItem("Ring of the Slime King",3);
Inventory::AddItem("Minor Health Potion"s,3);
Inventory::AddItem("Bandages"s,10);
Audio::Initialize();
EnvironmentalAudio::Initialize();

@ -142,14 +142,25 @@ void Menu::InitializeBlacksmithCraftingWindow(){
const std::weak_ptr<Item>item=comp.lock()->GetItem();
std::string label="";
if(item.lock()->EnhancementIsPossible()&&item.lock()->GetEnhancementInfo().size()>item.lock()->EnhancementLevel()+1){
label=std::format("Level {} ->#00AA00 {}",item.lock()->EnhancementLevel(),item.lock()->EnhancementLevel()+1);
if(Inventory::GetItemCount(item.lock()->ActualName())==0){ //If we don't own the item we have to create it first.
if(item.lock()->EnhancementIsPossible()&&item.lock()->GetEnhancementInfo().size()>item.lock()->EnhancementLevel()+1){
label="";
}
Component<MenuLabel>(CRAFT_ITEM,"Enhancement Level Header")->SetLabel(label);
Component<MenuLabel>(CRAFT_ITEM,"Item Name Header")->SetLabel(std::format("Crafting {}",item.lock()->DisplayName()));
Component<EnhancementStatsLabel>(CRAFT_ITEM,"Enhancement Stats Label")->SetItem(item);
Component<RequiredMaterialsList>(CRAFT_ITEM,"Required Materials List")->SetItem(item);
Component<MenuComponent>(CRAFT_ITEM,"Craft Button")->SetGrayedOut(!item.lock()->CanEnhanceItem());
}else{ //We will open the menu that lets us enhance by one level.
if(item.lock()->EnhancementIsPossible()&&item.lock()->GetEnhancementInfo().size()>item.lock()->EnhancementLevel()+1){
label=std::format("Level {} ->#00AA00 {}",item.lock()->EnhancementLevel(),item.lock()->EnhancementLevel()+1);
}
Component<MenuLabel>(CRAFT_ITEM,"Enhancement Level Header")->SetLabel(label);
Component<MenuLabel>(CRAFT_ITEM,"Item Name Header")->SetLabel(std::format("Enhancing {}",item.lock()->DisplayName()));
Component<EnhancementStatsLabel>(CRAFT_ITEM,"Enhancement Stats Label")->SetItem(item);
Component<RequiredMaterialsList>(CRAFT_ITEM,"Required Materials List")->SetItem(item);
Component<MenuComponent>(CRAFT_ITEM,"Craft Button")->SetGrayedOut(!item.lock()->CanEnhanceItem());
}
Component<MenuLabel>(CRAFT_ITEM,"Enhancement Level Header")->SetLabel(label);
Component<MenuLabel>(CRAFT_ITEM,"Item Name Header")->SetLabel(std::format("Crafting {}",item.lock()->DisplayName()));
Component<EnhancementStatsLabel>(CRAFT_ITEM,"Enhancement Stats Label")->SetItem(item);
Component<RequiredMaterialsList>(CRAFT_ITEM,"Required Materials List")->SetItem(item);
Component<MenuComponent>(CRAFT_ITEM,"Craft Button")->SetGrayedOut(!item.lock()->CanEnhanceItem());
return true;
},
[](MenuFuncData data){

@ -56,10 +56,12 @@ void Menu::InitializeCraftItemWindow(){
craftItemWindow->ADD("Back Button",MenuComponent)(geom2d::rect<float>{{36,116},{48,12}},"Back",[](MenuFuncData data){Menu::CloseMenu();return true;})END;
craftItemWindow->ADD("Craft Button",MenuComponent)(geom2d::rect<float>{{craftItemWindow->size.x-84,116},{48,12}},"Craft",[](MenuFuncData data){
const std::weak_ptr<Item>item=Component<EnhancementStatsLabel>(data.menu.GetType(),"Enhancement Stats Label")->GetItem();
std::weak_ptr<Item>item=Component<EnhancementStatsLabel>(data.menu.GetType(),"Enhancement Stats Label")->GetItem();
if(item.lock()->CanEnhanceItem()){
if(Inventory::GetItemCount(item.lock()->ActualName())==0){ //We don't own this item, so we need to give the player this item and refresh the blacksmith's inventory.
Inventory::AddItem(item.lock()->ActualName());
item=Inventory::AddItem(item.lock()->ActualName());
Component<EnhancementStatsLabel>(CRAFT_ITEM,"Enhancement Stats Label")->SetItem(item);
Component<RequiredMaterialsList>(CRAFT_ITEM,"Required Materials List")->SetItem(item); //Update the item refs in the enhancement level screen to now display the correct item.
Inventory::UpdateBlacksmithInventoryLists();
}else{ //Since we already own this equipment, just enhance it.
item.lock()->EnhanceItem();

@ -57,6 +57,7 @@ using BackdropName=std::string;
#define INCLUDE_ITEM_CATEGORIES extern safemap<std::string,std::set<std::string>>ITEM_CATEGORIES;
#define DO_NOTHING [](MenuFuncData data){return true;}
#define INCLUDE_WINDOW_SIZE extern vi2d WINDOW_SIZE;
#define INCLUDE_ITEM_CONVERSIONS extern safemap<std::string,IT>ITEM_CONVERSIONS;
#define INCLUDE_BACKDROP_DATA extern std::map<BackdropName,Renderable>BACKDROP_DATA;
@ -75,7 +76,7 @@ class::class() \
class::class(Player*player) \
:Player::Player(player){} \
Class class::GetClass(){return cl;} \
std::string class::GetClassName(){return name;} \
const std::string&class::GetClassName(){return name;} \
Ability&class::GetRightClickAbility(){return rightClickAbility;}; \
Ability&class::GetAbility1(){return ability1;}; \
Ability&class::GetAbility2(){return ability2;}; \

@ -90,16 +90,13 @@ protected:
std::string percentageSign=attr.DisplayAsPercent()?"%":"";
if(Inventory::GetItemCount(itemRef.lock()->ActualName())==0){ //This item hasn't been created yet, so just show that we are developing the item first.
window.DrawShadowStringDecal(drawPos+vf2d{maxAttributeLabelSize+4+24,yOffset},std::format("{:<5}",
attr.ShowAsDecimal()?std::format("{:>4.2f}{}",value,percentageSign):std::format("{}{}",value,percentageSign),
nextStageValue!=0?
attr.ShowAsDecimal()?std::format("{:<4.2f}{}",nextStageValue,percentageSign):std::format("{}{}",nextStageValue,percentageSign)
:"MAX"),
window.DrawShadowStringDecal(drawPos+vf2d{maxAttributeLabelSize+4+24,yOffset},std::format("{:<5}",(
(attr.ShowAsDecimal()?std::format("{:>4.2f}{}",value,percentageSign):std::format("{}{}",value,percentageSign)))),
WHITE,BLACK,adjustedScale,fitToLabel?std::numeric_limits<float>::max():rect.size.x,1.0f);
}else{ //This item is getting enhanced to the next level.
window.DrawShadowStringDecal(drawPos+vf2d{maxAttributeLabelSize+4+24,yOffset},std::format("{:>5} ->#00AA00 {:<5}",
attr.ShowAsDecimal()?std::format("{:>4.2f}{}",value,percentageSign):std::format("{}{}",value,percentageSign),
nextStageValue!=0?
nextEnhanceLevel!="Item.Item Max Enhancement Level"_I?
attr.ShowAsDecimal()?std::format("{:<4.2f}{}",nextStageValue,percentageSign):std::format("{}{}",nextStageValue,percentageSign)
:"MAX"),
WHITE,BLACK,adjustedScale,fitToLabel?std::numeric_limits<float>::max():rect.size.x,1.0f);

@ -38,7 +38,9 @@ All rights reserved.
#pragma once
#include "Error.h"
#include <format>
using IT=std::string;
#include "IT.h"
using namespace std::literals;
struct FunctionPrimingData{
bool primed=false;
@ -51,7 +53,7 @@ struct FunctionPrimingData{
};
struct MerchantFunctionPrimingData:public FunctionPrimingData{
IT item="";
IT item=""s;
uint32_t amt=0;
inline MerchantFunctionPrimingData(std::string dependentFunction)
:FunctionPrimingData(dependentFunction){}
@ -67,7 +69,7 @@ struct MerchantFunctionPrimingData:public FunctionPrimingData{
};
struct ItemEnhancementFunctionPrimingData:public FunctionPrimingData{
IT item="";
IT item=""s;
uint8_t enhancementLevel=0;
uint8_t qty=0;
inline ItemEnhancementFunctionPrimingData(std::string dependentFunction)

@ -0,0 +1,70 @@
#pragma region License
/*
License (OLC-3)
~~~~~~~~~~~~~~~
Copyright 2024 Joshua Sigona <sigonasr2@gmail.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
#include "DEFINES.h"
#include "IT.h"
#include "Item.h"
INCLUDE_ITEM_CONVERSIONS
IT::IT():itemName(""){}
IT::IT(std::string name)
:itemName(name){
if(ITEM_CONVERSIONS.count(name)){
itemName=ITEM_CONVERSIONS.at(name); //Convert the item if it's using an old name.
}
}
IT::operator std::string(){
return itemName;
}
std::ostream&operator<<(std::ostream&rhs,IT&item){
rhs<<item.itemName;
return rhs;
}
const bool IT::operator==(const std::shared_ptr<Item>&rhs){
return itemName==rhs->ActualName();
}
const bool IT::operator==(const std::weak_ptr<Item>&rhs){
return !rhs.expired()&&itemName==rhs.lock()->ActualName();
}
const bool operator==(const IT&lhs,const IT&rhs){
return lhs.itemName==rhs.itemName;
}
const bool operator<(const IT&lhs,const IT&rhs){
return lhs.itemName<rhs.itemName;
}

@ -35,4 +35,34 @@ Project (www.freetype.org). Please see LICENSE_FT.txt for more information.
All rights reserved.
*/
#pragma endregion
#pragma once
#pragma once
#include <string>
#include <memory>
#include <format>
class Item;
class IT{
friend struct std::formatter<IT>;
std::string itemName="";
public:
IT();
IT(std::string name);
operator std::string();
const bool operator==(const std::shared_ptr<Item>&rhs);
const bool operator==(const std::weak_ptr<Item>&rhs);
friend std::ostream&operator<<(std::ostream&rhs,IT&item);
friend const bool operator==(const IT&lhs,const IT&rhs);
friend const bool operator<(const IT&lhs,const IT&rhs);
};
template <>
struct std::formatter<IT> {
constexpr auto parse(std::format_parse_context&ctx) {
return ctx.begin();
}
auto format(const IT&item,std::format_context&ctx) const {
return std::format_to(ctx.out(),"{}",item.itemName);
}
};

@ -146,7 +146,11 @@ std::function<void(InventoryScrollableWindowComponent&component,ITCategory cat)>
[](InventoryScrollableWindowComponent&component,ITCategory cat){
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->IsWeapon();});
std::copy_if(Inventory::blacksmithInventory.begin(),Inventory::blacksmithInventory.end(),std::back_inserter(weapons),[](std::shared_ptr<Item>item){return item->IsWeapon();});
std::copy_if(Inventory::blacksmithInventory.begin(),Inventory::blacksmithInventory.end(),std::back_inserter(weapons),[](std::shared_ptr<Item>item){return game->GetCurrentChapter()>=item->GetEnhancementInfo().AvailableChapter()&&item->GetClass()==game->GetPlayer()->GetClassName()&&item->IsWeapon();});
std::sort(weapons.begin(),weapons.end(),[](const std::weak_ptr<Item>&it1,const std::weak_ptr<Item>&it2){
return ItemSortRules::GetItemSortRanking(it1)<ItemSortRules::GetItemSortRanking(it2);
});
RowInventoryScrollableWindowComponent*c=DYNAMIC_CAST<RowInventoryScrollableWindowComponent*>(&component);
@ -183,7 +187,11 @@ std::function<void(InventoryScrollableWindowComponent&component,ITCategory cat)>
[](InventoryScrollableWindowComponent&component,ITCategory cat){
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->IsArmor();});
std::copy_if(Inventory::blacksmithInventory.begin(),Inventory::blacksmithInventory.end(),std::back_inserter(armor),[](std::shared_ptr<Item>item){return item->IsArmor();});
std::copy_if(Inventory::blacksmithInventory.begin(),Inventory::blacksmithInventory.end(),std::back_inserter(armor),[](std::shared_ptr<Item>item){return game->GetCurrentChapter()>=item->GetEnhancementInfo().AvailableChapter()&&item->GetClass()==game->GetPlayer()->GetClassName()&&item->IsArmor();});
std::sort(armor.begin(),armor.end(),[](const std::weak_ptr<Item>&it1,const std::weak_ptr<Item>&it2){
return ItemSortRules::GetItemSortRanking(it1)<ItemSortRules::GetItemSortRanking(it2);
});
RowInventoryScrollableWindowComponent*c=DYNAMIC_CAST<RowInventoryScrollableWindowComponent*>(&component);

@ -69,11 +69,20 @@ int Item::IsBlankStaticCallCounter=0;
safemap<int,float>Stats::maxDamageReductionTable;
ItemEnhancementFunctionPrimingData Item::enhanceFunctionPrimed("CanEnhanceItem()");
std::vector<std::shared_ptr<Item>>ItemInfo::craftableConsumables;
std::vector<std::string>ItemSortRules::primarySort;
std::vector<std::string>ItemSortRules::secondarySort;
ItemInfo::ItemInfo()
:customProps({nullptr,nullptr}),img(nullptr){}
void ItemInfo::InitializeItems(){
for(const std::string&data:DATA.GetProperty("Item.Equipment Sort Order Primary").GetValues()){
ItemSortRules::primarySort.push_back(data);
}
for(const std::string&data:DATA.GetProperty("Item.Equipment Sort Order Secondary").GetValues()){
ItemSortRules::secondarySort.push_back(data);
}
for(int i=int(EquipSlot::HELMET);i<=int(EquipSlot::RING2);i<<=1){
Inventory::equipment[EquipSlot(i)]=Item::BLANK;
}
@ -171,8 +180,8 @@ void ItemInfo::InitializeItems(){
if(data[key].HasProperty("StatValues[0]")){ //This means this has enhancement levels.
EnhancementInfo enhancementStats;
uint8_t availableChapter=1;
for(int enhancementLevel=0;enhancementLevel<=10;enhancementLevel++){
uint8_t availableChapter=1;
datafile&dat=data[key]["StatValues["+std::to_string(enhancementLevel)+"]"];
for(int attrIndex=0;ItemAttribute&attr:statValueList){
enhancementStats.SetAttribute(enhancementLevel,attr,dat.GetReal(attrIndex));
@ -295,6 +304,13 @@ void ItemInfo::InitializeItems(){
if(it.Category()=="Accessories"&&it.IsArmor())ERR(std::format("WARNING! {} is in the Accessories Category, but is considered Armor!",it.Name()))
if(it.Category()=="Accessories"&&!it.IsAccessory())ERR(std::format("WARNING! {} is in the Accessories Category, but not considered an Accessory!",it.Name()))
#pragma endregion
#pragma region Equipment Sort Rules Verification Tests
if(category=="Equipment"){
if(std::find_if(ItemSortRules::primarySort.begin(),ItemSortRules::primarySort.end(),[&](const std::string&sort){return key.find(sort)!=std::string::npos;})==ItemSortRules::primarySort.end())ERR(std::format("WARNING! Item {} does not have valid equipment sorting primary rule! Check items.txt config key: 'Equipment Sort Order Primary'!",key))
if(std::find_if(ItemSortRules::secondarySort.begin(),ItemSortRules::secondarySort.end(),[&](const std::string&sort){return key.find(sort)!=std::string::npos;})==ItemSortRules::secondarySort.end())ERR(std::format("WARNING! Item {} does not have valid equipment sorting secondary rule! Check items.txt config key: 'Equipment Sort Order Secondary'!",key))
}
#pragma endregion
}
};
@ -408,28 +424,19 @@ Item::Item()
:amt(0),it(nullptr),enhancementLevel(0){}
Item::Item(uint32_t amt,IT item,uint8_t enhancementLevel)
:amt(amt),enhancementLevel(enhancementLevel){
if(ITEM_CONVERSIONS.count(item)){
it=&ITEM_DATA.at(ITEM_CONVERSIONS[item]); //Convert the item if it's using an old name.
}else{
it=&ITEM_DATA.at(item);
}
}
:amt(amt),enhancementLevel(enhancementLevel),it(&ITEM_DATA.at(item)){}
std::weak_ptr<Item>Inventory::AddItem(IT it,uint32_t amt,bool monsterDrop){
if(ITEM_CONVERSIONS.count(it)){
it=ITEM_CONVERSIONS[it]; //Convert the item if it's using an old name.
}
if(!ITEM_DATA.count(it))ERR("Item "<<std::quoted(it)<<" does not exist in Item Database!");
if(!ITEM_DATA.count(it))ERR("Item "<<it<<" does not exist in Item Database!");
std::weak_ptr<Item>itemPtr;
std::shared_ptr<Item>newItem;
if(ITEM_DATA[it].IsEquippable()){ //Do not stack equips!
for(uint32_t i=0;i<amt;i++){
std::shared_ptr<Item>newItem=(*_inventory.insert({it,std::make_shared<Item>(1,it)})).second;
newItem=(*_inventory.insert({it,std::make_shared<Item>(1,it)})).second;
newItem->RandomizeStats();
InsertIntoSortedInv(newItem);
InsertIntoStageInventoryCategory(newItem,monsterDrop);
itemPtr=newItem;
}
goto SkipAddingStackableItem;
@ -437,9 +444,8 @@ std::weak_ptr<Item>Inventory::AddItem(IT it,uint32_t amt,bool monsterDrop){
else
//There are two places to manipulate items in (Both the sorted inventory and the actual inventory)
if(!_inventory.count(it)){
std::shared_ptr<Item>newItem=(*_inventory.insert({it,std::make_shared<Item>(amt,it)})).second;
newItem=(*_inventory.insert({it,std::make_shared<Item>(amt,it)})).second;
InsertIntoSortedInv(newItem);
InsertIntoStageInventoryCategory(newItem,monsterDrop);
itemPtr=newItem;
}else{
auto inventory=_inventory.equal_range(it);
@ -447,10 +453,12 @@ std::weak_ptr<Item>Inventory::AddItem(IT it,uint32_t amt,bool monsterDrop){
[&](int counter,std::pair<IT,std::shared_ptr<Item>>item){
(*item.second).amt+=amt;
itemPtr=item.second;
newItem=std::make_shared<Item>(amt,it);
return counter+1;})>1)ERR("WARNING! We should not have more than 1 instance of a stackable item!");
}
SkipAddingStackableItem:
InsertIntoStageInventoryCategory(newItem,monsterDrop);
return itemPtr;
}
@ -671,7 +679,10 @@ const std::string Item::Description(CompactText compact)const{
if(compact==CRAFTING_INFO){
description+="\n\nCrafting Requirements:\n---------\n";
if(IsCraftable()){
const EnhancementLevelInfo&info=GetEnhancementInfo()[EnhancementLevel()+1];
size_t enhanceIndex=EnhancementLevel()+1;
if(IsEquippable()&&Inventory::GetItemCount(ActualName())==0)enhanceIndex=0;
const EnhancementLevelInfo&info=GetEnhancementInfo()[enhanceIndex];
for(const auto&[name,amt]:info.craftingRequirement.GetItems()){
description+=std::format("{}{} x{} ({})\n",
Inventory::GetItemCount(name)<amt?"#FF0000":"#FFFFFF",
@ -964,8 +975,8 @@ const std::string Stats::GetStatsString(CompactText compact)const{
}
ItemInfo&ItemInfo::operator[](const IT&item){
if(!ITEM_DATA.count(item))ERR("Item "<<std::quoted(item)<<" does not exist in the item database!");
return ITEM_DATA[item];
if(!ITEM_DATA.count(const_cast<IT&>(item)))ERR("Item "<<const_cast<IT&>(item)<<" does not exist in the item database!");
return ITEM_DATA[const_cast<IT&>(item)];
}
const uint32_t ItemInfo::GetBuyValue()const{
@ -1069,7 +1080,7 @@ const bool Item::CanEnhanceItem(uint8_t qty)const{
if(!GetEnhancementInfo().CanBeEnhanced())return false;
if(GetEnhancementInfo().AvailableChapter()<game->GetCurrentChapter())return false;
size_t enhanceIndex=EnhancementLevel()+1;
if(Inventory::GetItemCount(ActualName())==0)enhanceIndex=0;
if(IsEquippable()&&Inventory::GetItemCount(ActualName())==0)enhanceIndex=0;//Equipment we don't have we need to first craft.
const EnhancementLevelInfo&enhanceInfo=GetEnhancementInfo()[enhanceIndex];
if(GetEnhancementInfo().size()>2){ //If the item has exactly 2 enhancement levels, then it's an item that can only simply be crafted. Therefore, don't do the max enhancement level check.
if(EnhancementLevel()>="Item.Item Max Enhancement Level"_I)return false;
@ -1181,7 +1192,7 @@ const std::vector<std::shared_ptr<Item>>Inventory::GetInventory(){
}
const std::string&ItemInfo::GetClass()const{
return equippableClass;
return equippableClass.length()==0?game->GetPlayer()->GetClassName():equippableClass;
}
const std::string&Item::GetClass()const{
@ -1203,4 +1214,27 @@ void Inventory::UpdateBlacksmithInventoryLists(){
InventoryCreator::RowPlayerWeapons_InventorySlotsUpdate(*DYNAMIC_POINTER_CAST<InventoryScrollableWindowComponent>(weaponsList),"Equipment");
InventoryCreator::RowPlayerArmor_InventorySlotsUpdate(*DYNAMIC_POINTER_CAST<InventoryScrollableWindowComponent>(armorList),"Equipment");
}
uint16_t ItemSortRules::GetItemSortRanking(const std::weak_ptr<Item>&it){
uint16_t sortRank=0;
auto secondaryFind=std::find_if(secondarySort.begin(),secondarySort.end(),[&](const std::string&sort){
if(it.lock()->DisplayName().find(sort)!=std::string::npos){
return true;
}
return false;
});
sortRank+=std::distance(secondarySort.begin(),secondaryFind);
auto primaryFind=std::find_if(primarySort.begin(),primarySort.end(),[&](const std::string&sort){
if(it.lock()->DisplayName().find(sort)!=std::string::npos){
return true;
}
return false;
});
sortRank+=std::distance(primarySort.begin(),primaryFind)*(secondarySort.size()+1);
return sortRank;
}
uint16_t ItemSortRules::MaxSortRanking(){
return primarySort.size()*(secondarySort.size()+1)+secondarySort.size();
}

@ -46,12 +46,12 @@ All rights reserved.
#include "Merchant.h"
#include "CraftingRequirement.h"
#include "FunctionPriming.h"
#include "IT.h"
class AiL;
class ItemInfo;
class ItemProps;
using IT=std::string;
using ITCategory=std::string;
using EventName=std::string;
@ -132,6 +132,16 @@ public:
const size_t size()const;
};
class ItemSortRules{
friend class ItemInfo;
public:
static std::vector<std::string>primarySort;
static std::vector<std::string>secondarySort;
//Returns a number based on what the equipment type of an item is. The lower the number, the earlier it should appear in the list.
static uint16_t GetItemSortRanking(const std::weak_ptr<Item>&it);
static uint16_t MaxSortRanking();
};
//You cannot create instances of this class, access sets from ItemSet::sets and add the appropriate set bonuses.
class ItemSet{
friend class ItemInfo;
@ -219,9 +229,9 @@ public:
//Use ISBLANK macro instead!! This should not be called directly!!
static bool IsBlank(std::weak_ptr<Item>item);
friend const bool operator==(std::shared_ptr<Item>lhs,std::shared_ptr<Item>rhs){return lhs->it==rhs->it&&lhs->randomizedStats==rhs->randomizedStats;};
friend const bool operator==(std::shared_ptr<Item>lhs,const IT&rhs){return lhs->ActualName()==rhs;};
friend const bool operator==(std::shared_ptr<Item>lhs,const IT&rhs){return lhs->ActualName()==const_cast<IT&>(rhs);};
friend const bool operator==(std::weak_ptr<Item>lhs,std::weak_ptr<Item>rhs){return !lhs.expired()&&!rhs.expired()&&lhs.lock()->it==rhs.lock()->it&&lhs.lock()->randomizedStats==rhs.lock()->randomizedStats;};
friend const bool operator==(std::weak_ptr<Item>lhs,const IT&rhs){return !lhs.expired()&&lhs.lock()->ActualName()==rhs;};
friend const bool operator==(std::weak_ptr<Item>lhs,const IT&rhs){return !lhs.expired()&&lhs.lock()->ActualName()==const_cast<IT&>(rhs);};
friend const bool operator==(const IT&lhs,std::weak_ptr<Item>rhs){return operator==(rhs,lhs);};
friend const bool operator==(const IT&lhs,std::shared_ptr<Item>rhs){return operator==(rhs,lhs);};
};

@ -65,7 +65,6 @@ void Menu::InitializeLevelCompleteWindow(){
auto nextButtonAction=[](MenuFuncData data){
Unlock::UnlockArea(State_OverworldMap::GetCurrentConnectionPoint().map);
game->UpdateDiscordStatus("Hub Area",game->GetPlayer()->GetClassName());
Merchant::RandomizeTravelingMerchant();
GameState::ChangeState(States::GAME_HUB,0.25f);
return true;

@ -40,7 +40,6 @@ All rights reserved.
class Item;
using Chapter=int;
using IT=std::string;
using ITCategory=std::string;
class Merchant{

@ -189,7 +189,7 @@ public:
virtual Class GetClass()=0;
virtual bool AutoAttack()=0;
virtual void OnUpdate(float fElapsedTime)=0;
virtual std::string GetClassName()=0;
virtual const std::string&GetClassName()=0;
virtual Ability&GetRightClickAbility()=0;
virtual Ability&GetAbility1()=0;
virtual Ability&GetAbility2()=0;
@ -354,7 +354,7 @@ struct Warrior:Player{
//Include only WARRIOR-specific implementations!
void OnUpdate(float fElapsedTime)override;
static void InitializeClassAbilities();
std::string GetClassName()override;
const std::string&GetClassName()override;
Ability&GetRightClickAbility()override;
Ability&GetAbility1()override;
Ability&GetAbility2()override;
@ -385,7 +385,7 @@ struct Thief:Player{
//Include only THIEF-specific implementations!
void OnUpdate(float fElapsedTime)override;
static void InitializeClassAbilities();
std::string GetClassName()override;
const std::string&GetClassName()override;
Ability&GetRightClickAbility()override;
Ability&GetAbility1()override;
Ability&GetAbility2()override;
@ -416,7 +416,7 @@ struct Ranger:Player{
//Include only RANGER-specific implementations!
void OnUpdate(float fElapsedTime)override;
static void InitializeClassAbilities();
std::string GetClassName()override;
const std::string&GetClassName()override;
Ability&GetRightClickAbility()override;
Ability&GetAbility1()override;
Ability&GetAbility2()override;
@ -447,7 +447,7 @@ struct Trapper:Player{
//Include only TRAPPER-specific implementations!
void OnUpdate(float fElapsedTime)override;
static void InitializeClassAbilities();
std::string GetClassName()override;
const std::string&GetClassName()override;
Ability&GetRightClickAbility()override;
Ability&GetAbility1()override;
Ability&GetAbility2()override;
@ -478,7 +478,7 @@ struct Wizard:Player{
//Include only WIZARD-specific implementations!
void OnUpdate(float fElapsedTime)override;
static void InitializeClassAbilities();
std::string GetClassName()override;
const std::string&GetClassName()override;
Ability&GetRightClickAbility()override;
Ability&GetAbility1()override;
Ability&GetAbility2()override;
@ -509,7 +509,7 @@ struct Witch:Player{
//Include only WITCHs-specific implementations!
void OnUpdate(float fElapsedTime)override;
static void InitializeClassAbilities();
std::string GetClassName()override;
const std::string&GetClassName()override;
Ability&GetRightClickAbility()override;
Ability&GetAbility1()override;
Ability&GetAbility2()override;

@ -71,9 +71,7 @@ protected:
if(itemRef.lock()->EnhancementIsPossible()){
size_t enhancementIndex=itemRef.lock()->EnhancementLevel()+1;
if(Inventory::GetItemCount(itemRef.lock()->ActualName())==0){ //If we don't have the item, use the initial crafting list instead.
enhancementIndex=0;
}
if(itemRef.lock()->IsEquippable()&&Inventory::GetItemCount(itemRef.lock()->ActualName())==0)enhancementIndex=0;//If we don't have the item, use the initial crafting list instead. But only for equipment!
float drawWidth=rect.size.x/3;
int index=0;
for(const auto&[name,amt]:itemRef.lock()->GetEnhancementInfo()[enhancementIndex].craftingRequirement.GetItems()){

@ -43,6 +43,7 @@ All rights reserved.
#include "VisualNovel.h"
#include "State_OverworldMap.h"
#include "GameEvent.h"
#include "SaveFile.h"
INCLUDE_MONSTER_LIST
INCLUDE_game
@ -51,9 +52,12 @@ void State_GameHub::OnStateChange(GameState*prevState){
if(Menu::IsMenuOpen()){
Menu::CloseAllMenus();
}
SaveFile::SaveGame();
game->GetPlayer()->SetState(State::NORMAL);
game->LoadLevel("HUB");
game->UpdateDiscordStatus("Hub Area",game->GetPlayer()->GetClassName());
}
void State_GameHub::OnUserUpdate(AiL*game){
State_GameRun::OnUserUpdate(game);

@ -4,6 +4,7 @@ Settings Menu
- Any settings should be saved to the save file!
- Volume Controls
- Play Sound in Background
- Keyboard aim assist (When playing w/keyboard, have the game auto fire for players that don't want to use mouse or cannot)
- Key Configuration
-Upon pressing a key, check if the key is bound to another option, if so,
remove that bind from the list. Up to two keys may be binded per action.

@ -39,7 +39,7 @@ All rights reserved.
#define VERSION_MAJOR 0
#define VERSION_MINOR 3
#define VERSION_PATCH 0
#define VERSION_BUILD 6616
#define VERSION_BUILD 6677
#define stringify(a) stringify_(a)
#define stringify_(a) #a

@ -1383,7 +1383,7 @@ Equipment
Crafting
{
# When this crafting recipe is available.
AvailableChapter = 1
AvailableChapter = 4
Item[0] = Wolf Skin,1
Gold = 5

@ -27,6 +27,11 @@ Item
Missing Upgradeable Item Text = Missing Materials
# Color of the text that displays when items can be upgraded in the Blacksmith but the player doesn't have enough material.
Missing Upgradeable Item Text Color = 192,0,0,255
# The names of items to be sorted for equipment lists.
Equipment Sort Order Primary = Wooden, Leather, Steel, Copper, Shell, Bone, Laser, Plasma, Unknown
# The types of the items to be sorted for equipment lists if they have the same primary type.
Equipment Sort Order Secondary = Helmet, Armor, Pants, Gloves, Shoes, Sword, Bow, Staff
}
ItemDrop
{

Loading…
Cancel
Save