summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/AllToLua.pkg1
-rw-r--r--source/Bindings.cpp54
-rw-r--r--source/Bindings.h2
-rw-r--r--source/BlockID.cpp38
-rw-r--r--source/BlockID.h1
-rw-r--r--source/Defines.h16
-rw-r--r--source/blocks/Block.cpp302
-rw-r--r--source/blocks/Block.h54
-rw-r--r--source/blocks/BlockCactus.h51
-rw-r--r--source/blocks/BlockChest.h22
-rw-r--r--source/blocks/BlockCloth.cpp9
-rw-r--r--source/blocks/BlockCloth.h14
-rw-r--r--source/blocks/BlockCrops.h56
-rw-r--r--source/blocks/BlockDirt.cpp9
-rw-r--r--source/blocks/BlockDirt.h62
-rw-r--r--source/blocks/BlockDispenser.h22
-rw-r--r--source/blocks/BlockDoor.cpp60
-rw-r--r--source/blocks/BlockDoor.h29
-rw-r--r--source/blocks/BlockEntity.cpp15
-rw-r--r--source/blocks/BlockEntity.h16
-rw-r--r--source/blocks/BlockFire.cpp24
-rw-r--r--source/blocks/BlockFire.h14
-rw-r--r--source/blocks/BlockFlower.h32
-rw-r--r--source/blocks/BlockFluid.h20
-rw-r--r--source/blocks/BlockFurnace.h27
-rw-r--r--source/blocks/BlockGlowstone.h22
-rw-r--r--source/blocks/BlockIce.h26
-rw-r--r--source/blocks/BlockLadder.h28
-rw-r--r--source/blocks/BlockLeaves.h162
-rw-r--r--source/blocks/BlockMelon.h24
-rw-r--r--source/blocks/BlockMushroom.h42
-rw-r--r--source/blocks/BlockPiston.cpp51
-rw-r--r--source/blocks/BlockPiston.h15
-rw-r--r--source/blocks/BlockRedstone.cpp41
-rw-r--r--source/blocks/BlockRedstone.h33
-rw-r--r--source/blocks/BlockRedstoneOre.h26
-rw-r--r--source/blocks/BlockRedstoneRepeater.cpp34
-rw-r--r--source/blocks/BlockRedstoneRepeater.h46
-rw-r--r--source/blocks/BlockRedstoneTorch.h30
-rw-r--r--source/blocks/BlockSapling.h51
-rw-r--r--source/blocks/BlockSign.h42
-rw-r--r--source/blocks/BlockSlab.cpp17
-rw-r--r--source/blocks/BlockSlab.h33
-rw-r--r--source/blocks/BlockSnow.h39
-rw-r--r--source/blocks/BlockStairs.cpp18
-rw-r--r--source/blocks/BlockStairs.h14
-rw-r--r--source/blocks/BlockStems.h41
-rw-r--r--source/blocks/BlockStone.h18
-rw-r--r--source/blocks/BlockSugarcane.h43
-rw-r--r--source/blocks/BlockTallGrass.h35
-rw-r--r--source/blocks/BlockTorch.cpp15
-rw-r--r--source/blocks/BlockTorch.h25
-rw-r--r--source/blocks/BlockVine.cpp17
-rw-r--r--source/blocks/BlockVine.h23
-rw-r--r--source/blocks/BlockWood.h17
-rw-r--r--source/blocks/BlockWorkbench.cpp24
-rw-r--r--source/blocks/BlockWorkbench.h19
-rw-r--r--source/cBlockToPickup.cpp317
-rw-r--r--source/cBlockToPickup.h1
-rw-r--r--source/cChunk.cpp214
-rw-r--r--source/cChunk.h1
-rw-r--r--source/cClientHandle.cpp638
-rw-r--r--source/cFluidSimulator.cpp18
-rw-r--r--source/cPiston.cpp9
-rw-r--r--source/cPiston.h4
-rw-r--r--source/cRoot.cpp13
-rw-r--r--source/cStep.h15
-rw-r--r--source/cWorld.cpp139
-rw-r--r--source/cWorld.h21
-rw-r--r--source/items/Item.cpp224
-rw-r--r--source/items/Item.h45
-rw-r--r--source/items/ItemBucket.h75
-rw-r--r--source/items/ItemCloth.h18
-rw-r--r--source/items/ItemDoor.h25
-rw-r--r--source/items/ItemDye.h32
-rw-r--r--source/items/ItemHoe.h29
-rw-r--r--source/items/ItemLeaves.h17
-rw-r--r--source/items/ItemLighter.h27
-rw-r--r--source/items/ItemPickaxe.h72
-rw-r--r--source/items/ItemRedstoneDust.h27
-rw-r--r--source/items/ItemSapling.h20
-rw-r--r--source/items/ItemSeeds.h58
-rw-r--r--source/items/ItemShears.h41
-rw-r--r--source/items/ItemShovel.h35
-rw-r--r--source/items/ItemSlab.h39
-rw-r--r--source/items/ItemSugarcane.h34
-rw-r--r--source/items/ItemSword.h19
-rw-r--r--source/items/ItemWood.h17
-rw-r--r--source/main.cpp10
89 files changed, 3033 insertions, 1242 deletions
diff --git a/source/AllToLua.pkg b/source/AllToLua.pkg
index b6ee64579..e8268bfa6 100644
--- a/source/AllToLua.pkg
+++ b/source/AllToLua.pkg
@@ -7,7 +7,6 @@ $cfile "ChunkDef.h"
$cfile "cTorch.h"
$cfile "cStairs.h"
-$cfile "cStep.h"
$cfile "cLadder.h"
$cfile "cVine.h"
diff --git a/source/Bindings.cpp b/source/Bindings.cpp
index 638563732..9f780d6aa 100644
--- a/source/Bindings.cpp
+++ b/source/Bindings.cpp
@@ -1,6 +1,6 @@
/*
** Lua binding: AllToLua
-** Generated automatically by tolua++-1.0.92 on 07/15/12 14:45:49.
+** Generated automatically by tolua++-1.0.92 on 07/15/12 22:27:57.
*/
#ifndef __cplusplus
@@ -18,7 +18,6 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S);
#include "ChunkDef.h"
#include "cTorch.h"
#include "cStairs.h"
-#include "cStep.h"
#include "cLadder.h"
#include "cVine.h"
#include "../iniFile/iniFile.h"
@@ -184,26 +183,25 @@ static void tolua_reg_types (lua_State* tolua_S)
{
tolua_usertype(tolua_S,"TakeDamageInfo");
tolua_usertype(tolua_S,"cLuaItems");
- tolua_usertype(tolua_S,"cCraftingGrid");
tolua_usertype(tolua_S,"cCraftingRecipe");
tolua_usertype(tolua_S,"cPlugin");
- tolua_usertype(tolua_S,"cLuaChunk");
+ tolua_usertype(tolua_S,"cCraftingGrid");
tolua_usertype(tolua_S,"cStringMap");
- tolua_usertype(tolua_S,"cPluginManager");
+ tolua_usertype(tolua_S,"cLuaChunk");
tolua_usertype(tolua_S,"cBlockArea");
+ tolua_usertype(tolua_S,"cPluginManager");
tolua_usertype(tolua_S,"Lua__cPacket_BlockDig");
- tolua_usertype(tolua_S,"Lua__cTCPLink");
tolua_usertype(tolua_S,"cServer");
tolua_usertype(tolua_S,"cRoot");
- tolua_usertype(tolua_S,"cVine");
- tolua_usertype(tolua_S,"cTracer");
+ tolua_usertype(tolua_S,"Lua__cTCPLink");
+ tolua_usertype(tolua_S,"cPawn");
tolua_usertype(tolua_S,"cGroup");
tolua_usertype(tolua_S,"cPlugin::CommandStruct");
tolua_usertype(tolua_S,"cPickup");
tolua_usertype(tolua_S,"cItems");
tolua_usertype(tolua_S,"cPacket_Login");
tolua_usertype(tolua_S,"cClientHandle");
- tolua_usertype(tolua_S,"cStep");
+ tolua_usertype(tolua_S,"cTracer");
tolua_usertype(tolua_S,"cFurnaceRecipe");
tolua_usertype(tolua_S,"cMCLogger");
tolua_usertype(tolua_S,"cChatColor");
@@ -228,12 +226,12 @@ static void tolua_reg_types (lua_State* tolua_S)
tolua_usertype(tolua_S,"Lua__cEntity");
tolua_usertype(tolua_S,"cPacket_BlockPlace");
tolua_usertype(tolua_S,"cLadder");
- tolua_usertype(tolua_S,"cWebPlugin");
tolua_usertype(tolua_S,"Lua__cPlayer");
+ tolua_usertype(tolua_S,"cWebPlugin");
tolua_usertype(tolua_S,"cIniFile");
tolua_usertype(tolua_S,"cEntity");
tolua_usertype(tolua_S,"HTTPRequest");
- tolua_usertype(tolua_S,"cPawn");
+ tolua_usertype(tolua_S,"cVine");
tolua_usertype(tolua_S,"cPlayer");
tolua_usertype(tolua_S,"cTorch");
tolua_usertype(tolua_S,"HTTPFormData");
@@ -336,36 +334,6 @@ static int tolua_AllToLua_cStairs_RotationToMetaData00(lua_State* tolua_S)
}
#endif //#ifndef TOLUA_DISABLE
-/* method: DirectionToMetaData of class cStep */
-#ifndef TOLUA_DISABLE_tolua_AllToLua_cStep_DirectionToMetaData00
-static int tolua_AllToLua_cStep_DirectionToMetaData00(lua_State* tolua_S)
-{
-#ifndef TOLUA_RELEASE
- tolua_Error tolua_err;
- if (
- !tolua_isusertable(tolua_S,1,"cStep",0,&tolua_err) ||
- !tolua_isnumber(tolua_S,2,0,&tolua_err) ||
- !tolua_isnoobj(tolua_S,3,&tolua_err)
- )
- goto tolua_lerror;
- else
-#endif
- {
- int a_Direction = ((int) tolua_tonumber(tolua_S,2,0));
- {
- char tolua_ret = (char) cStep::DirectionToMetaData(a_Direction);
- tolua_pushnumber(tolua_S,(lua_Number)tolua_ret);
- }
- }
- return 1;
-#ifndef TOLUA_RELEASE
- tolua_lerror:
- tolua_error(tolua_S,"#ferror in function 'DirectionToMetaData'.",&tolua_err);
- return 0;
-#endif
-}
-#endif //#ifndef TOLUA_DISABLE
-
/* method: DirectionToMetaData of class cLadder */
#ifndef TOLUA_DISABLE_tolua_AllToLua_cLadder_DirectionToMetaData00
static int tolua_AllToLua_cLadder_DirectionToMetaData00(lua_State* tolua_S)
@@ -21154,10 +21122,6 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S)
tolua_beginmodule(tolua_S,"cStairs");
tolua_function(tolua_S,"RotationToMetaData",tolua_AllToLua_cStairs_RotationToMetaData00);
tolua_endmodule(tolua_S);
- tolua_cclass(tolua_S,"cStep","cStep","",NULL);
- tolua_beginmodule(tolua_S,"cStep");
- tolua_function(tolua_S,"DirectionToMetaData",tolua_AllToLua_cStep_DirectionToMetaData00);
- tolua_endmodule(tolua_S);
tolua_cclass(tolua_S,"cLadder","cLadder","",NULL);
tolua_beginmodule(tolua_S,"cLadder");
tolua_function(tolua_S,"DirectionToMetaData",tolua_AllToLua_cLadder_DirectionToMetaData00);
diff --git a/source/Bindings.h b/source/Bindings.h
index 37371c0b2..781e10357 100644
--- a/source/Bindings.h
+++ b/source/Bindings.h
@@ -1,6 +1,6 @@
/*
** Lua binding: AllToLua
-** Generated automatically by tolua++-1.0.92 on 07/15/12 14:45:49.
+** Generated automatically by tolua++-1.0.92 on 07/15/12 22:27:58.
*/
/* Exported function */
diff --git a/source/BlockID.cpp b/source/BlockID.cpp
index 42f4951e6..46a8ef5ca 100644
--- a/source/BlockID.cpp
+++ b/source/BlockID.cpp
@@ -18,6 +18,7 @@ bool g_BlockTransparent[256];
bool g_BlockOneHitDig[256];
bool g_BlockPistonBreakable[256];
bool g_BlockIsSnowable[256];
+bool g_BlockRequiresSpecialTool[256];
@@ -174,6 +175,7 @@ public:
memset( g_BlockOneHitDig, 0x00, sizeof( g_BlockOneHitDig ) );
memset( g_BlockPistonBreakable, 0x00, sizeof( g_BlockPistonBreakable ) );
memset( g_BlockIsSnowable, 0xff, sizeof( g_BlockIsSnowable)); // Set all blocks' snowable to true
+ memset( g_BlockRequiresSpecialTool, false, sizeof( g_BlockRequiresSpecialTool));
// Emissive blocks
g_BlockLightValue[E_BLOCK_FIRE] = 15;
@@ -324,6 +326,42 @@ public:
g_BlockIsSnowable[E_BLOCK_WALLSIGN] = false;
g_BlockIsSnowable[E_BLOCK_WATER] = false;
g_BlockIsSnowable[E_BLOCK_YELLOW_FLOWER] = false;
+
+ //Blocks that donīt drop without a special tool
+ g_BlockRequiresSpecialTool[E_BLOCK_DIAMOND_BLOCK] = true;
+ g_BlockRequiresSpecialTool[E_BLOCK_DIAMOND_ORE] = true;
+ g_BlockRequiresSpecialTool[E_BLOCK_GOLD_BLOCK] = true;
+ g_BlockRequiresSpecialTool[E_BLOCK_GOLD_ORE] = true;
+ g_BlockRequiresSpecialTool[E_BLOCK_IRON_BLOCK] = true;
+ g_BlockRequiresSpecialTool[E_BLOCK_IRON_ORE] = true;
+ g_BlockRequiresSpecialTool[E_BLOCK_REDSTONE_ORE] = true;
+ g_BlockRequiresSpecialTool[E_BLOCK_REDSTONE_ORE_GLOWING]= true;
+ g_BlockRequiresSpecialTool[E_BLOCK_LAPIS_ORE] = true;
+ g_BlockRequiresSpecialTool[E_BLOCK_LAPIS_BLOCK] = true;
+ g_BlockRequiresSpecialTool[E_BLOCK_EMERALD_ORE] = true;
+ g_BlockRequiresSpecialTool[E_BLOCK_COAL_ORE] = true;
+ g_BlockRequiresSpecialTool[E_BLOCK_OBSIDIAN] = true;
+ g_BlockRequiresSpecialTool[E_BLOCK_STONE] = true;
+ g_BlockRequiresSpecialTool[E_BLOCK_COBBLESTONE] = true;
+ g_BlockRequiresSpecialTool[E_BLOCK_END_STONE] = true;
+ g_BlockRequiresSpecialTool[E_BLOCK_MOSSY_COBBLESTONE] = true;
+ g_BlockRequiresSpecialTool[E_BLOCK_SANDSTONE] = true;
+ g_BlockRequiresSpecialTool[E_BLOCK_STONE_BRICKS] = true;
+ g_BlockRequiresSpecialTool[E_BLOCK_COBWEB] = true;
+ g_BlockRequiresSpecialTool[E_BLOCK_SNOW] = true;
+ g_BlockRequiresSpecialTool[E_BLOCK_NETHER_BRICK] = true;
+ g_BlockRequiresSpecialTool[E_BLOCK_NETHERRACK] = true;
+ g_BlockRequiresSpecialTool[E_BLOCK_STONE_SLAB] = true;
+ g_BlockRequiresSpecialTool[E_BLOCK_DOUBLE_STONE_SLAB] = true;
+ g_BlockRequiresSpecialTool[E_BLOCK_STONE_PRESSURE_PLATE]= true;
+ g_BlockRequiresSpecialTool[E_BLOCK_BRICK] = true;
+ g_BlockRequiresSpecialTool[E_BLOCK_COBBLESTONE_STAIRS] = true;
+ g_BlockRequiresSpecialTool[E_BLOCK_STONE_BRICK_STAIRS] = true;
+ g_BlockRequiresSpecialTool[E_BLOCK_SANDSTONE_STAIRS] = true;
+ g_BlockRequiresSpecialTool[E_BLOCK_NETHER_BRICK_STAIRS] = true;
+ g_BlockRequiresSpecialTool[E_BLOCK_VINES] = true;
+
+
}
} BlockPropertiesInitializer;
diff --git a/source/BlockID.h b/source/BlockID.h
index b94744310..becc0cad8 100644
--- a/source/BlockID.h
+++ b/source/BlockID.h
@@ -636,6 +636,7 @@ extern bool g_BlockTransparent[256];
extern bool g_BlockOneHitDig[256];
extern bool g_BlockPistonBreakable[256];
extern bool g_BlockIsSnowable[256];
+extern bool g_BlockRequiresSpecialTool[256];
diff --git a/source/Defines.h b/source/Defines.h
index edb1b485f..338f8347a 100644
--- a/source/Defines.h
+++ b/source/Defines.h
@@ -77,6 +77,17 @@ inline bool IsBlockLiquid(char a_BlockID)
return IsBlockWater(a_BlockID) || IsBlockLava(a_BlockID);
}
+inline bool IsBlockTypeOfDirt(char a_BlockID)
+{
+ switch (a_BlockID)
+ {
+ case E_BLOCK_DIRT:
+ case E_BLOCK_GRASS:
+ case E_BLOCK_FARMLAND:
+ return true;
+ }
+ return false;
+}
@@ -268,6 +279,11 @@ namespace ItemCategory
//tolua_end
+inline bool BlockRequiresSpecialTool(BLOCKTYPE a_BlockID)
+{
+ if(!IsValidBlock(a_BlockID)) return false;
+ return g_BlockRequiresSpecialTool[a_BlockID];
+}
//tolua_begin
diff --git a/source/blocks/Block.cpp b/source/blocks/Block.cpp
new file mode 100644
index 000000000..047caa989
--- /dev/null
+++ b/source/blocks/Block.cpp
@@ -0,0 +1,302 @@
+#include "Globals.h"
+#include "Block.h"
+#include "../cItem.h"
+#include "../cWorld.h"
+#include "BlockDoor.h"
+#include "BlockFire.h"
+#include "BlockRedstone.h"
+#include "BlockRedstoneTorch.h"
+#include "BlockRedstoneRepeater.h"
+#include "BlockPiston.h"
+#include "BlockWorkbench.h"
+#include "BlockEntity.h"
+#include "BlockVine.h"
+#include "BlockTallGrass.h"
+#include "BlockSnow.h"
+#include "BlockCloth.h"
+#include "BlockSlab.h"
+#include "BlockDirt.h"
+#include "BlockTorch.h"
+#include "BlockWood.h"
+#include "BlockLeaves.h"
+#include "BlockSapling.h"
+#include "BlockFluid.h"
+#include "BlockChest.h"
+#include "BlockFurnace.h"
+#include "BlockDispenser.h"
+#include "BlockStairs.h"
+#include "BlockLadder.h"
+#include "BlockSign.h"
+#include "BlockCrops.h"
+#include "BlockSugarcane.h"
+#include "BlockFlower.h"
+#include "BlockMushroom.h"
+#include "BlockCactus.h"
+#include "BlockStems.h"
+#include "BlockGlowstone.h"
+#include "BlockRedstoneOre.h"
+#include "BlockStone.h"
+#include "BlockMelon.h"
+#include "BlockIce.h"
+
+bool cBlockHandler::m_HandlerInitialized = false;
+cBlockHandler *cBlockHandler::m_BlockHandler[256];
+
+cBlockHandler *cBlockHandler::GetBlockHandler(char a_BlockID)
+{
+ if(!m_HandlerInitialized)
+ { //We have to initialize
+ memset(m_BlockHandler, 0, sizeof(m_BlockHandler));
+ m_HandlerInitialized = true;
+ }
+ if(m_BlockHandler[a_BlockID])
+ return m_BlockHandler[a_BlockID];
+
+ return m_BlockHandler[a_BlockID] = CreateBlockHandler(a_BlockID);
+}
+
+cBlockHandler *cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockID)
+{
+ switch(a_BlockID)
+ {
+ case E_BLOCK_WOODEN_DOOR:
+ case E_BLOCK_IRON_DOOR:
+ return new cBlockDoorHandler(a_BlockID);
+ case E_BLOCK_FIRE:
+ return new cBlockFireHandler(a_BlockID);
+ case E_BLOCK_REDSTONE_TORCH_ON:
+ case E_BLOCK_REDSTONE_TORCH_OFF:
+ return new cBlockRedstoneTorchHandler(a_BlockID);
+ case E_BLOCK_REDSTONE_WIRE:
+ return new cBlockRedstoneHandler(a_BlockID);
+ case E_BLOCK_PISTON:
+ case E_BLOCK_STICKY_PISTON:
+ return new cBlockPistonHandler(a_BlockID);
+ case E_BLOCK_REDSTONE_REPEATER_ON:
+ case E_BLOCK_REDSTONE_REPEATER_OFF:
+ return new cBlockRedstoneRepeaterHandler(a_BlockID);
+ case E_BLOCK_WORKBENCH:
+ return new cBlockWorkbenchHandler(a_BlockID);
+ case E_BLOCK_SNOW:
+ return new cBlockSnowHandler(a_BlockID);
+ case E_BLOCK_TALL_GRASS:
+ return new cBlockTallGrassHandler(a_BlockID);
+ case E_BLOCK_VINES:
+ return new cBlockVineHandler(a_BlockID);
+ case ::E_BLOCK_WOOL:
+ return new cBlockClothHandler(a_BlockID);
+ case E_BLOCK_WOODEN_SLAB:
+ case E_BLOCK_STONE_SLAB:
+ case E_BLOCK_DOUBLE_WOODEN_SLAB:
+ case E_BLOCK_DOUBLE_STONE_SLAB:
+ return new cBlockSlabHandler(a_BlockID);
+ case E_BLOCK_LOG:
+ case E_BLOCK_PLANKS:
+ return new cBlockWoodHandler(a_BlockID);
+ case E_BLOCK_TORCH:
+ return new cBlockTorchHandler(a_BlockID);
+ case E_BLOCK_DIRT:
+ case E_BLOCK_GRASS:
+ return new cBlockDirtHandler(a_BlockID);
+ case E_BLOCK_LEAVES:
+ return new cBlockLeavesHandler(a_BlockID);
+ case E_BLOCK_SAPLING:
+ return new cBlockSaplingHandler(a_BlockID);
+ case E_BLOCK_WATER:
+ case E_BLOCK_STATIONARY_WATER:
+ case E_BLOCK_STATIONARY_LAVA:
+ case E_BLOCK_LAVA:
+ return new cBlockFluidHandler(a_BlockID);
+ case E_BLOCK_DISPENSER:
+ return new cBlockDispenserHandler(a_BlockID);
+ case E_BLOCK_FURNACE:
+ case E_BLOCK_LIT_FURNACE:
+ return new cBlockFurnaceHandler(a_BlockID);
+ case E_BLOCK_CHEST:
+ return new cBlockChestHandler(a_BlockID);
+ case E_BLOCK_ICE:
+ return new cBlockIceHandler(a_BlockID);
+ case E_BLOCK_LADDER:
+ return new cBlockLadderHandler(a_BlockID);
+ case E_BLOCK_COBBLESTONE_STAIRS:
+ case E_BLOCK_BRICK_STAIRS:
+ case E_BLOCK_STONE_BRICK_STAIRS:
+ case E_BLOCK_NETHER_BRICK_STAIRS:
+ case E_BLOCK_WOODEN_STAIRS:
+ return new cBlockStairsHandler(a_BlockID);
+ case E_BLOCK_SIGN_POST:
+ case E_BLOCK_WALLSIGN:
+ return new cBlockSignHandler(a_BlockID);
+ case E_BLOCK_CROPS:
+ return new cBlockCropsHandler(a_BlockID);
+ case E_BLOCK_SUGARCANE:
+ return new cBlockSugarcaneHandler(a_BlockID);
+ case E_BLOCK_YELLOW_FLOWER:
+ case E_BLOCK_RED_ROSE:
+ return new cBlockFlowerHandler(a_BlockID);
+ case E_BLOCK_BROWN_MUSHROOM:
+ case E_BLOCK_RED_MUSHROOM:
+ return new cBlockMushroomHandler(a_BlockID);
+ case E_BLOCK_CACTUS:
+ return new cBlockCactusHandler(a_BlockID);
+ case E_BLOCK_MELON_STEM:
+ case E_BLOCK_PUMPKIN_STEM:
+ return new cBlockStemsHandler(a_BlockID);
+ case E_BLOCK_GLOWSTONE:
+ return new cBlockGlowstoneHandler(a_BlockID);
+ case E_BLOCK_REDSTONE_ORE:
+ case E_BLOCK_REDSTONE_ORE_GLOWING:
+ return new cBlockRedstoneOreHandler(a_BlockID);
+ case E_BLOCK_STONE:
+ case E_BLOCK_COBBLESTONE:
+ return new cBlockStoneHandler(a_BlockID);
+ case E_BLOCK_MELON:
+ return new cBlockMelonHandler(a_BlockID);
+ default:
+ return new cBlockHandler(a_BlockID);
+ break;
+ }
+}
+
+void cBlockHandler::Deinit()
+{
+ for(int i = 0; i < 256; i++)
+ {
+ delete m_BlockHandler[i];
+ }
+}
+
+cBlockHandler::cBlockHandler(BLOCKTYPE a_BlockID)
+{
+ m_BlockID = a_BlockID;
+}
+
+void cBlockHandler::OnUpdate(cWorld *a_World, int a_X, int a_Y, int a_Z)
+{
+
+}
+
+void cBlockHandler::OnPlacedByPlayer(cWorld *a_World, cPlayer * a_Player, int a_X, int a_Y, int a_Z, int a_Dir)
+{
+}
+
+void cBlockHandler::OnDestroyedByPlayer(cWorld *a_World, cPlayer * a_Player, int a_X, int a_Y, int a_Z)
+{
+}
+
+void cBlockHandler::OnPlaced(cWorld *a_World, int a_X, int a_Y, int a_Z, int a_Dir)
+{
+ //Notify the neighbors
+ NeighborChanged(a_World, a_X - 1, a_Y, a_Z);
+ NeighborChanged(a_World, a_X + 1, a_Y, a_Z);
+ NeighborChanged(a_World, a_X, a_Y - 1, a_Z);
+ NeighborChanged(a_World, a_X, a_Y + 1, a_Z);
+ NeighborChanged(a_World, a_X, a_Y, a_Z - 1);
+ NeighborChanged(a_World, a_X, a_Y, a_Z + 1);
+}
+
+void cBlockHandler::OnDestroyed(cWorld *a_World, int a_X, int a_Y, int a_Z)
+{
+ //Notify the neighbors
+ NeighborChanged(a_World, a_X - 1, a_Y, a_Z);
+ NeighborChanged(a_World, a_X + 1, a_Y, a_Z);
+ NeighborChanged(a_World, a_X, a_Y - 1, a_Z);
+ NeighborChanged(a_World, a_X, a_Y + 1, a_Z);
+ NeighborChanged(a_World, a_X, a_Y, a_Z - 1);
+ NeighborChanged(a_World, a_X, a_Y, a_Z + 1);
+}
+
+void cBlockHandler::NeighborChanged(cWorld *a_World, int a_X, int a_Y, int a_Z)
+{
+ GetBlockHandler(a_World->GetBlock(a_X, a_Y, a_Z))->OnNeighborChanged(a_World, a_X, a_Y, a_Z);
+}
+
+void cBlockHandler::OnNeighborChanged(cWorld *a_World, int a_X, int a_Y, int a_Z)
+{
+
+}
+
+void cBlockHandler::OnClick(cWorld *a_World, cPlayer *a_Player, int a_X, int a_Y, int a_Z)
+{
+
+}
+
+void cBlockHandler::PlaceBlock(cWorld *a_World, cPlayer *a_Player, char a_BlockMeta, int a_X, int a_Y, int a_Z, char a_Dir)
+{
+ a_World->SetBlock(a_X, a_Y, a_Z, m_BlockID, a_BlockMeta);
+ OnPlacedByPlayer(a_World, a_Player, a_X, a_Y, a_Z, a_Dir);
+}
+
+
+int cBlockHandler::GetTickRate()
+{
+ return 10;
+}
+
+char cBlockHandler::GetDropCount()
+{
+ return 1;
+}
+
+int cBlockHandler::GetDropID()
+{
+ return m_BlockID;
+}
+
+char cBlockHandler::GetDropMeta(char a_BlockMeta)
+{
+ return a_BlockMeta; //This keeps most textures. The few other blocks have to override this
+}
+
+void cBlockHandler::DropBlock(cWorld *a_World, int a_X, int a_Y, int a_Z)
+{
+ cItems Drops;
+ char Meta = a_World->GetBlockMeta(a_X, a_Y, a_Z);
+ char DropCount = GetDropCount();
+ int DropItem = GetDropID();
+ if(DropCount > 0 && DropItem != E_ITEM_EMPTY)
+ {
+ Drops.push_back(cItem((ENUM_ITEM_ID)DropItem, DropCount, GetDropMeta(Meta)));
+ a_World->SpawnItemPickups(Drops, a_X, a_Y, a_Z);
+ }
+}
+
+bool cBlockHandler::CanBeAt(cWorld *a_World, int a_X, int a_Y, int a_Z)
+{
+ return true;
+}
+
+bool cBlockHandler::IsUseable()
+{
+ return false;
+}
+
+bool cBlockHandler::IsClickedThrough()
+{
+ return false;
+}
+
+bool cBlockHandler::IgnoreBuildCollision()
+{
+ return m_BlockID == E_BLOCK_AIR;
+}
+
+bool cBlockHandler::NeedsRandomTicks()
+{
+ return false;
+}
+
+bool cBlockHandler::AllowBlockOnTop()
+{
+ return true;
+}
+
+bool cBlockHandler::CanBePlacedOnSide()
+{
+ return true;
+}
+
+bool cBlockHandler::DropOnUnsuitable()
+{
+ return true;
+} \ No newline at end of file
diff --git a/source/blocks/Block.h b/source/blocks/Block.h
new file mode 100644
index 000000000..09cff8487
--- /dev/null
+++ b/source/blocks/Block.h
@@ -0,0 +1,54 @@
+#pragma once
+#include "../Defines.h"
+
+class cWorld;
+class cPlayer;
+
+
+
+class cBlockHandler
+{
+public:
+ cBlockHandler(BLOCKTYPE a_BlockID);
+ //Called when the block gets ticked
+ virtual void OnUpdate(cWorld *a_World, int a_X, int a_Y, int a_Z);
+ virtual void OnPlacedByPlayer(cWorld *a_World, cPlayer * a_Player, int a_X, int a_Y, int a_Z, int a_Dir);
+ virtual void OnDestroyedByPlayer(cWorld *a_World, cPlayer * a_Player, int a_X, int a_Y, int a_Z);
+ virtual void OnPlaced(cWorld *a_World, int a_X, int a_Y, int a_Z, int a_Dir);
+ virtual void OnDestroyed(cWorld *a_World, int a_X, int a_Y, int a_Z);
+ virtual void OnNeighborChanged(cWorld *a_World, int a_X, int a_Y, int a_Z);
+ static void NeighborChanged(cWorld *a_World, int a_X, int a_Y, int a_Z);
+ virtual void OnClick(cWorld *a_World, cPlayer *a_Player, int a_X, int a_Y, int a_Z);
+ virtual void PlaceBlock(cWorld *a_World, cPlayer *a_Player, char a_BlockMeta, int a_X, int a_Y, int a_Z, char a_Dir);
+
+ virtual int GetTickRate();
+ virtual char GetDropCount();
+ virtual int GetDropID();
+ virtual char GetDropMeta(char a_BlockMeta);
+ virtual bool NeedsRandomTicks();
+ //Item is -2 if it wasnīt a player
+ virtual void DropBlock(cWorld *a_World, int a_X, int a_Y, int a_Z);
+ virtual bool CanBeAt(cWorld *a_World, int a_X, int a_Y, int a_Z);
+ //This gets called if the player tries to place a block ontop of this block (Only if he aims directly on this block)
+ virtual bool AllowBlockOnTop();
+ virtual bool IsUseable();
+ virtual bool IsClickedThrough();
+ virtual bool IgnoreBuildCollision();
+ //Indicates this block can be placed on the side of other blocks. Default: true
+ virtual bool CanBePlacedOnSide();
+ //Does this block drops if it gets destroyed by an unsuitable situation? Default: true
+ virtual bool DropOnUnsuitable();
+
+ static cBlockHandler *GetBlockHandler(char a_BlockID);
+
+ static void Deinit();
+
+protected:
+ char m_BlockID;
+ static cBlockHandler *CreateBlockHandler(BLOCKTYPE a_BlockID);
+ static cBlockHandler *m_BlockHandler[256];
+ static bool m_HandlerInitialized; //used to detect if the blockhandlers are initialized
+};
+
+
+inline cBlockHandler *BlockHandler(char a_BlockID) { return cBlockHandler::GetBlockHandler(a_BlockID); } \ No newline at end of file
diff --git a/source/blocks/BlockCactus.h b/source/blocks/BlockCactus.h
new file mode 100644
index 000000000..4977d4a98
--- /dev/null
+++ b/source/blocks/BlockCactus.h
@@ -0,0 +1,51 @@
+#pragma once
+#include "Block.h"
+
+
+class cBlockCactusHandler : public cBlockHandler
+{
+public:
+ cBlockCactusHandler(BLOCKTYPE a_BlockID)
+ : cBlockHandler(a_BlockID)
+ {
+ }
+
+ virtual char GetDropMeta(char a_BlockMeta)
+ {
+ return 0;
+ }
+
+ virtual bool CanBeAt(cWorld *a_World, int a_X, int a_Y, int a_Z)
+ {
+ BLOCKTYPE Surface = a_World->GetBlock(a_X, a_Y - 1, a_Z);
+ if ((Surface != E_BLOCK_SAND) && (Surface != E_BLOCK_CACTUS))
+ {
+ // Cactus can only be placed on sand and itself
+ return false;
+ }
+
+ // Check surroundings. Cacti may ONLY be surrounded by air
+ if (
+ (a_World->GetBlock(a_X - 1, a_Y, a_Z) != E_BLOCK_AIR) ||
+ (a_World->GetBlock(a_X + 1, a_Y, a_Z) != E_BLOCK_AIR) ||
+ (a_World->GetBlock(a_X, a_Y, a_Z - 1) != E_BLOCK_AIR) ||
+ (a_World->GetBlock(a_X, a_Y, a_Z + 1) != E_BLOCK_AIR)
+ )
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ virtual bool AllowBlockOnTop()
+ {
+ return false;
+ }
+
+
+ virtual bool CanBePlacedOnSide()
+ {
+ return false;
+ }
+}; \ No newline at end of file
diff --git a/source/blocks/BlockChest.h b/source/blocks/BlockChest.h
new file mode 100644
index 000000000..557b2d640
--- /dev/null
+++ b/source/blocks/BlockChest.h
@@ -0,0 +1,22 @@
+#pragma once
+#include "BlockEntity.h"
+#include "../cWorld.h"
+#include "../cPiston.h"
+#include "../cPlayer.h"
+
+class cBlockChestHandler : public cBlockEntityHandler
+{
+public:
+ cBlockChestHandler(BLOCKTYPE a_BlockID)
+ : cBlockEntityHandler(a_BlockID)
+ {
+ }
+
+ virtual void PlaceBlock(cWorld *a_World, cPlayer *a_Player, char a_BlockMeta, int a_X, int a_Y, int a_Z, char a_Dir)
+ {
+ a_World->SetBlock(a_X, a_Y, a_Z, m_BlockID, cPiston::RotationPitchToMetaData(a_Player->GetRotation(), 0));
+ OnPlacedByPlayer(a_World, a_Player, a_X, a_Y, a_Z, a_Dir);
+ }
+
+
+}; \ No newline at end of file
diff --git a/source/blocks/BlockCloth.cpp b/source/blocks/BlockCloth.cpp
new file mode 100644
index 000000000..a55b8dc7f
--- /dev/null
+++ b/source/blocks/BlockCloth.cpp
@@ -0,0 +1,9 @@
+#include "Globals.h"
+#include "BlockCloth.h"
+#include "../cItem.h"
+#include "../cPlayer.h"
+
+cBlockClothHandler::cBlockClothHandler(BLOCKTYPE a_BlockID)
+ : cBlockHandler(a_BlockID)
+{
+} \ No newline at end of file
diff --git a/source/blocks/BlockCloth.h b/source/blocks/BlockCloth.h
new file mode 100644
index 000000000..dca7184cb
--- /dev/null
+++ b/source/blocks/BlockCloth.h
@@ -0,0 +1,14 @@
+#pragma once
+#include "Block.h"
+
+
+class cBlockClothHandler : public cBlockHandler
+{
+public:
+ cBlockClothHandler(BLOCKTYPE a_BlockID);
+ char GetDropMeta(char a_BlockMeta)
+ {
+ return a_BlockMeta;
+ }
+
+}; \ No newline at end of file
diff --git a/source/blocks/BlockCrops.h b/source/blocks/BlockCrops.h
new file mode 100644
index 000000000..34af1a43c
--- /dev/null
+++ b/source/blocks/BlockCrops.h
@@ -0,0 +1,56 @@
+#pragma once
+#include "Block.h"
+#include "../MersenneTwister.h"
+#include "../cWorld.h"
+
+class cBlockCropsHandler : public cBlockHandler
+{
+public:
+ cBlockCropsHandler(BLOCKTYPE a_BlockID)
+ : cBlockHandler(a_BlockID)
+ {
+ }
+
+ virtual bool NeedsRandomTicks() override
+ {
+ return true;
+ }
+
+ virtual int GetDropID()
+ {
+ return E_ITEM_EMPTY;
+ }
+
+ virtual void OnDestroyed(cWorld *a_World, int a_X, int a_Y, int a_Z)
+ {
+ MTRand rand;
+ NIBBLETYPE Meta = a_World->GetBlockMeta(a_X, a_Y, a_Z);
+
+ ENUM_ITEM_ID Drop = E_ITEM_EMPTY;
+
+ cItems Drops;
+
+ if(Meta & 0x7) //Is Wheat
+ {
+ Drops.push_back(cItem(E_ITEM_WHEAT, 1, 0));
+ }
+ if(rand.randInt(3) == 0)
+ { //Drop an second seed
+ Drops.push_back(cItem(E_ITEM_SEEDS, 1, 0));
+ }
+ Drops.push_back(cItem(E_ITEM_SEEDS, 1, 0));
+ a_World->SpawnItemPickups(Drops, a_X, a_Y, a_Z);
+ }
+
+ void OnUpdate(cWorld *a_World, int a_X, int a_Y, int a_Z)
+ {
+
+ //TODO: Handle Growing here
+ }
+
+ virtual bool CanBeAt(cWorld *a_World, int a_X, int a_Y, int a_Z)
+ {
+ return a_World->GetBlock(a_X, a_Y - 1, a_Z) == E_BLOCK_FARMLAND;
+ }
+
+}; \ No newline at end of file
diff --git a/source/blocks/BlockDirt.cpp b/source/blocks/BlockDirt.cpp
new file mode 100644
index 000000000..ea8c6509d
--- /dev/null
+++ b/source/blocks/BlockDirt.cpp
@@ -0,0 +1,9 @@
+#include "Globals.h"
+#include "BlockDirt.h"
+#include "../cItem.h"
+#include "../cWorld.h"
+
+cBlockDirtHandler::cBlockDirtHandler(BLOCKTYPE a_BlockID)
+ : cBlockHandler(a_BlockID)
+{
+}
diff --git a/source/blocks/BlockDirt.h b/source/blocks/BlockDirt.h
new file mode 100644
index 000000000..49450b16d
--- /dev/null
+++ b/source/blocks/BlockDirt.h
@@ -0,0 +1,62 @@
+#pragma once
+#include "Block.h"
+#include "../MersenneTwister.h"
+#include "../cWorld.h"
+
+class cBlockDirtHandler : public cBlockHandler
+{
+public:
+ cBlockDirtHandler(BLOCKTYPE a_BlockID);
+
+
+ virtual bool NeedsRandomTicks()
+ {
+ return m_BlockID == E_BLOCK_GRASS;
+ }
+
+ virtual int GetDropID()
+ {
+ return E_BLOCK_DIRT;
+ }
+
+
+ void OnUpdate(cWorld *a_World, int a_X, int a_Y, int a_Z)
+ {
+ if(m_BlockID == E_BLOCK_GRASS)
+ {
+ //Grass becomes dirt if there is something on top of them
+ BLOCKTYPE Above = a_World->GetBlock(a_X, a_Y + 1, a_Z);
+ if(!g_BlockTransparent[Above] && !g_BlockOneHitDig[Above])
+ {
+ a_World->FastSetBlock(a_X, a_Y, a_Z, E_BLOCK_DIRT, 0);
+ }
+
+
+ MTRand rand;
+ for (int i = 0; i < 2; i++) // Pick two blocks to grow to
+ {
+ int OfsX = rand.randInt(2) - 1; // [-1 .. 1]
+ int OfsY = rand.randInt(4) - 3; // [-3 .. 1]
+ int OfsZ = rand.randInt(2) - 1; // [-1 .. 1]
+
+ BLOCKTYPE DestBlock;
+ NIBBLETYPE DestMeta;
+ a_World->GetBlockTypeMeta(a_X + OfsX, a_Y + OfsY, a_Z + OfsZ, DestBlock, DestMeta);
+ if(DestBlock != E_BLOCK_DIRT)
+ {
+ continue;
+ }
+
+ BLOCKTYPE AboveDest;
+ NIBBLETYPE AboveMeta;
+ a_World->GetBlockTypeMeta(a_X + OfsX, a_Y + OfsY + 1, a_Z + OfsZ, AboveDest, AboveMeta);
+ if (g_BlockOneHitDig[AboveDest] || g_BlockTransparent[AboveDest])
+ {
+ a_World->FastSetBlock(a_X + OfsX, a_Y + OfsY, a_Z + OfsZ, E_BLOCK_GRASS, 0);
+ }
+ } // for i - repeat twice
+
+ }
+ }
+
+}; \ No newline at end of file
diff --git a/source/blocks/BlockDispenser.h b/source/blocks/BlockDispenser.h
new file mode 100644
index 000000000..4ccfe0dfc
--- /dev/null
+++ b/source/blocks/BlockDispenser.h
@@ -0,0 +1,22 @@
+#pragma once
+#include "BlockEntity.h"
+#include "../cWorld.h"
+#include "../cPiston.h"
+#include "../cPlayer.h"
+
+class cBlockDispenserHandler : public cBlockEntityHandler
+{
+public:
+ cBlockDispenserHandler(BLOCKTYPE a_BlockID)
+ : cBlockEntityHandler(a_BlockID)
+ {
+ }
+
+ virtual void PlaceBlock(cWorld *a_World, cPlayer *a_Player, char a_BlockMeta, int a_X, int a_Y, int a_Z, char a_Dir)
+ {
+ a_World->SetBlock(a_X, a_Y, a_Z, m_BlockID, cPiston::RotationPitchToMetaData(a_Player->GetRotation(), 0));
+ OnPlacedByPlayer(a_World, a_Player, a_X, a_Y, a_Z, a_Dir);
+ }
+
+
+}; \ No newline at end of file
diff --git a/source/blocks/BlockDoor.cpp b/source/blocks/BlockDoor.cpp
new file mode 100644
index 000000000..e854281a5
--- /dev/null
+++ b/source/blocks/BlockDoor.cpp
@@ -0,0 +1,60 @@
+#include "Globals.h"
+#include "BlockDoor.h"
+#include "../cItem.h"
+#include "../cWorld.h"
+#include "../cDoors.h"
+#include "../cPlayer.h"
+
+
+cBlockDoorHandler::cBlockDoorHandler(BLOCKTYPE a_BlockID)
+ : cBlockHandler(a_BlockID)
+{
+}
+
+void cBlockDoorHandler::OnPlaced(cWorld *a_World, int a_X, int a_Y, int a_Z, int a_Dir)
+{
+
+}
+
+void cBlockDoorHandler::OnDestroyed(cWorld *a_World, int a_X, int a_Y, int a_Z)
+{
+ char OldMeta = a_World->GetBlockMeta(a_X, a_Y, a_Z);
+
+ if (OldMeta & 8)
+ {
+ // Was upper part of door
+ if (cDoors::IsDoor(a_World->GetBlock(a_X, a_Y - 1, a_Z)))
+ {
+ a_World->FastSetBlock(a_X, a_Y - 1, a_Z, E_BLOCK_AIR, 0);
+ }
+ }
+ else
+ {
+ // Was lower part
+ if (cDoors::IsDoor(a_World->GetBlock(a_X, a_Y + 1, a_Z)))
+ {
+ a_World->FastSetBlock(a_X, a_Y + 1, a_Z, E_BLOCK_AIR, 0);
+ }
+ }
+}
+
+void cBlockDoorHandler::OnClick(cWorld *a_World, cPlayer *a_Player, int a_X, int a_Y, int a_Z)
+{
+ cDoors::ChangeDoor(a_World, a_X, a_Y, a_Z);
+}
+
+char cBlockDoorHandler::GetDropCount()
+{
+ return 1;
+}
+
+void cBlockDoorHandler::PlaceBlock(cWorld *a_World, cPlayer *a_Player, char a_BlockMeta, int a_X, int a_Y, int a_Z, char a_Dir)
+{
+ if (a_World->GetBlock(a_X, a_Y + 1, a_Z) == E_BLOCK_AIR)
+ {
+ a_BlockMeta = cDoors::RotationToMetaData(a_Player->GetRotation());
+ a_World->SetBlock(a_X, a_Y + 1, a_Z, m_BlockID, a_BlockMeta + 8);
+ a_World->SetBlock(a_X, a_Y, a_Z, m_BlockID, a_BlockMeta);
+ OnPlacedByPlayer(a_World, a_Player, a_X, a_Y, a_Z, a_Dir);
+ }
+} \ No newline at end of file
diff --git a/source/blocks/BlockDoor.h b/source/blocks/BlockDoor.h
new file mode 100644
index 000000000..180d3b48f
--- /dev/null
+++ b/source/blocks/BlockDoor.h
@@ -0,0 +1,29 @@
+#pragma once
+#include "Block.h"
+
+
+class cBlockDoorHandler : public cBlockHandler
+{
+public:
+ cBlockDoorHandler(BLOCKTYPE a_BlockID);
+ virtual void OnPlaced(cWorld *a_World, int a_X, int a_Y, int a_Z, int a_Dir);
+ virtual void OnDestroyed(cWorld *a_World, int a_X, int a_Y, int a_Z);
+ virtual void OnClick(cWorld *a_World, cPlayer *a_Player, int a_X, int a_Y, int a_Z);
+ virtual char GetDropCount();
+ virtual bool IsUseable()
+ {
+ return true;
+ }
+
+ virtual void PlaceBlock(cWorld *a_World, cPlayer *a_Player, char a_BlockMeta, int a_X, int a_Y, int a_Z, char a_Dir);
+
+ virtual int GetDropID()
+ {
+ return (m_BlockID == E_BLOCK_WOODEN_DOOR) ? E_ITEM_WOODEN_DOOR : E_ITEM_IRON_DOOR;
+ }
+
+ virtual bool CanBePlacedOnSide()
+ {
+ return false;
+ }
+}; \ No newline at end of file
diff --git a/source/blocks/BlockEntity.cpp b/source/blocks/BlockEntity.cpp
new file mode 100644
index 000000000..b34b01ee9
--- /dev/null
+++ b/source/blocks/BlockEntity.cpp
@@ -0,0 +1,15 @@
+#include "Globals.h"
+#include "BlockEntity.h"
+#include "../cItem.h"
+#include "../cPlayer.h"
+#include "../cWorld.h"
+
+cBlockEntityHandler::cBlockEntityHandler(BLOCKTYPE a_BlockID)
+ : cBlockHandler(a_BlockID)
+{
+}
+
+void cBlockEntityHandler::OnClick(cWorld *a_World, cPlayer *a_Player, int a_X, int a_Y, int a_Z)
+{
+ a_World->UseBlockEntity(a_Player, a_X, a_Y, a_Z);
+}
diff --git a/source/blocks/BlockEntity.h b/source/blocks/BlockEntity.h
new file mode 100644
index 000000000..abdaa7615
--- /dev/null
+++ b/source/blocks/BlockEntity.h
@@ -0,0 +1,16 @@
+#pragma once
+#include "Block.h"
+
+
+class cBlockEntityHandler : public cBlockHandler
+{
+public:
+ cBlockEntityHandler(BLOCKTYPE a_BlockID);
+ virtual void OnClick(cWorld *a_World, cPlayer *a_Player, int a_X, int a_Y, int a_Z);
+ virtual bool IsUseable()
+ {
+ return true;
+ }
+
+
+}; \ No newline at end of file
diff --git a/source/blocks/BlockFire.cpp b/source/blocks/BlockFire.cpp
new file mode 100644
index 000000000..5ca8dd902
--- /dev/null
+++ b/source/blocks/BlockFire.cpp
@@ -0,0 +1,24 @@
+#include "Globals.h"
+#include "BlockFire.h"
+#include "../cItem.h"
+#include "../cWorld.h"
+
+cBlockFireHandler::cBlockFireHandler(BLOCKTYPE a_BlockID)
+ : cBlockHandler(a_BlockID)
+{
+}
+
+void cBlockFireHandler::OnClick(cWorld *a_World, cPlayer *a_Player, int a_X, int a_Y, int a_Z)
+{
+ a_World->DigBlock(a_X, a_Y, a_Z);
+}
+
+char cBlockFireHandler::GetDropCount()
+{
+ return -1;
+}
+
+bool cBlockFireHandler::IsClickedThrough()
+{
+ return true;
+} \ No newline at end of file
diff --git a/source/blocks/BlockFire.h b/source/blocks/BlockFire.h
new file mode 100644
index 000000000..0a5396096
--- /dev/null
+++ b/source/blocks/BlockFire.h
@@ -0,0 +1,14 @@
+#pragma once
+#include "Block.h"
+
+
+class cBlockFireHandler : public cBlockHandler
+{
+public:
+ cBlockFireHandler(BLOCKTYPE a_BlockID);
+ virtual void OnClick(cWorld *a_World, cPlayer *a_Player, int a_X, int a_Y, int a_Z);
+ virtual bool IsClickedThrough();
+ virtual char GetDropCount();
+
+
+}; \ No newline at end of file
diff --git a/source/blocks/BlockFlower.h b/source/blocks/BlockFlower.h
new file mode 100644
index 000000000..12eaa4dc8
--- /dev/null
+++ b/source/blocks/BlockFlower.h
@@ -0,0 +1,32 @@
+#pragma once
+#include "Block.h"
+
+
+class cBlockFlowerHandler : public cBlockHandler
+{
+public:
+ cBlockFlowerHandler(BLOCKTYPE a_BlockID)
+ : cBlockHandler(a_BlockID)
+ {
+ }
+
+ virtual char GetDropMeta(char a_BlockMeta)
+ {
+ return 0;
+ }
+
+ virtual bool CanBeAt(cWorld *a_World, int a_X, int a_Y, int a_Z)
+ {
+ return IsBlockTypeOfDirt(a_World->GetBlock(a_X, a_Y - 1, a_Z));
+ }
+
+ virtual bool AllowBlockOnTop()
+ {
+ return false;
+ }
+
+ virtual bool CanBePlacedOnSide()
+ {
+ return false;
+ }
+}; \ No newline at end of file
diff --git a/source/blocks/BlockFluid.h b/source/blocks/BlockFluid.h
new file mode 100644
index 000000000..4da785523
--- /dev/null
+++ b/source/blocks/BlockFluid.h
@@ -0,0 +1,20 @@
+#pragma once
+#include "Block.h"
+
+
+class cBlockFluidHandler : public cBlockHandler
+{
+public:
+ cBlockFluidHandler(BLOCKTYPE a_BlockID)
+ : cBlockHandler(a_BlockID)
+ {
+
+ }
+
+ virtual bool IgnoreBuildCollision()
+ {
+ return true;
+ }
+
+
+}; \ No newline at end of file
diff --git a/source/blocks/BlockFurnace.h b/source/blocks/BlockFurnace.h
new file mode 100644
index 000000000..927c925bd
--- /dev/null
+++ b/source/blocks/BlockFurnace.h
@@ -0,0 +1,27 @@
+#pragma once
+#include "BlockEntity.h"
+#include "../cWorld.h"
+#include "../cPiston.h"
+#include "../cPlayer.h"
+
+class cBlockFurnaceHandler : public cBlockEntityHandler
+{
+public:
+ cBlockFurnaceHandler(BLOCKTYPE a_BlockID)
+ : cBlockEntityHandler(a_BlockID)
+ {
+ }
+
+ virtual int GetDropID()
+ {
+ return E_ITEM_FURNACE;
+ }
+
+ virtual void PlaceBlock(cWorld *a_World, cPlayer *a_Player, char a_BlockMeta, int a_X, int a_Y, int a_Z, char a_Dir)
+ {
+ a_World->SetBlock(a_X, a_Y, a_Z, m_BlockID, cPiston::RotationPitchToMetaData(a_Player->GetRotation(), 0));
+ OnPlacedByPlayer(a_World, a_Player, a_X, a_Y, a_Z, a_Dir);
+ }
+
+
+}; \ No newline at end of file
diff --git a/source/blocks/BlockGlowstone.h b/source/blocks/BlockGlowstone.h
new file mode 100644
index 000000000..8d05cd799
--- /dev/null
+++ b/source/blocks/BlockGlowstone.h
@@ -0,0 +1,22 @@
+#pragma once
+#include "Block.h"
+
+
+class cBlockGlowstoneHandler : public cBlockHandler
+{
+public:
+ cBlockGlowstoneHandler(BLOCKTYPE a_BlockID)
+ : cBlockHandler(a_BlockID)
+ {
+ }
+
+ virtual char GetDropMeta(char a_BlockMeta)
+ {
+ return 0;
+ }
+
+ virtual int GetDropID()
+ {
+ return E_ITEM_GLOWSTONE_DUST;
+ }
+}; \ No newline at end of file
diff --git a/source/blocks/BlockIce.h b/source/blocks/BlockIce.h
new file mode 100644
index 000000000..9b356e323
--- /dev/null
+++ b/source/blocks/BlockIce.h
@@ -0,0 +1,26 @@
+#pragma once
+#include "Block.h"
+#include "../MersenneTwister.h"
+#include "../cWorld.h"
+
+class cBlockIceHandler : public cBlockHandler
+{
+public:
+ cBlockIceHandler(BLOCKTYPE a_BlockID)
+ : cBlockHandler(a_BlockID)
+ {
+ }
+
+ virtual int GetDropID()
+ {
+ return E_ITEM_EMPTY;
+ }
+
+ virtual void OnDestroyed(cWorld *a_World, int a_X, int a_Y, int a_Z)
+ {
+ a_World->FastSetBlock(a_X, a_Y, a_Z, E_BLOCK_STATIONARY_WATER, 8);
+ //This is called later than the real destroying of this ice block
+ }
+
+
+}; \ No newline at end of file
diff --git a/source/blocks/BlockLadder.h b/source/blocks/BlockLadder.h
new file mode 100644
index 000000000..0b63cc8e6
--- /dev/null
+++ b/source/blocks/BlockLadder.h
@@ -0,0 +1,28 @@
+#pragma once
+#include "Block.h"
+#include "../cWorld.h"
+#include "../cLadder.h"
+
+class cBlockLadderHandler : public cBlockHandler
+{
+public:
+ cBlockLadderHandler(BLOCKTYPE a_BlockID)
+ : cBlockHandler(a_BlockID)
+ {
+
+ }
+
+ virtual void PlaceBlock(cWorld *a_World, cPlayer *a_Player, char a_BlockMeta, int a_X, int a_Y, int a_Z, char a_Dir)
+ {
+ a_World->SetBlock(a_X, a_Y, a_Z, m_BlockID, cLadder::DirectionToMetaData(a_Dir));
+ OnPlacedByPlayer(a_World, a_Player, a_X, a_Y, a_Z, a_Dir);
+ }
+
+ virtual bool CanBeAt(cWorld *a_World, int a_X, int a_Y, int a_Z)
+ {
+ char Dir = cLadder::MetaDataToDirection(a_World->GetBlockMeta( a_X, a_Y, a_Z));
+ AddDirection( a_X, a_Y, a_Z, Dir, true );
+ return a_World->GetBlock( a_X, a_Y, a_Z ) != E_BLOCK_AIR;
+ }
+
+}; \ No newline at end of file
diff --git a/source/blocks/BlockLeaves.h b/source/blocks/BlockLeaves.h
new file mode 100644
index 000000000..4bae2003f
--- /dev/null
+++ b/source/blocks/BlockLeaves.h
@@ -0,0 +1,162 @@
+#pragma once
+#include "Block.h"
+#include "../MersenneTwister.h"
+#include "../cWorld.h"
+#include "../BlockArea.h"
+
+
+
+// Leaves can be this many blocks that away (inclusive) from the log not to decay
+#define LEAVES_CHECK_DISTANCE 6
+
+#define PROCESS_NEIGHBOR(x,y,z) \
+ switch (a_Area.GetBlockType(x, y, z)) \
+ { \
+ case E_BLOCK_LEAVES: a_Area.SetBlockType(x, y, z, E_BLOCK_SPONGE + i + 1); break; \
+ case E_BLOCK_LOG: return true; \
+ }
+
+bool HasNearLog(cBlockArea &a_Area, int a_BlockX, int a_BlockY, int a_BlockZ);
+
+
+
+class cBlockLeavesHandler : public cBlockHandler
+{
+public:
+ cBlockLeavesHandler(BLOCKTYPE a_BlockID)
+ : cBlockHandler(a_BlockID)
+ {
+ }
+
+ virtual int GetDropID()
+ {
+ MTRand rand;
+
+ if(rand.randInt(5) == 0)
+ {
+ return E_ITEM_SAPLING;
+ }
+
+ return E_ITEM_EMPTY;
+ }
+
+ void OnDestroyed(cWorld *a_World, int a_X, int a_Y, int a_Z)
+ {
+ cBlockHandler::OnDestroyed(a_World, a_X, a_Y, a_Z);
+
+ //0.5% chance of dropping an apple
+ NIBBLETYPE Meta = a_World->GetBlockMeta(a_X, a_Y, a_Z);
+ //check if Oak (0x1 and 0x2 bit not set)
+ MTRand rand;
+ if(!(Meta & 3) && rand.randInt(200) == 100)
+ {
+ cItems Drops;
+ Drops.push_back(cItem(E_ITEM_RED_APPLE, 1, 0));
+ a_World->SpawnItemPickups(Drops, a_X, a_Y, a_Z);
+ }
+ }
+
+ virtual void OnNeighborChanged(cWorld *a_World, int a_X, int a_Y, int a_Z)
+ {
+ NIBBLETYPE Meta = a_World->GetBlockMeta(a_X, a_Y, a_Z);
+ a_World->SetBlockMeta(a_X, a_Y, a_Z, Meta & 0x7); //Unset 0x8 bit so it gets checked for decay
+ }
+
+ virtual bool NeedsRandomTicks()
+ {
+ return true;
+ }
+
+ virtual void OnUpdate(cWorld *a_World, int a_X, int a_Y, int a_Z)
+ {
+ NIBBLETYPE Meta = a_World->GetBlockMeta(a_X, a_Y, a_Z);
+ if ((Meta & 0x04) != 0)
+ {
+ // Player-placed leaves, don't decay
+ return;
+ }
+
+ if (Meta & 0x8)
+ {
+ // These leaves have been checked for decay lately and nothing around them changed
+ return;
+ }
+
+ // Get the data around the leaves:
+ cBlockArea Area;
+ if (!Area.Read(
+ a_World,
+ a_X - LEAVES_CHECK_DISTANCE, a_X + LEAVES_CHECK_DISTANCE,
+ a_Y - LEAVES_CHECK_DISTANCE, a_Y + LEAVES_CHECK_DISTANCE,
+ a_Z - LEAVES_CHECK_DISTANCE, a_Z + LEAVES_CHECK_DISTANCE,
+ cBlockArea::baTypes)
+ )
+ {
+ // Cannot check leaves, a chunk is missing too close
+ return;
+ }
+
+ if (HasNearLog(Area, a_X, a_Y, a_Z))
+ {
+ // Wood found, the leaves stay; mark them as checked:
+ a_World->SetBlockMeta(a_X, a_Y, a_Z, Meta | 0x8);
+ return;
+ }
+ // Decay the leaves:
+ DropBlock(a_World, a_X, a_Y, a_Z);
+
+ a_World->DigBlock(a_X, a_Y, a_Z);
+
+ }
+};
+
+
+bool HasNearLog(cBlockArea &a_Area, int a_BlockX, int a_BlockY, int a_BlockZ)
+{
+ // Filter the blocks into a {leaves, log, other (air)} set:
+ BLOCKTYPE * Types = a_Area.GetBlockTypes();
+ for (int i = a_Area.GetBlockCount() - 1; i > 0; i--)
+ {
+ switch (Types[i])
+ {
+ case E_BLOCK_LEAVES:
+ case E_BLOCK_LOG:
+ {
+ break;
+ }
+ default:
+ {
+ Types[i] = E_BLOCK_AIR;
+ break;
+ }
+ }
+ } // for i - Types[]
+
+ // Perform a breadth-first search to see if there's a log connected within 4 blocks of the leaves block:
+ // Simply replace all reachable leaves blocks with a sponge block plus iteration (in the Area) and see if we can reach a log in 4 iterations
+ a_Area.SetBlockType(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_SPONGE);
+ for (int i = 0; i < LEAVES_CHECK_DISTANCE; i++)
+ {
+ for (int y = a_BlockY - i; y <= a_BlockY + i; y++)
+ {
+ for (int z = a_BlockZ - i; z <= a_BlockZ + i; z++)
+ {
+ for (int x = a_BlockX - i; x <= a_BlockX + i; x++)
+ {
+ if (a_Area.GetBlockType(x, y, z) != E_BLOCK_SPONGE + i)
+ {
+ continue;
+ }
+ PROCESS_NEIGHBOR(x - 1, y, z);
+ PROCESS_NEIGHBOR(x + 1, y, z);
+ PROCESS_NEIGHBOR(x, y, z - 1);
+ PROCESS_NEIGHBOR(x, y, z + 1);
+ PROCESS_NEIGHBOR(x, y + 1, z);
+ PROCESS_NEIGHBOR(x, y - 1, z);
+ } // for x
+ } // for z
+ } // for y
+ } // for i - BFS iterations
+ return false;
+}
+
diff --git a/source/blocks/BlockMelon.h b/source/blocks/BlockMelon.h
new file mode 100644
index 000000000..921745795
--- /dev/null
+++ b/source/blocks/BlockMelon.h
@@ -0,0 +1,24 @@
+#pragma once
+#include "Block.h"
+
+
+class cBlockMelonHandler : public cBlockHandler
+{
+public:
+ cBlockMelonHandler(BLOCKTYPE a_BlockID)
+ : cBlockHandler(a_BlockID)
+ {
+ }
+
+
+ virtual int GetDropID()
+ {
+ return E_ITEM_MELON_SLICE;
+ }
+
+ virtual char GetDropCount()
+ {
+ MTRand r1;
+ return 3 + r1.randInt(4);
+ }
+}; \ No newline at end of file
diff --git a/source/blocks/BlockMushroom.h b/source/blocks/BlockMushroom.h
new file mode 100644
index 000000000..5b2da6498
--- /dev/null
+++ b/source/blocks/BlockMushroom.h
@@ -0,0 +1,42 @@
+#pragma once
+#include "Block.h"
+
+
+class cBlockMushroomHandler : public cBlockHandler
+{
+public:
+ cBlockMushroomHandler(BLOCKTYPE a_BlockID)
+ : cBlockHandler(a_BlockID)
+ {
+ }
+
+ virtual char GetDropMeta(char a_BlockMeta)
+ {
+ return 0;
+ }
+
+ virtual bool CanBeAt(cWorld *a_World, int a_X, int a_Y, int a_Z)
+ {
+ switch (a_World->GetBlock(a_X, a_Y - 1, a_Z))
+ {
+ case E_BLOCK_GLASS:
+ case E_BLOCK_CACTUS:
+ case E_BLOCK_ICE:
+ case E_BLOCK_LEAVES:
+ case E_BLOCK_AIR:
+ return false;
+ }
+ return true;
+ }
+
+ virtual bool AllowBlockOnTop()
+ {
+ return false;
+ }
+
+
+ virtual bool CanBePlacedOnSide()
+ {
+ return false;
+ }
+}; \ No newline at end of file
diff --git a/source/blocks/BlockPiston.cpp b/source/blocks/BlockPiston.cpp
new file mode 100644
index 000000000..98463fd97
--- /dev/null
+++ b/source/blocks/BlockPiston.cpp
@@ -0,0 +1,51 @@
+#include "Globals.h"
+#include "BlockPiston.h"
+#include "../cItem.h"
+#include "../cWorld.h"
+#include "../cRedstone.h"
+#include "../cPlayer.h"
+#include "../cPiston.h"
+
+
+
+#define AddPistonDir(x, y, z, dir, amount) switch (dir) { case 0: (y)-=(amount); break; case 1: (y)+=(amount); break;\
+ case 2: (z)-=(amount); break; case 3: (z)+=(amount); break;\
+ case 4: (x)-=(amount); break; case 5: (x)+=(amount); break; }
+
+
+
+
+cBlockPistonHandler::cBlockPistonHandler(BLOCKTYPE a_BlockID)
+ : cBlockHandler(a_BlockID)
+{
+}
+
+void cBlockPistonHandler::OnPlaced(cWorld *a_World, int a_X, int a_Y, int a_Z, int a_Dir)
+{
+
+}
+
+void cBlockPistonHandler::OnDestroyed(cWorld *a_World, int a_X, int a_Y, int a_Z)
+{
+ char OldMeta = a_World->GetBlockMeta(a_X, a_Y, a_Z);
+
+ int newX = a_X;
+ int newY = a_Y;
+ int newZ = a_Z;
+ AddPistonDir(newX, newY, newZ, OldMeta & ~(8), 1);
+
+ if (a_World->GetBlock(newX, newY, newZ) == E_BLOCK_PISTON_EXTENSION)
+ {
+ a_World->SetBlock(newX, newY, newZ, E_BLOCK_AIR, 0);
+ }
+}
+
+void cBlockPistonHandler::PlaceBlock(cWorld *a_World, cPlayer *a_Player, char a_BlockMeta, int a_X, int a_Y, int a_Z, char a_Dir)
+{
+
+ a_World->SetBlock(a_X, a_Y, a_Z, m_BlockID, cPiston::RotationPitchToMetaData(a_Player->GetRotation(), a_Player->GetPitch()));
+ OnPlacedByPlayer(a_World, a_Player, a_X, a_Y, a_Z, a_Dir);
+
+ cRedstone Redstone(a_World);
+ Redstone.ChangeRedstone(a_X, a_Y, a_Z, false);
+} \ No newline at end of file
diff --git a/source/blocks/BlockPiston.h b/source/blocks/BlockPiston.h
new file mode 100644
index 000000000..69d3a204f
--- /dev/null
+++ b/source/blocks/BlockPiston.h
@@ -0,0 +1,15 @@
+#pragma once
+#include "Block.h"
+
+
+class cBlockPistonHandler : public cBlockHandler
+{
+public:
+ cBlockPistonHandler(BLOCKTYPE a_BlockID);
+ virtual void OnPlaced(cWorld *a_World, int a_X, int a_Y, int a_Z, int a_Dir);
+ virtual void OnDestroyed(cWorld *a_World, int a_X, int a_Y, int a_Z);
+
+
+ virtual void PlaceBlock(cWorld *a_World, cPlayer *a_Player, char a_BlockMeta, int a_X, int a_Y, int a_Z, char a_Dir);
+
+}; \ No newline at end of file
diff --git a/source/blocks/BlockRedstone.cpp b/source/blocks/BlockRedstone.cpp
new file mode 100644
index 000000000..1171d124a
--- /dev/null
+++ b/source/blocks/BlockRedstone.cpp
@@ -0,0 +1,41 @@
+#include "Globals.h"
+#include "BlockRedstone.h"
+#include "../cItem.h"
+#include "../cWorld.h"
+#include "../cRedstone.h"
+#include "../cTorch.h"
+
+cBlockRedstoneHandler::cBlockRedstoneHandler(BLOCKTYPE a_BlockID)
+ : cBlockHandler(a_BlockID)
+{
+}
+
+void cBlockRedstoneHandler::OnPlaced(cWorld *a_World, int a_X, int a_Y, int a_Z, int a_Dir)
+{
+ cRedstone Redstone(a_World);
+ bool Added = false;
+ if(a_World->GetBlock(a_X, a_Y, a_Z) == E_BLOCK_REDSTONE_TORCH_ON)
+ Added = true;
+
+ Redstone.ChangeRedstone(a_X, a_Y, a_Z, Added);
+}
+
+void cBlockRedstoneHandler::OnDestroyed(cWorld *a_World, int a_X, int a_Y, int a_Z)
+{
+ cRedstone Redstone(a_World);
+ Redstone.ChangeRedstone(a_X, a_Y, a_Z, false);
+}
+
+void cBlockRedstoneHandler::PlaceBlock(cWorld *a_World, cPlayer *a_Player, char a_BlockMeta, int a_X, int a_Y, int a_Z, char a_Dir)
+{
+ switch(m_BlockID)
+ {
+ case E_BLOCK_REDSTONE_TORCH_ON:
+ case E_BLOCK_REDSTONE_TORCH_OFF:
+ a_BlockMeta = cTorch::DirectionToMetaData(a_Dir);
+ break;
+
+ }
+ a_World->SetBlock(a_X, a_Y, a_Z, m_BlockID, a_BlockMeta);
+ OnPlacedByPlayer(a_World, a_Player, a_X, a_Y, a_Z, a_Dir);
+} \ No newline at end of file
diff --git a/source/blocks/BlockRedstone.h b/source/blocks/BlockRedstone.h
new file mode 100644
index 000000000..21c19d4c5
--- /dev/null
+++ b/source/blocks/BlockRedstone.h
@@ -0,0 +1,33 @@
+#pragma once
+#include "Block.h"
+#include "../cWorld.h"
+
+class cBlockRedstoneHandler : public cBlockHandler
+{
+public:
+ cBlockRedstoneHandler(BLOCKTYPE a_BlockID);
+ virtual void OnPlaced(cWorld *a_World, int a_X, int a_Y, int a_Z, int a_Dir);
+ virtual void OnDestroyed(cWorld *a_World, int a_X, int a_Y, int a_Z);
+
+ virtual void PlaceBlock(cWorld *a_World, cPlayer *a_Player, char a_BlockMeta, int a_X, int a_Y, int a_Z, char a_Dir);
+
+ virtual bool AllowBlockOnTop()
+ {
+ return false;
+ }
+
+ virtual bool CanBeAt(cWorld *a_World, int a_X, int a_Y, int a_Z)
+ {
+ return a_World->GetBlock(a_X, a_Y - 1, a_Z) != E_BLOCK_AIR;
+ }
+
+ virtual int GetDropID()
+ {
+ return E_ITEM_REDSTONE_DUST;
+ }
+
+ virtual bool CanBePlacedOnSide()
+ {
+ return false;
+ }
+}; \ No newline at end of file
diff --git a/source/blocks/BlockRedstoneOre.h b/source/blocks/BlockRedstoneOre.h
new file mode 100644
index 000000000..5658d76ad
--- /dev/null
+++ b/source/blocks/BlockRedstoneOre.h
@@ -0,0 +1,26 @@
+#pragma once
+#include "Block.h"
+#include "../MersenneTwister.h"
+#include "../cWorld.h"
+
+class cBlockRedstoneOreHandler : public cBlockHandler
+{
+public:
+ cBlockRedstoneOreHandler(BLOCKTYPE a_BlockID)
+ : cBlockHandler(a_BlockID)
+ {
+ }
+
+ virtual int GetDropID()
+ {
+ return E_ITEM_REDSTONE_DUST;
+ }
+
+ virtual char GetDropCount()
+ {
+ MTRand r1;
+ return 4 + r1.randInt(1);
+ }
+
+
+}; \ No newline at end of file
diff --git a/source/blocks/BlockRedstoneRepeater.cpp b/source/blocks/BlockRedstoneRepeater.cpp
new file mode 100644
index 000000000..639764aa5
--- /dev/null
+++ b/source/blocks/BlockRedstoneRepeater.cpp
@@ -0,0 +1,34 @@
+#include "Globals.h"
+#include "BlockRedstoneRepeater.h"
+#include "../cItem.h"
+#include "../cWorld.h"
+#include "../cRedstone.h"
+#include "../cPlayer.h"
+
+cBlockRedstoneRepeaterHandler::cBlockRedstoneRepeaterHandler(BLOCKTYPE a_BlockID)
+ : cBlockHandler(a_BlockID)
+{
+}
+
+void cBlockRedstoneRepeaterHandler::OnPlaced(cWorld *a_World, int a_X, int a_Y, int a_Z, int a_Dir)
+{
+ cRedstone Redstone(a_World);
+ Redstone.ChangeRedstone(a_X, a_Y, a_Z, false);
+}
+
+void cBlockRedstoneRepeaterHandler::OnDestroyed(cWorld *a_World, int a_X, int a_Y, int a_Z)
+{
+ cRedstone Redstone(a_World);
+ Redstone.ChangeRedstone(a_X, a_Y, a_Z, false);
+}
+
+void cBlockRedstoneRepeaterHandler::OnClick(cWorld *a_World, cPlayer *a_Player, int a_X, int a_Y, int a_Z)
+{
+ a_World->FastSetBlock(a_X, a_Y, a_Z, m_BlockID, ((a_World->GetBlockMeta(a_X, a_Y, a_Z) + 0x04) & 0x0f));
+}
+
+void cBlockRedstoneRepeaterHandler::PlaceBlock(cWorld *a_World, cPlayer *a_Player, char a_BlockMeta, int a_X, int a_Y, int a_Z, char a_Dir)
+{
+ a_World->SetBlock(a_X, a_Y, a_Z, m_BlockID, cRedstone::RepeaterRotationToMetaData(a_Player->GetRotation()));
+ OnPlacedByPlayer(a_World, a_Player, a_X, a_Y, a_Z, a_Dir);
+} \ No newline at end of file
diff --git a/source/blocks/BlockRedstoneRepeater.h b/source/blocks/BlockRedstoneRepeater.h
new file mode 100644
index 000000000..e8618cdeb
--- /dev/null
+++ b/source/blocks/BlockRedstoneRepeater.h
@@ -0,0 +1,46 @@
+#pragma once
+#include "Block.h"
+#include "../cWorld.h"
+
+class cBlockRedstoneRepeaterHandler : public cBlockHandler
+{
+public:
+ cBlockRedstoneRepeaterHandler(BLOCKTYPE a_BlockID);
+ virtual void OnPlaced(cWorld *a_World, int a_X, int a_Y, int a_Z, int a_Dir);
+ virtual void OnDestroyed(cWorld *a_World, int a_X, int a_Y, int a_Z);
+
+ virtual void OnClick(cWorld *a_World, cPlayer *a_Player, int a_X, int a_Y, int a_Z);
+
+ virtual char GetDropMeta(char a_BlockMeta)
+ {
+ return 0;
+ }
+
+ virtual int GetDropID()
+ {
+ return E_ITEM_REDSTONE_REPEATER;
+ }
+
+ virtual bool IsUseable()
+ {
+ return true;
+ }
+
+ virtual void PlaceBlock(cWorld *a_World, cPlayer *a_Player, char a_BlockMeta, int a_X, int a_Y, int a_Z, char a_Dir);
+
+ virtual bool AllowBlockOnTop()
+ {
+ return false;
+ }
+
+ virtual bool CanBeAt(cWorld *a_World, int a_X, int a_Y, int a_Z)
+ {
+ return a_World->GetBlock(a_X, a_Y - 1, a_Z) != E_BLOCK_AIR;
+ }
+
+
+ virtual bool CanBePlacedOnSide()
+ {
+ return false;
+ }
+}; \ No newline at end of file
diff --git a/source/blocks/BlockRedstoneTorch.h b/source/blocks/BlockRedstoneTorch.h
new file mode 100644
index 000000000..6ae37cd1e
--- /dev/null
+++ b/source/blocks/BlockRedstoneTorch.h
@@ -0,0 +1,30 @@
+#pragma once
+#include "BlockRedstone.h"
+#include "../cTorch.h"
+
+
+class cBlockRedstoneTorchHandler : public cBlockRedstoneHandler
+{
+public:
+ cBlockRedstoneTorchHandler(BLOCKTYPE a_BlockID)
+ : cBlockRedstoneHandler(a_BlockID)
+ {
+ }
+
+ virtual bool CanBeAt(cWorld *a_World, int a_X, int a_Y, int a_Z)
+ {
+ char Dir = cTorch::MetaDataToDirection(a_World->GetBlockMeta( a_X, a_Y, a_Z));
+ AddDirection( a_X, a_Y, a_Z, Dir, true );
+ return a_World->GetBlock( a_X, a_Y, a_Z ) != E_BLOCK_AIR;
+ }
+
+ virtual int GetDropID()
+ {
+ return E_ITEM_REDSTONE_TORCH_ON;
+ }
+
+ virtual bool CanBePlacedOnSide()
+ {
+ return true;
+ }
+}; \ No newline at end of file
diff --git a/source/blocks/BlockSapling.h b/source/blocks/BlockSapling.h
new file mode 100644
index 000000000..d0498afea
--- /dev/null
+++ b/source/blocks/BlockSapling.h
@@ -0,0 +1,51 @@
+#pragma once
+#include "Block.h"
+#include "../cWorld.h"
+
+class cBlockSaplingHandler : public cBlockHandler
+{
+public:
+ cBlockSaplingHandler(BLOCKTYPE a_BlockID)
+ : cBlockHandler(a_BlockID)
+ {
+ }
+
+ virtual bool NeedsRandomTicks() override
+ {
+ return true;
+ }
+
+ virtual char GetDropMeta(char a_BlockMeta)
+ {
+ return a_BlockMeta & 3; //Only the first 2 bits contain the display information the others are for growing
+ }
+
+ virtual bool CanBeAt(cWorld *a_World, int a_X, int a_Y, int a_Z)
+ {
+ return IsBlockTypeOfDirt(a_World->GetBlock(a_X, a_Y - 1, a_Z));
+ }
+
+ virtual bool AllowBlockOnTop()
+ {
+ return false;
+ }
+
+ void OnUpdate(cWorld *a_World, int a_X, int a_Y, int a_Z)
+ {
+ NIBBLETYPE Meta = a_World->GetBlockMeta(a_X, a_Y, a_Z);
+
+ if ((Meta & 0x08) != 0)
+ {
+ a_World->GrowTree(a_X, a_Y, a_Z);
+ }
+ else
+ {
+ a_World->SetBlockMeta(a_X, a_Y, a_Z, Meta | 0x08);
+ }
+ }
+
+ virtual bool CanBePlacedOnSide()
+ {
+ return false;
+ }
+}; \ No newline at end of file
diff --git a/source/blocks/BlockSign.h b/source/blocks/BlockSign.h
new file mode 100644
index 000000000..3b2e208e1
--- /dev/null
+++ b/source/blocks/BlockSign.h
@@ -0,0 +1,42 @@
+#pragma once
+#include "Block.h"
+#include "../cWorld.h"
+#include "../cSign.h"
+#include "../cPlayer.h"
+
+class cBlockSignHandler : public cBlockHandler
+{
+public:
+ cBlockSignHandler(BLOCKTYPE a_BlockID)
+ : cBlockHandler(a_BlockID)
+ {
+
+ }
+
+ virtual void PlaceBlock(cWorld *a_World, cPlayer *a_Player, char a_BlockMeta, int a_X, int a_Y, int a_Z, char a_Dir)
+ {
+ BLOCKTYPE Block;
+ NIBBLETYPE Meta;
+ if(a_Dir == 1)
+ {
+ Meta = cSign::RotationToMetaData(a_Player->GetRotation());
+ Block = E_BLOCK_SIGN_POST;
+ }else{
+ Meta = cSign::DirectionToMetaData(a_Dir);
+ Block = E_BLOCK_WALLSIGN;
+ }
+
+ a_World->SetBlock(a_X, a_Y, a_Z, Block, Meta);
+ OnPlacedByPlayer(a_World, a_Player, a_X, a_Y, a_Z, a_Dir);
+ }
+
+ virtual int GetDropID()
+ {
+ return E_ITEM_SIGN;
+ }
+
+ virtual bool AllowBlockOnTop()
+ {
+ return false;
+ }
+}; \ No newline at end of file
diff --git a/source/blocks/BlockSlab.cpp b/source/blocks/BlockSlab.cpp
new file mode 100644
index 000000000..659dc7986
--- /dev/null
+++ b/source/blocks/BlockSlab.cpp
@@ -0,0 +1,17 @@
+#include "Globals.h"
+#include "BlockSlab.h"
+#include "../cItem.h"
+#include "../cPlayer.h"
+#include "../cWorld.h"
+
+cBlockSlabHandler::cBlockSlabHandler(BLOCKTYPE a_BlockID)
+ : cBlockHandler(a_BlockID)
+{
+}
+
+
+void cBlockSlabHandler::PlaceBlock(cWorld *a_World, cPlayer *a_Player, char a_BlockMeta, int a_X, int a_Y, int a_Z, char a_Dir)
+{
+ a_World->SetBlock(a_X, a_Y, a_Z, m_BlockID, DirectionToMetaData( a_Dir, a_BlockMeta ));
+ OnPlacedByPlayer(a_World, a_Player, a_X, a_Y, a_Z, a_Dir);
+} \ No newline at end of file
diff --git a/source/blocks/BlockSlab.h b/source/blocks/BlockSlab.h
new file mode 100644
index 000000000..05df819b2
--- /dev/null
+++ b/source/blocks/BlockSlab.h
@@ -0,0 +1,33 @@
+#pragma once
+#include "Block.h"
+
+
+class cBlockSlabHandler : public cBlockHandler
+{
+public:
+ cBlockSlabHandler(BLOCKTYPE a_BlockID);
+ virtual char GetDropMeta(char a_BlockMeta)
+ {
+ return a_BlockMeta;
+ }
+
+ virtual char GetDropCount()
+ {
+ if(m_BlockID == E_BLOCK_DOUBLE_STONE_SLAB
+ || m_BlockID == E_BLOCK_DOUBLE_WOODEN_SLAB)
+ return 2;
+ return 1;
+ }
+
+ virtual void PlaceBlock(cWorld *a_World, cPlayer *a_Player, char a_BlockMeta, int a_X, int a_Y, int a_Z, char a_Dir);
+
+ static char DirectionToMetaData( char a_Direction, NIBBLETYPE Meta )
+ {
+ char result = Meta;
+ if( a_Direction == 0)
+ {
+ result |= 0x8;
+ }
+ return result;
+ }
+}; \ No newline at end of file
diff --git a/source/blocks/BlockSnow.h b/source/blocks/BlockSnow.h
new file mode 100644
index 000000000..75143b73e
--- /dev/null
+++ b/source/blocks/BlockSnow.h
@@ -0,0 +1,39 @@
+#pragma once
+#include "Block.h"
+
+
+class cBlockSnowHandler : public cBlockHandler
+{
+public:
+ cBlockSnowHandler(BLOCKTYPE a_BlockID)
+ : cBlockHandler(a_BlockID)
+ {
+ }
+
+ virtual bool IgnoreBuildCollision()
+ {
+ return true;
+ }
+
+ virtual int GetDropID()
+ {
+ return E_ITEM_SNOWBALL;
+ }
+
+ virtual char GetDropCount()
+ {
+ return 4;
+ }
+
+
+ virtual bool CanBeAt(cWorld *a_World, int a_X, int a_Y, int a_Z)
+ {
+ return a_World->GetBlock(a_X, a_Y - 1, a_Z) != E_BLOCK_AIR;
+ }
+
+ virtual bool DropOnUnsuitable()
+ {
+ return false;
+ }
+
+}; \ No newline at end of file
diff --git a/source/blocks/BlockStairs.cpp b/source/blocks/BlockStairs.cpp
new file mode 100644
index 000000000..cd4ad9907
--- /dev/null
+++ b/source/blocks/BlockStairs.cpp
@@ -0,0 +1,18 @@
+#include "Globals.h"
+#include "BlockStairs.h"
+#include "../cItem.h"
+#include "../cVine.h"
+#include "../cPlayer.h"
+#include "../cWorld.h"
+#include "../cStairs.h"
+
+cBlockStairsHandler::cBlockStairsHandler(BLOCKTYPE a_BlockID)
+ : cBlockHandler(a_BlockID)
+{
+}
+
+void cBlockStairsHandler::PlaceBlock(cWorld *a_World, cPlayer *a_Player, char a_BlockMeta, int a_X, int a_Y, int a_Z, char a_Dir)
+{
+ a_World->SetBlock(a_X, a_Y, a_Z, m_BlockID, cStairs::RotationToMetaData(a_Player->GetRotation(), a_Dir));
+ OnPlacedByPlayer(a_World, a_Player, a_X, a_Y, a_Z, a_Dir);
+} \ No newline at end of file
diff --git a/source/blocks/BlockStairs.h b/source/blocks/BlockStairs.h
new file mode 100644
index 000000000..d7de17c1f
--- /dev/null
+++ b/source/blocks/BlockStairs.h
@@ -0,0 +1,14 @@
+#pragma once
+#include "Block.h"
+
+
+class cBlockStairsHandler : public cBlockHandler
+{
+public:
+ cBlockStairsHandler(BLOCKTYPE a_BlockID);
+
+
+ virtual void PlaceBlock(cWorld *a_World, cPlayer *a_Player, char a_BlockMeta, int a_X, int a_Y, int a_Z, char a_Dir);
+
+
+}; \ No newline at end of file
diff --git a/source/blocks/BlockStems.h b/source/blocks/BlockStems.h
new file mode 100644
index 000000000..8f1d4ddca
--- /dev/null
+++ b/source/blocks/BlockStems.h
@@ -0,0 +1,41 @@
+#pragma once
+#include "Block.h"
+#include "../MersenneTwister.h"
+#include "../cWorld.h"
+
+class cBlockStemsHandler : public cBlockHandler
+{
+public:
+ cBlockStemsHandler(BLOCKTYPE a_BlockID)
+ : cBlockHandler(a_BlockID)
+ {
+ }
+
+ virtual bool NeedsRandomTicks()
+ {
+ return true;
+ }
+
+ virtual char GetDropMeta(char a_BlockMeta)
+ {
+ return 0;
+ }
+
+ virtual int GetDropID()
+ {
+ if(m_BlockID == E_BLOCK_MELON_STEM)
+ return E_ITEM_MELON_SEEDS;
+ return E_ITEM_PUMPKIN_SEEDS;
+ }
+
+ void OnUpdate(cWorld *a_World, int a_X, int a_Y, int a_Z)
+ {
+ //TODO: Handle Growing here
+ }
+
+ virtual bool CanBeAt(cWorld *a_World, int a_X, int a_Y, int a_Z)
+ {
+ return a_World->GetBlock(a_X, a_Y - 1, a_Z) == E_BLOCK_FARMLAND;
+ }
+
+}; \ No newline at end of file
diff --git a/source/blocks/BlockStone.h b/source/blocks/BlockStone.h
new file mode 100644
index 000000000..d15e4730a
--- /dev/null
+++ b/source/blocks/BlockStone.h
@@ -0,0 +1,18 @@
+#pragma once
+#include "Block.h"
+#include "../MersenneTwister.h"
+#include "../cWorld.h"
+
+class cBlockStoneHandler : public cBlockHandler
+{
+public:
+ cBlockStoneHandler(BLOCKTYPE a_BlockID)
+ : cBlockHandler(a_BlockID)
+ {
+ }
+
+ virtual int GetDropID()
+ {
+ return E_ITEM_COBBLESTONE;
+ }
+}; \ No newline at end of file
diff --git a/source/blocks/BlockSugarcane.h b/source/blocks/BlockSugarcane.h
new file mode 100644
index 000000000..610052880
--- /dev/null
+++ b/source/blocks/BlockSugarcane.h
@@ -0,0 +1,43 @@
+#pragma once
+#include "Block.h"
+#include "../MersenneTwister.h"
+#include "../cWorld.h"
+
+class cBlockSugarcaneHandler : public cBlockHandler
+{
+public:
+ cBlockSugarcaneHandler(BLOCKTYPE a_BlockID)
+ : cBlockHandler(a_BlockID)
+ {
+ }
+
+ virtual bool NeedsRandomTicks()
+ {
+ return true;
+ }
+
+ virtual int GetDropID()
+ {
+ return E_ITEM_SUGARCANE;
+ }
+
+ virtual bool CanBeAt(cWorld *a_World, int a_X, int a_Y, int a_Z)
+ {
+ BLOCKTYPE Block = a_World->GetBlock(a_X, a_Y-1, a_Z);
+ if(!IsBlockTypeOfDirt(Block) && Block != E_BLOCK_SAND && Block != E_BLOCK_SUGARCANE)
+ return false;
+
+ return a_World->IsBlockDirectlyWatered(a_X, a_Y - 1, a_Z);
+ }
+
+ void OnUpdate(cWorld *a_World, int a_X, int a_Y, int a_Z)
+ {
+
+ //TODO: Handle Growing here
+ }
+
+ virtual bool CanBePlacedOnSide()
+ {
+ return false;
+ }
+}; \ No newline at end of file
diff --git a/source/blocks/BlockTallGrass.h b/source/blocks/BlockTallGrass.h
new file mode 100644
index 000000000..a702bb8ca
--- /dev/null
+++ b/source/blocks/BlockTallGrass.h
@@ -0,0 +1,35 @@
+#pragma once
+#include "Block.h"
+
+
+class cBlockTallGrassHandler : public cBlockHandler
+{
+public:
+ cBlockTallGrassHandler(BLOCKTYPE a_BlockID)
+ : cBlockHandler(a_BlockID)
+ {
+ }
+
+ virtual bool IgnoreBuildCollision()
+ {
+ return true;
+ }
+
+ virtual int GetDropID()
+ {
+ return E_ITEM_SEEDS;
+ }
+
+ virtual char GetDropCount()
+ {
+ MTRand r1;
+ if(r1.randInt(10) == 5)
+ return 1;
+ return 0;
+ }
+
+ virtual bool CanBeAt(cWorld *a_World, int a_X, int a_Y, int a_Z)
+ {
+ return a_World->GetBlock(a_X, a_Y - 1, a_Z) != E_BLOCK_AIR;
+ }
+}; \ No newline at end of file
diff --git a/source/blocks/BlockTorch.cpp b/source/blocks/BlockTorch.cpp
new file mode 100644
index 000000000..d9597a9ac
--- /dev/null
+++ b/source/blocks/BlockTorch.cpp
@@ -0,0 +1,15 @@
+#include "Globals.h"
+#include "BlockTorch.h"
+#include "../cTorch.h"
+#include "../cWorld.h"
+
+cBlockTorchHandler::cBlockTorchHandler(BLOCKTYPE a_BlockID)
+ : cBlockHandler(a_BlockID)
+{
+}
+
+void cBlockTorchHandler::PlaceBlock(cWorld *a_World, cPlayer *a_Player, char a_BlockMeta, int a_X, int a_Y, int a_Z, char a_Dir)
+{
+ a_World->SetBlock(a_X, a_Y, a_Z, m_BlockID, cTorch::DirectionToMetaData(a_Dir));
+ OnPlacedByPlayer(a_World, a_Player, a_X, a_Y, a_Z, a_Dir);
+} \ No newline at end of file
diff --git a/source/blocks/BlockTorch.h b/source/blocks/BlockTorch.h
new file mode 100644
index 000000000..1e4827ac1
--- /dev/null
+++ b/source/blocks/BlockTorch.h
@@ -0,0 +1,25 @@
+#pragma once
+#include "Block.h"
+#include "../cTorch.h"
+#include "../cWorld.h"
+
+
+class cBlockTorchHandler : public cBlockHandler
+{
+public:
+ cBlockTorchHandler(BLOCKTYPE a_BlockID);
+
+ virtual void PlaceBlock(cWorld *a_World, cPlayer *a_Player, char a_BlockMeta, int a_X, int a_Y, int a_Z, char a_Dir);
+
+ virtual bool AllowBlockOnTop()
+ {
+ return false;
+ }
+
+ virtual bool CanBeAt(cWorld *a_World, int a_X, int a_Y, int a_Z)
+ {
+ char Dir = cTorch::MetaDataToDirection(a_World->GetBlockMeta( a_X, a_Y, a_Z));
+ AddDirection( a_X, a_Y, a_Z, Dir, true );
+ return a_World->GetBlock( a_X, a_Y, a_Z ) != E_BLOCK_AIR;
+ }
+}; \ No newline at end of file
diff --git a/source/blocks/BlockVine.cpp b/source/blocks/BlockVine.cpp
new file mode 100644
index 000000000..fda3c818c
--- /dev/null
+++ b/source/blocks/BlockVine.cpp
@@ -0,0 +1,17 @@
+#include "Globals.h"
+#include "BlockVine.h"
+#include "../cItem.h"
+#include "../cVine.h"
+#include "../cPlayer.h"
+#include "../cWorld.h"
+
+cBlockVineHandler::cBlockVineHandler(BLOCKTYPE a_BlockID)
+ : cBlockHandler(a_BlockID)
+{
+}
+
+void cBlockVineHandler::PlaceBlock(cWorld *a_World, cPlayer *a_Player, char a_BlockMeta, int a_X, int a_Y, int a_Z, char a_Dir)
+{
+ a_World->SetBlock(a_X, a_Y, a_Z, m_BlockID, cVine::DirectionToMetaData(a_Dir));
+ OnPlacedByPlayer(a_World, a_Player, a_X, a_Y, a_Z, a_Dir);
+} \ No newline at end of file
diff --git a/source/blocks/BlockVine.h b/source/blocks/BlockVine.h
new file mode 100644
index 000000000..d601e622c
--- /dev/null
+++ b/source/blocks/BlockVine.h
@@ -0,0 +1,23 @@
+#pragma once
+#include "Block.h"
+
+
+class cBlockVineHandler : public cBlockHandler
+{
+public:
+ cBlockVineHandler(BLOCKTYPE a_BlockID);
+
+ virtual bool IgnoreBuildCollision()
+ {
+ return true;
+ }
+
+ virtual void PlaceBlock(cWorld *a_World, cPlayer *a_Player, char a_BlockMeta, int a_X, int a_Y, int a_Z, char a_Dir);
+
+
+ virtual bool AllowBlockOnTop()
+ {
+ return false;
+ }
+
+}; \ No newline at end of file
diff --git a/source/blocks/BlockWood.h b/source/blocks/BlockWood.h
new file mode 100644
index 000000000..c93c44b4f
--- /dev/null
+++ b/source/blocks/BlockWood.h
@@ -0,0 +1,17 @@
+#pragma once
+#include "Block.h"
+
+
+class cBlockWoodHandler : public cBlockHandler
+{
+public:
+ cBlockWoodHandler(BLOCKTYPE a_BlockID)
+ : cBlockHandler(a_BlockID)
+ {
+ }
+ char GetDropMeta(char a_BlockMeta)
+ {
+ return a_BlockMeta;
+ }
+
+}; \ No newline at end of file
diff --git a/source/blocks/BlockWorkbench.cpp b/source/blocks/BlockWorkbench.cpp
new file mode 100644
index 000000000..095a6e1da
--- /dev/null
+++ b/source/blocks/BlockWorkbench.cpp
@@ -0,0 +1,24 @@
+#include "Globals.h"
+#include "BlockWorkbench.h"
+#include "../cItem.h"
+#include "../cPlayer.h"
+#include "../cCraftingWindow.h"
+
+cBlockWorkbenchHandler::cBlockWorkbenchHandler(BLOCKTYPE a_BlockID)
+ : cBlockHandler(a_BlockID)
+{
+}
+
+void cBlockWorkbenchHandler::OnPlaced(cWorld *a_World, int a_X, int a_Y, int a_Z, int a_Dir)
+{
+}
+
+void cBlockWorkbenchHandler::OnDestroyed(cWorld *a_World, int a_X, int a_Y, int a_Z)
+{
+}
+
+void cBlockWorkbenchHandler::OnClick(cWorld *a_World, cPlayer *a_Player, int a_X, int a_Y, int a_Z)
+{
+ cWindow* Window = new cCraftingWindow(0, true);
+ a_Player->OpenWindow(Window);
+}
diff --git a/source/blocks/BlockWorkbench.h b/source/blocks/BlockWorkbench.h
new file mode 100644
index 000000000..2a0936c08
--- /dev/null
+++ b/source/blocks/BlockWorkbench.h
@@ -0,0 +1,19 @@
+#pragma once
+#include "Block.h"
+
+
+class cBlockWorkbenchHandler : public cBlockHandler
+{
+public:
+ cBlockWorkbenchHandler(BLOCKTYPE a_BlockID);
+ virtual void OnPlaced(cWorld *a_World, int a_X, int a_Y, int a_Z, int a_Dir);
+ virtual void OnDestroyed(cWorld *a_World, int a_X, int a_Y, int a_Z);
+
+ virtual void OnClick(cWorld *a_World, cPlayer *a_Player, int a_X, int a_Y, int a_Z);
+ virtual bool IsUseable()
+ {
+ return true;
+ }
+
+
+}; \ No newline at end of file
diff --git a/source/cBlockToPickup.cpp b/source/cBlockToPickup.cpp
index eec750183..add34dfcf 100644
--- a/source/cBlockToPickup.cpp
+++ b/source/cBlockToPickup.cpp
@@ -7,320 +7,3 @@
#include "MersenneTwister.h"
-
-
-
-static void AddRandomDrop(cItems & a_Drops, MTRand & r1, int a_OneInNChance, ENUM_ITEM_ID a_ItemID)
-{
- if ((r1.randInt(16 * a_OneInNChance - 1) / 16) != 0)
- {
- return;
- }
- a_Drops.push_back(cItem(a_ItemID, 1));
-}
-
-
-
-
-
-void cBlockToPickup::ToPickup(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, const cItem & a_UsedItem, cItems & a_Drops)
-{
- MTRand r1;
-
- switch (a_BlockType)
- {
- // Blocks that always drop themselves as the only item, no matter what tool; copy damage from meta:
- case E_BLOCK_LOG:
- case E_BLOCK_PLANKS:
- case E_BLOCK_WOOL:
- {
- a_Drops.push_back(cItem((ENUM_ITEM_ID)a_BlockType, 1, a_BlockMeta));
- return;
- }
-
-
- // Blocks that always drop themselves as the only item, no matter what tool, set damage value zero:
- case E_BLOCK_DIRT:
- case E_BLOCK_SAPLING:
- case E_BLOCK_SAND:
- case E_BLOCK_TORCH:
- case E_BLOCK_YELLOW_FLOWER:
- case E_BLOCK_RED_ROSE:
- case E_BLOCK_BROWN_MUSHROOM:
- case E_BLOCK_RED_MUSHROOM:
- case E_BLOCK_TNT:
- case E_BLOCK_CRAFTING_TABLE:
- case E_BLOCK_FURNACE:
- case E_BLOCK_CACTUS:
- case E_BLOCK_REDSTONE_TORCH_OFF:
- case E_BLOCK_POWERED_RAIL:
- case E_BLOCK_DETECTOR_RAIL:
- case E_BLOCK_RAIL:
- case E_BLOCK_LADDER:
- case E_BLOCK_LEVER:
- case E_BLOCK_WOODEN_PRESSURE_PLATE:
- case E_BLOCK_STONE_BUTTON:
- case E_BLOCK_JUKEBOX:
- case E_BLOCK_FENCE:
- case E_BLOCK_FENCE_GATE:
- case E_BLOCK_PUMPKIN:
- case E_BLOCK_NETHERRACK:
- case E_BLOCK_SOULSAND:
- case E_BLOCK_JACK_O_LANTERN:
- case E_BLOCK_TRAPDOOR:
- {
- a_Drops.push_back(cItem((ENUM_ITEM_ID)a_BlockType, 1, 0));
- return;
- }
-
-
- // Blocks that always drop a single item, no matter what tool:
- case E_BLOCK_SIGN_POST:
- case E_BLOCK_WALLSIGN: a_Drops.push_back(cItem(E_ITEM_SIGN, 1)); return;
- case E_BLOCK_REDSTONE_WIRE: a_Drops.push_back(cItem(E_ITEM_REDSTONE_DUST, 1)); return;
- case E_BLOCK_GLOWSTONE: a_Drops.push_back(cItem(E_ITEM_GLOWSTONE_DUST, 1)); return;
- case E_BLOCK_REDSTONE_REPEATER_OFF:
- case E_BLOCK_REDSTONE_REPEATER_ON: a_Drops.push_back(cItem(E_ITEM_REDSTONE_REPEATER, 1)); return;
- case E_BLOCK_COBWEB: a_Drops.push_back(cItem(E_ITEM_STRING, 1)); return;
- case E_BLOCK_FARMLAND:
- case E_BLOCK_GRASS: a_Drops.push_back(cItem(E_ITEM_DIRT, 1)); return;
- case E_BLOCK_LIT_FURNACE: a_Drops.push_back(cItem(E_ITEM_FURNACE, 1)); return;
- case E_BLOCK_SUGARCANE: a_Drops.push_back(cItem(E_ITEM_SUGARCANE, 1)); return;
- case E_BLOCK_PUMPKIN_STEM: a_Drops.push_back(cItem(E_ITEM_PUMPKIN_SEEDS, 1)); return;
- case E_BLOCK_MELON_STEM: a_Drops.push_back(cItem(E_ITEM_MELON_SEEDS, 1)); return;
-
-
- // Doors seem to need their meta set to 1
- case E_BLOCK_WOODEN_DOOR: a_Drops.push_back(cItem(E_ITEM_WOODEN_DOOR, 1, 1)); return;
- case E_BLOCK_IRON_DOOR: a_Drops.push_back(cItem(E_ITEM_IRON_DOOR, 1, 1)); return;
-
-
- ////////////////////////
- // Ores:
-
- // Coal ore requires a pickaxe:
- case E_BLOCK_COAL_ORE:
- {
- if (ItemCategory::IsPickaxe(a_UsedItem.m_ItemID))
- {
- a_Drops.push_back(cItem(E_ITEM_COAL, 1));
- }
- return;
- }
-
- // Iron ore requires a stone or better pickaxe:
- case E_BLOCK_IRON_ORE:
- {
- if (
- (a_UsedItem.m_ItemID == E_ITEM_STONE_PICKAXE) ||
- (a_UsedItem.m_ItemID == E_ITEM_IRON_PICKAXE) ||
- (a_UsedItem.m_ItemID == E_ITEM_DIAMOND_PICKAXE)
- )
- {
- a_Drops.push_back(cItem(E_ITEM_IRON_ORE, 1));
- }
- return;
- }
-
- // Gold and diamond ores require an iron or better pickaxe:
- case E_BLOCK_GOLD_ORE:
- case E_BLOCK_DIAMOND_ORE:
- {
- if (
- (a_UsedItem.m_ItemID == E_ITEM_IRON_PICKAXE) ||
- (a_UsedItem.m_ItemID == E_ITEM_DIAMOND_PICKAXE)
- )
- {
- a_Drops.push_back(cItem((ENUM_ITEM_ID)a_BlockType, 1));
- }
- return;
- }
-
- // Obsidian require a diamond pickaxe:
- case E_BLOCK_OBSIDIAN:
- {
- if (a_UsedItem.m_ItemID == E_ITEM_DIAMOND_PICKAXE)
- {
- a_Drops.push_back(cItem((ENUM_ITEM_ID)a_BlockType, 1));
- }
- return;
- }
-
- // Redstone requires an iron or better pickaxe:
- case E_BLOCK_REDSTONE_ORE_GLOWING:
- case E_BLOCK_REDSTONE_ORE:
- {
- if (
- (a_UsedItem.m_ItemID == E_ITEM_IRON_PICKAXE) ||
- (a_UsedItem.m_ItemID == E_ITEM_DIAMOND_PICKAXE)
- )
- {
- a_Drops.push_back(cItem(E_ITEM_REDSTONE_DUST, 4 + (short)r1.randInt(1)));
- }
- return;
- }
-
- // Lapis ore requires a stone or better pickaxe:
- case E_BLOCK_LAPIS_ORE:
- {
- if (
- (a_UsedItem.m_ItemID == E_ITEM_STONE_PICKAXE) ||
- (a_UsedItem.m_ItemID == E_ITEM_IRON_PICKAXE) ||
- (a_UsedItem.m_ItemID == E_ITEM_GOLD_PICKAXE) ||
- (a_UsedItem.m_ItemID == E_ITEM_DIAMOND_PICKAXE)
- )
- {
- a_Drops.push_back(cItem(E_ITEM_DYE, 4 + (short)r1.randInt(4), E_META_DYE_BLUE));
- }
- return;
- }
-
-
- ////////////////////////
- // Resource blocks:
-
- // Iron and lapis blocks require a stone or better pickaxe:
- case E_BLOCK_IRON_BLOCK:
- case E_BLOCK_LAPIS_BLOCK:
- {
- if (
- (a_UsedItem.m_ItemID == E_ITEM_STONE_PICKAXE) ||
- (a_UsedItem.m_ItemID == E_ITEM_IRON_PICKAXE) ||
- (a_UsedItem.m_ItemID == E_ITEM_DIAMOND_PICKAXE)
- )
- {
- a_Drops.push_back(cItem((ENUM_ITEM_ID)a_BlockType, 1));
- }
- return;
- }
-
- // Diamond and gold blocks require an iron or better pickaxe:
- case E_BLOCK_DIAMOND_BLOCK:
- {
- if (
- (a_UsedItem.m_ItemID == E_ITEM_IRON_PICKAXE) ||
- (a_UsedItem.m_ItemID == E_ITEM_DIAMOND_PICKAXE)
- )
- {
- a_Drops.push_back(cItem((ENUM_ITEM_ID)a_BlockType, 1));
- }
- }
-
-
- // These blocks require a pickaxe to drop themselves:
- case E_BLOCK_COBBLESTONE:
- case E_BLOCK_BRICK:
- case E_BLOCK_NETHER_BRICK:
- case E_BLOCK_MOSSY_COBBLESTONE:
- case E_BLOCK_STONE_SLAB:
- case E_BLOCK_COBBLESTONE_STAIRS:
- case E_BLOCK_STONE_BRICK_STAIRS:
- case E_BLOCK_NETHER_BRICK_STAIRS:
- case E_BLOCK_SANDSTONE_STAIRS:
- case E_BLOCK_SANDSTONE:
- case E_BLOCK_STONE_PRESSURE_PLATE:
- {
- if (ItemCategory::IsPickaxe(a_UsedItem.m_ItemID))
- {
- a_Drops.push_back(cItem((ENUM_ITEM_ID)a_BlockType, 1));
- }
- return;
- }
-
-
- // Stone requires a pickaxe to drop cobblestone:
- case E_BLOCK_STONE:
- {
- if (ItemCategory::IsPickaxe(a_UsedItem.m_ItemID))
- {
- a_Drops.push_back(cItem(E_ITEM_COBBLESTONE, 1));
- }
- return;
- }
-
-
- // Snow requires a shovel to harvest:
- case E_BLOCK_SNOW:
- {
- if (ItemCategory::IsShovel(a_UsedItem.m_ItemID))
- {
- a_Drops.push_back(cItem(E_ITEM_SNOWBALL, 1));
- }
- return;
- }
-
-
- // Leaves require shears for harvesting and have a chance of dropping a sapling and a red apple:
- case E_BLOCK_LEAVES:
- {
- if (a_UsedItem.m_ItemID == E_ITEM_SHEARS)
- {
- a_Drops.push_back(cItem(E_ITEM_LEAVES, 1));
- }
- else
- {
- AddRandomDrop(a_Drops, r1, 5, E_ITEM_SAPLING);
- if (a_BlockMeta == E_META_LEAVES_APPLE)
- {
- AddRandomDrop(a_Drops, r1, 200, E_ITEM_APPLE);
- }
- }
- return;
- }
-
-
- // Crops drop a wheat and possibly another seeds when ripe; always drop at least a single seed
- case E_BLOCK_CROPS:
- {
- if (a_BlockMeta == 7)
- {
- AddRandomDrop(a_Drops, r1, 3, E_ITEM_SEEDS);
- a_Drops.push_back(cItem(E_ITEM_WHEAT, 1));
- }
- a_Drops.push_back(cItem(E_ITEM_SEEDS, 1));
- return;
- }
-
-
- // Vines drop only with shears, otherwise they are destroyed
- case E_BLOCK_VINES:
- {
- if (a_UsedItem.m_ItemID == E_ITEM_SHEARS)
- {
- a_Drops.push_back(cItem(E_ITEM_VINES, 1));
- }
- return;
- }
-
-
- // Snow drops only when using a shovel
- case E_BLOCK_SNOW_BLOCK:
- {
- if (ItemCategory::IsShovel(a_UsedItem.m_ItemID))
- {
- a_Drops.push_back(cItem(E_ITEM_SNOWBALL, 4, 0)); return;
- }
- return;
- }
-
-
- // Random multi-drop blocks:
- case E_BLOCK_TALL_GRASS: a_Drops.push_back(cItem(E_ITEM_SEEDS, (short)r1.randInt(3) / 2, 1)); return;
- case E_BLOCK_MELON: a_Drops.push_back(cItem(E_ITEM_MELON_SLICE, 3 + (short)r1.randInt(2), 1)); return;
-
-
- // Fixed multi-drop blocks:
- case E_BLOCK_DOUBLE_STONE_SLAB: a_Drops.push_back(cItem(E_ITEM_STONE_SLAB, 2, 0)); return;
- case E_BLOCK_DOUBLE_WOODEN_SLAB: a_Drops.push_back(cItem(E_ITEM_STEP, 2, 0)); return;
-
- default:
- {
- return;
- }
- } // switch (a_BlockType)
-}
-
-
-
-
-
diff --git a/source/cBlockToPickup.h b/source/cBlockToPickup.h
index 559e0a052..1f4759c99 100644
--- a/source/cBlockToPickup.h
+++ b/source/cBlockToPickup.h
@@ -16,7 +16,6 @@ class cBlockToPickup // tolua_export
{ // tolua_export
public:
/// For a given block and tool, returns the list of drops generated
- static void ToPickup(BLOCKTYPE a_BlockID, NIBBLETYPE a_BlockMeta, const cItem & a_UsedItem, cItems & a_Drops); // tolua_export
/// Returns true if the tool used for the block is the right one for the job. cClientHandle uses this to determine whether to decrease tool durability twice as much
static bool IsRightTool(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, ENUM_ITEM_ID a_UsedTool); // tolua_export
diff --git a/source/cChunk.cpp b/source/cChunk.cpp
index a7405ced2..99d938919 100644
--- a/source/cChunk.cpp
+++ b/source/cChunk.cpp
@@ -29,20 +29,20 @@
#include "cPlayer.h"
#include "BlockArea.h"
#include "cPluginManager.h"
+#include "blocks/Block.h"
#include "packets/cPacket_DestroyEntity.h"
#include "packets/cPacket_PreChunk.h"
#include "packets/cPacket_BlockChange.h"
#include "packets/cPacket_MultiBlock.h"
-#include <json/json.h>
+#include "blocks/Block.h"
+#include <json/json.h>
-// Leaves can be this many blocks that away (inclusive) from the log not to decay
-#define LEAVES_CHECK_DISTANCE 6
@@ -449,7 +449,20 @@ void cChunk::CheckBlocks(void)
{
unsigned int index = (*itr);
Vector3i BlockPos = IndexToCoordinate(index);
+ Vector3i WorldPos = PositionToWorldPosition( BlockPos );
+ cBlockHandler * Handler = BlockHandler(GetBlock(index));
+ if(!Handler->CanBeAt(m_World, WorldPos.x, WorldPos.y, WorldPos.z))
+ {
+ if(Handler->DropOnUnsuitable())
+ {
+ Handler->DropBlock(m_World, WorldPos.x, WorldPos.y, WorldPos.z);
+ }
+
+ m_World->SetBlock(WorldPos.x, WorldPos.y, WorldPos.z, E_BLOCK_AIR, 0);
+ }
+
+ /*
BLOCKTYPE BlockType = GetBlock(index);
NIBBLETYPE BlockMeta = GetMeta (index);
switch (BlockType)
@@ -524,14 +537,8 @@ void cChunk::CheckBlocks(void)
}
break;
}
-
- // If anything next to a leaves block changes, set the leaves' "check for decay" bit (clear bit 0x08):
- case E_BLOCK_LEAVES:
- {
- cChunkDef::SetNibble(m_BlockMeta, index, BlockMeta & 0x07);
- break;
- }
} // switch (BlockType)
+ */
} // for itr - ToTickBlocks[]
}
@@ -585,89 +592,24 @@ void cChunk::TickBlocks(MTRand & a_TickRandom)
break;
}
- case E_BLOCK_GRASS: TickGrass (m_BlockTickX, m_BlockTickY, m_BlockTickZ, a_TickRandom); break;
case E_BLOCK_PUMPKIN_STEM:
case E_BLOCK_MELON_STEM: TickMelonPumpkin(m_BlockTickX, m_BlockTickY, m_BlockTickZ, Index, ID, a_TickRandom); break;
case E_BLOCK_FARMLAND: TickFarmland (m_BlockTickX, m_BlockTickY, m_BlockTickZ); break;
case E_BLOCK_SUGARCANE: GrowSugarcane (m_BlockTickX, m_BlockTickY, m_BlockTickZ, 1); break;
case E_BLOCK_CACTUS: GrowCactus (m_BlockTickX, m_BlockTickY, m_BlockTickZ, 1); break;
-
- case E_BLOCK_SAPLING:
- {
- // Check the highest bit, if set, grow the tree, if not, set it (1-bit delay):
- NIBBLETYPE Meta = GetMeta(m_BlockTickX, m_BlockTickY, m_BlockTickZ);
- if ((Meta & 0x08) != 0)
- {
- m_World->GrowTree( m_BlockTickX + m_PosX*Width, m_BlockTickY, m_BlockTickZ + m_PosZ*Width );
- }
- else
- {
- SetMeta(m_BlockTickX, m_BlockTickY, m_BlockTickZ, Meta | 0x08);
- }
- break;
- }
-
- case E_BLOCK_LEAVES: TickLeaves(m_BlockTickX, m_BlockTickY, m_BlockTickZ, a_TickRandom); break;
+
default:
{
+ cBlockHandler *Handler = BlockHandler(ID);
+ if(Handler->NeedsRandomTicks())
+ Handler->OnUpdate(m_World, m_BlockTickX + m_PosX*Width, m_BlockTickY, m_BlockTickZ + m_PosZ*Width);
break;
}
}
}
}
-
-
-
-
-void cChunk::TickGrass(int a_RelX, int a_RelY, int a_RelZ, MTRand & a_TickRandom)
-{
- // Grass turns into dirt if there's another block on top of it:
- {
- BLOCKTYPE AboveBlock = cChunkDef::GetBlock(m_BlockTypes, a_RelX, a_RelY + 1, a_RelZ);
- if (!((g_BlockOneHitDig[AboveBlock]) || (g_BlockTransparent[AboveBlock])))
- {
- FastSetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_DIRT, 0);
- return;
- }
- }
-
- // Grass spreads to nearby blocks if there's enough light (TODO) and free space above that block
- // Ref.: http://www.minecraftwiki.net/wiki/Grass_Block#Growth
- for (int i = 0; i < 2; i++) // Pick two blocks to grow to
- {
- int OfsX = a_TickRandom.randInt(2) - 1; // [-1 .. 1]
- int OfsY = a_TickRandom.randInt(4) - 3; // [-3 .. 1]
- int OfsZ = a_TickRandom.randInt(2) - 1; // [-1 .. 1]
-
- BLOCKTYPE DestBlock;
- NIBBLETYPE DestMeta;
- if (
- !UnboundedRelGetBlock(a_RelX + OfsX, a_RelY + OfsY, a_RelZ + OfsZ, DestBlock, DestMeta) ||
- (DestBlock != E_BLOCK_DIRT)
- )
- {
- continue;
- }
-
- BLOCKTYPE AboveDest;
- NIBBLETYPE AboveMeta;
- if (
- UnboundedRelGetBlock(a_RelX + OfsX, a_RelY + OfsY + 1, a_RelZ + OfsZ, AboveDest, AboveMeta) &&
- ((g_BlockOneHitDig[AboveDest]) || (g_BlockTransparent[AboveDest]))
- // TODO: Query dest light, if it's enough
- )
- {
- UnboundedRelFastSetBlock(a_RelX + OfsX, a_RelY + OfsY, a_RelZ + OfsZ, E_BLOCK_GRASS, 0);
- }
- } // for i - repeat twice
-}
-
-
-
-
-
void cChunk::TickMelonPumpkin(int a_RelX, int a_RelY, int a_RelZ, int a_BlockIdx, BLOCKTYPE a_BlockType, MTRand & a_TickRandom)
{
NIBBLETYPE Meta = GetMeta(a_BlockIdx);
@@ -762,120 +704,6 @@ void cChunk::TickFarmland(int a_RelX, int a_RelY, int a_RelZ)
-void cChunk::TickLeaves(int a_RelX, int a_RelY, int a_RelZ, MTRand & a_TickRandom)
-{
- // Since leaves-checking is a costly operation, it is done only if leaves are marked for checking (Meta has its 0x08 bit cleared)
- // The meta bit 0x08 bit is cleared (check flag set) each time a block next to the leaves changes
-
- NIBBLETYPE Meta = GetMeta(a_RelX, a_RelY, a_RelZ);
- if ((Meta & 0x04) != 0)
- {
- // Player-placed leaves, don't decay
- return;
- }
- if ((Meta & 0x08) != 0)
- {
- // These leaves have been checked for decay lately and nothing around them changed
- return;
- }
-
- // Get the data around the leaves:
- cBlockArea Area;
- int BaseX = cChunkDef::Width * m_PosX + a_RelX;
- int BaseZ = cChunkDef::Width * m_PosZ + a_RelZ;
- if (!Area.Read(
- m_World,
- BaseX - LEAVES_CHECK_DISTANCE, BaseX + LEAVES_CHECK_DISTANCE,
- a_RelY - LEAVES_CHECK_DISTANCE, a_RelY + LEAVES_CHECK_DISTANCE,
- BaseZ - LEAVES_CHECK_DISTANCE, BaseZ + LEAVES_CHECK_DISTANCE,
- cBlockArea::baTypes)
- )
- {
- // Cannot check leaves, a chunk is missing too close
- return;
- }
-
- if (HasNearLog(Area, BaseX, a_RelY, BaseZ))
- {
- // Log found, the leaves stay; mark them as checked:
- SetNibble(m_BlockMeta, a_RelX, a_RelY, a_RelZ, Meta & 0x07);
- return;
- }
- // Decay the leaves:
- m_World->DigBlock(m_PosX * cChunkDef::Width + a_RelX, a_RelY, m_PosZ * cChunkDef::Width + a_RelZ);
-
- // Let them drop something if the random is right:
- cItems PickupItems;
- cBlockToPickup::ToPickup(E_BLOCK_LEAVES, Meta, cItem(), PickupItems);
-
- // Allow plugins to change the dropped objects:
- cRoot::Get()->GetPluginManager()->CallHookBlockToPickup(E_BLOCK_LEAVES, Meta, NULL, cItem(), PickupItems);
- m_World->SpawnItemPickups(PickupItems, BaseX, a_RelY, BaseZ);
-}
-
-
-
-
-
-#define PROCESS_NEIGHBOR(x,y,z) \
- switch (a_Area.GetBlockType(x, y, z)) \
- { \
- case E_BLOCK_LEAVES: a_Area.SetBlockType(x, y, z, E_BLOCK_SPONGE + i + 1); break; \
- case E_BLOCK_LOG: return true; \
- }
-
-bool cChunk::HasNearLog(cBlockArea & a_Area, int a_BlockX, int a_BlockY, int a_BlockZ)
-{
- // Filter the blocks into a {leaves, log, other (air)} set:
- BLOCKTYPE * Types = a_Area.GetBlockTypes();
- for (int i = a_Area.GetBlockCount() - 1; i > 0; i--)
- {
- switch (Types[i])
- {
- case E_BLOCK_LEAVES:
- case E_BLOCK_LOG:
- {
- break;
- }
- default:
- {
- Types[i] = E_BLOCK_AIR;
- break;
- }
- }
- } // for i - Types[]
-
- // Perform a breadth-first search to see if there's a log connected within 4 blocks of the leaves block:
- // Simply replace all reachable leaves blocks with a sponge block plus iteration (in the Area) and see if we can reach a log in 4 iterations
- a_Area.SetBlockType(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_SPONGE);
- for (int i = 0; i < LEAVES_CHECK_DISTANCE; i++)
- {
- for (int y = a_BlockY - i; y <= a_BlockY + i; y++)
- {
- for (int z = a_BlockZ - i; z <= a_BlockZ + i; z++)
- {
- for (int x = a_BlockX - i; x <= a_BlockX + i; x++)
- {
- if (a_Area.GetBlockType(x, y, z) != E_BLOCK_SPONGE + i)
- {
- continue;
- }
- PROCESS_NEIGHBOR(x - 1, y, z);
- PROCESS_NEIGHBOR(x + 1, y, z);
- PROCESS_NEIGHBOR(x, y, z - 1);
- PROCESS_NEIGHBOR(x, y, z + 1);
- PROCESS_NEIGHBOR(x, y + 1, z);
- PROCESS_NEIGHBOR(x, y - 1, z);
- } // for x
- } // for z
- } // for y
- } // for i - BFS iterations
- return false;
-}
-
-
-
-
void cChunk::GrowMelonPumpkin(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, MTRand & a_TickRandom)
{
diff --git a/source/cChunk.h b/source/cChunk.h
index 652e63204..898a05f86 100644
--- a/source/cChunk.h
+++ b/source/cChunk.h
@@ -257,7 +257,6 @@ private:
void TickGrass (int a_RelX, int a_RelY, int a_RelZ, MTRand & a_TickRandom);
void TickMelonPumpkin(int a_RelX, int a_RelY, int a_RelZ, int a_BlockIdx, BLOCKTYPE a_BlockType, MTRand & a_TickRandom);
void TickFarmland (int a_RelX, int a_RelY, int a_RelZ);
- void TickLeaves (int a_RelX, int a_RelY, int a_RelZ, MTRand & a_TickRandom);
/// Grows sugarcane by the specified number of blocks, but no more than 3 blocks high (used by both bonemeal and ticking)
void GrowSugarcane (int a_RelX, int a_RelY, int a_RelZ, int a_NumBlocks);
diff --git a/source/cClientHandle.cpp b/source/cClientHandle.cpp
index 1ce6fa37b..53852438d 100644
--- a/source/cClientHandle.cpp
+++ b/source/cClientHandle.cpp
@@ -14,8 +14,6 @@
#include "cCraftingWindow.h"
#include "cItem.h"
#include "cTorch.h"
-#include "cStairs.h"
-#include "cStep.h"
#include "cDoors.h"
#include "cLadder.h"
#include "cVine.h"
@@ -27,6 +25,8 @@
#include "cChatColor.h"
#include "cSocket.h"
#include "cTimer.h"
+#include "items/Item.h"
+#include "blocks/Block.h"
#include "cTracer.h"
#include "Vector3f.h"
@@ -796,6 +796,11 @@ void cClientHandle::HandleBlockDig(cPacket_BlockDig * a_Packet)
m_Player->TossItem(false);
return;
}
+
+ if (a_Packet->m_Status == 0x05)
+ {
+ LOGINFO("BlockDig: Status 5 not implemented");
+ }
cWorld* World = m_Player->GetWorld();
BLOCKTYPE OldBlock = World->GetBlock(a_Packet->m_PosX, a_Packet->m_PosY, a_Packet->m_PosZ);
@@ -814,94 +819,35 @@ void cClientHandle::HandleBlockDig(cPacket_BlockDig * a_Packet)
((a_Packet->m_Status == 0x00) && (m_Player->GetGameMode() == 1))
);
- if ((OldBlock == E_BLOCK_WOODEN_DOOR) && !bBroken)
- {
- cDoors::ChangeDoor(m_Player->GetWorld(), a_Packet->m_PosX, a_Packet->m_PosY, a_Packet->m_PosZ);
- }
+ cItem &Equipped = m_Player->GetInventory().GetEquippedItem();
+
+ cItemHandler *ItemHandler = cItemHandler::GetItemHandler(Equipped.m_ItemID);
- cItems PickupItems;
- if (bBroken && !(m_Player->GetGameMode() == 1)) // broken
+ if(bBroken)
{
- cBlockToPickup::ToPickup(OldBlock, OldMeta, m_Player->GetInventory().GetEquippedItem(), PickupItems);
+ ItemHandler->OnBlockDestroyed(World, m_Player, &Equipped, a_Packet->m_PosX, a_Packet->m_PosY, a_Packet->m_PosZ);
- // Allow plugins to change the dropped objects:
- cRoot::Get()->GetPluginManager()->CallHookBlockToPickup(OldBlock, OldMeta, m_Player, m_Player->GetInventory().GetEquippedItem(), PickupItems);
- }
-
- int pX = a_Packet->m_PosX;
- unsigned char pY = a_Packet->m_PosY;
- int pZ = a_Packet->m_PosZ;
-
- AddDirection(pX, pY, pZ, a_Packet->m_Direction);
+ BlockHandler(OldBlock)->OnDestroyedByPlayer(World, m_Player, a_Packet->m_PosX, a_Packet->m_PosY, a_Packet->m_PosZ);
+ World->DigBlock(a_Packet->m_PosX, a_Packet->m_PosY, a_Packet->m_PosZ);
+ }else{
+ cBlockHandler *Handler = cBlockHandler::GetBlockHandler(OldBlock);
+ Handler->OnClick(World, m_Player, a_Packet->m_PosX, a_Packet->m_PosY, a_Packet->m_PosZ);
- char PossibleBlock = World->GetBlock(pX, pY, pZ);
-
- if (PossibleBlock == E_BLOCK_FIRE)
- {
- a_Packet->m_PosX = pX;
- a_Packet->m_PosY = pY;
- a_Packet->m_PosZ = pZ;
- bBroken = true;
- }
+ ItemHandler->OnDiggingBlock(World, m_Player, &Equipped, a_Packet->m_PosX, a_Packet->m_PosY, a_Packet->m_PosZ, a_Packet->m_Direction);
+
- if (!bBroken)
- {
- return;
- }
-
- if (!World->DigBlock(a_Packet->m_PosX, a_Packet->m_PosY, a_Packet->m_PosZ))
- {
- return;
- }
-
- World->SpawnItemPickups(PickupItems, a_Packet->m_PosX, a_Packet->m_PosY, a_Packet->m_PosZ);
-
- switch (OldBlock)
- {
- case E_BLOCK_REDSTONE_TORCH_ON:
- case E_BLOCK_REDSTONE_TORCH_OFF:
- case E_BLOCK_REDSTONE_WIRE:
- {
- cRedstone Redstone(World);
- Redstone.ChangeRedstone(a_Packet->m_PosX, a_Packet->m_PosY, a_Packet->m_PosZ, false);
- break;
- }
- }
-
- if ((OldBlock == E_BLOCK_PISTON) || (OldBlock == E_BLOCK_STICKY_PISTON))
- {
- int newX = a_Packet->m_PosX;
- int newY = a_Packet->m_PosY;
- int newZ = a_Packet->m_PosZ;
- AddPistonDir(newX, newY, newZ, OldMeta & ~(8), 1);
- if (World->GetBlock(newX, newY, newZ) == E_BLOCK_PISTON_EXTENSION)
- {
- World->SetBlock(newX, newY, newZ, E_BLOCK_AIR, 0);
- }
- }
+ //Check for clickthrough-blocks:
+ int pX = a_Packet->m_PosX;
+ unsigned char pY = a_Packet->m_PosY;
+ int pZ = a_Packet->m_PosZ;
+ AddDirection(pX, pY, pZ, a_Packet->m_Direction);
- if (cDoors::IsDoor(OldBlock))
- {
- // Special actions for destroyed door (Destroy second part)
- if (OldMeta & 8)
- {
- // Was upper part of door
- if (cDoors::IsDoor(World->GetBlock(a_Packet->m_PosX, a_Packet->m_PosY - 1, a_Packet->m_PosZ)))
- {
- World->SetBlock(a_Packet->m_PosX, a_Packet->m_PosY - 1, a_Packet->m_PosZ, E_BLOCK_AIR, 0);
- }
- }
- else
+ Handler = cBlockHandler::GetBlockHandler(World->GetBlock(pX, pY, pZ));
+ if(Handler->IsClickedThrough())
{
- // Was lower part
- if (cDoors::IsDoor(World->GetBlock(a_Packet->m_PosX, a_Packet->m_PosY + 1, a_Packet->m_PosZ)))
- {
- World->SetBlock(a_Packet->m_PosX, a_Packet->m_PosY + 1, a_Packet->m_PosZ, E_BLOCK_AIR, 0);
- }
+ Handler->OnClick(World, m_Player, pX, pY, pZ);
}
}
-
- m_Player->UseEquippedItem();
}
@@ -943,490 +889,85 @@ void cClientHandle::HandleBlockPlace(cPacket_BlockPlace * a_Packet)
}
return;
}
+
+ cWorld * World = m_Player->GetWorld();
- //LOG("%i %i %i %i %i %i", a_Packet->m_Count, a_Packet->m_Direction, a_Packet->m_ItemType, a_Packet->m_PosX, a_Packet->m_PosY, a_Packet->m_PosZ);
-
- //printf("Place Dir:%i %i %i %i : %i\n", a_Packet->m_Direction, a_Packet->m_PosX, a_Packet->m_PosY, a_Packet->m_PosZ, a_Packet->m_ItemType);
- // 'use' useable items instead of placing blocks
- bool bPlaceBlock = true;
- bool UpdateRedstone = false;
- bool AddedCurrent = false;
-
- if (a_Packet->m_Direction >= 0)
+ cBlockHandler *Handler = cBlockHandler::GetBlockHandler(World->GetBlock(a_Packet->m_PosX, a_Packet->m_PosY, a_Packet->m_PosZ));
+ if(Handler->IsUseable())
{
- cWorld * World = m_Player->GetWorld();
- BLOCKTYPE BlockType = 0;
- NIBBLETYPE BlockMeta;
- World->GetBlockTypeMeta(a_Packet->m_PosX, a_Packet->m_PosY, a_Packet->m_PosZ, BlockType, BlockMeta);
- switch (BlockType)
- {
- case E_BLOCK_REDSTONE_REPEATER_ON:
- case E_BLOCK_REDSTONE_REPEATER_OFF:
- {
- // no need to update redstone current with a repeater
- // Find meta value of repeater and change it to one step more:
- World->FastSetBlock(a_Packet->m_PosX, a_Packet->m_PosY, a_Packet->m_PosZ, BlockType, ((BlockMeta + 0x04) & 0x0f));
- bPlaceBlock = false;
- break;
- }
-
- case E_BLOCK_WORKBENCH:
- {
- bPlaceBlock = false;
- cWindow* Window = new cCraftingWindow(0, true);
- m_Player->OpenWindow(Window);
- break;
- }
-
- case E_BLOCK_FURNACE:
- case E_BLOCK_LIT_FURNACE:
- case E_BLOCK_CHEST:
- {
- bPlaceBlock = false;
- m_Player->GetWorld()->UseBlockEntity(m_Player, a_Packet->m_PosX, a_Packet->m_PosY, a_Packet->m_PosZ);
- break;
- }
-
- case E_BLOCK_WOODEN_DOOR:
- {
- bPlaceBlock = false;
- cDoors::ChangeDoor(m_Player->GetWorld(), a_Packet->m_PosX, a_Packet->m_PosY, a_Packet->m_PosZ);
- break;
- }
-
- default:
- {
- break;
- }
- } // switch (BlockID)
- } // if (Direction >= 0)
-
- // Some checks to see if it's a placeable item :P
- if (bPlaceBlock)
- {
- cItem Item;
- Item.m_ItemID = Equipped.m_ItemID;
- Item.m_ItemCount = 1;
- LOGD("Placing item of type %i at {%d, %d, %d}",
- (int)a_Packet->m_ItemType,
- a_Packet->m_PosX, a_Packet->m_PosY, a_Packet->m_PosZ
- );
-
- if (m_Player->EatItem(Item.m_ItemID))
- {
- m_Player->GetInventory().RemoveItem(Item);
- return;
- }
+ Handler->OnClick(World, m_Player, a_Packet->m_PosX, a_Packet->m_PosY, a_Packet->m_PosZ);
+ }else{
+ cItemHandler *ItemHandler = cItemHandler::GetItemHandler(Equipped.m_ItemID);
- if (a_Packet->m_Direction < 0)
+ if(ItemHandler->OnItemUse(World, m_Player, &Equipped, a_Packet->m_PosX, a_Packet->m_PosY, a_Packet->m_PosZ, a_Packet->m_Direction))
{
- // clicked in air
- return;
- }
- bool isDoor = false;
-
- //TODO: Wrong Blocks!
- BLOCKTYPE ClickedBlock = m_Player->GetWorld()->GetBlock(a_Packet->m_PosX, a_Packet->m_PosY, a_Packet->m_PosZ);
-
- if (ItemCategory::IsHoe(Item.m_ItemID))
+ //Nothing here :P
+ }else if(ItemHandler->IsPlaceable())
{
- if ((ClickedBlock == E_BLOCK_DIRT) || (ClickedBlock == E_BLOCK_GRASS))
+ if (a_Packet->m_Direction < 0)
{
- m_Player->GetWorld()->FastSetBlock(a_Packet->m_PosX, a_Packet->m_PosY, a_Packet->m_PosZ, E_BLOCK_FARMLAND, 0);
+ // clicked in air
+ return;
}
- return;
- }
- NIBBLETYPE MetaData = (NIBBLETYPE)Equipped.m_ItemHealth; // This generally works for logs & planks, others will override
- bool LavaBucket = false;
- bool WaterBucket = false;
- bool bRemoveItem = true;
- bool bIgnoreCollision = false;
+ int X = a_Packet->m_PosX;
+ int Y = a_Packet->m_PosY;
+ int Z = a_Packet->m_PosZ;
+ char Dir = a_Packet->m_Direction;
+ BLOCKTYPE ClickedBlock = World->GetBlock(X, Y, Z);
+ cBlockHandler *Handler = cBlockHandler::GetBlockHandler(ClickedBlock);
- if (ClickedBlock == E_BLOCK_STEP)
- {
- // Only make double slab if meta values are the same and if player clicked either on top or on bottom of the block (direction either 0 or 1)
- if (MetaData == ( m_Player->GetWorld()->GetBlockMeta(a_Packet->m_PosX, a_Packet->m_PosY, a_Packet->m_PosZ) & 0x7) && a_Packet->m_Direction <= 1)
- //if (MetaData == m_Player->GetWorld()->GetBlockMeta(a_Packet->m_PosX, a_Packet->m_PosY, a_Packet->m_PosZ) && a_Packet->m_Direction == 1)
+ if(Handler->IgnoreBuildCollision())
{
- a_Packet->m_ItemType = E_BLOCK_DOUBLE_STEP;
- if(a_Packet->m_Direction == 1)
- {
- a_Packet->m_PosY--;
- }
- else
+ Handler->OnDestroyedByPlayer(World, m_Player, X, Y, Z);
+ World->FastSetBlock(X, Y, Z, E_BLOCK_AIR, 0);
+ }else{
+ AddDirection(X, Y, Z, a_Packet->m_Direction);
+ //Check for Blocks not allowing placement on top
+ if(Dir == 1 && !Handler->AllowBlockOnTop())
{
- a_Packet->m_PosY++;
- }
- bIgnoreCollision = true;
- }
- }
-
- if ((ClickedBlock == E_BLOCK_SNOW) || (ClickedBlock == E_BLOCK_TALL_GRASS) || (ClickedBlock == E_BLOCK_VINES))
- {
- switch (a_Packet->m_Direction)
- {
- case 1:
- a_Packet->m_PosY--;
- break;
- case 2:
- a_Packet->m_PosZ++;
- break;
- case 3:
- a_Packet->m_PosZ--;
- break;
- case 4:
- a_Packet->m_PosX++;
- break;
- case 5:
- a_Packet->m_PosX--;
- break;
- default: break;
- }
- bIgnoreCollision = true;
- }
+ //Resend the old block
+ //Some times the client still places the block O.o
- // Special handling for special items:
- switch (a_Packet->m_ItemType)
- {
- case E_ITEM_BUCKET:
- {
- // TODO: Change this, it is just a small hack to get it working a little bit. seems like the Client sends the position from the first hitable block :s
- ClickedBlock = (int)m_Player->GetWorld()->GetBlock(a_Packet->m_PosX, a_Packet->m_PosY + 1, a_Packet->m_PosZ);
- LOG("Bucket Clicked BlockID: %d", ClickedBlock);
- switch (ClickedBlock)
- {
- case E_BLOCK_WATER:
- case E_BLOCK_STATIONARY_WATER:
- {
- WaterBucket = true;
- break;
- }
- case E_BLOCK_LAVA:
- case E_BLOCK_STATIONARY_LAVA:
- {
- LavaBucket = true;
- break;
- }
+ World->SendBlockTo(X, Y, Z, m_Player);
+ return;
}
- break;
- } // case E_ITEM_BUCKET
-
- case E_ITEM_LAVA_BUCKET:
- {
- if ((m_Player->GetGameMode() == 1) || (m_Player->GetInventory().RemoveItem(Item)))
- {
- a_Packet->m_ItemType = E_BLOCK_LAVA;
- if (m_Player->GetGameMode() == 1)
- {
- break; //No new Bucket for creative players
- }
- cItem NewItem;
- NewItem.m_ItemID = E_ITEM_BUCKET;
- NewItem.m_ItemCount = 1;
- m_Player->GetInventory().AddItem(NewItem);
- }
- break;
- } // case E_ITEM_LAVA_BUCKET
-
- case E_ITEM_WATER_BUCKET:
- {
- if ((m_Player->GetGameMode() == 1) || (m_Player->GetInventory().RemoveItem(Item)))
- {
- a_Packet->m_ItemType = E_BLOCK_WATER;
- if (m_Player->GetGameMode() == 1)
- {
- break; //No new Bucket for creative players
- }
- cItem NewItem;
- NewItem.m_ItemID = E_ITEM_BUCKET;
- NewItem.m_ItemCount = 1;
- m_Player->GetInventory().AddItem(NewItem);
- }
- break;
- }
-
- case E_BLOCK_TORCH:
- {
- MetaData = cTorch::DirectionToMetaData(a_Packet->m_Direction);
- break;
- }
-
- case E_BLOCK_REDSTONE_TORCH_OFF:
- {
- MetaData = cTorch::DirectionToMetaData(a_Packet->m_Direction);
- if (g_BlockTransparent[ (int)m_Player->GetWorld()->GetBlock(a_Packet->m_PosX, a_Packet->m_PosY+2, a_Packet->m_PosZ) ] == true)
- {
- //if block above is transparent
- //printf("transparent above me\n");
- }
- else
+
+ int PlaceBlock = m_Player->GetWorld()->GetBlock(X, Y, Z);
+ if (!BlockHandler(PlaceBlock)->IgnoreBuildCollision())
{
- //printf("transparent not above me\n");
+ //tried to place a block *into* another?
+ return; // happens when you place a block aiming at side of block like torch or stem
}
- UpdateRedstone = true;
- AddedCurrent = false;
- break;
- }
-
- case E_BLOCK_REDSTONE_TORCH_ON:
- {
- MetaData = cTorch::DirectionToMetaData(a_Packet->m_Direction);
- UpdateRedstone = true;
- AddedCurrent = true;
- break;
- }
-
- case E_ITEM_REDSTONE_DUST:
- {
- MetaData = 0;
- a_Packet->m_ItemType = E_BLOCK_REDSTONE_WIRE;
- UpdateRedstone = true;
- AddedCurrent = false;
- break;
}
- case E_ITEM_REDSTONE_REPEATER:
- {
- MetaData = cRedstone::RepeaterRotationToMetaData(m_Player->GetRotation());
- a_Packet->m_ItemType = E_BLOCK_REDSTONE_REPEATER_OFF;
- UpdateRedstone = true;
- AddedCurrent = false;
- break;
- }
+ cBlockHandler *NewBlock = BlockHandler(ItemHandler->GetBlockType());
- case E_BLOCK_PISTON:
- case E_BLOCK_STICKY_PISTON:
- {
- MetaData = cPiston::RotationPitchToMetaData(m_Player->GetRotation(), m_Player->GetPitch());
- UpdateRedstone = true;
- AddedCurrent = false;
- break;
- }
-
- case E_ITEM_IRON_DOOR:
- {
- a_Packet->m_ItemType = E_BLOCK_IRON_DOOR;
- MetaData = cDoors::RotationToMetaData(m_Player->GetRotation());
- isDoor = true;
- break;
- }
-
- case E_ITEM_WOODEN_DOOR:
- {
- a_Packet->m_ItemType = E_BLOCK_WOODEN_DOOR;
- MetaData = cDoors::RotationToMetaData(m_Player->GetRotation());
- isDoor = true;
- break;
- }
-
- case E_BLOCK_CHEST:
- case E_BLOCK_FURNACE:
- case E_BLOCK_DISPENSER:
- {
- MetaData = cPiston::RotationPitchToMetaData(m_Player->GetRotation(), 0); // Same orientation as pistons, just ignore pitch
- break;
- }
+ //cannot be placed on the side of an other block
+ if(Dir != 1 && !NewBlock->CanBePlacedOnSide())
+ return;
- case E_BLOCK_STEP:
+ if(NewBlock->CanBeAt(World, X, Y, Z))
{
- MetaData += cStep::DirectionToMetaData( a_Packet->m_Direction );
- break;
+ ItemHandler->PlaceBlock(World, m_Player, &m_Player->GetInventory().GetEquippedItem(), X, Y, Z, a_Packet->m_Direction);
+ }else{
+ World->SendBlockTo(X, Y, Z, m_Player); //Send the old block back to the player
+ return;
}
- case E_BLOCK_COBBLESTONE_STAIRS:
- case E_BLOCK_BRICK_STAIRS:
- case E_BLOCK_STONE_BRICK_STAIRS:
- case E_BLOCK_NETHER_BRICK_STAIRS:
- case E_BLOCK_WOODEN_STAIRS:
- {
- MetaData = cStairs::RotationToMetaData(m_Player->GetRotation(), a_Packet->m_Direction);
- break;
- }
- case E_BLOCK_VINES:
- {
- MetaData = cVine::DirectionToMetaData(a_Packet->m_Direction);
- break;
- }
- case E_BLOCK_LADDER:
- {
- MetaData = cLadder::DirectionToMetaData(a_Packet->m_Direction);
- break;
- }
- case E_ITEM_SIGN:
- {
- LOGD("Sign Dir: %i", a_Packet->m_Direction);
- if (a_Packet->m_Direction == 1)
- {
- LOGD("Player Rotation: %f", m_Player->GetRotation());
- MetaData = cSign::RotationToMetaData(m_Player->GetRotation());
- LOGD("Sign rotation %i", MetaData);
- a_Packet->m_ItemType = E_BLOCK_SIGN_POST;
- }
- else
- {
- MetaData = cSign::DirectionToMetaData(a_Packet->m_Direction);
- a_Packet->m_ItemType = E_BLOCK_WALLSIGN;
- }
- break;
- }
-
- case E_ITEM_FLINT_AND_STEEL:
- {
- a_Packet->m_ItemType = E_ITEM_FIRE;
- m_Player->UseEquippedItem();
- bRemoveItem = false;
- break;
- }
- case E_BLOCK_LEAVES:
- {
- MetaData += 0x4;
- break;
- }
- case E_ITEM_SEEDS:
- {
- if (ClickedBlock != E_BLOCK_FARMLAND)
- {
- return;
- }
- a_Packet->m_ItemType = E_BLOCK_CROPS;
- break;
- }
- case E_ITEM_MELON_SEEDS:
+ } else if(ItemHandler->IsFood()) {
+ cItem Item;
+ Item.m_ItemID = Equipped.m_ItemID;
+ Item.m_ItemCount = 1;
+ if (m_Player->EatItem(Item.m_ItemID))
{
- if (ClickedBlock != E_BLOCK_FARMLAND)
- {
- return;
- }
- a_Packet->m_ItemType = E_BLOCK_MELON_STEM;
- break;
- }
- case E_ITEM_PUMPKIN_SEEDS:
- {
- if (ClickedBlock != E_BLOCK_FARMLAND)
- {
- return;
- }
- a_Packet->m_ItemType = E_BLOCK_PUMPKIN_STEM;
- break;
- }
- case E_ITEM_DYE:
- {
- // Handle bonemeal and dyes on sheep
- if (HandleDyes(a_Packet))
- {
- if (m_Player->GetGameMode() == eGameMode_Survival)
- {
- m_Player->GetInventory().RemoveItem(Item);
- }
- return;
- }
- break;
- }
- case E_ITEM_SUGARCANE:
- {
- a_Packet->m_ItemType = E_BLOCK_SUGARCANE;
- break;
- }
- default:
- {
- break;
- }
- } // switch (a_Packet->m_ItemType)
-
-
- if (LavaBucket)
- {
- if ((m_Player->GetGameMode() == 1) || (m_Player->GetInventory().RemoveItem(Item))) {
- cItem NewItem;
- NewItem.m_ItemID = E_ITEM_LAVA_BUCKET;
- NewItem.m_ItemCount = 1;
- m_Player->GetInventory().AddItem(NewItem);
- m_Player->GetWorld()->SetBlock(a_Packet->m_PosX, a_Packet->m_PosY + 1, a_Packet->m_PosZ, E_BLOCK_AIR, 0);
- }
- }
- else if (WaterBucket)
- {
- if ((m_Player->GetGameMode() == 1) || (m_Player->GetInventory().RemoveItem(Item)))
- {
- cItem NewItem;
- NewItem.m_ItemID = E_ITEM_WATER_BUCKET;
- NewItem.m_ItemCount = 1;
- m_Player->GetInventory().AddItem(NewItem);
- m_Player->GetWorld()->SetBlock(a_Packet->m_PosX, a_Packet->m_PosY + 1, a_Packet->m_PosZ, E_BLOCK_AIR, 0);
- }
- }
- else if (IsValidBlock(a_Packet->m_ItemType))
- {
- int X = a_Packet->m_PosX;
- int Y = a_Packet->m_PosY;
- int Z = a_Packet->m_PosZ;
- AddDirection(X, Y, Z, a_Packet->m_Direction);
-
- int PlaceBlock = m_Player->GetWorld()->GetBlock(X, Y, Z);
- if (
- (PlaceBlock != E_BLOCK_AIR)
- && (PlaceBlock != E_BLOCK_WATER)
- && (PlaceBlock != E_BLOCK_STATIONARY_WATER)
- && (PlaceBlock != E_BLOCK_LAVA)
- && (PlaceBlock != E_BLOCK_STATIONARY_LAVA)
- && !bIgnoreCollision
- )
- {
- //tried to place a block *into* another?
- return; // happens when you place a block aiming at side of block like torch or stem
- }
-
- // Check whether selected item is allowed to be placed on specific surface
- if (!m_Player->GetWorld()->IsPlacingItemLegal(a_Packet->m_ItemType, X, Y, Z))
- {
- // If we don't send the block, MC is happy placing cacti underwater:
- m_Player->GetWorld()->SendBlockTo(X, Y, Z, m_Player);
+ ItemHandler->OnFoodEaten(World, m_Player, &Item);
+ m_Player->GetInventory().RemoveItem(Item);
return;
}
-
- if (bRemoveItem)
- {
- if ((m_Player->GetGameMode() != 1) && !m_Player->GetInventory().RemoveItem(Item))
- {
- return;
- }
- }
-
-
- if (isDoor)
- {
- if ((m_Player->GetWorld()->GetBlock(X, Y + 1, Z) == E_BLOCK_AIR) || (m_Player->GetWorld()->GetBlock(X, Y + 1, Z) == E_BLOCK_AIR))
- {
- m_Player->GetWorld()->SetBlock(X, Y + 1, Z, (char)a_Packet->m_ItemType, MetaData + 8);
- m_Player->GetWorld()->SetBlock(X, Y, Z, (char)a_Packet->m_ItemType, MetaData);
- }
- }
- else
- {
- m_Player->GetWorld()->SetBlock(X, Y, Z, (char)a_Packet->m_ItemType, MetaData);
- }
-
- if (UpdateRedstone)
- {
- cRedstone Redstone(m_Player->GetWorld());
- Redstone.ChangeRedstone(a_Packet->m_PosX, a_Packet->m_PosY + 1, a_Packet->m_PosZ, AddedCurrent);
- }
}
}
-
- /*
- // FakeTruth's "magic stick of removal" :D
- // TODO: Turn this into a plugin
- if (m_Username.compare("FakeTruth") == 0)
- {
- if (a_Packet->m_ItemType == 280)
- {
- cRoot::Get()->GetWorld()->SetBlock(a_Packet->m_PosX, a_Packet->m_PosY, a_Packet->m_PosZ, 0, 0);
- }
- }
- */
}
@@ -1624,29 +1165,6 @@ void cClientHandle::HandleKeepAlive(cPacket_KeepAlive * a_Packet)
}
-
-
-
-bool cClientHandle::HandleDyes(cPacket_BlockPlace * a_Packet)
-{
- cItem & Equipped = m_Player->GetInventory().GetEquippedItem();
-
- // TODO: Handle coloring the sheep, too
-
- // Handle growing the plants:
- if (Equipped.m_ItemHealth == E_META_DYE_WHITE)
- {
- cWorld * World = m_Player->GetWorld();
- return World->GrowPlant(a_Packet->m_PosX, a_Packet->m_PosY, a_Packet->m_PosZ, true);
- }
-
- return false;
-}
-
-
-
-
-
bool cClientHandle::CheckBlockInteractionsRate(void)
{
ASSERT(m_Player != NULL);
diff --git a/source/cFluidSimulator.cpp b/source/cFluidSimulator.cpp
index 1301caa8c..937a40c68 100644
--- a/source/cFluidSimulator.cpp
+++ b/source/cFluidSimulator.cpp
@@ -9,7 +9,7 @@
#include "BlockID.h"
#include "Defines.h"
#include "cItem.h"
-#include "cBlockToPickup.h"
+#include "blocks/Block.h"
@@ -356,9 +356,11 @@ void cFluidSimulator::Simulate( float a_Dt )
{
if( bWashedAwayItem )
{
- cItems Drops;
- cBlockToPickup::ToPickup(DownID, m_World->GetBlockMeta(pos.x, pos.y - 1, pos.z), E_ITEM_EMPTY, Drops);
- m_World->SpawnItemPickups(Drops, pos.x, pos.y - 1, pos.z);
+ cBlockHandler * Handler = BlockHandler(DownID);
+ if(Handler->DropOnUnsuitable())
+ {
+ Handler->DropBlock(m_World, pos.x, pos.y - 1, pos.z);
+ }
}
if (pos.y > 0)
{
@@ -390,9 +392,11 @@ void cFluidSimulator::Simulate( float a_Dt )
{
if (bWashedAwayItem)
{
- cItems Drops;
- cBlockToPickup::ToPickup(DownID, m_World->GetBlockMeta(p.x, p.y, p.z), E_ITEM_EMPTY, Drops);
- m_World->SpawnItemPickups(Drops, p.x, p.y, p.z);
+ cBlockHandler * Handler = BlockHandler(DownID);
+ if(Handler->DropOnUnsuitable())
+ {
+ Handler->DropBlock(m_World, p.x, p.y, p.z);
+ }
}
if( p.y == pos.y )
diff --git a/source/cPiston.cpp b/source/cPiston.cpp
index 8cf463c1b..be8b0dff3 100644
--- a/source/cPiston.cpp
+++ b/source/cPiston.cpp
@@ -13,6 +13,7 @@
#include "BlockID.h"
#include "packets/cPacket_BlockAction.h"
#include "cServer.h"
+#include "blocks/Block.h"
extern bool g_BlockPistonBreakable[];
@@ -67,9 +68,11 @@ void cPiston::ExtendPiston( int pistx, int pisty, int pistz )
NIBBLETYPE currMeta = m_World->GetBlockMeta(pistx, pisty, pistz);
if (currBlock != E_BLOCK_AIR)
{
- cItems PickupItems;
- cBlockToPickup::ToPickup(currBlock, currMeta, E_ITEM_EMPTY, PickupItems);
- m_World->SpawnItemPickups(PickupItems, pistx, pisty, pistz);
+ cBlockHandler * Handler = BlockHandler(currBlock);
+ if(Handler->DropOnUnsuitable())
+ {
+ Handler->DropBlock(m_World, pistx, pisty, pistz);
+ }
recalc = true;
}
int oldx = pistx, oldy = pisty, oldz = pistz;
diff --git a/source/cPiston.h b/source/cPiston.h
index d74f0c0a4..d52b92b3d 100644
--- a/source/cPiston.h
+++ b/source/cPiston.h
@@ -20,8 +20,8 @@ public:
static char RotationPitchToMetaData( float a_Rotation, float a_Pitch )
{
- LOG("pre:a_Rotation %f \n",a_Rotation);
- LOG("a_Pitch %f \n",a_Pitch);
+ LOGD("pre:a_Rotation %f \n",a_Rotation);
+ LOGD("a_Pitch %f \n",a_Pitch);
if (a_Pitch >= 50.f ){
return 0x1;
diff --git a/source/cRoot.cpp b/source/cRoot.cpp
index ef234044f..514a00764 100644
--- a/source/cRoot.cpp
+++ b/source/cRoot.cpp
@@ -14,6 +14,10 @@
#include "cThread.h"
#include "cFileFormatUpdater.h"
#include "cRedstone.h"
+#include "blocks/Block.h"
+#include "items/Item.h"
+#include "squirrelbindings/SquirrelFunctions.h"
+#include "squirrelbindings/SquirrelBindings.h"
#include "../iniFile/iniFile.h"
@@ -168,6 +172,11 @@ void cRoot::Start()
m_Authenticator.Stop();
LOG("Stopping plugin manager...");
delete m_PluginManager; m_PluginManager = 0; // This should be first
+
+
+ #if USE_SQUIRREL
+ CloseSquirrelVM();
+ #endif
LOG("Freeing MonsterConfig...");
delete m_MonsterConfig; m_MonsterConfig = 0;
LOG("Stopping WebAdmin...");
@@ -179,6 +188,10 @@ void cRoot::Start()
delete m_GroupManager; m_GroupManager = 0;
LOG("Unloading worlds...");
UnloadWorlds();
+
+ cItemHandler::Deinit();
+ cBlockHandler::Deinit();
+
LOG("Destroying server...");
//delete HeartBeat; HeartBeat = 0;
delete m_Server; m_Server = 0;
diff --git a/source/cStep.h b/source/cStep.h
deleted file mode 100644
index 482bb9b7b..000000000
--- a/source/cStep.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#pragma once
-
-class cStep //tolua_export
-{ //tolua_export
-public:
- static char DirectionToMetaData( int a_Direction ) //tolua_export
- { //tolua_export
- char result = 0x0;
- if( a_Direction == 0)
- {
- result = 0x8;
- }
- return result;
- } //tolua_export
-}; //tolua_export
diff --git a/source/cWorld.cpp b/source/cWorld.cpp
index 980d09cdb..bdf37cb94 100644
--- a/source/cWorld.cpp
+++ b/source/cWorld.cpp
@@ -42,6 +42,7 @@
#include "cTracer.h"
#include "Trees.h"
#include "cPluginManager.h"
+#include "blocks/Block.h"
#include "packets/cPacket_TimeUpdate.h"
@@ -288,6 +289,10 @@ cWorld::cWorld( const AString & a_WorldName )
m_LastSave = 0;
m_LastUnload = 0;
+ //preallocate some memory for ticking blocks so we donīt need to allocate that often
+ m_BlockTickQueue.reserve(1000);
+ m_BlockTickQueueCopy.reserve(1000);
+
//Simulators:
m_WaterSimulator = new cWaterSimulator( this );
m_LavaSimulator = new cLavaSimulator( this );
@@ -355,94 +360,11 @@ void cWorld::CastThunderbolt ( int a_X, int a_Y, int a_Z )
BroadcastToChunkOfBlock(a_X, a_Y, a_Z, &ThunderboltPacket);
}
-
-
-
-
-bool cWorld::IsPlacingItemLegal(Int16 a_ItemType, int a_BlockX, int a_BlockY, int a_BlockZ)
-{
- BLOCKTYPE SurfaceBlock = GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ);
- switch (a_ItemType)
- {
- case E_BLOCK_YELLOW_FLOWER: // Can ONLY be placed on dirt/grass
- case E_BLOCK_RED_ROSE:
- case E_BLOCK_SAPLING:
- {
- switch (SurfaceBlock)
- {
- case E_BLOCK_DIRT:
- case E_BLOCK_GRASS:
- case E_BLOCK_FARMLAND:
- {
- return true;
- }
- }
- return false;
- }
-
- case E_BLOCK_BROWN_MUSHROOM: // Can be placed on pretty much anything, with exceptions
- case E_BLOCK_RED_MUSHROOM:
- {
- switch (SurfaceBlock)
- {
- case E_BLOCK_GLASS:
- case E_BLOCK_YELLOW_FLOWER:
- case E_BLOCK_RED_ROSE:
- case E_BLOCK_BROWN_MUSHROOM:
- case E_BLOCK_RED_MUSHROOM:
- case E_BLOCK_CACTUS:
- {
- return false;
- }
- }
- return true;
- }
-
- case E_BLOCK_CACTUS:
- {
- if ((SurfaceBlock != E_BLOCK_SAND) && (SurfaceBlock != E_BLOCK_CACTUS))
- {
- // Cactus can only be placed on sand and itself
- return false;
- }
-
- // Check surroundings. Cacti may ONLY be surrounded by air
- if (
- (GetBlock(a_BlockX - 1, a_BlockY, a_BlockZ) != E_BLOCK_AIR) ||
- (GetBlock(a_BlockX + 1, a_BlockY, a_BlockZ) != E_BLOCK_AIR) ||
- (GetBlock(a_BlockX, a_BlockY, a_BlockZ - 1) != E_BLOCK_AIR) ||
- (GetBlock(a_BlockX, a_BlockY, a_BlockZ + 1) != E_BLOCK_AIR)
- )
- {
- return false;
- }
- return true;
- }
-
- case E_ITEM_SEEDS:
- case E_ITEM_MELON_SEEDS:
- case E_ITEM_PUMPKIN_SEEDS:
- {
- // Seeds can go only on the farmland block:
- return (SurfaceBlock == E_BLOCK_FARMLAND);
- }
- } // switch (a_Packet->m_ItemType)
- return true;
-}
-
-
-
-
-
void cWorld::SetNextBlockTick(int a_BlockX, int a_BlockY, int a_BlockZ)
{
return m_ChunkMap->SetNextBlockTick(a_BlockX, a_BlockY, a_BlockZ);
}
-
-
-
-
void cWorld::InitializeSpawn(void)
{
int ChunkX = 0, ChunkY = 0, ChunkZ = 0;
@@ -555,6 +477,8 @@ void cWorld::Tick(float a_Dt)
}
m_ChunkMap->Tick(a_Dt, m_TickRand);
+
+ TickQueuedBlocks(a_Dt);
GetSimulatorManager()->Simulate(a_Dt);
@@ -1110,9 +1034,14 @@ int cWorld::GetBiomeAt (int a_BlockX, int a_BlockZ)
void cWorld::SetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_BlockMeta )
{
+ if(a_BlockType == E_BLOCK_AIR)
+ {
+ BlockHandler(GetBlock(a_X, a_Y, a_Z))->OnDestroyed(this, a_X, a_Y, a_Z);
+ }
m_ChunkMap->SetBlock(a_X, a_Y, a_Z, a_BlockType, a_BlockMeta);
GetSimulatorManager()->WakeUp(a_X, a_Y, a_Z);
+ BlockHandler(a_BlockType)->OnPlaced(this, a_X, a_Y, a_Z, a_BlockMeta);
}
@@ -1264,6 +1193,8 @@ bool cWorld::GetBlocks(sSetBlockVector & a_Blocks, bool a_ContinueOnFailure)
bool cWorld::DigBlock( int a_X, int a_Y, int a_Z)
{
+ cBlockHandler *Handler = cBlockHandler::GetBlockHandler(GetBlock(a_X, a_Y, a_Z));
+ Handler->OnDestroyed(this, a_X, a_Y, a_Z);
return m_ChunkMap->DigBlock(a_X, a_Y, a_Z);
}
@@ -1902,3 +1833,45 @@ void cWorld::GetChunkStats(int & a_NumValid, int & a_NumDirty, int & a_NumInLigh
+void cWorld::TickQueuedBlocks(float a_Dt)
+{
+ if(m_BlockTickQueue.empty())
+ return;
+ m_BlockTickQueueCopy.clear();
+ m_BlockTickQueue.swap(m_BlockTickQueueCopy);
+
+ for(std::vector<BlockTickQueueItem *>::iterator itr = m_BlockTickQueueCopy.begin(); itr != m_BlockTickQueueCopy.end(); itr++)
+ {
+ BlockTickQueueItem *Block = (*itr);
+ Block->ToWait -= a_Dt;
+ if(Block->ToWait <= 0)
+ {
+ BlockHandler(GetBlock(Block->X, Block->Y, Block->Z))->OnUpdate(this, Block->X, Block->Y, Block->Z);
+ delete Block; //We donīt have to remove it from the vector, this will happen automatically on the next tick
+ }else{
+ m_BlockTickQueue.push_back(Block); //Keep the block in the queue
+ }
+ }
+
+}
+
+
+void cWorld::QueueBlockForTick(int a_X, int a_Y, int a_Z, float a_Time)
+{
+ BlockTickQueueItem *Block = new BlockTickQueueItem;
+ Block->X = a_X;
+ Block->Y = a_Y;
+ Block->Z = a_Z;
+ Block->ToWait = a_Time;
+
+ m_BlockTickQueue.push_back(Block);
+}
+
+
+bool cWorld::IsBlockDirectlyWatered(int a_X, int a_Y, int a_Z)
+{
+ return IsBlockWater(GetBlock(a_X - 1, a_Y, a_Z))
+ || IsBlockWater(GetBlock(a_X + 1, a_Y, a_Z))
+ || IsBlockWater(GetBlock(a_X, a_Y, a_Z - 1))
+ || IsBlockWater(GetBlock(a_X, a_Y, a_Z + 1));
+} \ No newline at end of file
diff --git a/source/cWorld.h b/source/cWorld.h
index 0a4d0280e..e0e87b708 100644
--- a/source/cWorld.h
+++ b/source/cWorld.h
@@ -54,6 +54,7 @@ typedef cItemCallback<cFurnaceEntity> cFurnaceCallback;
+
class cWorld //tolua_export
{ //tolua_export
public:
@@ -330,6 +331,17 @@ public:
/// Stops threads that belong to this world (part of deinit)
void StopThreads(void);
+ void TickQueuedBlocks(float a_Dt);
+
+ struct BlockTickQueueItem
+ {
+ int X;
+ int Y;
+ int Z;
+ float ToWait;
+ };
+
+ void QueueBlockForTick(int a_X, int a_Y, int a_Z, float a_Time);
void CastThunderbolt (int a_X, int a_Y, int a_Z); //tolua_export
void SetWeather ( eWeather a_Weather ); //tolua_export
@@ -339,14 +351,14 @@ public:
cChunkGenerator & GetGenerator(void) { return m_Generator; }
cWorldStorage & GetStorage (void) { return m_Storage; }
cChunkMap * GetChunkMap (void) { return m_ChunkMap; }
-
- bool IsPlacingItemLegal(Int16 a_ItemType, int a_BlockX, int a_BlockY, int a_BlockZ);
-
+
/// Sets the blockticking to start at the specified block. Only one blocktick per chunk may be set, second call overwrites the first call
void SetNextBlockTick(int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_export
int GetMaxSugarcaneHeight(void) const { return m_MaxSugarcaneHeight; } // tolua_export
int GetMaxCactusHeight (void) const { return m_MaxCactusHeight; } // tolua_export
+
+ bool IsBlockDirectlyWatered(int a_X, int a_Y, int a_Z);
private:
@@ -370,6 +382,9 @@ private:
// The cRedstone class simulates redstone and needs access to m_RSList
friend class cRedstone;
std::vector<int> m_RSList;
+
+ std::vector<BlockTickQueueItem *> m_BlockTickQueue;
+ std::vector<BlockTickQueueItem *> m_BlockTickQueueCopy; //Second is for safely removing the objects from the queue
cSimulatorManager * m_SimulatorManager;
cSandSimulator * m_SandSimulator;
diff --git a/source/items/Item.cpp b/source/items/Item.cpp
new file mode 100644
index 000000000..b3a525c6b
--- /dev/null
+++ b/source/items/Item.cpp
@@ -0,0 +1,224 @@
+#include "Globals.h"
+#include "Item.h"
+#include "../cItem.h"
+#include "../cWorld.h"
+#include "../cPlayer.h"
+
+//Handler
+#include "ItemCloth.h"
+#include "ItemHoe.h"
+#include "ItemSlab.h"
+#include "ItemWood.h"
+#include "ItemShears.h"
+#include "ItemLeaves.h"
+#include "ItemSapling.h"
+#include "ItemBucket.h"
+#include "ItemLighter.h"
+#include "ItemRedstoneDust.h"
+#include "ItemSeeds.h"
+#include "ItemDye.h"
+#include "ItemSugarcane.h"
+#include "ItemPickaxe.h"
+#include "ItemShovel.h"
+#include "ItemSword.h"
+#include "ItemDoor.h"
+
+#include "../blocks/Block.h"
+
+bool cItemHandler::m_HandlerInitialized = false;
+cItemHandler *cItemHandler::m_ItemHandler[2266];
+
+cItemHandler *cItemHandler::GetItemHandler(int a_ItemID)
+{
+ if(a_ItemID < 0) a_ItemID = 0;
+
+ if(!m_HandlerInitialized)
+ { //We have to initialize
+ memset(m_ItemHandler, 0, sizeof(m_ItemHandler));
+ m_HandlerInitialized = true;
+ }
+ if(m_ItemHandler[a_ItemID])
+ return m_ItemHandler[a_ItemID];
+ m_ItemHandler[a_ItemID] = CreateItemHandler(a_ItemID);
+ return m_ItemHandler[a_ItemID];
+}
+
+cItemHandler *cItemHandler::CreateItemHandler(int a_ItemID)
+{
+ switch(a_ItemID)
+ {
+ case E_ITEM_WOODEN_HOE:
+ case E_ITEM_STONE_HOE:
+ case E_ITEM_IRON_HOE:
+ case E_ITEM_GOLD_HOE:
+ case E_ITEM_DIAMOND_HOE:
+ return new cItemHoeHandler(a_ItemID);
+ case E_ITEM_WHITE_CLOTH:
+ return new cItemClothHandler(a_ItemID);
+ case E_ITEM_STONE_SLAB:
+ case E_ITEM_WOODEN_SLAB:
+ return new cItemSlabHandler(a_ItemID);
+ case E_ITEM_LOG:
+ case E_ITEM_WOOD:
+ return new cItemWoodHandler(a_ItemID);
+ case E_ITEM_SHEARS:
+ return new cItemShearsHandler(a_ItemID);
+ case E_ITEM_LEAVES:
+ return new cItemLeavesHandler(a_ItemID);
+ case E_ITEM_SAPLING:
+ return new cItemSaplingHandler(a_ItemID);
+ case E_ITEM_REDSTONE_DUST:
+ return new cItemRedstoneDustHandler(a_ItemID);
+ case E_ITEM_BUCKET:
+ case E_ITEM_WATER_BUCKET:
+ case E_ITEM_LAVA_BUCKET:
+ return new cItemBucketHandler(a_ItemID);
+ case E_ITEM_FLINT_AND_STEEL:
+ return new cItemLighterHandler(a_ItemID);
+ case E_ITEM_PUMPKIN_SEEDS:
+ case E_ITEM_MELON_SEEDS:
+ case E_ITEM_SEEDS:
+ return new cItemSeedsHandler(a_ItemID);
+ case E_ITEM_DYE:
+ return new cItemDyeHandler(a_ItemID);
+ case E_ITEM_SUGARCANE:
+ return new cItemSugarcaneHandler(a_ItemID);
+ case E_ITEM_WOODEN_PICKAXE:
+ case E_ITEM_STONE_PICKAXE:
+ case E_ITEM_IRON_PICKAXE:
+ case E_ITEM_GOLD_PICKAXE:
+ case E_ITEM_DIAMOND_PICKAXE:
+ return new cItemPickaxeHandler(a_ItemID);
+ case E_ITEM_WOODEN_SHOVEL:
+ case E_ITEM_STONE_SHOVEL:
+ case E_ITEM_IRON_SHOVEL:
+ case E_ITEM_GOLD_SHOVEL:
+ case E_ITEM_DIAMOND_SHOVEL:
+ return new cItemShovelHandler(a_ItemID);
+ case E_ITEM_WOODEN_SWORD:
+ case E_ITEM_STONE_SWORD:
+ case E_ITEM_IRON_SWORD:
+ case E_ITEM_GOLD_SWORD:
+ case E_ITEM_DIAMOND_SWORD:
+ return new cItemSwordHandler(a_ItemID);
+
+ case E_ITEM_IRON_DOOR:
+ case E_ITEM_WOODEN_DOOR:
+ return new cItemDoorHandler(a_ItemID);
+
+ default:
+ return new cItemHandler(a_ItemID);
+ break;
+ }
+}
+
+void cItemHandler::Deinit()
+{
+ for(int i = 0; i < 2266; i++)
+ {
+ delete m_ItemHandler[i];
+ }
+}
+
+cItemHandler::cItemHandler(int a_ItemID)
+{
+ m_ItemID = a_ItemID;
+}
+
+bool cItemHandler::OnItemUse(cWorld *a_World, cPlayer *a_Player, cItem *a_Item, int a_X, int a_Y, int a_Z, char a_Dir)
+{
+ return false;
+}
+
+bool cItemHandler::OnDiggingBlock(cWorld *a_World, cPlayer *a_Player, cItem *a_Item, int a_X, int a_Y, int a_Z, char a_Dir)
+{
+ return false;
+}
+
+void cItemHandler::OnBlockDestroyed(cWorld *a_World, cPlayer *a_Player, cItem *a_Item, int a_X, int a_Y, int a_Z)
+{
+ char Block = a_World->GetBlock(a_X, a_Y, a_Z);
+ cBlockHandler *Handler = cBlockHandler::GetBlockHandler(Block);
+
+ if(a_Player->GetGameMode() == eGameMode_Survival)
+ {
+ if(!BlockRequiresSpecialTool(Block) || CanHarvestBlock(Block))
+ {
+ Handler->DropBlock(a_World, a_X, a_Y, a_Z);
+ }
+ }
+
+ a_Player->UseEquippedItem();
+}
+
+void cItemHandler::OnFoodEaten(cWorld *a_World, cPlayer *a_Player, cItem *a_Item)
+{
+
+}
+
+int cItemHandler::GetMaxStackSize()
+{
+ return 64;
+}
+
+int cItemHandler::GetMaxDamage()
+{
+ return 0;
+}
+
+bool cItemHandler::IsTool()
+{
+ return
+ (m_ItemID >= 256 && m_ItemID <= 259)
+ || (m_ItemID == 261)
+ || (m_ItemID >= 267 && m_ItemID <= 279)
+ || (m_ItemID >= 283 && m_ItemID <= 286)
+ || (m_ItemID >= 290 && m_ItemID <= 294)
+ || (m_ItemID >= 256 && m_ItemID <= 259)
+ || (m_ItemID == 325)
+ || (m_ItemID == 346);
+}
+
+bool cItemHandler::IsFood()
+{
+ return
+ (m_ItemID == 260)
+ || (m_ItemID == 282)
+ || (m_ItemID == 297)
+ || (m_ItemID >= 319 && m_ItemID <= 320)
+ || (m_ItemID == 335)
+ || (m_ItemID >= 349 && m_ItemID <= 350)
+ || (m_ItemID == 357)
+ || (m_ItemID == 360)
+ || (m_ItemID >= 363 && m_ItemID <= 366);
+}
+
+bool cItemHandler::IsPlaceable()
+{
+ return m_ItemID >= 1 && m_ItemID <= 136;
+}
+
+
+bool cItemHandler::CanHarvestBlock(BLOCKTYPE a_BlockID)
+{
+ return false;
+}
+
+BLOCKTYPE cItemHandler::GetBlockType()
+{
+ return m_ItemID;
+}
+
+char cItemHandler::GetBlockMeta(char a_ItemMeta)
+{
+ return a_ItemMeta; //This keeps most textures. The few other items have to override this
+}
+
+void cItemHandler::PlaceBlock(cWorld *a_World, cPlayer *a_Player, cItem *a_Item, int a_X, int a_Y, int a_Z, char a_Dir)
+{
+ BLOCKTYPE Block = GetBlockType();
+ cBlockHandler *Handler = cBlockHandler::GetBlockHandler(Block);
+ Handler->PlaceBlock(a_World, a_Player, GetBlockMeta(a_Item->m_ItemHealth), a_X, a_Y, a_Z, a_Dir);
+ if(a_Player->GetGameMode() == eGameMode_Survival)
+ a_Player->GetInventory().RemoveItem(cItem(a_Item->m_ItemID, 1));
+} \ No newline at end of file
diff --git a/source/items/Item.h b/source/items/Item.h
new file mode 100644
index 000000000..e63ec2fc4
--- /dev/null
+++ b/source/items/Item.h
@@ -0,0 +1,45 @@
+#pragma once
+#include "../Defines.h"
+
+class cWorld;
+class cPlayer;
+
+
+class cItemHandler
+{
+public:
+ cItemHandler(int a_ItemID);
+ virtual bool OnItemUse(cWorld *a_World, cPlayer *a_Player, cItem *a_Item, int a_X, int a_Y, int a_Z, char a_Dir); //eg for fishing or hoes
+ virtual bool OnDiggingBlock(cWorld *a_World, cPlayer *a_Player, cItem *a_Item, int a_X, int a_Y, int a_Z, char a_Dir);
+ virtual void OnBlockDestroyed(cWorld *a_World, cPlayer *a_Player, cItem *a_Item, int a_X, int a_Y, int a_Z);
+ virtual void OnFoodEaten(cWorld *a_World, cPlayer *a_Player, cItem *a_Item);
+ virtual int GetMaxStackSize();
+ virtual int GetMaxDamage();
+
+ virtual void PlaceBlock(cWorld *a_World, cPlayer *a_Player, cItem *a_Item, int a_X, int a_Y, int a_Z, char a_Dir);
+
+ virtual bool IsTool();
+ virtual bool IsFood();
+ //Blocks simply get placed
+ virtual bool IsPlaceable();
+
+ virtual BLOCKTYPE GetBlockType();
+ virtual char GetBlockMeta(char a_ItemMeta);
+
+ virtual bool CanHarvestBlock(BLOCKTYPE a_BlockID);
+
+ static cItemHandler *GetItemHandler(int a_ItemID);
+
+ static void Deinit();
+
+
+protected:
+ int m_ItemID;
+ static cItemHandler *CreateItemHandler(int m_ItemID);
+
+ static cItemHandler *m_ItemHandler[2266];
+ static bool m_HandlerInitialized; //used to detect if the itemhandlers are initialized
+};
+
+//Short function
+inline cItemHandler *ItemHandler(int a_ItemID) { return cItemHandler::GetItemHandler(a_ItemID); } \ No newline at end of file
diff --git a/source/items/ItemBucket.h b/source/items/ItemBucket.h
new file mode 100644
index 000000000..e223d47f1
--- /dev/null
+++ b/source/items/ItemBucket.h
@@ -0,0 +1,75 @@
+#pragma once
+
+#include "Item.h"
+#include "../cWorld.h"
+
+class cItemBucketHandler : public cItemHandler
+{
+public:
+ cItemBucketHandler(int a_ItemID)
+ : cItemHandler(a_ItemID)
+ {
+
+ }
+
+ virtual bool OnItemUse(cWorld *a_World, cPlayer *a_Player, cItem *a_Item, int a_X, int a_Y, int a_Z, char a_Dir)
+ {
+ switch(m_ItemID)
+ {
+ case E_ITEM_BUCKET:
+ {
+ AddDirection(a_X, a_Y, a_Z, a_Dir);
+ BLOCKTYPE ClickedBlock = a_World->GetBlock(a_X, a_Y, a_Z);
+ LOG("Bucket Clicked BlockID: %d", ClickedBlock);
+ ENUM_ITEM_ID NewItem = E_ITEM_EMPTY;
+ switch (ClickedBlock)
+ {
+ case E_BLOCK_WATER:
+ case E_BLOCK_STATIONARY_WATER:
+ NewItem = E_ITEM_WATER_BUCKET;
+ break;
+ case E_BLOCK_LAVA:
+ case E_BLOCK_STATIONARY_LAVA:
+ NewItem = E_ITEM_LAVA_BUCKET;
+ break;
+ }
+ if (NewItem != E_ITEM_EMPTY
+ && (a_Player->GetGameMode() == 1 || (a_Player->GetInventory().RemoveItem(cItem(a_Item->m_ItemID, 1)))))
+ {
+ //Give New Bucket
+ a_Player->GetInventory().AddItem(cItem(NewItem, 1));
+ //remove water block
+ a_Player->GetWorld()->SetBlock(a_X, a_Y, a_Z, E_BLOCK_AIR, 0);
+ return true;
+ }
+ }
+ break;
+ case E_ITEM_WATER_BUCKET:
+ case E_ITEM_LAVA_BUCKET:
+ {
+ BLOCKTYPE NewBlock = (m_ItemID == E_ITEM_LAVA_BUCKET) ? E_BLOCK_LAVA : E_BLOCK_WATER;
+
+ AddDirection(a_X, a_Y, a_Z, a_Dir);
+ if(a_World->GetBlock(a_X, a_Y, a_Z) == E_BLOCK_AIR)
+ {
+ if ((a_Player->GetGameMode() == 1) || (a_Player->GetInventory().RemoveItem(cItem(a_Item->m_ItemID, 1))))
+ {
+ a_World->SetBlock(a_X, a_Y, a_Z, NewBlock, 0);
+
+ if (a_Player->GetGameMode() == 1)
+ {
+ break; //No new Bucket for creative players
+ }
+
+ a_Player->GetInventory().AddItem(cItem(E_ITEM_BUCKET, 1));
+ return true;
+ }
+ }
+ }
+ break;
+ }
+
+ return false;
+ }
+
+}; \ No newline at end of file
diff --git a/source/items/ItemCloth.h b/source/items/ItemCloth.h
new file mode 100644
index 000000000..805e90cb4
--- /dev/null
+++ b/source/items/ItemCloth.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#include "Item.h"
+
+
+class cItemClothHandler : public cItemHandler
+{
+public:
+ cItemClothHandler(int a_ItemID)
+ : cItemHandler(a_ItemID)
+ {
+
+ }
+ virtual char GetBlockMeta(char a_ItemMeta)
+ {
+ return a_ItemMeta;
+ }
+}; \ No newline at end of file
diff --git a/source/items/ItemDoor.h b/source/items/ItemDoor.h
new file mode 100644
index 000000000..5b656ce17
--- /dev/null
+++ b/source/items/ItemDoor.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#include "Item.h"
+#include "../cWorld.h"
+
+class cItemDoorHandler : public cItemHandler
+{
+public:
+ cItemDoorHandler(int a_ItemID)
+ : cItemHandler(a_ItemID)
+ {
+
+ }
+
+ virtual bool IsPlaceable()
+ {
+ return true;
+ }
+
+ virtual BLOCKTYPE GetBlockType()
+ {
+ return (m_ItemID == E_ITEM_WOODEN_DOOR) ? E_BLOCK_WOODEN_DOOR : E_BLOCK_IRON_DOOR;
+ }
+
+}; \ No newline at end of file
diff --git a/source/items/ItemDye.h b/source/items/ItemDye.h
new file mode 100644
index 000000000..60a1ed289
--- /dev/null
+++ b/source/items/ItemDye.h
@@ -0,0 +1,32 @@
+#pragma once
+#include "Item.h"
+#include "../cWorld.h"
+#include "../cPlayer.h"
+
+class cItemDyeHandler : public cItemHandler
+{
+public:
+ cItemDyeHandler(int a_ItemID)
+ : cItemHandler(a_ItemID)
+ {
+
+ }
+
+ virtual bool OnItemUse(cWorld *a_World, cPlayer *a_Player, cItem *a_Item, int a_X, int a_Y, int a_Z, char a_Dir)
+ {
+ // TODO: Handle coloring the sheep, too (OnItemUseOnEntity maybe)
+ // Handle growing the plants:
+ if (a_Item->m_ItemHealth == E_META_DYE_WHITE)
+ {
+ if(a_World->GrowPlant(a_X, a_Y, a_Z, true))
+ {
+ if (a_Player->GetGameMode() == eGameMode_Survival)
+ {
+ a_Player->GetInventory().RemoveItem(cItem(a_Item->m_ItemID, 1, a_Item->m_ItemHealth));
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+}; \ No newline at end of file
diff --git a/source/items/ItemHoe.h b/source/items/ItemHoe.h
new file mode 100644
index 000000000..dd73f4ac9
--- /dev/null
+++ b/source/items/ItemHoe.h
@@ -0,0 +1,29 @@
+#pragma once
+#include "Item.h"
+#include "../cWorld.h"
+#include "../cPlayer.h"
+
+class cItemHoeHandler : public cItemHandler
+{
+public:
+ cItemHoeHandler(int a_ItemID)
+ : cItemHandler(a_ItemID)
+ {
+
+ }
+
+ virtual bool OnItemUse(cWorld *a_World, cPlayer *a_Player, cItem *a_Item, int a_X, int a_Y, int a_Z, char a_Dir)
+ {
+ BLOCKTYPE Block = a_World->GetBlock(a_X, a_Y, a_Z);
+
+ if(Block == E_BLOCK_DIRT || Block == E_BLOCK_GRASS)
+ {
+ a_World->FastSetBlock(a_X, a_Y, a_Z, E_BLOCK_FARMLAND, 0);
+
+ a_Player->UseEquippedItem();
+ return true;
+
+ }
+ return false;
+ }
+}; \ No newline at end of file
diff --git a/source/items/ItemLeaves.h b/source/items/ItemLeaves.h
new file mode 100644
index 000000000..d328858fd
--- /dev/null
+++ b/source/items/ItemLeaves.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#include "Item.h"
+
+
+class cItemLeavesHandler : public cItemHandler
+{
+public:
+ cItemLeavesHandler(int a_ItemID)
+ : cItemHandler(a_ItemID)
+ {
+ }
+ virtual char GetBlockMeta(char a_ItemMeta)
+ {
+ return a_ItemMeta | 0x4; //0x4 bit set means this is a player places leave
+ }
+}; \ No newline at end of file
diff --git a/source/items/ItemLighter.h b/source/items/ItemLighter.h
new file mode 100644
index 000000000..287a7742f
--- /dev/null
+++ b/source/items/ItemLighter.h
@@ -0,0 +1,27 @@
+#pragma once
+
+#include "Item.h"
+#include "../cWorld.h"
+#include "../cPlayer.h"
+
+class cItemLighterHandler : public cItemHandler
+{
+public:
+ cItemLighterHandler(int a_ItemID)
+ : cItemHandler(a_ItemID)
+ {
+
+ }
+
+ virtual bool OnItemUse(cWorld *a_World, cPlayer *a_Player, cItem *a_Item, int a_X, int a_Y, int a_Z, char a_Dir)
+ {
+ a_Player->UseEquippedItem();
+
+ AddDirection(a_X, a_Y, a_Z, a_Dir);
+
+ a_World->SetBlock(a_X, a_Y, a_Z, E_BLOCK_FIRE, 0); //0 -> new fire TODO: Make Firesimulator use this
+
+ return false;
+ }
+
+}; \ No newline at end of file
diff --git a/source/items/ItemPickaxe.h b/source/items/ItemPickaxe.h
new file mode 100644
index 000000000..1be3745de
--- /dev/null
+++ b/source/items/ItemPickaxe.h
@@ -0,0 +1,72 @@
+#pragma once
+#include "Item.h"
+#include "../cWorld.h"
+#include "../cPlayer.h"
+
+class cItemPickaxeHandler : public cItemHandler
+{
+public:
+ cItemPickaxeHandler(int a_ItemID)
+ : cItemHandler(a_ItemID)
+ {
+
+ }
+
+ char PickaxeLevel()
+ {
+ switch(m_ItemID)
+ {
+ case E_ITEM_WOODEN_PICKAXE:
+ case E_ITEM_GOLD_PICKAXE:
+ return 1;
+ case E_ITEM_STONE_PICKAXE:
+ return 2;
+ case E_ITEM_IRON_PICKAXE:
+ return 3;
+ case E_ITEM_DIAMOND_PICKAXE:
+ return 4;
+ default:
+ return 0;
+ }
+ }
+
+ virtual bool CanHarvestBlock(BLOCKTYPE a_BlockID)
+ {
+ switch(a_BlockID)
+ {
+ case E_BLOCK_OBSIDIAN:
+ return PickaxeLevel() >= 4;
+ case E_BLOCK_DIAMOND_BLOCK:
+ case E_BLOCK_DIAMOND_ORE:
+ case E_BLOCK_GOLD_BLOCK:
+ case E_BLOCK_GOLD_ORE:
+ case E_BLOCK_REDSTONE_ORE:
+ case E_BLOCK_REDSTONE_ORE_GLOWING:
+ case E_BLOCK_EMERALD_ORE:
+ return PickaxeLevel() >= 3;
+ case E_BLOCK_IRON_BLOCK:
+ case E_BLOCK_IRON_ORE:
+ case E_BLOCK_LAPIS_ORE:
+ case E_BLOCK_LAPIS_BLOCK:
+ return PickaxeLevel() >= 2;
+ case E_BLOCK_COAL_ORE:
+ case E_BLOCK_STONE:
+ case E_BLOCK_COBBLESTONE:
+ case E_BLOCK_END_STONE:
+ case E_BLOCK_MOSSY_COBBLESTONE:
+ case E_BLOCK_SANDSTONE_STAIRS:
+ case E_BLOCK_SANDSTONE:
+ case E_BLOCK_STONE_BRICKS:
+ case E_BLOCK_NETHER_BRICK:
+ case E_BLOCK_NETHERRACK:
+ case E_BLOCK_STONE_SLAB:
+ case E_BLOCK_DOUBLE_STONE_SLAB:
+ case E_BLOCK_STONE_PRESSURE_PLATE:
+ case E_BLOCK_BRICK:
+ case E_BLOCK_COBBLESTONE_STAIRS:
+ case E_BLOCK_STONE_BRICK_STAIRS:
+ case E_BLOCK_NETHER_BRICK_STAIRS:
+ return PickaxeLevel() >= 1;
+ }
+ }
+}; \ No newline at end of file
diff --git a/source/items/ItemRedstoneDust.h b/source/items/ItemRedstoneDust.h
new file mode 100644
index 000000000..99529a4e8
--- /dev/null
+++ b/source/items/ItemRedstoneDust.h
@@ -0,0 +1,27 @@
+#pragma once
+#include "Item.h"
+
+
+class cItemRedstoneDustHandler : public cItemHandler
+{
+public:
+ cItemRedstoneDustHandler(int a_ItemID)
+ : cItemHandler(a_ItemID)
+ {
+ }
+
+ virtual bool IsPlaceable()
+ {
+ return true;
+ }
+
+ virtual BLOCKTYPE GetBlockType()
+ {
+ return E_BLOCK_REDSTONE_WIRE;
+ }
+
+ virtual char GetBlockMeta(char a_ItemMeta)
+ {
+ return 0;
+ }
+}; \ No newline at end of file
diff --git a/source/items/ItemSapling.h b/source/items/ItemSapling.h
new file mode 100644
index 000000000..29c14abee
--- /dev/null
+++ b/source/items/ItemSapling.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include "Item.h"
+
+
+class cItemSaplingHandler : public cItemHandler
+{
+public:
+ cItemSaplingHandler(int a_ItemID)
+ : cItemHandler(a_ItemID)
+ {
+
+ }
+
+ virtual char GetBlockMeta(char a_ItemMeta)
+ {
+ //Only the first 2 bits are important
+ return a_ItemMeta & 3;
+ }
+}; \ No newline at end of file
diff --git a/source/items/ItemSeeds.h b/source/items/ItemSeeds.h
new file mode 100644
index 000000000..d5f9244b2
--- /dev/null
+++ b/source/items/ItemSeeds.h
@@ -0,0 +1,58 @@
+#pragma once
+
+#include "Item.h"
+#include "../cWorld.h"
+
+class cItemSeedsHandler : public cItemHandler
+{
+public:
+ cItemSeedsHandler(int a_ItemID)
+ : cItemHandler(a_ItemID)
+ {
+
+ }
+
+ virtual bool IsPlaceable()
+ {
+ return true;
+ }
+
+ virtual bool AllowBlockOnTop()
+ {
+ return false;
+ }
+
+ virtual BLOCKTYPE GetBlockType()
+ {
+ switch(m_ItemID)
+ {
+ case E_ITEM_SEEDS:
+ return E_BLOCK_CROPS;
+ case E_ITEM_MELON_SEEDS:
+ E_BLOCK_MELON_STEM;
+ case E_ITEM_PUMPKIN_SEEDS:
+ E_BLOCK_PUMPKIN_STEM;
+ default:
+ return E_BLOCK_AIR;
+ }
+ }
+
+ virtual char GetBlockMeta(char a_ItemMeta)
+ {
+ return 0; //Not grown yet
+ }
+
+ virtual void PlaceBlock(cWorld *a_World, cPlayer *a_Player, cItem *a_Item, int a_X, int a_Y, int a_Z, char a_Dir)
+ {
+ int X = a_X,
+ Y = a_Y,
+ Z = a_Z;
+
+ AddDirection(X, Y, Z, a_Dir, true);
+
+ if(a_World->GetBlock(X, Y, Z) != E_BLOCK_FARMLAND)
+ return;
+
+ return cItemHandler::PlaceBlock(a_World, a_Player, a_Item, a_X, a_Y, a_Z, a_Dir);
+ }
+}; \ No newline at end of file
diff --git a/source/items/ItemShears.h b/source/items/ItemShears.h
new file mode 100644
index 000000000..786ea5f5e
--- /dev/null
+++ b/source/items/ItemShears.h
@@ -0,0 +1,41 @@
+#pragma once
+
+#include "Item.h"
+#include "../cWorld.h"
+#include "../cPlayer.h"
+
+class cItemShearsHandler : public cItemHandler
+{
+public:
+ cItemShearsHandler(int a_ItemID)
+ : cItemHandler(a_ItemID)
+ {
+
+ }
+ virtual bool IsTool()
+ {
+ return true;
+ }
+ virtual bool OnDiggingBlock(cWorld *a_World, cPlayer *a_Player, cItem *a_Item, int a_X, int a_Y, int a_Z, char a_Dir) override
+ {
+ BLOCKTYPE Block = a_World->GetBlock(a_X, a_Y, a_Z);
+ if(Block == E_BLOCK_LEAVES)
+ {
+ cItems Drops;
+ Drops.push_back(cItem(E_ITEM_LEAVES, 1, a_World->GetBlockMeta(a_X, a_Y, a_Z)));
+ a_World->SpawnItemPickups(Drops, a_X, a_Y, a_Z);
+
+ a_World->SetBlock(a_X, a_Y, a_Z, E_BLOCK_AIR, 0);
+ a_Player->UseEquippedItem();
+ return true;
+ }
+ return false;
+ }
+
+
+ virtual bool CanHarvestBlock(BLOCKTYPE a_BlockID)
+ {
+ return a_BlockID == E_BLOCK_COBWEB
+ || a_BlockID == E_BLOCK_VINES;
+ }
+}; \ No newline at end of file
diff --git a/source/items/ItemShovel.h b/source/items/ItemShovel.h
new file mode 100644
index 000000000..5fd21cc26
--- /dev/null
+++ b/source/items/ItemShovel.h
@@ -0,0 +1,35 @@
+#pragma once
+#include "Item.h"
+#include "../cWorld.h"
+#include "../cPlayer.h"
+
+#include "../blocks/Block.h"
+
+class cItemShovelHandler : public cItemHandler
+{
+public:
+ cItemShovelHandler(int a_ItemID)
+ : cItemHandler(a_ItemID)
+ {
+
+ }
+
+ virtual bool OnDiggingBlock(cWorld *a_World, cPlayer *a_Player, cItem *a_Item, int a_X, int a_Y, int a_Z, char a_Dir) override
+ {
+ BLOCKTYPE Block = a_World->GetBlock(a_X, a_Y, a_Z);
+ if(Block == E_BLOCK_SNOW)
+ {
+ BlockHandler(Block)->DropBlock(a_World, a_X, a_Y, a_Z);
+
+ a_World->SetBlock(a_X, a_Y, a_Z, E_BLOCK_AIR, 0);
+ a_Player->UseEquippedItem();
+ return true;
+ }
+ return false;
+ }
+
+ virtual bool CanHarvestBlock(BLOCKTYPE a_BlockID)
+ {
+ return a_BlockID == E_BLOCK_SNOW;
+ }
+}; \ No newline at end of file
diff --git a/source/items/ItemSlab.h b/source/items/ItemSlab.h
new file mode 100644
index 000000000..3cb4afeb0
--- /dev/null
+++ b/source/items/ItemSlab.h
@@ -0,0 +1,39 @@
+#pragma once
+
+#include "Item.h"
+#include "../cWorld.h"
+
+class cItemSlabHandler : public cItemHandler
+{
+public:
+ cItemSlabHandler(int a_ItemID)
+ : cItemHandler(a_ItemID)
+ {
+
+ }
+
+ virtual bool OnItemUse(cWorld *a_World, cPlayer *a_Player, cItem *a_Item, int a_X, int a_Y, int a_Z, char a_Dir)
+ {
+ BLOCKTYPE Block;
+ NIBBLETYPE Meta;
+ a_World->GetBlockTypeMeta(a_X, a_Y, a_Z, Block, Meta);
+
+ if( (a_Dir == 0 || a_Dir == 1) //Only when clicking on top or on bottom of the block
+ && (Block == E_BLOCK_WOODEN_SLAB || Block == E_BLOCK_STONE_SLAB) //It is a slab
+ && (Block == a_Item->m_ItemID) //Same slab
+ && ((Meta & 0x7) == (a_Item->m_ItemHealth & 0x7))) //Same Texture
+ {
+ if(a_Player->GetInventory().RemoveItem(cItem(a_Item->m_ItemID, 1)))
+ {
+ a_World->SetBlock(a_X, a_Y, a_Z, Block - 1, Meta); //Block - 1 simple hack to save one if statement
+ return true;
+ }
+ }
+ return false;
+ }
+
+ virtual char GetBlockMeta(char a_ItemMeta)
+ {
+ return a_ItemMeta;
+ }
+}; \ No newline at end of file
diff --git a/source/items/ItemSugarcane.h b/source/items/ItemSugarcane.h
new file mode 100644
index 000000000..515f94014
--- /dev/null
+++ b/source/items/ItemSugarcane.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#include "Item.h"
+#include "../cWorld.h"
+
+class cItemSugarcaneHandler : public cItemHandler
+{
+public:
+ cItemSugarcaneHandler(int a_ItemID)
+ : cItemHandler(a_ItemID)
+ {
+
+ }
+
+ virtual bool IsPlaceable()
+ {
+ return true;
+ }
+
+ virtual bool AllowBlockOnTop()
+ {
+ return false;
+ }
+
+ virtual BLOCKTYPE GetBlockType()
+ {
+ return E_BLOCK_SUGARCANE;
+ }
+
+ virtual char GetBlockMeta(char a_ItemMeta)
+ {
+ return 0; //Not grown yet
+ }
+}; \ No newline at end of file
diff --git a/source/items/ItemSword.h b/source/items/ItemSword.h
new file mode 100644
index 000000000..f49436d51
--- /dev/null
+++ b/source/items/ItemSword.h
@@ -0,0 +1,19 @@
+#pragma once
+#include "Item.h"
+#include "../cWorld.h"
+#include "../cPlayer.h"
+
+class cItemSwordHandler : public cItemHandler
+{
+public:
+ cItemSwordHandler(int a_ItemID)
+ : cItemHandler(a_ItemID)
+ {
+
+ }
+
+ virtual bool CanHarvestBlock(BLOCKTYPE a_BlockID)
+ {
+ return a_BlockID == E_BLOCK_COBWEB;
+ }
+}; \ No newline at end of file
diff --git a/source/items/ItemWood.h b/source/items/ItemWood.h
new file mode 100644
index 000000000..91eaa7675
--- /dev/null
+++ b/source/items/ItemWood.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#include "Item.h"
+
+
+class cItemWoodHandler : public cItemHandler
+{
+public:
+ cItemWoodHandler(int a_ItemID)
+ : cItemHandler(a_ItemID)
+ {
+ }
+ virtual char GetBlockMeta(char a_ItemMeta)
+ {
+ return a_ItemMeta;
+ }
+}; \ No newline at end of file
diff --git a/source/main.cpp b/source/main.cpp
index 03dea6f01..0f51e27d8 100644
--- a/source/main.cpp
+++ b/source/main.cpp
@@ -13,13 +13,6 @@
#endif // _WIN32
#include "squirrelbindings/SquirrelBindings.h"
-#if USE_SQUIRREL
- #pragma warning(push)
- #pragma warning(disable:4100;disable:4127;disable:4510;disable:4610;disable:4244;disable:4512) // Getting A LOT of these warnings from SqPlus
-
- #pragma warning(pop)
-#endif
-
@@ -189,9 +182,6 @@ int main( int argc, char **argv )
LOGERROR("Unknown exception!");
}
- #if USE_SQUIRREL
- CloseSquirrelVM();
- #endif
#if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER)
DeinitLeakFinder();