summaryrefslogtreecommitdiffstats
path: root/src/Items
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/Items/ItemArmor.h35
-rw-r--r--src/Items/ItemBed.h41
-rw-r--r--src/Items/ItemBigFlower.h29
-rw-r--r--src/Items/ItemBoat.h42
-rw-r--r--src/Items/ItemBottle.h44
-rw-r--r--src/Items/ItemBow.h16
-rw-r--r--src/Items/ItemBrewingStand.h14
-rw-r--r--src/Items/ItemBucket.h34
-rw-r--r--src/Items/ItemCake.h14
-rw-r--r--src/Items/ItemCauldron.h14
-rw-r--r--src/Items/ItemChest.h62
-rw-r--r--src/Items/ItemComparator.h20
-rw-r--r--src/Items/ItemDoor.h40
-rw-r--r--src/Items/ItemDye.h31
-rw-r--r--src/Items/ItemEmptyMap.h30
-rw-r--r--src/Items/ItemEyeOfEnder.h41
-rw-r--r--src/Items/ItemFishingRod.h370
-rw-r--r--src/Items/ItemFlowerPot.h20
-rw-r--r--src/Items/ItemHandler.cpp85
-rw-r--r--src/Items/ItemHandler.h60
-rw-r--r--src/Items/ItemHoe.h76
-rw-r--r--src/Items/ItemItemFrame.h60
-rw-r--r--src/Items/ItemLeaves.h14
-rw-r--r--src/Items/ItemLighter.h37
-rw-r--r--src/Items/ItemLilypad.h39
-rw-r--r--src/Items/ItemMinecart.h26
-rw-r--r--src/Items/ItemMobHead.h61
-rw-r--r--src/Items/ItemNetherWart.h36
-rw-r--r--src/Items/ItemPainting.h125
-rw-r--r--src/Items/ItemPotion.h19
-rw-r--r--src/Items/ItemPumpkin.h83
-rw-r--r--src/Items/ItemRedstoneDust.h35
-rw-r--r--src/Items/ItemRedstoneRepeater.h22
-rw-r--r--src/Items/ItemSapling.h19
-rw-r--r--src/Items/ItemSeeds.h33
-rw-r--r--src/Items/ItemShears.h29
-rw-r--r--src/Items/ItemSign.h44
-rw-r--r--src/Items/ItemSlab.h60
-rw-r--r--src/Items/ItemSpawnEgg.h38
-rw-r--r--src/Items/ItemString.h24
-rw-r--r--src/Items/ItemSugarcane.h22
-rw-r--r--src/Items/ItemThrowable.h40
42 files changed, 1194 insertions, 790 deletions
diff --git a/src/Items/ItemArmor.h b/src/Items/ItemArmor.h
index d218c22b3..d91888d5b 100644
--- a/src/Items/ItemArmor.h
+++ b/src/Items/ItemArmor.h
@@ -8,43 +8,52 @@
-class cItemArmorHandler :
+class cItemArmorHandler:
public cItemHandler
{
+ using Super = cItemHandler;
+
public:
- cItemArmorHandler(int a_ItemType) :
- cItemHandler(a_ItemType)
+
+ cItemArmorHandler(int a_ItemType):
+ Super(a_ItemType)
{
}
+
+
/** Move the armor to the armor slot of the player's inventory */
virtual bool OnItemUse(
- cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
+ cWorld * a_World,
+ cPlayer * a_Player,
+ cBlockPluginInterface & a_PluginInterface,
+ const cItem & a_HeldItem,
+ const Vector3i a_ClickedBlockPos,
+ eBlockFace a_ClickedBlockFace
) override
{
int SlotNum;
- if (ItemCategory::IsHelmet(a_Item.m_ItemType))
+ if (ItemCategory::IsHelmet(a_HeldItem.m_ItemType))
{
SlotNum = 0;
}
- else if (ItemCategory::IsChestPlate(a_Item.m_ItemType))
+ else if (ItemCategory::IsChestPlate(a_HeldItem.m_ItemType))
{
SlotNum = 1;
}
- else if (ItemCategory::IsLeggings(a_Item.m_ItemType))
+ else if (ItemCategory::IsLeggings(a_HeldItem.m_ItemType))
{
SlotNum = 2;
}
- else if (ItemCategory::IsBoots(a_Item.m_ItemType))
+ else if (ItemCategory::IsBoots(a_HeldItem.m_ItemType))
{
SlotNum = 3;
}
else
{
- LOGWARNING("Used unknown armor: %i", a_Item.m_ItemType);
+ LOGWARNING("Used unknown armor: %i", a_HeldItem.m_ItemType);
return false;
}
@@ -53,9 +62,9 @@ public:
return false;
}
- a_Player->GetInventory().SetArmorSlot(SlotNum, a_Item.CopyOne());
+ a_Player->GetInventory().SetArmorSlot(SlotNum, a_HeldItem.CopyOne());
- cItem Item(a_Item);
+ cItem Item(a_HeldItem);
Item.m_ItemCount--;
if (Item.m_ItemCount <= 0)
{
@@ -67,6 +76,8 @@ public:
+
+
virtual bool CanRepairWithRawMaterial(short a_ItemType) override
{
switch (m_ItemType)
diff --git a/src/Items/ItemBed.h b/src/Items/ItemBed.h
index 0f085d489..9c79a134a 100644
--- a/src/Items/ItemBed.h
+++ b/src/Items/ItemBed.h
@@ -9,51 +9,60 @@
-class cItemBedHandler :
+class cItemBedHandler:
public cItemHandler
{
+ using Super = cItemHandler;
+
public:
- cItemBedHandler(int a_ItemType) :
- cItemHandler(a_ItemType)
+
+ cItemBedHandler(int a_ItemType):
+ Super(a_ItemType)
{
}
+
+
+
virtual bool IsPlaceable(void) override
{
return true;
}
+
+
+
virtual bool GetBlocksToPlace(
- cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
- int a_CursorX, int a_CursorY, int a_CursorZ,
+ cWorld & a_World,
+ cPlayer & a_Player,
+ const cItem & a_EquippedItem,
+ const Vector3i a_PlacedBlockPos,
+ eBlockFace a_ClickedBlockFace,
+ const Vector3i a_CursorPos,
sSetBlockVector & a_BlocksToPlace
) override
{
// Can only be placed on the floor:
- if (a_BlockFace != BLOCK_FACE_TOP)
+ if (a_ClickedBlockFace != BLOCK_FACE_TOP)
{
return false;
}
// The "foot" block:
NIBBLETYPE BlockMeta = cBlockBedHandler::YawToMetaData(a_Player.GetYaw());
- a_BlocksToPlace.emplace_back(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_BED, BlockMeta);
+ a_BlocksToPlace.emplace_back(a_PlacedBlockPos, E_BLOCK_BED, BlockMeta);
// Check if there is empty space for the "head" block:
// (Vanilla only allows beds to be placed into air)
- Vector3i Direction = cBlockBedHandler::MetaDataToDirection(BlockMeta);
- if (a_World.GetBlock(a_BlockX + Direction.x, a_BlockY, a_BlockZ + Direction.z) != E_BLOCK_AIR)
+ auto Direction = cBlockBedHandler::MetaDataToDirection(BlockMeta);
+ auto HeadPos = a_PlacedBlockPos + Direction;
+ if (a_World.GetBlock(HeadPos) != E_BLOCK_AIR)
{
return false;
}
- a_BlocksToPlace.emplace_back(a_BlockX + Direction.x, a_BlockY, a_BlockZ + Direction.z, E_BLOCK_BED, BlockMeta | 0x08);
+ a_BlocksToPlace.emplace_back(HeadPos, E_BLOCK_BED, BlockMeta | 0x08);
return true;
}
-} ;
-
-
-
-
+};
diff --git a/src/Items/ItemBigFlower.h b/src/Items/ItemBigFlower.h
index 81a9d3818..a126a72bc 100644
--- a/src/Items/ItemBigFlower.h
+++ b/src/Items/ItemBigFlower.h
@@ -15,43 +15,50 @@ class cItemBigFlowerHandler:
public:
- cItemBigFlowerHandler(void):
+ cItemBigFlowerHandler():
Super(E_BLOCK_BIG_FLOWER)
{
}
+
+
+
virtual bool GetBlocksToPlace(
- cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
- int a_CursorX, int a_CursorY, int a_CursorZ,
- sSetBlockVector & a_BlocksToSet
+ cWorld & a_World,
+ cPlayer & a_Player,
+ const cItem & a_EquippedItem,
+ const Vector3i a_PlacedBlockPos,
+ eBlockFace a_ClickedBlockFace,
+ const Vector3i a_CursorPos,
+ sSetBlockVector & a_BlocksToPlace
) override
{
// Can only be placed on dirt:
- if ((a_BlockY <= 0) || !IsBlockTypeOfDirt(a_World.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ)))
+ if ((a_PlacedBlockPos.y <= 0) || !IsBlockTypeOfDirt(a_World.GetBlock(a_PlacedBlockPos.addedY(-1))))
{
return false;
}
// Needs at least two free blocks to build in
- if (a_BlockY >= cChunkDef::Height - 1)
+ if (a_PlacedBlockPos.y >= cChunkDef::Height - 1)
{
return false;
}
+ auto TopPos = a_PlacedBlockPos.addedY(1);
BLOCKTYPE TopType;
NIBBLETYPE TopMeta;
- a_World.GetBlockTypeMeta(a_BlockX, a_BlockY + 1, a_BlockZ, TopType, TopMeta);
+ a_World.GetBlockTypeMeta(TopPos, TopType, TopMeta);
cChunkInterface ChunkInterface(a_World.GetChunkMap());
- if (!BlockHandler(TopType)->DoesIgnoreBuildCollision(ChunkInterface, { a_BlockX, a_BlockY + 1, a_BlockZ }, a_Player, TopMeta))
+ if (!BlockHandler(TopType)->DoesIgnoreBuildCollision(ChunkInterface, TopPos, a_Player, TopMeta))
{
return false;
}
- a_BlocksToSet.emplace_back(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_BIG_FLOWER, a_EquippedItem.m_ItemDamage & 0x07);
- a_BlocksToSet.emplace_back(a_BlockX, a_BlockY + 1, a_BlockZ, E_BLOCK_BIG_FLOWER, E_META_BIG_FLOWER_TOP);
+ a_BlocksToPlace.emplace_back(a_PlacedBlockPos, E_BLOCK_BIG_FLOWER, a_EquippedItem.m_ItemDamage & 0x07);
+ a_BlocksToPlace.emplace_back(TopPos, E_BLOCK_BIG_FLOWER, E_META_BIG_FLOWER_TOP);
return true;
}
};
diff --git a/src/Items/ItemBoat.h b/src/Items/ItemBoat.h
index 682b68ff2..b6af554c5 100644
--- a/src/Items/ItemBoat.h
+++ b/src/Items/ItemBoat.h
@@ -22,24 +22,32 @@ public:
+
+
virtual bool OnItemUse(
- cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
+ cWorld * a_World,
+ cPlayer * a_Player,
+ cBlockPluginInterface & a_PluginInterface,
+ const cItem & a_HeldItem,
+ const Vector3i a_ClickedBlockPos,
+ eBlockFace a_ClickedBlockFace
) override
{
- if ((a_BlockFace != BLOCK_FACE_YM) && (a_BlockFace != BLOCK_FACE_NONE))
+ // Only allow placing blocks on top of blocks, or when not in range of dest block:
+ if ((a_ClickedBlockFace != BLOCK_FACE_YM) && (a_ClickedBlockFace != BLOCK_FACE_NONE))
{
return false;
}
- class cCallbacks :
+ // Find the actual placement position by tracing line of sight until non-air block:
+ class cCallbacks:
public cBlockTracer::cCallbacks
{
public:
Vector3d m_Pos;
bool m_HasFound;
- cCallbacks(void) :
+ cCallbacks():
m_HasFound(false)
{
}
@@ -55,27 +63,21 @@ public:
return false;
}
} Callbacks;
-
- cLineBlockTracer Tracer(*a_World, Callbacks);
- Vector3d Start(a_Player->GetEyePosition() + a_Player->GetLookVector());
- Vector3d End(a_Player->GetEyePosition() + a_Player->GetLookVector() * 5);
-
- Tracer.Trace(Start.x, Start.y, Start.z, End.x, End.y, End.z);
-
+ auto Start = a_Player->GetEyePosition() + a_Player->GetLookVector();
+ auto End = a_Player->GetEyePosition() + a_Player->GetLookVector() * 5;
+ cLineBlockTracer::Trace(*a_World, Callbacks, Start, End);
if (!Callbacks.m_HasFound)
{
return false;
}
- auto x = Callbacks.m_Pos.x;
- auto y = Callbacks.m_Pos.y;
- auto z = Callbacks.m_Pos.z;
- auto bx = FloorC(x);
- auto by = FloorC(y);
- auto bz = FloorC(z);
-
// Block above must be air to spawn a boat (prevents spawning a boat underwater)
- BLOCKTYPE BlockAbove = a_World->GetBlock(bx, by + 1, bz);
+ auto PosAbove = Callbacks.m_Pos.Floor().addedY(1);
+ if (!cChunkDef::IsValidHeight(PosAbove.y))
+ {
+ return false;
+ }
+ BLOCKTYPE BlockAbove = a_World->GetBlock(PosAbove);
if (BlockAbove != E_BLOCK_AIR)
{
return false;
diff --git a/src/Items/ItemBottle.h b/src/Items/ItemBottle.h
index 319bc708f..2f4d8f93f 100644
--- a/src/Items/ItemBottle.h
+++ b/src/Items/ItemBottle.h
@@ -9,19 +9,28 @@
-class cItemBottleHandler :
+class cItemBottleHandler:
public cItemHandler
{
+ using Super = cItemHandler;
+
public:
- cItemBottleHandler() :
- cItemHandler(E_ITEM_GLASS_BOTTLE)
+
+ cItemBottleHandler():
+ Super(E_ITEM_GLASS_BOTTLE)
{
}
+
+
+
+ /** Searches for a water source block in the line of sight.
+ Returns true and sets a_BlockPos if a water source block is found within line-of-sight.
+ Returns false if not. */
bool GetBlockFromTrace(cWorld * a_World, cPlayer * a_Player, Vector3i & a_BlockPos)
{
- class cCallbacks :
+ class cCallbacks:
public cBlockTracer::cCallbacks
{
public:
@@ -29,7 +38,7 @@ public:
bool m_HasHitFluid;
- cCallbacks(void) :
+ cCallbacks():
m_HasHitFluid(false)
{
}
@@ -49,31 +58,32 @@ public:
return false;
}
} Callbacks;
-
- cLineBlockTracer Tracer(*a_World, Callbacks);
- Vector3d Start(a_Player->GetEyePosition() + a_Player->GetLookVector());
- Vector3d End(a_Player->GetEyePosition() + a_Player->GetLookVector() * 5);
-
- Tracer.Trace(Start.x, Start.y, Start.z, End.x, End.y, End.z);
-
+ auto Start = a_Player->GetEyePosition() + a_Player->GetLookVector();
+ auto End = a_Player->GetEyePosition() + a_Player->GetLookVector() * 5;
+ cLineBlockTracer::Trace(*a_World, Callbacks, Start, End);
if (!Callbacks.m_HasHitFluid)
{
return false;
}
-
a_BlockPos = Callbacks.m_Pos;
return true;
}
+
+
virtual bool OnItemUse(
- cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
- ) override
+ cWorld * a_World,
+ cPlayer * a_Player,
+ cBlockPluginInterface & a_PluginInterface,
+ const cItem & a_HeldItem,
+ const Vector3i a_ClickedBlockPos,
+ eBlockFace a_ClickedBlockFace
+ ) override
{
- if (a_BlockFace != BLOCK_FACE_NONE)
+ if (a_ClickedBlockFace != BLOCK_FACE_NONE)
{
return false;
}
diff --git a/src/Items/ItemBow.h b/src/Items/ItemBow.h
index 81f012c7c..b7a9ef638 100644
--- a/src/Items/ItemBow.h
+++ b/src/Items/ItemBow.h
@@ -22,9 +22,15 @@ public:
+
+
virtual bool OnItemUse(
- cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
+ cWorld * a_World,
+ cPlayer * a_Player,
+ cBlockPluginInterface & a_PluginInterface,
+ const cItem & a_HeldItem,
+ const Vector3i a_ClickedBlockPos,
+ eBlockFace a_ClickedBlockFace
) override
{
ASSERT(a_Player != nullptr);
@@ -41,9 +47,10 @@ public:
- virtual void OnItemShoot(cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override
+ virtual void OnItemShoot(cPlayer * a_Player, const Vector3i a_BlockPos, eBlockFace a_BlockFace) override
{
- // Actual shot - produce the arrow with speed based on the ticks that the bow was charged
+ // Actual shot - produce the arrow with speed based on the number of ticks that the bow was charged
+ UNUSED(a_BlockPos);
ASSERT(a_Player != nullptr);
int BowCharge = a_Player->FinishChargingBow();
@@ -88,7 +95,6 @@ public:
a_Player->UseEquippedItem();
}
-
if (a_Player->GetEquippedItem().m_Enchantments.GetLevel(cEnchantments::enchFlame) > 0)
{
ArrowPtr->StartBurning(100);
diff --git a/src/Items/ItemBrewingStand.h b/src/Items/ItemBrewingStand.h
index 7be57763c..fdf53ff8f 100644
--- a/src/Items/ItemBrewingStand.h
+++ b/src/Items/ItemBrewingStand.h
@@ -7,12 +7,15 @@
-class cItemBrewingStandHandler :
+class cItemBrewingStandHandler:
public cItemHandler
{
+ using Super = cItemHandler;
+
public:
- cItemBrewingStandHandler(int a_ItemType) :
- cItemHandler(a_ItemType)
+
+ cItemBrewingStandHandler(int a_ItemType):
+ Super(a_ItemType)
{
}
@@ -25,8 +28,9 @@ public:
virtual bool GetPlacementBlockTypeMeta(
cWorld * a_World, cPlayer * a_Player,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
- int a_CursorX, int a_CursorY, int a_CursorZ,
+ const Vector3i a_PlacedBlockPos,
+ eBlockFace a_ClickedBlockFace,
+ const Vector3i a_CursorPos,
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) override
{
diff --git a/src/Items/ItemBucket.h b/src/Items/ItemBucket.h
index 7b837d449..d2a9b1884 100644
--- a/src/Items/ItemBucket.h
+++ b/src/Items/ItemBucket.h
@@ -16,25 +16,34 @@
class cItemBucketHandler :
public cItemHandler
{
+ using Super = cItemHandler;
+
public:
- cItemBucketHandler(int a_ItemType) :
- cItemHandler(a_ItemType)
+
+ cItemBucketHandler(int a_ItemType):
+ Super(a_ItemType)
{
}
+
+
virtual bool OnItemUse(
- cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
+ cWorld * a_World,
+ cPlayer * a_Player,
+ cBlockPluginInterface & a_PluginInterface,
+ const cItem & a_HeldItem,
+ const Vector3i a_ClickedBlockPos,
+ eBlockFace a_ClickedBlockFace
) override
{
switch (m_ItemType)
{
- case E_ITEM_BUCKET: return ScoopUpFluid(a_World, a_Player, a_Item, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
- case E_ITEM_LAVA_BUCKET: return PlaceFluid (a_World, a_Player, a_PluginInterface, a_Item, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, E_BLOCK_LAVA);
- case E_ITEM_WATER_BUCKET: return PlaceFluid (a_World, a_Player, a_PluginInterface, a_Item, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, E_BLOCK_WATER);
+ case E_ITEM_BUCKET: return ScoopUpFluid(a_World, a_Player, a_HeldItem, a_ClickedBlockPos, a_ClickedBlockFace);
+ case E_ITEM_LAVA_BUCKET: return PlaceFluid (a_World, a_Player, a_PluginInterface, a_HeldItem, a_ClickedBlockPos, a_ClickedBlockFace, E_BLOCK_LAVA);
+ case E_ITEM_WATER_BUCKET: return PlaceFluid (a_World, a_Player, a_PluginInterface, a_HeldItem, a_ClickedBlockPos, a_ClickedBlockFace, E_BLOCK_WATER);
default:
{
ASSERT(!"Unhandled ItemType");
@@ -45,7 +54,9 @@ public:
- bool ScoopUpFluid(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace)
+
+
+ bool ScoopUpFluid(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, const Vector3i a_ClickedBlockPos, eBlockFace a_ClickedBlockFace)
{
// Players can't pick up fluid while in adventure mode.
if (a_Player->IsGameModeAdventure())
@@ -53,7 +64,8 @@ public:
return false;
}
- if (a_BlockFace != BLOCK_FACE_NONE)
+ // Needs a valid clicked block:
+ if (a_ClickedBlockFace != BLOCK_FACE_NONE)
{
return false;
}
@@ -114,7 +126,7 @@ public:
bool PlaceFluid(
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, BLOCKTYPE a_FluidBlock
+ const Vector3i a_BlockPos, eBlockFace a_BlockFace, BLOCKTYPE a_FluidBlock
)
{
// Players can't place fluid while in adventure mode.
@@ -219,6 +231,8 @@ public:
+
+
bool GetPlacementCoordsFromTrace(cWorld * a_World, cPlayer * a_Player, Vector3i & a_BlockPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta, eBlockFace & a_BlockFace)
{
class cCallbacks :
diff --git a/src/Items/ItemCake.h b/src/Items/ItemCake.h
index d1cb091b6..5751853f6 100644
--- a/src/Items/ItemCake.h
+++ b/src/Items/ItemCake.h
@@ -7,12 +7,15 @@
-class cItemCakeHandler :
+class cItemCakeHandler:
public cItemHandler
{
+ using Super = cItemHandler;
+
public:
- cItemCakeHandler(int a_ItemType) :
- cItemHandler(a_ItemType)
+
+ cItemCakeHandler(int a_ItemType):
+ Super(a_ItemType)
{
}
@@ -25,8 +28,9 @@ public:
virtual bool GetPlacementBlockTypeMeta(
cWorld * a_World, cPlayer * a_Player,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
- int a_CursorX, int a_CursorY, int a_CursorZ,
+ const Vector3i a_PlacedBlockPos,
+ eBlockFace a_ClickedBlockFace,
+ const Vector3i a_CursorPos,
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) override
{
diff --git a/src/Items/ItemCauldron.h b/src/Items/ItemCauldron.h
index 9617c30ef..7f2ccdeac 100644
--- a/src/Items/ItemCauldron.h
+++ b/src/Items/ItemCauldron.h
@@ -7,12 +7,15 @@
-class cItemCauldronHandler :
+class cItemCauldronHandler:
public cItemHandler
{
+ using Super = cItemHandler;
+
public:
- cItemCauldronHandler(int a_ItemType) :
- cItemHandler(a_ItemType)
+
+ cItemCauldronHandler(int a_ItemType):
+ Super(a_ItemType)
{
}
@@ -25,8 +28,9 @@ public:
virtual bool GetPlacementBlockTypeMeta(
cWorld * a_World, cPlayer * a_Player,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
- int a_CursorX, int a_CursorY, int a_CursorZ,
+ const Vector3i a_PlacedBlockPos,
+ eBlockFace a_ClickedBlockFace,
+ const Vector3i a_CursorPos,
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) override
{
diff --git a/src/Items/ItemChest.h b/src/Items/ItemChest.h
index b8807e5d8..014ccc3e6 100644
--- a/src/Items/ItemChest.h
+++ b/src/Items/ItemChest.h
@@ -25,56 +25,57 @@ public:
/** We need an OnPlayerPlace override because we're processing neighbor chests and changing their metas,
the parent class cannot do that. */
virtual bool OnPlayerPlace(
- cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
- int a_CursorX, int a_CursorY, int a_CursorZ
+ cWorld & a_World,
+ cPlayer & a_Player,
+ const cItem & a_EquippedItem,
+ const Vector3i a_ClickedBlockPos,
+ eBlockFace a_ClickedBlockFace,
+ const Vector3i a_CursorPos
) override
{
- if (a_BlockFace < 0)
+ if (a_ClickedBlockFace < 0)
{
// Clicked in air
return false;
}
- if ((a_BlockY < 0) || (a_BlockY >= cChunkDef::Height))
+ if (!cChunkDef::IsValidHeight(a_ClickedBlockPos.y))
{
// The clicked block is outside the world, ignore this call altogether (#128)
return false;
}
// Check if the block ignores build collision (water, grass etc.):
- BLOCKTYPE clickedBlock;
- NIBBLETYPE clickedBlockMeta;
- Vector3i blockPos(a_BlockX, a_BlockY, a_BlockZ);
- a_World.GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, clickedBlock, clickedBlockMeta);
+ BLOCKTYPE ClickedBlockType;
+ NIBBLETYPE ClickedBlockMeta;
+ a_World.GetBlockTypeMeta(a_ClickedBlockPos, ClickedBlockType, ClickedBlockMeta);
cChunkInterface ChunkInterface(a_World.GetChunkMap());
- auto blockHandler = BlockHandler(clickedBlock);
- if (blockHandler->DoesIgnoreBuildCollision(ChunkInterface, blockPos, a_Player, clickedBlockMeta))
+ auto blockHandler = BlockHandler(ClickedBlockType);
+ Vector3i PlacePos;
+ if (blockHandler->DoesIgnoreBuildCollision(ChunkInterface, a_ClickedBlockPos, a_Player, ClickedBlockMeta))
{
- blockHandler->OnPlayerBreakingBlock(ChunkInterface, a_World, a_Player, blockPos);
+ blockHandler->OnPlayerBreakingBlock(ChunkInterface, a_World, a_Player, a_ClickedBlockPos);
+ PlacePos = a_ClickedBlockPos;
}
else
{
- AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
-
- if ((a_BlockY < 0) || (a_BlockY >= cChunkDef::Height))
+ PlacePos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace);
+ if (!cChunkDef::IsValidHeight(PlacePos.y))
{
// The block is being placed outside the world, ignore this packet altogether (#128)
return false;
}
- NIBBLETYPE PlaceMeta;
+ // Check if the chest can overwrite the block at PlacePos:
BLOCKTYPE PlaceBlock;
- a_World.GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, PlaceBlock, PlaceMeta);
-
- // Clicked on side of block, make sure that placement won't be cancelled if there is a slab able to be double slabbed.
- // No need to do combinability (dblslab) checks, client will do that here.
- if (blockHandler->DoesIgnoreBuildCollision(ChunkInterface, blockPos, a_Player, clickedBlockMeta))
+ NIBBLETYPE PlaceMeta;
+ a_World.GetBlockTypeMeta(PlacePos, PlaceBlock, PlaceMeta);
+ blockHandler = BlockHandler(PlaceBlock);
+ if (!blockHandler->DoesIgnoreBuildCollision(ChunkInterface, PlacePos, a_Player, PlaceMeta))
{
- // Tried to place a block into another?
- // Happens when you place a block aiming at side of block with a torch on it or stem beside it
return false;
}
+ blockHandler->OnPlayerBreakingBlock(ChunkInterface, a_World, a_Player, PlacePos);
}
// Check that there is at most one single neighbor of the same chest type:
@@ -88,7 +89,8 @@ public:
int NeighborIdx = -1;
for (size_t i = 0; i < ARRAYCOUNT(CrossCoords); i++)
{
- if (a_World.GetBlock(a_BlockX + CrossCoords[i].x, a_BlockY, a_BlockZ + CrossCoords[i].z) != m_ItemType)
+ auto NeighborPos = PlacePos + CrossCoords[i];
+ if (a_World.GetBlock(NeighborPos) != m_ItemType)
{
continue;
}
@@ -100,12 +102,11 @@ public:
NeighborIdx = static_cast<int>(i);
// Check that this neighbor is a single chest:
- int bx = a_BlockX + CrossCoords[i].x;
- int bz = a_BlockZ + CrossCoords[i].z;
for (size_t j = 0; j < ARRAYCOUNT(CrossCoords); j++)
{
- if (a_World.GetBlock(bx + CrossCoords[j].x, a_BlockY, bz + CrossCoords[j].z) == m_ItemType)
+ if (a_World.GetBlock(NeighborPos + CrossCoords[j]) == m_ItemType)
{
+ // Trying to place next to a dblchest
return false;
}
} // for j
@@ -133,13 +134,14 @@ public:
}
default:
{
+ // No neighbor, place based on yaw:
Meta = cBlockChestHandler::PlayerYawToMetaData(yaw);
break;
}
} // switch (NeighborIdx)
// Place the new chest:
- if (!a_Player.PlaceBlock(a_BlockX, a_BlockY, a_BlockZ, ChestBlockType, Meta))
+ if (!a_Player.PlaceBlock(PlacePos.x, PlacePos.y, PlacePos.z, ChestBlockType, Meta))
{
return false;
}
@@ -147,10 +149,10 @@ public:
// Adjust the existing chest, if any:
if (NeighborIdx != -1)
{
- a_World.FastSetBlock(a_BlockX + CrossCoords[NeighborIdx].x, a_BlockY, a_BlockZ + CrossCoords[NeighborIdx].z, ChestBlockType, Meta);
+ a_World.FastSetBlock(PlacePos + CrossCoords[NeighborIdx], ChestBlockType, Meta);
}
- // Remove the "placed" item:
+ // Remove the "placed" item from inventory:
if (a_Player.IsGameModeSurvival())
{
a_Player.GetInventory().RemoveOneEquippedItem();
diff --git a/src/Items/ItemComparator.h b/src/Items/ItemComparator.h
index 6f32e229d..fbb61b317 100644
--- a/src/Items/ItemComparator.h
+++ b/src/Items/ItemComparator.h
@@ -8,24 +8,36 @@
-class cItemComparatorHandler :
+class cItemComparatorHandler:
public cItemHandler
{
+ using Super = cItemHandler;
+
public:
- cItemComparatorHandler(int a_ItemType) :
+
+ cItemComparatorHandler(int a_ItemType):
cItemHandler(a_ItemType)
{
}
+
+
+
+
virtual bool IsPlaceable(void) override
{
return true;
}
+
+
+
+
virtual bool GetPlacementBlockTypeMeta(
cWorld * a_World, cPlayer * a_Player,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
- int a_CursorX, int a_CursorY, int a_CursorZ,
+ const Vector3i a_PlacedBlockPos,
+ eBlockFace a_ClickedBlockFace,
+ const Vector3i a_CursorPos,
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) override
{
diff --git a/src/Items/ItemDoor.h b/src/Items/ItemDoor.h
index 790e08ffc..aec6bc0fe 100644
--- a/src/Items/ItemDoor.h
+++ b/src/Items/ItemDoor.h
@@ -9,38 +9,45 @@
-class cItemDoorHandler :
+class cItemDoorHandler:
public cItemHandler
{
+ using Super = cItemHandler;
+
public:
- cItemDoorHandler(int a_ItemType) :
- cItemHandler(a_ItemType)
+
+ cItemDoorHandler(int a_ItemType):
+ Super(a_ItemType)
{
}
+
+
virtual bool GetBlocksToPlace(
cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
- int a_CursorX, int a_CursorY, int a_CursorZ,
+ const Vector3i a_PlacedBlockPos,
+ eBlockFace a_ClickedBlockFace,
+ const Vector3i a_CursorPos,
sSetBlockVector & a_BlocksToSet
) override
{
// Vanilla only allows door placement while clicking on the top face of the block below the door:
- if (a_BlockFace != BLOCK_FACE_TOP)
+ if (a_ClickedBlockFace != BLOCK_FACE_TOP)
{
return false;
}
// Door (bottom block) can be placed in Y range of [1, 254]:
- if ((a_BlockY < 1) || (a_BlockY >= cChunkDef::Height - 2))
+ if ((a_PlacedBlockPos.y < 1) || (a_PlacedBlockPos.y >= cChunkDef::Height - 2))
{
return false;
}
// The door needs a compatible block below it:
- if (!cBlockDoorHandler::CanBeOn(a_World.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ), a_World.GetBlockMeta(a_BlockX, a_BlockY - 1, a_BlockZ)))
+ auto BelowPos = a_PlacedBlockPos.addedY(-1);
+ if (!cBlockDoorHandler::CanBeOn(a_World.GetBlock(BelowPos), a_World.GetBlockMeta(BelowPos)))
{
return false;
}
@@ -64,8 +71,9 @@ public:
}
// Check the two blocks that will get replaced by the door:
- BLOCKTYPE LowerBlockType = a_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ);
- BLOCKTYPE UpperBlockType = a_World.GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ);
+ auto UpperBlockPos = a_PlacedBlockPos.addedY(1);
+ BLOCKTYPE LowerBlockType = a_World.GetBlock(a_PlacedBlockPos);
+ BLOCKTYPE UpperBlockType = a_World.GetBlock(UpperBlockPos);
if (
!cBlockDoorHandler::CanReplaceBlock(LowerBlockType) ||
!cBlockDoorHandler::CanReplaceBlock(UpperBlockType))
@@ -78,10 +86,10 @@ public:
Vector3i RelDirToOutside = cBlockDoorHandler::GetRelativeDirectionToOutside(LowerBlockMeta);
Vector3i LeftNeighborPos = RelDirToOutside;
LeftNeighborPos.TurnCW();
- LeftNeighborPos.Move(a_BlockX, a_BlockY, a_BlockZ);
+ LeftNeighborPos.Move(a_PlacedBlockPos);
Vector3i RightNeighborPos = RelDirToOutside;
RightNeighborPos.TurnCCW();
- RightNeighborPos.Move(a_BlockX, a_BlockY, a_BlockZ);
+ RightNeighborPos.Move(a_PlacedBlockPos);
// Decide whether the hinge is on the left (default) or on the right:
NIBBLETYPE UpperBlockMeta = 0x08;
@@ -89,7 +97,7 @@ public:
BLOCKTYPE RightNeighborBlock = a_World.GetBlock(RightNeighborPos);
/*
// DEBUG:
- FLOGD("Door being placed at {0}", Vector3i{a_BlockX, a_BlockY, a_BlockZ});
+ FLOGD("Door being placed at {0}", a_PlacedBlockPos);
FLOGD("RelDirToOutside: {0}", RelDirToOutside);
FLOGD("Left neighbor at {0}: {1} ({2})", LeftNeighborPos, LeftNeighborBlock, ItemTypeToString(LeftNeighborBlock));
FLOGD("Right neighbor at {0}: {1} ({2})", RightNeighborPos, RightNeighborBlock, ItemTypeToString(RightNeighborBlock));
@@ -108,12 +116,14 @@ public:
}
// Set the blocks:
- a_BlocksToSet.emplace_back(a_BlockX, a_BlockY, a_BlockZ, BlockType, LowerBlockMeta);
- a_BlocksToSet.emplace_back(a_BlockX, a_BlockY + 1, a_BlockZ, BlockType, UpperBlockMeta);
+ a_BlocksToSet.emplace_back(a_PlacedBlockPos, BlockType, LowerBlockMeta);
+ a_BlocksToSet.emplace_back(UpperBlockPos, BlockType, UpperBlockMeta);
return true;
}
+
+
virtual bool IsPlaceable(void) override
{
return true;
diff --git a/src/Items/ItemDye.h b/src/Items/ItemDye.h
index 890fcc9db..5e3088541 100644
--- a/src/Items/ItemDye.h
+++ b/src/Items/ItemDye.h
@@ -26,14 +26,18 @@ public:
virtual bool OnItemUse(
- cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
+ cWorld * a_World,
+ cPlayer * a_Player,
+ cBlockPluginInterface & a_PluginInterface,
+ const cItem & a_HeldItem,
+ const Vector3i a_ClickedBlockPos,
+ eBlockFace a_ClickedBlockFace
) override
{
- if ((a_Item.m_ItemDamage == E_META_DYE_WHITE) && (a_BlockFace != BLOCK_FACE_NONE))
+ if ((a_HeldItem.m_ItemDamage == E_META_DYE_WHITE) && (a_ClickedBlockFace != BLOCK_FACE_NONE))
{
// Bonemeal (white dye) is used to fertilize plants:
- if (fertilizePlant(*a_World, {a_BlockX, a_BlockY, a_BlockZ}))
+ if (FertilizePlant(*a_World, a_ClickedBlockPos))
{
if (a_Player->IsGameModeSurvival())
{
@@ -42,7 +46,7 @@ public:
}
}
}
- else if ((a_Item.m_ItemDamage == E_META_DYE_BROWN) && (a_BlockFace >= BLOCK_FACE_ZM) && (a_BlockFace <= BLOCK_FACE_XP))
+ else if ((a_HeldItem.m_ItemDamage == E_META_DYE_BROWN) && (a_ClickedBlockFace >= BLOCK_FACE_ZM) && (a_ClickedBlockFace <= BLOCK_FACE_XP))
{
// Players can't place blocks while in adventure mode.
if (a_Player->IsGameModeAdventure())
@@ -53,25 +57,24 @@ public:
// Cocoa (brown dye) can be planted on jungle logs:
BLOCKTYPE BlockType;
NIBBLETYPE BlockMeta;
- a_World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta);
+ a_World->GetBlockTypeMeta(a_ClickedBlockPos, BlockType, BlockMeta);
// Check if the block that the player clicked is a jungle log.
- if ((BlockType != E_BLOCK_LOG) || ((BlockMeta & 0x3) != E_META_LOG_JUNGLE))
+ if ((BlockType != E_BLOCK_LOG) || ((BlockMeta & 0x03) != E_META_LOG_JUNGLE))
{
return false;
}
// Get the location from the new cocoa pod.
- AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, false);
- BlockMeta = cBlockCocoaPodHandler::BlockFaceToMeta(a_BlockFace);
+ auto CocoaPos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace, false);
+ BlockMeta = cBlockCocoaPodHandler::BlockFaceToMeta(a_ClickedBlockFace);
- if (a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) != E_BLOCK_AIR)
+ // Place the cocoa pod:
+ if (a_World->GetBlock(CocoaPos) != E_BLOCK_AIR)
{
return false;
}
-
- // Place the cocoa pod:
- if (a_Player->PlaceBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_COCOA_POD, BlockMeta))
+ if (a_Player->PlaceBlock(CocoaPos.x, CocoaPos.y, CocoaPos.z, E_BLOCK_COCOA_POD, BlockMeta))
{
if (a_Player->IsGameModeSurvival())
{
@@ -97,7 +100,7 @@ public:
Returns true if the plant was fertilized successfully, false if not / not a plant.
Note that successful fertilization doesn't mean successful growth - for blocks that have only a chance to grow,
fertilization success is reported even in the case when the chance fails (bonemeal still needs to be consumed). */
- bool fertilizePlant(cWorld & a_World, Vector3i a_BlockPos)
+ bool FertilizePlant(cWorld & a_World, Vector3i a_BlockPos)
{
BLOCKTYPE blockType;
NIBBLETYPE blockMeta;
diff --git a/src/Items/ItemEmptyMap.h b/src/Items/ItemEmptyMap.h
index fe7b03e23..ac5053107 100644
--- a/src/Items/ItemEmptyMap.h
+++ b/src/Items/ItemEmptyMap.h
@@ -23,15 +23,19 @@ public:
+
+
virtual bool OnItemUse(
- cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
+ cWorld * a_World,
+ cPlayer * a_Player,
+ cBlockPluginInterface & a_PluginInterface,
+ const cItem & a_HeldItem,
+ const Vector3i a_ClickedBlockPos,
+ eBlockFace a_ClickedBlockFace
) override
{
- UNUSED(a_Item);
- UNUSED(a_BlockX);
- UNUSED(a_BlockZ);
- UNUSED(a_BlockFace);
+ UNUSED(a_HeldItem);
+ UNUSED(a_ClickedBlockFace);
// The map center is fixed at the central point of the 8x8 block of chunks you are standing in when you right-click it.
@@ -40,22 +44,14 @@ public:
int CenterX = FloorC(a_Player->GetPosX() / RegionWidth) * RegionWidth + (RegionWidth / 2);
int CenterZ = FloorC(a_Player->GetPosZ() / RegionWidth) * RegionWidth + (RegionWidth / 2);
- cMap * NewMap = a_World->GetMapManager().CreateMap(CenterX, CenterZ, DEFAULT_SCALE);
-
- // Remove empty map from inventory
- if (!a_Player->GetInventory().RemoveOneEquippedItem())
- {
- ASSERT(!"Inventory mismatch");
- return true;
- }
-
+ auto NewMap = a_World->GetMapManager().CreateMap(CenterX, CenterZ, DEFAULT_SCALE);
if (NewMap == nullptr)
{
return true;
}
- a_Player->GetInventory().AddItem(cItem(E_ITEM_MAP, 1, static_cast<short>(NewMap->GetID() & 0x7fff)));
-
+ // Replace map in the inventory:
+ a_Player->ReplaceOneEquippedItemTossRest(cItem(E_ITEM_MAP, 1, static_cast<short>(NewMap->GetID() & 0x7fff)));
return true;
}
} ;
diff --git a/src/Items/ItemEyeOfEnder.h b/src/Items/ItemEyeOfEnder.h
index f911955a1..3849feb00 100644
--- a/src/Items/ItemEyeOfEnder.h
+++ b/src/Items/ItemEyeOfEnder.h
@@ -8,46 +8,53 @@
-class cItemEyeOfEnderHandler :
+class cItemEyeOfEnderHandler:
public cItemThrowableHandler
{
- typedef cItemThrowableHandler super;
+ using Super = cItemThrowableHandler;
+
public:
- cItemEyeOfEnderHandler(void) :
- super(E_ITEM_EYE_OF_ENDER, cProjectileEntity::pkSnowball, 30)
+
+ cItemEyeOfEnderHandler():
+ Super(E_ITEM_EYE_OF_ENDER, cProjectileEntity::pkSnowball, 30)
{
}
+
+
+
+
virtual bool OnItemUse(
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
+ const Vector3i a_ClickedBlockPos,
+ eBlockFace a_ClickedBlockFace
) override
{
- BLOCKTYPE FacingBlock;
- NIBBLETYPE FacingMeta;
- a_World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, FacingBlock, FacingMeta);
- switch (FacingBlock)
+ // Try to fill an End Portal Frame block:
+ if (a_ClickedBlockFace != BLOCK_FACE_NONE)
{
- case E_BLOCK_END_PORTAL_FRAME:
+ BLOCKTYPE FacingBlock;
+ NIBBLETYPE FacingMeta;
+ a_World->GetBlockTypeMeta(a_ClickedBlockPos, FacingBlock, FacingMeta);
+ if (FacingBlock == E_BLOCK_END_PORTAL_FRAME)
{
// Fill the portal frame. E_META_END_PORTAL_EYE is the bit for holding the eye of ender.
if ((FacingMeta & E_META_END_PORTAL_FRAME_EYE) != E_META_END_PORTAL_FRAME_EYE)
{
- a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_END_PORTAL_FRAME, FacingMeta | E_META_END_PORTAL_FRAME_EYE);
+ a_World->SetBlock(a_ClickedBlockPos, E_BLOCK_END_PORTAL_FRAME, FacingMeta | E_META_END_PORTAL_FRAME_EYE);
if (!a_Player->IsGameModeCreative())
{
a_Player->GetInventory().RemoveOneEquippedItem();
}
+ return true;
}
- break;
- }
- default:
- {
- // TODO: Create projectile for Eye Of Ender
- // return cItemThrowableHandler::OnItemUse(a_World, a_Player, a_PluginInterface, a_Item, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
}
+ return false;
}
+ // TODO: Create projectile for Eye Of Ender
+ // return Super::OnItemUse(a_World, a_Player, a_PluginInterface, a_Item, a_ClickedBlockPos, a_ClickedBlockFace);
+
return false;
}
diff --git a/src/Items/ItemFishingRod.h b/src/Items/ItemFishingRod.h
index 48568ed69..8817c8c38 100644
--- a/src/Items/ItemFishingRod.h
+++ b/src/Items/ItemFishingRod.h
@@ -63,197 +63,245 @@ public:
+
+
virtual bool OnItemUse(
- cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
+ cWorld * a_World,
+ cPlayer * a_Player,
+ cBlockPluginInterface & a_PluginInterface,
+ const cItem & a_HeldItem,
+ const Vector3i a_ClickedBlockPos,
+ eBlockFace a_ClickedBlockFace
) override
{
- if (a_BlockFace != BLOCK_FACE_NONE)
+ if (a_ClickedBlockFace != BLOCK_FACE_NONE)
{
return false;
}
- auto & Random = GetRandomProvider();
-
if (a_Player->IsFishing())
{
- cFloaterCallback FloaterInfo;
- a_World->DoWithEntityByID(a_Player->GetFloaterID(), FloaterInfo);
- a_Player->SetIsFishing(false);
-
- if (FloaterInfo.IsAttached())
+ ReelIn(*a_World, *a_Player);
+ }
+ else
+ {
+ // Cast a hook:
+ auto & Random = GetRandomProvider();
+ auto CountDownTime = Random.RandInt(100, 900) - static_cast<int>(a_Player->GetEquippedItem().m_Enchantments.GetLevel(cEnchantments::enchLure) * 100);
+ auto Floater = cpp14::make_unique<cFloater>(
+ a_Player->GetEyePosition(), a_Player->GetLookVector() * 15,
+ a_Player->GetUniqueID(),
+ CountDownTime
+ );
+ auto FloaterPtr = Floater.get();
+ if (!FloaterPtr->Initialize(std::move(Floater), *a_World))
{
- a_World->DoWithEntityByID(FloaterInfo.GetAttachedMobID(), [=](cEntity & a_Entity)
- {
- Vector3d Speed = a_Player->GetPosition() - a_Entity.GetPosition();
- a_Entity.AddSpeed(Speed);
- return true;
- }
- );
- a_Player->UseEquippedItem(5);
+ return false;
}
- else if (FloaterInfo.CanPickup())
+ a_Player->SetIsFishing(true, FloaterPtr->GetUniqueID());
+ }
+ return true;
+ }
+
+
+
+
+
+ /** Reels back the fishing line, reeling any attached mob, or creating fished loot, or just breaking the fishing rod. */
+ void ReelIn(cWorld & a_World, cPlayer & a_Player)
+ {
+ cFloaterCallback FloaterInfo;
+ a_World.DoWithEntityByID(a_Player.GetFloaterID(), FloaterInfo);
+ a_Player.SetIsFishing(false);
+
+ // If attached to an entity, reel it in:
+ if (FloaterInfo.IsAttached())
+ {
+ ReelInEntity(a_World, a_Player, FloaterInfo.GetAttachedMobID());
+ return;
+ }
+
+ // If loot can be caught, get it:
+ if (FloaterInfo.CanPickup())
+ {
+ ReelInLoot(a_World, a_Player, FloaterInfo.GetBitePos());
+ return;
+ }
+
+ // Empty fishing rod, just damage it:
+ auto BlockType = a_World.GetBlock(FloaterInfo.GetPos() - Vector3d(0, 0.1, 0));
+ if ((BlockType != E_BLOCK_AIR) && !IsBlockWater(BlockType))
+ {
+ a_Player.UseEquippedItem(2);
+ }
+ }
+
+
+
+
+ /** Reels back the entity, specified by the ID, and damages the fishing rod accordingly. */
+ void ReelInEntity(cWorld & a_World, cPlayer & a_Player, UInt32 a_EntityID)
+ {
+ auto PlayerPos = a_Player.GetPosition();
+ a_World.DoWithEntityByID(a_EntityID, [=](cEntity & a_Entity)
{
- UInt32 LotSLevel = std::min(a_Player->GetEquippedItem().m_Enchantments.GetLevel(cEnchantments::enchLuckOfTheSea), 3u);
+ auto Speed = PlayerPos - a_Entity.GetPosition();
+ a_Entity.AddSpeed(Speed);
+ return true;
+ }
+ );
+ a_Player.UseEquippedItem(5);
+ }
+
+
+
+
- // Chances for getting an item from the category for each level of Luck of the Sea (0 - 3)
- const int TreasureChances[] = {50, 71, 92, 113}; // 5% | 7.1% | 9.2% | 11.3%
- const int JunkChances[] = {100, 81, 61, 42}; // 10% | 8.1% | 6.1% | 4.2%
+ void ReelInLoot(cWorld & a_World, cPlayer & a_Player, const Vector3d a_FloaterBitePos)
+ {
+ auto LotSLevel = std::min(a_Player.GetEquippedItem().m_Enchantments.GetLevel(cEnchantments::enchLuckOfTheSea), 3u);
+
+ // Chances for getting an item from the category for each level of Luck of the Sea (0 - 3)
+ const int TreasureChances[] = {50, 71, 92, 113}; // 5% | 7.1% | 9.2% | 11.3%
+ const int JunkChances[] = {100, 81, 61, 42}; // 10% | 8.1% | 6.1% | 4.2%
- cItems Drops;
- int ItemCategory = Random.RandInt(999);
- if (ItemCategory < TreasureChances[LotSLevel])
+ cItems Drops;
+ auto & Random = GetRandomProvider();
+ int ItemCategory = Random.RandInt(999);
+ if (ItemCategory < TreasureChances[LotSLevel])
+ {
+ switch (Random.RandInt(5)) // Each piece of treasure has an equal chance of 1 / 6
+ {
+ case 0:
{
- switch (Random.RandInt(5)) // Each piece of treasure has an equal chance of 1 / 6
- {
- case 0:
- {
- cItem Bow(E_ITEM_BOW, 1, Random.RandInt<short>(50));
- Bow.EnchantByXPLevels(Random.RandInt(22, 30));
- Drops.Add(Bow);
- break;
- }
- case 1:
- {
- cItem Book(E_ITEM_BOOK);
- Book.EnchantByXPLevels(30);
- Drops.Add(Book);
- break;
- }
- case 2:
- {
- cItem Rod(E_ITEM_FISHING_ROD, 1, Random.RandInt<short>(50));
- Rod.EnchantByXPLevels(Random.RandInt(22, 30));
- Drops.Add(Rod);
- break;
- }
- case 3:
- {
- Drops.Add(cItem(E_ITEM_NAME_TAG));
- break;
- }
- case 4:
- {
- Drops.Add(cItem(E_ITEM_SADDLE));
- break;
- }
- case 5:
- {
- Drops.Add(cItem(E_BLOCK_LILY_PAD));
- break;
- }
- }
-
- a_Player->GetStatManager().AddValue(statTreasureFished, 1);
+ cItem Bow(E_ITEM_BOW, 1, Random.RandInt<short>(50));
+ Bow.EnchantByXPLevels(Random.RandInt(22, 30));
+ Drops.Add(Bow);
+ break;
}
- else if (ItemCategory < JunkChances[LotSLevel])
+ case 1:
{
- int Junk = Random.RandInt(82);
- if (Junk < 10) // 10 / 83 chance of spawning a bowl
- {
- Drops.Add(cItem(E_ITEM_BOWL));
- }
- else if (Junk < 12) // 2 / 83 chance of spawning a fishing rod
- {
- // Fishing Rods caught from the Junk category will be 10%-100% damaged, and always unenchanted.
- Drops.Add(cItem(E_ITEM_FISHING_ROD, 1, Random.RandInt<short>(7, 65)));
- }
- else if (Junk < 22) // 10 / 83 chance of spawning leather
- {
- Drops.Add(cItem(E_ITEM_LEATHER));
- }
- else if (Junk < 32) // 10 / 83 chance of spawning leather boots
- {
- // Leather boots caught from the Junk category will be 10%-100% damaged, and always unenchanted.
- Drops.Add(cItem(E_ITEM_LEATHER_BOOTS, 1, Random.RandInt<short>(7, 66)));
- }
- else if (Junk < 42) // 10 / 83 chance of spawning rotten flesh
- {
- Drops.Add(cItem(E_ITEM_ROTTEN_FLESH));
- }
- else if (Junk < 47) // 5 / 83 chance of spawning a stick
- {
- Drops.Add(cItem(E_ITEM_STICK));
- }
- else if (Junk < 52) // 5 / 83 chance of spawning string
- {
- Drops.Add(cItem(E_ITEM_STRING));
- }
- else if (Junk < 62) // 10 / 83 chance of spawning a water bottle
- {
- Drops.Add(cItem(E_ITEM_POTION));
- }
- else if (Junk < 72) // 10 / 83 chance of spawning a bone
- {
- Drops.Add(cItem(E_ITEM_BONE));
- }
- else if (Junk < 73) // 1 / 83 chance of spawning an ink sac
- {
- Drops.Add(cItem(E_ITEM_DYE));
- }
- else // 10 / 83 chance of spawning a tripwire hook
- {
- Drops.Add(cItem(E_BLOCK_TRIPWIRE_HOOK));
- }
-
- a_Player->GetStatManager().AddValue(statJunkFished, 1);
+ cItem Book(E_ITEM_BOOK);
+ Book.EnchantByXPLevels(30);
+ Drops.Add(Book);
+ break;
}
- else
+ case 2:
{
- int FishType = Random.RandInt(99);
- if (FishType <= 1) // Clownfish has a 2% chance of spawning
- {
- Drops.Add(cItem(E_ITEM_RAW_FISH, 1, E_META_RAW_FISH_CLOWNFISH));
- }
- else if (FishType <= 12) // Pufferfish has a 13% chance of spawning
- {
- Drops.Add(cItem(E_ITEM_RAW_FISH, 1, E_META_RAW_FISH_PUFFERFISH));
- }
- else if (FishType <= 24) // Raw salmon has a 25% chance of spawning
- {
- Drops.Add(cItem(E_ITEM_RAW_FISH, 1, E_META_RAW_FISH_SALMON));
- }
- else // Raw fish has a 60% chance of spawning
- {
- Drops.Add(cItem(E_ITEM_RAW_FISH, 1, E_META_RAW_FISH_FISH));
- }
-
- a_Player->GetStatManager().AddValue(statFishCaught, 1);
+ cItem Rod(E_ITEM_FISHING_ROD, 1, Random.RandInt<short>(50));
+ Rod.EnchantByXPLevels(Random.RandInt(22, 30));
+ Drops.Add(Rod);
+ break;
}
-
- if (cRoot::Get()->GetPluginManager()->CallHookPlayerFishing(*a_Player, Drops))
+ case 3:
{
- return true;
+ Drops.Add(cItem(E_ITEM_NAME_TAG));
+ break;
}
- Vector3d FloaterPos = FloaterInfo.GetBitePos();
- FloaterPos.y += 0.5f;
- const float FISH_SPEED_MULT = 2.25f;
-
- Vector3d FlyDirection = (a_Player->GetEyePosition() - FloaterPos).addedY(1.0f) * FISH_SPEED_MULT;
- a_World->SpawnItemPickups(Drops, FloaterPos, FlyDirection);
- a_World->SpawnExperienceOrb(a_Player->GetPosition(), Random.RandInt(1, 6));
- a_Player->UseEquippedItem(1);
- cRoot::Get()->GetPluginManager()->CallHookPlayerFished(*a_Player, Drops);
- }
- else
- {
- BLOCKTYPE Block = a_World->GetBlock(FloaterInfo.GetPos() - Vector3d(0, 0.1, 0));
- if ((Block != E_BLOCK_AIR) && !IsBlockWater(Block))
+ case 4:
+ {
+ Drops.Add(cItem(E_ITEM_SADDLE));
+ break;
+ }
+ case 5:
{
- a_Player->UseEquippedItem(2);
+ Drops.Add(cItem(E_BLOCK_LILY_PAD));
+ break;
}
}
+
+ a_Player.GetStatManager().AddValue(statTreasureFished, 1);
+ }
+ else if (ItemCategory < JunkChances[LotSLevel])
+ {
+ int Junk = Random.RandInt(82);
+ if (Junk < 10) // 10 / 83 chance of spawning a bowl
+ {
+ Drops.Add(cItem(E_ITEM_BOWL));
+ }
+ else if (Junk < 12) // 2 / 83 chance of spawning a fishing rod
+ {
+ // Fishing Rods caught from the Junk category will be 10% .. 100% damaged, and always unenchanted.
+ Drops.Add(cItem(E_ITEM_FISHING_ROD, 1, Random.RandInt<short>(7, 65)));
+ }
+ else if (Junk < 22) // 10 / 83 chance of spawning leather
+ {
+ Drops.Add(cItem(E_ITEM_LEATHER));
+ }
+ else if (Junk < 32) // 10 / 83 chance of spawning leather boots
+ {
+ // Leather boots caught from the Junk category will be 10% .. 100% damaged, and always unenchanted.
+ Drops.Add(cItem(E_ITEM_LEATHER_BOOTS, 1, Random.RandInt<short>(7, 66)));
+ }
+ else if (Junk < 42) // 10 / 83 chance of spawning rotten flesh
+ {
+ Drops.Add(cItem(E_ITEM_ROTTEN_FLESH));
+ }
+ else if (Junk < 47) // 5 / 83 chance of spawning a stick
+ {
+ Drops.Add(cItem(E_ITEM_STICK));
+ }
+ else if (Junk < 52) // 5 / 83 chance of spawning string
+ {
+ Drops.Add(cItem(E_ITEM_STRING));
+ }
+ else if (Junk < 62) // 10 / 83 chance of spawning a water bottle
+ {
+ Drops.Add(cItem(E_ITEM_POTION));
+ }
+ else if (Junk < 72) // 10 / 83 chance of spawning a bone
+ {
+ Drops.Add(cItem(E_ITEM_BONE));
+ }
+ else if (Junk < 73) // 1 / 83 chance of spawning an ink sac
+ {
+ Drops.Add(cItem(E_ITEM_DYE));
+ }
+ else // 10 / 83 chance of spawning a tripwire hook
+ {
+ Drops.Add(cItem(E_BLOCK_TRIPWIRE_HOOK));
+ }
+
+ a_Player.GetStatManager().AddValue(statJunkFished, 1);
}
else
{
- auto Floater = cpp14::make_unique<cFloater>(a_Player->GetEyePosition(), a_Player->GetLookVector() * 15, a_Player->GetUniqueID(), (Random.RandInt(100, 900) - static_cast<int>(a_Player->GetEquippedItem().m_Enchantments.GetLevel(cEnchantments::enchLure) * 100)));
- auto FloaterPtr = Floater.get();
- if (!FloaterPtr->Initialize(std::move(Floater), *a_World))
+ int FishType = Random.RandInt(99);
+ if (FishType <= 1) // Clownfish has a 2% chance of spawning
{
- return false;
+ Drops.Add(cItem(E_ITEM_RAW_FISH, 1, E_META_RAW_FISH_CLOWNFISH));
}
- a_Player->SetIsFishing(true, FloaterPtr->GetUniqueID());
+ else if (FishType <= 12) // Pufferfish has a 13% chance of spawning
+ {
+ Drops.Add(cItem(E_ITEM_RAW_FISH, 1, E_META_RAW_FISH_PUFFERFISH));
+ }
+ else if (FishType <= 24) // Raw salmon has a 25% chance of spawning
+ {
+ Drops.Add(cItem(E_ITEM_RAW_FISH, 1, E_META_RAW_FISH_SALMON));
+ }
+ else // Raw fish has a 60% chance of spawning
+ {
+ Drops.Add(cItem(E_ITEM_RAW_FISH, 1, E_META_RAW_FISH_FISH));
+ }
+
+ a_Player.GetStatManager().AddValue(statFishCaught, 1);
}
- return true;
+
+ // Check with plugins if this loot is acceptable:
+ if (cRoot::Get()->GetPluginManager()->CallHookPlayerFishing(a_Player, Drops))
+ {
+ return;
+ }
+
+ // Spawn the loot and the experience orb:
+ auto FloaterPos = a_FloaterBitePos.addedY(0.5);
+ const float FISH_SPEED_MULT = 2.25f;
+ Vector3d FlyDirection = (a_Player.GetEyePosition() - FloaterPos).addedY(1.0f) * FISH_SPEED_MULT;
+ a_World.SpawnItemPickups(Drops, FloaterPos, FlyDirection);
+ a_World.SpawnExperienceOrb(a_Player.GetPosition(), Random.RandInt(1, 6));
+ a_Player.UseEquippedItem(1);
+
+ // Notify plugins
+ cRoot::Get()->GetPluginManager()->CallHookPlayerFished(a_Player, Drops);
}
} ;
diff --git a/src/Items/ItemFlowerPot.h b/src/Items/ItemFlowerPot.h
index 320dce997..655633785 100644
--- a/src/Items/ItemFlowerPot.h
+++ b/src/Items/ItemFlowerPot.h
@@ -7,26 +7,36 @@
-class cItemFlowerPotHandler :
+class cItemFlowerPotHandler:
public cItemHandler
{
+ using Super = cItemHandler;
+
public:
- cItemFlowerPotHandler(int a_ItemType) :
- cItemHandler(a_ItemType)
+
+ cItemFlowerPotHandler(int a_ItemType):
+ Super(a_ItemType)
{
}
+
+
+
virtual bool IsPlaceable(void) override
{
return true;
}
+
+
+
virtual bool GetPlacementBlockTypeMeta(
cWorld * a_World, cPlayer * a_Player,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
- int a_CursorX, int a_CursorY, int a_CursorZ,
+ const Vector3i a_PlacedBlockPos,
+ eBlockFace a_ClickedBlockFace,
+ const Vector3i a_CursorPos,
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) override
{
diff --git a/src/Items/ItemHandler.cpp b/src/Items/ItemHandler.cpp
index 807be9393..c014ba794 100644
--- a/src/Items/ItemHandler.cpp
+++ b/src/Items/ItemHandler.cpp
@@ -346,41 +346,44 @@ cItemHandler::cItemHandler(int a_ItemType)
bool cItemHandler::OnPlayerPlace(
- cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
- int a_CursorX, int a_CursorY, int a_CursorZ
+ cWorld & a_World,
+ cPlayer & a_Player,
+ const cItem & a_EquippedItem,
+ const Vector3i a_ClickedBlockPos,
+ eBlockFace a_ClickedBlockFace,
+ const Vector3i a_CursorPos
)
{
- if (a_BlockFace < 0)
+ if (a_ClickedBlockFace == BLOCK_FACE_NONE)
{
- // Clicked in air
+ // Clicked in the air, no placement possible
return false;
}
- if ((a_BlockY < 0) || (a_BlockY >= cChunkDef::Height))
+ if (!cChunkDef::IsValidHeight(a_ClickedBlockPos.y))
{
// The clicked block is outside the world, ignore this call altogether (#128)
return false;
}
- BLOCKTYPE ClickedBlock;
+ BLOCKTYPE ClickedBlockType;
NIBBLETYPE ClickedBlockMeta;
- a_World.GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, ClickedBlock, ClickedBlockMeta);
+ a_World.GetBlockTypeMeta(a_ClickedBlockPos, ClickedBlockType, ClickedBlockMeta);
cChunkInterface ChunkInterface(a_World.GetChunkMap());
// Check if the block ignores build collision (water, grass etc.):
- auto blockHandler = BlockHandler(ClickedBlock);
- Vector3i absPos(a_BlockX, a_BlockY, a_BlockZ);
- if (blockHandler->DoesIgnoreBuildCollision(ChunkInterface, absPos, a_Player, ClickedBlockMeta))
+ auto HandlerB = BlockHandler(ClickedBlockType);
+ auto PlacedBlockPos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace);
+ if (HandlerB->DoesIgnoreBuildCollision(ChunkInterface, a_ClickedBlockPos, a_Player, ClickedBlockMeta))
{
- a_World.DropBlockAsPickups(absPos, &a_Player, nullptr);
+ // Replace the clicked block:
+ a_World.DropBlockAsPickups(a_ClickedBlockPos, &a_Player, nullptr);
+ PlacedBlockPos = a_ClickedBlockPos;
}
else
{
- AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
-
- if ((a_BlockY < 0) || (a_BlockY >= cChunkDef::Height))
+ if (!cChunkDef::IsValidHeight(PlacedBlockPos.y))
{
// The block is being placed outside the world, ignore this packet altogether (#128)
return false;
@@ -388,11 +391,11 @@ bool cItemHandler::OnPlayerPlace(
NIBBLETYPE PlaceMeta;
BLOCKTYPE PlaceBlock;
- a_World.GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, PlaceBlock, PlaceMeta);
+ a_World.GetBlockTypeMeta(PlacedBlockPos, PlaceBlock, PlaceMeta);
// Clicked on side of block, make sure that placement won't be cancelled if there is a slab able to be double slabbed.
// No need to do combinability (dblslab) checks, client will do that here.
- if (!BlockHandler(PlaceBlock)->DoesIgnoreBuildCollision(ChunkInterface, { a_BlockX, a_BlockY, a_BlockZ }, a_Player, PlaceMeta))
+ if (!BlockHandler(PlaceBlock)->DoesIgnoreBuildCollision(ChunkInterface, PlacedBlockPos, a_Player, PlaceMeta))
{
// Tried to place a block into another?
// Happens when you place a block aiming at side of block with a torch on it or stem beside it
@@ -402,14 +405,15 @@ bool cItemHandler::OnPlayerPlace(
// Get all the blocks to place:
sSetBlockVector blocks;
- if (!GetBlocksToPlace(a_World, a_Player, a_EquippedItem, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, blocks))
+ if (!GetBlocksToPlace(a_World, a_Player, a_EquippedItem, PlacedBlockPos, a_ClickedBlockFace, a_CursorPos, blocks))
{
// Handler refused the placement, send that information back to the client:
for (const auto & blk: blocks)
{
- a_World.SendBlockTo(blk.GetX(), blk.GetY(), blk.GetZ(), a_Player);
+ const auto & AbsPos = blk.GetAbsolutePos();
+ a_World.SendBlockTo(AbsPos, a_Player);
}
- a_World.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
+ a_World.SendBlockTo(PlacedBlockPos, a_Player);
a_Player.GetInventory().SendEquippedSlot();
return false;
}
@@ -436,18 +440,19 @@ bool cItemHandler::OnPlayerPlace(
bool cItemHandler::GetBlocksToPlace(
cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
- int a_CursorX, int a_CursorY, int a_CursorZ,
+ const Vector3i a_PlacedBlockPos,
+ eBlockFace a_ClickedBlockFace,
+ const Vector3i a_CursorPos,
sSetBlockVector & a_BlocksToSet
)
{
BLOCKTYPE BlockType;
NIBBLETYPE BlockMeta;
- if (!GetPlacementBlockTypeMeta(&a_World, &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta))
+ if (!GetPlacementBlockTypeMeta(&a_World, &a_Player, a_PlacedBlockPos, a_ClickedBlockFace, a_CursorPos, BlockType, BlockMeta))
{
return false;
}
- a_BlocksToSet.emplace_back(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta);
+ a_BlocksToSet.emplace_back(a_PlacedBlockPos, BlockType, BlockMeta);
return true;
}
@@ -457,17 +462,15 @@ bool cItemHandler::GetBlocksToPlace(
bool cItemHandler::OnItemUse(
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
+ const Vector3i a_ClickedBlockPos, eBlockFace a_ClickedBlockFace
)
{
UNUSED(a_World);
UNUSED(a_Player);
UNUSED(a_PluginInterface);
UNUSED(a_Item);
- UNUSED(a_BlockX);
- UNUSED(a_BlockY);
- UNUSED(a_BlockZ);
- UNUSED(a_BlockFace);
+ UNUSED(a_ClickedBlockPos);
+ UNUSED(a_ClickedBlockFace);
return false;
}
@@ -476,15 +479,19 @@ bool cItemHandler::OnItemUse(
-bool cItemHandler::OnDiggingBlock(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir)
+bool cItemHandler::OnDiggingBlock(
+ cWorld * a_World,
+ cPlayer * a_Player,
+ const cItem & a_HeldItem,
+ const Vector3i a_ClickedBlockPos,
+ eBlockFace a_ClickedBlockFace
+)
{
UNUSED(a_World);
UNUSED(a_Player);
- UNUSED(a_Item);
- UNUSED(a_BlockX);
- UNUSED(a_BlockY);
- UNUSED(a_BlockZ);
- UNUSED(a_Dir);
+ UNUSED(a_HeldItem);
+ UNUSED(a_ClickedBlockPos);
+ UNUSED(a_ClickedBlockFace);
return false;
}
@@ -815,8 +822,8 @@ bool cItemHandler::CanHarvestBlock(BLOCKTYPE a_BlockType)
bool cItemHandler::GetPlacementBlockTypeMeta(
cWorld * a_World, cPlayer * a_Player,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
- int a_CursorX, int a_CursorY, int a_CursorZ,
+ const Vector3i a_PlacedBlockPos, eBlockFace a_ClickedBlockFace,
+ const Vector3i a_CursorPos,
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
)
{
@@ -832,8 +839,8 @@ bool cItemHandler::GetPlacementBlockTypeMeta(
cChunkInterface ChunkInterface(a_World->GetChunkMap());
return BlockH->GetPlacementBlockTypeMeta(
ChunkInterface, *a_Player,
- a_BlockX, a_BlockY, a_BlockZ, a_BlockFace,
- a_CursorX, a_CursorY, a_CursorZ,
+ a_PlacedBlockPos, a_ClickedBlockFace,
+ a_CursorPos,
a_BlockType, a_BlockMeta
);
}
diff --git a/src/Items/ItemHandler.h b/src/Items/ItemHandler.h
index ea0684dd1..74de4eaa5 100644
--- a/src/Items/ItemHandler.h
+++ b/src/Items/ItemHandler.h
@@ -38,28 +38,39 @@ public:
/** Called when the player tries to place the item (right mouse button, IsPlaceable() == true).
- The block coords are for the block that has been clicked.
+ a_ClickedBlockPos is the (neighbor) block that has been clicked to place this item.
+ a_ClickedBlockFace is the face of the neighbor that has been clicked to place this item.
+ a_CursorPos is the position of the player's cursor within a_ClickedBlockFace.
The default handler uses GetBlocksToPlace() and places the returned blocks.
Override if the item needs advanced processing, such as spawning a mob based on the blocks being placed.
If the block placement is refused inside this call, it will automatically revert the client-side changes.
Returns true if the placement succeeded, false if the placement was aborted for any reason. */
virtual bool OnPlayerPlace(
- cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
- int a_CursorX, int a_CursorY, int a_CursorZ
+ cWorld & a_World,
+ cPlayer & a_Player,
+ const cItem & a_EquippedItem,
+ const Vector3i a_ClickedBlockPos,
+ eBlockFace a_ClickedBlockFace,
+ const Vector3i a_CursorPos
);
/** Called from OnPlayerPlace() to determine the blocks that the current placement operation should set.
- The block coords are where the new (main) block should be placed.
+ a_PlacedBlockPos points to the location where the new block should be set.
+ a_ClickedBlockFace is the block face of the neighbor that was clicked to place this block.
+ a_CursorPos is the position of the mouse cursor within the clicked (neighbor's) block face.
+ The blocks in a_BlocksToPlace will be sent through cPlayer::PlaceBlocks() after returning from this function.
The default handler uses GetPlacementBlockTypeMeta() and provides that as the single block at the specified coords.
Returns true if the placement succeeded, false if the placement was aborted for any reason.
If aborted, the server then sends all original blocks in the coords provided in a_BlocksToSet to the client. */
virtual bool GetBlocksToPlace(
- cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
- int a_CursorX, int a_CursorY, int a_CursorZ,
- sSetBlockVector & a_BlocksToSet
+ cWorld & a_World,
+ cPlayer & a_Player,
+ const cItem & a_EquippedItem,
+ const Vector3i a_PlacedBlockPos,
+ eBlockFace a_ClickedBlockFace,
+ const Vector3i a_CursorPos,
+ sSetBlockVector & a_BlocksToPlace
);
@@ -68,26 +79,29 @@ public:
Returns true to allow placement, false to refuse. */
virtual bool GetPlacementBlockTypeMeta(
cWorld * a_World, cPlayer * a_Player,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
- int a_CursorX, int a_CursorY, int a_CursorZ,
+ const Vector3i a_PlacedBlockPos,
+ eBlockFace a_ClickedBlockFace,
+ const Vector3i a_CursorPos,
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
);
/** Called when the player tries to use the item (right mouse button).
- Return false to abort the usage. DEFAULT: False */
+ Descendants can return false to abort the usage (default behavior). */
virtual bool OnItemUse(
- cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
+ cWorld * a_World,
+ cPlayer * a_Player,
+ cBlockPluginInterface & a_PluginInterface,
+ const cItem & a_HeldItem,
+ const Vector3i a_ClickedBlockPos,
+ eBlockFace a_ClickedBlockFace
);
- /** Called when the client sends the SHOOT status in the lclk packet */
- virtual void OnItemShoot(cPlayer *, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace)
+ /** Called when the client sends the SHOOT status in the lclk packet (releasing the bow). */
+ virtual void OnItemShoot(cPlayer *, const Vector3i a_BlockPos, eBlockFace a_BlockFace)
{
- UNUSED(a_BlockX);
- UNUSED(a_BlockY);
- UNUSED(a_BlockZ);
+ UNUSED(a_BlockPos);
UNUSED(a_BlockFace);
}
@@ -100,9 +114,13 @@ public:
}
/** Called while the player digs a block using this item */
- virtual bool OnDiggingBlock(cWorld * a_World, cPlayer * a_Player, const cItem & a_HeldItem, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace);
+ virtual bool OnDiggingBlock(
+ cWorld * a_World, cPlayer * a_Player, const cItem & a_HeldItem,
+ const Vector3i a_ClickedBlockPos,
+ eBlockFace a_ClickedBlockFace
+ );
- /** Called when a player attacks a other entity. */
+ /** Called when a player attacks an entity with this item in hand. */
virtual void OnEntityAttack(cPlayer * a_Attacker, cEntity * a_AttackedEntity);
/** Called after the player has eaten this item. */
diff --git a/src/Items/ItemHoe.h b/src/Items/ItemHoe.h
index a0bf44a93..b33ab6b90 100644
--- a/src/Items/ItemHoe.h
+++ b/src/Items/ItemHoe.h
@@ -9,64 +9,68 @@
-class cItemHoeHandler :
+class cItemHoeHandler:
public cItemHandler
{
+ using Super = cItemHandler;
+
public:
- cItemHoeHandler(int a_ItemType)
- : cItemHandler(a_ItemType)
+
+ cItemHoeHandler(int a_ItemType):
+ Super(a_ItemType)
{
}
+
+
virtual bool OnItemUse(
- cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
+ cWorld * a_World,
+ cPlayer * a_Player,
+ cBlockPluginInterface & a_PluginInterface,
+ const cItem & a_HeldItem,
+ const Vector3i a_ClickedBlockPos,
+ eBlockFace a_ClickedBlockFace
) override
{
- if ((a_BlockFace == BLOCK_FACE_NONE) || (a_BlockY >= cChunkDef::Height))
+ if ((a_ClickedBlockFace == BLOCK_FACE_NONE) || (a_ClickedBlockPos.y >= cChunkDef::Height))
{
return false;
}
- BLOCKTYPE UpperBlock = a_World->GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ);
- BLOCKTYPE Block;
- NIBBLETYPE BlockMeta;
- a_World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, Block, BlockMeta);
+ // Need air above the hoe-d block to transform it:
+ BLOCKTYPE UpperBlockType = a_World->GetBlock(a_ClickedBlockPos.addedY(1));
+ if (UpperBlockType != E_BLOCK_AIR)
+ {
+ return false;
+ }
- if (((Block == E_BLOCK_DIRT) || (Block == E_BLOCK_GRASS)) && (UpperBlock == E_BLOCK_AIR))
+ // Can only transform dirt or grass blocks:
+ BLOCKTYPE BlockType;
+ NIBBLETYPE BlockMeta;
+ a_World->GetBlockTypeMeta(a_ClickedBlockPos, BlockType, BlockMeta);
+ if ((BlockType != E_BLOCK_DIRT) && (BlockType != E_BLOCK_GRASS))
+ {
+ return false;
+ }
+ if ((BlockType == E_BLOCK_DIRT) && (BlockMeta == E_META_DIRT_PODZOL))
{
- BLOCKTYPE NewBlock = E_BLOCK_FARMLAND;
- if (Block == E_BLOCK_DIRT)
- {
- switch (BlockMeta)
- {
- case E_META_DIRT_COARSE:
- {
- // Transform to normal dirt
- NewBlock = E_BLOCK_DIRT;
- break;
- }
- case E_META_DIRT_PODZOL:
- {
- // You can't transform this block with a hoe in vanilla
- return false;
- }
- default: break;
- }
- }
-
- a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, NewBlock, 0);
- a_World->BroadcastSoundEffect("item.hoe.till", {a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5}, 1.0f, 0.8f);
- a_Player->UseEquippedItem();
- return true;
+ return false;
}
- return false;
+ // Transform:
+ auto NewBlockType = ((BlockType == E_BLOCK_DIRT) && (BlockMeta == E_META_DIRT_COARSE)) ? E_BLOCK_DIRT : E_BLOCK_FARMLAND;
+ a_World->SetBlock(a_ClickedBlockPos, NewBlockType, 0);
+ a_World->BroadcastSoundEffect("item.hoe.till", a_ClickedBlockPos + Vector3d(0.5, 0.5, 0.5), 1.0f, 0.8f);
+ a_Player->UseEquippedItem();
+ return true;
}
+
+
+
virtual short GetDurabilityLossByAction(eDurabilityLostAction a_Action) override
{
switch (a_Action)
diff --git a/src/Items/ItemItemFrame.h b/src/Items/ItemItemFrame.h
index 7845701fe..bcc325701 100644
--- a/src/Items/ItemItemFrame.h
+++ b/src/Items/ItemItemFrame.h
@@ -9,51 +9,59 @@
-class cItemItemFrameHandler :
+class cItemItemFrameHandler:
public cItemHandler
{
+ using Super = cItemHandler;
+
public:
- cItemItemFrameHandler(int a_ItemType)
- : cItemHandler(a_ItemType)
- {
+ cItemItemFrameHandler(int a_ItemType):
+ Super(a_ItemType)
+ {
}
+
+
virtual bool OnItemUse(
- cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
+ cWorld * a_World,
+ cPlayer * a_Player,
+ cBlockPluginInterface & a_PluginInterface,
+ const cItem & a_HeldItem,
+ const Vector3i a_ClickedBlockPos,
+ eBlockFace a_ClickedBlockFace
) override
{
- if ((a_BlockFace == BLOCK_FACE_NONE) || (a_BlockFace == BLOCK_FACE_YP) || (a_BlockFace == BLOCK_FACE_YM))
+ // Can only place on a side face:
+ if ((a_ClickedBlockFace == BLOCK_FACE_NONE) || (a_ClickedBlockFace == BLOCK_FACE_YP) || (a_ClickedBlockFace == BLOCK_FACE_YM))
{
- // Client sends this if clicked on top or bottom face
return false;
}
- AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); // Make sure block that will be occupied is free
- BLOCKTYPE Block = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
- AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, true); // We want the clicked block, so go back again
-
- if (Block == E_BLOCK_AIR)
+ // Make sure block that will be occupied by the item frame is free now:
+ auto PlacePos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace);
+ BLOCKTYPE Block = a_World->GetBlock(PlacePos);
+ if (Block != E_BLOCK_AIR)
{
- auto ItemFrame = cpp14::make_unique<cItemFrame>(a_BlockFace, Vector3i{a_BlockX, a_BlockY, a_BlockZ});
- auto ItemFramePtr = ItemFrame.get();
- if (!ItemFramePtr->Initialize(std::move(ItemFrame), *a_World))
- {
- return false;
- }
-
- if (!a_Player->IsGameModeCreative())
- {
- a_Player->GetInventory().RemoveOneEquippedItem();
- }
+ return false;
+ }
- return true;
+ // Place the item frame:
+ auto ItemFrame = cpp14::make_unique<cItemFrame>(a_ClickedBlockFace, a_ClickedBlockPos);
+ auto ItemFramePtr = ItemFrame.get();
+ if (!ItemFramePtr->Initialize(std::move(ItemFrame), *a_World))
+ {
+ return false;
+ }
+ if (!a_Player->IsGameModeCreative())
+ {
+ a_Player->GetInventory().RemoveOneEquippedItem();
}
- return false;
+
+ return true;
}
};
diff --git a/src/Items/ItemLeaves.h b/src/Items/ItemLeaves.h
index 59cc1429d..0233ed6a6 100644
--- a/src/Items/ItemLeaves.h
+++ b/src/Items/ItemLeaves.h
@@ -19,17 +19,23 @@ public:
{
}
+
+
+
+
virtual bool GetPlacementBlockTypeMeta(
cWorld * a_World, cPlayer * a_Player,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
- int a_CursorX, int a_CursorY, int a_CursorZ,
+ const Vector3i a_PlacedBlockPos,
+ eBlockFace a_ClickedBlockFace,
+ const Vector3i a_CursorPos,
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) override
{
bool res = Super::GetPlacementBlockTypeMeta(
a_World, a_Player,
- a_BlockX, a_BlockY, a_BlockZ, a_BlockFace,
- a_CursorX, a_CursorY, a_CursorZ,
+ a_PlacedBlockPos,
+ a_ClickedBlockFace,
+ a_CursorPos,
a_BlockType, a_BlockMeta
);
a_BlockMeta = a_BlockMeta | 0x4; // 0x4 bit set means this is a player-placed leaves block, not to be decayed
diff --git a/src/Items/ItemLighter.h b/src/Items/ItemLighter.h
index 241e0511e..d4469a31b 100644
--- a/src/Items/ItemLighter.h
+++ b/src/Items/ItemLighter.h
@@ -9,23 +9,32 @@
-class cItemLighterHandler :
+class cItemLighterHandler:
public cItemHandler
{
+ using Super = cItemHandler;
+
public:
- cItemLighterHandler(int a_ItemType) :
- cItemHandler(a_ItemType)
+
+ cItemLighterHandler(int a_ItemType):
+ Super(a_ItemType)
{
}
+
+
virtual bool OnItemUse(
- cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
+ cWorld * a_World,
+ cPlayer * a_Player,
+ cBlockPluginInterface & a_PluginInterface,
+ const cItem & a_HeldItem,
+ const Vector3i a_ClickedBlockPos,
+ eBlockFace a_ClickedBlockFace
) override
{
- if (a_BlockFace < 0)
+ if (a_ClickedBlockFace < 0)
{
return false;
}
@@ -51,27 +60,27 @@ public:
}
}
- switch (a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ))
+ switch (a_World->GetBlock(a_ClickedBlockPos))
{
case E_BLOCK_TNT:
{
// Activate the TNT:
- a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
- a_World->SpawnPrimedTNT({a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5}); // 80 ticks to boom
+ a_World->SetBlock(a_ClickedBlockPos, E_BLOCK_AIR, 0);
+ a_World->SpawnPrimedTNT(Vector3d(a_ClickedBlockPos) + Vector3d(0.5, 0.5, 0.5)); // 80 ticks to boom
break;
}
default:
{
// Light a fire next to / on top of the block if air:
- AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
- if ((a_BlockY < 0) || (a_BlockY >= cChunkDef::Height))
+ auto FirePos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace);
+ if (!cChunkDef::IsValidHeight(FirePos.y))
{
break;
}
- if (a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_AIR)
+ if (a_World->GetBlock(FirePos) == E_BLOCK_AIR)
{
- a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_FIRE, 0);
- a_World->BroadcastSoundEffect("item.flintandsteel.use", Vector3d(a_BlockX, a_BlockY, a_BlockZ), 1.0F, 1.04F);
+ a_World->SetBlock(FirePos, E_BLOCK_FIRE, 0);
+ a_World->BroadcastSoundEffect("item.flintandsteel.use", FirePos, 1.0f, 1.04f);
break;
}
}
diff --git a/src/Items/ItemLilypad.h b/src/Items/ItemLilypad.h
index 985da3ed5..1190e817b 100644
--- a/src/Items/ItemLilypad.h
+++ b/src/Items/ItemLilypad.h
@@ -23,6 +23,9 @@ public:
}
+
+
+
virtual bool IsPlaceable(void) override
{
return false; // Set as not placeable so OnItemUse is called
@@ -30,16 +33,22 @@ public:
+
+
virtual bool OnItemUse(
- cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
+ cWorld * a_World,
+ cPlayer * a_Player,
+ cBlockPluginInterface & a_PluginInterface,
+ const cItem & a_HeldItem,
+ const Vector3i a_ClickedBlockPos,
+ eBlockFace a_ClickedBlockFace
) override
{
- if (a_BlockFace > BLOCK_FACE_NONE)
+ if (a_ClickedBlockFace > BLOCK_FACE_NONE)
{
- // Clicked on the side of a submerged block; vanilla allows placement, so should we
- AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
- a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_LILY_PAD, 0);
+ // Clicked on a face of a submerged block; vanilla allows placement, so should we
+ auto PlacePos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace);
+ a_World->SetBlock(PlacePos, E_BLOCK_LILY_PAD, 0);
if (!a_Player->IsGameModeCreative())
{
a_Player->GetInventory().RemoveOneEquippedItem();
@@ -47,12 +56,12 @@ public:
return true;
}
- class cCallbacks :
+ class cCallbacks:
public cBlockTracer::cCallbacks
{
public:
- cCallbacks(void) :
+ cCallbacks():
m_HasHitFluid(false)
{
}
@@ -84,18 +93,14 @@ public:
Vector3i m_Pos;
bool m_HasHitFluid;
- };
-
- cCallbacks Callbacks;
- cLineBlockTracer Tracer(*a_Player->GetWorld(), Callbacks);
- Vector3d Start(a_Player->GetEyePosition() + a_Player->GetLookVector());
- Vector3d End(a_Player->GetEyePosition() + a_Player->GetLookVector() * 5);
-
- Tracer.Trace(Start.x, Start.y, Start.z, End.x, End.y, End.z);
+ } Callbacks;
+ auto Start = a_Player->GetEyePosition() + a_Player->GetLookVector();
+ auto End = a_Player->GetEyePosition() + a_Player->GetLookVector() * 5;
+ cLineBlockTracer::Trace(*a_Player->GetWorld(), Callbacks, Start.x, Start.y, Start.z, End.x, End.y, End.z);
if (Callbacks.m_HasHitFluid)
{
- a_World->SetBlock(Callbacks.m_Pos.x, Callbacks.m_Pos.y, Callbacks.m_Pos.z, E_BLOCK_LILY_PAD, 0);
+ a_World->SetBlock(Callbacks.m_Pos, E_BLOCK_LILY_PAD, 0);
if (!a_Player->IsGameModeCreative())
{
a_Player->GetInventory().RemoveOneEquippedItem();
diff --git a/src/Items/ItemMinecart.h b/src/Items/ItemMinecart.h
index 603d3f9c5..d108c2ca8 100644
--- a/src/Items/ItemMinecart.h
+++ b/src/Items/ItemMinecart.h
@@ -1,8 +1,6 @@
#pragma once
-#include "../Entities/Minecart.h"
-
@@ -21,18 +19,25 @@ public:
+
+
virtual bool OnItemUse(
- cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
+ cWorld * a_World,
+ cPlayer * a_Player,
+ cBlockPluginInterface & a_PluginInterface,
+ const cItem & a_HeldItem,
+ const Vector3i a_ClickedBlockPos,
+ eBlockFace a_ClickedBlockFace
) override
{
- if (a_BlockFace < 0)
+ // Must be used on a block
+ if (a_ClickedBlockFace < 0)
{
return false;
}
// Check that there's rail in there:
- BLOCKTYPE Block = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
+ BLOCKTYPE Block = a_World->GetBlock(a_ClickedBlockPos);
switch (Block)
{
case E_BLOCK_MINECART_TRACKS:
@@ -50,15 +55,14 @@ public:
}
}
- double x = static_cast<double>(a_BlockX) + 0.5;
- double y = static_cast<double>(a_BlockY) + 0.5;
- double z = static_cast<double>(a_BlockZ) + 0.5;
-
- if (a_World->SpawnMinecart(x, y, z, m_ItemType) == cEntity::INVALID_ID)
+ // Spawn the minecart:
+ auto SpawnPos = Vector3d(a_ClickedBlockPos) + Vector3d(0.5, 0.5, 0.5);
+ if (a_World->SpawnMinecart(SpawnPos, m_ItemType) == cEntity::INVALID_ID)
{
return false;
}
+ // Remove the item from inventory:
if (!a_Player->IsGameModeCreative())
{
a_Player->GetInventory().RemoveOneEquippedItem();
diff --git a/src/Items/ItemMobHead.h b/src/Items/ItemMobHead.h
index d732327a5..036893c15 100644
--- a/src/Items/ItemMobHead.h
+++ b/src/Items/ItemMobHead.h
@@ -22,52 +22,60 @@ public:
}
+
+
+
virtual bool OnPlayerPlace(
- cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
- int a_CursorX, int a_CursorY, int a_CursorZ
+ cWorld & a_World,
+ cPlayer & a_Player,
+ const cItem & a_EquippedItem,
+ const Vector3i a_ClickedBlockPos,
+ eBlockFace a_ClickedBlockFace,
+ const Vector3i a_CursorPos
) override
{
// Cannot place a head at "no face" and from the bottom:
- if ((a_BlockFace == BLOCK_FACE_NONE) || (a_BlockFace == BLOCK_FACE_BOTTOM))
+ if ((a_ClickedBlockFace == BLOCK_FACE_NONE) || (a_ClickedBlockFace == BLOCK_FACE_BOTTOM))
{
return true;
}
- auto placedX = a_BlockX, placedY = a_BlockY, placedZ = a_BlockZ;
- AddFaceDirection(placedY, placedY, placedZ, a_BlockFace);
+ const auto PlacePos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace);
// If the placed head is a wither, try to spawn the wither first:
if (a_EquippedItem.m_ItemDamage == E_META_HEAD_WITHER)
{
- if (TrySpawnWitherAround(a_World, a_Player, {placedX, placedY, placedZ}))
+ if (TrySpawnWitherAround(a_World, a_Player, PlacePos))
{
return true;
}
// Wither not created, proceed with regular head placement
}
- cItem itemCopy(a_EquippedItem); // Make a copy in case this is the player's last head item and OnPlayerPlace removes it
- if (!Super::OnPlayerPlace(a_World, a_Player, a_EquippedItem, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ))
+ cItem ItemCopy(a_EquippedItem); // Make a copy in case this is the player's last head item and OnPlayerPlace removes it
+ if (!Super::OnPlayerPlace(a_World, a_Player, a_EquippedItem, a_ClickedBlockPos, a_ClickedBlockFace, a_CursorPos))
{
return false;
}
- RegularHeadPlaced(a_World, a_Player, itemCopy, placedX, placedY, placedZ, a_BlockFace);
+ RegularHeadPlaced(a_World, a_Player, ItemCopy, PlacePos, a_ClickedBlockFace);
return true;
}
+
+
+
/** Called after placing a regular head block with no mob spawning.
Adjusts the mob head entity based on the equipped item's data. */
void RegularHeadPlaced(
cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
+ const Vector3i a_PlacePos, eBlockFace a_ClickedBlockFace
)
{
auto HeadType = static_cast<eMobHeadType>(a_EquippedItem.m_ItemDamage);
- auto BlockMeta = static_cast<NIBBLETYPE>(a_BlockFace);
+ auto BlockMeta = static_cast<NIBBLETYPE>(a_ClickedBlockFace);
// Use a callback to set the properties of the mob head block entity:
- a_World.DoWithBlockEntityAt(a_BlockX, a_BlockY, a_BlockZ, [&](cBlockEntity & a_BlockEntity)
+ a_World.DoWithBlockEntityAt(a_PlacePos.x, a_PlacePos.y, a_PlacePos.z, [&](cBlockEntity & a_BlockEntity)
{
if (a_BlockEntity.GetBlockType() != E_BLOCK_HEAD)
{
@@ -90,11 +98,14 @@ public:
}
+
+
+
/** Spawns a wither if the wither skull placed at the specified coords completes wither's spawning formula.
Returns true if the wither was created. */
bool TrySpawnWitherAround(
cWorld & a_World, cPlayer & a_Player,
- Vector3i a_BlockPos
+ const Vector3i a_BlockPos
)
{
// No wither can be created at Y < 2 - not enough space for the formula:
@@ -183,6 +194,9 @@ public:
}
+
+
+
/** Tries to spawn a wither from the specified image at the specified offset from the placed head block.
PlacedHead coords are used to override the block query - at those coords the block is not queried from the world,
but assumed to be a head instead.
@@ -265,6 +279,9 @@ public:
}
+
+
+
/** Awards the achievement to all players close to the specified point. */
void AwardSpawnWitherAchievement(cWorld & a_World, Vector3i a_BlockPos)
{
@@ -283,6 +300,9 @@ public:
}
+
+
+
/** Converts the block face of the placement (which face of the block was clicked to place the head)
into the block's metadata value. */
static NIBBLETYPE BlockFaceToBlockMeta(int a_BlockFace)
@@ -303,21 +323,28 @@ public:
}
+
+
+
virtual bool IsPlaceable(void) override
{
return true;
}
+
+
+
virtual bool GetPlacementBlockTypeMeta(
cWorld * a_World, cPlayer * a_Player,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
- int a_CursorX, int a_CursorY, int a_CursorZ,
+ const Vector3i a_PlacedBlockPos,
+ eBlockFace a_ClickedBlockFace,
+ const Vector3i a_CursorPos,
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) override
{
a_BlockType = E_BLOCK_HEAD;
- a_BlockMeta = BlockFaceToBlockMeta(a_BlockFace);
+ a_BlockMeta = BlockFaceToBlockMeta(a_ClickedBlockFace);
return true;
}
} ;
diff --git a/src/Items/ItemNetherWart.h b/src/Items/ItemNetherWart.h
index 3586231b3..462ea61f9 100644
--- a/src/Items/ItemNetherWart.h
+++ b/src/Items/ItemNetherWart.h
@@ -8,47 +8,53 @@
-class cItemNetherWartHandler :
+class cItemNetherWartHandler:
public cItemHandler
{
+ using Super = cItemHandler;
+
public:
- cItemNetherWartHandler(int a_ItemType) :
- cItemHandler(a_ItemType)
- {
+ cItemNetherWartHandler(int a_ItemType):
+ Super(a_ItemType)
+ {
}
+
+
+
+
virtual bool IsPlaceable(void) override
{
return true;
}
+
+
+
+
virtual bool GetPlacementBlockTypeMeta(
cWorld * a_World, cPlayer * a_Player,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
- int a_CursorX, int a_CursorY, int a_CursorZ,
+ const Vector3i a_PlacedBlockPos,
+ eBlockFace a_ClickedBlockFace,
+ const Vector3i a_CursorPos,
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) override
{
- if (a_BlockFace != BLOCK_FACE_TOP)
+ // Only allow planting nether wart onto the top side of the block:
+ if (a_ClickedBlockFace != BLOCK_FACE_TOP)
{
- // Only allow planting nether wart from the top side of the block
return false;
}
- // Only allow placement on farmland
- int X = a_BlockX;
- int Y = a_BlockY;
- int Z = a_BlockZ;
- AddFaceDirection(X, Y, Z, a_BlockFace, true);
- if (a_World->GetBlock(X, Y, Z) != E_BLOCK_SOULSAND)
+ // Only allow placement on soulsand
+ if ((a_PlacedBlockPos.y < 1) || (a_World->GetBlock(a_PlacedBlockPos.addedY(-1)) != E_BLOCK_SOULSAND))
{
return false;
}
a_BlockMeta = 0;
a_BlockType = E_BLOCK_NETHER_WART;
-
return true;
}
} ;
diff --git a/src/Items/ItemPainting.h b/src/Items/ItemPainting.h
index f9fa0a601..cc1d02ac4 100644
--- a/src/Items/ItemPainting.h
+++ b/src/Items/ItemPainting.h
@@ -10,82 +10,93 @@
-class cItemPaintingHandler :
+class cItemPaintingHandler:
public cItemHandler
{
+ using Super = cItemHandler;
+
public:
- cItemPaintingHandler(int a_ItemType)
- : cItemHandler(a_ItemType)
+
+ cItemPaintingHandler(int a_ItemType):
+ Super(a_ItemType)
{
}
+
+
virtual bool OnItemUse(
- cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
+ cWorld * a_World,
+ cPlayer * a_Player,
+ cBlockPluginInterface & a_PluginInterface,
+ const cItem & a_HeldItem,
+ const Vector3i a_ClickedBlockPos,
+ eBlockFace a_ClickedBlockFace
) override
{
- if ((a_BlockFace == BLOCK_FACE_NONE) || (a_BlockFace == BLOCK_FACE_YM) || (a_BlockFace == BLOCK_FACE_YP))
+ // Paintings can't be flatly placed:
+ if (
+ (a_ClickedBlockFace == BLOCK_FACE_NONE) ||
+ (a_ClickedBlockFace == BLOCK_FACE_YM) ||
+ (a_ClickedBlockFace == BLOCK_FACE_YP)
+ )
{
- // Paintings can't be flatly placed
return false;
}
- AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); // Make sure block that will be occupied is free
- BLOCKTYPE Block = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
+ // Make sure block that will be occupied is free:
+ auto PlacePos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace);
+ BLOCKTYPE PlaceBlockType = a_World->GetBlock(PlacePos);
+ if (PlaceBlockType != E_BLOCK_AIR)
+ {
+ return false;
+ }
- if (Block == E_BLOCK_AIR)
+ // Define all the possible painting titles
+ static const AString gPaintingTitlesList[] =
+ {
+ { "Kebab" },
+ { "Aztec" },
+ { "Alban" },
+ { "Aztec2" },
+ { "Bomb" },
+ { "Plant" },
+ { "Wasteland" },
+ { "Wanderer" },
+ { "Graham" },
+ { "Pool" },
+ { "Courbet" },
+ { "Sunset" },
+ { "Sea" },
+ { "Creebet" },
+ { "Match" },
+ { "Bust" },
+ { "Stage" },
+ { "Void" },
+ { "SkullAndRoses" },
+ { "Wither" },
+ { "Fighters" },
+ { "Skeleton" },
+ { "DonkeyKong" },
+ { "Pointer" },
+ { "Pigscene" },
+ { "BurningSkull" }
+ };
+
+ auto PaintingTitle = gPaintingTitlesList[a_World->GetTickRandomNumber(ARRAYCOUNT(gPaintingTitlesList) - 1)];
+ auto Painting = cpp14::make_unique<cPainting>(PaintingTitle, a_ClickedBlockFace, PlacePos);
+ auto PaintingPtr = Painting.get();
+ if (!PaintingPtr->Initialize(std::move(Painting), *a_World))
{
- static const struct // Define all the possible painting titles
- {
- AString Title;
- } gPaintingTitlesList[] =
- {
- { "Kebab" },
- { "Aztec" },
- { "Alban" },
- { "Aztec2" },
- { "Bomb" },
- { "Plant" },
- { "Wasteland" },
- { "Wanderer" },
- { "Graham" },
- { "Pool" },
- { "Courbet" },
- { "Sunset" },
- { "Sea" },
- { "Creebet" },
- { "Match" },
- { "Bust" },
- { "Stage" },
- { "Void" },
- { "SkullAndRoses" },
- { "Wither" },
- { "Fighters" },
- { "Skeleton" },
- { "DonkeyKong" },
- { "Pointer" },
- { "Pigscene" },
- { "BurningSkull" }
- };
-
- auto Painting = cpp14::make_unique<cPainting>(gPaintingTitlesList[a_World->GetTickRandomNumber(ARRAYCOUNT(gPaintingTitlesList) - 1)].Title, a_BlockFace, Vector3i{a_BlockX, a_BlockY, a_BlockZ});
- auto PaintingPtr = Painting.get();
- if (!PaintingPtr->Initialize(std::move(Painting), *a_World))
- {
- return false;
- }
-
- if (!a_Player->IsGameModeCreative())
- {
- a_Player->GetInventory().RemoveOneEquippedItem();
- }
-
- return true;
+ return false;
+ }
+ if (!a_Player->IsGameModeCreative())
+ {
+ a_Player->GetInventory().RemoveOneEquippedItem();
}
- return false;
+ return true;
}
};
diff --git a/src/Items/ItemPotion.h b/src/Items/ItemPotion.h
index 49fbfa0dd..875fbec02 100644
--- a/src/Items/ItemPotion.h
+++ b/src/Items/ItemPotion.h
@@ -17,6 +17,9 @@ public:
}
+
+
+
// cItemHandler overrides:
virtual bool IsDrinkable(short a_ItemDamage) override
{
@@ -26,12 +29,19 @@ public:
}
+
+
+
virtual bool OnItemUse(
- cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
+ cWorld * a_World,
+ cPlayer * a_Player,
+ cBlockPluginInterface & a_PluginInterface,
+ const cItem & a_HeldItem,
+ const Vector3i a_ClickedBlockPos,
+ eBlockFace a_ClickedBlockFace
) override
{
- short PotionDamage = a_Item.m_ItemDamage;
+ short PotionDamage = a_HeldItem.m_ItemDamage;
// Do not throw non-splash potions:
if (cEntityEffect::IsPotionDrinkable(PotionDamage))
@@ -59,6 +69,9 @@ public:
}
+
+
+
virtual bool EatItem(cPlayer * a_Player, cItem * a_Item) override
{
short PotionDamage = a_Item->m_ItemDamage;
diff --git a/src/Items/ItemPumpkin.h b/src/Items/ItemPumpkin.h
index b8038093c..33810b51f 100644
--- a/src/Items/ItemPumpkin.h
+++ b/src/Items/ItemPumpkin.h
@@ -20,44 +20,50 @@ public:
}
+
+
+
virtual bool OnPlayerPlace(
- cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
- int a_CursorX, int a_CursorY, int a_CursorZ
+ cWorld & a_World,
+ cPlayer & a_Player,
+ const cItem & a_EquippedItem,
+ const Vector3i a_ClickedBlockPos,
+ eBlockFace a_ClickedBlockFace,
+ const Vector3i a_CursorPos
) override
{
// First try spawning a snow golem or an iron golem:
- int PlacedBlockX = a_BlockX;
- int PlacedBlockY = a_BlockY;
- int PlacedBlockZ = a_BlockZ;
- AddFaceDirection(PlacedBlockX, PlacedBlockY, PlacedBlockZ, a_BlockFace);
- if (TrySpawnGolem(a_World, a_Player, PlacedBlockX, PlacedBlockY, PlacedBlockZ))
+ auto PlacePos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace);
+ if (TrySpawnGolem(a_World, a_Player, PlacePos))
{
// The client thinks that they placed the pumpkin, let them know it's been replaced:
- a_Player.SendBlocksAround(PlacedBlockX, PlacedBlockY, PlacedBlockZ);
+ a_Player.SendBlocksAround(PlacePos.x, PlacePos.y, PlacePos.z);
return true;
}
// No golem at these coords, place the block normally:
- return Super::OnPlayerPlace(a_World, a_Player, a_EquippedItem, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ);
+ return Super::OnPlayerPlace(a_World, a_Player, a_EquippedItem, a_ClickedBlockPos, a_ClickedBlockFace, a_CursorPos);
}
+
+
+
/** Spawns a snow / iron golem if the shape matches the recipe, supposing that the block placed at the specified coords is a pumpkin.
Returns true if the golem blocks are removed (for spawning), false if the recipe is not matched. */
- bool TrySpawnGolem(cWorld & a_World, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ)
+ bool TrySpawnGolem(cWorld & a_World, cPlayer & a_Player, const Vector3i a_PumpkinPos)
{
// A golem can't form with a pumpkin below level 2 or above level 255
- if ((a_BlockY < 2) || (a_BlockY >= cChunkDef::Height))
+ if ((a_PumpkinPos.y < 2) || (a_PumpkinPos.y >= cChunkDef::Height))
{
return false;
}
// Decide which golem to try spawning based on the block below the placed pumpkin:
- switch (a_World.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ))
+ switch (a_World.GetBlock(a_PumpkinPos.addedY(-1)))
{
- case E_BLOCK_SNOW_BLOCK: return TrySpawnSnowGolem(a_World, a_Player, a_BlockX, a_BlockY, a_BlockZ);
- case E_BLOCK_IRON_BLOCK: return TrySpawnIronGolem(a_World, a_Player, a_BlockX, a_BlockY, a_BlockZ);
+ case E_BLOCK_SNOW_BLOCK: return TrySpawnSnowGolem(a_World, a_Player, a_PumpkinPos);
+ case E_BLOCK_IRON_BLOCK: return TrySpawnIronGolem(a_World, a_Player, a_PumpkinPos);
default:
{
// No golem here
@@ -67,45 +73,59 @@ public:
}
+
+
+
/** Spawns a snow golem if the shape matches the recipe, supposing that the block placed at the specified coords is a pumpkin.
Returns true if the golem blocks are removed (for spawning), false if the recipe is not matched.
Assumes that the block below the specified block has already been checked and is a snow block. */
- bool TrySpawnSnowGolem(cWorld & a_World, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ)
+ bool TrySpawnSnowGolem(cWorld & a_World, cPlayer & a_Player, const Vector3i a_PumpkinPos)
{
+ ASSERT(a_PumpkinPos.y > 1);
+ ASSERT(a_World.GetBlock(a_PumpkinPos.addedY(-1)) == E_BLOCK_SNOW);
+
// Need one more snow block 2 blocks below the pumpkin:
- if (a_World.GetBlock(a_BlockX, a_BlockY - 2, a_BlockZ) != E_BLOCK_SNOW_BLOCK)
+ if (a_World.GetBlock(a_PumpkinPos.addedY(-2)) != E_BLOCK_SNOW_BLOCK)
{
return false;
}
// Try to place air blocks where the original recipe blocks were:
sSetBlockVector AirBlocks;
- AirBlocks.emplace_back(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0); // Head
- AirBlocks.emplace_back(a_BlockX, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0); // Torso
- AirBlocks.emplace_back(a_BlockX, a_BlockY - 2, a_BlockZ, E_BLOCK_AIR, 0); // Legs
+ AirBlocks.emplace_back(a_PumpkinPos, E_BLOCK_AIR, 0); // Head
+ AirBlocks.emplace_back(a_PumpkinPos.addedY(-1), E_BLOCK_AIR, 0); // Torso
+ AirBlocks.emplace_back(a_PumpkinPos.addedY(-2), E_BLOCK_AIR, 0); // Legs
if (!a_Player.PlaceBlocks(AirBlocks))
{
return false;
}
// Spawn the golem:
- a_World.SpawnMob(static_cast<double>(a_BlockX) + 0.5, a_BlockY - 2, static_cast<double>(a_BlockZ) + 0.5, mtSnowGolem, false);
+ auto GolemPos = Vector3d(a_PumpkinPos) + Vector3d(0.5, -2, 0.5);
+ a_World.SpawnMob(GolemPos.x, GolemPos.y, GolemPos.z, mtSnowGolem, false);
return true;
}
+
+
+
/** Spawns an iron golem if the shape matches the recipe, supposing that the block placed at the specified coords is a pumpkin.
Returns true if the golem blocks are removed (for spawning), false if the recipe is not matched.
Assumes that the block below the specified block has already been checked and is an iron block. */
- bool TrySpawnIronGolem(cWorld & a_World, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ)
+ bool TrySpawnIronGolem(cWorld & a_World, cPlayer & a_Player, const Vector3i a_PumpkinPos)
{
+ ASSERT(a_PumpkinPos.y > 1);
+ ASSERT(a_World.GetBlock(a_PumpkinPos.addedY(-1)) == E_BLOCK_IRON_BLOCK);
+
// Need one more iron block 2 blocks below the pumpkin:
- if (a_World.GetBlock(a_BlockX, a_BlockY - 2, a_BlockZ) != E_BLOCK_IRON_BLOCK)
+ if (a_World.GetBlock(a_PumpkinPos.addedY(-2)) != E_BLOCK_IRON_BLOCK)
{
return false;
}
// Check the two arm directions (X, Z) using a loop over two sets of offset vectors:
+ auto BodyPos = a_PumpkinPos.addedY(-1);
static const Vector3i ArmOffsets[] =
{
{1, 0, 0},
@@ -115,8 +135,8 @@ public:
{
// If the arm blocks don't match, bail out of this loop repetition:
if (
- (a_World.GetBlock(a_BlockX + ArmOffsets[i].x, a_BlockY - 1, a_BlockZ + ArmOffsets[i].z) != E_BLOCK_IRON_BLOCK) ||
- (a_World.GetBlock(a_BlockX - ArmOffsets[i].x, a_BlockY - 1, a_BlockZ - ArmOffsets[i].z) != E_BLOCK_IRON_BLOCK)
+ (a_World.GetBlock(BodyPos + ArmOffsets[i]) != E_BLOCK_IRON_BLOCK) ||
+ (a_World.GetBlock(BodyPos - ArmOffsets[i]) != E_BLOCK_IRON_BLOCK)
)
{
continue;
@@ -124,18 +144,19 @@ public:
// Try to place air blocks where the original recipe blocks were:
sSetBlockVector AirBlocks;
- AirBlocks.emplace_back(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0); // Head
- AirBlocks.emplace_back(a_BlockX, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0); // Torso
- AirBlocks.emplace_back(a_BlockX, a_BlockY - 2, a_BlockZ, E_BLOCK_AIR, 0); // Legs
- AirBlocks.emplace_back(a_BlockX + ArmOffsets[i].x, a_BlockY - 1, a_BlockZ + ArmOffsets[i].z, E_BLOCK_AIR, 0); // Arm
- AirBlocks.emplace_back(a_BlockX - ArmOffsets[i].x, a_BlockY - 1, a_BlockZ - ArmOffsets[i].z, E_BLOCK_AIR, 0); // Arm
+ AirBlocks.emplace_back(a_PumpkinPos, E_BLOCK_AIR, 0); // Head
+ AirBlocks.emplace_back(BodyPos, E_BLOCK_AIR, 0); // Torso
+ AirBlocks.emplace_back(BodyPos.addedY(-1), E_BLOCK_AIR, 0); // Legs
+ AirBlocks.emplace_back(BodyPos + ArmOffsets[i], E_BLOCK_AIR, 0); // Arm
+ AirBlocks.emplace_back(BodyPos - ArmOffsets[i], E_BLOCK_AIR, 0); // Arm
if (!a_Player.PlaceBlocks(AirBlocks))
{
return false;
}
// Spawn the golem:
- a_World.SpawnMob(static_cast<double>(a_BlockX) + 0.5, a_BlockY - 2, static_cast<double>(a_BlockZ) + 0.5, mtIronGolem, false);
+ auto GolemPos = Vector3d(a_PumpkinPos) + Vector3d(0.5, -2, 0.5);
+ a_World.SpawnMob(GolemPos.x, GolemPos.y, GolemPos.z, mtIronGolem, false);
return true;
} // for i - ArmOffsets[]
diff --git a/src/Items/ItemRedstoneDust.h b/src/Items/ItemRedstoneDust.h
index 87f351654..559be843d 100644
--- a/src/Items/ItemRedstoneDust.h
+++ b/src/Items/ItemRedstoneDust.h
@@ -7,36 +7,48 @@
-class cItemRedstoneDustHandler : public cItemHandler
+class cItemRedstoneDustHandler:
+ public cItemHandler
{
+ using Super = cItemHandler;
+
public:
- cItemRedstoneDustHandler(int a_ItemType)
- : cItemHandler(a_ItemType)
+
+ cItemRedstoneDustHandler(int a_ItemType):
+ Super(a_ItemType)
{
}
+
+
+
+
virtual bool IsPlaceable(void) override
{
return true;
}
+
+
+
+
virtual bool GetPlacementBlockTypeMeta(
cWorld * a_World, cPlayer * a_Player,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
- int a_CursorX, int a_CursorY, int a_CursorZ,
+ const Vector3i a_PlacedBlockPos,
+ eBlockFace a_ClickedBlockFace,
+ const Vector3i a_CursorPos,
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) override
{
- // Check if coords are out of range:
- if ((a_BlockY <= 0) || (a_BlockY >= cChunkDef::Height))
+ // Check the block below, if it supports dust on top of it:
+ auto UnderPos = a_PlacedBlockPos.addedY(-1);
+ if (UnderPos.y < 0)
{
return false;
}
-
- // Check the block below, if it supports dust on top of it:
BLOCKTYPE BlockType;
NIBBLETYPE BlockMeta;
- if (!a_World->GetBlockTypeMeta(a_BlockX, a_BlockY - 1, a_BlockZ, BlockType, BlockMeta))
+ if (!a_World->GetBlockTypeMeta(UnderPos, BlockType, BlockMeta))
{
return false;
}
@@ -51,6 +63,9 @@ public:
}
+
+
+
/** Returns true if the specified block type / meta is suitable to have redstone dust on top of it. */
static bool IsBlockTypeUnderSuitable(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
{
diff --git a/src/Items/ItemRedstoneRepeater.h b/src/Items/ItemRedstoneRepeater.h
index 9b0fc1bcc..6b1635609 100644
--- a/src/Items/ItemRedstoneRepeater.h
+++ b/src/Items/ItemRedstoneRepeater.h
@@ -8,24 +8,36 @@
-class cItemRedstoneRepeaterHandler :
+class cItemRedstoneRepeaterHandler:
public cItemHandler
{
+ using Super = cItemHandler;
+
public:
- cItemRedstoneRepeaterHandler(int a_ItemType)
- : cItemHandler(a_ItemType)
+
+ cItemRedstoneRepeaterHandler(int a_ItemType):
+ Super(a_ItemType)
{
}
+
+
+
+
virtual bool IsPlaceable() override
{
return true;
}
+
+
+
+
virtual bool GetPlacementBlockTypeMeta(
cWorld * a_World, cPlayer * a_Player,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
- int a_CursorX, int a_CursorY, int a_CursorZ,
+ const Vector3i a_PlacedBlockPos,
+ eBlockFace a_ClickedBlockFace,
+ const Vector3i a_CursorPos,
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) override
{
diff --git a/src/Items/ItemSapling.h b/src/Items/ItemSapling.h
index e8deb37a9..513f542f6 100644
--- a/src/Items/ItemSapling.h
+++ b/src/Items/ItemSapling.h
@@ -17,24 +17,29 @@ public:
cItemSaplingHandler(int a_ItemType):
Super(a_ItemType)
{
-
}
+
+
+
+
virtual bool GetPlacementBlockTypeMeta(
cWorld * a_World, cPlayer * a_Player,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
- int a_CursorX, int a_CursorY, int a_CursorZ,
+ const Vector3i a_PlacedBlockPos,
+ eBlockFace a_ClickedBlockFace,
+ const Vector3i a_CursorPos,
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) override
{
bool res = Super::GetPlacementBlockTypeMeta(
a_World, a_Player,
- a_BlockX, a_BlockY, a_BlockZ, a_BlockFace,
- a_CursorX, a_CursorY, a_CursorZ,
+ a_PlacedBlockPos, a_ClickedBlockFace,
+ a_CursorPos,
a_BlockType, a_BlockMeta
);
- // Only the lowest 3 bits are important
- a_BlockMeta = a_BlockMeta & 0x7;
+
+ // Allow only the lowest 3 bits (top bit is for growth):
+ a_BlockMeta = a_BlockMeta & 0x07;
return res;
}
} ;
diff --git a/src/Items/ItemSeeds.h b/src/Items/ItemSeeds.h
index 8338d1060..67d90362a 100644
--- a/src/Items/ItemSeeds.h
+++ b/src/Items/ItemSeeds.h
@@ -8,44 +8,53 @@
-class cItemSeedsHandler :
+class cItemSeedsHandler:
public cItemHandler
{
+ using Super = cItemHandler;
+
public:
- cItemSeedsHandler(int a_ItemType) :
- cItemHandler(a_ItemType)
+
+ cItemSeedsHandler(int a_ItemType):
+ Super(a_ItemType)
{
}
+
+
+
+
virtual bool IsPlaceable(void) override
{
return true;
}
+
+
+
+
virtual bool GetPlacementBlockTypeMeta(
cWorld * a_World, cPlayer * a_Player,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
- int a_CursorX, int a_CursorY, int a_CursorZ,
+ const Vector3i a_PlacedBlockPos,
+ eBlockFace a_ClickedBlockFace,
+ const Vector3i a_CursorPos,
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) override
{
- if (a_BlockFace != BLOCK_FACE_TOP)
+ // Only allow planting seeds from the top side of the block:
+ if ((a_ClickedBlockFace != BLOCK_FACE_TOP) || (a_PlacedBlockPos.y <= 0))
{
- // Only allow planting seeds from the top side of the block
return false;
}
// Only allow placement on farmland
- int X = a_BlockX;
- int Y = a_BlockY;
- int Z = a_BlockZ;
- AddFaceDirection(X, Y, Z, a_BlockFace, true);
- if (a_World->GetBlock(X, Y, Z) != E_BLOCK_FARMLAND)
+ if (a_World->GetBlock(a_PlacedBlockPos.addedY(-1)) != E_BLOCK_FARMLAND)
{
return false;
}
+ // Get the produce block based on the seed item:
a_BlockMeta = 0;
switch (m_ItemType)
{
diff --git a/src/Items/ItemShears.h b/src/Items/ItemShears.h
index a100a52a3..140e26c5e 100644
--- a/src/Items/ItemShears.h
+++ b/src/Items/ItemShears.h
@@ -22,25 +22,33 @@ public:
}
+
+
+
virtual bool IsTool(void) override
{
return true;
}
- virtual bool OnDiggingBlock(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir) override
+
+
+
+ virtual bool OnDiggingBlock(
+ cWorld * a_World,
+ cPlayer * a_Player,
+ const cItem & a_HeldItem,
+ const Vector3i a_ClickedBlockPos,
+ eBlockFace a_ClickedBlockFace
+ ) override
{
BLOCKTYPE Block;
NIBBLETYPE BlockMeta;
- a_World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, Block, BlockMeta);
+ a_World->GetBlockTypeMeta(a_ClickedBlockPos, Block, BlockMeta);
if ((Block == E_BLOCK_LEAVES) || (Block == E_BLOCK_NEW_LEAVES))
{
- cItems Drops;
- Drops.Add(Block, 1, BlockMeta & 3);
- a_World->SpawnItemPickups(Drops, a_BlockX, a_BlockY, a_BlockZ);
-
- a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
+ a_World->DropBlockAsPickups(a_ClickedBlockPos, a_Player, &a_HeldItem);
return true;
}
@@ -48,6 +56,9 @@ public:
}
+
+
+
virtual bool CanHarvestBlock(BLOCKTYPE a_BlockType) override
{
switch (a_BlockType)
@@ -63,6 +74,9 @@ public:
}
+
+
+
virtual short GetDurabilityLossByAction(eDurabilityLostAction a_Action) override
{
switch (a_Action)
@@ -93,5 +107,4 @@ public:
return Super::GetBlockBreakingStrength(a_Block);
}
}
-
} ;
diff --git a/src/Items/ItemSign.h b/src/Items/ItemSign.h
index 21acd81ae..cb9136db1 100644
--- a/src/Items/ItemSign.h
+++ b/src/Items/ItemSign.h
@@ -24,58 +24,68 @@ public:
}
+
+
+
virtual bool OnPlayerPlace(
- cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
- int a_CursorX, int a_CursorY, int a_CursorZ
+ cWorld & a_World,
+ cPlayer & a_Player,
+ const cItem & a_EquippedItem,
+ const Vector3i a_ClickedBlockPos,
+ eBlockFace a_ClickedBlockFace,
+ const Vector3i a_CursorPos
) override
{
// Check if placing on something ignoring build collision to edit the correct sign later on:
- BLOCKTYPE ClickedBlock;
+ BLOCKTYPE ClickedBlockType;
NIBBLETYPE ClickedBlockMeta;
- a_World.GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, ClickedBlock, ClickedBlockMeta);
+ a_World.GetBlockTypeMeta(a_ClickedBlockPos, ClickedBlockType, ClickedBlockMeta);
cChunkInterface ChunkInterface(a_World.GetChunkMap());
- bool isReplacingClickedBlock = BlockHandler(ClickedBlock)->DoesIgnoreBuildCollision(ChunkInterface, { a_BlockX, a_BlockY, a_BlockZ }, a_Player, ClickedBlockMeta);
+ bool IsReplacingClickedBlock = BlockHandler(ClickedBlockType)->DoesIgnoreBuildCollision(ChunkInterface, a_ClickedBlockPos, a_Player, ClickedBlockMeta);
// If the regular placement doesn't work, do no further processing:
- if (!Super::OnPlayerPlace(a_World, a_Player, a_EquippedItem, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ))
+ if (!Super::OnPlayerPlace(a_World, a_Player, a_EquippedItem, a_ClickedBlockPos, a_ClickedBlockFace, a_CursorPos))
{
return false;
}
- // Use isReplacingClickedBlock to make sure we will edit the right sign:
- if (!isReplacingClickedBlock)
- {
- AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
- }
+ // Use IsReplacingClickedBlock to make sure we will edit the right sign:
+ auto SignPos = IsReplacingClickedBlock ? a_ClickedBlockPos : AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace);
// After successfully placing the sign, open the sign editor for the player:
- a_Player.GetClientHandle()->SendEditSign(a_BlockX, a_BlockY, a_BlockZ);
+ a_Player.GetClientHandle()->SendEditSign(SignPos.x, SignPos.y, SignPos.z);
return true;
}
+
+
+
virtual bool IsPlaceable(void) override
{
return true;
}
+
+
+
virtual bool GetPlacementBlockTypeMeta(
cWorld * a_World, cPlayer * a_Player,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
- int a_CursorX, int a_CursorY, int a_CursorZ,
+ const Vector3i a_PlacedBlockPos,
+ eBlockFace a_ClickedBlockFace,
+ const Vector3i a_CursorPos,
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) override
{
- if (a_BlockFace == BLOCK_FACE_TOP)
+ if (a_ClickedBlockFace == BLOCK_FACE_TOP)
{
a_BlockMeta = cBlockSignPostHandler::RotationToMetaData(a_Player->GetYaw());
a_BlockType = E_BLOCK_SIGN_POST;
}
else
{
- a_BlockMeta = cBlockWallSignHandler::DirectionToMetaData(a_BlockFace);
+ a_BlockMeta = cBlockWallSignHandler::BlockFaceToMetaData(a_ClickedBlockFace);
a_BlockType = E_BLOCK_WALLSIGN;
}
return true;
diff --git a/src/Items/ItemSlab.h b/src/Items/ItemSlab.h
index 0c7654113..944336f7e 100644
--- a/src/Items/ItemSlab.h
+++ b/src/Items/ItemSlab.h
@@ -23,47 +23,34 @@ public:
}
+
+
+
// cItemHandler overrides:
virtual bool OnPlayerPlace(
- cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
- int a_CursorX, int a_CursorY, int a_CursorZ
+ cWorld & a_World,
+ cPlayer & a_Player,
+ const cItem & a_EquippedItem,
+ const Vector3i a_ClickedBlockPos,
+ eBlockFace a_ClickedBlockFace,
+ const Vector3i a_CursorPos
) override
{
- // Special slab handling - placing a slab onto another slab produces a dblslab instead:
+ // If clicking a slab, try combining it into a double-slab:
BLOCKTYPE ClickedBlockType;
NIBBLETYPE ClickedBlockMeta;
- a_World.GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, ClickedBlockType, ClickedBlockMeta);
- // If clicked on a half slab directly
+ a_World.GetBlockTypeMeta(a_ClickedBlockPos, ClickedBlockType, ClickedBlockMeta);
if (
(ClickedBlockType == m_ItemType) && // Placing the same slab material
((ClickedBlockMeta & 0x07) == a_EquippedItem.m_ItemDamage) // Placing the same slab sub-kind (and existing slab is single)
)
{
- // If clicking the top side of a bottom-half slab, combine into a doubleslab:
- if (
- (a_BlockFace == BLOCK_FACE_TOP) &&
- ((ClickedBlockMeta & 0x08) == 0)
- )
- {
- if (!a_Player.PlaceBlock(a_BlockX, a_BlockY, a_BlockZ, m_DoubleSlabBlockType, ClickedBlockMeta & 0x07))
- {
- return false;
- }
- if (a_Player.IsGameModeSurvival())
- {
- a_Player.GetInventory().RemoveOneEquippedItem();
- }
- return true;
- }
-
- // If clicking the bottom side of a top-half slab, combine into a doubleslab:
if (
- (a_BlockFace == BLOCK_FACE_BOTTOM) &&
- ((ClickedBlockMeta & 0x08) != 0)
+ ((a_ClickedBlockFace == BLOCK_FACE_TOP) && ((ClickedBlockMeta & 0x08) == 0)) || // Top side of a bottom-half-slab
+ ((a_ClickedBlockFace == BLOCK_FACE_BOTTOM) && ((ClickedBlockMeta & 0x08) != 0)) // Bottom side of a top-half-slab
)
{
- if (!a_Player.PlaceBlock(a_BlockX, a_BlockY, a_BlockZ, m_DoubleSlabBlockType, ClickedBlockMeta & 0x07))
+ if (!a_Player.PlaceBlock(a_ClickedBlockPos.x, a_ClickedBlockPos.y, a_ClickedBlockPos.z, m_DoubleSlabBlockType, ClickedBlockMeta & 0x07))
{
return false;
}
@@ -75,18 +62,17 @@ public:
}
}
- // Checking the type of block that should be placed
- AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
+ // If there's already a slab in the destination, combine it into a double-slab:
+ auto PlacePos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace);
BLOCKTYPE PlaceBlockType;
NIBBLETYPE PlaceBlockMeta;
- a_World.GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, PlaceBlockType, PlaceBlockMeta);
- // If it's a slab combine into a doubleslab (means that clicked on side, top or bottom of a block adjacent to a half slab)
+ a_World.GetBlockTypeMeta(PlacePos, PlaceBlockType, PlaceBlockMeta);
if (
(PlaceBlockType == m_ItemType) && // Placing the same slab material
((PlaceBlockMeta & 0x07) == a_EquippedItem.m_ItemDamage) // Placing the same slab sub-kind (and existing slab is single)
)
{
- if (!a_Player.PlaceBlock(a_BlockX, a_BlockY, a_BlockZ, m_DoubleSlabBlockType, PlaceBlockMeta & 0x07))
+ if (!a_Player.PlaceBlock(PlacePos.x, PlacePos.y, PlacePos.z, m_DoubleSlabBlockType, PlaceBlockMeta & 0x07))
{
return false;
}
@@ -98,8 +84,7 @@ public:
}
// The slabs didn't combine, use the default handler to place the slab:
- AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, true);
- bool res = Super::OnPlayerPlace(a_World, a_Player, a_EquippedItem, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ);
+ bool res = Super::OnPlayerPlace(a_World, a_Player, a_EquippedItem, a_ClickedBlockPos, a_ClickedBlockFace, a_CursorPos);
/*
The client has a bug when a slab replaces snow and there's a slab above it.
@@ -107,14 +92,17 @@ public:
We send the block above the currently placed block back to the client to fix the bug.
Ref.: https://forum.cuberite.org/thread-434-post-17388.html#pid17388
*/
- if ((a_BlockFace == BLOCK_FACE_TOP) && (a_BlockY < cChunkDef::Height - 1))
+ if ((a_ClickedBlockFace == BLOCK_FACE_TOP) && (a_ClickedBlockPos.y < cChunkDef::Height - 1))
{
- a_Player.SendBlocksAround(a_BlockX, a_BlockY + 1, a_BlockZ, 1);
+ auto AbovePos = a_ClickedBlockPos.addedY(1);
+ a_Player.SendBlocksAround(AbovePos.x, AbovePos.y, AbovePos.z, 1);
}
return res;
}
+
protected:
+
/** The block type to use when the slab combines into a doubleslab block. */
BLOCKTYPE m_DoubleSlabBlockType;
};
diff --git a/src/Items/ItemSpawnEgg.h b/src/Items/ItemSpawnEgg.h
index d57b93b2c..8408bd815 100644
--- a/src/Items/ItemSpawnEgg.h
+++ b/src/Items/ItemSpawnEgg.h
@@ -9,38 +9,47 @@
-class cItemSpawnEggHandler : public cItemHandler
+class cItemSpawnEggHandler:
+ public cItemHandler
{
+ using Super = cItemHandler;
+
public:
- cItemSpawnEggHandler(int a_ItemType) :
- cItemHandler(a_ItemType)
- {
+ cItemSpawnEggHandler(int a_ItemType):
+ Super(a_ItemType)
+ {
}
+
+
virtual bool OnItemUse(
- cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
+ cWorld * a_World,
+ cPlayer * a_Player,
+ cBlockPluginInterface & a_PluginInterface,
+ const cItem & a_HeldItem,
+ const Vector3i a_ClickedBlockPos,
+ eBlockFace a_ClickedBlockFace
) override
{
- if (a_BlockFace < 0)
+ // Must click a valid block:
+ if (a_ClickedBlockFace < 0)
{
return false;
}
- AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
-
- if (a_BlockFace == BLOCK_FACE_YM)
+ auto PlacementPos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace);
+ if (a_ClickedBlockFace == BLOCK_FACE_YM)
{
- a_BlockY--;
+ PlacementPos.y--;
}
- eMonsterType MonsterType = ItemDamageToMonsterType(a_Item.m_ItemDamage);
+ auto MonsterType = ItemDamageToMonsterType(a_HeldItem.m_ItemDamage);
if (
(MonsterType != mtInvalidType) && // Valid monster type
- (a_World->SpawnMob(a_BlockX + 0.5, a_BlockY, a_BlockZ + 0.5, MonsterType, false) != cEntity::INVALID_ID)) // Spawning succeeded
+ (a_World->SpawnMob(PlacementPos.x + 0.5, PlacementPos.y, PlacementPos.z + 0.5, MonsterType, false) != cEntity::INVALID_ID)) // Spawning succeeded
{
if (!a_Player->IsGameModeCreative())
{
@@ -54,6 +63,9 @@ public:
}
+
+
+
/** Converts the Spawn egg item damage to the monster type to spawn.
Returns mtInvalidType for invalid damage values. */
static eMonsterType ItemDamageToMonsterType(short a_ItemDamage)
diff --git a/src/Items/ItemString.h b/src/Items/ItemString.h
index a97fbe0ce..e7c9617d4 100644
--- a/src/Items/ItemString.h
+++ b/src/Items/ItemString.h
@@ -7,26 +7,38 @@
-class cItemStringHandler :
+class cItemStringHandler:
public cItemHandler
{
+ using Super = cItemHandler;
+
public:
- cItemStringHandler(int a_ItemType) :
- cItemHandler(a_ItemType)
+
+ cItemStringHandler(int a_ItemType):
+ Super(a_ItemType)
{
}
+
+
+
+
virtual bool IsPlaceable(void) override
{
return true;
}
+
+
+
+
virtual bool GetPlacementBlockTypeMeta(
cWorld * a_World, cPlayer * a_Player,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
- int a_CursorX, int a_CursorY, int a_CursorZ,
+ const Vector3i a_PlacedBlockPos,
+ eBlockFace a_ClickedBlockFace,
+ const Vector3i a_CursorPos,
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
- ) override
+ ) override
{
a_BlockType = E_BLOCK_TRIPWIRE;
a_BlockMeta = 0;
diff --git a/src/Items/ItemSugarcane.h b/src/Items/ItemSugarcane.h
index dd2e2ece3..b870f38f1 100644
--- a/src/Items/ItemSugarcane.h
+++ b/src/Items/ItemSugarcane.h
@@ -7,24 +7,36 @@
-class cItemSugarcaneHandler :
+class cItemSugarcaneHandler:
public cItemHandler
{
+ using Super = cItemHandler;
+
public:
- cItemSugarcaneHandler(int a_ItemType) :
- cItemHandler(a_ItemType)
+
+ cItemSugarcaneHandler(int a_ItemType):
+ Super(a_ItemType)
{
}
+
+
+
+
virtual bool IsPlaceable(void) override
{
return true;
}
+
+
+
+
virtual bool GetPlacementBlockTypeMeta(
cWorld * a_World, cPlayer * a_Player,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
- int a_CursorX, int a_CursorY, int a_CursorZ,
+ const Vector3i a_PlacedBlockPos,
+ eBlockFace a_ClickedBlockFace,
+ const Vector3i a_CursorPos,
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) override
{
diff --git a/src/Items/ItemThrowable.h b/src/Items/ItemThrowable.h
index daae7658c..606f655e9 100644
--- a/src/Items/ItemThrowable.h
+++ b/src/Items/ItemThrowable.h
@@ -23,22 +23,30 @@ public:
+
+
virtual bool OnItemUse(
- cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
+ cWorld * a_World,
+ cPlayer * a_Player,
+ cBlockPluginInterface & a_PluginInterface,
+ const cItem & a_HeldItem,
+ const Vector3i a_ClickedBlockPos,
+ eBlockFace a_ClickedBlockFace
) override
{
- Vector3d Pos = a_Player->GetThrowStartPos();
- Vector3d Speed = a_Player->GetLookVector() * m_SpeedCoeff;
-
- // Play sound
- a_World->BroadcastSoundEffect("entity.arrow.shoot", a_Player->GetPosition() - Vector3d(0, a_Player->GetHeight(), 0), 0.5f, 0.4f / GetRandomProvider().RandReal(0.8f, 1.2f));
+ auto Pos = a_Player->GetThrowStartPos();
+ auto Speed = a_Player->GetLookVector() * m_SpeedCoeff;
+ // Create the projectile:
if (a_World->CreateProjectile(Pos.x, Pos.y, Pos.z, m_ProjectileKind, a_Player, &a_Player->GetEquippedItem(), &Speed) == cEntity::INVALID_ID)
{
return false;
}
+ // Play sound:
+ a_World->BroadcastSoundEffect("entity.arrow.shoot", a_Player->GetPosition() - Vector3d(0, a_Player->GetHeight(), 0), 0.5f, 0.4f / GetRandomProvider().RandReal(0.8f, 1.2f));
+
+ // Remove from inventory
if (!a_Player->IsGameModeCreative())
{
a_Player->GetInventory().RemoveOneEquippedItem();
@@ -48,7 +56,11 @@ public:
}
protected:
+
+ /** The kind of projectile to create when shooting */
cProjectileEntity::eKind m_ProjectileKind;
+
+ /** The speed multiplier (to the player's normalized look vector) to set for the new projectile. */
double m_SpeedCoeff;
} ;
@@ -137,17 +149,23 @@ public:
+
+
virtual bool OnItemUse(
- cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
- int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
+ cWorld * a_World,
+ cPlayer * a_Player,
+ cBlockPluginInterface & a_PluginInterface,
+ const cItem & a_HeldItem,
+ const Vector3i a_ClickedBlockPos,
+ eBlockFace a_ClickedBlockFace
) override
{
- if (a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_AIR)
+ if (a_World->GetBlock(a_ClickedBlockPos) == E_BLOCK_AIR)
{
return false;
}
- if (a_World->CreateProjectile(a_BlockX + 0.5, a_BlockY + 1, a_BlockZ + 0.5, m_ProjectileKind, a_Player, &a_Player->GetEquippedItem()) == 0)
+ if (a_World->CreateProjectile(Vector3d(a_ClickedBlockPos) + Vector3d(0.5, 1, 0.5), m_ProjectileKind, a_Player, &a_Player->GetEquippedItem()) == 0)
{
return false;
}