1
0

Merge pull request #2497 from Seadragon91/brewing

Implemented brewing
This commit is contained in:
Julian Laubstein 2015-11-03 22:06:43 +01:00
commit 1bc145ff44
40 changed files with 1858 additions and 9 deletions

View File

@ -2067,6 +2067,7 @@ a_Player:OpenWindow(Window);
ForEachPlayer = { Params = "CallbackFunction", Return = "", Notes = "Calls the given callback function for each player. The callback function has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cPlayer|cPlayer}})</pre>" },
ForEachWorld = { Params = "CallbackFunction", Return = "", Notes = "Calls the given callback function for each world. The callback function has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cWorld|cWorld}})</pre>" },
Get = { Params = "", Return = "Root object", Notes = "(STATIC) This function returns the cRoot object." },
GetBrewingRecipe = { Params = "{{cItem|cItem}}, {{cItem|cItem}}", Return = "{{cItem|cItem}}", Notes = "(STATIC) Returns the result item, if a recipe has been found. If no recipe is found, returns no value." },
GetBuildCommitID = { Params = "", Return = "string", Notes = "(STATIC) For official builds (Travis CI / Jenkins) it returns the exact commit hash used for the build. For unofficial local builds, returns the approximate commit hash (since the true one cannot be determined), formatted as \"approx: &lt;CommitHash&gt;\"." },
GetBuildDateTime = { Params = "", Return = "string", Notes = "(STATIC) For official builds (Travic CI / Jenkins) it returns the date and time of the build. For unofficial local builds, returns the approximate datetime of the commit (since the true one cannot be determined), formatted as \"approx: &lt;DateTime-iso8601&gt;\"." },
GetBuildID = { Params = "", Return = "string", Notes = "(STATIC) For official builds (Travis CI / Jenkins) it returns the unique ID of the build, as recognized by the build system. For unofficial local builds, returns the string \"Unknown\"." },
@ -2333,6 +2334,7 @@ local CompressedString = cStringCompression.CompressStringGZIP("DataToCompress")
DigBlock = { Params = "X, Y, Z", Return = "", Notes = "Replaces the specified block with air, without dropping the usual pickups for the block. Wakes up the simulators for the block and its neighbors." },
DoExplosionAt = { Params = "Force, X, Y, Z, CanCauseFire, Source, SourceData", Return = "", Notes = "Creates an explosion of the specified relative force in the specified position. If CanCauseFire is set, the explosion will set blocks on fire, too. The Source parameter specifies the source of the explosion, one of the esXXX constants. The SourceData parameter is specific to each source type, usually it provides more info about the source." },
DoWithBlockEntityAt = { Params = "BlockX, BlockY, BlockZ, CallbackFunction", Return = "bool", Notes = "If there is a block entity at the specified coords, calls the CallbackFunction with the {{cBlockEntity}} parameter representing the block entity. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cBlockEntity|BlockEntity}})</pre> The function returns false if there is no block entity, or if there is, it returns the bool value that the callback has returned. Use {{tolua}}.cast() to cast the Callback's BlockEntity parameter to the correct {{cBlockEntity}} descendant." },
DoWithBrewingstandAt = { Params = "BlockX, BlockY, BlockZ, CallbackFunction", Return = "bool", Notes = "If there is a brewingstand at the specified coords, calls the CallbackFunction with the {{cBrewingstandEntity}} parameter representing the brewingstand. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cBrewingstandEntity|cBrewingstandEntity}})</pre> The function returns false if there is no brewingstand, or if there is, it returns the bool value that the callback has returned." },
DoWithBeaconAt = { Params = "BlockX, BlockY, BlockZ, CallbackFunction", Return = "bool", Notes = "If there is a beacon at the specified coords, calls the CallbackFunction with the {{cBeaconEntity}} parameter representing the beacon. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cBeaconEntity|BeaconEntity}})</pre> The function returns false if there is no beacon, or if there is, it returns the bool value that the callback has returned." },
DoWithChestAt = { Params = "BlockX, BlockY, BlockZ, CallbackFunction", Return = "bool", Notes = "If there is a chest at the specified coords, calls the CallbackFunction with the {{cChestEntity}} parameter representing the chest. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cChestEntity|ChestEntity}})</pre> The function returns false if there is no chest, or if there is, it returns the bool value that the callback has returned." },
DoWithCommandBlockAt = { Params = "BlockX, BlockY, BlockZ, CallbackFunction", Return = "bool", Notes = "If there is a command block at the specified coords, calls the CallbackFunction with the {{cCommandBlockEntity}} parameter representing the command block. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cCommandBlockEntity|CommandBlockEntity}})</pre> The function returns false if there is no command block, or if there is, it returns the bool value that the callback has returned." },
@ -2353,6 +2355,7 @@ local CompressedString = cStringCompression.CompressStringGZIP("DataToCompress")
},
FindAndDoWithPlayer = { Params = "PlayerName, CallbackFunction", Return = "bool", Notes = "Calls the given callback function for the player with the name best matching the name string provided.<br>This function is case-insensitive and will match partial names.<br>Returns false if player not found or there is ambiguity, true otherwise. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cPlayer|Player}})</pre>" },
ForEachBlockEntityInChunk = { Params = "ChunkX, ChunkZ, CallbackFunction", Return = "bool", Notes = "Calls the specified callback for each block entity in the chunk. Returns true if all block entities in the chunk have been processed (including when there are zero block entities), or false if the callback has aborted the enumeration by returning true. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cBlockEntity|BlockEntity}})</pre> The callback should return false or no value to continue with the next block entity, or true to abort the enumeration. Use {{tolua}}.cast() to cast the Callback's BlockEntity parameter to the correct {{cBlockEntity}} descendant." },
ForEachBrewingstandInChunk = { Params = "ChunkX, ChunkZ, CallbackFunction", Return = "bool", Notes = "Calls the specified callback for each brewingstand in the chunk. Returns true if all brewingstands in the chunk have been processed (including when there are zero brewingstands), or false if the callback has aborted the enumeration by returning true. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cBrewingstandEntity|cBrewingstandEntity}})</pre> The callback should return false or no value to continue with the next brewingstand, or true to abort the enumeration." },
ForEachChestInChunk = { Params = "ChunkX, ChunkZ, CallbackFunction", Return = "bool", Notes = "Calls the specified callback for each chest in the chunk. Returns true if all chests in the chunk have been processed (including when there are zero chests), or false if the callback has aborted the enumeration by returning true. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cChestEntity|ChestEntity}})</pre> The callback should return false or no value to continue with the next chest, or true to abort the enumeration." },
ForEachEntity = { Params = "CallbackFunction", Return = "bool", Notes = "Calls the specified callback for each entity in the loaded world. Returns true if all the entities have been processed (including when there are zero entities), or false if the callback function has aborted the enumeration by returning true. The callback function has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cEntity|Entity}})</pre> The callback should return false or no value to continue with the next entity, or true to abort the enumeration." },
ForEachEntityInBox = { Params = "{{cBoundingBox|Box}}, CallbackFunction", Return = "bool", Notes = "Calls the specified callback for each entity in the specified bounding box. Returns true if all the entities have been processed (including when there are zero entities), or false if the callback function has aborted the enumeration by returning true. If any chunk within the bounding box is not valid, it is silently skipped without any notification. The callback function has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cEntity|Entity}})</pre> The callback should return false or no value to continue with the next entity, or true to abort the enumeration." },

