Пример #1
0
void cCraftingRecipes::GetRecipe(cPlayer & a_Player, cCraftingGrid & a_CraftingGrid, cCraftingRecipe & a_Recipe)
{
	// Allow plugins to intercept recipes using a pre-craft hook:
	if (cRoot::Get()->GetPluginManager()->CallHookPreCrafting(a_Player, a_CraftingGrid, a_Recipe))
	{
		return;
	}
	
	// Built-in recipes:
	std::unique_ptr<cRecipe> Recipe(FindRecipe(a_CraftingGrid.GetItems(), a_CraftingGrid.GetWidth(), a_CraftingGrid.GetHeight()));
	a_Recipe.Clear();
	if (Recipe.get() == nullptr)
	{
		// Allow plugins to intercept a no-recipe-found situation:
		cRoot::Get()->GetPluginManager()->CallHookCraftingNoRecipe(a_Player, a_CraftingGrid, a_Recipe);
		return;
	}
	for (cRecipeSlots::const_iterator itr = Recipe->m_Ingredients.begin(); itr != Recipe->m_Ingredients.end(); ++itr)
	{
		a_Recipe.SetIngredient(itr->x, itr->y, itr->m_Item);
	}  // for itr
	a_Recipe.SetResult(Recipe->m_Result);
	
	// Allow plugins to intercept recipes after they are processed:
	cRoot::Get()->GetPluginManager()->CallHookPostCrafting(a_Player, a_CraftingGrid, a_Recipe);
}
Пример #2
0
// создать рецепты
bool IngameMenu::CreateRecipes() {

	Recipe rec[] =  {
		Recipe(II_ROPE, 1, II_STICK, 10, II_NOTHING, 0, II_CLUB, 1),
		Recipe(II_FERN, 5, II_NOTHING, 0, II_NOTHING, 0, II_ROPE, 1),
		Recipe(II_FANG, 2, II_ROPE, 1, II_STICK, 5, II_PICK, 1),
		Recipe(II_ROCK, 1, II_ROPE, 1, II_STICK, 5, II_AXE, 1),
	};

	// выравнивание рецептов по возрастанию
	for (UINT receptNumber(0); receptNumber < ARRAYSIZE(rec); receptNumber++) {

		// для каждого рецепта
		for (UINT j(0); j < ARRAYSIZE(rec[receptNumber].ingredient) - 1; j++) {
			INVENTORY_ITEM maxItem = rec[receptNumber].ingredient[j].invItem;
			UINT maxIndex = j;
			for (UINT i(j + 1); i < ARRAYSIZE(rec[receptNumber].ingredient); i++) {
				if (rec[receptNumber].ingredient[i].invItem > maxItem) {
					maxItem = rec[receptNumber].ingredient[i].invItem;
					maxIndex = i;
				}
			}
			if (maxIndex != j) MathHelper::Swap(&rec[receptNumber].ingredient[maxIndex], &rec[receptNumber].ingredient[j]);
		} // для каждого рецепта
	}

	recipesAmount = ARRAYSIZE(rec);
	recipes = new Recipe[recipesAmount];
	memcpy(recipes, rec, sizeof(rec));

	// проверка на возрастаемость рецептов
	for (UINT j(0); j < recipesAmount; j ++)
		for (UINT i(0); i < MAX_ITEM_CRAFT_AMOUNT - 2; i++) {
			BR(recipes[j].ingredient[i].invItem >= recipes[j].ingredient[i + 1].invItem);
		}

	return true;

}
Пример #3
0
// recipe population
void Recipes::add_recipe(const string & name,
	const map<string, int> & inv_n, const map<string, int> & inv_r,
	const map<string, int> & loc_n, const map<string, int> & loc_r, const map<string, int> & yields)
{
	/* arguments in order:
	recipe name
	map of item IDs that need to be in inventory
	map of item IDs that need to be in inventory, are removed
	map of item IDs that need to be in the room
	map of item IDs that need to be in the room, are removed
	map of item IDs to be yielded */

	this->recipes.insert(pair<string, Recipe>(name, Recipe(inv_n, inv_r, loc_n, loc_r, yields)));
}
Пример #4
0
cCraftingRecipe & cSlotAreaCrafting::GetRecipeForPlayer(cPlayer & a_Player)
{
	for (cRecipeMap::iterator itr = m_Recipes.begin(), end = m_Recipes.end(); itr != end; ++itr)
	{
		if (itr->first == a_Player.GetUniqueID())
		{
			return itr->second;
		}
	}  // for itr - m_Recipes[]
	
	// Not found. Add a new one:
	cCraftingGrid   Grid(GetPlayerSlots(a_Player) + 1, m_GridSize, m_GridSize);
	cCraftingRecipe Recipe(Grid);
	cRoot::Get()->GetCraftingRecipes()->GetRecipe(&a_Player, Grid, Recipe);
	m_Recipes.push_back(std::make_pair(a_Player.GetUniqueID(), Recipe));
	return m_Recipes.back().second;
}
Пример #5
0
cCraftingRecipes::cRecipe * cCraftingRecipes::MatchRecipe(const cItem * a_CraftingGrid, int a_GridWidth, int a_GridHeight, int a_GridStride, const cRecipe * a_Recipe, int a_OffsetX, int a_OffsetY)
{
	// Check the regular items first:
	bool HasMatched[MAX_GRID_WIDTH][MAX_GRID_HEIGHT];
	memset(HasMatched, 0, sizeof(HasMatched));
	for (cRecipeSlots::const_iterator itrS = a_Recipe->m_Ingredients.begin(); itrS != a_Recipe->m_Ingredients.end(); ++itrS)
	{
		if ((itrS->x < 0) || (itrS->y < 0))
		{
			// "Anywhere" item, process later
			continue;
		}
		ASSERT(itrS->x + a_OffsetX < a_GridWidth);
		ASSERT(itrS->y + a_OffsetY < a_GridHeight);
		int GridID = (itrS->x + a_OffsetX) + a_GridStride * (itrS->y + a_OffsetY);
		
		const cItem & Item = itrS->m_Item;
		if (
			(itrS->x >= a_GridWidth) ||
			(itrS->y >= a_GridHeight) ||
			(Item.m_ItemType != a_CraftingGrid[GridID].m_ItemType) ||   // same item type?
			(Item.m_ItemCount > a_CraftingGrid[GridID].m_ItemCount) ||  // not enough items
			(
				(Item.m_ItemDamage >= 0) &&  // should compare damage values?
				(Item.m_ItemDamage != a_CraftingGrid[GridID].m_ItemDamage)
			)
		)
		{
			// Doesn't match
			return nullptr;
		}
		HasMatched[itrS->x + a_OffsetX][itrS->y + a_OffsetY] = true;
	}  // for itrS - Recipe->m_Ingredients[]
	
	// Process the "Anywhere" items now, and only in the cells that haven't matched yet
	// The "anywhere" items are processed on a first-come-first-served basis.
	// Do not use a recipe with one horizontal and one vertical "anywhere" ("*:1, 1:*") as it may not match properly!
	cRecipeSlots MatchedSlots;  // Stores the slots of "anywhere" items that have matched, with the match coords
	for (cRecipeSlots::const_iterator itrS = a_Recipe->m_Ingredients.begin(); itrS != a_Recipe->m_Ingredients.end(); ++itrS)
	{
		if ((itrS->x >= 0) && (itrS->y >= 0))
		{
			// Regular item, already processed
			continue;
		}
		int StartX = 0, EndX = a_GridWidth  - 1;
		int StartY = 0, EndY = a_GridHeight - 1;
		if (itrS->x >= 0)
		{
			StartX = itrS->x;
			EndX = itrS->x;
		}
		else if (itrS->y >= 0)
		{
			StartY = itrS->y;
			EndY = itrS->y;
		}
		bool Found = false;
		for (int x = StartX; x <= EndX; x++)
		{
			for (int y = StartY; y <= EndY; y++)
			{
				if (HasMatched[x][y])
				{
					// Already matched some other item
					continue;
				}
				int GridIdx = x + a_GridStride * y;
				if (
					(a_CraftingGrid[GridIdx].m_ItemType == itrS->m_Item.m_ItemType) &&
					(
						(itrS->m_Item.m_ItemDamage < 0) ||  // doesn't want damage comparison
						(itrS->m_Item.m_ItemDamage == a_CraftingGrid[GridIdx].m_ItemDamage)  // the damage matches
					)
				)
				{
					HasMatched[x][y] = true;
					Found = true;
					MatchedSlots.push_back(*itrS);
					MatchedSlots.back().x = x;
					MatchedSlots.back().y = y;
					break;
				}
			}  // for y
			if (Found)
			{
				break;
			}
		}  // for x
		if (!Found)
		{
			return nullptr;
		}
	}  // for itrS - a_Recipe->m_Ingredients[]
	
	// Check if the whole grid has matched:
	for (int x = 0; x < a_GridWidth; x++) for (int y = 0; y < a_GridHeight; y++)
	{
		if (!HasMatched[x][y] && !a_CraftingGrid[x + a_GridStride * y].IsEmpty())
		{
			// There's an unmatched item in the grid
			return nullptr;
		}
	}  // for y, for x
	
	// The recipe has matched. Create a copy of the recipe and set its coords to match the crafting grid:
	std::unique_ptr<cRecipe> Recipe(new cRecipe);
	Recipe->m_Result = a_Recipe->m_Result;
	Recipe->m_Width  = a_Recipe->m_Width;
	Recipe->m_Height = a_Recipe->m_Height;
	for (cRecipeSlots::const_iterator itrS = a_Recipe->m_Ingredients.begin(); itrS != a_Recipe->m_Ingredients.end(); ++itrS)
	{
		if ((itrS->x < 0) || (itrS->y < 0))
		{
			// "Anywhere" item, process later
			continue;
		}
		Recipe->m_Ingredients.push_back(*itrS);
	}
	Recipe->m_Ingredients.insert(Recipe->m_Ingredients.end(), MatchedSlots.begin(), MatchedSlots.end());

	// We use Recipe instead of a_Recipe because we want the wildcard ingredients' slot numbers as well, which was just added previously
	HandleFireworks(a_CraftingGrid, Recipe.get(), a_GridStride, a_OffsetX, a_OffsetY);

	return Recipe.release();
}
Пример #6
0
void cCraftingRecipes::AddRecipeLine(int a_LineNum, const AString & a_RecipeLine)
{
	// Remove any spaces within the line:
	AString RecipeLine(a_RecipeLine);
	RecipeLine.erase(std::remove_if(RecipeLine.begin(), RecipeLine.end(), isspace), RecipeLine.end());

	AStringVector Sides = StringSplit(RecipeLine, "=");
	if (Sides.size() != 2)
	{
		LOGWARNING("crafting.txt: line %d: A single '=' was expected, got %d", a_LineNum, (int)Sides.size() - 1);
		LOGINFO("Offending line: \"%s\"", a_RecipeLine.c_str());
		return;
	}
	
	std::unique_ptr<cCraftingRecipes::cRecipe> Recipe(new cCraftingRecipes::cRecipe);
	
	// Parse the result:
	AStringVector ResultSplit = StringSplit(Sides[0], ",");
	if (ResultSplit.empty())
	{
		LOGWARNING("crafting.txt: line %d: Result is empty, ignoring the recipe.", a_LineNum);
		LOGINFO("Offending line: \"%s\"", a_RecipeLine.c_str());
		return;
	}
	if (!ParseItem(ResultSplit[0], Recipe->m_Result))
	{
		LOGWARNING("crafting.txt: line %d: Cannot parse result item, ignoring the recipe.", a_LineNum);
		LOGINFO("Offending line: \"%s\"", a_RecipeLine.c_str());
		return;
	}
	if (ResultSplit.size() > 1)
	{
		if (!StringToInteger<char>(ResultSplit[1].c_str(), Recipe->m_Result.m_ItemCount))
		{
			LOGWARNING("crafting.txt: line %d: Cannot parse result count, ignoring the recipe.", a_LineNum);
			LOGINFO("Offending line: \"%s\"", a_RecipeLine.c_str());
			return;
		}
	}
	else
	{
		Recipe->m_Result.m_ItemCount = 1;
	}
	
	// Parse each ingredient:
	AStringVector Ingredients = StringSplit(Sides[1], "|");
	int Num = 1;
	for (AStringVector::const_iterator itr = Ingredients.begin(); itr != Ingredients.end(); ++itr, ++Num)
	{
		if (!ParseIngredient(*itr, Recipe.get()))
		{
			LOGWARNING("crafting.txt: line %d: Cannot parse ingredient #%d, ignoring the recipe.", a_LineNum, Num);
			LOGINFO("Offending line: \"%s\"", a_RecipeLine.c_str());
			return;
		}
	}  // for itr - Ingredients[]
	
	NormalizeIngredients(Recipe.get());
	
	m_Recipes.push_back(Recipe.release());
}