diff options
Diffstat (limited to '')
-rw-r--r-- | src/Blocks/BlockAnvil.h | 7 | ||||
-rw-r--r-- | src/Blocks/BlockBed.h | 7 | ||||
-rw-r--r-- | src/Blocks/BlockChest.h | 1 | ||||
-rw-r--r-- | src/Blocks/BlockDirt.h | 8 | ||||
-rw-r--r-- | src/Blocks/BlockDoor.cpp | 2 | ||||
-rw-r--r-- | src/Blocks/BlockDoor.h | 104 | ||||
-rw-r--r-- | src/Blocks/BlockDropSpenser.h | 4 | ||||
-rw-r--r-- | src/Blocks/BlockEnchantmentTable.h | 37 | ||||
-rw-r--r-- | src/Blocks/BlockFarmland.h | 4 | ||||
-rw-r--r-- | src/Blocks/BlockFire.h | 19 | ||||
-rw-r--r-- | src/Blocks/BlockFluid.h | 6 | ||||
-rw-r--r-- | src/Blocks/BlockFurnace.h | 4 | ||||
-rw-r--r-- | src/Blocks/BlockHandler.cpp | 11 | ||||
-rw-r--r-- | src/Blocks/BlockHandler.h | 3 | ||||
-rw-r--r-- | src/Blocks/BlockLeaves.h | 7 | ||||
-rw-r--r-- | src/Blocks/BlockMobHead.h | 28 | ||||
-rw-r--r-- | src/Blocks/BlockPiston.cpp | 177 | ||||
-rw-r--r-- | src/Blocks/BlockPiston.h | 134 | ||||
-rw-r--r-- | src/Blocks/BlockPortal.h | 14 | ||||
-rw-r--r-- | src/Blocks/BlockRail.h | 2 | ||||
-rw-r--r-- | src/Blocks/BlockSlab.h | 6 | ||||
-rw-r--r-- | src/Blocks/BlockStairs.h | 5 | ||||
-rw-r--r-- | src/Blocks/CMakeLists.txt | 1 |
23 files changed, 530 insertions, 61 deletions
diff --git a/src/Blocks/BlockAnvil.h b/src/Blocks/BlockAnvil.h index 93a796ef7..35a356678 100644 --- a/src/Blocks/BlockAnvil.h +++ b/src/Blocks/BlockAnvil.h @@ -23,6 +23,13 @@ public: { a_Pickups.push_back(cItem(E_BLOCK_ANVIL, 1, a_BlockMeta >> 2)); } + + + virtual void OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override + { + cWindow * Window = new cAnvilWindow(a_BlockX, a_BlockY, a_BlockZ); + a_Player->OpenWindow(Window); + } virtual bool GetPlacementBlockTypeMeta( diff --git a/src/Blocks/BlockBed.h b/src/Blocks/BlockBed.h index 92804aaac..51e79b888 100644 --- a/src/Blocks/BlockBed.h +++ b/src/Blocks/BlockBed.h @@ -39,6 +39,13 @@ public: } + virtual bool CanDirtGrowGrass(NIBBLETYPE a_Meta) override + { + return true; + } + + + // Bed specific helper functions static NIBBLETYPE RotationToMetaData(double a_Rotation) { diff --git a/src/Blocks/BlockChest.h b/src/Blocks/BlockChest.h index a1ded4c26..c9a769c75 100644 --- a/src/Blocks/BlockChest.h +++ b/src/Blocks/BlockChest.h @@ -56,6 +56,7 @@ public: (Area.GetRelBlockType(2, 0, 1) == E_BLOCK_CHEST) ) { + // FIXME: This is unreachable, as the condition is the same as the above one a_BlockMeta = (yaw < 0) ? 4 : 5; return true; } diff --git a/src/Blocks/BlockDirt.h b/src/Blocks/BlockDirt.h index aa24b8668..2d4fccbac 100644 --- a/src/Blocks/BlockDirt.h +++ b/src/Blocks/BlockDirt.h @@ -35,8 +35,10 @@ public: // Grass becomes dirt if there is something on top of it: if (a_RelY < cChunkDef::Height - 1) { - BLOCKTYPE Above = a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ); - if ((!cBlockInfo::IsTransparent(Above) && !cBlockInfo::IsOneHitDig(Above)) || IsBlockWater(Above)) + BLOCKTYPE Above; + NIBBLETYPE AboveMeta; + a_Chunk.GetBlockTypeMeta(a_RelX, a_RelY + 1, a_RelZ, Above, AboveMeta); + if (!cBlockInfo::GetHandler(Above)->CanDirtGrowGrass(AboveMeta)) { a_Chunk.FastSetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_DIRT, E_META_DIRT_NORMAL); return; @@ -77,7 +79,7 @@ public: BLOCKTYPE AboveDest; NIBBLETYPE AboveMeta; Chunk->GetBlockTypeMeta(BlockX, BlockY + 1, BlockZ, AboveDest, AboveMeta); - if ((cBlockInfo::IsOneHitDig(AboveDest) || cBlockInfo::IsTransparent(AboveDest)) && !IsBlockWater(AboveDest)) + if (cBlockInfo::GetHandler(AboveDest)->CanDirtGrowGrass(AboveMeta)) { if (!cRoot::Get()->GetPluginManager()->CallHookBlockSpread((cWorld*) &a_WorldInterface, BlockX * cChunkDef::Width, BlockY, BlockZ * cChunkDef::Width, ssGrassSpread)) { diff --git a/src/Blocks/BlockDoor.cpp b/src/Blocks/BlockDoor.cpp index 479c68153..fb2d6f2dc 100644 --- a/src/Blocks/BlockDoor.cpp +++ b/src/Blocks/BlockDoor.cpp @@ -62,7 +62,7 @@ void cBlockDoorHandler::OnCancelRightClick(cChunkInterface & a_ChunkInterface, c a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player); NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); - if (Meta & 8) + if (Meta & 0x8) { // Current block is top of the door a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY - 1, a_BlockZ, a_Player); diff --git a/src/Blocks/BlockDoor.h b/src/Blocks/BlockDoor.h index 797fe484c..049c4a334 100644 --- a/src/Blocks/BlockDoor.h +++ b/src/Blocks/BlockDoor.h @@ -20,12 +20,12 @@ public: virtual void OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override; virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override; virtual const char * GetStepSound(void) override; - + virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override; virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override; virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override; virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override; - + virtual bool GetPlacementBlockTypeMeta( cChunkInterface & a_ChunkInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, @@ -52,7 +52,7 @@ public: return true; } - + virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override { a_Pickups.push_back(cItem((m_BlockType == E_BLOCK_WOODEN_DOOR) ? E_ITEM_WOODEN_DOOR : E_ITEM_IRON_DOOR, 1, 0)); @@ -77,8 +77,8 @@ public: { return ((a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) != E_BLOCK_AIR)); } - - + + bool CanReplaceBlock(BLOCKTYPE a_BlockType) { switch (a_BlockType) @@ -99,7 +99,7 @@ public: } - /// Converts the player's yaw to placed door's blockmeta + /** Converts the player's yaw to placed door's blockmeta */ inline static NIBBLETYPE PlayerYawToMetaData(double a_Yaw) { ASSERT((a_Yaw >= -180) && (a_Yaw < 180)); @@ -111,67 +111,109 @@ public: } if ((a_Yaw >= 0) && (a_Yaw < 90)) { - return 0x0; + return 0x00; } else if ((a_Yaw >= 180) && (a_Yaw < 270)) { - return 0x2; + return 0x02; } else if ((a_Yaw >= 90) && (a_Yaw < 180)) { - return 0x1; + return 0x01; } else { - return 0x3; + return 0x03; } } - /// Returns true if the specified blocktype is any kind of door + /** Returns true if the specified blocktype is any kind of door */ inline static bool IsDoor(BLOCKTYPE a_Block) { return (a_Block == E_BLOCK_WOODEN_DOOR) || (a_Block == E_BLOCK_IRON_DOOR); } - /// Returns the metadata for the opposite door state (open vs closed) - static NIBBLETYPE ChangeStateMetaData(NIBBLETYPE a_MetaData) + static NIBBLETYPE IsOpen(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ) { - return a_MetaData ^ 4; + NIBBLETYPE Meta = GetCompleteDoorMeta(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ); + return ((Meta & 0x04) != 0); } - /// Changes the door at the specified coords from open to close or vice versa - static void ChangeDoor(cChunkInterface & a_ChunkInterface, int a_X, int a_Y, int a_Z) + /** Returns the complete meta composed from the both parts of the door as (TopMeta << 4) | BottomMeta + The coords may point to either part of the door. + The returned value has bit 3 (0x08) set iff the coords point to the top part of the door. + Fails gracefully for (invalid) doors on the world's top and bottom. */ + static NIBBLETYPE GetCompleteDoorMeta(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ) { - NIBBLETYPE OldMetaData = a_ChunkInterface.GetBlockMeta(a_X, a_Y, a_Z); - - a_ChunkInterface.SetBlockMeta(a_X, a_Y, a_Z, ChangeStateMetaData(OldMetaData)); + NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); - if (OldMetaData & 8) + if ((Meta & 0x08) != 0) { - // Current block is top of the door - BLOCKTYPE BottomBlock = a_ChunkInterface.GetBlock(a_X, a_Y - 1, a_Z); - NIBBLETYPE BottomMeta = a_ChunkInterface.GetBlockMeta(a_X, a_Y - 1, a_Z); - - if (IsDoor(BottomBlock) && !(BottomMeta & 8)) + // The coords are pointing at the top part of the door + if (a_BlockX > 0) { - a_ChunkInterface.SetBlockMeta(a_X, a_Y - 1, a_Z, ChangeStateMetaData(BottomMeta)); + NIBBLETYPE DownMeta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY - 1, a_BlockZ); + return (NIBBLETYPE) ((DownMeta & 0x07) | 0x08 | (Meta << 4)); } + // This is the top part of the door at the bottommost layer of the world, there's no bottom: + return (NIBBLETYPE) (0x08 | (Meta << 4)); } else { - // Current block is bottom of the door - BLOCKTYPE TopBlock = a_ChunkInterface.GetBlock(a_X, a_Y + 1, a_Z); - NIBBLETYPE TopMeta = a_ChunkInterface.GetBlockMeta(a_X, a_Y + 1, a_Z); + // The coords are pointing at the bottom part of the door + if (a_BlockY < cChunkDef::Height - 1) + { + NIBBLETYPE UpMeta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY + 1, a_BlockZ); + return (NIBBLETYPE) (Meta | (UpMeta << 4)); + } + // This is the bottom part of the door at the topmost layer of the world, there's no top: + return Meta; + } + } - if (IsDoor(TopBlock) && (TopMeta & 8)) + + /** Sets the door to the specified state. If the door is already in that state, does nothing. */ + static void SetOpen(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ, bool a_Open) + { + BLOCKTYPE Block = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY, a_BlockZ); + if (!IsDoor(Block)) + { + return; + } + + NIBBLETYPE Meta = GetCompleteDoorMeta(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ); + bool IsOpened = ((Meta & 0x04) != 0); + if (IsOpened == a_Open) + { + return; + } + + // Change the door + NIBBLETYPE NewMeta = (Meta & 0x07) ^ 0x04; // Flip the "IsOpen" bit (0x04) + if ((Meta & 0x08) == 0) + { + // The block is the bottom part of the door + a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, NewMeta); + } + else + { + // The block is the top part of the door, set the meta to the corresponding top part + if (a_BlockY > 0) { - a_ChunkInterface.SetBlockMeta(a_X, a_Y + 1, a_Z, ChangeStateMetaData(TopMeta)); + a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY - 1, a_BlockZ, NewMeta); } } } + + + /** Changes the door at the specified coords from open to close or vice versa */ + static void ChangeDoor(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ) + { + SetOpen(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ, !IsOpen(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ)); + } } ; diff --git a/src/Blocks/BlockDropSpenser.h b/src/Blocks/BlockDropSpenser.h index 88b61a418..e2b3039fd 100644 --- a/src/Blocks/BlockDropSpenser.h +++ b/src/Blocks/BlockDropSpenser.h @@ -5,7 +5,7 @@ #pragma once -#include "../Piston.h" +#include "../Blocks/BlockPiston.h" #include "MetaRotator.h" @@ -32,7 +32,7 @@ public: a_BlockType = m_BlockType; // FIXME: Do not use cPiston class for dispenser placement! - a_BlockMeta = cPiston::RotationPitchToMetaData(a_Player->GetYaw(), a_Player->GetPitch()); + a_BlockMeta = cBlockPistonHandler::RotationPitchToMetaData(a_Player->GetYaw(), a_Player->GetPitch()); return true; } diff --git a/src/Blocks/BlockEnchantmentTable.h b/src/Blocks/BlockEnchantmentTable.h new file mode 100644 index 000000000..81d2cb9a0 --- /dev/null +++ b/src/Blocks/BlockEnchantmentTable.h @@ -0,0 +1,37 @@ + +#pragma once + +#include "BlockHandler.h" +#include "../UI/Window.h" +#include "../Entities/Player.h" + + + + + +class cBlockEnchantmentTableHandler : + public cBlockHandler +{ +public: + cBlockEnchantmentTableHandler(BLOCKTYPE a_BlockType) + : cBlockHandler(a_BlockType) + { + } + + + virtual void OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override + { + cWindow * Window = new cEnchantingWindow(a_BlockX, a_BlockY, a_BlockZ); + a_Player->OpenWindow(Window); + } + + + virtual bool IsUseable(void) override + { + return true; + } +}; + + + + diff --git a/src/Blocks/BlockFarmland.h b/src/Blocks/BlockFarmland.h index b720ccd14..3dd5bcd1d 100644 --- a/src/Blocks/BlockFarmland.h +++ b/src/Blocks/BlockFarmland.h @@ -52,9 +52,9 @@ public: return; } - int NumBlocks = Area.GetBlockCount(); + size_t NumBlocks = Area.GetBlockCount(); BLOCKTYPE * BlockTypes = Area.GetBlockTypes(); - for (int i = 0; i < NumBlocks; i++) + for (size_t i = 0; i < NumBlocks; i++) { if ( (BlockTypes[i] == E_BLOCK_WATER) || diff --git a/src/Blocks/BlockFire.h b/src/Blocks/BlockFire.h index c8f158e7e..f9f32eb50 100644 --- a/src/Blocks/BlockFire.h +++ b/src/Blocks/BlockFire.h @@ -68,7 +68,6 @@ public: { return 0; } - for (int newY = Y + 1; newY < cChunkDef::Height; newY++) { @@ -84,7 +83,7 @@ public: // This is because the frame is a solid obsidian pillar if ((MaxY != 0) && (newY == Y + 1)) { - return EvaluatePortalBorder(X, newY, Z, MaxY, a_ChunkInterface); + return EvaluatePortalBorder(X, newY, Z, MaxY, a_ChunkInterface) ? -1 /* -1 = found a frame */ : 0; } else { @@ -99,18 +98,18 @@ public: } /// Evaluates if coords have a valid border on top, based on MaxY - int EvaluatePortalBorder(int X, int FoundObsidianY, int Z, int MaxY, cChunkInterface & a_ChunkInterface) + bool EvaluatePortalBorder(int X, int FoundObsidianY, int Z, int MaxY, cChunkInterface & a_ChunkInterface) { for (int checkBorder = FoundObsidianY + 1; checkBorder <= MaxY - 1; checkBorder++) // FoundObsidianY + 1: FoundObsidianY has already been checked in FindObsidianCeiling; MaxY - 1: portal doesn't need corners { if (a_ChunkInterface.GetBlock(X, checkBorder, Z) != E_BLOCK_OBSIDIAN) { // Base obsidian, base + 1 obsidian, base + x NOT obsidian -> not complete portal - return 0; + return false; } } // Everything was obsidian, found a border! - return -1; // Return -1 for a frame border + return true; } /// Finds entire frame in any direction with the coordinates of a base block and fills hole with nether portal (START HERE) @@ -169,7 +168,7 @@ public: { return false; // Not valid slice, no portal can be formed } - } XZP = X1 - 1; // Set boundary of frame interior, note that for some reason, the loop of X and the loop of Z go to different numbers, hence -1 here and -2 there + } XZP = X1 - 1; // Set boundary of frame interior for (; ((a_ChunkInterface.GetBlock(X2, Y, Z) == E_BLOCK_OBSIDIAN) || (a_ChunkInterface.GetBlock(X2, Y + 1, Z) == E_BLOCK_OBSIDIAN)); X2--) // Go the other direction (XM) { int Value = FindObsidianCeiling(X2, Y, Z, a_ChunkInterface, MaxY); @@ -199,13 +198,13 @@ public: if ((Value == -1) || (ValueTwo == -1)) { FoundFrameZP = true; - continue; + break; } else if ((Value != MaxY) && (ValueTwo != MaxY)) { return false; } - } XZP = Z1 - 2; + } XZP = Z1 - 1; for (; ((a_ChunkInterface.GetBlock(X, Y, Z2) == E_BLOCK_OBSIDIAN) || (a_ChunkInterface.GetBlock(X, Y + 1, Z2) == E_BLOCK_OBSIDIAN)); Z2--) { int Value = FindObsidianCeiling(X, Y, Z2, a_ChunkInterface, MaxY); @@ -213,13 +212,13 @@ public: if ((Value == -1) || (ValueTwo == -1)) { FoundFrameZM = true; - continue; + break; } else if ((Value != MaxY) && (ValueTwo != MaxY)) { return false; } - } XZM = Z2 + 2; + } XZM = Z2 + 1; return (FoundFrameZP && FoundFrameZM); } }; diff --git a/src/Blocks/BlockFluid.h b/src/Blocks/BlockFluid.h index d486d642d..d0c4ea55b 100644 --- a/src/Blocks/BlockFluid.h +++ b/src/Blocks/BlockFluid.h @@ -49,6 +49,12 @@ public: } super::Check(a_ChunkInterface, a_PluginInterface, a_RelX, a_RelY, a_RelZ, a_Chunk); } + + + virtual bool CanDirtGrowGrass(NIBBLETYPE a_Meta) override + { + return false; + } } ; diff --git a/src/Blocks/BlockFurnace.h b/src/Blocks/BlockFurnace.h index a7a807957..74582c3b3 100644 --- a/src/Blocks/BlockFurnace.h +++ b/src/Blocks/BlockFurnace.h @@ -3,7 +3,7 @@ #include "BlockEntity.h" #include "../World.h" -#include "../Piston.h" +#include "../Blocks/BlockPiston.h" #include "MetaRotator.h" @@ -35,7 +35,7 @@ public: a_BlockType = m_BlockType; // FIXME: Do not use cPiston class for furnace placement! - a_BlockMeta = cPiston::RotationPitchToMetaData(a_Player->GetYaw(), 0); + a_BlockMeta = cBlockPistonHandler::RotationPitchToMetaData(a_Player->GetYaw(), 0); return true; } diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp index 4a29ff628..304e35e84 100644 --- a/src/Blocks/BlockHandler.cpp +++ b/src/Blocks/BlockHandler.cpp @@ -25,6 +25,7 @@ #include "BlockDirt.h" #include "BlockDoor.h" #include "BlockDropSpenser.h" +#include "BlockEnchantmentTable.h" #include "BlockEnderchest.h" #include "BlockEntity.h" #include "BlockFarmland.h" @@ -119,6 +120,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType) case E_BLOCK_DOUBLE_WOODEN_SLAB: return new cBlockDoubleSlabHandler (a_BlockType); case E_BLOCK_DROPPER: return new cBlockDropSpenserHandler (a_BlockType); case E_BLOCK_EMERALD_ORE: return new cBlockOreHandler (a_BlockType); + case E_BLOCK_ENCHANTMENT_TABLE: return new cBlockEnchantmentTableHandler(a_BlockType); case E_BLOCK_ENDER_CHEST: return new cBlockEnderchestHandler (a_BlockType); case E_BLOCK_FARMLAND: return new cBlockFarmlandHandler ( ); case E_BLOCK_FENCE_GATE: return new cBlockFenceGateHandler (a_BlockType); @@ -398,6 +400,15 @@ bool cBlockHandler::CanBeAt(cChunkInterface & a_ChunkInterface, int a_BlockX, in +bool cBlockHandler::CanDirtGrowGrass(NIBBLETYPE a_Meta) +{ + return ((cBlockInfo::IsTransparent(m_BlockType)) || (cBlockInfo::IsOneHitDig(m_BlockType))); +} + + + + + bool cBlockHandler::IsUseable() { return false; diff --git a/src/Blocks/BlockHandler.h b/src/Blocks/BlockHandler.h index 3a3efb3cc..fb6cae729 100644 --- a/src/Blocks/BlockHandler.h +++ b/src/Blocks/BlockHandler.h @@ -85,6 +85,9 @@ public: /// Checks if the block can stay at the specified relative coords in the chunk virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk); + + /** Can the dirt under this block grow to grass? */ + virtual bool CanDirtGrowGrass(NIBBLETYPE a_Meta); /** Checks if the block can be placed at this point. Default: CanBeAt(...) diff --git a/src/Blocks/BlockLeaves.h b/src/Blocks/BlockLeaves.h index 8af14686e..495e849fa 100644 --- a/src/Blocks/BlockLeaves.h +++ b/src/Blocks/BlockLeaves.h @@ -16,6 +16,7 @@ { \ case E_BLOCK_LEAVES: a_Area.SetBlockType(x, y, z, (BLOCKTYPE)(E_BLOCK_SPONGE + i + 1)); break; \ case E_BLOCK_LOG: return true; \ + case E_BLOCK_NEW_LEAVES: a_Area.SetBlockType(x, y, z, (BLOCKTYPE)(E_BLOCK_SPONGE + i + 1)); break; \ case E_BLOCK_NEW_LOG: return true; \ } @@ -137,14 +138,14 @@ 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--) + for (size_t i = a_Area.GetBlockCount() - 1; i > 0; i--) { switch (Types[i]) { - case E_BLOCK_NEW_LEAVES: - case E_BLOCK_NEW_LOG: case E_BLOCK_LEAVES: case E_BLOCK_LOG: + case E_BLOCK_NEW_LEAVES: + case E_BLOCK_NEW_LOG: { break; } diff --git a/src/Blocks/BlockMobHead.h b/src/Blocks/BlockMobHead.h index acd1c88fb..9855574ad 100644 --- a/src/Blocks/BlockMobHead.h +++ b/src/Blocks/BlockMobHead.h @@ -46,8 +46,30 @@ public: bool IsWither(void) const { return m_IsWither; } void Reset(void) { m_IsWither = false; } + } CallbackA, CallbackB; + class cPlayerCallback : public cPlayerListCallback + { + Vector3f m_Pos; + + virtual bool Item(cPlayer * a_Player) + { + // TODO 2014-05-21 xdot: Vanilla minecraft uses an AABB check instead of a radius one + double Dist = (a_Player->GetPosition() - m_Pos).Length(); + if (Dist < 50.0) + { + // If player is close, award achievement + a_Player->AwardAchievement(achSpawnWither); + } + return false; + } + + public: + cPlayerCallback(const Vector3f & a_Pos) : m_Pos(a_Pos) {} + + } PlayerCallback(Vector3f((float)a_BlockX, (float)a_BlockY, (float)a_BlockZ)); + a_World->DoWithMobHeadAt(a_BlockX, a_BlockY, a_BlockZ, CallbackA); if (!CallbackA.IsWither()) @@ -86,6 +108,9 @@ public: // Spawn the wither: a_World->SpawnMob(a_BlockX + 0.5, a_BlockY - 2, a_BlockZ + 0.5, cMonster::mtWither); + // Award Achievement + a_World->ForEachPlayer(PlayerCallback); + return true; } @@ -113,6 +138,9 @@ public: // Spawn the wither: a_World->SpawnMob(a_BlockX + 0.5, a_BlockY - 2, a_BlockZ + 0.5, cMonster::mtWither); + // Award Achievement + a_World->ForEachPlayer(PlayerCallback); + return true; } diff --git a/src/Blocks/BlockPiston.cpp b/src/Blocks/BlockPiston.cpp index 542eb33b5..faf639312 100644 --- a/src/Blocks/BlockPiston.cpp +++ b/src/Blocks/BlockPiston.cpp @@ -4,14 +4,14 @@ #include "../Item.h" #include "../World.h" #include "../Entities/Player.h" -#include "../Piston.h" +#include "BlockInServerPluginInterface.h" #define AddPistonDir(x, y, z, dir, amount) \ - switch (dir) \ + switch (dir & 0x07) \ { \ case 0: (y) -= (amount); break; \ case 1: (y) += (amount); break; \ @@ -19,8 +19,16 @@ case 3: (z) += (amount); break; \ case 4: (x) -= (amount); break; \ case 5: (x) += (amount); break; \ + default: \ + { \ + LOGWARNING("%s: invalid direction %d, ignoring", __FUNCTION__, dir & 0x07); \ + break; \ + } \ } +#define PISTON_TICK_DELAY 1 +#define PISTON_MAX_PUSH_DISTANCE 12 + @@ -40,7 +48,7 @@ void cBlockPistonHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorld int newX = a_BlockX; int newY = a_BlockY; int newZ = a_BlockZ; - AddPistonDir(newX, newY, newZ, OldMeta & ~(8), 1); + AddPistonDir(newX, newY, newZ, OldMeta, 1); if (a_ChunkInterface.GetBlock(newX, newY, newZ) == E_BLOCK_PISTON_EXTENSION) { @@ -60,7 +68,7 @@ bool cBlockPistonHandler::GetPlacementBlockTypeMeta( ) { a_BlockType = m_BlockType; - a_BlockMeta = cPiston::RotationPitchToMetaData(a_Player->GetYaw(), a_Player->GetPitch()); + a_BlockMeta = RotationPitchToMetaData(a_Player->GetYaw(), a_Player->GetPitch()); return true; } @@ -68,6 +76,165 @@ bool cBlockPistonHandler::GetPlacementBlockTypeMeta( +int cBlockPistonHandler::FirstPassthroughBlock(int a_PistonX, int a_PistonY, int a_PistonZ, NIBBLETYPE pistonmeta, cWorld * a_World) +{ + // Examine each of the 12 blocks ahead of the piston: + for (int ret = 0; ret < PISTON_MAX_PUSH_DISTANCE; ret++) + { + BLOCKTYPE currBlock; + NIBBLETYPE currMeta; + AddPistonDir(a_PistonX, a_PistonY, a_PistonZ, pistonmeta, 1); + a_World->GetBlockTypeMeta(a_PistonX, a_PistonY, a_PistonZ, currBlock, currMeta); + if (CanBreakPush(currBlock)) + { + // This block breaks when pushed, extend up to here + return ret; + } + if (!CanPush(currBlock, currMeta)) + { + // This block cannot be pushed at all, the piston can't extend + return -1; + } + } + // There is no space for the blocks to move, piston can't extend + return -1; +} + + + + + +void cBlockPistonHandler::ExtendPiston(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) +{ + BLOCKTYPE pistonBlock; + NIBBLETYPE pistonMeta; + a_World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, pistonBlock, pistonMeta); + + if (IsExtended(pistonMeta)) + { + // Already extended, bail out + return; + } + + int dist = FirstPassthroughBlock(a_BlockX, a_BlockY, a_BlockZ, pistonMeta, a_World); + if (dist < 0) + { + // FirstPassthroughBlock says piston can't push anything, bail out + return; + } + + a_World->BroadcastBlockAction(a_BlockX, a_BlockY, a_BlockZ, 0, pistonMeta, pistonBlock); + a_World->BroadcastSoundEffect("tile.piston.out", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, 0.7f); + + // Drop the breakable block in the line, if appropriate: + AddPistonDir(a_BlockX, a_BlockY, a_BlockZ, pistonMeta, dist + 1); // "a_Block" now at the breakable / empty block + BLOCKTYPE currBlock; + NIBBLETYPE currMeta; + a_World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, currBlock, currMeta); + if (currBlock != E_BLOCK_AIR) + { + cBlockHandler * Handler = BlockHandler(currBlock); + if (Handler->DoesDropOnUnsuitable()) + { + cChunkInterface ChunkInterface(a_World->GetChunkMap()); + cBlockInServerPluginInterface PluginInterface(*a_World); + Handler->DropBlock(ChunkInterface, *a_World, PluginInterface, NULL, a_BlockX, a_BlockY, a_BlockZ); + } + } + + // Push blocks, from the furthest to the nearest: + int oldx = a_BlockX, oldy = a_BlockY, oldz = a_BlockZ; + NIBBLETYPE currBlockMeta; + std::vector<Vector3i> ScheduledBlocks; + ScheduledBlocks.reserve(PISTON_MAX_PUSH_DISTANCE); + + for (int i = dist + 1; i > 1; i--) + { + AddPistonDir(a_BlockX, a_BlockY, a_BlockZ, pistonMeta, -1); + a_World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, currBlock, currBlockMeta); + a_World->SetBlock(oldx, oldy, oldz, currBlock, currBlockMeta, false); + ScheduledBlocks.push_back(Vector3i(oldx, oldy, oldz)); + oldx = a_BlockX; + oldy = a_BlockY; + oldz = a_BlockZ; + } + + int extx = a_BlockX; + int exty = a_BlockY; + int extz = a_BlockZ; + ScheduledBlocks.push_back(Vector3i(extx, exty, extz)); + AddPistonDir(a_BlockX, a_BlockY, a_BlockZ, pistonMeta, -1); + // "a_Block" now at piston body, "ext" at future extension + + a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, pistonBlock, pistonMeta | 0x8); + a_World->SetBlock(extx, exty, extz, E_BLOCK_PISTON_EXTENSION, pistonMeta | (IsSticky(pistonBlock) ? 8 : 0), false); + a_World->ScheduleTask(PISTON_TICK_DELAY, new cWorld::cTaskSendBlockToAllPlayers(ScheduledBlocks)); +} + + + + + +void cBlockPistonHandler::RetractPiston(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) +{ + BLOCKTYPE pistonBlock; + NIBBLETYPE pistonMeta; + a_World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, pistonBlock, pistonMeta); + + if (!IsExtended(pistonMeta)) + { + // Already retracted, bail out + return; + } + + // Check the extension: + AddPistonDir(a_BlockX, a_BlockY, a_BlockZ, pistonMeta, 1); + if (a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) != E_BLOCK_PISTON_EXTENSION) + { + LOGD("%s: Piston without an extension - still extending, or just in an invalid state?", __FUNCTION__); + return; + } + + AddPistonDir(a_BlockX, a_BlockY, a_BlockZ, pistonMeta, -1); + a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, pistonBlock, pistonMeta & ~(8)); + a_World->BroadcastBlockAction(a_BlockX, a_BlockY, a_BlockZ, 1, pistonMeta & ~(8), pistonBlock); + a_World->BroadcastSoundEffect("tile.piston.in", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, 0.7f); + AddPistonDir(a_BlockX, a_BlockY, a_BlockZ, pistonMeta, 1); + + // Retract the extension, pull block if appropriate + if (IsSticky(pistonBlock)) + { + int tempx = a_BlockX, tempy = a_BlockY, tempz = a_BlockZ; + AddPistonDir(tempx, tempy, tempz, pistonMeta, 1); + BLOCKTYPE tempBlock; + NIBBLETYPE tempMeta; + a_World->GetBlockTypeMeta(tempx, tempy, tempz, tempBlock, tempMeta); + if (CanPull(tempBlock, tempMeta)) + { + // Pull the block + a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, tempBlock, tempMeta, false); + a_World->SetBlock(tempx, tempy, tempz, E_BLOCK_AIR, 0, false); + + std::vector<Vector3i> ScheduledBlocks; + ScheduledBlocks.push_back(Vector3i(a_BlockX, a_BlockY, a_BlockZ)); + ScheduledBlocks.push_back(Vector3i(tempx, tempy, tempz)); + a_World->ScheduleTask(PISTON_TICK_DELAY + 1, new cWorld::cTaskSendBlockToAllPlayers(ScheduledBlocks)); + return; + } + } + + // Retract without pulling + a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0, false); + + std::vector<Vector3i> ScheduledBlocks; + ScheduledBlocks.push_back(Vector3i(a_BlockX, a_BlockY, a_BlockZ)); + a_World->ScheduleTask(PISTON_TICK_DELAY + 1, new cWorld::cTaskSendBlockToAllPlayers(ScheduledBlocks)); +} + + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cBlockPistonHeadHandler: @@ -87,7 +254,7 @@ void cBlockPistonHeadHandler::OnDestroyedByPlayer(cChunkInterface & a_ChunkInter int newX = a_BlockX; int newY = a_BlockY; int newZ = a_BlockZ; - AddPistonDir(newX, newY, newZ, OldMeta & ~(8), -1); + AddPistonDir(newX, newY, newZ, OldMeta, -1); BLOCKTYPE Block = a_ChunkInterface.GetBlock(newX, newY, newZ); if ((Block == E_BLOCK_STICKY_PISTON) || (Block == E_BLOCK_PISTON)) diff --git a/src/Blocks/BlockPiston.h b/src/Blocks/BlockPiston.h index 7632b5e5a..e6fa48e54 100644 --- a/src/Blocks/BlockPiston.h +++ b/src/Blocks/BlockPiston.h @@ -21,6 +21,138 @@ public: int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override; + + static NIBBLETYPE RotationPitchToMetaData(double a_Rotation, double a_Pitch) + { + if (a_Pitch >= 50) + { + return 0x1; + } + else if (a_Pitch <= -50) + { + return 0x0; + } + else + { + a_Rotation += 90 + 45; // So its not aligned with axis + + if (a_Rotation > 360) + { + a_Rotation -= 360; + } + if ((a_Rotation >= 0) && (a_Rotation < 90)) + { + return 0x4; + } + else if ((a_Rotation >= 180) && (a_Rotation < 270)) + { + return 0x5; + } + else if ((a_Rotation >= 90) && (a_Rotation < 180)) + { + return 0x2; + } + else + { + return 0x3; + } + } + } + + static eBlockFace MetaDataToDirection(NIBBLETYPE a_MetaData) + { + switch (a_MetaData) + { + case 0x0: return BLOCK_FACE_YM; + case 0x1: return BLOCK_FACE_YP; + case 0x2: return BLOCK_FACE_ZM; + case 0x3: return BLOCK_FACE_ZP; + case 0x4: return BLOCK_FACE_XM; + case 0x5: return BLOCK_FACE_XP; + default: + { + ASSERT(!"Invalid Metadata"); + return BLOCK_FACE_NONE; + } + } + } + + static void ExtendPiston(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World); + static void RetractPiston(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World); + +private: + + /// Returns true if the piston (specified by blocktype) is a sticky piston + static inline bool IsSticky(BLOCKTYPE a_BlockType) { return (a_BlockType == E_BLOCK_STICKY_PISTON); } + + /// Returns true if the piston (with the specified meta) is extended + static inline bool IsExtended(NIBBLETYPE a_PistonMeta) { return ((a_PistonMeta & 0x8) != 0x0); } + + /// Returns true if the specified block can be pushed by a piston (and left intact) + static inline bool CanPush(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) + { + switch (a_BlockType) + { + case E_BLOCK_ANVIL: + case E_BLOCK_BED: + case E_BLOCK_BEDROCK: + case E_BLOCK_BREWING_STAND: + case E_BLOCK_CHEST: + case E_BLOCK_COMMAND_BLOCK: + case E_BLOCK_DISPENSER: + case E_BLOCK_DROPPER: + case E_BLOCK_ENCHANTMENT_TABLE: + case E_BLOCK_END_PORTAL: + case E_BLOCK_END_PORTAL_FRAME: + case E_BLOCK_FURNACE: + case E_BLOCK_LIT_FURNACE: + case E_BLOCK_HOPPER: + case E_BLOCK_JUKEBOX: + case E_BLOCK_MOB_SPAWNER: + case E_BLOCK_NETHER_PORTAL: + case E_BLOCK_NOTE_BLOCK: + case E_BLOCK_OBSIDIAN: + case E_BLOCK_PISTON_EXTENSION: + { + return false; + } + case E_BLOCK_STICKY_PISTON: + case E_BLOCK_PISTON: + { + // A piston can only be pushed if retracted: + return !IsExtended(a_BlockMeta); + } + } + return true; + } + + /// Returns true if the specified block can be pushed by a piston and broken / replaced + static inline bool CanBreakPush(BLOCKTYPE a_BlockType) { return cBlockInfo::IsPistonBreakable(a_BlockType); } + + /// Returns true if the specified block can be pulled by a sticky piston + static inline bool CanPull(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) + { + switch (a_BlockType) + { + case E_BLOCK_LAVA: + case E_BLOCK_STATIONARY_LAVA: + case E_BLOCK_STATIONARY_WATER: + case E_BLOCK_WATER: + { + return false; + } + } + + if (CanBreakPush(a_BlockType)) + { + return false; // CanBreakPush returns true, but we need false to prevent pulling + } + + return CanPush(a_BlockType, a_BlockMeta); + } + + /// Returns how many blocks the piston has to push (where the first free space is); < 0 when unpushable + static int FirstPassthroughBlock(int a_PistonX, int a_PistonY, int a_PistonZ, NIBBLETYPE a_PistonMeta, cWorld * a_World); } ; @@ -40,7 +172,7 @@ public: virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override { // No pickups - // Also with 1.7, the item forms of these tecnical blocks have been removed, so giving someone this will crash their client... + // Also with 1.7, the item forms of these technical blocks have been removed, so giving someone this will crash their client... } } ; diff --git a/src/Blocks/BlockPortal.h b/src/Blocks/BlockPortal.h index 21bcbdeea..3b8030028 100644 --- a/src/Blocks/BlockPortal.h +++ b/src/Blocks/BlockPortal.h @@ -2,6 +2,7 @@ #pragma once #include "BlockHandler.h" +#include "../Mobs/Monster.h" @@ -38,6 +39,19 @@ public: return; // No pickups } + virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override + { + cFastRandom Random; + if (Random.NextInt(2000) != 0) + { + return; + } + + int PosX = a_Chunk.GetPosX() * 16 + a_RelX; + int PosZ = a_Chunk.GetPosZ() * 16 + a_RelZ; + + a_WorldInterface.SpawnMob(PosX, a_RelY, PosZ, cMonster::mtZombiePigman); + } virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { diff --git a/src/Blocks/BlockRail.h b/src/Blocks/BlockRail.h index ad78d290a..358b5ca11 100644 --- a/src/Blocks/BlockRail.h +++ b/src/Blocks/BlockRail.h @@ -141,7 +141,7 @@ public: NIBBLETYPE Meta = 0; char RailsCnt = 0; bool Neighbors[8]; // 0 - EAST, 1 - WEST, 2 - NORTH, 3 - SOUTH, 4 - EAST UP, 5 - WEST UP, 6 - NORTH UP, 7 - SOUTH UP - memset(Neighbors, false, sizeof(Neighbors)); + memset(Neighbors, 0, sizeof(Neighbors)); Neighbors[0] = (IsUnstable(a_ChunkInterface, a_BlockX + 1, a_BlockY, a_BlockZ) || !IsNotConnected(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_EAST, E_PURE_DOWN)); Neighbors[1] = (IsUnstable(a_ChunkInterface, a_BlockX - 1, a_BlockY, a_BlockZ) || !IsNotConnected(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_WEST, E_PURE_DOWN)); Neighbors[2] = (IsUnstable(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ - 1) || !IsNotConnected(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_NORTH, E_PURE_DOWN)); diff --git a/src/Blocks/BlockSlab.h b/src/Blocks/BlockSlab.h index 76f5ed0e7..80841b094 100644 --- a/src/Blocks/BlockSlab.h +++ b/src/Blocks/BlockSlab.h @@ -97,6 +97,12 @@ public: return ""; } + + virtual bool CanDirtGrowGrass(NIBBLETYPE a_Meta) override + { + return ((a_Meta & 0x8) != 0); + } + /// Returns true if the specified blocktype is one of the slabs handled by this handler static bool IsAnySlabType(BLOCKTYPE a_BlockType) diff --git a/src/Blocks/BlockStairs.h b/src/Blocks/BlockStairs.h index 09ff254a6..a49fda5ae 100644 --- a/src/Blocks/BlockStairs.h +++ b/src/Blocks/BlockStairs.h @@ -77,6 +77,11 @@ public: // Reset meta to 0 a_Pickups.push_back(cItem(m_BlockType, 1, 0)); } + + virtual bool CanDirtGrowGrass(NIBBLETYPE a_Meta) override + { + return true; + } static NIBBLETYPE RotationToMetaData(double a_Rotation) { diff --git a/src/Blocks/CMakeLists.txt b/src/Blocks/CMakeLists.txt index 082ff41ac..4b8c745ad 100644 --- a/src/Blocks/CMakeLists.txt +++ b/src/Blocks/CMakeLists.txt @@ -6,6 +6,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../") file(GLOB SOURCE "*.cpp" + "*.h" ) add_library(Blocks ${SOURCE}) |