summaryrefslogtreecommitdiffstats
path: root/src/BrewingRecipes.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/BrewingRecipes.cpp')
-rw-r--r--src/BrewingRecipes.cpp287
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);
+}
+
+
+
+
+