diff options
Diffstat (limited to 'src/BrewingRecipes.cpp')
-rw-r--r-- | src/BrewingRecipes.cpp | 287 |
1 files changed, 287 insertions, 0 deletions
diff --git a/src/BrewingRecipes.cpp b/src/BrewingRecipes.cpp new file mode 100644 index 000000000..3ee39c8af --- /dev/null +++ b/src/BrewingRecipes.cpp @@ -0,0 +1,287 @@ + +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "BrewingRecipes.h" +#include "Item.h" + +#include <fstream> + +#define BREWING_RECIPE_FILE "brewing.txt" + + + + + +typedef std::vector<std::unique_ptr<cBrewingRecipes::cRecipe>> RecipeList; + + + + + +struct cBrewingRecipes::sBrewingRecipeState +{ + RecipeList Recipes; +}; + + + + + +cBrewingRecipes::cBrewingRecipes() + : m_pState(new sBrewingRecipeState) +{ + ReloadRecipes(); +} + + + + + +cBrewingRecipes::~cBrewingRecipes() +{ + ClearRecipes(); +} + + + + + +void cBrewingRecipes::ReloadRecipes(void) +{ + ClearRecipes(); + LOGD("Loading brewing recipes..."); + + std::ifstream f(BREWING_RECIPE_FILE, std::ios::in); + if (!f.good()) + { + LOG("Could not open the brewing recipes file \"%s\". No brewing recipes are available.", BREWING_RECIPE_FILE); + return; + } + + unsigned int LineNum = 0; + AString ParsingLine; + + while (std::getline(f, ParsingLine)) + { + LineNum++; + // Remove comments from the line: + size_t FirstCommentSymbol = ParsingLine.find('#'); + if (FirstCommentSymbol != AString::npos) + { + ParsingLine.erase(ParsingLine.begin() += static_cast<long>(FirstCommentSymbol), ParsingLine.end()); + } + + if (ParsingLine.empty()) + { + continue; + } + AddRecipeFromLine(ParsingLine, LineNum); + } // while (getline(ParsingLine)) + + LOG("Loaded " SIZE_T_FMT " brewing recipes", m_pState->Recipes.size()); +} + + + + + +void cBrewingRecipes::AddRecipeFromLine(const AString & a_Line, unsigned int a_LineNum) +{ + AString Line(a_Line); + Line.erase(std::remove_if(Line.begin(), Line.end(), isspace), Line.end()); + + short InputDamage; + short OutputDamage; + + std::unique_ptr<cItem> InputItem = cpp14::make_unique<cItem>(); + std::unique_ptr<cItem> IngredientItem = cpp14::make_unique<cItem>(); + std::unique_ptr<cItem> OutputItem = cpp14::make_unique<cItem>(); + + const AStringVector & InputAndIngredient = StringSplit(Line, "+"); + + if (InputAndIngredient.size() != 2) + { + LOGWARNING("brewing.txt: line %d: A line with '+' was expected", a_LineNum); + LOGINFO("Offending line: \"%s\"", a_Line.c_str()); + return; + } + + const AStringVector & IngredientAndOutput = StringSplit(InputAndIngredient[1].c_str(), "="); + if (IngredientAndOutput.size() != 2) + { + LOGWARNING("brewing.txt: line %d: A line with '=' was expected", a_LineNum); + LOGINFO("Offending line: \"%s\"", a_Line.c_str()); + return; + } + + if (!ParseItem(IngredientAndOutput[0], *IngredientItem)) + { + LOGWARNING("brewing.txt: Parsing of the item didn't worked."); + LOGINFO("Offending line: \"%s\"", a_Line.c_str()); + return; + } + + if (!StringToInteger<short>(InputAndIngredient[0], InputDamage)) + { + LOGWARNING("brewing.txt: line %d: Cannot parse the damage value for the input item\"%s\".", a_LineNum, InputAndIngredient[0].c_str()); + LOGINFO("Offending line: \"%s\"", a_Line.c_str()); + return; + } + + if (!StringToInteger<short>(IngredientAndOutput[1], OutputDamage)) + { + LOGWARNING("brewing.txt: line %d: Cannot parse the damage value for the output item\"%s\".", a_LineNum, IngredientAndOutput[1].c_str()); + LOGINFO("Offending line: \"%s\"", a_Line.c_str()); + return; + } + + // The items has always the same type + InputItem->m_ItemType = E_ITEM_POTION; + InputItem->m_ItemDamage = InputDamage; + + OutputItem->m_ItemType = E_ITEM_POTION; + OutputItem->m_ItemDamage = OutputDamage; + + std::unique_ptr<cRecipe> Recipe = cpp14::make_unique<cRecipe>(); + Recipe->Input = std::move(InputItem); + Recipe->Output = std::move(OutputItem); + Recipe->Ingredient = std::move(IngredientItem); + m_pState->Recipes.push_back(std::move(Recipe)); +} + + + + + +bool cBrewingRecipes::ParseItem(const AString & a_String, cItem & a_Item) +{ + return StringToItem(a_String, a_Item); +} + + + + + +void cBrewingRecipes::ClearRecipes(void) +{ + m_pState->Recipes.clear(); +} + + + + + +const cBrewingRecipes::cRecipe * cBrewingRecipes::GetRecipeFrom(const cItem & a_Input, const cItem & a_Ingredient) const +{ + for (auto & Recipe : m_pState->Recipes) + { + if ((Recipe->Input->IsEqual(a_Input)) && (Recipe->Ingredient->IsEqual(a_Ingredient))) + { + return Recipe.get(); + } + } + + // Check for gunpowder + if (a_Ingredient.m_ItemType == E_ITEM_GUNPOWDER) + { + if (a_Input.m_ItemDamage & 0x2000) + { + // Create new recipe and add it to list + std::unique_ptr<cItem> InputItem = cpp14::make_unique<cItem>(); + std::unique_ptr<cItem> IngredientItem = cpp14::make_unique<cItem>(); + std::unique_ptr<cItem> OutputItem = cpp14::make_unique<cItem>(); + + InputItem->m_ItemType = E_ITEM_POTION; + InputItem->m_ItemDamage = a_Input.m_ItemDamage; + OutputItem->m_ItemType = E_ITEM_POTION; + OutputItem->m_ItemDamage = a_Input.m_ItemDamage + 8192; + IngredientItem->m_ItemType = E_ITEM_GUNPOWDER; + + std::unique_ptr<cRecipe> Recipe = cpp14::make_unique<cRecipe>(); + Recipe->Input = std::move(InputItem); + Recipe->Output = std::move(OutputItem); + Recipe->Ingredient = std::move(IngredientItem); + m_pState->Recipes.push_back(std::move(Recipe)); + return Recipe.get(); + } + return nullptr; + } + + // Check for splash potion + if (a_Input.m_ItemDamage & 0x4000) + { + const std::unique_ptr<cRecipe> * FoundRecipe = nullptr; + // Search for the drinkable potion, the ingredients are the same + short SplashItemDamage = a_Input.m_ItemDamage - 8192; + + for (auto & Recipe : m_pState->Recipes) + { + if ((Recipe->Input->m_ItemDamage == SplashItemDamage) && (Recipe->Ingredient->IsEqual(a_Ingredient))) + { + FoundRecipe = &Recipe; + break; + } + } + + if (FoundRecipe == nullptr) + { + return nullptr; + } + + // Create new recipe and add it to list + std::unique_ptr<cItem> InputItem = cpp14::make_unique<cItem>(); + std::unique_ptr<cItem> IngredientItem = cpp14::make_unique<cItem>(); + std::unique_ptr<cItem> OutputItem = cpp14::make_unique<cItem>(); + + InputItem->m_ItemType = E_ITEM_POTION; + InputItem->m_ItemDamage = a_Input.m_ItemDamage; + OutputItem->m_ItemType = E_ITEM_POTION; + OutputItem->m_ItemDamage = (*FoundRecipe)->Output->m_ItemDamage + 8192; + IngredientItem->m_ItemType = (*FoundRecipe)->Ingredient->m_ItemType; + + std::unique_ptr<cRecipe> Recipe = cpp14::make_unique<cRecipe>(); + Recipe->Input = std::move(InputItem); + Recipe->Output = std::move(OutputItem); + Recipe->Ingredient = std::move(IngredientItem); + m_pState->Recipes.push_back(std::move(Recipe)); + return Recipe.get(); + } + return nullptr; +} + + + + + + +bool cBrewingRecipes::IsIngredient(const cItem & a_Ingredient) const +{ + // Check for gunpowder + if (a_Ingredient.m_ItemType == E_ITEM_GUNPOWDER) + { + return true; + } + + for (auto & Recipe : m_pState->Recipes) + { + if (Recipe->Ingredient->IsEqual(a_Ingredient)) + { + return true; + } + } + return false; +} + + + + + +bool cBrewingRecipes::IsBottle(const cItem & a_Item) const +{ + return (a_Item.m_ItemType == E_ITEM_POTION); +} + + + + + |