View File

@ -76,6 +76,47 @@ return
},
},
cBrewingstandEntity =
{
Desc = [[
This class represents a brewingstand entity in the world.</p>
<p>
See also the {{cRoot}}:GetBrewingRecipe() function.
]],
Functions =
{
GetBrewingTimeLeft = { Params = "", Return = "number", Notes = "Returns the time until the current items finishes brewing, in ticks" },
GetTimeBrewed = { Params = "", Return = "number", Notes = "Returns the time that the current items has been brewing, in ticks" },
GetLeftBottleSlot = { Params = "", Return = "{{cItem|cItem}}", Notes = "Returns the item in the left bottle slot" },
GetMiddleBottleSlot = { Params = "", Return = "{{cItem|cItem}}", Notes = "Returns the item in the middle bottle slot" },
GetRightBottleSlot = { Params = "", Return = "{{cItem|cItem}}", Notes = "Returns the item in the right bottle slot" },
GetIndgredientSlot = { Params = "", Return = "{{cItem|cItem}}", Notes = "Returns the item in the ingredient slot" },
GetResultItem = { Params = "number", Return = "{{cItem|cItem}}", Notes = "Returns the expected result item for the given slot number." },
SetLeftBottleSlot = { Params = "{{cItem|cItem}}", Return = "", Notes = "Sets the item in the left bottle slot" },
SetMiddleBottleSlot = { Params = "{{cItem|cItem}}", Return = "", Notes = "Sets the item in the middle bottle slot" },
SetRightBottleSlot = { Params = "{{cItem|cItem}}", Return = "", Notes = "Sets the item in the right bottle slot" },
SetIngredientSlot = { Params = "{{cItem|cItem}}", Return = "", Notes = "Sets the item in the ingredient bottle slot" },
},
Constants =
{
bsLeftBottle = { Notes = "Index of the left bottle slot" },
bsMiddleBottle = { Notes = "Index of the middle bottle slot" },
bsRightBottle = { Notes = "Index of the right bottle slot" },
bsIngredient = { Notes = "Index of the ingredient slot" },
ContentsWidth = { Notes = "Width (X) of the {{cItemGrid|cItemGrid}} representing the contents" },
ContentsHeight = { Notes = "Height (Y) of the {{cItemGrid|cItemGrid}} representing the contents" },
},
ConstantGroups =
{
SlotIndices =
{
Include = "bs.*",
TextBefore = "When using the GetSlot() or SetSlot() function, use these constants for slot index:",
},
},
Inherits = "cBlockEntityWithItems"
}, -- cBrewingstandEntity
cChestEntity =
{
Desc = [[

View File

@ -110,6 +110,8 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage);
crUnknownCommand = { Notes = "When the given command doesn't exist." },
HOOK_BLOCK_SPREAD = { Notes = "Called when a block spreads based on world conditions" },
HOOK_BLOCK_TO_PICKUPS = { Notes = "Called when a block has been dug and is being converted to pickups. The server has provided the default pickups and the plugins may modify them." },
HOOK_BREWING_COMPLETING = { "Called before a brewing stand completes a brewing process." },
HOOK_BREWING_COMPLETED = { "Called when a brewing stand completed a brewing process." },
HOOK_CHAT = { Notes = "Called when a client sends a chat message that is not a command. The plugin may modify the chat message" },
HOOK_CHUNK_AVAILABLE = { Notes = "Called when a chunk is loaded or generated and becomes available in the {{cWorld|world}}." },
HOOK_CHUNK_GENERATED = { Notes = "Called after a chunk is generated. A plugin may do last modifications on the generated chunk before it is handed of to the {{cWorld|world}}." },

View File

@ -0,0 +1,26 @@
return
{
HOOK_BREWING_COMPLETED =
{
CalledWhen = "A brewing process is completed.",
DefaultFnName = "OnBrewingCompleted", -- also used as pagename
Desc = [[
This hook is called whenever a {{cBrewingstand|brewing stand}} has completed the brewing process.
See also the {{OnBrewingCompleting|HOOK_BREWING_COMPLETING}} hook for a similar hook, is called when a
brewing process is completing.
]],
Params =
{
{ Name = "World", Type = "{{cWorld}}", Notes = "World where the brewing stand resides." },
{ Name = "Brewingstand", Type = "{{cBrewingstand}}", Notes = "The brewing stand that completed the brewing process." },
},
Returns = [[
If the function returns false or no value, Cuberite calls other plugins with this event. If the
function returns true, no other plugin is called for this event.</p>
]],
}, -- HOOK_BREWING_COMPLETED
}

View File

@ -0,0 +1,28 @@
return
{
HOOK_BREWING_COMPLETING =
{
CalledWhen = "A brewing process is completing.",
DefaultFnName = "OnBrewingCompleting", -- also used as pagename
Desc = [[
This hook is called whenever a {{cBrewingstand|brewing stand}} is completing the brewing process. Plugins may
refuse the completing of the brewing process.<p>
See also the {{OnBrewingCompleted|HOOK_BREWING_COMPLETED}} hook for a similar hook, is called after the
brewing process has been completed.
]],
Params =
{
{ Name = "World", Type = "{{cWorld}}", Notes = "World where the brewing stand resides." },
{ Name = "Brewingstand", Type = "{{cBrewingstand}}", Notes = "The brewing stand that completes the brewing process." },
},
Returns = [[
If the function returns false or no value, Cuberite calls other plugins with this event. If the function returns true,
no other plugin's callback is called and the brewing process is canceled.
<p>
]],
}, -- HOOK_BREWING_COMPLETING
}

235
Server/brewing.txt Normal file
View File

@ -0,0 +1,235 @@
#*****************#
# Brewing Recipes #
#*****************#
# The time for a brewing recipe is always 20 seconds (400 ticks).
#
# Minecraft-Wiki Brewing:
# http://minecraft.gamepedia.com/Brewing
#
# A brewing recipe has this format:
# Data Value + Ingredient = Potion
### Primary ###
# Akward Potion
0 + netherwart = 16
# Mundane Potion
0 + redstonedust = 64
0 + ghasttear = 8192
0 + glisteringmelon = 8192
0 + blazepowder = 8192
0 + magmacream = 8192
0 + sugar = 8192
0 + spidereye = 8192
0 + rabbitsfoot = 8192
# Thick Potion
0 + glowstonedust = 32
# Potion of Weakness
0 + fermentedspidereye = 8264
### Secondary ###
## Positive ##
# Potion of Healing
16 + glisteringmelon = 8197
# Potion of Fire Resistance
16 + magmacream = 8195
# Potion of Regeneration
16 + ghasttear = 8193
# Potion of Strength
16 + blazepowder = 8201
# Potion of Swiftness
16 + sugar = 8194
# Potion of Night Vision
16 + goldencarrot = 8198
# Potion of Water Breathing
16 + pufferfish = 8205
# Potion of Leaping
16 + rabbitsfoot = 8203
## Negative ##
# Potion of Poison
16 + spidereye = 8196
# Potion of Weakness
16 + fermentedspidereye = 8200
32 + fermentedspidereye = 8200
64 + fermentedspidereye = 8200
# Potion of Weakness (extended)
8192 + fermentedspidereye = 8264
### Tertiary ###
## Positive ##
# Potion of Fire Resistance (extended)
8195 + redstonedust = 8259
8227 + redstonedust = 8259
# Potion of Healing II
8197 + glowstonedust = 8229
8261 + glowstonedust = 8229
# Potion of Regeneration (extended)
8193 + redstonedust = 8257
8225 + redstonedust = 8257
# Potion of Regeneration II
8193 + glowstonedust = 8225
8257 + glowstonedust = 8225
# Potion of Strength (extended)
8201 + redstonedust = 8265
8233 + redstonedust = 8265
# Potion of Strength II
8201 + glowstonedust = 8233
8265 + glowstonedust = 8233
# Potion of Swiftness (extended)
8194 + redstonedust = 8258
8226 + redstonedust = 8258
# Potion of Swiftness II
8194 + glowstonedust = 8226
8258 + glowstonedust = 8226
# Potion of Night Vision (extended)
8198 + redstonedust = 8262
# Potion of Invisibility
8198 + fermentedspidereye = 8206
# Potion of Invisibility (extended)
8262 + fermentedspidereye = 8270
# Potion of Invisibility (extended)
8206 + redstonedust = 8270
# Potion of Water Breathing (extended)
8205 + redstonedust = 8269
8237 + redstonedust = 8269
# Potion of Leaping II
8203 + glowstonedust = 8235
8267 + glowstonedust = 8235
# Potion of Leaping (extended)
8203 + redstonedust = 8267
8235 + redstonedust = 8267
## Negative ##
# Potion of Harming
8197 + fermentedspidereye = 8204
8196 + fermentedspidereye = 8204
8260 + fermentedspidereye = 8204
# Potion of Harming II
8229 + fermentedspidereye = 8236
8228 + fermentedspidereye = 8236
# Potion of Harming II
8204 + glowstonedust = 8236
8268 + glowstonedust = 8236
# Potion of Poison (extended)
8196 + redstonedust = 8260
8228 + redstonedust = 8260
# Potion of Poison II
8196 + glowstonedust = 8228
8260 + glowstonedust = 8228
# Potion of Slowness
8195 + fermentedspidereye = 8202
8194 + fermentedspidereye = 8202
8203 + fermentedspidereye = 8202
# Potion of Slowness (extended)
8202 + redstonedust = 8266
8234 + redstonedust = 8266
# Potion of Slowness (extended)
8259 + fermentedspidereye = 8266
8258 + fermentedspidereye = 8266
8267 + fermentedspidereye = 8266
# Potion of Weakness
8201 + fermentedspidereye = 8200
8193 + fermentedspidereye = 8200
# Potion of Weakness (extended)
8265 + fermentedspidereye = 8264
8257 + fermentedspidereye = 8264
# Potion of Weakness (extended)
8200 + redstonedust = 8264
8232 + redstonedust = 8264
### Reverted ###
## Glowstone ##
# Potion of Fire Resistance (reverted)
8259 + glowstonedust = 8227
# Potion of Night Vision (reverted)
8262 + glowstonedust = 8230
# Potion of Weakness (reverted)
8264 + glowstonedust = 8232
# Potion of Slowness (reverted)
8266 + glowstonedust = 8234
# Potion of Water Breathing (reverted)
8269 + glowstonedust = 8237
## Redstone ##
# Potion of Healing (reverted)
8229 + redstonedust = 8261
# Potion of Harming (reverted)
8236 + redstonedust = 8268
## Fermented Spider Eye ##
# Potion of Harming (reverted)
8261 + fermentedspidereye = 8268
8260 + fermentedspidereye = 8268
# Potion of Slowness (reverted)
8227 + fermentedspidereye = 8234
8226 + fermentedspidereye = 8234
# Potion of Weakness (reverted)
8233 + fermentedspidereye = 8232
8225 + fermentedspidereye = 8232

View File

@ -98,6 +98,7 @@ $cfile "../Mobs/Monster.h"
$cfile "../BlockEntities/BlockEntity.h"
$cfile "../BlockEntities/BeaconEntity.h"
$cfile "../BlockEntities/BlockEntityWithItems.h"
$cfile "../BlockEntities/BrewingstandEntity.h"
$cfile "../BlockEntities/ChestEntity.h"
$cfile "../BlockEntities/CommandBlockEntity.h"
$cfile "../BlockEntities/DropSpenserEntity.h"

View File

@ -20,6 +20,7 @@
#include "../ClientHandle.h"
#include "../BlockArea.h"
#include "../BlockEntities/BeaconEntity.h"
#include "../BlockEntities/BrewingstandEntity.h"
#include "../BlockEntities/ChestEntity.h"
#include "../BlockEntities/CommandBlockEntity.h"
#include "../BlockEntities/DispenserEntity.h"
@ -2516,6 +2517,54 @@ static int tolua_cRoot_GetBuildSeriesName(lua_State * tolua_S)
static int tolua_cRoot_GetBrewingRecipe(lua_State * tolua_S)
{
cLuaState L(tolua_S);
if (
!L.CheckParamUserTable(1, "cRoot") ||
!L.CheckParamUserType (2, "const cItem") ||
!L.CheckParamUserType (3, "const cItem") ||
!L.CheckParamEnd (4)
)
{
return 0;
}
// Check the bottle param:
cItem * Bottle = nullptr;
L.GetStackValue(2, Bottle);
if (Bottle == nullptr)
{
LOGWARNING("cRoot:GetBrewingRecipe: the Bottle parameter is nil or missing.");
return 0;
}
cItem * Ingredient = nullptr;
L.GetStackValue(3, Ingredient);
if (Ingredient == nullptr)
{
LOGWARNING("cRoot:GetBrewingRecipe: the Ingredient parameter is nil or missing.");
return 0;
}
// Get the recipe for the input
cBrewingRecipes * BR = cRoot::Get()->GetBrewingRecipes();
const cBrewingRecipes::cRecipe * Recipe = BR->GetRecipeFrom(*Bottle, *Ingredient);
if (Recipe == nullptr)
{
// There is no such brewing recipe for this bottle and ingredient, return no value
return 0;
}
// Push the output item
L.Push(Recipe->Output.get());
return 1;
}
static int tolua_cRoot_GetFurnaceRecipe(lua_State * tolua_S)
{
cLuaState L(tolua_S);
@ -3320,6 +3369,7 @@ void cManualBindings::Bind(lua_State * tolua_S)
tolua_function(tolua_S, "DoWithPlayerByUUID", DoWith <cRoot, cPlayer, &cRoot::DoWithPlayerByUUID>);
tolua_function(tolua_S, "ForEachPlayer", ForEach<cRoot, cPlayer, &cRoot::ForEachPlayer>);
tolua_function(tolua_S, "ForEachWorld", ForEach<cRoot, cWorld, &cRoot::ForEachWorld>);
tolua_function(tolua_S, "GetBrewingRecipe", tolua_cRoot_GetBrewingRecipe);
tolua_function(tolua_S, "GetBuildCommitID", tolua_cRoot_GetBuildCommitID);
tolua_function(tolua_S, "GetBuildDateTime", tolua_cRoot_GetBuildDateTime);
tolua_function(tolua_S, "GetBuildID", tolua_cRoot_GetBuildID);

View File

@ -580,6 +580,7 @@ void cManualBindings::BindWorld(lua_State * tolua_S)
tolua_function(tolua_S, "ChunkStay", tolua_cWorld_ChunkStay);
tolua_function(tolua_S, "DoWithBlockEntityAt", DoWithXYZ<cWorld, cBlockEntity, &cWorld::DoWithBlockEntityAt>);
tolua_function(tolua_S, "DoWithBeaconAt", DoWithXYZ<cWorld, cBeaconEntity, &cWorld::DoWithBeaconAt>);
tolua_function(tolua_S, "DoWithBrewingstandAt", DoWithXYZ<cWorld, cBrewingstandEntity, &cWorld::DoWithBrewingstandAt>);
tolua_function(tolua_S, "DoWithChestAt", DoWithXYZ<cWorld, cChestEntity, &cWorld::DoWithChestAt>);
tolua_function(tolua_S, "DoWithDispenserAt", DoWithXYZ<cWorld, cDispenserEntity, &cWorld::DoWithDispenserAt>);
tolua_function(tolua_S, "DoWithDropSpenserAt", DoWithXYZ<cWorld, cDropSpenserEntity, &cWorld::DoWithDropSpenserAt>);
@ -594,6 +595,7 @@ void cManualBindings::BindWorld(lua_State * tolua_S)
tolua_function(tolua_S, "FindAndDoWithPlayer", DoWith< cWorld, cPlayer, &cWorld::FindAndDoWithPlayer>);
tolua_function(tolua_S, "DoWithPlayerByUUID", DoWith< cWorld, cPlayer, &cWorld::DoWithPlayerByUUID>);
tolua_function(tolua_S, "ForEachBlockEntityInChunk", ForEachInChunk<cWorld, cBlockEntity, &cWorld::ForEachBlockEntityInChunk>);
tolua_function(tolua_S, "ForEachBrewingstandInChunk", ForEachInChunk<cWorld, cBrewingstandEntity, &cWorld::ForEachBrewingstandInChunk>);
tolua_function(tolua_S, "ForEachChestInChunk", ForEachInChunk<cWorld, cChestEntity, &cWorld::ForEachChestInChunk>);
tolua_function(tolua_S, "ForEachEntity", ForEach< cWorld, cEntity, &cWorld::ForEachEntity>);
tolua_function(tolua_S, "ForEachEntityInBox", ForEachInBox< cWorld, cEntity, &cWorld::ForEachEntityInBox>);

View File

@ -45,6 +45,8 @@ public:
/** Calls the specified hook with the params given. Returns the bool that the hook callback returns. */
virtual bool OnBlockSpread (cWorld & a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source) = 0;
virtual bool OnBlockToPickups (cWorld & a_World, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups) = 0;
virtual bool OnBrewingCompleting (cWorld & a_World, cBrewingstandEntity & a_BrewingstandEntity) = 0;
virtual bool OnBrewingCompleted (cWorld & a_World, cBrewingstandEntity & a_BrewingstandEntity) = 0;
virtual bool OnChat (cPlayer & a_Player, AString & a_Message) = 0;
virtual bool OnChunkAvailable (cWorld & a_World, int a_ChunkX, int a_ChunkZ) = 0;
virtual bool OnChunkGenerated (cWorld & a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc * a_ChunkDesc) = 0;

View File

@ -294,6 +294,54 @@ bool cPluginLua::OnBlockToPickups(cWorld & a_World, cEntity * a_Digger, int a_Bl
bool cPluginLua::OnBrewingCompleted(cWorld & a_World, cBrewingstandEntity & a_Brewingstand)
{
cCSLock Lock(m_CriticalSection);
if (!m_LuaState.IsValid())
{
return false;
}
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_BREWING_COMPLETED];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
{
m_LuaState.Call(static_cast<int>(**itr), &a_World, &a_Brewingstand, cLuaState::Return, res);
if (res)
{
return true;
}
}
return false;
}
bool cPluginLua::OnBrewingCompleting(cWorld & a_World, cBrewingstandEntity & a_Brewingstand)
{
cCSLock Lock(m_CriticalSection);
if (!m_LuaState.IsValid())
{
return false;
}
bool res = false;
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_BREWING_COMPLETING];
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
{
m_LuaState.Call(static_cast<int>(**itr), &a_World, &a_Brewingstand, cLuaState::Return, res);
if (res)
{
return true;
}
}
return false;
}
bool cPluginLua::OnChat(cPlayer & a_Player, AString & a_Message)
{
cCSLock Lock(m_CriticalSection);

View File

@ -105,6 +105,8 @@ public:
virtual bool OnBlockSpread (cWorld & a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source) override;
virtual bool OnBlockToPickups (cWorld & a_World, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups) override;
virtual bool OnBrewingCompleting (cWorld & a_World, cBrewingstandEntity & a_BrewingstandEntity) override;
virtual bool OnBrewingCompleted (cWorld & a_World, cBrewingstandEntity & a_BrewingstandEntity) override;
virtual bool OnChat (cPlayer & a_Player, AString & a_Message) override;
virtual bool OnChunkAvailable (cWorld & a_World, int a_ChunkX, int a_ChunkZ) override;
virtual bool OnChunkGenerated (cWorld & a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc * a_ChunkDesc) override;

View File

@ -269,6 +269,44 @@ bool cPluginManager::CallHookBlockToPickups(
bool cPluginManager::CallHookBrewingCompleted(cWorld & a_World, cBrewingstandEntity & a_Brewingstand)
{
FIND_HOOK(HOOK_BREWING_COMPLETED);
VERIFY_HOOK;
for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr)
{
if ((*itr)->OnBrewingCompleted(a_World, a_Brewingstand))
{
return true;
}
}
return false;
}
bool cPluginManager::CallHookBrewingCompleting(cWorld & a_World, cBrewingstandEntity & a_Brewingstand)
{
FIND_HOOK(HOOK_BREWING_COMPLETING);
VERIFY_HOOK;
for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr)
{
if ((*itr)->OnBrewingCompleting(a_World, a_Brewingstand))
{
return true;
}
}
return false;
}
bool cPluginManager::CallHookChat(cPlayer & a_Player, AString & a_Message)
{
// Check if the message contains a command, execute it:

View File

@ -10,6 +10,7 @@
// fwd:
class cBlockEntityWithItems;
class cBrewingstandEntity;
class cChunkDesc;
class cClientHandle;
class cCommandOutputCallback;
@ -75,6 +76,8 @@ public:
{
HOOK_BLOCK_SPREAD,
HOOK_BLOCK_TO_PICKUPS,
HOOK_BREWING_COMPLETING,
HOOK_BREWING_COMPLETED,
HOOK_CHAT,
HOOK_CHUNK_AVAILABLE,
HOOK_CHUNK_GENERATED,
@ -193,6 +196,8 @@ public:
// Calls for individual hooks. Each returns false if the action is to continue or true if the plugin wants to abort
bool CallHookBlockSpread (cWorld & a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source);
bool CallHookBlockToPickups (cWorld & a_World, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups);
bool CallHookBrewingCompleting (cWorld & a_World, cBrewingstandEntity & a_Brewingstand);
bool CallHookBrewingCompleted (cWorld & a_World, cBrewingstandEntity & a_Brewingstand);
bool CallHookChat (cPlayer & a_Player, AString & a_Message);
bool CallHookChunkAvailable (cWorld & a_World, int a_ChunkX, int a_ChunkZ);
bool CallHookChunkGenerated (cWorld & a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc * a_ChunkDesc);

View File

@ -6,6 +6,7 @@
#include "Globals.h"
#include "BeaconEntity.h"
#include "BlockEntity.h"
#include "BrewingstandEntity.h"
#include "ChestEntity.h"
#include "CommandBlockEntity.h"
#include "DispenserEntity.h"
@ -36,6 +37,7 @@ cBlockEntity * cBlockEntity::CreateByBlockType(BLOCKTYPE a_BlockType, NIBBLETYPE
case E_BLOCK_ENDER_CHEST: return new cEnderChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_FLOWER_POT: return new cFlowerPotEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World);
case E_BLOCK_BREWING_STAND: return new cBrewingstandEntity(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World);
case E_BLOCK_HEAD: return new cMobHeadEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_HOPPER: return new cHopperEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_MOB_SPAWNER: return new cMobSpawnerEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);

View File

@ -0,0 +1,309 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "BrewingstandEntity.h"
#include "../Bindings/PluginManager.h"
#include "../UI/BrewingstandWindow.h"
#include "../Entities/Player.h"
#include "../Root.h"
#include "../Chunk.h"
cBrewingstandEntity::cBrewingstandEntity(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cWorld * a_World) :
super(a_BlockType, a_BlockX, a_BlockY, a_BlockZ, ContentsWidth, ContentsHeight, a_World),
m_BlockMeta(a_BlockMeta),
m_IsDestroyed(false),
m_IsBrewing(false),
m_TimeBrewed(0)
{
m_Contents.AddListener(*this);
for (int i = 0; i < 3; i++)
{
m_Results[i] = *(new cItem());
}
}
cBrewingstandEntity::~cBrewingstandEntity()
{
// Tell window its owner is destroyed
cWindow * Window = GetWindow();
if (Window != nullptr)
{
Window->OwnerDestroyed();
}
}
void cBrewingstandEntity::UsedBy(cPlayer * a_Player)
{
cWindow * Window = GetWindow();
if (Window == nullptr)
{
OpenWindow(new cBrewingstandWindow(m_PosX, m_PosY, m_PosZ, this));
Window = GetWindow();
}
if (Window != nullptr)
{
if (a_Player->GetWindow() != Window)
{
a_Player->OpenWindow(Window);
}
}
if (m_IsBrewing)
{
BroadcastProgress(0, m_NeedBrewingTime - m_TimeBrewed);
}
else
{
BroadcastProgress(0, 0);
}
}
bool cBrewingstandEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
UNUSED(a_Dt);
if (!m_IsBrewing)
{
return false;
}
const cBrewingRecipes::cRecipe * Recipe = nullptr;
// The necessary brewing time, has been reached
if (m_TimeBrewed >= m_NeedBrewingTime)
{
BroadcastProgress(0, 0);
m_IsBrewing = false;
m_TimeBrewed = 0;
// Return if the hook has been canceled
if (cPluginManager::Get()->CallHookBrewingCompleting(*m_World, *this))
{
return false;
}
// Decrease item count, full stacks are allowed in the ingredient slot
cItem Ingredient = m_Contents.GetSlot(bsIngredient);
Ingredient.m_ItemCount -= 1;
m_Contents.SetSlot(bsIngredient, Ingredient);
// Loop over all bottle slots and update available bottles
for (int i = 0; i < 3; i++)
{
if (m_Contents.GetSlot(i).IsEmpty() || (m_CurrentBrewingRecipes[i] == nullptr))
{
continue;
}
Recipe = m_CurrentBrewingRecipes[i];
m_Contents.SetSlot(i, Recipe->Output->CopyOne());
}
// Brewing process completed
cPluginManager::Get()->CallHookBrewingCompleted(*m_World, *this);
return true;
}
m_TimeBrewed++;
UpdateProgressBars(false);
return false;
}
void cBrewingstandEntity::SendTo(cClientHandle & a_Client)
{
// Nothing needs to be sent
UNUSED(a_Client);
}
void cBrewingstandEntity::BroadcastProgress(short a_ProgressbarID, short a_Value)
{
cWindow * Window = GetWindow();
if (Window != nullptr)
{
Window->SetProperty(a_ProgressbarID, a_Value);
}
}
void cBrewingstandEntity::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum)
{
super::OnSlotChanged(a_ItemGrid, a_SlotNum);
if (m_IsDestroyed)
{
return;
}
ASSERT(a_ItemGrid == &m_Contents);
// Check if still a item is in the ingredient slot
if (GetSlot(bsIngredient).IsEmpty())
{
if (m_IsBrewing)
{
// Cancel brewing
BroadcastProgress(0, 0);
m_IsBrewing = false;
m_TimeBrewed = 0;
}
return;
}
// Recheck the bottles
cBrewingRecipes * BR = cRoot::Get()->GetBrewingRecipes();
const cBrewingRecipes::cRecipe * Recipe = nullptr;
bool Stop = true;
for (int i = 0; i < 3; i++)
{
if (GetSlot(i).IsEmpty())
{
m_CurrentBrewingRecipes[i] = nullptr;
m_Results[i].Clear();
continue;
}
if (m_CurrentBrewingRecipes[i] != nullptr)
{
Recipe = m_CurrentBrewingRecipes[i];
if (Recipe->Ingredient->IsEqual(GetSlot(bsIngredient)) && Recipe->Input->IsEqual(GetSlot(i)))
{
Stop = false;
continue;
}
}
Recipe = BR->GetRecipeFrom(m_Contents.GetSlot(i), m_Contents.GetSlot(bsIngredient));
if (Recipe != nullptr)
{
// Found a brewing recipe for the items
m_CurrentBrewingRecipes[i] = Recipe;
m_Results[i] = Recipe->Output->CopyOne();
Stop = false;
}
}
if (Stop)
{
if (m_IsBrewing)
{
// Cancel brewing
BroadcastProgress(0, 0);
m_IsBrewing = false;
m_TimeBrewed = 0;
}
return;
}
// Start brewing process, if not running
if (!m_IsBrewing)
{
m_IsBrewing = true;
}
}
void cBrewingstandEntity::UpdateProgressBars(bool a_ForceUpdate)
{
/** Sending an update every 3th tick, using a higher value lets look the progressbar ugly */
if (!a_ForceUpdate && (m_World->GetWorldAge() % 3 != 0))
{
return;
}
BroadcastProgress(0, m_NeedBrewingTime - m_TimeBrewed);
}
void cBrewingstandEntity::setTimeBrewed(short a_TimeBrewed)
{
m_TimeBrewed = a_TimeBrewed;
}
void cBrewingstandEntity::ContinueBrewing(void)
{
// Continue brewing if number is greater than 0
if (m_TimeBrewed > 0)
{
m_IsBrewing = true;
}
}
void cBrewingstandEntity::GetRecipes(void)
{
if (GetSlot(3).IsEmpty())
{
return;
}
cBrewingRecipes * BR = cRoot::Get()->GetBrewingRecipes();
const cBrewingRecipes::cRecipe * Recipe = nullptr;
for (int i = 0; i < 3; i++)
{
if (GetSlot(i).IsEmpty())
{
continue;
}
Recipe = BR->GetRecipeFrom(GetSlot(i), GetSlot(bsIngredient));
if (Recipe != nullptr)
{
m_CurrentBrewingRecipes[i] = Recipe;
m_Results[i] = Recipe->Output->CopyOne();
}
}
}

View File

@ -0,0 +1,136 @@
#pragma once
#include "BlockEntityWithItems.h"
#include "../BrewingRecipes.h"
#include "../Root.h"
class cClientHandle;
// tolua_begin
class cBrewingstandEntity :
public cBlockEntityWithItems
{
typedef cBlockEntityWithItems super;
public:
enum
{
bsLeftBottle = 0, // Left bottle slot number
bsMiddleBottle = 1, // Middle bottle slot number
bsRightBottle = 2, // Right bottle slot number
bsIngredient = 3, // Top ingredient slot number
ContentsWidth = 4,
ContentsHeight = 1,
};
// tolua_end
BLOCKENTITY_PROTODEF(cBrewingstandEntity)
/** Constructor used for normal operation */
cBrewingstandEntity(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cWorld * a_World);
virtual ~cBrewingstandEntity();
// cBlockEntity overrides:
virtual void SendTo(cClientHandle & a_Client) override;
virtual bool Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
virtual void UsedBy(cPlayer * a_Player) override;
virtual void Destroy() override
{
m_IsDestroyed = true;
super::Destroy();
}
// tolua_begin
/** Returns the time until the current items finishes brewing, in ticks */
short GetBrewingTimeLeft(void) const { return m_NeedBrewingTime - m_TimeBrewed; }
/** Returns the time that the current items has been brewing, in ticks */
short GetTimeBrewed(void) { return m_TimeBrewed; }
/** Returns the item in the left bottle slot */
const cItem & GetLeftBottleSlot(void) const { return GetSlot(bsLeftBottle); }
/** Returns the item in the middle bottle slot */
const cItem & GetMiddleBottleSlot(void) const { return GetSlot(bsMiddleBottle); }
/** Returns the item in the right bottle slot */
const cItem & GetRightBottleSlot(void) const { return GetSlot(bsRightBottle); }
/** Returns the item in the ingredient slot */
const cItem & GetIndgredientSlot(void) const { return GetSlot(bsIngredient); }
/** Get the expected result item for the given slot number */
const cItem & GetResultItem(int a_SlotNumber) { return m_Results[a_SlotNumber]; }
/** Sets the item in the left bottle slot */
void SetLeftBottleSlot(const cItem & a_Item) { SetSlot(bsLeftBottle, a_Item); }
/** Sets the item in the middle bottle slot */
void SetMiddleBottleSlot(const cItem & a_Item) { SetSlot(bsMiddleBottle, a_Item); }
/** Sets the item in the right bottle slot */
void SetRightBottleSlot(const cItem & a_Item) { SetSlot(bsRightBottle, a_Item); }
/** Sets the item in the ingredient slot */
void SetIngredientSlot(const cItem & a_Item) { SetSlot(bsIngredient, a_Item); }
// tolua_end
/** Sets the current brewing time. Will be called if the brewing stand gets loaded from the world. */
void setTimeBrewed(short a_TimeBrewed);
/** Starts the brewing proccess. Will be called if the brewing stand gets loaded from the world. */
void ContinueBrewing(void);
/** Gets the recipes. Will be called if the brewing stand gets loaded from the world. */
void GetRecipes(void);
protected:
/** Block meta of the block currently represented by this entity */
NIBBLETYPE m_BlockMeta;
/** Set to true when the brewing stand entity has been destroyed to prevent the block being set again */
bool m_IsDestroyed;
/** Set to true if the brewing stand is brewing an item */
bool m_IsBrewing;
/** Brewing time is 400 ticks */
const short m_NeedBrewingTime = 400;
/** Store the current brewing recipes */
const cBrewingRecipes::cRecipe * m_CurrentBrewingRecipes[3] = {};
/** Result items for the bottle inputs */
cItem m_Results[3] = {};
/** Amount of ticks that the current item has been brewed */
short m_TimeBrewed;
/** Sends the specified progressbar value to all clients of the window */
void BroadcastProgress(short a_ProgressbarID, short a_Value);
// /** Broadcasts progressbar updates, if needed */
void UpdateProgressBars(bool a_ForceUpdate = false);
// cItemGrid::cListener overrides:
virtual void OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) override;
} ; // tolua_export

View File

@ -7,6 +7,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../")
SET (SRCS
BeaconEntity.cpp
BlockEntity.cpp
BrewingstandEntity.cpp
ChestEntity.cpp
CommandBlockEntity.cpp
DispenserEntity.cpp
@ -27,6 +28,7 @@ SET (HDRS
BeaconEntity.h
BlockEntity.h
BlockEntityWithItems.h
BrewingstandEntity.h
ChestEntity.h
CommandBlockEntity.h
DispenserEntity.h

View File

@ -1,18 +1,18 @@
#pragma once
#include "BlockEntity.h"
#include "BlockHandler.h"
#include "MetaRotator.h"
class cBlockBrewingStandHandler :
public cBlockHandler
public cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>
{
public:
cBlockBrewingStandHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType)
: cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>(a_BlockType)
{
}

287
src/BrewingRecipes.cpp Normal file
View File

@ -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;
}