Vector3 in Handlers (#4680)
Refactored all cBlockHandler and cItemHandler descendants to use Vector3.
This commit is contained in:
parent
246acb19f9
commit
487f9a2aa9
|
@ -35,21 +35,34 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override
|
virtual bool OnUse(
|
||||||
|
cChunkInterface & a_ChunkInterface,
|
||||||
|
cWorldInterface & a_WorldInterface,
|
||||||
|
cPlayer & a_Player,
|
||||||
|
const Vector3i a_BlockPos,
|
||||||
|
eBlockFace a_BlockFace,
|
||||||
|
const Vector3i a_CursorPos
|
||||||
|
) override
|
||||||
{
|
{
|
||||||
cWindow * Window = new cAnvilWindow(a_BlockX, a_BlockY, a_BlockZ);
|
cWindow * Window = new cAnvilWindow(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z);
|
||||||
a_Player.OpenWindow(*Window);
|
a_Player.OpenWindow(*Window);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool GetPlacementBlockTypeMeta(
|
virtual bool GetPlacementBlockTypeMeta(
|
||||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
cChunkInterface & a_ChunkInterface,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
cPlayer & a_Player,
|
||||||
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
|
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
if (!Super::GetPlacementBlockTypeMeta(a_ChunkInterface, a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, a_BlockType, a_BlockMeta))
|
if (!Super::GetPlacementBlockTypeMeta(a_ChunkInterface, a_Player, a_PlacedBlockPos, a_ClickedBlockFace, a_CursorPos, a_BlockType, a_BlockMeta))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -58,11 +71,19 @@ public:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool IsUseable() override
|
virtual bool IsUseable() override
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
||||||
{
|
{
|
||||||
UNUSED(a_Meta);
|
UNUSED(a_Meta);
|
||||||
|
|
|
@ -15,7 +15,11 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cBlockBedHandler::OnBroken(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta)
|
void cBlockBedHandler::OnBroken(
|
||||||
|
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface,
|
||||||
|
const Vector3i a_BlockPos,
|
||||||
|
BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta
|
||||||
|
)
|
||||||
{
|
{
|
||||||
auto Direction = MetaDataToDirection(a_OldBlockMeta & 0x03);
|
auto Direction = MetaDataToDirection(a_OldBlockMeta & 0x03);
|
||||||
if ((a_OldBlockMeta & 0x08) != 0)
|
if ((a_OldBlockMeta & 0x08) != 0)
|
||||||
|
@ -50,87 +54,97 @@ void cBlockBedHandler::OnBroken(cChunkInterface & a_ChunkInterface, cWorldInterf
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cBlockBedHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ)
|
bool cBlockBedHandler::OnUse(
|
||||||
|
cChunkInterface & a_ChunkInterface,
|
||||||
|
cWorldInterface & a_WorldInterface,
|
||||||
|
cPlayer & a_Player,
|
||||||
|
const Vector3i a_BlockPos,
|
||||||
|
eBlockFace a_BlockFace,
|
||||||
|
const Vector3i a_CursorPos
|
||||||
|
)
|
||||||
{
|
{
|
||||||
Vector3i Coords(a_BlockX, a_BlockY, a_BlockZ);
|
// Sleeping in bed only allowed in Overworld, beds explode elsewhere:
|
||||||
if (a_WorldInterface.GetDimension() != dimOverworld)
|
if (a_WorldInterface.GetDimension() != dimOverworld)
|
||||||
{
|
{
|
||||||
a_WorldInterface.DoExplosionAt(5, a_BlockX, a_BlockY, a_BlockZ, true, esBed, &Coords);
|
auto PosCopy = a_BlockPos;
|
||||||
|
a_WorldInterface.DoExplosionAt(5, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, true, esBed, &PosCopy);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
else if (!((a_WorldInterface.GetTimeOfDay() > 12541) && (a_WorldInterface.GetTimeOfDay() < 23458))) // Source: https://minecraft.gamepedia.com/Bed#Sleeping
|
|
||||||
|
// Sleeping is allowed only during night:
|
||||||
|
// TODO: Also during thunderstorms
|
||||||
|
if (!((a_WorldInterface.GetTimeOfDay() > 12541) && (a_WorldInterface.GetTimeOfDay() < 23458))) // Source: https://minecraft.gamepedia.com/Bed#Sleeping
|
||||||
{
|
{
|
||||||
a_Player.SendMessageFailure("You can only sleep at night");
|
a_Player.SendMessageFailure("You can only sleep at night");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the bed is occupied:
|
||||||
|
auto Meta = a_ChunkInterface.GetBlockMeta(a_BlockPos);
|
||||||
|
if ((Meta & 0x04) == 0x04)
|
||||||
|
{
|
||||||
|
a_Player.SendMessageFailure("This bed is occupied");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cannot sleep if there are hostile mobs nearby:
|
||||||
|
auto FindMobs = [](cEntity & a_Entity)
|
||||||
|
{
|
||||||
|
return (
|
||||||
|
(a_Entity.GetEntityType() == cEntity::etMonster) &&
|
||||||
|
(static_cast<cMonster&>(a_Entity).GetMobFamily() == cMonster::mfHostile)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
if (!a_Player.GetWorld()->ForEachEntityInBox(cBoundingBox(a_Player.GetPosition() - Vector3i(0, 5, 0), 8, 10), FindMobs))
|
||||||
|
{
|
||||||
|
a_Player.SendMessageFailure("You may not rest now, there are monsters nearby");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Broadcast the "Use bed" for the pillow block:
|
||||||
|
if ((Meta & 0x8) == 0x8)
|
||||||
|
{
|
||||||
|
// Is pillow
|
||||||
|
a_WorldInterface.GetBroadcastManager().BroadcastUseBed(a_Player, a_BlockPos);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(Coords);
|
// Is foot end
|
||||||
if ((Meta & 0x4) == 0x4)
|
VERIFY((Meta & 0x04) != 0x04); // Occupied flag should never be set, else our compilator (intended) is broken
|
||||||
|
|
||||||
|
auto PillowPos = a_BlockPos + MetaDataToDirection(Meta & 0x03);
|
||||||
|
if (a_ChunkInterface.GetBlock(PillowPos) == E_BLOCK_BED) // Must always use pillow location for sleeping
|
||||||
{
|
{
|
||||||
a_Player.SendMessageFailure("This bed is occupied");
|
a_WorldInterface.GetBroadcastManager().BroadcastUseBed(a_Player, PillowPos);
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
|
||||||
|
// Occupy the bed:
|
||||||
|
a_Player.SetBedPos(a_BlockPos);
|
||||||
|
SetBedOccupationState(a_ChunkInterface, a_Player.GetLastBedPos(), true);
|
||||||
|
a_Player.SetIsInBed(true);
|
||||||
|
a_Player.SendMessageSuccess("Home position set successfully");
|
||||||
|
|
||||||
|
// Fast-forward the time if all players in the world are in their beds:
|
||||||
|
auto TimeFastForwardTester = [](cPlayer & a_OtherPlayer)
|
||||||
|
{
|
||||||
|
if (!a_OtherPlayer.IsInBed())
|
||||||
{
|
{
|
||||||
auto FindMobs = [](cEntity & a_Entity)
|
return true;
|
||||||
{
|
|
||||||
return (
|
|
||||||
(a_Entity.GetEntityType() == cEntity::etMonster) &&
|
|
||||||
(static_cast<cMonster&>(a_Entity).GetMobFamily() == cMonster::mfHostile)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!a_Player.GetWorld()->ForEachEntityInBox(cBoundingBox(a_Player.GetPosition() - Vector3i(0, 5, 0), 8, 10), FindMobs))
|
|
||||||
{
|
|
||||||
a_Player.SendMessageFailure("You may not rest now, there are monsters nearby");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Vector3i PillowDirection(0, 0, 0);
|
|
||||||
|
|
||||||
if ((Meta & 0x8) == 0x8)
|
|
||||||
{
|
|
||||||
// Is pillow
|
|
||||||
a_WorldInterface.GetBroadcastManager().BroadcastUseBed(a_Player, { a_BlockX, a_BlockY, a_BlockZ });
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Is foot end
|
|
||||||
VERIFY((Meta & 0x4) != 0x4); // Occupied flag should never be set, else our compilator (intended) is broken
|
|
||||||
|
|
||||||
PillowDirection = MetaDataToDirection(Meta & 0x3);
|
|
||||||
if (a_ChunkInterface.GetBlock(Coords + PillowDirection) == E_BLOCK_BED) // Must always use pillow location for sleeping
|
|
||||||
{
|
|
||||||
a_WorldInterface.GetBroadcastManager().BroadcastUseBed(a_Player, Vector3i{a_BlockX, a_BlockY, a_BlockZ} + PillowDirection);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
a_Player.SetBedPos(Coords);
|
|
||||||
SetBedOccupationState(a_ChunkInterface, a_Player.GetLastBedPos(), true);
|
|
||||||
a_Player.SetIsInBed(true);
|
|
||||||
a_Player.SendMessageSuccess("Home position set successfully");
|
|
||||||
|
|
||||||
auto TimeFastForwardTester = [](cPlayer & a_OtherPlayer)
|
|
||||||
{
|
|
||||||
if (!a_OtherPlayer.IsInBed())
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (a_WorldInterface.ForEachPlayer(TimeFastForwardTester))
|
|
||||||
{
|
|
||||||
a_WorldInterface.ForEachPlayer([&](cPlayer & a_OtherPlayer)
|
|
||||||
{
|
|
||||||
cBlockBedHandler::SetBedOccupationState(a_ChunkInterface, a_OtherPlayer.GetLastBedPos(), false);
|
|
||||||
a_OtherPlayer.SetIsInBed(false);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
a_WorldInterface.SetTimeOfDay(0);
|
|
||||||
a_ChunkInterface.SetBlockMeta({a_BlockX, a_BlockY, a_BlockZ}, Meta & 0x0b); // Clear the "occupied" bit of the bed's block
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
if (a_WorldInterface.ForEachPlayer(TimeFastForwardTester))
|
||||||
|
{
|
||||||
|
a_WorldInterface.ForEachPlayer([&](cPlayer & a_OtherPlayer)
|
||||||
|
{
|
||||||
|
cBlockBedHandler::SetBedOccupationState(a_ChunkInterface, a_OtherPlayer.GetLastBedPos(), false);
|
||||||
|
a_OtherPlayer.SetIsInBed(false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
a_WorldInterface.SetTimeOfDay(0);
|
||||||
|
a_ChunkInterface.SetBlockMeta(a_BlockPos, Meta & 0x0b); // Clear the "occupied" bit of the bed's block
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,10 +32,30 @@ public:
|
||||||
|
|
||||||
|
|
||||||
// Overrides:
|
// Overrides:
|
||||||
virtual void OnBroken(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta) override;
|
virtual void OnBroken(
|
||||||
virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override;
|
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface,
|
||||||
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override;
|
const Vector3i a_BlockPos,
|
||||||
virtual void OnPlacedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, const sSetBlock & a_BlockChange) override;
|
BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta
|
||||||
|
) override;
|
||||||
|
|
||||||
|
virtual bool OnUse(
|
||||||
|
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player,
|
||||||
|
const Vector3i a_ClickedBlockPos,
|
||||||
|
eBlockFace a_ClickedBlockFace,
|
||||||
|
const Vector3i a_CursorPos
|
||||||
|
) override;
|
||||||
|
|
||||||
|
virtual cItems ConvertToPickups(
|
||||||
|
NIBBLETYPE a_BlockMeta,
|
||||||
|
cBlockEntity * a_BlockEntity,
|
||||||
|
const cEntity * a_Digger,
|
||||||
|
const cItem * a_Tool
|
||||||
|
) override;
|
||||||
|
|
||||||
|
virtual void OnPlacedByPlayer(
|
||||||
|
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player,
|
||||||
|
const sSetBlock & a_BlockChange
|
||||||
|
) override;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cBlockBigFlowerHandler :
|
class cBlockBigFlowerHandler:
|
||||||
public cBlockHandler
|
public cBlockHandler
|
||||||
{
|
{
|
||||||
using Super = cBlockHandler;
|
using Super = cBlockHandler;
|
||||||
|
@ -95,15 +95,15 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
|
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override
|
||||||
{
|
{
|
||||||
if (a_RelY <= 0)
|
if (a_RelPos.y <= 0)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
BLOCKTYPE BlockType;
|
BLOCKTYPE BlockType;
|
||||||
NIBBLETYPE BlockMeta;
|
NIBBLETYPE BlockMeta;
|
||||||
a_Chunk.GetBlockTypeMeta(a_RelX, a_RelY - 1, a_RelZ, BlockType, BlockMeta);
|
a_Chunk.GetBlockTypeMeta(a_RelPos.addedY(-1), BlockType, BlockMeta);
|
||||||
|
|
||||||
return IsBlockTypeOfDirt(BlockType) || ((BlockType == E_BLOCK_BIG_FLOWER) && !IsMetaTopPart(BlockMeta));
|
return IsBlockTypeOfDirt(BlockType) || ((BlockType == E_BLOCK_BIG_FLOWER) && !IsMetaTopPart(BlockMeta));
|
||||||
}
|
}
|
||||||
|
@ -112,7 +112,7 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual void OnBroken(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta) override
|
virtual void OnBroken(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, const Vector3i a_BlockPos, BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta) override
|
||||||
{
|
{
|
||||||
if ((a_OldBlockMeta & 0x8) != 0)
|
if ((a_OldBlockMeta & 0x8) != 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -24,36 +24,40 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override
|
virtual bool OnUse(
|
||||||
|
cChunkInterface & a_ChunkInterface,
|
||||||
|
cWorldInterface & a_WorldInterface,
|
||||||
|
cPlayer & a_Player,
|
||||||
|
const Vector3i a_BlockPos,
|
||||||
|
eBlockFace a_BlockFace,
|
||||||
|
const Vector3i a_CursorPos
|
||||||
|
) override
|
||||||
{
|
{
|
||||||
Vector3i Pos(a_BlockX, a_BlockY, a_BlockZ);
|
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockPos);
|
||||||
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(Pos);
|
|
||||||
|
|
||||||
Vector3d SoundPos(Pos);
|
// If button is already on, do nothing:
|
||||||
|
|
||||||
// If button is already on do nothing
|
|
||||||
if (Meta & 0x08)
|
if (Meta & 0x08)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set p the ON bit to on
|
// Set the ON bit to on
|
||||||
Meta |= 0x08;
|
Meta |= 0x08;
|
||||||
|
|
||||||
a_ChunkInterface.SetBlockMeta({a_BlockX, a_BlockY, a_BlockZ}, Meta, false);
|
a_ChunkInterface.SetBlockMeta(a_BlockPos, Meta, false);
|
||||||
a_WorldInterface.WakeUpSimulators(Pos);
|
a_WorldInterface.WakeUpSimulators(a_BlockPos);
|
||||||
a_WorldInterface.GetBroadcastManager().BroadcastSoundEffect("block.stone_button.click_on", SoundPos, 0.5f, 0.6f);
|
a_WorldInterface.GetBroadcastManager().BroadcastSoundEffect("block.stone_button.click_on", a_BlockPos, 0.5f, 0.6f);
|
||||||
|
|
||||||
// Queue a button reset (unpress)
|
// Queue a button reset (unpress)
|
||||||
auto TickDelay = (m_BlockType == E_BLOCK_STONE_BUTTON) ? 20 : 30;
|
auto TickDelay = (m_BlockType == E_BLOCK_STONE_BUTTON) ? 20 : 30;
|
||||||
a_Player.GetWorld()->ScheduleTask(TickDelay, [SoundPos, Pos, this](cWorld & a_World)
|
a_Player.GetWorld()->ScheduleTask(TickDelay, [a_BlockPos, this](cWorld & a_World)
|
||||||
{
|
{
|
||||||
if (a_World.GetBlock(Pos) == m_BlockType)
|
if (a_World.GetBlock(a_BlockPos) == m_BlockType)
|
||||||
{
|
{
|
||||||
// Block hasn't change in the meantime; set its meta
|
// Block hasn't change in the meantime; set its meta
|
||||||
a_World.SetBlockMeta(Pos.x, Pos.y, Pos.z, a_World.GetBlockMeta(Pos) & 0x07, false);
|
a_World.SetBlockMeta(a_BlockPos, a_World.GetBlockMeta(a_BlockPos) & 0x07, false);
|
||||||
a_World.WakeUpSimulators(Pos);
|
a_World.WakeUpSimulators(a_BlockPos);
|
||||||
a_World.BroadcastSoundEffect("block.stone_button.click_off", SoundPos, 0.5f, 0.5f);
|
a_World.BroadcastSoundEffect("block.stone_button.click_off", a_BlockPos, 0.5f, 0.5f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -61,23 +65,38 @@ public:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool IsUseable(void) override
|
virtual bool IsUseable(void) override
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool GetPlacementBlockTypeMeta(
|
virtual bool GetPlacementBlockTypeMeta(
|
||||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
cChunkInterface & a_ChunkInterface,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
cPlayer & a_Player,
|
||||||
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
|
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
a_BlockType = m_BlockType;
|
a_BlockType = m_BlockType;
|
||||||
a_BlockMeta = BlockFaceToMetaData(a_BlockFace);
|
a_BlockMeta = BlockFaceToMetaData(a_ClickedBlockFace);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Converts the block face of the neighbor to which the button is attached, to the block meta for this button. */
|
||||||
inline static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_BlockFace)
|
inline static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_BlockFace)
|
||||||
{
|
{
|
||||||
switch (a_BlockFace)
|
switch (a_BlockFace)
|
||||||
|
@ -97,6 +116,11 @@ public:
|
||||||
UNREACHABLE("Unsupported block face");
|
UNREACHABLE("Unsupported block face");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Converts the block meta of this button into a block face of the neighbor to which the button is attached. */
|
||||||
inline static eBlockFace BlockMetaDataToBlockFace(NIBBLETYPE a_Meta)
|
inline static eBlockFace BlockMetaDataToBlockFace(NIBBLETYPE a_Meta)
|
||||||
{
|
{
|
||||||
switch (a_Meta & 0x7)
|
switch (a_Meta & 0x7)
|
||||||
|
@ -115,24 +139,39 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override
|
||||||
{
|
{
|
||||||
NIBBLETYPE Meta;
|
auto Meta = a_Chunk.GetMeta(a_RelPos);
|
||||||
a_Chunk.UnboundedRelGetBlockMeta(a_RelX, a_RelY, a_RelZ, Meta);
|
auto SupportRelPos = AddFaceDirection(a_RelPos, BlockMetaDataToBlockFace(Meta), true);
|
||||||
|
if (!cChunkDef::IsValidHeight(SupportRelPos.y))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
BLOCKTYPE SupportBlockType;
|
||||||
|
a_Chunk.UnboundedRelGetBlockType(SupportRelPos, SupportBlockType);
|
||||||
|
|
||||||
AddFaceDirection(a_RelX, a_RelY, a_RelZ, BlockMetaDataToBlockFace(Meta), true);
|
return cBlockInfo::FullyOccupiesVoxel(SupportBlockType);
|
||||||
BLOCKTYPE BlockIsOn; a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ, BlockIsOn);
|
|
||||||
|
|
||||||
return (a_RelY > 0) && (cBlockInfo::FullyOccupiesVoxel(BlockIsOn));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
||||||
{
|
{
|
||||||
UNUSED(a_Meta);
|
UNUSED(a_Meta);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Extracts the ON bit from metadata and returns if true if it is set */
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Extracts the ON bit from metadata. */
|
||||||
static bool IsButtonOn(NIBBLETYPE a_BlockMeta)
|
static bool IsButtonOn(NIBBLETYPE a_BlockMeta)
|
||||||
{
|
{
|
||||||
return ((a_BlockMeta & 0x8) == 0x8);
|
return ((a_BlockMeta & 0x8) == 0x8);
|
||||||
|
|
|
@ -23,13 +23,13 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
|
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override
|
||||||
{
|
{
|
||||||
if (a_RelY <= 0)
|
if (a_RelPos.y <= 0)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
BLOCKTYPE Surface = a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ);
|
BLOCKTYPE Surface = a_Chunk.GetBlock(a_RelPos.addedY(-1));
|
||||||
if ((Surface != E_BLOCK_SAND) && (Surface != E_BLOCK_CACTUS))
|
if ((Surface != E_BLOCK_SAND) && (Surface != E_BLOCK_CACTUS))
|
||||||
{
|
{
|
||||||
// Cactus can only be placed on sand and itself
|
// Cactus can only be placed on sand and itself
|
||||||
|
@ -37,22 +37,19 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check surroundings. Cacti may ONLY be surrounded by non-solid blocks
|
// Check surroundings. Cacti may ONLY be surrounded by non-solid blocks
|
||||||
static const struct
|
static const Vector3i Coords[] =
|
||||||
{
|
{
|
||||||
int x, z;
|
{-1, 0, 0},
|
||||||
} Coords[] =
|
{ 1, 0, 0},
|
||||||
{
|
{ 0, 0, -1},
|
||||||
{-1, 0},
|
{ 0, 0, 1},
|
||||||
{ 1, 0},
|
};
|
||||||
{ 0, -1},
|
|
||||||
{ 0, 1},
|
|
||||||
} ;
|
|
||||||
for (size_t i = 0; i < ARRAYCOUNT(Coords); i++)
|
for (size_t i = 0; i < ARRAYCOUNT(Coords); i++)
|
||||||
{
|
{
|
||||||
BLOCKTYPE BlockType;
|
BLOCKTYPE BlockType;
|
||||||
NIBBLETYPE BlockMeta;
|
NIBBLETYPE BlockMeta;
|
||||||
if (
|
if (
|
||||||
a_Chunk.UnboundedRelGetBlock(a_RelX + Coords[i].x, a_RelY, a_RelZ + Coords[i].z, BlockType, BlockMeta) &&
|
a_Chunk.UnboundedRelGetBlock(a_RelPos + Coords[i], BlockType, BlockMeta) &&
|
||||||
(
|
(
|
||||||
cBlockInfo::IsSolid(BlockType) ||
|
cBlockInfo::IsSolid(BlockType) ||
|
||||||
(BlockType == E_BLOCK_LAVA) ||
|
(BlockType == E_BLOCK_LAVA) ||
|
||||||
|
|
|
@ -20,9 +20,16 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override
|
virtual bool OnUse(
|
||||||
|
cChunkInterface & a_ChunkInterface,
|
||||||
|
cWorldInterface & a_WorldInterface,
|
||||||
|
cPlayer & a_Player,
|
||||||
|
const Vector3i a_BlockPos,
|
||||||
|
eBlockFace a_BlockFace,
|
||||||
|
const Vector3i a_CursorPos
|
||||||
|
) override
|
||||||
{
|
{
|
||||||
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta({a_BlockX, a_BlockY, a_BlockZ});
|
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockPos);
|
||||||
|
|
||||||
if (!a_Player.Feed(2, 0.4))
|
if (!a_Player.Feed(2, 0.4))
|
||||||
{
|
{
|
||||||
|
@ -31,11 +38,11 @@ public:
|
||||||
|
|
||||||
if (Meta >= 5)
|
if (Meta >= 5)
|
||||||
{
|
{
|
||||||
a_ChunkInterface.DigBlock(a_WorldInterface, {a_BlockX, a_BlockY, a_BlockZ});
|
a_ChunkInterface.DigBlock(a_WorldInterface, a_BlockPos);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
a_ChunkInterface.SetBlockMeta({a_BlockX, a_BlockY, a_BlockZ}, Meta + 1);
|
a_ChunkInterface.SetBlockMeta(a_BlockPos, Meta + 1);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,14 +14,14 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cBlockCarpetHandler :
|
class cBlockCarpetHandler:
|
||||||
public cBlockHandler
|
public cBlockHandler
|
||||||
{
|
{
|
||||||
using Super = cBlockHandler;
|
using Super = cBlockHandler;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
cBlockCarpetHandler(BLOCKTYPE a_BlockType) :
|
cBlockCarpetHandler(BLOCKTYPE a_BlockType):
|
||||||
Super(a_BlockType)
|
Super(a_BlockType)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -31,9 +31,11 @@ public:
|
||||||
|
|
||||||
|
|
||||||
virtual bool GetPlacementBlockTypeMeta(
|
virtual bool GetPlacementBlockTypeMeta(
|
||||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
cChunkInterface & a_ChunkInterface,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
cPlayer & a_Player,
|
||||||
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
|
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
|
@ -46,9 +48,9 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
|
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override
|
||||||
{
|
{
|
||||||
return (a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) != E_BLOCK_AIR);
|
return (a_RelPos.y > 0) && (a_Chunk.GetBlock(a_RelPos.addedY(-1)) != E_BLOCK_AIR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -32,9 +32,16 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override
|
virtual bool OnUse(
|
||||||
|
cChunkInterface & a_ChunkInterface,
|
||||||
|
cWorldInterface & a_WorldInterface,
|
||||||
|
cPlayer & a_Player,
|
||||||
|
const Vector3i a_BlockPos,
|
||||||
|
eBlockFace a_BlockFace,
|
||||||
|
const Vector3i a_CursorPos
|
||||||
|
) override
|
||||||
{
|
{
|
||||||
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta({a_BlockX, a_BlockY, a_BlockZ});
|
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockPos);
|
||||||
auto EquippedItem = a_Player.GetEquippedItem();
|
auto EquippedItem = a_Player.GetEquippedItem();
|
||||||
switch (EquippedItem.m_ItemType)
|
switch (EquippedItem.m_ItemType)
|
||||||
{
|
{
|
||||||
|
@ -42,7 +49,7 @@ public:
|
||||||
{
|
{
|
||||||
if (Meta == 3)
|
if (Meta == 3)
|
||||||
{
|
{
|
||||||
a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0);
|
a_ChunkInterface.SetBlockMeta(a_BlockPos, 0);
|
||||||
// Give new bucket, filled with fluid when the gamemode is not creative:
|
// Give new bucket, filled with fluid when the gamemode is not creative:
|
||||||
if (!a_Player.IsGameModeCreative())
|
if (!a_Player.IsGameModeCreative())
|
||||||
{
|
{
|
||||||
|
@ -55,7 +62,7 @@ public:
|
||||||
{
|
{
|
||||||
if (Meta < 3)
|
if (Meta < 3)
|
||||||
{
|
{
|
||||||
a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 3);
|
a_ChunkInterface.SetBlockMeta(a_BlockPos, 3);
|
||||||
// Give empty bucket back when the gamemode is not creative:
|
// Give empty bucket back when the gamemode is not creative:
|
||||||
if (!a_Player.IsGameModeCreative())
|
if (!a_Player.IsGameModeCreative())
|
||||||
{
|
{
|
||||||
|
@ -68,7 +75,7 @@ public:
|
||||||
{
|
{
|
||||||
if (Meta > 0)
|
if (Meta > 0)
|
||||||
{
|
{
|
||||||
a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, --Meta);
|
a_ChunkInterface.SetBlockMeta(a_BlockPos, --Meta);
|
||||||
// Give new potion when the gamemode is not creative:
|
// Give new potion when the gamemode is not creative:
|
||||||
if (!a_Player.IsGameModeCreative())
|
if (!a_Player.IsGameModeCreative())
|
||||||
{
|
{
|
||||||
|
@ -82,8 +89,8 @@ public:
|
||||||
// Refill cauldron with water bottles.
|
// Refill cauldron with water bottles.
|
||||||
if ((Meta < 3) && (EquippedItem.m_ItemDamage == 0))
|
if ((Meta < 3) && (EquippedItem.m_ItemDamage == 0))
|
||||||
{
|
{
|
||||||
a_ChunkInterface.SetBlockMeta(Vector3i(a_BlockX, a_BlockY, a_BlockZ), ++Meta);
|
a_ChunkInterface.SetBlockMeta(Vector3i(a_BlockPos), ++Meta);
|
||||||
// Give empty bottle when the gamemode is not creative:
|
// Give back an empty bottle when the gamemode is not creative:
|
||||||
if (!a_Player.IsGameModeCreative())
|
if (!a_Player.IsGameModeCreative())
|
||||||
{
|
{
|
||||||
a_Player.ReplaceOneEquippedItemTossRest(cItem(E_ITEM_GLASS_BOTTLE));
|
a_Player.ReplaceOneEquippedItemTossRest(cItem(E_ITEM_GLASS_BOTTLE));
|
||||||
|
|
|
@ -27,14 +27,16 @@ public:
|
||||||
|
|
||||||
|
|
||||||
virtual bool GetPlacementBlockTypeMeta(
|
virtual bool GetPlacementBlockTypeMeta(
|
||||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
cChunkInterface & a_ChunkInterface,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
cPlayer & a_Player,
|
||||||
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
|
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
// Is there a doublechest already next to this block?
|
// Cannot place right next to double-chest:
|
||||||
if (!CanBeAt(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ))
|
if (!CanBeAt(a_ChunkInterface, a_PlacedBlockPos))
|
||||||
{
|
{
|
||||||
// Yup, cannot form a triple-chest, refuse:
|
// Yup, cannot form a triple-chest, refuse:
|
||||||
return false;
|
return false;
|
||||||
|
@ -42,13 +44,13 @@ public:
|
||||||
|
|
||||||
// Try to read double-chest information:
|
// Try to read double-chest information:
|
||||||
cBlockArea Area;
|
cBlockArea Area;
|
||||||
if (!Area.Read(a_ChunkInterface, a_BlockX - 1, a_BlockX + 1, a_BlockY, a_BlockY, a_BlockZ - 1, a_BlockZ + 1))
|
if (!Area.Read(a_ChunkInterface, a_PlacedBlockPos - Vector3i(1, 0, 1), a_PlacedBlockPos + Vector3i(1, 0, 1)))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get meta as if this was a single-chest:
|
// Get meta as if this was a single-chest:
|
||||||
if (!Super::GetPlacementBlockTypeMeta(a_ChunkInterface, a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, a_BlockType, a_BlockMeta))
|
if (!Super::GetPlacementBlockTypeMeta(a_ChunkInterface, a_Player, a_PlacedBlockPos, a_ClickedBlockFace, a_CursorPos, a_BlockType, a_BlockMeta))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -80,21 +82,20 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
|
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override
|
||||||
{
|
{
|
||||||
int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width;
|
auto BlockPos = a_Chunk.RelativeToAbsolute(a_RelPos);
|
||||||
int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width;
|
return CanBeAt(a_ChunkInterface, BlockPos);
|
||||||
return CanBeAt(a_ChunkInterface, BlockX, a_RelY, BlockZ);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ)
|
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_BlockPos)
|
||||||
{
|
{
|
||||||
cBlockArea Area;
|
cBlockArea Area;
|
||||||
if (!Area.Read(a_ChunkInterface, a_BlockX - 2, a_BlockX + 2, a_BlockY, a_BlockY, a_BlockZ - 2, a_BlockZ + 2))
|
if (!Area.Read(a_ChunkInterface, a_BlockPos - Vector3i(2, 0, 2), a_BlockPos + Vector3i(2, 0, 2)))
|
||||||
{
|
{
|
||||||
// Cannot read the surroundings, probably at the edge of loaded chunks. Disallow.
|
// Cannot read the surroundings, probably at the edge of loaded chunks. Disallow.
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -22,16 +22,15 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
|
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override
|
||||||
{
|
{
|
||||||
eBlockFace BlockFace = MetaToBlockFace(a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ));
|
// Check that we're attached to a jungle log block:
|
||||||
AddFaceDirection(a_RelX, a_RelY, a_RelZ, BlockFace, true);
|
eBlockFace BlockFace = MetaToBlockFace(a_Chunk.GetMeta(a_RelPos));
|
||||||
|
auto LogPos = AddFaceDirection(a_RelPos, BlockFace, true);
|
||||||
BLOCKTYPE BlockType;
|
BLOCKTYPE BlockType;
|
||||||
NIBBLETYPE BlockMeta;
|
NIBBLETYPE BlockMeta;
|
||||||
a_Chunk.UnboundedRelGetBlock(a_RelX, a_RelY, a_RelZ, BlockType, BlockMeta);
|
a_Chunk.UnboundedRelGetBlock(LogPos, BlockType, BlockMeta);
|
||||||
|
return ((BlockType == E_BLOCK_LOG) && ((BlockMeta & 0x03) == E_META_LOG_JUNGLE));
|
||||||
return ((BlockType == E_BLOCK_LOG) && ((BlockMeta & 0x3) == E_META_LOG_JUNGLE));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -21,45 +21,114 @@ public:
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
virtual bool OnUse(
|
||||||
|
cChunkInterface & a_ChunkInterface,
|
||||||
|
cWorldInterface & a_WorldInterface,
|
||||||
|
cPlayer & a_Player,
|
||||||
|
const Vector3i a_BlockPos,
|
||||||
|
eBlockFace a_BlockFace,
|
||||||
|
const Vector3i a_CursorPos
|
||||||
|
) override
|
||||||
{
|
{
|
||||||
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta({a_BlockX, a_BlockY, a_BlockZ});
|
// Toggle the 3rd bit (addition / subtraction):
|
||||||
Meta ^= 0x04; // Toggle 3rd (addition / subtraction) bit with XOR
|
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockPos);
|
||||||
a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta);
|
Meta ^= 0x04;
|
||||||
|
a_ChunkInterface.SetBlockMeta(a_BlockPos, Meta);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
virtual void OnCancelRightClick(
|
||||||
|
cChunkInterface & a_ChunkInterface,
|
||||||
|
cWorldInterface & a_WorldInterface,
|
||||||
|
cPlayer & a_Player,
|
||||||
|
const Vector3i a_BlockPos,
|
||||||
|
eBlockFace a_BlockFace
|
||||||
|
) override
|
||||||
{
|
{
|
||||||
UNUSED(a_ChunkInterface);
|
UNUSED(a_ChunkInterface);
|
||||||
a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
|
UNUSED(a_BlockFace);
|
||||||
|
|
||||||
|
a_WorldInterface.SendBlockTo(a_BlockPos, a_Player);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool IsUseable(void) override
|
virtual bool IsUseable(void) override
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override
|
||||||
{
|
{
|
||||||
return ((a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) != E_BLOCK_AIR));
|
if (a_RelPos.y <= 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
BLOCKTYPE BelowBlock;
|
||||||
|
NIBBLETYPE BelowBlockMeta;
|
||||||
|
a_Chunk.GetBlockTypeMeta(a_RelPos.addedY(-1), BelowBlock, BelowBlockMeta);
|
||||||
|
|
||||||
|
if (cBlockInfo::FullyOccupiesVoxel(BelowBlock))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (cBlockSlabHandler::IsAnySlabType(BelowBlock))
|
||||||
|
{
|
||||||
|
// Check if the slab is turned up side down
|
||||||
|
if ((BelowBlockMeta & 0x08) == 0x08)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
|
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
|
||||||
{
|
{
|
||||||
return cItem(E_ITEM_COMPARATOR, 1, 0);
|
return cItem(E_ITEM_COMPARATOR, 1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
inline static bool IsInSubtractionMode(NIBBLETYPE a_Meta)
|
inline static bool IsInSubtractionMode(NIBBLETYPE a_Meta)
|
||||||
{
|
{
|
||||||
return ((a_Meta & 0x4) == 0x4);
|
return ((a_Meta & 0x4) == 0x4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
inline static bool IsOn(NIBBLETYPE a_Meta)
|
inline static bool IsOn(NIBBLETYPE a_Meta)
|
||||||
{
|
{
|
||||||
return ((a_Meta & 0x8) == 0x8);
|
return ((a_Meta & 0x8) == 0x8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
inline static Vector3i GetSideCoordinate(Vector3i a_Position, NIBBLETYPE a_Meta, bool a_bInverse)
|
inline static Vector3i GetSideCoordinate(Vector3i a_Position, NIBBLETYPE a_Meta, bool a_bInverse)
|
||||||
{
|
{
|
||||||
if (!a_bInverse)
|
if (!a_bInverse)
|
||||||
|
@ -98,6 +167,10 @@ public:
|
||||||
return a_Position;
|
return a_Position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
inline static Vector3i GetRearCoordinate(Vector3i a_Position, NIBBLETYPE a_Meta)
|
inline static Vector3i GetRearCoordinate(Vector3i a_Position, NIBBLETYPE a_Meta)
|
||||||
{
|
{
|
||||||
switch (a_Meta)
|
switch (a_Meta)
|
||||||
|
@ -117,6 +190,10 @@ public:
|
||||||
return a_Position;
|
return a_Position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
inline static Vector3i GetFrontCoordinate(Vector3i a_Position, NIBBLETYPE a_Meta)
|
inline static Vector3i GetFrontCoordinate(Vector3i a_Position, NIBBLETYPE a_Meta)
|
||||||
{
|
{
|
||||||
switch (a_Meta)
|
switch (a_Meta)
|
||||||
|
@ -136,6 +213,10 @@ public:
|
||||||
return a_Position;
|
return a_Position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
||||||
{
|
{
|
||||||
UNUSED(a_Meta);
|
UNUSED(a_Meta);
|
||||||
|
|
|
@ -108,13 +108,15 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
|
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override
|
||||||
{
|
{
|
||||||
return ((a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) == E_BLOCK_FARMLAND));
|
return ((a_RelPos.y > 0) && (a_Chunk.GetBlock(a_RelPos.addedY(-1)) == E_BLOCK_FARMLAND));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
||||||
{
|
{
|
||||||
UNUSED(a_Meta);
|
UNUSED(a_Meta);
|
||||||
|
|
|
@ -31,14 +31,14 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
|
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override
|
||||||
{
|
{
|
||||||
if (a_RelY <= 0)
|
if (a_RelPos.y <= 0)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
BLOCKTYPE BelowBlock = a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ);
|
BLOCKTYPE BelowBlock = a_Chunk.GetBlock(a_RelPos.addedY(-1));
|
||||||
switch (BelowBlock)
|
switch (BelowBlock)
|
||||||
{
|
{
|
||||||
case E_BLOCK_CLAY:
|
case E_BLOCK_CLAY:
|
||||||
|
|
|
@ -40,15 +40,20 @@ void cBlockDoorHandler::OnBroken(cChunkInterface & a_ChunkInterface, cWorldInter
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cBlockDoorHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ)
|
bool cBlockDoorHandler::OnUse(
|
||||||
|
cChunkInterface & a_ChunkInterface,
|
||||||
|
cWorldInterface & a_WorldInterface,
|
||||||
|
cPlayer & a_Player,
|
||||||
|
const Vector3i a_BlockPos,
|
||||||
|
eBlockFace a_BlockFace,
|
||||||
|
const Vector3i a_CursorPos
|
||||||
|
)
|
||||||
{
|
{
|
||||||
UNUSED(a_WorldInterface);
|
UNUSED(a_WorldInterface);
|
||||||
UNUSED(a_BlockFace);
|
UNUSED(a_BlockFace);
|
||||||
UNUSED(a_CursorX);
|
UNUSED(a_CursorPos);
|
||||||
UNUSED(a_CursorY);
|
|
||||||
UNUSED(a_CursorZ);
|
|
||||||
|
|
||||||
switch (a_ChunkInterface.GetBlock({a_BlockX, a_BlockY, a_BlockZ}))
|
switch (a_ChunkInterface.GetBlock(a_BlockPos))
|
||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
|
@ -61,14 +66,14 @@ bool cBlockDoorHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterfac
|
||||||
case E_BLOCK_SPRUCE_DOOR:
|
case E_BLOCK_SPRUCE_DOOR:
|
||||||
case E_BLOCK_OAK_DOOR:
|
case E_BLOCK_OAK_DOOR:
|
||||||
{
|
{
|
||||||
ChangeDoor(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ);
|
ChangeDoor(a_ChunkInterface, a_BlockPos);
|
||||||
a_Player.GetWorld()->BroadcastSoundParticleEffect(EffectID::SFX_RANDOM_WOODEN_DOOR_OPEN, {a_BlockX, a_BlockY, a_BlockZ}, 0, a_Player.GetClientHandle());
|
a_Player.GetWorld()->BroadcastSoundParticleEffect(EffectID::SFX_RANDOM_WOODEN_DOOR_OPEN, a_BlockPos, 0, a_Player.GetClientHandle());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Prevent iron door from opening on player click
|
// Prevent iron door from opening on player click
|
||||||
case E_BLOCK_IRON_DOOR:
|
case E_BLOCK_IRON_DOOR:
|
||||||
{
|
{
|
||||||
OnCancelRightClick(a_ChunkInterface, a_WorldInterface, a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
|
OnCancelRightClick(a_ChunkInterface, a_WorldInterface, a_Player, a_BlockPos, a_BlockFace);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,22 +85,29 @@ bool cBlockDoorHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterfac
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cBlockDoorHandler::OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace)
|
void cBlockDoorHandler::OnCancelRightClick(
|
||||||
|
cChunkInterface & a_ChunkInterface,
|
||||||
|
cWorldInterface & a_WorldInterface,
|
||||||
|
cPlayer & a_Player,
|
||||||
|
const Vector3i a_BlockPos,
|
||||||
|
eBlockFace a_BlockFace
|
||||||
|
)
|
||||||
{
|
{
|
||||||
UNUSED(a_ChunkInterface);
|
UNUSED(a_ChunkInterface);
|
||||||
|
UNUSED(a_BlockFace);
|
||||||
|
|
||||||
a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
|
a_WorldInterface.SendBlockTo(a_BlockPos, a_Player);
|
||||||
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta({a_BlockX, a_BlockY, a_BlockZ});
|
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockPos);
|
||||||
|
|
||||||
if (Meta & 0x8)
|
if (Meta & 0x08)
|
||||||
{
|
{
|
||||||
// Current block is top of the door
|
// Current block is top of the door, send the bottom part:
|
||||||
a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY - 1, a_BlockZ, a_Player);
|
a_WorldInterface.SendBlockTo(a_BlockPos.addedY(-1), a_Player);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Current block is bottom of the door
|
// Current block is bottom of the door, send the top part:
|
||||||
a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY + 1, a_BlockZ, a_Player);
|
a_WorldInterface.SendBlockTo(a_BlockPos.addedY(1), a_Player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,37 +20,63 @@ public:
|
||||||
|
|
||||||
cBlockDoorHandler(BLOCKTYPE a_BlockType);
|
cBlockDoorHandler(BLOCKTYPE a_BlockType);
|
||||||
|
|
||||||
virtual void OnBroken(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta) override;
|
virtual void OnBroken(
|
||||||
virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override;
|
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface,
|
||||||
virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override;
|
Vector3i a_BlockPos,
|
||||||
|
BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta
|
||||||
|
) override;
|
||||||
|
|
||||||
|
virtual bool OnUse(
|
||||||
|
cChunkInterface & a_ChunkInterface,
|
||||||
|
cWorldInterface & a_WorldInterface,
|
||||||
|
cPlayer & a_Player,
|
||||||
|
const Vector3i a_BlockPos,
|
||||||
|
eBlockFace a_BlockFace,
|
||||||
|
const Vector3i a_CursorPos
|
||||||
|
) override;
|
||||||
|
|
||||||
|
virtual void OnCancelRightClick(
|
||||||
|
cChunkInterface & a_ChunkInterface,
|
||||||
|
cWorldInterface & a_WorldInterface,
|
||||||
|
cPlayer & a_Player,
|
||||||
|
const Vector3i a_BlockPos,
|
||||||
|
eBlockFace a_BlockFace
|
||||||
|
) override;
|
||||||
|
|
||||||
virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override;
|
virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override;
|
||||||
virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override;
|
virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override;
|
||||||
virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override;
|
virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override;
|
||||||
virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override;
|
virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool GetPlacementBlockTypeMeta(
|
virtual bool GetPlacementBlockTypeMeta(
|
||||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
cChunkInterface & a_ChunkInterface,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
cPlayer & a_Player,
|
||||||
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
|
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
// If clicking a bottom face, place the door one block lower:
|
// If clicking a bottom face, place the door one block lower:
|
||||||
if (a_BlockFace == BLOCK_FACE_BOTTOM)
|
auto PlacedPos = a_PlacedBlockPos;
|
||||||
|
if (a_ClickedBlockFace == BLOCK_FACE_BOTTOM)
|
||||||
{
|
{
|
||||||
a_BlockY--;
|
PlacedPos.y--;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!CanReplaceBlock(a_ChunkInterface.GetBlock({a_BlockX, a_BlockY, a_BlockZ})) ||
|
!CanReplaceBlock(a_ChunkInterface.GetBlock(PlacedPos)) ||
|
||||||
!CanReplaceBlock(a_ChunkInterface.GetBlock({a_BlockX, a_BlockY + 1, a_BlockZ}))
|
!CanReplaceBlock(a_ChunkInterface.GetBlock(PlacedPos.addedY(1)))
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Super::GetPlacementBlockTypeMeta(a_ChunkInterface, a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, a_BlockType, a_BlockMeta);
|
return Super::GetPlacementBlockTypeMeta(a_ChunkInterface, a_Player, PlacedPos, a_ClickedBlockFace, a_CursorPos, a_BlockType, a_BlockMeta);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual cBoundingBox GetPlacementCollisionBox(BLOCKTYPE a_XM, BLOCKTYPE a_XP, BLOCKTYPE a_YM, BLOCKTYPE a_YP, BLOCKTYPE a_ZM, BLOCKTYPE a_ZP) override;
|
virtual cBoundingBox GetPlacementCollisionBox(BLOCKTYPE a_XM, BLOCKTYPE a_XP, BLOCKTYPE a_YM, BLOCKTYPE a_YP, BLOCKTYPE a_ZM, BLOCKTYPE a_ZP) override;
|
||||||
|
@ -93,11 +119,19 @@ public:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override
|
||||||
{
|
{
|
||||||
return ((a_RelY > 0) && CanBeOn(a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ), a_Chunk.GetMeta(a_RelX, a_RelY - 1, a_RelZ)));
|
return ((a_RelPos.y > 0) && CanBeOn(a_Chunk.GetBlock(a_RelPos.addedY(-1)), a_Chunk.GetMeta(a_RelPos.addedY(-1))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Returns true if door can be placed on the specified block type. */
|
/** Returns true if door can be placed on the specified block type. */
|
||||||
static bool CanBeOn(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
|
static bool CanBeOn(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
|
||||||
{
|
{
|
||||||
|
@ -188,9 +222,9 @@ public:
|
||||||
|
|
||||||
/** Returns true iff the door at the specified coords is open.
|
/** Returns true iff the door at the specified coords is open.
|
||||||
The coords may point to either the top part or the bottom part of the door. */
|
The coords may point to either the top part or the bottom part of the door. */
|
||||||
static NIBBLETYPE IsOpen(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ)
|
static NIBBLETYPE IsOpen(cChunkInterface & a_ChunkInterface, const Vector3i a_BlockPos)
|
||||||
{
|
{
|
||||||
NIBBLETYPE Meta = GetCompleteDoorMeta(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ);
|
NIBBLETYPE Meta = GetCompleteDoorMeta(a_ChunkInterface, a_BlockPos);
|
||||||
return ((Meta & 0x04) != 0);
|
return ((Meta & 0x04) != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,17 +235,17 @@ public:
|
||||||
/** Returns the complete meta composed from the both parts of the door as (TopMeta << 4) | BottomMeta
|
/** Returns the complete meta composed from the both parts of the door as (TopMeta << 4) | BottomMeta
|
||||||
The coords may point to either part of the door.
|
The coords may point to either part of the door.
|
||||||
The returned value has bit 3 (0x08) set iff the coords point to the top part of the door.
|
The returned value has bit 3 (0x08) set iff the coords point to the top part of the door.
|
||||||
Fails gracefully for (invalid) doors on the world's top and bottom. */
|
Fails silently for (invalid) doors on the world's top and bottom. */
|
||||||
static NIBBLETYPE GetCompleteDoorMeta(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ)
|
static NIBBLETYPE GetCompleteDoorMeta(cChunkInterface & a_ChunkInterface, const Vector3i a_BlockPos)
|
||||||
{
|
{
|
||||||
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta({a_BlockX, a_BlockY, a_BlockZ});
|
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockPos);
|
||||||
|
|
||||||
if ((Meta & 0x08) != 0)
|
if ((Meta & 0x08) != 0)
|
||||||
{
|
{
|
||||||
// The coords are pointing at the top part of the door
|
// The coords are pointing at the top part of the door
|
||||||
if (a_BlockY > 0)
|
if (a_BlockPos.y > 0)
|
||||||
{
|
{
|
||||||
NIBBLETYPE DownMeta = a_ChunkInterface.GetBlockMeta({a_BlockX, a_BlockY - 1, a_BlockZ});
|
NIBBLETYPE DownMeta = a_ChunkInterface.GetBlockMeta(a_BlockPos.addedY(-1));
|
||||||
return static_cast<NIBBLETYPE>((DownMeta & 0x07) | 0x08 | (Meta << 4));
|
return static_cast<NIBBLETYPE>((DownMeta & 0x07) | 0x08 | (Meta << 4));
|
||||||
}
|
}
|
||||||
// This is the top part of the door at the bottommost layer of the world, there's no bottom:
|
// This is the top part of the door at the bottommost layer of the world, there's no bottom:
|
||||||
|
@ -220,9 +254,9 @@ public:
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// The coords are pointing at the bottom part of the door
|
// The coords are pointing at the bottom part of the door
|
||||||
if (a_BlockY < cChunkDef::Height - 1)
|
if (a_BlockPos.y < cChunkDef::Height - 1)
|
||||||
{
|
{
|
||||||
NIBBLETYPE UpMeta = a_ChunkInterface.GetBlockMeta({a_BlockX, a_BlockY + 1, a_BlockZ});
|
NIBBLETYPE UpMeta = a_ChunkInterface.GetBlockMeta(a_BlockPos.addedY(1));
|
||||||
return static_cast<NIBBLETYPE>(Meta | (UpMeta << 4));
|
return static_cast<NIBBLETYPE>(Meta | (UpMeta << 4));
|
||||||
}
|
}
|
||||||
// This is the bottom part of the door at the topmost layer of the world, there's no top:
|
// This is the bottom part of the door at the topmost layer of the world, there's no top:
|
||||||
|
@ -235,15 +269,15 @@ public:
|
||||||
|
|
||||||
|
|
||||||
/** Sets the door to the specified state. If the door is already in that state, does nothing. */
|
/** Sets the door to the specified state. If the door is already in that state, does nothing. */
|
||||||
static void SetOpen(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ, bool a_Open)
|
static void SetOpen(cChunkInterface & a_ChunkInterface, const Vector3i a_BlockPos, bool a_Open)
|
||||||
{
|
{
|
||||||
BLOCKTYPE Block = a_ChunkInterface.GetBlock({a_BlockX, a_BlockY, a_BlockZ});
|
BLOCKTYPE Block = a_ChunkInterface.GetBlock(a_BlockPos);
|
||||||
if (!IsDoorBlockType(Block))
|
if (!IsDoorBlockType(Block))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NIBBLETYPE Meta = GetCompleteDoorMeta(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ);
|
NIBBLETYPE Meta = GetCompleteDoorMeta(a_ChunkInterface, a_BlockPos);
|
||||||
bool IsOpened = ((Meta & 0x04) != 0);
|
bool IsOpened = ((Meta & 0x04) != 0);
|
||||||
if (IsOpened == a_Open)
|
if (IsOpened == a_Open)
|
||||||
{
|
{
|
||||||
|
@ -255,14 +289,14 @@ public:
|
||||||
if ((Meta & 0x08) == 0)
|
if ((Meta & 0x08) == 0)
|
||||||
{
|
{
|
||||||
// The block is the bottom part of the door
|
// The block is the bottom part of the door
|
||||||
a_ChunkInterface.SetBlockMeta({a_BlockX, a_BlockY, a_BlockZ}, NewMeta);
|
a_ChunkInterface.SetBlockMeta(a_BlockPos, NewMeta);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// The block is the top part of the door, set the meta to the corresponding top part
|
// The block is the top part of the door, set the meta to the corresponding top part
|
||||||
if (a_BlockY > 0)
|
if (a_BlockPos.y > 0)
|
||||||
{
|
{
|
||||||
a_ChunkInterface.SetBlockMeta({a_BlockX, a_BlockY - 1, a_BlockZ}, NewMeta);
|
a_ChunkInterface.SetBlockMeta(a_BlockPos.addedY(-1), NewMeta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -272,9 +306,9 @@ public:
|
||||||
|
|
||||||
|
|
||||||
/** Changes the door at the specified coords from open to close or vice versa */
|
/** Changes the door at the specified coords from open to close or vice versa */
|
||||||
static void ChangeDoor(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ)
|
static void ChangeDoor(cChunkInterface & a_ChunkInterface, const Vector3i a_BlockPos)
|
||||||
{
|
{
|
||||||
SetOpen(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ, !IsOpen(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ));
|
SetOpen(a_ChunkInterface, a_BlockPos, !IsOpen(a_ChunkInterface, a_BlockPos));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -9,27 +9,49 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cBlockEnchantmentTableHandler :
|
class cBlockEnchantmentTableHandler:
|
||||||
public cBlockHandler
|
public cBlockHandler
|
||||||
{
|
{
|
||||||
|
using Super = cBlockHandler;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
cBlockEnchantmentTableHandler(BLOCKTYPE a_BlockType)
|
|
||||||
: cBlockHandler(a_BlockType)
|
cBlockEnchantmentTableHandler(BLOCKTYPE a_BlockType):
|
||||||
|
Super(a_BlockType)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
virtual bool OnUse(
|
||||||
|
cChunkInterface & a_ChunkInterface,
|
||||||
|
cWorldInterface & a_WorldInterface,
|
||||||
|
cPlayer & a_Player,
|
||||||
|
const Vector3i a_BlockPos,
|
||||||
|
eBlockFace a_BlockFace,
|
||||||
|
const Vector3i a_CursorPos
|
||||||
|
) override
|
||||||
{
|
{
|
||||||
cWindow * Window = new cEnchantingWindow(a_BlockX, a_BlockY, a_BlockZ);
|
cWindow * Window = new cEnchantingWindow(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z);
|
||||||
a_Player.OpenWindow(*Window);
|
a_Player.OpenWindow(*Window);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool IsUseable(void) override
|
virtual bool IsUseable(void) override
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
||||||
{
|
{
|
||||||
UNUSED(a_Meta);
|
UNUSED(a_Meta);
|
||||||
|
|
|
@ -7,22 +7,26 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cBlockEndPortalFrameHandler :
|
class cBlockEndPortalFrameHandler:
|
||||||
public cMetaRotator<cBlockHandler, 0x03,
|
public cMetaRotator<cBlockHandler, 0x03,
|
||||||
E_META_END_PORTAL_FRAME_ZM,
|
|
||||||
E_META_END_PORTAL_FRAME_XP,
|
|
||||||
E_META_END_PORTAL_FRAME_ZP,
|
|
||||||
E_META_END_PORTAL_FRAME_XM
|
|
||||||
>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
cBlockEndPortalFrameHandler(BLOCKTYPE a_BlockType):
|
|
||||||
cMetaRotator<cBlockHandler, 0x03,
|
|
||||||
E_META_END_PORTAL_FRAME_ZM,
|
E_META_END_PORTAL_FRAME_ZM,
|
||||||
E_META_END_PORTAL_FRAME_XP,
|
E_META_END_PORTAL_FRAME_XP,
|
||||||
E_META_END_PORTAL_FRAME_ZP,
|
E_META_END_PORTAL_FRAME_ZP,
|
||||||
E_META_END_PORTAL_FRAME_XM
|
E_META_END_PORTAL_FRAME_XM
|
||||||
>(a_BlockType)
|
>
|
||||||
|
{
|
||||||
|
using Super = cMetaRotator<
|
||||||
|
cBlockHandler, 0x03,
|
||||||
|
E_META_END_PORTAL_FRAME_ZM,
|
||||||
|
E_META_END_PORTAL_FRAME_XP,
|
||||||
|
E_META_END_PORTAL_FRAME_ZP,
|
||||||
|
E_META_END_PORTAL_FRAME_XM
|
||||||
|
>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
cBlockEndPortalFrameHandler(BLOCKTYPE a_BlockType):
|
||||||
|
Super(a_BlockType)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,9 +35,11 @@ public:
|
||||||
|
|
||||||
|
|
||||||
virtual bool GetPlacementBlockTypeMeta(
|
virtual bool GetPlacementBlockTypeMeta(
|
||||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
cChunkInterface & a_ChunkInterface,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
cPlayer & a_Player,
|
||||||
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
|
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
|
|
|
@ -28,9 +28,16 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override
|
virtual bool OnUse(
|
||||||
|
cChunkInterface & a_ChunkInterface,
|
||||||
|
cWorldInterface & a_WorldInterface,
|
||||||
|
cPlayer & a_Player,
|
||||||
|
const Vector3i a_BlockPos,
|
||||||
|
eBlockFace a_BlockFace,
|
||||||
|
const Vector3i a_CursorPos
|
||||||
|
) override
|
||||||
{
|
{
|
||||||
return a_ChunkInterface.UseBlockEntity(&a_Player, a_BlockX, a_BlockY, a_BlockZ);
|
return a_ChunkInterface.UseBlockEntity(&a_Player, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -10,21 +10,28 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cBlockFenceHandler :
|
class cBlockFenceHandler:
|
||||||
public cBlockHandler
|
public cBlockHandler
|
||||||
{
|
{
|
||||||
|
using Super = cBlockHandler;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// These are the min and max coordinates (X and Z) for a straight fence.
|
// These are the min and max coordinates (X and Z) for a straight fence.
|
||||||
// 0.4 and 0.6 are really just guesses, but they seem pretty good.
|
// 0.4 and 0.6 are really just guesses, but they seem pretty good.
|
||||||
// (0.4 to 0.6 is a fence that's 0.2 wide, down the center of the block)
|
// (0.4 to 0.6 is a fence that's 0.2 wide, down the center of the block)
|
||||||
const double MIN_COORD = 0.4;
|
const double MIN_COORD = 0.4;
|
||||||
const double MAX_COORD = 0.6;
|
const double MAX_COORD = 0.6;
|
||||||
|
|
||||||
cBlockFenceHandler(BLOCKTYPE a_BlockType)
|
cBlockFenceHandler(BLOCKTYPE a_BlockType):
|
||||||
: cBlockHandler(a_BlockType)
|
Super(a_BlockType)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual cBoundingBox GetPlacementCollisionBox(BLOCKTYPE a_XM, BLOCKTYPE a_XP, BLOCKTYPE a_YM, BLOCKTYPE a_YP, BLOCKTYPE a_ZM, BLOCKTYPE a_ZP) override
|
virtual cBoundingBox GetPlacementCollisionBox(BLOCKTYPE a_XM, BLOCKTYPE a_XP, BLOCKTYPE a_YM, BLOCKTYPE a_YP, BLOCKTYPE a_ZM, BLOCKTYPE a_ZP) override
|
||||||
{
|
{
|
||||||
bool XMSolid = cBlockInfo::IsSolid(a_XM);
|
bool XMSolid = cBlockInfo::IsSolid(a_XM);
|
||||||
|
@ -76,9 +83,20 @@ public:
|
||||||
return PlacementBox;
|
return PlacementBox;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
virtual bool OnUse(
|
||||||
|
cChunkInterface & a_ChunkInterface,
|
||||||
|
cWorldInterface & a_WorldInterface,
|
||||||
|
cPlayer & a_Player,
|
||||||
|
const Vector3i a_BlockPos,
|
||||||
|
eBlockFace a_BlockFace,
|
||||||
|
const Vector3i a_CursorPos
|
||||||
|
) override
|
||||||
{
|
{
|
||||||
auto LeashKnot = cLeashKnot::FindKnotAtPos(*a_Player.GetWorld(), { a_BlockX, a_BlockY, a_BlockZ });
|
auto LeashKnot = cLeashKnot::FindKnotAtPos(*a_Player.GetWorld(), a_BlockPos);
|
||||||
auto KnotAlreadyExists = (LeashKnot != nullptr);
|
auto KnotAlreadyExists = (LeashKnot != nullptr);
|
||||||
|
|
||||||
if (KnotAlreadyExists)
|
if (KnotAlreadyExists)
|
||||||
|
@ -89,7 +107,7 @@ public:
|
||||||
// New knot? needs to init and produce sound effect
|
// New knot? needs to init and produce sound effect
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto NewLeashKnot = cpp14::make_unique<cLeashKnot>(a_BlockFace, Vector3i{a_BlockX, a_BlockY, a_BlockZ});
|
auto NewLeashKnot = cpp14::make_unique<cLeashKnot>(a_BlockFace, a_BlockPos);
|
||||||
auto NewLeashKnotPtr = NewLeashKnot.get();
|
auto NewLeashKnotPtr = NewLeashKnot.get();
|
||||||
|
|
||||||
NewLeashKnotPtr->TiePlayersLeashedMobs(a_Player, KnotAlreadyExists);
|
NewLeashKnotPtr->TiePlayersLeashedMobs(a_Player, KnotAlreadyExists);
|
||||||
|
@ -112,11 +130,25 @@ public:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
virtual void OnCancelRightClick(
|
||||||
|
cChunkInterface & a_ChunkInterface,
|
||||||
|
cWorldInterface & a_WorldInterface,
|
||||||
|
cPlayer & a_Player,
|
||||||
|
const Vector3i a_BlockPos,
|
||||||
|
eBlockFace a_BlockFace
|
||||||
|
) override
|
||||||
{
|
{
|
||||||
a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
|
a_WorldInterface.SendBlockTo(a_BlockPos, a_Player);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool IsUseable(void) override
|
virtual bool IsUseable(void) override
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -20,36 +20,65 @@ public:
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
virtual bool OnUse(
|
||||||
|
cChunkInterface & a_ChunkInterface,
|
||||||
|
cWorldInterface & a_WorldInterface,
|
||||||
|
cPlayer & a_Player,
|
||||||
|
const Vector3i a_BlockPos,
|
||||||
|
eBlockFace a_BlockFace,
|
||||||
|
const Vector3i a_CursorPos
|
||||||
|
) override
|
||||||
{
|
{
|
||||||
NIBBLETYPE OldMetaData = a_ChunkInterface.GetBlockMeta({a_BlockX, a_BlockY, a_BlockZ});
|
NIBBLETYPE OldMetaData = a_ChunkInterface.GetBlockMeta(a_BlockPos);
|
||||||
NIBBLETYPE NewMetaData = YawToMetaData(a_Player.GetYaw());
|
NIBBLETYPE NewMetaData = YawToMetaData(a_Player.GetYaw());
|
||||||
OldMetaData ^= 4; // Toggle the gate
|
OldMetaData ^= 4; // Toggle the gate
|
||||||
|
|
||||||
if ((OldMetaData & 1) == (NewMetaData & 1))
|
if ((OldMetaData & 1) == (NewMetaData & 1))
|
||||||
{
|
{
|
||||||
// Standing in front of the gate - apply new direction
|
// Standing in front of the gate - apply new direction
|
||||||
a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, (OldMetaData & 4) | (NewMetaData & 3));
|
a_ChunkInterface.SetBlockMeta(a_BlockPos, (OldMetaData & 4) | (NewMetaData & 3));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Standing aside - use last direction
|
// Standing aside - use last direction
|
||||||
a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, OldMetaData);
|
a_ChunkInterface.SetBlockMeta(a_BlockPos, OldMetaData);
|
||||||
}
|
}
|
||||||
a_Player.GetWorld()->BroadcastSoundParticleEffect(EffectID::SFX_RANDOM_FENCE_GATE_OPEN, {a_BlockX, a_BlockY, a_BlockZ}, 0, a_Player.GetClientHandle());
|
a_Player.GetWorld()->BroadcastSoundParticleEffect(EffectID::SFX_RANDOM_FENCE_GATE_OPEN, a_BlockPos, 0, a_Player.GetClientHandle());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
virtual void OnCancelRightClick(
|
||||||
|
cChunkInterface & a_ChunkInterface,
|
||||||
|
cWorldInterface & a_WorldInterface,
|
||||||
|
cPlayer & a_Player,
|
||||||
|
const Vector3i a_BlockPos,
|
||||||
|
eBlockFace a_BlockFace
|
||||||
|
) override
|
||||||
{
|
{
|
||||||
a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
|
a_WorldInterface.SendBlockTo(a_BlockPos, a_Player);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool IsUseable(void) override
|
virtual bool IsUseable(void) override
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
||||||
{
|
{
|
||||||
UNUSED(a_Meta);
|
UNUSED(a_Meta);
|
||||||
|
|
|
@ -7,12 +7,15 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cBlockFlowerHandler :
|
class cBlockFlowerHandler:
|
||||||
public cBlockHandler
|
public cBlockHandler
|
||||||
{
|
{
|
||||||
|
using Super = cBlockHandler;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
cBlockFlowerHandler(BLOCKTYPE a_BlockType)
|
|
||||||
: cBlockHandler(a_BlockType)
|
cBlockFlowerHandler(BLOCKTYPE a_BlockType):
|
||||||
|
Super(a_BlockType)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,11 +33,15 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
|
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override
|
||||||
{
|
{
|
||||||
return (a_RelY > 0) && IsBlockTypeOfDirt(a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ));
|
return ((a_RelPos.y > 0) && IsBlockTypeOfDirt(a_Chunk.GetBlock(a_RelPos.addedY(-1))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
||||||
{
|
{
|
||||||
UNUSED(a_Meta);
|
UNUSED(a_Meta);
|
||||||
|
|
|
@ -90,30 +90,31 @@ public:
|
||||||
// Y Coord out of range
|
// Y Coord out of range
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(Pos);
|
auto Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(Pos);
|
||||||
if (chunk == nullptr)
|
if (Chunk == nullptr)
|
||||||
{
|
{
|
||||||
// Unloaded chunk
|
// Unloaded chunk
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
chunk->GetBlockTypeMeta(Pos, DestBlock, DestMeta);
|
Chunk->GetBlockTypeMeta(Pos, DestBlock, DestMeta);
|
||||||
if ((DestBlock != E_BLOCK_DIRT) || (DestMeta != E_META_DIRT_NORMAL))
|
if ((DestBlock != E_BLOCK_DIRT) || (DestMeta != E_META_DIRT_NORMAL))
|
||||||
{
|
{
|
||||||
// Not a regular dirt block
|
// Not a regular dirt block
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
BLOCKTYPE Above = chunk->GetBlock(AbovePos);
|
auto AboveDestPos = Pos.addedY(1);
|
||||||
NIBBLETYPE light = std::max(chunk->GetBlockLight(AbovePos), chunk->GetTimeAlteredLight(chunk->GetSkyLight(AbovePos)));
|
auto AboveBlockType = Chunk->GetBlock(AboveDestPos);
|
||||||
if ((light > 4) &&
|
auto Light = std::max(Chunk->GetBlockLight(AboveDestPos), Chunk->GetTimeAlteredLight(Chunk->GetSkyLight(AboveDestPos)));
|
||||||
cBlockInfo::IsTransparent(Above) &&
|
if ((Light > 4) &&
|
||||||
(!IsBlockLava(Above)) &&
|
cBlockInfo::IsTransparent(AboveBlockType) &&
|
||||||
(!IsBlockWaterOrIce(Above))
|
(!IsBlockLava(AboveBlockType)) &&
|
||||||
|
(!IsBlockWaterOrIce(AboveBlockType))
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
auto absPos = chunk->RelativeToAbsolute(Pos);
|
auto AbsPos = Chunk->RelativeToAbsolute(Pos);
|
||||||
if (!cRoot::Get()->GetPluginManager()->CallHookBlockSpread(*chunk->GetWorld(), absPos.x, absPos.y, absPos.z, ssGrassSpread))
|
if (!cRoot::Get()->GetPluginManager()->CallHookBlockSpread(*Chunk->GetWorld(), AbsPos.x, AbsPos.y, AbsPos.z, ssGrassSpread))
|
||||||
{
|
{
|
||||||
chunk->FastSetBlock(Pos, E_BLOCK_GRASS, 0);
|
Chunk->FastSetBlock(Pos, E_BLOCK_GRASS, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // for i - repeat twice
|
} // for i - repeat twice
|
||||||
|
|
|
@ -406,8 +406,9 @@ cBlockHandler::cBlockHandler(BLOCKTYPE a_BlockType)
|
||||||
|
|
||||||
bool cBlockHandler::GetPlacementBlockTypeMeta(
|
bool cBlockHandler::GetPlacementBlockTypeMeta(
|
||||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
const Vector3i a_ClickedBlockPos,
|
||||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
eBlockFace a_ClickedBlockFace,
|
||||||
|
const Vector3i a_CursorPos,
|
||||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
@ -437,7 +438,7 @@ void cBlockHandler::OnUpdate(
|
||||||
|
|
||||||
void cBlockHandler::OnPlacedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, const sSetBlock & a_BlockChange)
|
void cBlockHandler::OnPlacedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, const sSetBlock & a_BlockChange)
|
||||||
{
|
{
|
||||||
OnPlaced(a_ChunkInterface, a_WorldInterface, a_BlockChange.GetPos(), a_BlockChange.m_BlockType, a_BlockChange.m_BlockMeta);
|
OnPlaced(a_ChunkInterface, a_WorldInterface, a_BlockChange.GetAbsolutePos(), a_BlockChange.m_BlockType, a_BlockChange.m_BlockMeta);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -509,7 +510,7 @@ cItems cBlockHandler::ConvertToPickups(
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cBlockHandler::CanBeAt(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ, const cChunk & a_Chunk)
|
bool cBlockHandler::CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -554,10 +555,10 @@ bool cBlockHandler::DoesDropOnUnsuitable(void)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* default functionality: only test for height, since we assume full voxels with varying height */
|
bool cBlockHandler::IsInsideBlock(const Vector3d a_RelPosition, const NIBBLETYPE a_BlockMeta)
|
||||||
bool cBlockHandler::IsInsideBlock(Vector3d a_Position, const BLOCKTYPE a_BlockType, const NIBBLETYPE a_BlockMeta)
|
|
||||||
{
|
{
|
||||||
return a_Position.y < cBlockInfo::GetBlockHeight(a_BlockType);
|
// Default functionality: Test the height, since we assume full voxels with varying height
|
||||||
|
return (a_RelPosition.y < cBlockInfo::GetBlockHeight(m_BlockType));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -584,7 +585,7 @@ void cBlockHandler::Check(
|
||||||
cChunk & a_Chunk
|
cChunk & a_Chunk
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (!CanBeAt(a_ChunkInterface, a_RelPos.x, a_RelPos.y, a_RelPos.z, a_Chunk))
|
if (!CanBeAt(a_ChunkInterface, a_RelPos, a_Chunk))
|
||||||
{
|
{
|
||||||
if (DoesDropOnUnsuitable())
|
if (DoesDropOnUnsuitable())
|
||||||
{
|
{
|
||||||
|
|
|
@ -44,19 +44,28 @@ public:
|
||||||
blocktype of the minus-X neighbor, the positive-X neighbor, etc. */
|
blocktype of the minus-X neighbor, the positive-X neighbor, etc. */
|
||||||
virtual cBoundingBox GetPlacementCollisionBox(BLOCKTYPE a_XM, BLOCKTYPE a_XP, BLOCKTYPE a_YM, BLOCKTYPE a_YP, BLOCKTYPE a_ZM, BLOCKTYPE a_ZP);
|
virtual cBoundingBox GetPlacementCollisionBox(BLOCKTYPE a_XM, BLOCKTYPE a_XP, BLOCKTYPE a_YM, BLOCKTYPE a_YP, BLOCKTYPE a_ZM, BLOCKTYPE a_ZP);
|
||||||
|
|
||||||
/** Called before a block is placed into a world.
|
/** Called before a block is placed into a world by player, by cItemHandler::GetPlacementBlockTypeMeta().
|
||||||
The handler should return true to allow placement, false to refuse.
|
The handler should return true to allow placement, false to refuse.
|
||||||
Also, the handler should set a_BlockType and a_BlockMeta to correct values for the newly placed block.
|
a_PlacedBlockPos is the coords of the block being placed
|
||||||
Called by cItemHandler::GetPlacementBlockTypeMeta() if the item is a block */
|
a_ClickedBlockFace is the face of the neighbor block clicked by the client to place this block.
|
||||||
|
a_CursorPos is the position of the cursor within the neighbor's face
|
||||||
|
The descendant handler should set a_BlockType and a_BlockMeta to correct values for the newly placed block.
|
||||||
|
The default handler uses the stored block type and meta copied from the lowest 4 bits of the player's equipped item's damage value. */
|
||||||
virtual bool GetPlacementBlockTypeMeta(
|
virtual bool GetPlacementBlockTypeMeta(
|
||||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
cChunkInterface & a_ChunkInterface,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
cPlayer & a_Player,
|
||||||
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
|
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||||
);
|
);
|
||||||
|
|
||||||
/** Called by cWorld::SetBlock() after the block has been set */
|
/** Called by cWorld::SetBlock() after the block has been set */
|
||||||
virtual void OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
|
virtual void OnPlaced(
|
||||||
|
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface,
|
||||||
|
Vector3i a_BlockPos,
|
||||||
|
BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta
|
||||||
|
);
|
||||||
|
|
||||||
/** Called by cPlayer::PlaceBlocks() for each block after it has been set to the world. Called after OnPlaced(). */
|
/** Called by cPlayer::PlaceBlocks() for each block after it has been set to the world. Called after OnPlaced(). */
|
||||||
virtual void OnPlacedByPlayer(
|
virtual void OnPlacedByPlayer(
|
||||||
|
@ -118,18 +127,37 @@ public:
|
||||||
cChunkInterface & a_ChunkInterface,
|
cChunkInterface & a_ChunkInterface,
|
||||||
cWorldInterface & a_WorldInterface,
|
cWorldInterface & a_WorldInterface,
|
||||||
cPlayer & a_Player,
|
cPlayer & a_Player,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ
|
const Vector3i a_BlockPos
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Called if the user right clicks the block and the block is useable
|
/** Called when the user right clicks the block and the block is useable.
|
||||||
returns true if the use was successful, return false to use the block as a "normal" block */
|
a_CursorPos is the cursor position within the clicked block face.
|
||||||
virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) { return false; }
|
Returns true if the use was successful, return false to use the block as a "normal" block */
|
||||||
|
virtual bool OnUse(
|
||||||
|
cChunkInterface & a_ChunkInterface,
|
||||||
|
cWorldInterface & a_WorldInterface,
|
||||||
|
cPlayer & a_Player,
|
||||||
|
const Vector3i a_BlockPos,
|
||||||
|
eBlockFace a_BlockFace,
|
||||||
|
const Vector3i a_CursorPos
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/** Called when a right click to this block is cancelled.
|
/** Called when a right click to this block is cancelled.
|
||||||
It forces the server to send the real state of a block to the client to prevent client assuming the operation is successfull */
|
Descendants should force the server to send the real state of a block to the client to prevent client assuming the operation was successfull. */
|
||||||
virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) {}
|
virtual void OnCancelRightClick(
|
||||||
|
cChunkInterface & a_ChunkInterface,
|
||||||
|
cWorldInterface & a_WorldInterface,
|
||||||
|
cPlayer & a_Player,
|
||||||
|
const Vector3i a_BlockPos,
|
||||||
|
eBlockFace a_BlockFace
|
||||||
|
)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/** Returns the pickups that would result if the block was mined by a_Digger using a_Tool.
|
/** Returns the pickups that would result if the block was mined by a_Digger using a_Tool.
|
||||||
Doesn't do any actual block change / mining, only calculates the pickups.
|
Doesn't do any actual block change / mining, only calculates the pickups.
|
||||||
|
@ -145,41 +173,37 @@ public:
|
||||||
);
|
);
|
||||||
|
|
||||||
/** Checks if the block can stay at the specified relative coords in the chunk */
|
/** Checks if the block can stay at the specified relative coords in the chunk */
|
||||||
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk);
|
virtual bool CanBeAt(
|
||||||
|
cChunkInterface & a_ChunkInterface,
|
||||||
|
const Vector3i a_RelPos,
|
||||||
|
const cChunk & a_Chunk
|
||||||
|
);
|
||||||
|
|
||||||
/** Checks whether the block has an effect on growing the plant */
|
/** Checks whether the block has an effect on growing the plant */
|
||||||
virtual bool CanSustainPlant(BLOCKTYPE a_Plant) { return false; }
|
virtual bool CanSustainPlant(BLOCKTYPE a_Plant) { return false; }
|
||||||
|
|
||||||
/** Checks if the block can be placed at this point.
|
|
||||||
Default: CanBeAt(...)
|
|
||||||
NOTE: This call doesn't actually place the block
|
|
||||||
*/
|
|
||||||
// virtual bool CanBePlacedAt(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Dir);
|
|
||||||
|
|
||||||
/** Called to check whether this block supports a rclk action.
|
/** Called to check whether this block supports a rclk action.
|
||||||
If it returns true, OnUse() is called */
|
If it returns true, OnUse() is called */
|
||||||
virtual bool IsUseable(void);
|
virtual bool IsUseable(void);
|
||||||
|
|
||||||
/** Indicates whether the client will click through this block.
|
/** Indicates whether the client will click through this block.
|
||||||
For example digging a fire will hit the block below the fire so fire is clicked through
|
For example digging a fire will hit the block below the fire so fire is clicked through. */
|
||||||
*/
|
|
||||||
virtual bool IsClickedThrough(void);
|
virtual bool IsClickedThrough(void);
|
||||||
|
|
||||||
/** Checks if the player can build "inside" this block.
|
/** Checks if the player can build "inside" this block.
|
||||||
For example blocks placed "on" snow will be placed at the same position. So: Snow ignores Build collision
|
For example blocks placed "on" snow will be placed at the same position. So: Snow ignores Build collision
|
||||||
@param a_Pos Position of the block
|
@param a_Pos Position of the block
|
||||||
@param a_Player Player trying to build on the block
|
@param a_Player Player trying to build on the block
|
||||||
@param a_Meta Meta value of the block currently at a_Pos
|
@param a_Meta Meta value of the block currently at a_Pos */
|
||||||
*/
|
virtual bool DoesIgnoreBuildCollision(cChunkInterface & ChunkInterface, const Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta);
|
||||||
virtual bool DoesIgnoreBuildCollision(cChunkInterface & ChunkInterface, Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta);
|
|
||||||
|
|
||||||
/** Returns if this block drops if it gets destroyed by an unsuitable situation.
|
/** Returns if this block drops if it gets destroyed by an unsuitable situation.
|
||||||
Default: true */
|
Default: true */
|
||||||
virtual bool DoesDropOnUnsuitable(void);
|
virtual bool DoesDropOnUnsuitable(void);
|
||||||
|
|
||||||
/** Tests if a_Position is inside the block where a_Position is relative to the origin of the block
|
/** Tests if a_RelPosition is inside the block, where a_RelPosition is relative to the origin of the block.
|
||||||
Note that this is considered from a "top-down" perspective i.e. empty spaces on the bottom of a block don't matter */
|
Coords in a_RelPosition are guaranteed to be in the [0..1] range. */
|
||||||
virtual bool IsInsideBlock(Vector3d a_Position, const BLOCKTYPE a_BlockType, const NIBBLETYPE a_BlockMeta);
|
virtual bool IsInsideBlock(const Vector3d a_RelPosition, const NIBBLETYPE a_BlockMeta);
|
||||||
|
|
||||||
/** Called when one of the neighbors gets set; equivalent to MC block update.
|
/** Called when one of the neighbors gets set; equivalent to MC block update.
|
||||||
By default drops (DropBlockAsPickup() / SetBlock()) if the position is no longer suitable (CanBeAt(), DoesDropOnUnsuitable()),
|
By default drops (DropBlockAsPickup() / SetBlock()) if the position is no longer suitable (CanBeAt(), DoesDropOnUnsuitable()),
|
||||||
|
|
|
@ -24,16 +24,18 @@ public:
|
||||||
|
|
||||||
|
|
||||||
virtual bool GetPlacementBlockTypeMeta(
|
virtual bool GetPlacementBlockTypeMeta(
|
||||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
cChunkInterface & a_ChunkInterface,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
cPlayer & a_Player,
|
||||||
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
|
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
a_BlockType = m_BlockType;
|
a_BlockType = m_BlockType;
|
||||||
|
|
||||||
// Convert the blockface into meta:
|
// Convert the blockface into meta:
|
||||||
switch (a_BlockFace)
|
switch (a_ClickedBlockFace)
|
||||||
{
|
{
|
||||||
case BLOCK_FACE_BOTTOM: a_BlockMeta = E_META_HOPPER_FACING_YM; break;
|
case BLOCK_FACE_BOTTOM: a_BlockMeta = E_META_HOPPER_FACING_YM; break;
|
||||||
case BLOCK_FACE_TOP: a_BlockMeta = E_META_HOPPER_FACING_YM; break;
|
case BLOCK_FACE_TOP: a_BlockMeta = E_META_HOPPER_FACING_YM; break;
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cBlockLadderHandler :
|
class cBlockLadderHandler:
|
||||||
public cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x07, 0x02, 0x05, 0x03, 0x04> >
|
public cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x07, 0x02, 0x05, 0x03, 0x04> >
|
||||||
{
|
{
|
||||||
using Super = cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x07, 0x02, 0x05, 0x03, 0x04>>;
|
using Super = cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x07, 0x02, 0x05, 0x03, 0x04>>;
|
||||||
|
@ -25,24 +25,26 @@ public:
|
||||||
|
|
||||||
|
|
||||||
virtual bool GetPlacementBlockTypeMeta(
|
virtual bool GetPlacementBlockTypeMeta(
|
||||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
cChunkInterface & a_ChunkInterface,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
cPlayer & a_Player,
|
||||||
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
|
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
if (!LadderCanBePlacedAt(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace))
|
// Try finding a suitable neighbor block face for the ladder; start with the given one.
|
||||||
|
if (!LadderCanBePlacedAt(a_ChunkInterface, a_PlacedBlockPos, a_ClickedBlockFace))
|
||||||
{
|
{
|
||||||
a_BlockFace = FindSuitableBlockFace(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ);
|
a_ClickedBlockFace = FindSuitableBlockFace(a_ChunkInterface, a_PlacedBlockPos);
|
||||||
|
if (a_ClickedBlockFace == BLOCK_FACE_NONE)
|
||||||
if (a_BlockFace == BLOCK_FACE_BOTTOM)
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
a_BlockType = m_BlockType;
|
a_BlockType = m_BlockType;
|
||||||
a_BlockMeta = DirectionToMetaData(a_BlockFace);
|
a_BlockMeta = BlockFaceToMetaData(a_ClickedBlockFace);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,9 +52,10 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static NIBBLETYPE DirectionToMetaData(eBlockFace a_Direction)
|
/** Converts the block face of the neighbor to which the ladder is attached to the ladder block's meta. */
|
||||||
|
static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_NeighborBlockFace)
|
||||||
{
|
{
|
||||||
switch (a_Direction)
|
switch (a_NeighborBlockFace)
|
||||||
{
|
{
|
||||||
case BLOCK_FACE_ZM: return 0x2;
|
case BLOCK_FACE_ZM: return 0x2;
|
||||||
case BLOCK_FACE_ZP: return 0x3;
|
case BLOCK_FACE_ZP: return 0x3;
|
||||||
|
@ -65,14 +68,15 @@ public:
|
||||||
return 0x2;
|
return 0x2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UNREACHABLE("Unsupported block face");
|
UNREACHABLE("Unsupported neighbor block face");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static eBlockFace MetaDataToDirection(NIBBLETYPE a_MetaData)
|
/** Converts the ladder block's meta to the block face of the neighbor to which the ladder is attached. */
|
||||||
|
static eBlockFace MetaDataToBlockFace(NIBBLETYPE a_MetaData)
|
||||||
{
|
{
|
||||||
switch (a_MetaData)
|
switch (a_MetaData)
|
||||||
{
|
{
|
||||||
|
@ -88,47 +92,51 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Finds a suitable Direction for the Ladder. Returns BLOCK_FACE_BOTTOM on failure */
|
/** Finds a suitable block face value for the Ladder.
|
||||||
static eBlockFace FindSuitableBlockFace(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ)
|
The returned value is the block face of the neighbor of the specified block to which a ladder at a_LadderPos can be attached.
|
||||||
|
Returns BLOCK_FACE_NONE if no valid location is found */
|
||||||
|
static eBlockFace FindSuitableBlockFace(cChunkInterface & a_ChunkInterface, const Vector3i a_LadderPos)
|
||||||
{
|
{
|
||||||
for (int FaceInt = BLOCK_FACE_ZM; FaceInt <= BLOCK_FACE_XP; FaceInt++)
|
for (int FaceInt = BLOCK_FACE_ZM; FaceInt <= BLOCK_FACE_XP; FaceInt++)
|
||||||
{
|
{
|
||||||
eBlockFace Face = static_cast<eBlockFace>(FaceInt);
|
eBlockFace Face = static_cast<eBlockFace>(FaceInt);
|
||||||
if (LadderCanBePlacedAt(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ, Face))
|
if (LadderCanBePlacedAt(a_ChunkInterface, a_LadderPos, Face))
|
||||||
{
|
{
|
||||||
return Face;
|
return Face;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return BLOCK_FACE_BOTTOM;
|
return BLOCK_FACE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static bool LadderCanBePlacedAt(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace)
|
/** Returns true if the ladder in the specified position will be supported by its neghbor through the specified neighbor's blockface. */
|
||||||
|
static bool LadderCanBePlacedAt(cChunkInterface & a_ChunkInterface, const Vector3i a_LadderPos, eBlockFace a_NeighborBlockFace)
|
||||||
{
|
{
|
||||||
if ((a_BlockFace == BLOCK_FACE_BOTTOM) || (a_BlockFace == BLOCK_FACE_TOP))
|
if (
|
||||||
|
(a_NeighborBlockFace == BLOCK_FACE_NONE) ||
|
||||||
|
(a_NeighborBlockFace == BLOCK_FACE_BOTTOM) ||
|
||||||
|
(a_NeighborBlockFace == BLOCK_FACE_TOP)
|
||||||
|
)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
AddFaceDirection( a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, true);
|
auto NeighborPos = AddFaceDirection(a_LadderPos, a_NeighborBlockFace, true);
|
||||||
|
return cBlockInfo::IsSolid(a_ChunkInterface.GetBlock(NeighborPos));
|
||||||
return cBlockInfo::IsSolid(a_ChunkInterface.GetBlock({a_BlockX, a_BlockY, a_BlockZ}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
|
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override
|
||||||
{
|
{
|
||||||
// TODO: Use AdjustCoordsByMeta(), then cChunk::UnboundedRelGetBlock() and finally some comparison
|
auto NeighborBlockFace = MetaDataToBlockFace(a_Chunk.GetMeta(a_RelPos));
|
||||||
eBlockFace BlockFace = MetaDataToDirection(a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ));
|
auto LadderAbsPos = a_Chunk.RelativeToAbsolute(a_RelPos);
|
||||||
int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width;
|
return LadderCanBePlacedAt(a_ChunkInterface, LadderAbsPos, NeighborBlockFace);
|
||||||
int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width;
|
|
||||||
return LadderCanBePlacedAt(a_ChunkInterface, BlockX, a_RelY, BlockZ, BlockFace);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -6,14 +6,14 @@
|
||||||
#include "BlockSlab.h"
|
#include "BlockSlab.h"
|
||||||
|
|
||||||
|
|
||||||
class cBlockLeverHandler :
|
class cBlockLeverHandler:
|
||||||
public cMetaRotator<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, false>
|
public cMetaRotator<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, false>
|
||||||
{
|
{
|
||||||
using Super = cMetaRotator<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, false>;
|
using Super = cMetaRotator<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, false>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
cBlockLeverHandler(BLOCKTYPE a_BlockType) :
|
cBlockLeverHandler(BLOCKTYPE a_BlockType):
|
||||||
Super(a_BlockType)
|
Super(a_BlockType)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -22,15 +22,21 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override
|
virtual bool OnUse(
|
||||||
|
cChunkInterface & a_ChunkInterface,
|
||||||
|
cWorldInterface & a_WorldInterface,
|
||||||
|
cPlayer & a_Player,
|
||||||
|
const Vector3i a_BlockPos,
|
||||||
|
eBlockFace a_BlockFace,
|
||||||
|
const Vector3i a_CursorPos
|
||||||
|
) override
|
||||||
{
|
{
|
||||||
Vector3i Coords(a_BlockX, a_BlockY, a_BlockZ);
|
|
||||||
// Flip the ON bit on / off using the XOR bitwise operation
|
// Flip the ON bit on / off using the XOR bitwise operation
|
||||||
NIBBLETYPE Meta = (a_ChunkInterface.GetBlockMeta(Coords) ^ 0x08);
|
NIBBLETYPE Meta = (a_ChunkInterface.GetBlockMeta(a_BlockPos) ^ 0x08);
|
||||||
|
|
||||||
a_ChunkInterface.SetBlockMeta(Coords.x, Coords.y, Coords.z, Meta);
|
a_ChunkInterface.SetBlockMeta(a_BlockPos, Meta);
|
||||||
a_WorldInterface.WakeUpSimulators(Coords);
|
a_WorldInterface.WakeUpSimulators(a_BlockPos);
|
||||||
a_WorldInterface.GetBroadcastManager().BroadcastSoundEffect("block.lever.click", Vector3d(Coords), 0.5f, (Meta & 0x08) ? 0.6f : 0.5f);
|
a_WorldInterface.GetBroadcastManager().BroadcastSoundEffect("block.lever.click", a_BlockPos, 0.5f, (Meta & 0x08) ? 0.6f : 0.5f);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,14 +64,16 @@ public:
|
||||||
|
|
||||||
|
|
||||||
virtual bool GetPlacementBlockTypeMeta(
|
virtual bool GetPlacementBlockTypeMeta(
|
||||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
cChunkInterface & a_ChunkInterface,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
cPlayer & a_Player,
|
||||||
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
|
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
a_BlockType = m_BlockType;
|
a_BlockType = m_BlockType;
|
||||||
a_BlockMeta = LeverDirectionToMetaData(a_BlockFace);
|
a_BlockMeta = LeverDirectionToMetaData(a_ClickedBlockFace);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,6 +81,7 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Converts the block face of the neighbor to which the lever is attached to the lever block's meta. */
|
||||||
inline static NIBBLETYPE LeverDirectionToMetaData(eBlockFace a_Dir)
|
inline static NIBBLETYPE LeverDirectionToMetaData(eBlockFace a_Dir)
|
||||||
{
|
{
|
||||||
// Determine lever direction:
|
// Determine lever direction:
|
||||||
|
@ -93,6 +102,7 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Converts the leve block's meta to the block face of the neighbor to which the lever is attached. */
|
||||||
inline static eBlockFace BlockMetaDataToBlockFace(NIBBLETYPE a_Meta)
|
inline static eBlockFace BlockMetaDataToBlockFace(NIBBLETYPE a_Meta)
|
||||||
{
|
{
|
||||||
switch (a_Meta & 0x7)
|
switch (a_Meta & 0x7)
|
||||||
|
@ -117,34 +127,33 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
|
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override
|
||||||
{
|
{
|
||||||
NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ);
|
// Find the type of block the lever is attached to:
|
||||||
|
auto Meta = a_Chunk.GetMeta(a_RelPos);
|
||||||
eBlockFace Face = BlockMetaDataToBlockFace(Meta);
|
auto NeighborFace = BlockMetaDataToBlockFace(Meta);
|
||||||
|
auto NeighborPos = AddFaceDirection(a_RelPos, NeighborFace, true);
|
||||||
AddFaceDirection(a_RelX, a_RelY, a_RelZ, Face, true);
|
if (!cChunkDef::IsValidHeight(NeighborPos.y))
|
||||||
|
{
|
||||||
if ((a_RelY < 0) || (a_RelY >= cChunkDef::Height -1))
|
return false;
|
||||||
|
}
|
||||||
|
BLOCKTYPE NeighborBlockType;
|
||||||
|
if (!a_Chunk.UnboundedRelGetBlock(NeighborPos, NeighborBlockType, Meta))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
BLOCKTYPE BlockIsOn;
|
// Allow any full block or the "good" side of a half-slab:
|
||||||
a_Chunk.UnboundedRelGetBlock(a_RelX, a_RelY, a_RelZ, BlockIsOn, Meta);
|
if (cBlockInfo::FullyOccupiesVoxel(NeighborBlockType))
|
||||||
|
|
||||||
|
|
||||||
if (cBlockInfo::FullyOccupiesVoxel(BlockIsOn))
|
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (cBlockSlabHandler::IsAnySlabType(BlockIsOn))
|
else if (cBlockSlabHandler::IsAnySlabType(NeighborBlockType))
|
||||||
{
|
{
|
||||||
// Check if the slab is turned up side down
|
return (
|
||||||
if (((Meta & 0x08) == 0x08) && (Face == BLOCK_FACE_TOP))
|
(((Meta & 0x08) == 0x08) && (NeighborFace == BLOCK_FACE_TOP)) ||
|
||||||
{
|
(((Meta & 0x08) == 0) && (NeighborFace == BLOCK_FACE_BOTTOM))
|
||||||
return true;
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -19,6 +19,10 @@ public:
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
||||||
{
|
{
|
||||||
UNUSED(a_Meta);
|
UNUSED(a_Meta);
|
||||||
|
@ -26,15 +30,19 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
|
|
||||||
|
|
||||||
|
|
||||||
|
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override
|
||||||
{
|
{
|
||||||
if ((a_RelY < 1) || (a_RelY >= cChunkDef::Height))
|
auto UnderPos = a_RelPos.addedY(-1);
|
||||||
|
if (!cChunkDef::IsValidHeight(UnderPos.y))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
BLOCKTYPE UnderType;
|
BLOCKTYPE UnderType;
|
||||||
NIBBLETYPE UnderMeta;
|
NIBBLETYPE UnderMeta;
|
||||||
a_Chunk.GetBlockTypeMeta(a_RelX, a_RelY - 1, a_RelZ, UnderType, UnderMeta);
|
a_Chunk.GetBlockTypeMeta(UnderPos, UnderType, UnderMeta);
|
||||||
return (
|
return (
|
||||||
(((UnderType == E_BLOCK_STATIONARY_WATER) || (UnderType == E_BLOCK_WATER)) && (UnderMeta == 0)) || // A water source is below
|
(((UnderType == E_BLOCK_STATIONARY_WATER) || (UnderType == E_BLOCK_WATER)) && (UnderMeta == 0)) || // A water source is below
|
||||||
(UnderType == E_BLOCK_ICE) || (UnderType == E_BLOCK_FROSTED_ICE) // Or (frosted) ice
|
(UnderType == E_BLOCK_ICE) || (UnderType == E_BLOCK_FROSTED_ICE) // Or (frosted) ice
|
||||||
|
|
|
@ -8,22 +8,38 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cBlockMobSpawnerHandler :
|
class cBlockMobSpawnerHandler:
|
||||||
public cBlockHandler
|
public cBlockHandler
|
||||||
{
|
{
|
||||||
|
using Super = cBlockHandler;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
cBlockMobSpawnerHandler(BLOCKTYPE a_BlockType)
|
|
||||||
: cBlockHandler(a_BlockType)
|
cBlockMobSpawnerHandler(BLOCKTYPE a_BlockType):
|
||||||
|
Super(a_BlockType)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override
|
|
||||||
|
|
||||||
|
|
||||||
|
virtual bool OnUse(
|
||||||
|
cChunkInterface & a_ChunkInterface,
|
||||||
|
cWorldInterface & a_WorldInterface,
|
||||||
|
cPlayer & a_Player,
|
||||||
|
const Vector3i a_BlockPos,
|
||||||
|
eBlockFace a_BlockFace,
|
||||||
|
const Vector3i a_CursorPos
|
||||||
|
) override
|
||||||
{
|
{
|
||||||
return a_ChunkInterface.UseBlockEntity(&a_Player, a_BlockX, a_BlockY, a_BlockZ);
|
return a_ChunkInterface.UseBlockEntity(&a_Player, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool IsUseable() override
|
virtual bool IsUseable() override
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Handler for the small (singleblock) mushrooms. */
|
||||||
class cBlockMushroomHandler:
|
class cBlockMushroomHandler:
|
||||||
public cClearMetaOnDrop<cBlockHandler>
|
public cClearMetaOnDrop<cBlockHandler>
|
||||||
{
|
{
|
||||||
|
@ -19,18 +20,26 @@ public:
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// TODO: Add Mushroom Spread
|
// TODO: Add Mushroom Spread
|
||||||
|
|
||||||
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override
|
||||||
{
|
{
|
||||||
if (a_RelY <= 0)
|
if (a_RelPos.y <= 0)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Cannot be at too much daylight
|
// TODO: Cannot be at too much daylight
|
||||||
|
|
||||||
switch (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ))
|
switch (a_Chunk.GetBlock(a_RelPos.addedY(-1)))
|
||||||
{
|
{
|
||||||
case E_BLOCK_GLASS:
|
case E_BLOCK_GLASS:
|
||||||
case E_BLOCK_CACTUS:
|
case E_BLOCK_CACTUS:
|
||||||
|
@ -45,6 +54,10 @@ public:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
||||||
{
|
{
|
||||||
UNUSED(a_Meta);
|
UNUSED(a_Meta);
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cBlockNetherWartHandler :
|
class cBlockNetherWartHandler:
|
||||||
public cBlockPlant<false>
|
public cBlockPlant<false>
|
||||||
{
|
{
|
||||||
using Super = cBlockPlant<false>;
|
using Super = cBlockPlant<false>;
|
||||||
|
@ -64,10 +64,10 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
|
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override
|
||||||
{
|
{
|
||||||
// Needs to be placed on top of a Soulsand block:
|
// Needs to be placed on top of a Soulsand block:
|
||||||
return ((a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) == E_BLOCK_SOULSAND));
|
return ((a_RelPos.y > 0) && (a_Chunk.GetBlock(a_RelPos.addedY(-1)) == E_BLOCK_SOULSAND));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,18 +7,28 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cBlockPlanksHandler : public cBlockHandler
|
class cBlockPlanksHandler:
|
||||||
|
public cBlockHandler
|
||||||
{
|
{
|
||||||
|
using Super = cBlockHandler;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
cBlockPlanksHandler(BLOCKTYPE a_BlockType)
|
|
||||||
: cBlockHandler(a_BlockType)
|
cBlockPlanksHandler(BLOCKTYPE a_BlockType):
|
||||||
|
Super(a_BlockType)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool GetPlacementBlockTypeMeta(
|
virtual bool GetPlacementBlockTypeMeta(
|
||||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
cChunkInterface & a_ChunkInterface,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
cPlayer & a_Player,
|
||||||
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
|
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
|
@ -27,6 +37,10 @@ public:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
||||||
{
|
{
|
||||||
switch (a_Meta)
|
switch (a_Meta)
|
||||||
|
|
|
@ -7,25 +7,33 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cBlockPortalHandler :
|
class cBlockPortalHandler:
|
||||||
public cBlockHandler
|
public cBlockHandler
|
||||||
{
|
{
|
||||||
|
using Super = cBlockHandler;
|
||||||
public:
|
public:
|
||||||
cBlockPortalHandler(BLOCKTYPE a_BlockType)
|
|
||||||
: cBlockHandler(a_BlockType)
|
cBlockPortalHandler(BLOCKTYPE a_BlockType):
|
||||||
|
Super(a_BlockType)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool GetPlacementBlockTypeMeta(
|
virtual bool GetPlacementBlockTypeMeta(
|
||||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
cChunkInterface & a_ChunkInterface,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
cPlayer & a_Player,
|
||||||
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
|
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
// We set to zero so MCS doesn't stop you from building weird portals like vanilla does
|
// We set meta to zero so Cuberite doesn't stop a Creative-mode player from building custom portal shapes
|
||||||
// CanBeAt doesn't do anything if meta is zero
|
// CanBeAt doesn't do anything if meta is zero
|
||||||
// We set to zero because the client sends meta = 2 to the server (it calculates rotation itself)
|
// We set to zero because the client sends meta = 1 or 2 to the server (it calculates rotation itself)
|
||||||
|
|
||||||
a_BlockType = m_BlockType;
|
a_BlockType = m_BlockType;
|
||||||
a_BlockMeta = 0;
|
a_BlockMeta = 0;
|
||||||
|
@ -67,14 +75,14 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
|
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override
|
||||||
{
|
{
|
||||||
if ((a_RelY <= 0) || (a_RelY >= cChunkDef::Height - 1))
|
if ((a_RelPos.y <= 0) || (a_RelPos.y >= cChunkDef::Height - 1))
|
||||||
{
|
{
|
||||||
return false; // In case someone places a portal with meta 1 or 2 at boundaries, and server tries to get invalid coords at Y - 1 or Y + 1
|
return false; // In case someone places a portal with meta 1 or 2 at boundaries, and server tries to get invalid coords at Y - 1 or Y + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ))
|
switch (a_Chunk.GetMeta(a_RelPos))
|
||||||
{
|
{
|
||||||
case 0x1:
|
case 0x1:
|
||||||
{
|
{
|
||||||
|
@ -91,8 +99,7 @@ public:
|
||||||
for (const auto & Direction : PortalCheck)
|
for (const auto & Direction : PortalCheck)
|
||||||
{
|
{
|
||||||
BLOCKTYPE Block;
|
BLOCKTYPE Block;
|
||||||
a_Chunk.UnboundedRelGetBlockType(a_RelX + Direction.x, a_RelY + Direction.y, a_RelZ + Direction.z, Block);
|
a_Chunk.UnboundedRelGetBlockType(a_RelPos + Direction, Block);
|
||||||
|
|
||||||
if ((Block != E_BLOCK_NETHER_PORTAL) && (Block != E_BLOCK_OBSIDIAN))
|
if ((Block != E_BLOCK_NETHER_PORTAL) && (Block != E_BLOCK_OBSIDIAN))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@ -115,8 +122,7 @@ public:
|
||||||
for (const auto & Direction : PortalCheck)
|
for (const auto & Direction : PortalCheck)
|
||||||
{
|
{
|
||||||
BLOCKTYPE Block;
|
BLOCKTYPE Block;
|
||||||
a_Chunk.UnboundedRelGetBlockType(a_RelX + Direction.x, a_RelY + Direction.y, a_RelZ + Direction.z, Block);
|
a_Chunk.UnboundedRelGetBlockType(a_RelPos + Direction, Block);
|
||||||
|
|
||||||
if ((Block != E_BLOCK_NETHER_PORTAL) && (Block != E_BLOCK_OBSIDIAN))
|
if ((Block != E_BLOCK_NETHER_PORTAL) && (Block != E_BLOCK_OBSIDIAN))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@ -128,6 +134,10 @@ public:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
||||||
{
|
{
|
||||||
UNUSED(a_Meta);
|
UNUSED(a_Meta);
|
||||||
|
|
|
@ -18,15 +18,19 @@ public:
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override
|
||||||
{
|
{
|
||||||
if (a_RelY - 1 <= 0)
|
if (a_RelPos.y <= 1)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: check if the block is upside-down slab or upside-down stairs
|
// TODO: check if the block is upside-down slab or upside-down stairs
|
||||||
BLOCKTYPE Block = a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ);
|
auto Block = a_Chunk.GetBlock(a_RelPos.addedY(-1));
|
||||||
switch (Block)
|
switch (Block)
|
||||||
{
|
{
|
||||||
case E_BLOCK_ACACIA_FENCE:
|
case E_BLOCK_ACACIA_FENCE:
|
||||||
|
@ -47,6 +51,10 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
||||||
{
|
{
|
||||||
UNUSED(a_Meta);
|
UNUSED(a_Meta);
|
||||||
|
|
|
@ -7,42 +7,57 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cBlockQuartzHandler : public cBlockHandler
|
class cBlockQuartzHandler:
|
||||||
|
public cBlockHandler
|
||||||
{
|
{
|
||||||
|
using Super = cBlockHandler;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
cBlockQuartzHandler(BLOCKTYPE a_BlockType)
|
|
||||||
: cBlockHandler(a_BlockType)
|
cBlockQuartzHandler(BLOCKTYPE a_BlockType):
|
||||||
|
Super(a_BlockType)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool GetPlacementBlockTypeMeta(
|
virtual bool GetPlacementBlockTypeMeta(
|
||||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
cChunkInterface & a_ChunkInterface,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
cPlayer & a_Player,
|
||||||
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
|
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
a_BlockType = m_BlockType;
|
a_BlockType = m_BlockType;
|
||||||
NIBBLETYPE Meta = static_cast<NIBBLETYPE>(a_Player.GetEquippedItem().m_ItemDamage);
|
auto Meta = static_cast<NIBBLETYPE>(a_Player.GetEquippedItem().m_ItemDamage);
|
||||||
|
|
||||||
if (Meta != E_META_QUARTZ_PILLAR) // Check if the block is a pillar block.
|
// Pillar block needs additional direction in the metadata:
|
||||||
|
if (Meta != E_META_QUARTZ_PILLAR)
|
||||||
{
|
{
|
||||||
a_BlockMeta = Meta;
|
a_BlockMeta = Meta;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
a_BlockMeta = BlockFaceToMetaData(a_ClickedBlockFace);
|
||||||
a_BlockMeta = BlockFaceToMetaData(a_BlockFace, Meta);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_BlockFace, NIBBLETYPE a_QuartzMeta)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Converts the block face of the pillar block's "base" to the block's metadata. */
|
||||||
|
inline static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_BlockFace)
|
||||||
{
|
{
|
||||||
switch (a_BlockFace)
|
switch (a_BlockFace)
|
||||||
{
|
{
|
||||||
case BLOCK_FACE_YM:
|
case BLOCK_FACE_YM:
|
||||||
case BLOCK_FACE_YP:
|
case BLOCK_FACE_YP:
|
||||||
{
|
{
|
||||||
return a_QuartzMeta; // Top or bottom, just return original
|
return E_META_QUARTZ_PILLAR; // Top or bottom
|
||||||
}
|
}
|
||||||
|
|
||||||
case BLOCK_FACE_ZP:
|
case BLOCK_FACE_ZP:
|
||||||
|
@ -57,15 +72,17 @@ public:
|
||||||
return 0x3; // East or west
|
return 0x3; // East or west
|
||||||
}
|
}
|
||||||
|
|
||||||
case BLOCK_FACE_NONE:
|
default:
|
||||||
{
|
{
|
||||||
ASSERT(!"Unhandled block face!");
|
return E_META_QUARTZ_PILLAR;
|
||||||
return a_QuartzMeta; // No idea, give a special meta (all sides the same)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UNREACHABLE("Unsupported block face");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
||||||
{
|
{
|
||||||
UNUSED(a_Meta);
|
UNUSED(a_Meta);
|
||||||
|
|
|
@ -28,21 +28,26 @@ public:
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool GetPlacementBlockTypeMeta(
|
virtual bool GetPlacementBlockTypeMeta(
|
||||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
cChunkInterface & a_ChunkInterface,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
cPlayer & a_Player,
|
||||||
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
|
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
a_BlockType = m_BlockType;
|
a_BlockType = m_BlockType;
|
||||||
Vector3i Pos{ a_BlockX, a_BlockY, a_BlockZ };
|
a_BlockMeta = FindMeta(a_ChunkInterface, a_PlacedBlockPos);
|
||||||
a_BlockMeta = FindMeta(a_ChunkInterface, Pos);
|
return a_Player.GetWorld()->DoWithChunkAt(a_PlacedBlockPos,
|
||||||
return a_Player.GetWorld()->DoWithChunkAt(Pos,
|
[this, a_PlacedBlockPos, &a_ChunkInterface](cChunk & a_Chunk)
|
||||||
[this, Pos, &a_ChunkInterface](cChunk & a_Chunk)
|
|
||||||
{
|
{
|
||||||
auto RelPos = cChunkDef::AbsoluteToRelative(Pos);
|
auto RelPos = cChunkDef::AbsoluteToRelative(a_PlacedBlockPos);
|
||||||
return CanBeAt(a_ChunkInterface, RelPos.x, RelPos.y, RelPos.z, a_Chunk);
|
return CanBeAt(a_ChunkInterface, RelPos, a_Chunk);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -111,18 +116,18 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
|
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override
|
||||||
{
|
{
|
||||||
if (a_RelY <= 0)
|
if (a_RelPos.y <= 0)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!cBlockInfo::FullyOccupiesVoxel(a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ)))
|
if (!cBlockInfo::FullyOccupiesVoxel(a_Chunk.GetBlock(a_RelPos.addedY(-1))))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ);
|
NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelPos);
|
||||||
switch (Meta)
|
switch (Meta)
|
||||||
{
|
{
|
||||||
case E_META_RAIL_ASCEND_XP:
|
case E_META_RAIL_ASCEND_XP:
|
||||||
|
@ -132,19 +137,16 @@ public:
|
||||||
{
|
{
|
||||||
// Mapping between the meta and the neighbors that need checking
|
// Mapping between the meta and the neighbors that need checking
|
||||||
Meta -= E_META_RAIL_ASCEND_XP; // Base index at zero
|
Meta -= E_META_RAIL_ASCEND_XP; // Base index at zero
|
||||||
static const struct
|
static const Vector3i Coords[] =
|
||||||
{
|
{
|
||||||
int x, z;
|
{ 1, 0, 0}, // east, XP
|
||||||
} Coords[] =
|
{-1, 0, 0}, // west, XM
|
||||||
{
|
{ 0, 0, -1}, // north, ZM
|
||||||
{ 1, 0}, // east, XP
|
{ 0, 0, 1}, // south, ZP
|
||||||
{-1, 0}, // west, XM
|
|
||||||
{ 0, -1}, // north, ZM
|
|
||||||
{ 0, 1}, // south, ZP
|
|
||||||
} ;
|
} ;
|
||||||
BLOCKTYPE BlockType;
|
BLOCKTYPE BlockType;
|
||||||
NIBBLETYPE BlockMeta;
|
NIBBLETYPE BlockMeta;
|
||||||
if (!a_Chunk.UnboundedRelGetBlock(a_RelX + Coords[Meta].x, a_RelY, a_RelZ + Coords[Meta].z, BlockType, BlockMeta))
|
if (!a_Chunk.UnboundedRelGetBlock(a_RelPos + Coords[Meta], BlockType, BlockMeta))
|
||||||
{
|
{
|
||||||
// Too close to the edge, cannot simulate
|
// Too close to the edge, cannot simulate
|
||||||
return true;
|
return true;
|
||||||
|
@ -155,6 +157,10 @@ public:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
NIBBLETYPE FindMeta(cChunkInterface & a_ChunkInterface, Vector3i a_BlockPos)
|
NIBBLETYPE FindMeta(cChunkInterface & a_ChunkInterface, Vector3i a_BlockPos)
|
||||||
{
|
{
|
||||||
NIBBLETYPE Meta = 0;
|
NIBBLETYPE Meta = 0;
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cBlockRedstoneHandler :
|
class cBlockRedstoneHandler:
|
||||||
public cBlockHandler
|
public cBlockHandler
|
||||||
{
|
{
|
||||||
using Super = cBlockHandler;
|
using Super = cBlockHandler;
|
||||||
|
@ -20,16 +20,20 @@ public:
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override
|
||||||
{
|
{
|
||||||
if (a_RelY <= 0)
|
if (a_RelPos.y <= 0)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
BLOCKTYPE BelowBlock;
|
BLOCKTYPE BelowBlock;
|
||||||
NIBBLETYPE BelowBlockMeta;
|
NIBBLETYPE BelowBlockMeta;
|
||||||
a_Chunk.GetBlockTypeMeta(a_RelX, a_RelY - 1, a_RelZ, BelowBlock, BelowBlockMeta);
|
a_Chunk.GetBlockTypeMeta(a_RelPos.addedY(-1), BelowBlock, BelowBlockMeta);
|
||||||
|
|
||||||
if (cBlockInfo::FullyOccupiesVoxel(BelowBlock))
|
if (cBlockInfo::FullyOccupiesVoxel(BelowBlock))
|
||||||
{
|
{
|
||||||
|
@ -46,11 +50,19 @@ public:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
|
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
|
||||||
{
|
{
|
||||||
return cItem(E_ITEM_REDSTONE_DUST, 1, 0);
|
return cItem(E_ITEM_REDSTONE_DUST, 1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
||||||
{
|
{
|
||||||
UNUSED(a_Meta);
|
UNUSED(a_Meta);
|
||||||
|
|
|
@ -17,31 +17,39 @@ public:
|
||||||
|
|
||||||
using Super::Super; // Inherit constructor from base
|
using Super::Super; // Inherit constructor from base
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool OnUse(
|
virtual bool OnUse(
|
||||||
cChunkInterface & a_ChunkInterface,
|
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player,
|
||||||
cWorldInterface & a_WorldInterface,
|
const Vector3i a_BlockPos,
|
||||||
cPlayer & a_Player,
|
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ,
|
|
||||||
eBlockFace a_BlockFace,
|
eBlockFace a_BlockFace,
|
||||||
int a_CursorX, int a_CursorY, int a_CursorZ
|
const Vector3i a_CursorPos
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
Vector3i BlockPos{a_BlockX, a_BlockY, a_BlockZ};
|
a_ChunkInterface.SetBlock(a_BlockPos, E_BLOCK_REDSTONE_ORE_GLOWING, 0);
|
||||||
a_ChunkInterface.SetBlock(BlockPos, E_BLOCK_REDSTONE_ORE_GLOWING, 0);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual void OnDigging(
|
virtual void OnDigging(
|
||||||
cChunkInterface & a_ChunkInterface,
|
cChunkInterface & a_ChunkInterface,
|
||||||
cWorldInterface & a_WorldInterface,
|
cWorldInterface & a_WorldInterface,
|
||||||
cPlayer & a_Player,
|
cPlayer & a_Player,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ
|
const Vector3i a_BlockPos
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
Vector3i BlockPos{a_BlockX, a_BlockY, a_BlockZ};
|
a_ChunkInterface.SetBlock(a_BlockPos, E_BLOCK_REDSTONE_ORE_GLOWING, 0);
|
||||||
a_ChunkInterface.SetBlock(BlockPos, E_BLOCK_REDSTONE_ORE_GLOWING, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool IsUseable() override
|
virtual bool IsUseable() override
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
|
@ -61,6 +69,10 @@ public:
|
||||||
|
|
||||||
using Super::Super; // Inherit constructor from base
|
using Super::Super; // Inherit constructor from base
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual void OnUpdate(
|
virtual void OnUpdate(
|
||||||
cChunkInterface & a_ChunkInterface,
|
cChunkInterface & a_ChunkInterface,
|
||||||
cWorldInterface & a_WorldInterface,
|
cWorldInterface & a_WorldInterface,
|
||||||
|
|
|
@ -23,33 +23,63 @@ public:
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
virtual bool OnUse(
|
||||||
|
cChunkInterface & a_ChunkInterface,
|
||||||
|
cWorldInterface & a_WorldInterface,
|
||||||
|
cPlayer & a_Player,
|
||||||
|
const Vector3i a_BlockPos,
|
||||||
|
eBlockFace a_BlockFace,
|
||||||
|
const Vector3i a_CursorPos
|
||||||
|
) override
|
||||||
{
|
{
|
||||||
a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, ((a_ChunkInterface.GetBlockMeta({a_BlockX, a_BlockY, a_BlockZ}) + 0x04) & 0x0f));
|
// Increment the delay setting:
|
||||||
|
a_ChunkInterface.SetBlockMeta(a_BlockPos, ((a_ChunkInterface.GetBlockMeta(a_BlockPos) + 0x04) & 0x0f));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
virtual void OnCancelRightClick(
|
||||||
|
cChunkInterface & a_ChunkInterface,
|
||||||
|
cWorldInterface & a_WorldInterface,
|
||||||
|
cPlayer & a_Player,
|
||||||
|
const Vector3i a_BlockPos,
|
||||||
|
eBlockFace a_BlockFace
|
||||||
|
) override
|
||||||
{
|
{
|
||||||
UNUSED(a_ChunkInterface);
|
UNUSED(a_ChunkInterface);
|
||||||
a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
|
a_WorldInterface.SendBlockTo(a_BlockPos, a_Player);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool IsUseable(void) override
|
virtual bool IsUseable(void) override
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override
|
||||||
{
|
{
|
||||||
if (a_RelY <= 0)
|
if (a_RelPos.y <= 0)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
BLOCKTYPE BelowBlock;
|
BLOCKTYPE BelowBlock;
|
||||||
NIBBLETYPE BelowBlockMeta;
|
NIBBLETYPE BelowBlockMeta;
|
||||||
a_Chunk.GetBlockTypeMeta(a_RelX, a_RelY - 1, a_RelZ, BelowBlock, BelowBlockMeta);
|
a_Chunk.GetBlockTypeMeta(a_RelPos.addedY(-1), BelowBlock, BelowBlockMeta);
|
||||||
|
|
||||||
if (cBlockInfo::FullyOccupiesVoxel(BelowBlock))
|
if (cBlockInfo::FullyOccupiesVoxel(BelowBlock))
|
||||||
{
|
{
|
||||||
|
@ -66,17 +96,29 @@ public:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
|
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
|
||||||
{
|
{
|
||||||
return cItem(E_ITEM_REDSTONE_REPEATER, 1, 0);
|
return cItem(E_ITEM_REDSTONE_REPEATER, 1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
||||||
{
|
{
|
||||||
UNUSED(a_Meta);
|
UNUSED(a_Meta);
|
||||||
return 11;
|
return 11;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
inline static Vector3i GetLeftCoordinateOffset(NIBBLETYPE a_Meta)
|
inline static Vector3i GetLeftCoordinateOffset(NIBBLETYPE a_Meta)
|
||||||
{
|
{
|
||||||
switch (a_Meta & E_META_REDSTONE_REPEATER_FACING_MASK) // We only want the direction (bottom) bits
|
switch (a_Meta & E_META_REDSTONE_REPEATER_FACING_MASK) // We only want the direction (bottom) bits
|
||||||
|
@ -95,11 +137,18 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
inline static Vector3i GetFrontCoordinateOffset(NIBBLETYPE a_Meta)
|
inline static Vector3i GetFrontCoordinateOffset(NIBBLETYPE a_Meta)
|
||||||
{
|
{
|
||||||
return -GetRearCoordinateOffset(a_Meta);
|
return -GetRearCoordinateOffset(a_Meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
inline static Vector3i GetRearCoordinateOffset(NIBBLETYPE a_Meta)
|
inline static Vector3i GetRearCoordinateOffset(NIBBLETYPE a_Meta)
|
||||||
{
|
{
|
||||||
switch (a_Meta & E_META_REDSTONE_REPEATER_FACING_MASK) // We only want the direction (bottom) bits
|
switch (a_Meta & E_META_REDSTONE_REPEATER_FACING_MASK) // We only want the direction (bottom) bits
|
||||||
|
|
|
@ -34,9 +34,9 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
|
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override
|
||||||
{
|
{
|
||||||
return (a_RelY > 0) && IsBlockTypeOfDirt(a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ));
|
return (a_RelPos.y > 0) && IsBlockTypeOfDirt(a_Chunk.GetBlock(a_RelPos.addedY(-1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -27,15 +27,17 @@ public:
|
||||||
|
|
||||||
|
|
||||||
virtual bool GetPlacementBlockTypeMeta(
|
virtual bool GetPlacementBlockTypeMeta(
|
||||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
cChunkInterface & a_ChunkInterface,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
cPlayer & a_Player,
|
||||||
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
|
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
a_BlockType = m_BlockType;
|
a_BlockType = m_BlockType;
|
||||||
NIBBLETYPE Meta = static_cast<NIBBLETYPE>(a_Player.GetEquippedItem().m_ItemDamage);
|
NIBBLETYPE Meta = static_cast<NIBBLETYPE>(a_Player.GetEquippedItem().m_ItemDamage);
|
||||||
a_BlockMeta = BlockFaceToMetaData(a_BlockFace, Meta);
|
a_BlockMeta = BlockFaceToMetaData(a_ClickedBlockFace, Meta);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,17 +32,21 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
|
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override
|
||||||
{
|
{
|
||||||
if (a_RelY <= 0)
|
if (a_RelPos.y <= 0)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
BLOCKTYPE Type = a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ);
|
BLOCKTYPE Type = a_Chunk.GetBlock(a_RelPos.addedY(-1));
|
||||||
|
|
||||||
return ((Type == E_BLOCK_SIGN_POST) || (Type == E_BLOCK_WALLSIGN) || cBlockInfo::IsSolid(Type));
|
return ((Type == E_BLOCK_SIGN_POST) || (Type == E_BLOCK_WALLSIGN) || cBlockInfo::IsSolid(Type));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Converts the (player) rotation to placed-signpost block meta. */
|
||||||
static NIBBLETYPE RotationToMetaData(double a_Rotation)
|
static NIBBLETYPE RotationToMetaData(double a_Rotation)
|
||||||
{
|
{
|
||||||
a_Rotation += 180 + (180 / 16); // So it's not aligned with axis
|
a_Rotation += 180 + (180 / 16); // So it's not aligned with axis
|
||||||
|
@ -56,16 +60,28 @@ public:
|
||||||
return (static_cast<char>(a_Rotation)) % 16;
|
return (static_cast<char>(a_Rotation)) % 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override
|
virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override
|
||||||
{
|
{
|
||||||
return (a_Meta + 4) & 0x0f;
|
return (a_Meta + 4) & 0x0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override
|
virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override
|
||||||
{
|
{
|
||||||
return (a_Meta + 12) & 0x0f;
|
return (a_Meta + 12) & 0x0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override
|
virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override
|
||||||
{
|
{
|
||||||
// Mirrors signs over the XY plane (North-South Mirroring)
|
// Mirrors signs over the XY plane (North-South Mirroring)
|
||||||
|
@ -75,6 +91,10 @@ public:
|
||||||
return (a_Meta < 0x08) ? (0x08 - a_Meta) : (0x18 - a_Meta);
|
return (a_Meta < 0x08) ? (0x08 - a_Meta) : (0x18 - a_Meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override
|
virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override
|
||||||
{
|
{
|
||||||
// Mirrors signs over the YZ plane (East-West Mirroring)
|
// Mirrors signs over the YZ plane (East-West Mirroring)
|
||||||
|
@ -84,6 +104,10 @@ public:
|
||||||
return 0x0f - a_Meta;
|
return 0x0f - a_Meta;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
||||||
{
|
{
|
||||||
UNUSED(a_Meta);
|
UNUSED(a_Meta);
|
||||||
|
|
|
@ -44,9 +44,11 @@ public:
|
||||||
|
|
||||||
|
|
||||||
virtual bool GetPlacementBlockTypeMeta(
|
virtual bool GetPlacementBlockTypeMeta(
|
||||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
cChunkInterface & a_ChunkInterface,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
cPlayer & a_Player,
|
||||||
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
|
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
|
@ -54,18 +56,18 @@ public:
|
||||||
NIBBLETYPE Meta = static_cast<NIBBLETYPE>(a_Player.GetEquippedItem().m_ItemDamage);
|
NIBBLETYPE Meta = static_cast<NIBBLETYPE>(a_Player.GetEquippedItem().m_ItemDamage);
|
||||||
|
|
||||||
// Set the correct metadata based on player equipped item (i.e. a_BlockMeta not initialised yet)
|
// Set the correct metadata based on player equipped item (i.e. a_BlockMeta not initialised yet)
|
||||||
switch (a_BlockFace)
|
switch (a_ClickedBlockFace)
|
||||||
{
|
{
|
||||||
case BLOCK_FACE_TOP:
|
case BLOCK_FACE_TOP:
|
||||||
{
|
{
|
||||||
// Bottom half slab block
|
// Bottom half slab block
|
||||||
a_BlockMeta = Meta & 0x7;
|
a_BlockMeta = Meta & 0x07;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BLOCK_FACE_BOTTOM:
|
case BLOCK_FACE_BOTTOM:
|
||||||
{
|
{
|
||||||
// Top half slab block
|
// Top half slab block
|
||||||
a_BlockMeta = Meta | 0x8;
|
a_BlockMeta = Meta | 0x08;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BLOCK_FACE_EAST:
|
case BLOCK_FACE_EAST:
|
||||||
|
@ -73,15 +75,15 @@ public:
|
||||||
case BLOCK_FACE_SOUTH:
|
case BLOCK_FACE_SOUTH:
|
||||||
case BLOCK_FACE_WEST:
|
case BLOCK_FACE_WEST:
|
||||||
{
|
{
|
||||||
if (a_CursorY > 7)
|
if (a_CursorPos.y > 7)
|
||||||
{
|
{
|
||||||
// Cursor at top half of block, place top slab
|
// Cursor at top half of block, place top slab
|
||||||
a_BlockMeta = Meta | 0x8; break;
|
a_BlockMeta = Meta | 0x08; break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Cursor at bottom half of block, place bottom slab
|
// Cursor at bottom half of block, place bottom slab
|
||||||
a_BlockMeta = Meta & 0x7; break;
|
a_BlockMeta = Meta & 0x07; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case BLOCK_FACE_NONE: return false;
|
case BLOCK_FACE_NONE: return false;
|
||||||
|
@ -89,10 +91,10 @@ public:
|
||||||
|
|
||||||
// Check if the block at the coordinates is a single slab. Eligibility for combining has already been processed in ClientHandle
|
// Check if the block at the coordinates is a single slab. Eligibility for combining has already been processed in ClientHandle
|
||||||
// Changed to-be-placed to a double slab if we are clicking on a single slab, as opposed to placing one for the first time
|
// Changed to-be-placed to a double slab if we are clicking on a single slab, as opposed to placing one for the first time
|
||||||
if (IsAnySlabType(a_ChunkInterface.GetBlock({a_BlockX, a_BlockY, a_BlockZ})))
|
if (IsAnySlabType(a_ChunkInterface.GetBlock(a_PlacedBlockPos)))
|
||||||
{
|
{
|
||||||
a_BlockType = GetDoubleSlabType(m_BlockType);
|
a_BlockType = GetDoubleSlabType(m_BlockType);
|
||||||
a_BlockMeta = a_BlockMeta & 0x7;
|
a_BlockMeta = a_BlockMeta & 0x07;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -117,7 +119,13 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override
|
virtual void OnCancelRightClick(
|
||||||
|
cChunkInterface & a_ChunkInterface,
|
||||||
|
cWorldInterface & a_WorldInterface,
|
||||||
|
cPlayer & a_Player,
|
||||||
|
const Vector3i a_BlockPos,
|
||||||
|
eBlockFace a_BlockFace
|
||||||
|
) override
|
||||||
{
|
{
|
||||||
if ((a_BlockFace == BLOCK_FACE_NONE) || (a_Player.GetEquippedItem().m_ItemType != static_cast<short>(m_BlockType)))
|
if ((a_BlockFace == BLOCK_FACE_NONE) || (a_Player.GetEquippedItem().m_ItemType != static_cast<short>(m_BlockType)))
|
||||||
{
|
{
|
||||||
|
@ -125,7 +133,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sends the slab back to the client. It's to refuse a doubleslab placement. */
|
// Sends the slab back to the client. It's to refuse a doubleslab placement. */
|
||||||
a_Player.GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
|
a_Player.GetWorld()->SendBlockTo(a_BlockPos, a_Player);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -222,13 +230,13 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool IsInsideBlock(Vector3d a_Position, const BLOCKTYPE a_BlockType, const NIBBLETYPE a_BlockMeta) override
|
virtual bool IsInsideBlock(Vector3d a_Position, const NIBBLETYPE a_BlockMeta) override
|
||||||
{
|
{
|
||||||
if (a_BlockMeta & 0x8) // top half
|
if (a_BlockMeta & 0x08) // top half
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return cBlockHandler::IsInsideBlock(a_Position, a_BlockType, a_BlockMeta);
|
return cBlockHandler::IsInsideBlock(a_Position, a_BlockMeta);
|
||||||
}
|
}
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
@ -236,7 +244,7 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cBlockDoubleSlabHandler :
|
class cBlockDoubleSlabHandler:
|
||||||
public cBlockHandler
|
public cBlockHandler
|
||||||
{
|
{
|
||||||
using Super = cBlockHandler;
|
using Super = cBlockHandler;
|
||||||
|
|
|
@ -10,30 +10,40 @@
|
||||||
class cBlockSnowHandler :
|
class cBlockSnowHandler :
|
||||||
public cBlockHandler
|
public cBlockHandler
|
||||||
{
|
{
|
||||||
|
using Super = cBlockHandler;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
FullBlockMeta = 7 // Meta value of a full-height snow block
|
FullBlockMeta = 7 // Meta value of a full-height snow block
|
||||||
};
|
};
|
||||||
|
|
||||||
cBlockSnowHandler(BLOCKTYPE a_BlockType)
|
|
||||||
: cBlockHandler(a_BlockType)
|
cBlockSnowHandler(BLOCKTYPE a_BlockType):
|
||||||
|
Super(a_BlockType)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool GetPlacementBlockTypeMeta(
|
virtual bool GetPlacementBlockTypeMeta(
|
||||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
cChunkInterface & a_ChunkInterface,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
cPlayer & a_Player,
|
||||||
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
|
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
a_BlockType = m_BlockType;
|
a_BlockType = m_BlockType;
|
||||||
|
|
||||||
|
// Check if incrementing existing snow height:
|
||||||
BLOCKTYPE BlockBeforePlacement;
|
BLOCKTYPE BlockBeforePlacement;
|
||||||
NIBBLETYPE MetaBeforePlacement;
|
NIBBLETYPE MetaBeforePlacement;
|
||||||
a_ChunkInterface.GetBlockTypeMeta({a_BlockX, a_BlockY, a_BlockZ}, BlockBeforePlacement, MetaBeforePlacement);
|
a_ChunkInterface.GetBlockTypeMeta(a_PlacedBlockPos, BlockBeforePlacement, MetaBeforePlacement);
|
||||||
|
|
||||||
if ((BlockBeforePlacement == E_BLOCK_SNOW) && (MetaBeforePlacement < FullBlockMeta))
|
if ((BlockBeforePlacement == E_BLOCK_SNOW) && (MetaBeforePlacement < FullBlockMeta))
|
||||||
{
|
{
|
||||||
// Only increment if:
|
// Only increment if:
|
||||||
|
@ -45,16 +55,19 @@ public:
|
||||||
|
|
||||||
// First time placement, check placement is valid
|
// First time placement, check placement is valid
|
||||||
a_BlockMeta = 0;
|
a_BlockMeta = 0;
|
||||||
|
|
||||||
BLOCKTYPE BlockBelow;
|
BLOCKTYPE BlockBelow;
|
||||||
NIBBLETYPE MetaBelow;
|
NIBBLETYPE MetaBelow;
|
||||||
return (
|
return (
|
||||||
(a_BlockY > 0) &&
|
(a_PlacedBlockPos.y > 0) &&
|
||||||
a_ChunkInterface.GetBlockTypeMeta({a_BlockX, a_BlockY - 1, a_BlockZ}, BlockBelow, MetaBelow) &&
|
a_ChunkInterface.GetBlockTypeMeta(a_PlacedBlockPos.addedY(-1), BlockBelow, MetaBelow) &&
|
||||||
CanBeOn(BlockBelow, MetaBelow)
|
CanBeOn(BlockBelow, MetaBelow)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool DoesIgnoreBuildCollision(cChunkInterface & a_ChunkInterface, Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta) override
|
virtual bool DoesIgnoreBuildCollision(cChunkInterface & a_ChunkInterface, Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta) override
|
||||||
{
|
{
|
||||||
if ((a_Player.GetEquippedItem().m_ItemType == E_BLOCK_SNOW) && (a_Meta < FullBlockMeta))
|
if ((a_Player.GetEquippedItem().m_ItemType == E_BLOCK_SNOW) && (a_Meta < FullBlockMeta))
|
||||||
|
@ -97,35 +110,47 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
|
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override
|
||||||
{
|
{
|
||||||
if (a_RelY > 0)
|
if (a_RelPos.y <= 0)
|
||||||
{
|
{
|
||||||
BLOCKTYPE BlockBelow = a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ);
|
return false;
|
||||||
NIBBLETYPE MetaBelow = a_Chunk.GetMeta(a_RelX, a_RelY - 1, a_RelZ);
|
|
||||||
|
|
||||||
return CanBeOn(BlockBelow, MetaBelow);
|
|
||||||
}
|
}
|
||||||
|
auto BelowPos = a_RelPos.addedY(-1);
|
||||||
return false;
|
auto BlockBelow = a_Chunk.GetBlock(BelowPos);
|
||||||
|
auto MetaBelow = a_Chunk.GetMeta(BelowPos);
|
||||||
|
return CanBeOn(BlockBelow, MetaBelow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool DoesDropOnUnsuitable(void) override
|
virtual bool DoesDropOnUnsuitable(void) override
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
||||||
{
|
{
|
||||||
UNUSED(a_Meta);
|
UNUSED(a_Meta);
|
||||||
return 14;
|
return 14;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool IsInsideBlock(Vector3d a_Position, const BLOCKTYPE a_BlockType, const NIBBLETYPE a_BlockMeta) override
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
virtual bool IsInsideBlock(const Vector3d a_RelPosition, const NIBBLETYPE a_BlockMeta) override
|
||||||
{
|
{
|
||||||
return a_Position.y < (cBlockInfo::GetBlockHeight(a_BlockType) * (a_BlockMeta & 0x07));
|
return a_RelPosition.y < (cBlockInfo::GetBlockHeight(m_BlockType) * (a_BlockMeta & 0x07));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/** Returns true if snow can be placed on top of a block with the given type and meta. */
|
/** Returns true if snow can be placed on top of a block with the given type and meta. */
|
||||||
|
|
|
@ -17,25 +17,27 @@ public:
|
||||||
cBlockStairsHandler(BLOCKTYPE a_BlockType):
|
cBlockStairsHandler(BLOCKTYPE a_BlockType):
|
||||||
Super(a_BlockType)
|
Super(a_BlockType)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool GetPlacementBlockTypeMeta(
|
virtual bool GetPlacementBlockTypeMeta(
|
||||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
cChunkInterface & a_ChunkInterface,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
cPlayer & a_Player,
|
||||||
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
|
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
UNUSED(a_ChunkInterface);
|
UNUSED(a_ChunkInterface);
|
||||||
UNUSED(a_BlockX);
|
UNUSED(a_PlacedBlockPos);
|
||||||
UNUSED(a_BlockY);
|
UNUSED(a_CursorPos);
|
||||||
UNUSED(a_BlockZ);
|
|
||||||
UNUSED(a_CursorX);
|
|
||||||
UNUSED(a_CursorZ);
|
|
||||||
a_BlockType = m_BlockType;
|
a_BlockType = m_BlockType;
|
||||||
a_BlockMeta = RotationToMetaData(a_Player.GetYaw());
|
a_BlockMeta = RotationToMetaData(a_Player.GetYaw());
|
||||||
switch (a_BlockFace)
|
switch (a_ClickedBlockFace)
|
||||||
{
|
{
|
||||||
case BLOCK_FACE_TOP: break;
|
case BLOCK_FACE_TOP: break;
|
||||||
case BLOCK_FACE_BOTTOM: a_BlockMeta = a_BlockMeta | 0x4; break; // When placing onto a bottom face, always place an upside-down stairs block
|
case BLOCK_FACE_BOTTOM: a_BlockMeta = a_BlockMeta | 0x4; break; // When placing onto a bottom face, always place an upside-down stairs block
|
||||||
|
@ -45,7 +47,7 @@ public:
|
||||||
case BLOCK_FACE_WEST:
|
case BLOCK_FACE_WEST:
|
||||||
{
|
{
|
||||||
// When placing onto a sideways face, check cursor, if in top half, make it an upside-down stairs block
|
// When placing onto a sideways face, check cursor, if in top half, make it an upside-down stairs block
|
||||||
if (a_CursorY > 8)
|
if (a_CursorPos.y > 8)
|
||||||
{
|
{
|
||||||
a_BlockMeta |= 0x4;
|
a_BlockMeta |= 0x4;
|
||||||
}
|
}
|
||||||
|
@ -56,6 +58,10 @@ public:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static NIBBLETYPE RotationToMetaData(double a_Rotation)
|
static NIBBLETYPE RotationToMetaData(double a_Rotation)
|
||||||
{
|
{
|
||||||
a_Rotation += 90 + 45; // So its not aligned with axis
|
a_Rotation += 90 + 45; // So its not aligned with axis
|
||||||
|
@ -81,12 +87,20 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual NIBBLETYPE MetaMirrorXZ(NIBBLETYPE a_Meta) override
|
virtual NIBBLETYPE MetaMirrorXZ(NIBBLETYPE a_Meta) override
|
||||||
{
|
{
|
||||||
// Toggle bit 3:
|
// Toggle bit 3:
|
||||||
return (a_Meta & 0x0b) | ((~a_Meta) & 0x04);
|
return (a_Meta & 0x0b) | ((~a_Meta) & 0x04);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
||||||
{
|
{
|
||||||
UNUSED(a_Meta);
|
UNUSED(a_Meta);
|
||||||
|
@ -114,12 +128,16 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** EXCEPTION a.k.a. why is this removed:
|
/** EXCEPTION a.k.a. why is this removed:
|
||||||
This collision-detection is actually more accurate than the client, but since the client itself
|
This collision-detection is actually more accurate than the client, but since the client itself
|
||||||
sends inaccurate / sparse data, it's easier to just err on the side of the client and keep the
|
sends inaccurate / sparse data, it's easier to just err on the side of the client and keep the
|
||||||
two in sync by assuming that if a player hit ANY of the stair's bounding cube, it counts as the ground. */
|
two in sync by assuming that if a player hit ANY of the stair's bounding cube, it counts as the ground. */
|
||||||
#if 0
|
#if 0
|
||||||
bool IsInsideBlock(const Vector3d & a_Position, const BLOCKTYPE a_BlockType, const NIBBLETYPE a_BlockMeta)
|
bool IsInsideBlock(Vector3d a_RelPosition, const BLOCKTYPE a_BlockType, const NIBBLETYPE a_BlockMeta)
|
||||||
{
|
{
|
||||||
if (a_BlockMeta & 0x4) // upside down
|
if (a_BlockMeta & 0x4) // upside down
|
||||||
{
|
{
|
||||||
|
@ -127,19 +145,19 @@ public:
|
||||||
}
|
}
|
||||||
else if ((a_BlockMeta & 0x3) == 0) // tall side is east (+X)
|
else if ((a_BlockMeta & 0x3) == 0) // tall side is east (+X)
|
||||||
{
|
{
|
||||||
return a_Position.y < ((a_Position.x > 0.5) ? 1.0 : 0.5);
|
return (a_RelPosition.y < ((a_RelPosition.x > 0.5) ? 1.0 : 0.5));
|
||||||
}
|
}
|
||||||
else if ((a_BlockMeta & 0x3) == 1) // tall side is west (-X)
|
else if ((a_BlockMeta & 0x3) == 1) // tall side is west (-X)
|
||||||
{
|
{
|
||||||
return a_Position.y < ((a_Position.x < 0.5) ? 1.0 : 0.5);
|
return (a_RelPosition.y < ((a_RelPosition.x < 0.5) ? 1.0 : 0.5));
|
||||||
}
|
}
|
||||||
else if ((a_BlockMeta & 0x3) == 2) // tall side is south (+Z)
|
else if ((a_BlockMeta & 0x3) == 2) // tall side is south (+Z)
|
||||||
{
|
{
|
||||||
return a_Position.y < ((a_Position.z > 0.5) ? 1.0 : 0.5);
|
return (a_RelPosition.y < ((a_RelPosition.z > 0.5) ? 1.0 : 0.5));
|
||||||
}
|
}
|
||||||
else if ((a_BlockMeta & 0x3) == 3) // tall side is north (-Z)
|
else if ((a_BlockMeta & 0x3) == 3) // tall side is north (-Z)
|
||||||
{
|
{
|
||||||
return a_Position.y < ((a_Position.z < 0.5) ? 1.0 : 0.5);
|
return (a_RelPosition.y < ((a_RelPosition.z < 0.5) ? 1.0 : 0.5));
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,9 +36,9 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
|
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override
|
||||||
{
|
{
|
||||||
return ((a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) == E_BLOCK_FARMLAND));
|
return ((a_RelPos.y > 0) && (a_Chunk.GetBlock(a_RelPos.addedY(-1)) == E_BLOCK_FARMLAND));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -32,36 +32,32 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
|
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override
|
||||||
{
|
{
|
||||||
if (a_RelY <= 0)
|
if (a_RelPos.y <= 0)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ))
|
switch (a_Chunk.GetBlock(a_RelPos.addedY(-1)))
|
||||||
{
|
{
|
||||||
case E_BLOCK_DIRT:
|
case E_BLOCK_DIRT:
|
||||||
case E_BLOCK_GRASS:
|
case E_BLOCK_GRASS:
|
||||||
case E_BLOCK_FARMLAND:
|
case E_BLOCK_FARMLAND:
|
||||||
case E_BLOCK_SAND:
|
case E_BLOCK_SAND:
|
||||||
{
|
{
|
||||||
static const struct
|
static const Vector3i Coords[] =
|
||||||
{
|
{
|
||||||
int x, z;
|
{-1, -1, 0},
|
||||||
} Coords[] =
|
{ 1, -1, 0},
|
||||||
{
|
{ 0, -1, -1},
|
||||||
{-1, 0},
|
{ 0, -1, 1},
|
||||||
{ 1, 0},
|
|
||||||
{ 0, -1},
|
|
||||||
{ 0, 1},
|
|
||||||
} ;
|
} ;
|
||||||
a_RelY -= 1;
|
|
||||||
for (size_t i = 0; i < ARRAYCOUNT(Coords); i++)
|
for (size_t i = 0; i < ARRAYCOUNT(Coords); i++)
|
||||||
{
|
{
|
||||||
BLOCKTYPE BlockType;
|
BLOCKTYPE BlockType;
|
||||||
NIBBLETYPE BlockMeta;
|
NIBBLETYPE BlockMeta;
|
||||||
if (!a_Chunk.UnboundedRelGetBlock(a_RelX + Coords[i].x, a_RelY, a_RelZ + Coords[i].z, BlockType, BlockMeta))
|
if (!a_Chunk.UnboundedRelGetBlock(a_RelPos + Coords[i], BlockType, BlockMeta))
|
||||||
{
|
{
|
||||||
// Too close to the edge, cannot simulate
|
// Too close to the edge, cannot simulate
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -10,17 +10,34 @@
|
||||||
class cBlockTNTHandler :
|
class cBlockTNTHandler :
|
||||||
public cBlockHandler
|
public cBlockHandler
|
||||||
{
|
{
|
||||||
|
using Super = cBlockHandler;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
cBlockTNTHandler(BLOCKTYPE a_BlockType)
|
|
||||||
: cBlockHandler(a_BlockType)
|
cBlockTNTHandler(BLOCKTYPE a_BlockType):
|
||||||
|
Super(a_BlockType)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
virtual void OnCancelRightClick(
|
||||||
|
cChunkInterface & a_ChunkInterface,
|
||||||
|
cWorldInterface & a_WorldInterface,
|
||||||
|
cPlayer & a_Player,
|
||||||
|
const Vector3i a_BlockPos,
|
||||||
|
eBlockFace a_BlockFace
|
||||||
|
) override
|
||||||
{
|
{
|
||||||
a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
|
a_WorldInterface.SendBlockTo(a_BlockPos, a_Player);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
||||||
{
|
{
|
||||||
UNUSED(a_Meta);
|
UNUSED(a_Meta);
|
||||||
|
|
|
@ -54,14 +54,14 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
|
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override
|
||||||
{
|
{
|
||||||
if (a_RelY <= 0)
|
if (a_RelPos.y <= 0)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
BLOCKTYPE BelowBlock = a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ);
|
BLOCKTYPE BelowBlock = a_Chunk.GetBlock(a_RelPos.addedY(-1));
|
||||||
return IsBlockTypeOfDirt(BelowBlock);
|
return IsBlockTypeOfDirt(BelowBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cBlockTorchHandler :
|
class cBlockTorchHandler:
|
||||||
public cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x7, 0x4, 0x1, 0x3, 0x2>>
|
public cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x7, 0x4, 0x1, 0x3, 0x2>>
|
||||||
{
|
{
|
||||||
using Super = cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x7, 0x4, 0x1, 0x3, 0x2>>;
|
using Super = cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x7, 0x4, 0x1, 0x3, 0x2>>;
|
||||||
|
@ -20,39 +20,46 @@ public:
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool GetPlacementBlockTypeMeta(
|
virtual bool GetPlacementBlockTypeMeta(
|
||||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
cChunkInterface & a_ChunkInterface,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
cPlayer & a_Player,
|
||||||
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
|
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
BLOCKTYPE Block;
|
BLOCKTYPE ClickedBlockType;
|
||||||
NIBBLETYPE Meta;
|
NIBBLETYPE ClickedBlockMeta;
|
||||||
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, true); // Set to clicked block
|
auto ClickedBlockPos = AddFaceDirection(a_PlacedBlockPos, a_ClickedBlockFace, true);
|
||||||
a_ChunkInterface.GetBlockTypeMeta({a_BlockX, a_BlockY, a_BlockZ}, Block, Meta);
|
a_ChunkInterface.GetBlockTypeMeta(ClickedBlockPos, ClickedBlockType, ClickedBlockMeta);
|
||||||
|
if (!CanBePlacedOn(ClickedBlockType, ClickedBlockMeta, a_ClickedBlockFace))
|
||||||
if (!CanBePlacedOn(Block, Meta, a_BlockFace)) // Try to preserve original direction
|
|
||||||
{
|
{
|
||||||
// Torch couldn't be placed on whatever face was clicked, last ditch resort - find another face
|
// Couldn't be placed on whatever face was clicked, last ditch resort - find another face
|
||||||
|
a_ClickedBlockFace = FindSuitableFace(a_ChunkInterface, a_PlacedBlockPos); // Set a_BlockFace to a valid direction which will be converted later to a metadata
|
||||||
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, false); // Reset to torch block
|
if (a_ClickedBlockFace == BLOCK_FACE_NONE)
|
||||||
a_BlockFace = FindSuitableFace(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ); // Set a_BlockFace to a valid direction which will be converted later to a metadata
|
|
||||||
if (a_BlockFace == BLOCK_FACE_NONE)
|
|
||||||
{
|
{
|
||||||
// No attachable face found - don't place the torch
|
// No attachable face found - don't place the torch
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
a_BlockType = m_BlockType;
|
a_BlockType = m_BlockType;
|
||||||
a_BlockMeta = DirectionToMetaData(a_BlockFace);
|
a_BlockMeta = BlockFaceToMetaData(a_ClickedBlockFace);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static NIBBLETYPE DirectionToMetaData(eBlockFace a_Direction)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Converts the block face of the neighbor to which the torch is attached, to the torch block's meta. */
|
||||||
|
inline static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_NeighborBlockFace)
|
||||||
{
|
{
|
||||||
switch (a_Direction)
|
switch (a_NeighborBlockFace)
|
||||||
{
|
{
|
||||||
case BLOCK_FACE_BOTTOM: ASSERT(!"Shouldn't be getting this face"); return 0;
|
case BLOCK_FACE_BOTTOM: ASSERT(!"Shouldn't be getting this face"); return 0;
|
||||||
case BLOCK_FACE_TOP: return E_META_TORCH_FLOOR;
|
case BLOCK_FACE_TOP: return E_META_TORCH_FLOOR;
|
||||||
|
@ -69,7 +76,12 @@ public:
|
||||||
return 0x0;
|
return 0x0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static eBlockFace MetaDataToDirection(NIBBLETYPE a_MetaData)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Converts the torch block's meta to the block face of the neighbor to which the torch is attached. */
|
||||||
|
inline static eBlockFace MetaDataToBlockFace(NIBBLETYPE a_MetaData)
|
||||||
{
|
{
|
||||||
switch (a_MetaData)
|
switch (a_MetaData)
|
||||||
{
|
{
|
||||||
|
@ -88,6 +100,11 @@ public:
|
||||||
return BLOCK_FACE_TOP;
|
return BLOCK_FACE_TOP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Returns true if the torch can be placed on the specified block's face. */
|
||||||
static bool CanBePlacedOn(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, eBlockFace a_BlockFace)
|
static bool CanBePlacedOn(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, eBlockFace a_BlockFace)
|
||||||
{
|
{
|
||||||
switch (a_BlockType)
|
switch (a_BlockType)
|
||||||
|
@ -115,7 +132,7 @@ public:
|
||||||
case E_BLOCK_STONE_SLAB:
|
case E_BLOCK_STONE_SLAB:
|
||||||
case E_BLOCK_WOODEN_SLAB:
|
case E_BLOCK_WOODEN_SLAB:
|
||||||
{
|
{
|
||||||
// Toches can be placed on the top of these slabs only if the occupy the top half of the voxel
|
// Toches can be placed only on the top of top-half-slabs
|
||||||
return ((a_BlockFace == BLOCK_FACE_YP) && ((a_BlockMeta & 0x08) == 0x08));
|
return ((a_BlockFace == BLOCK_FACE_YP) && ((a_BlockMeta & 0x08) == 0x08));
|
||||||
}
|
}
|
||||||
case E_BLOCK_OAK_WOOD_STAIRS:
|
case E_BLOCK_OAK_WOOD_STAIRS:
|
||||||
|
@ -146,45 +163,52 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Finds a suitable face to place the torch, returning BLOCK_FACE_NONE on failure */
|
|
||||||
static eBlockFace FindSuitableFace(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ)
|
|
||||||
{
|
|
||||||
for (int i = BLOCK_FACE_YM; i <= BLOCK_FACE_XP; i++) // Loop through all directions
|
|
||||||
{
|
|
||||||
eBlockFace Face = static_cast<eBlockFace>(i);
|
|
||||||
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, Face, true);
|
|
||||||
BLOCKTYPE BlockInQuestion;
|
|
||||||
NIBBLETYPE BlockInQuestionMeta;
|
|
||||||
a_ChunkInterface.GetBlockTypeMeta({a_BlockX, a_BlockY, a_BlockZ}, BlockInQuestion, BlockInQuestionMeta);
|
|
||||||
|
|
||||||
if (CanBePlacedOn(BlockInQuestion, BlockInQuestionMeta, Face))
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Returns a suitable neighbor's blockface to place the torch at the specified pos
|
||||||
|
Returns BLOCK_FACE_NONE on failure */
|
||||||
|
static eBlockFace FindSuitableFace(cChunkInterface & a_ChunkInterface, const Vector3i a_TorchPos)
|
||||||
|
{
|
||||||
|
for (int i = BLOCK_FACE_YM; i <= BLOCK_FACE_XP; i++) // Loop through all faces
|
||||||
|
{
|
||||||
|
auto Face = static_cast<eBlockFace>(i);
|
||||||
|
auto NeighborPos = AddFaceDirection(a_TorchPos, Face, true);
|
||||||
|
BLOCKTYPE NeighborBlockType;
|
||||||
|
NIBBLETYPE NeighborBlockMeta;
|
||||||
|
a_ChunkInterface.GetBlockTypeMeta(NeighborPos, NeighborBlockType, NeighborBlockMeta);
|
||||||
|
if (CanBePlacedOn(NeighborBlockType, NeighborBlockMeta, Face))
|
||||||
{
|
{
|
||||||
return Face;
|
return Face;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
// Reset coords in preparation for next iteration
|
|
||||||
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, Face, false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return BLOCK_FACE_NONE;
|
return BLOCK_FACE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
|
|
||||||
{
|
|
||||||
eBlockFace Face = MetaDataToDirection(a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ));
|
|
||||||
AddFaceDirection(a_RelX, a_RelY, a_RelZ, Face, true);
|
|
||||||
|
|
||||||
BLOCKTYPE BlockInQuestion;
|
|
||||||
NIBBLETYPE BlockInQuestionMeta;
|
|
||||||
if (!a_Chunk.UnboundedRelGetBlock(a_RelX, a_RelY, a_RelZ, BlockInQuestion, BlockInQuestionMeta))
|
|
||||||
|
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override
|
||||||
|
{
|
||||||
|
auto Face = MetaDataToBlockFace(a_Chunk.GetMeta(a_RelPos));
|
||||||
|
auto NeighborRelPos = AddFaceDirection(a_RelPos, Face, true);
|
||||||
|
BLOCKTYPE NeighborBlockType;
|
||||||
|
NIBBLETYPE NeighborBlockMeta;
|
||||||
|
if (!a_Chunk.UnboundedRelGetBlock(NeighborRelPos, NeighborBlockType, NeighborBlockMeta))
|
||||||
{
|
{
|
||||||
|
// Neighbor in an unloaded chunk, bail out without changint this.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return CanBePlacedOn(BlockInQuestion, BlockInQuestionMeta, Face);
|
return CanBePlacedOn(NeighborBlockType, NeighborBlockMeta, Face);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
||||||
{
|
{
|
||||||
UNUSED(a_Meta);
|
UNUSED(a_Meta);
|
||||||
|
|
|
@ -32,7 +32,14 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override
|
virtual bool OnUse(
|
||||||
|
cChunkInterface & a_ChunkInterface,
|
||||||
|
cWorldInterface & a_WorldInterface,
|
||||||
|
cPlayer & a_Player,
|
||||||
|
const Vector3i a_BlockPos,
|
||||||
|
eBlockFace a_BlockFace,
|
||||||
|
const Vector3i a_CursorPos
|
||||||
|
) override
|
||||||
{
|
{
|
||||||
if (m_BlockType == E_BLOCK_IRON_TRAPDOOR)
|
if (m_BlockType == E_BLOCK_IRON_TRAPDOOR)
|
||||||
{
|
{
|
||||||
|
@ -41,36 +48,56 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flip the ON bit on / off using the XOR bitwise operation
|
// Flip the ON bit on / off using the XOR bitwise operation
|
||||||
NIBBLETYPE Meta = (a_ChunkInterface.GetBlockMeta({a_BlockX, a_BlockY, a_BlockZ}) ^ 0x04);
|
NIBBLETYPE Meta = (a_ChunkInterface.GetBlockMeta(a_BlockPos) ^ 0x04);
|
||||||
a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta);
|
a_ChunkInterface.SetBlockMeta(a_BlockPos, Meta);
|
||||||
a_WorldInterface.GetBroadcastManager().BroadcastSoundParticleEffect(EffectID::SFX_RANDOM_FENCE_GATE_OPEN, { a_BlockX, a_BlockY, a_BlockZ }, 0, a_Player.GetClientHandle());
|
a_WorldInterface.GetBroadcastManager().BroadcastSoundParticleEffect(EffectID::SFX_RANDOM_FENCE_GATE_OPEN, a_BlockPos, 0, a_Player.GetClientHandle());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
virtual void OnCancelRightClick(
|
||||||
|
cChunkInterface & a_ChunkInterface,
|
||||||
|
cWorldInterface & a_WorldInterface,
|
||||||
|
cPlayer & a_Player,
|
||||||
|
const Vector3i a_BlockPos,
|
||||||
|
eBlockFace a_BlockFace
|
||||||
|
) override
|
||||||
{
|
{
|
||||||
UNUSED(a_ChunkInterface);
|
UNUSED(a_ChunkInterface);
|
||||||
a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
|
a_WorldInterface.SendBlockTo(a_BlockPos, a_Player);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool GetPlacementBlockTypeMeta(
|
virtual bool GetPlacementBlockTypeMeta(
|
||||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
cChunkInterface & a_ChunkInterface,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
cPlayer & a_Player,
|
||||||
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
|
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
a_BlockType = m_BlockType;
|
a_BlockType = m_BlockType;
|
||||||
a_BlockMeta = BlockFaceToMetaData(a_BlockFace);
|
a_BlockMeta = BlockFaceToMetaData(a_ClickedBlockFace);
|
||||||
|
|
||||||
if (a_CursorY > 7)
|
if (a_CursorPos.y > 7)
|
||||||
{
|
{
|
||||||
a_BlockMeta |= 0x8;
|
a_BlockMeta |= 0x8;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
inline static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_BlockFace)
|
inline static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_BlockFace)
|
||||||
{
|
{
|
||||||
switch (a_BlockFace)
|
switch (a_BlockFace)
|
||||||
|
@ -90,6 +117,10 @@ public:
|
||||||
UNREACHABLE("Unsupported block face");
|
UNREACHABLE("Unsupported block face");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
inline static eBlockFace BlockMetaDataToBlockFace(NIBBLETYPE a_Meta)
|
inline static eBlockFace BlockMetaDataToBlockFace(NIBBLETYPE a_Meta)
|
||||||
{
|
{
|
||||||
switch (a_Meta & 0x3)
|
switch (a_Meta & 0x3)
|
||||||
|
@ -106,6 +137,10 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
||||||
{
|
{
|
||||||
UNUSED(a_Meta);
|
UNUSED(a_Meta);
|
||||||
|
|
|
@ -24,14 +24,16 @@ public:
|
||||||
|
|
||||||
|
|
||||||
virtual bool GetPlacementBlockTypeMeta(
|
virtual bool GetPlacementBlockTypeMeta(
|
||||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
cChunkInterface & a_ChunkInterface,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
cPlayer & a_Player,
|
||||||
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
|
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
a_BlockType = m_BlockType;
|
a_BlockType = m_BlockType;
|
||||||
a_BlockMeta = DirectionToMetadata(a_BlockFace);
|
a_BlockMeta = DirectionToMetadata(a_ClickedBlockFace);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -79,16 +81,17 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
|
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override
|
||||||
{
|
{
|
||||||
NIBBLETYPE Meta;
|
auto Meta = a_Chunk.GetMeta(a_RelPos);
|
||||||
a_Chunk.UnboundedRelGetBlockMeta(a_RelX, a_RelY, a_RelZ, Meta);
|
auto NeighborPos = AddFaceDirection(a_RelPos, MetadataToDirection(Meta), true);
|
||||||
|
if (!cChunkDef::IsValidHeight(NeighborPos.y))
|
||||||
AddFaceDirection(a_RelX, a_RelY, a_RelZ, MetadataToDirection(Meta), true);
|
{
|
||||||
BLOCKTYPE BlockIsOn;
|
return false;
|
||||||
a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ, BlockIsOn);
|
}
|
||||||
|
BLOCKTYPE NeighborBlockType;
|
||||||
return ((a_RelY > 0) && cBlockInfo::FullyOccupiesVoxel(BlockIsOn));
|
a_Chunk.UnboundedRelGetBlockType(a_RelPos, NeighborBlockType);
|
||||||
|
return cBlockInfo::FullyOccupiesVoxel(NeighborBlockType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -23,23 +23,25 @@ public:
|
||||||
|
|
||||||
|
|
||||||
virtual bool GetPlacementBlockTypeMeta(
|
virtual bool GetPlacementBlockTypeMeta(
|
||||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
cChunkInterface & a_ChunkInterface,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
cPlayer & a_Player,
|
||||||
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
|
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
// TODO: Disallow placement where the vine doesn't attach to something properly
|
// TODO: Disallow placement where the vine doesn't attach to something properly
|
||||||
BLOCKTYPE BlockType = 0;
|
BLOCKTYPE BlockType = 0;
|
||||||
NIBBLETYPE BlockMeta;
|
NIBBLETYPE BlockMeta;
|
||||||
a_ChunkInterface.GetBlockTypeMeta({a_BlockX, a_BlockY, a_BlockZ}, BlockType, BlockMeta);
|
a_ChunkInterface.GetBlockTypeMeta(a_PlacedBlockPos, BlockType, BlockMeta);
|
||||||
if (BlockType == m_BlockType)
|
if (BlockType == m_BlockType)
|
||||||
{
|
{
|
||||||
a_BlockMeta = BlockMeta | DirectionToMetaData(a_BlockFace);
|
a_BlockMeta = BlockMeta | DirectionToMetaData(a_ClickedBlockFace);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
a_BlockMeta = DirectionToMetaData(a_BlockFace);
|
a_BlockMeta = DirectionToMetaData(a_ClickedBlockFace);
|
||||||
}
|
}
|
||||||
a_BlockType = m_BlockType;
|
a_BlockType = m_BlockType;
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -33,39 +33,45 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
|
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, const Vector3i a_RelPos, const cChunk & a_Chunk) override
|
||||||
{
|
{
|
||||||
int BlockX = (a_Chunk.GetPosX() * cChunkDef::Width) + a_RelX;
|
auto NeighborPos = a_RelPos + GetOffsetBehindTheSign(a_Chunk.GetMeta(a_RelPos));
|
||||||
int BlockZ = (a_Chunk.GetPosZ() * cChunkDef::Width) + a_RelZ;
|
BLOCKTYPE NeighborType;
|
||||||
GetBlockCoordsBehindTheSign(a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ), BlockX, BlockZ);
|
if (!a_Chunk.UnboundedRelGetBlockType(NeighborPos, NeighborType))
|
||||||
BLOCKTYPE Type = a_ChunkInterface.GetBlock({BlockX, a_RelY, BlockZ});
|
{
|
||||||
|
// The neighbor is not accessible (unloaded chunk), bail out without changing this
|
||||||
return ((Type == E_BLOCK_WALLSIGN) || (Type == E_BLOCK_SIGN_POST) || cBlockInfo::IsSolid(Type));
|
return true;
|
||||||
|
}
|
||||||
|
return ((NeighborType == E_BLOCK_WALLSIGN) || (NeighborType == E_BLOCK_SIGN_POST) || cBlockInfo::IsSolid(NeighborType));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void GetBlockCoordsBehindTheSign(NIBBLETYPE a_BlockMeta, int & a_BlockX, int & a_BlockZ)
|
/** Returns the offset from the sign coords to the block to which the wallsign is attached, based on the wallsign's block meta.
|
||||||
|
Asserts / returns a zero vector on wrong meta. */
|
||||||
|
static Vector3i GetOffsetBehindTheSign(NIBBLETYPE a_BlockMeta)
|
||||||
{
|
{
|
||||||
switch (a_BlockMeta)
|
switch (a_BlockMeta)
|
||||||
{
|
{
|
||||||
case 2: a_BlockZ++; break;
|
case 2: return Vector3i( 0, 0, 1);
|
||||||
case 3: a_BlockZ--; break;
|
case 3: return Vector3i( 0, 0, -1);
|
||||||
case 4: a_BlockX++; break;
|
case 4: return Vector3i( 1, 0, 0);
|
||||||
case 5: a_BlockX--; break;
|
case 5: return Vector3i(-1, 0, 0);
|
||||||
default: break;
|
|
||||||
}
|
}
|
||||||
|
ASSERT(!"Invalid wallsign block meta");
|
||||||
|
return Vector3i();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static NIBBLETYPE DirectionToMetaData(eBlockFace a_Direction)
|
/** Converts the block face of the neighbor to which the wallsign is attached to the wallsign block's meta. */
|
||||||
|
static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_NeighborBlockFace)
|
||||||
{
|
{
|
||||||
switch (a_Direction)
|
switch (a_NeighborBlockFace)
|
||||||
{
|
{
|
||||||
case BLOCK_FACE_ZM: return 0x02;
|
case BLOCK_FACE_ZM: return 0x02;
|
||||||
case BLOCK_FACE_ZP: return 0x03;
|
case BLOCK_FACE_ZP: return 0x03;
|
||||||
|
|
|
@ -12,24 +12,46 @@
|
||||||
class cBlockWorkbenchHandler:
|
class cBlockWorkbenchHandler:
|
||||||
public cBlockHandler
|
public cBlockHandler
|
||||||
{
|
{
|
||||||
|
using Super = cBlockHandler;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
cBlockWorkbenchHandler(BLOCKTYPE a_BlockType)
|
|
||||||
: cBlockHandler(a_BlockType)
|
cBlockWorkbenchHandler(BLOCKTYPE a_BlockType):
|
||||||
|
Super(a_BlockType)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
virtual bool OnUse(
|
||||||
|
cChunkInterface & a_ChunkInterface,
|
||||||
|
cWorldInterface & a_WorldInterface,
|
||||||
|
cPlayer & a_Player,
|
||||||
|
const Vector3i a_BlockPos,
|
||||||
|
eBlockFace a_BlockFace,
|
||||||
|
const Vector3i a_CursorPos
|
||||||
|
) override
|
||||||
{
|
{
|
||||||
cWindow * Window = new cCraftingWindow(a_BlockX, a_BlockY, a_BlockZ);
|
cWindow * Window = new cCraftingWindow(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z);
|
||||||
a_Player.OpenWindow(*Window);
|
a_Player.OpenWindow(*Window);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool IsUseable(void) override
|
virtual bool IsUseable(void) override
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
||||||
{
|
{
|
||||||
UNUSED(a_Meta);
|
UNUSED(a_Meta);
|
||||||
|
|
|
@ -189,7 +189,8 @@ public:
|
||||||
|
|
||||||
cYawRotator(BLOCKTYPE a_BlockType):
|
cYawRotator(BLOCKTYPE a_BlockType):
|
||||||
Super(a_BlockType)
|
Super(a_BlockType)
|
||||||
{}
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -197,13 +198,14 @@ public:
|
||||||
|
|
||||||
virtual bool GetPlacementBlockTypeMeta(
|
virtual bool GetPlacementBlockTypeMeta(
|
||||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
const Vector3i a_BlockPos,
|
||||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
eBlockFace a_BlockFace,
|
||||||
|
const Vector3i a_CursorPos,
|
||||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
NIBBLETYPE BaseMeta;
|
NIBBLETYPE BaseMeta;
|
||||||
if (!Super::GetPlacementBlockTypeMeta(a_ChunkInterface, a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, a_BlockType, BaseMeta))
|
if (!Super::GetPlacementBlockTypeMeta(a_ChunkInterface, a_Player, a_BlockPos, a_BlockFace, a_CursorPos, a_BlockType, BaseMeta))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -259,25 +261,29 @@ class cPitchYawRotator:
|
||||||
public cYawRotator<Base, BitMask, North, East, South, West>
|
public cYawRotator<Base, BitMask, North, East, South, West>
|
||||||
{
|
{
|
||||||
using Super = cYawRotator<Base, BitMask, North, East, South, West>;
|
using Super = cYawRotator<Base, BitMask, North, East, South, West>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
cPitchYawRotator(BLOCKTYPE a_BlockType):
|
cPitchYawRotator(BLOCKTYPE a_BlockType):
|
||||||
Super(a_BlockType)
|
Super(a_BlockType)
|
||||||
{}
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool GetPlacementBlockTypeMeta(
|
virtual bool GetPlacementBlockTypeMeta(
|
||||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
cChunkInterface & a_ChunkInterface,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
cPlayer & a_Player,
|
||||||
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
|
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
NIBBLETYPE BaseMeta;
|
NIBBLETYPE BaseMeta;
|
||||||
if (!Super::GetPlacementBlockTypeMeta(a_ChunkInterface, a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, a_BlockType, BaseMeta))
|
if (!Super::GetPlacementBlockTypeMeta(a_ChunkInterface, a_Player, a_PlacedBlockPos, a_ClickedBlockFace, a_CursorPos, a_BlockType, BaseMeta))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,6 +60,12 @@ public:
|
||||||
/** Sends the block on those coords to the player */
|
/** Sends the block on those coords to the player */
|
||||||
virtual void SendBlockTo(int a_BlockX, int a_BlockY, int a_BlockZ, cPlayer & a_Player) = 0;
|
virtual void SendBlockTo(int a_BlockX, int a_BlockY, int a_BlockZ, cPlayer & a_Player) = 0;
|
||||||
|
|
||||||
|
/** Sends the block on those coords to the player */
|
||||||
|
inline void SendBlockTo(const Vector3i a_BlockPos, cPlayer & a_Player)
|
||||||
|
{
|
||||||
|
SendBlockTo(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, a_Player);
|
||||||
|
}
|
||||||
|
|
||||||
/** Calls the callback for each player in the list; returns true if all players processed, false if the callback aborted by returning true */
|
/** Calls the callback for each player in the list; returns true if all players processed, false if the callback aborted by returning true */
|
||||||
virtual bool ForEachPlayer(cPlayerListCallback a_Callback) = 0;
|
virtual bool ForEachPlayer(cPlayerListCallback a_Callback) = 0;
|
||||||
|
|
||||||
|
|
|
@ -572,7 +572,7 @@ public:
|
||||||
|
|
||||||
/** Converts the coord relative to this chunk into an absolute coord.
|
/** Converts the coord relative to this chunk into an absolute coord.
|
||||||
Doesn't check relative coord validity. */
|
Doesn't check relative coord validity. */
|
||||||
Vector3i RelativeToAbsolute(Vector3i a_RelBlockPosition)
|
Vector3i RelativeToAbsolute(Vector3i a_RelBlockPosition) const
|
||||||
{
|
{
|
||||||
return cChunkDef::RelativeToAbsolute(a_RelBlockPosition, {m_PosX, m_PosZ});
|
return cChunkDef::RelativeToAbsolute(a_RelBlockPosition, {m_PosX, m_PosZ});
|
||||||
}
|
}
|
||||||
|
|
|
@ -555,8 +555,17 @@ struct sSetBlock
|
||||||
/** Returns the absolute Z coord of the stored block. */
|
/** Returns the absolute Z coord of the stored block. */
|
||||||
int GetZ(void) const { return m_RelZ + cChunkDef::Width * m_ChunkZ; }
|
int GetZ(void) const { return m_RelZ + cChunkDef::Width * m_ChunkZ; }
|
||||||
|
|
||||||
/** Returns the absolute position of the stored block. */
|
/** Returns the absolute coords of the stored block. */
|
||||||
Vector3i GetPos(void) const { return Vector3i(GetX(), GetY(), GetZ()); }
|
Vector3i GetAbsolutePos() const
|
||||||
|
{
|
||||||
|
return Vector3i(GetX(), GetY(), GetZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the relative position of the stored block within its chunk. */
|
||||||
|
Vector3i GetRelativePos() const
|
||||||
|
{
|
||||||
|
return Vector3i(m_RelX, m_RelY, m_RelZ);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::list<sSetBlock> sSetBlockList;
|
typedef std::list<sSetBlock> sSetBlockList;
|
||||||
|
|
|
@ -1165,7 +1165,7 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eB
|
||||||
{
|
{
|
||||||
ItemHandler = cItemHandler::GetItemHandler(m_Player->GetInventory().GetShieldSlot());
|
ItemHandler = cItemHandler::GetItemHandler(m_Player->GetInventory().GetShieldSlot());
|
||||||
}
|
}
|
||||||
ItemHandler->OnItemShoot(m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
|
ItemHandler->OnItemShoot(m_Player, {a_BlockX, a_BlockY, a_BlockZ}, a_BlockFace);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1294,10 +1294,10 @@ void cClientHandle::HandleBlockDigStarted(int a_BlockX, int a_BlockY, int a_Bloc
|
||||||
cWorld * World = m_Player->GetWorld();
|
cWorld * World = m_Player->GetWorld();
|
||||||
cChunkInterface ChunkInterface(World->GetChunkMap());
|
cChunkInterface ChunkInterface(World->GetChunkMap());
|
||||||
cBlockHandler * Handler = cBlockInfo::GetHandler(a_OldBlock);
|
cBlockHandler * Handler = cBlockInfo::GetHandler(a_OldBlock);
|
||||||
Handler->OnDigging(ChunkInterface, *World, *m_Player, a_BlockX, a_BlockY, a_BlockZ);
|
Handler->OnDigging(ChunkInterface, *World, *m_Player, {a_BlockX, a_BlockY, a_BlockZ});
|
||||||
|
|
||||||
cItemHandler * ItemHandler = cItemHandler::GetItemHandler(m_Player->GetEquippedItem());
|
cItemHandler * ItemHandler = cItemHandler::GetItemHandler(m_Player->GetEquippedItem());
|
||||||
ItemHandler->OnDiggingBlock(World, m_Player, m_Player->GetEquippedItem(), a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
|
ItemHandler->OnDiggingBlock(World, m_Player, m_Player->GetEquippedItem(), {a_BlockX, a_BlockY, a_BlockZ}, a_BlockFace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1444,9 +1444,11 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
|
||||||
|
|
||||||
// TODO: This distance should be calculated from the point that the cursor pointing at, instead of the center of the block
|
// TODO: This distance should be calculated from the point that the cursor pointing at, instead of the center of the block
|
||||||
// Distance from the block's center to the player's eye height
|
// Distance from the block's center to the player's eye height
|
||||||
double Dist = (Vector3d(a_BlockX, a_BlockY, a_BlockZ) + Vector3d(0.5, 0.5, 0.5) - m_Player->GetEyePosition()).Length();
|
auto ClickedBlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ);
|
||||||
FLOGD("HandleRightClick: {0}, face {1}, Hand: {2}, HeldItem: {3}; Dist: {4:.02f}",
|
auto CursorPos = Vector3i(a_CursorX, a_CursorY, a_CursorZ);
|
||||||
Vector3i{a_BlockX, a_BlockY, a_BlockZ}, a_BlockFace, a_Hand, ItemToFullString(HeldItem), Dist
|
double Dist = (Vector3d(ClickedBlockPos) + Vector3d(0.5, 0.5, 0.5) - m_Player->GetEyePosition()).Length();
|
||||||
|
FLOGD("HandleRightClick: {0}, face {1}, Cursor {2}, Hand: {3}, HeldItem: {4}; Dist: {5:.02f}",
|
||||||
|
ClickedBlockPos, a_BlockFace, CursorPos, a_Hand, ItemToFullString(HeldItem), Dist
|
||||||
);
|
);
|
||||||
|
|
||||||
// Check the reach distance:
|
// Check the reach distance:
|
||||||
|
@ -1464,7 +1466,7 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
|
||||||
{
|
{
|
||||||
BLOCKTYPE BlockType;
|
BLOCKTYPE BlockType;
|
||||||
NIBBLETYPE BlockMeta;
|
NIBBLETYPE BlockMeta;
|
||||||
World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta);
|
World->GetBlockTypeMeta(ClickedBlockPos, BlockType, BlockMeta);
|
||||||
cBlockHandler * BlockHandler = cBlockInfo::GetHandler(BlockType);
|
cBlockHandler * BlockHandler = cBlockInfo::GetHandler(BlockType);
|
||||||
|
|
||||||
bool Placeable = ItemHandler->IsPlaceable() && !m_Player->IsGameModeAdventure() && !m_Player->IsGameModeSpectator();
|
bool Placeable = ItemHandler->IsPlaceable() && !m_Player->IsGameModeAdventure() && !m_Player->IsGameModeSpectator();
|
||||||
|
@ -1476,7 +1478,7 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
|
||||||
cChunkInterface ChunkInterface(World->GetChunkMap());
|
cChunkInterface ChunkInterface(World->GetChunkMap());
|
||||||
if (!PlgMgr->CallHookPlayerUsingBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta))
|
if (!PlgMgr->CallHookPlayerUsingBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta))
|
||||||
{
|
{
|
||||||
if (BlockHandler->OnUse(ChunkInterface, *World, *m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ))
|
if (BlockHandler->OnUse(ChunkInterface, *World, *m_Player, ClickedBlockPos, a_BlockFace, CursorPos))
|
||||||
{
|
{
|
||||||
// block use was successful, we're done
|
// block use was successful, we're done
|
||||||
PlgMgr->CallHookPlayerUsedBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta);
|
PlgMgr->CallHookPlayerUsedBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta);
|
||||||
|
@ -1487,14 +1489,14 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
|
||||||
if (!Success && Placeable)
|
if (!Success && Placeable)
|
||||||
{
|
{
|
||||||
// place a block
|
// place a block
|
||||||
Success = ItemHandler->OnPlayerPlace(*World, *m_Player, HeldItem, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ);
|
Success = ItemHandler->OnPlayerPlace(*World, *m_Player, HeldItem, {a_BlockX, a_BlockY, a_BlockZ}, a_BlockFace, {a_CursorX, a_CursorY, a_CursorZ});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// TODO: OnCancelRightClick seems to do the same thing with updating blocks at the end of this function. Need to double check
|
// TODO: OnCancelRightClick seems to do the same thing with updating blocks at the end of this function. Need to double check
|
||||||
// A plugin doesn't agree with the action, replace the block on the client and quit:
|
// A plugin doesn't agree with the action, replace the block on the client and quit:
|
||||||
BlockHandler->OnCancelRightClick(ChunkInterface, *World, *m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
|
BlockHandler->OnCancelRightClick(ChunkInterface, *World, *m_Player, {a_BlockX, a_BlockY, a_BlockZ}, a_BlockFace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Placeable)
|
else if (Placeable)
|
||||||
|
@ -1507,7 +1509,7 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// place a block
|
// place a block
|
||||||
Success = ItemHandler->OnPlayerPlace(*World, *m_Player, HeldItem, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ);
|
Success = ItemHandler->OnPlayerPlace(*World, *m_Player, HeldItem, {a_BlockX, a_BlockY, a_BlockZ}, a_BlockFace, {a_CursorX, a_CursorY, a_CursorZ});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1516,7 +1518,7 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
|
||||||
{
|
{
|
||||||
// All plugins agree with using the item
|
// All plugins agree with using the item
|
||||||
cBlockInServerPluginInterface PluginInterface(*World);
|
cBlockInServerPluginInterface PluginInterface(*World);
|
||||||
ItemHandler->OnItemUse(World, m_Player, PluginInterface, HeldItem, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
|
ItemHandler->OnItemUse(World, m_Player, PluginInterface, HeldItem, {a_BlockX, a_BlockY, a_BlockZ}, a_BlockFace);
|
||||||
PlgMgr->CallHookPlayerUsedItem(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ);
|
PlgMgr->CallHookPlayerUsedItem(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ);
|
||||||
Success = true;
|
Success = true;
|
||||||
}
|
}
|
||||||
|
@ -1827,7 +1829,7 @@ void cClientHandle::HandleUseItem(eHand a_Hand)
|
||||||
{
|
{
|
||||||
// All plugins agree with using the item
|
// All plugins agree with using the item
|
||||||
cBlockInServerPluginInterface PluginInterface(*World);
|
cBlockInServerPluginInterface PluginInterface(*World);
|
||||||
ItemHandler->OnItemUse(World, m_Player, PluginInterface, HeldItem, -1, 255, -1, BLOCK_FACE_NONE);
|
ItemHandler->OnItemUse(World, m_Player, PluginInterface, HeldItem, {-1, 255, -1}, BLOCK_FACE_NONE);
|
||||||
PlgMgr->CallHookPlayerUsedItem(*m_Player, -1, 255, -1, BLOCK_FACE_NONE, 0, 0, 0);
|
PlgMgr->CallHookPlayerUsedItem(*m_Player, -1, 255, -1, BLOCK_FACE_NONE, 0, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2641,7 +2643,7 @@ void cClientHandle::SendEntityVelocity(const cEntity & a_Entity)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cClientHandle::SendExplosion(double a_BlockX, double a_BlockY, double a_BlockZ, float a_Radius, const cVector3iArray & a_BlocksAffected, const Vector3d & a_PlayerMotion)
|
void cClientHandle::SendExplosion(const Vector3d a_Pos, float a_Radius, const cVector3iArray & a_BlocksAffected, const Vector3d a_PlayerMotion)
|
||||||
{
|
{
|
||||||
if (m_NumExplosionsThisTick > MAX_EXPLOSIONS_PER_TICK)
|
if (m_NumExplosionsThisTick > MAX_EXPLOSIONS_PER_TICK)
|
||||||
{
|
{
|
||||||
|
@ -2652,7 +2654,7 @@ void cClientHandle::SendExplosion(double a_BlockX, double a_BlockY, double a_Blo
|
||||||
// Update the statistics:
|
// Update the statistics:
|
||||||
m_NumExplosionsThisTick++;
|
m_NumExplosionsThisTick++;
|
||||||
|
|
||||||
m_Protocol->SendExplosion(a_BlockX, a_BlockY, a_BlockZ, a_Radius, a_BlocksAffected, a_PlayerMotion);
|
m_Protocol->SendExplosion(a_Pos.x, a_Pos.y, a_Pos.z, a_Radius, a_BlocksAffected, a_PlayerMotion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -173,7 +173,7 @@ public: // tolua_export
|
||||||
void SendEntityVelocity (const cEntity & a_Entity);
|
void SendEntityVelocity (const cEntity & a_Entity);
|
||||||
void SendExperience (void);
|
void SendExperience (void);
|
||||||
void SendExperienceOrb (const cExpOrb & a_ExpOrb);
|
void SendExperienceOrb (const cExpOrb & a_ExpOrb);
|
||||||
void SendExplosion (double a_BlockX, double a_BlockY, double a_BlockZ, float a_Radius, const cVector3iArray & a_BlocksAffected, const Vector3d & a_PlayerMotion);
|
void SendExplosion (const Vector3d a_Pos, float a_Radius, const cVector3iArray & a_BlocksAffected, const Vector3d a_PlayerMotion);
|
||||||
void SendGameMode (eGameMode a_GameMode);
|
void SendGameMode (eGameMode a_GameMode);
|
||||||
void SendHealth (void);
|
void SendHealth (void);
|
||||||
void SendHeldItemChange (int a_ItemIndex);
|
void SendHeldItemChange (int a_ItemIndex);
|
||||||
|
|
|
@ -331,10 +331,7 @@ void cPawn::HandleFalling(void)
|
||||||
/* The blocks we're interested in relative to the player to account for larger than 1 blocks.
|
/* The blocks we're interested in relative to the player to account for larger than 1 blocks.
|
||||||
This can be extended to do additional checks in case there are blocks that are represented as one block
|
This can be extended to do additional checks in case there are blocks that are represented as one block
|
||||||
in memory but have a hitbox larger than 1 (like fences) */
|
in memory but have a hitbox larger than 1 (like fences) */
|
||||||
static const struct
|
static const Vector3i BlockSampleOffsets[] =
|
||||||
{
|
|
||||||
int x, y, z;
|
|
||||||
} BlockSampleOffsets[] =
|
|
||||||
{
|
{
|
||||||
{ 0, 0, 0 }, // TODO: something went wrong here (offset 0?)
|
{ 0, 0, 0 }, // TODO: something went wrong here (offset 0?)
|
||||||
{ 0, -1, 0 }, // Potentially causes mis-detection (IsFootInWater) when player stands on block diagonal to water (i.e. on side of pool)
|
{ 0, -1, 0 }, // Potentially causes mis-detection (IsFootInWater) when player stands on block diagonal to water (i.e. on side of pool)
|
||||||
|
@ -354,26 +351,26 @@ void cPawn::HandleFalling(void)
|
||||||
/* We go through the blocks that we consider "relevant" */
|
/* We go through the blocks that we consider "relevant" */
|
||||||
for (size_t j = 0; j < ARRAYCOUNT(BlockSampleOffsets); j++)
|
for (size_t j = 0; j < ARRAYCOUNT(BlockSampleOffsets); j++)
|
||||||
{
|
{
|
||||||
Vector3i BlockTestPosition = CrossTestPosition.Floor() + Vector3i(BlockSampleOffsets[j].x, BlockSampleOffsets[j].y, BlockSampleOffsets[j].z);
|
Vector3i BlockTestPosition = CrossTestPosition.Floor() + BlockSampleOffsets[j];
|
||||||
|
|
||||||
if (!cChunkDef::IsValidHeight(BlockTestPosition.y))
|
if (!cChunkDef::IsValidHeight(BlockTestPosition.y))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
BLOCKTYPE Block = GetWorld()->GetBlock(BlockTestPosition);
|
BLOCKTYPE BlockType = GetWorld()->GetBlock(BlockTestPosition);
|
||||||
NIBBLETYPE BlockMeta = GetWorld()->GetBlockMeta(BlockTestPosition);
|
NIBBLETYPE BlockMeta = GetWorld()->GetBlockMeta(BlockTestPosition);
|
||||||
|
|
||||||
/* we do the cross-shaped sampling to check for water / liquids, but only on our level because water blocks are never bigger than unit voxels */
|
/* we do the cross-shaped sampling to check for water / liquids, but only on our level because water blocks are never bigger than unit voxels */
|
||||||
if (j == 0)
|
if (j == 0)
|
||||||
{
|
{
|
||||||
IsFootInWater |= IsBlockWater(Block);
|
IsFootInWater |= IsBlockWater(BlockType);
|
||||||
IsFootInLiquid |= IsFootInWater || IsBlockLava(Block) || (Block == E_BLOCK_COBWEB); // okay so cobweb is not _technically_ a liquid...
|
IsFootInLiquid |= IsFootInWater || IsBlockLava(BlockType) || (BlockType == E_BLOCK_COBWEB); // okay so cobweb is not _technically_ a liquid...
|
||||||
IsFootOnSlimeBlock |= (Block == E_BLOCK_SLIME_BLOCK);
|
IsFootOnSlimeBlock |= (BlockType == E_BLOCK_SLIME_BLOCK);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the block is solid, and the blockhandler confirms the block to be inside, we're officially on the ground. */
|
/* If the block is solid, and the blockhandler confirms the block to be inside, we're officially on the ground. */
|
||||||
if ((cBlockInfo::IsSolid(Block)) && (cBlockInfo::GetHandler(Block)->IsInsideBlock(CrossTestPosition - BlockTestPosition, Block, BlockMeta)))
|
if ((cBlockInfo::IsSolid(BlockType)) && (cBlockInfo::GetHandler(BlockType)->IsInsideBlock(CrossTestPosition - BlockTestPosition, BlockMeta)))
|
||||||
{
|
{
|
||||||
OnGround = true;
|
OnGround = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,43 +8,52 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cItemArmorHandler :
|
class cItemArmorHandler:
|
||||||
public cItemHandler
|
public cItemHandler
|
||||||
{
|
{
|
||||||
|
using Super = cItemHandler;
|
||||||
|
|
||||||
public:
|
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 */
|
/** Move the armor to the armor slot of the player's inventory */
|
||||||
virtual bool OnItemUse(
|
virtual bool OnItemUse(
|
||||||
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
|
cWorld * a_World,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
|
cPlayer * a_Player,
|
||||||
|
cBlockPluginInterface & a_PluginInterface,
|
||||||
|
const cItem & a_HeldItem,
|
||||||
|
const Vector3i a_ClickedBlockPos,
|
||||||
|
eBlockFace a_ClickedBlockFace
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
int SlotNum;
|
int SlotNum;
|
||||||
if (ItemCategory::IsHelmet(a_Item.m_ItemType))
|
if (ItemCategory::IsHelmet(a_HeldItem.m_ItemType))
|
||||||
{
|
{
|
||||||
SlotNum = 0;
|
SlotNum = 0;
|
||||||
}
|
}
|
||||||
else if (ItemCategory::IsChestPlate(a_Item.m_ItemType))
|
else if (ItemCategory::IsChestPlate(a_HeldItem.m_ItemType))
|
||||||
{
|
{
|
||||||
SlotNum = 1;
|
SlotNum = 1;
|
||||||
}
|
}
|
||||||
else if (ItemCategory::IsLeggings(a_Item.m_ItemType))
|
else if (ItemCategory::IsLeggings(a_HeldItem.m_ItemType))
|
||||||
{
|
{
|
||||||
SlotNum = 2;
|
SlotNum = 2;
|
||||||
}
|
}
|
||||||
else if (ItemCategory::IsBoots(a_Item.m_ItemType))
|
else if (ItemCategory::IsBoots(a_HeldItem.m_ItemType))
|
||||||
{
|
{
|
||||||
SlotNum = 3;
|
SlotNum = 3;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOGWARNING("Used unknown armor: %i", a_Item.m_ItemType);
|
LOGWARNING("Used unknown armor: %i", a_HeldItem.m_ItemType);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,9 +62,9 @@ public:
|
||||||
return false;
|
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--;
|
Item.m_ItemCount--;
|
||||||
if (Item.m_ItemCount <= 0)
|
if (Item.m_ItemCount <= 0)
|
||||||
{
|
{
|
||||||
|
@ -67,6 +76,8 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool CanRepairWithRawMaterial(short a_ItemType) override
|
virtual bool CanRepairWithRawMaterial(short a_ItemType) override
|
||||||
{
|
{
|
||||||
switch (m_ItemType)
|
switch (m_ItemType)
|
||||||
|
|
|
@ -9,51 +9,60 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cItemBedHandler :
|
class cItemBedHandler:
|
||||||
public cItemHandler
|
public cItemHandler
|
||||||
{
|
{
|
||||||
|
using Super = cItemHandler;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
cItemBedHandler(int a_ItemType) :
|
|
||||||
cItemHandler(a_ItemType)
|
cItemBedHandler(int a_ItemType):
|
||||||
|
Super(a_ItemType)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool IsPlaceable(void) override
|
virtual bool IsPlaceable(void) override
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool GetBlocksToPlace(
|
virtual bool GetBlocksToPlace(
|
||||||
cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
|
cWorld & a_World,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
cPlayer & a_Player,
|
||||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
const cItem & a_EquippedItem,
|
||||||
|
const Vector3i a_PlacedBlockPos,
|
||||||
|
eBlockFace a_ClickedBlockFace,
|
||||||
|
const Vector3i a_CursorPos,
|
||||||
sSetBlockVector & a_BlocksToPlace
|
sSetBlockVector & a_BlocksToPlace
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
// Can only be placed on the floor:
|
// Can only be placed on the floor:
|
||||||
if (a_BlockFace != BLOCK_FACE_TOP)
|
if (a_ClickedBlockFace != BLOCK_FACE_TOP)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The "foot" block:
|
// The "foot" block:
|
||||||
NIBBLETYPE BlockMeta = cBlockBedHandler::YawToMetaData(a_Player.GetYaw());
|
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:
|
// Check if there is empty space for the "head" block:
|
||||||
// (Vanilla only allows beds to be placed into air)
|
// (Vanilla only allows beds to be placed into air)
|
||||||
Vector3i Direction = cBlockBedHandler::MetaDataToDirection(BlockMeta);
|
auto Direction = cBlockBedHandler::MetaDataToDirection(BlockMeta);
|
||||||
if (a_World.GetBlock(a_BlockX + Direction.x, a_BlockY, a_BlockZ + Direction.z) != E_BLOCK_AIR)
|
auto HeadPos = a_PlacedBlockPos + Direction;
|
||||||
|
if (a_World.GetBlock(HeadPos) != E_BLOCK_AIR)
|
||||||
{
|
{
|
||||||
return false;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
} ;
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -15,43 +15,50 @@ class cItemBigFlowerHandler:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
cItemBigFlowerHandler(void):
|
cItemBigFlowerHandler():
|
||||||
Super(E_BLOCK_BIG_FLOWER)
|
Super(E_BLOCK_BIG_FLOWER)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool GetBlocksToPlace(
|
virtual bool GetBlocksToPlace(
|
||||||
cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
|
cWorld & a_World,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
cPlayer & a_Player,
|
||||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
const cItem & a_EquippedItem,
|
||||||
sSetBlockVector & a_BlocksToSet
|
const Vector3i a_PlacedBlockPos,
|
||||||
|
eBlockFace a_ClickedBlockFace,
|
||||||
|
const Vector3i a_CursorPos,
|
||||||
|
sSetBlockVector & a_BlocksToPlace
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
// Can only be placed on dirt:
|
// 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Needs at least two free blocks to build in
|
// Needs at least two free blocks to build in
|
||||||
if (a_BlockY >= cChunkDef::Height - 1)
|
if (a_PlacedBlockPos.y >= cChunkDef::Height - 1)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto TopPos = a_PlacedBlockPos.addedY(1);
|
||||||
BLOCKTYPE TopType;
|
BLOCKTYPE TopType;
|
||||||
NIBBLETYPE TopMeta;
|
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());
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
a_BlocksToSet.emplace_back(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_BIG_FLOWER, a_EquippedItem.m_ItemDamage & 0x07);
|
a_BlocksToPlace.emplace_back(a_PlacedBlockPos, 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(TopPos, E_BLOCK_BIG_FLOWER, E_META_BIG_FLOWER_TOP);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -22,24 +22,32 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool OnItemUse(
|
virtual bool OnItemUse(
|
||||||
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
|
cWorld * a_World,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
|
cPlayer * a_Player,
|
||||||
|
cBlockPluginInterface & a_PluginInterface,
|
||||||
|
const cItem & a_HeldItem,
|
||||||
|
const Vector3i a_ClickedBlockPos,
|
||||||
|
eBlockFace a_ClickedBlockFace
|
||||||
) override
|
) 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
class cCallbacks :
|
// Find the actual placement position by tracing line of sight until non-air block:
|
||||||
|
class cCallbacks:
|
||||||
public cBlockTracer::cCallbacks
|
public cBlockTracer::cCallbacks
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Vector3d m_Pos;
|
Vector3d m_Pos;
|
||||||
bool m_HasFound;
|
bool m_HasFound;
|
||||||
|
|
||||||
cCallbacks(void) :
|
cCallbacks():
|
||||||
m_HasFound(false)
|
m_HasFound(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -55,27 +63,21 @@ public:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} Callbacks;
|
} Callbacks;
|
||||||
|
auto Start = a_Player->GetEyePosition() + a_Player->GetLookVector();
|
||||||
cLineBlockTracer Tracer(*a_World, Callbacks);
|
auto End = a_Player->GetEyePosition() + a_Player->GetLookVector() * 5;
|
||||||
Vector3d Start(a_Player->GetEyePosition() + a_Player->GetLookVector());
|
cLineBlockTracer::Trace(*a_World, Callbacks, Start, End);
|
||||||
Vector3d End(a_Player->GetEyePosition() + a_Player->GetLookVector() * 5);
|
|
||||||
|
|
||||||
Tracer.Trace(Start.x, Start.y, Start.z, End.x, End.y, End.z);
|
|
||||||
|
|
||||||
if (!Callbacks.m_HasFound)
|
if (!Callbacks.m_HasFound)
|
||||||
{
|
{
|
||||||
return false;
|
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)
|
// 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)
|
if (BlockAbove != E_BLOCK_AIR)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -9,19 +9,28 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cItemBottleHandler :
|
class cItemBottleHandler:
|
||||||
public cItemHandler
|
public cItemHandler
|
||||||
{
|
{
|
||||||
|
using Super = cItemHandler;
|
||||||
|
|
||||||
public:
|
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)
|
bool GetBlockFromTrace(cWorld * a_World, cPlayer * a_Player, Vector3i & a_BlockPos)
|
||||||
{
|
{
|
||||||
class cCallbacks :
|
class cCallbacks:
|
||||||
public cBlockTracer::cCallbacks
|
public cBlockTracer::cCallbacks
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -29,7 +38,7 @@ public:
|
||||||
bool m_HasHitFluid;
|
bool m_HasHitFluid;
|
||||||
|
|
||||||
|
|
||||||
cCallbacks(void) :
|
cCallbacks():
|
||||||
m_HasHitFluid(false)
|
m_HasHitFluid(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -49,31 +58,32 @@ public:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} Callbacks;
|
} Callbacks;
|
||||||
|
auto Start = a_Player->GetEyePosition() + a_Player->GetLookVector();
|
||||||
cLineBlockTracer Tracer(*a_World, Callbacks);
|
auto End = a_Player->GetEyePosition() + a_Player->GetLookVector() * 5;
|
||||||
Vector3d Start(a_Player->GetEyePosition() + a_Player->GetLookVector());
|
cLineBlockTracer::Trace(*a_World, Callbacks, Start, End);
|
||||||
Vector3d End(a_Player->GetEyePosition() + a_Player->GetLookVector() * 5);
|
|
||||||
|
|
||||||
Tracer.Trace(Start.x, Start.y, Start.z, End.x, End.y, End.z);
|
|
||||||
|
|
||||||
if (!Callbacks.m_HasHitFluid)
|
if (!Callbacks.m_HasHitFluid)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
a_BlockPos = Callbacks.m_Pos;
|
a_BlockPos = Callbacks.m_Pos;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool OnItemUse(
|
virtual bool OnItemUse(
|
||||||
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
|
cWorld * a_World,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
|
cPlayer * a_Player,
|
||||||
) override
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,9 +22,15 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool OnItemUse(
|
virtual bool OnItemUse(
|
||||||
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
|
cWorld * a_World,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
|
cPlayer * a_Player,
|
||||||
|
cBlockPluginInterface & a_PluginInterface,
|
||||||
|
const cItem & a_HeldItem,
|
||||||
|
const Vector3i a_ClickedBlockPos,
|
||||||
|
eBlockFace a_ClickedBlockFace
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
ASSERT(a_Player != nullptr);
|
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);
|
ASSERT(a_Player != nullptr);
|
||||||
|
|
||||||
int BowCharge = a_Player->FinishChargingBow();
|
int BowCharge = a_Player->FinishChargingBow();
|
||||||
|
@ -88,7 +95,6 @@ public:
|
||||||
|
|
||||||
a_Player->UseEquippedItem();
|
a_Player->UseEquippedItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (a_Player->GetEquippedItem().m_Enchantments.GetLevel(cEnchantments::enchFlame) > 0)
|
if (a_Player->GetEquippedItem().m_Enchantments.GetLevel(cEnchantments::enchFlame) > 0)
|
||||||
{
|
{
|
||||||
ArrowPtr->StartBurning(100);
|
ArrowPtr->StartBurning(100);
|
||||||
|
|
|
@ -7,12 +7,15 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cItemBrewingStandHandler :
|
class cItemBrewingStandHandler:
|
||||||
public cItemHandler
|
public cItemHandler
|
||||||
{
|
{
|
||||||
|
using Super = cItemHandler;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
cItemBrewingStandHandler(int a_ItemType) :
|
|
||||||
cItemHandler(a_ItemType)
|
cItemBrewingStandHandler(int a_ItemType):
|
||||||
|
Super(a_ItemType)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,8 +28,9 @@ public:
|
||||||
|
|
||||||
virtual bool GetPlacementBlockTypeMeta(
|
virtual bool GetPlacementBlockTypeMeta(
|
||||||
cWorld * a_World, cPlayer * a_Player,
|
cWorld * a_World, cPlayer * a_Player,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
const Vector3i a_PlacedBlockPos,
|
||||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
eBlockFace a_ClickedBlockFace,
|
||||||
|
const Vector3i a_CursorPos,
|
||||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
|
|
|
@ -16,25 +16,34 @@
|
||||||
class cItemBucketHandler :
|
class cItemBucketHandler :
|
||||||
public cItemHandler
|
public cItemHandler
|
||||||
{
|
{
|
||||||
|
using Super = cItemHandler;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
cItemBucketHandler(int a_ItemType) :
|
|
||||||
cItemHandler(a_ItemType)
|
cItemBucketHandler(int a_ItemType):
|
||||||
|
Super(a_ItemType)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool OnItemUse(
|
virtual bool OnItemUse(
|
||||||
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
|
cWorld * a_World,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
|
cPlayer * a_Player,
|
||||||
|
cBlockPluginInterface & a_PluginInterface,
|
||||||
|
const cItem & a_HeldItem,
|
||||||
|
const Vector3i a_ClickedBlockPos,
|
||||||
|
eBlockFace a_ClickedBlockFace
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
switch (m_ItemType)
|
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_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_Item, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, E_BLOCK_LAVA);
|
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_Item, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, E_BLOCK_WATER);
|
case E_ITEM_WATER_BUCKET: return PlaceFluid (a_World, a_Player, a_PluginInterface, a_HeldItem, a_ClickedBlockPos, a_ClickedBlockFace, E_BLOCK_WATER);
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
ASSERT(!"Unhandled ItemType");
|
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.
|
// Players can't pick up fluid while in adventure mode.
|
||||||
if (a_Player->IsGameModeAdventure())
|
if (a_Player->IsGameModeAdventure())
|
||||||
|
@ -53,7 +64,8 @@ public:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (a_BlockFace != BLOCK_FACE_NONE)
|
// Needs a valid clicked block:
|
||||||
|
if (a_ClickedBlockFace != BLOCK_FACE_NONE)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -114,7 +126,7 @@ public:
|
||||||
|
|
||||||
bool PlaceFluid(
|
bool PlaceFluid(
|
||||||
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
|
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.
|
// 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)
|
bool GetPlacementCoordsFromTrace(cWorld * a_World, cPlayer * a_Player, Vector3i & a_BlockPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta, eBlockFace & a_BlockFace)
|
||||||
{
|
{
|
||||||
class cCallbacks :
|
class cCallbacks :
|
||||||
|
|
|
@ -7,12 +7,15 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cItemCakeHandler :
|
class cItemCakeHandler:
|
||||||
public cItemHandler
|
public cItemHandler
|
||||||
{
|
{
|
||||||
|
using Super = cItemHandler;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
cItemCakeHandler(int a_ItemType) :
|
|
||||||
cItemHandler(a_ItemType)
|
cItemCakeHandler(int a_ItemType):
|
||||||
|
Super(a_ItemType)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,8 +28,9 @@ public:
|
||||||
|
|
||||||
virtual bool GetPlacementBlockTypeMeta(
|
virtual bool GetPlacementBlockTypeMeta(
|
||||||
cWorld * a_World, cPlayer * a_Player,
|
cWorld * a_World, cPlayer * a_Player,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
const Vector3i a_PlacedBlockPos,
|
||||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
eBlockFace a_ClickedBlockFace,
|
||||||
|
const Vector3i a_CursorPos,
|
||||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
|
|
|
@ -7,12 +7,15 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cItemCauldronHandler :
|
class cItemCauldronHandler:
|
||||||
public cItemHandler
|
public cItemHandler
|
||||||
{
|
{
|
||||||
|
using Super = cItemHandler;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
cItemCauldronHandler(int a_ItemType) :
|
|
||||||
cItemHandler(a_ItemType)
|
cItemCauldronHandler(int a_ItemType):
|
||||||
|
Super(a_ItemType)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,8 +28,9 @@ public:
|
||||||
|
|
||||||
virtual bool GetPlacementBlockTypeMeta(
|
virtual bool GetPlacementBlockTypeMeta(
|
||||||
cWorld * a_World, cPlayer * a_Player,
|
cWorld * a_World, cPlayer * a_Player,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
const Vector3i a_PlacedBlockPos,
|
||||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
eBlockFace a_ClickedBlockFace,
|
||||||
|
const Vector3i a_CursorPos,
|
||||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
|
|
|
@ -25,56 +25,57 @@ public:
|
||||||
/** We need an OnPlayerPlace override because we're processing neighbor chests and changing their metas,
|
/** We need an OnPlayerPlace override because we're processing neighbor chests and changing their metas,
|
||||||
the parent class cannot do that. */
|
the parent class cannot do that. */
|
||||||
virtual bool OnPlayerPlace(
|
virtual bool OnPlayerPlace(
|
||||||
cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
|
cWorld & a_World,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
cPlayer & a_Player,
|
||||||
int a_CursorX, int a_CursorY, int a_CursorZ
|
const cItem & a_EquippedItem,
|
||||||
|
const Vector3i a_ClickedBlockPos,
|
||||||
|
eBlockFace a_ClickedBlockFace,
|
||||||
|
const Vector3i a_CursorPos
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
if (a_BlockFace < 0)
|
if (a_ClickedBlockFace < 0)
|
||||||
{
|
{
|
||||||
// Clicked in air
|
// Clicked in air
|
||||||
return false;
|
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)
|
// The clicked block is outside the world, ignore this call altogether (#128)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the block ignores build collision (water, grass etc.):
|
// Check if the block ignores build collision (water, grass etc.):
|
||||||
BLOCKTYPE clickedBlock;
|
BLOCKTYPE ClickedBlockType;
|
||||||
NIBBLETYPE clickedBlockMeta;
|
NIBBLETYPE ClickedBlockMeta;
|
||||||
Vector3i blockPos(a_BlockX, a_BlockY, a_BlockZ);
|
a_World.GetBlockTypeMeta(a_ClickedBlockPos, ClickedBlockType, ClickedBlockMeta);
|
||||||
a_World.GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, clickedBlock, clickedBlockMeta);
|
|
||||||
cChunkInterface ChunkInterface(a_World.GetChunkMap());
|
cChunkInterface ChunkInterface(a_World.GetChunkMap());
|
||||||
auto blockHandler = BlockHandler(clickedBlock);
|
auto blockHandler = BlockHandler(ClickedBlockType);
|
||||||
if (blockHandler->DoesIgnoreBuildCollision(ChunkInterface, blockPos, a_Player, clickedBlockMeta))
|
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
|
else
|
||||||
{
|
{
|
||||||
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
|
PlacePos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace);
|
||||||
|
if (!cChunkDef::IsValidHeight(PlacePos.y))
|
||||||
if ((a_BlockY < 0) || (a_BlockY >= cChunkDef::Height))
|
|
||||||
{
|
{
|
||||||
// The block is being placed outside the world, ignore this packet altogether (#128)
|
// The block is being placed outside the world, ignore this packet altogether (#128)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
NIBBLETYPE PlaceMeta;
|
// Check if the chest can overwrite the block at PlacePos:
|
||||||
BLOCKTYPE PlaceBlock;
|
BLOCKTYPE PlaceBlock;
|
||||||
a_World.GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, PlaceBlock, PlaceMeta);
|
NIBBLETYPE PlaceMeta;
|
||||||
|
a_World.GetBlockTypeMeta(PlacePos, 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.
|
blockHandler = BlockHandler(PlaceBlock);
|
||||||
// No need to do combinability (dblslab) checks, client will do that here.
|
if (!blockHandler->DoesIgnoreBuildCollision(ChunkInterface, PlacePos, a_Player, PlaceMeta))
|
||||||
if (blockHandler->DoesIgnoreBuildCollision(ChunkInterface, blockPos, a_Player, clickedBlockMeta))
|
|
||||||
{
|
{
|
||||||
// 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
blockHandler->OnPlayerBreakingBlock(ChunkInterface, a_World, a_Player, PlacePos);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that there is at most one single neighbor of the same chest type:
|
// Check that there is at most one single neighbor of the same chest type:
|
||||||
|
@ -88,7 +89,8 @@ public:
|
||||||
int NeighborIdx = -1;
|
int NeighborIdx = -1;
|
||||||
for (size_t i = 0; i < ARRAYCOUNT(CrossCoords); i++)
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -100,12 +102,11 @@ public:
|
||||||
NeighborIdx = static_cast<int>(i);
|
NeighborIdx = static_cast<int>(i);
|
||||||
|
|
||||||
// Check that this neighbor is a single chest:
|
// 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++)
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
} // for j
|
} // for j
|
||||||
|
@ -133,13 +134,14 @@ public:
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
|
// No neighbor, place based on yaw:
|
||||||
Meta = cBlockChestHandler::PlayerYawToMetaData(yaw);
|
Meta = cBlockChestHandler::PlayerYawToMetaData(yaw);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} // switch (NeighborIdx)
|
} // switch (NeighborIdx)
|
||||||
|
|
||||||
// Place the new chest:
|
// 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -147,10 +149,10 @@ public:
|
||||||
// Adjust the existing chest, if any:
|
// Adjust the existing chest, if any:
|
||||||
if (NeighborIdx != -1)
|
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())
|
if (a_Player.IsGameModeSurvival())
|
||||||
{
|
{
|
||||||
a_Player.GetInventory().RemoveOneEquippedItem();
|
a_Player.GetInventory().RemoveOneEquippedItem();
|
||||||
|
|
|
@ -8,24 +8,36 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cItemComparatorHandler :
|
class cItemComparatorHandler:
|
||||||
public cItemHandler
|
public cItemHandler
|
||||||
{
|
{
|
||||||
|
using Super = cItemHandler;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
cItemComparatorHandler(int a_ItemType) :
|
|
||||||
|
cItemComparatorHandler(int a_ItemType):
|
||||||
cItemHandler(a_ItemType)
|
cItemHandler(a_ItemType)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool IsPlaceable(void) override
|
virtual bool IsPlaceable(void) override
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool GetPlacementBlockTypeMeta(
|
virtual bool GetPlacementBlockTypeMeta(
|
||||||
cWorld * a_World, cPlayer * a_Player,
|
cWorld * a_World, cPlayer * a_Player,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
const Vector3i a_PlacedBlockPos,
|
||||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
eBlockFace a_ClickedBlockFace,
|
||||||
|
const Vector3i a_CursorPos,
|
||||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,38 +9,45 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cItemDoorHandler :
|
class cItemDoorHandler:
|
||||||
public cItemHandler
|
public cItemHandler
|
||||||
{
|
{
|
||||||
|
using Super = cItemHandler;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
cItemDoorHandler(int a_ItemType) :
|
|
||||||
cItemHandler(a_ItemType)
|
cItemDoorHandler(int a_ItemType):
|
||||||
|
Super(a_ItemType)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool GetBlocksToPlace(
|
virtual bool GetBlocksToPlace(
|
||||||
cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
|
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_PlacedBlockPos,
|
||||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
eBlockFace a_ClickedBlockFace,
|
||||||
|
const Vector3i a_CursorPos,
|
||||||
sSetBlockVector & a_BlocksToSet
|
sSetBlockVector & a_BlocksToSet
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
// Vanilla only allows door placement while clicking on the top face of the block below the door:
|
// 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Door (bottom block) can be placed in Y range of [1, 254]:
|
// 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The door needs a compatible block below it:
|
// 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -64,8 +71,9 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the two blocks that will get replaced by the door:
|
// Check the two blocks that will get replaced by the door:
|
||||||
BLOCKTYPE LowerBlockType = a_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ);
|
auto UpperBlockPos = a_PlacedBlockPos.addedY(1);
|
||||||
BLOCKTYPE UpperBlockType = a_World.GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ);
|
BLOCKTYPE LowerBlockType = a_World.GetBlock(a_PlacedBlockPos);
|
||||||
|
BLOCKTYPE UpperBlockType = a_World.GetBlock(UpperBlockPos);
|
||||||
if (
|
if (
|
||||||
!cBlockDoorHandler::CanReplaceBlock(LowerBlockType) ||
|
!cBlockDoorHandler::CanReplaceBlock(LowerBlockType) ||
|
||||||
!cBlockDoorHandler::CanReplaceBlock(UpperBlockType))
|
!cBlockDoorHandler::CanReplaceBlock(UpperBlockType))
|
||||||
|
@ -78,10 +86,10 @@ public:
|
||||||
Vector3i RelDirToOutside = cBlockDoorHandler::GetRelativeDirectionToOutside(LowerBlockMeta);
|
Vector3i RelDirToOutside = cBlockDoorHandler::GetRelativeDirectionToOutside(LowerBlockMeta);
|
||||||
Vector3i LeftNeighborPos = RelDirToOutside;
|
Vector3i LeftNeighborPos = RelDirToOutside;
|
||||||
LeftNeighborPos.TurnCW();
|
LeftNeighborPos.TurnCW();
|
||||||
LeftNeighborPos.Move(a_BlockX, a_BlockY, a_BlockZ);
|
LeftNeighborPos.Move(a_PlacedBlockPos);
|
||||||
Vector3i RightNeighborPos = RelDirToOutside;
|
Vector3i RightNeighborPos = RelDirToOutside;
|
||||||
RightNeighborPos.TurnCCW();
|
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:
|
// Decide whether the hinge is on the left (default) or on the right:
|
||||||
NIBBLETYPE UpperBlockMeta = 0x08;
|
NIBBLETYPE UpperBlockMeta = 0x08;
|
||||||
|
@ -89,7 +97,7 @@ public:
|
||||||
BLOCKTYPE RightNeighborBlock = a_World.GetBlock(RightNeighborPos);
|
BLOCKTYPE RightNeighborBlock = a_World.GetBlock(RightNeighborPos);
|
||||||
/*
|
/*
|
||||||
// DEBUG:
|
// 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("RelDirToOutside: {0}", RelDirToOutside);
|
||||||
FLOGD("Left neighbor at {0}: {1} ({2})", LeftNeighborPos, LeftNeighborBlock, ItemTypeToString(LeftNeighborBlock));
|
FLOGD("Left neighbor at {0}: {1} ({2})", LeftNeighborPos, LeftNeighborBlock, ItemTypeToString(LeftNeighborBlock));
|
||||||
FLOGD("Right neighbor at {0}: {1} ({2})", RightNeighborPos, RightNeighborBlock, ItemTypeToString(RightNeighborBlock));
|
FLOGD("Right neighbor at {0}: {1} ({2})", RightNeighborPos, RightNeighborBlock, ItemTypeToString(RightNeighborBlock));
|
||||||
|
@ -108,12 +116,14 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the blocks:
|
// Set the blocks:
|
||||||
a_BlocksToSet.emplace_back(a_BlockX, a_BlockY, a_BlockZ, BlockType, LowerBlockMeta);
|
a_BlocksToSet.emplace_back(a_PlacedBlockPos, BlockType, LowerBlockMeta);
|
||||||
a_BlocksToSet.emplace_back(a_BlockX, a_BlockY + 1, a_BlockZ, BlockType, UpperBlockMeta);
|
a_BlocksToSet.emplace_back(UpperBlockPos, BlockType, UpperBlockMeta);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool IsPlaceable(void) override
|
virtual bool IsPlaceable(void) override
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -26,14 +26,18 @@ public:
|
||||||
|
|
||||||
|
|
||||||
virtual bool OnItemUse(
|
virtual bool OnItemUse(
|
||||||
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
|
cWorld * a_World,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
|
cPlayer * a_Player,
|
||||||
|
cBlockPluginInterface & a_PluginInterface,
|
||||||
|
const cItem & a_HeldItem,
|
||||||
|
const Vector3i a_ClickedBlockPos,
|
||||||
|
eBlockFace a_ClickedBlockFace
|
||||||
) override
|
) 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:
|
// 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())
|
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.
|
// Players can't place blocks while in adventure mode.
|
||||||
if (a_Player->IsGameModeAdventure())
|
if (a_Player->IsGameModeAdventure())
|
||||||
|
@ -53,25 +57,24 @@ public:
|
||||||
// Cocoa (brown dye) can be planted on jungle logs:
|
// Cocoa (brown dye) can be planted on jungle logs:
|
||||||
BLOCKTYPE BlockType;
|
BLOCKTYPE BlockType;
|
||||||
NIBBLETYPE BlockMeta;
|
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.
|
// 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the location from the new cocoa pod.
|
// Get the location from the new cocoa pod.
|
||||||
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, false);
|
auto CocoaPos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace, false);
|
||||||
BlockMeta = cBlockCocoaPodHandler::BlockFaceToMeta(a_BlockFace);
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (a_Player->PlaceBlock(CocoaPos.x, CocoaPos.y, CocoaPos.z, E_BLOCK_COCOA_POD, BlockMeta))
|
||||||
// Place the cocoa pod:
|
|
||||||
if (a_Player->PlaceBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_COCOA_POD, BlockMeta))
|
|
||||||
{
|
{
|
||||||
if (a_Player->IsGameModeSurvival())
|
if (a_Player->IsGameModeSurvival())
|
||||||
{
|
{
|
||||||
|
@ -97,7 +100,7 @@ public:
|
||||||
Returns true if the plant was fertilized successfully, false if not / not a plant.
|
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,
|
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). */
|
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;
|
BLOCKTYPE blockType;
|
||||||
NIBBLETYPE blockMeta;
|
NIBBLETYPE blockMeta;
|
||||||
|
|
|
@ -23,15 +23,19 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool OnItemUse(
|
virtual bool OnItemUse(
|
||||||
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
|
cWorld * a_World,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
|
cPlayer * a_Player,
|
||||||
|
cBlockPluginInterface & a_PluginInterface,
|
||||||
|
const cItem & a_HeldItem,
|
||||||
|
const Vector3i a_ClickedBlockPos,
|
||||||
|
eBlockFace a_ClickedBlockFace
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
UNUSED(a_Item);
|
UNUSED(a_HeldItem);
|
||||||
UNUSED(a_BlockX);
|
UNUSED(a_ClickedBlockFace);
|
||||||
UNUSED(a_BlockZ);
|
|
||||||
UNUSED(a_BlockFace);
|
|
||||||
|
|
||||||
// The map center is fixed at the central point of the 8x8 block of chunks you are standing in when you right-click it.
|
// 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 CenterX = FloorC(a_Player->GetPosX() / RegionWidth) * RegionWidth + (RegionWidth / 2);
|
||||||
int CenterZ = FloorC(a_Player->GetPosZ() / RegionWidth) * RegionWidth + (RegionWidth / 2);
|
int CenterZ = FloorC(a_Player->GetPosZ() / RegionWidth) * RegionWidth + (RegionWidth / 2);
|
||||||
|
|
||||||
cMap * NewMap = a_World->GetMapManager().CreateMap(CenterX, CenterZ, DEFAULT_SCALE);
|
auto NewMap = a_World->GetMapManager().CreateMap(CenterX, CenterZ, DEFAULT_SCALE);
|
||||||
|
|
||||||
// Remove empty map from inventory
|
|
||||||
if (!a_Player->GetInventory().RemoveOneEquippedItem())
|
|
||||||
{
|
|
||||||
ASSERT(!"Inventory mismatch");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (NewMap == nullptr)
|
if (NewMap == nullptr)
|
||||||
{
|
{
|
||||||
return true;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
} ;
|
} ;
|
||||||
|
|
|
@ -8,46 +8,53 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cItemEyeOfEnderHandler :
|
class cItemEyeOfEnderHandler:
|
||||||
public cItemThrowableHandler
|
public cItemThrowableHandler
|
||||||
{
|
{
|
||||||
typedef cItemThrowableHandler super;
|
using Super = cItemThrowableHandler;
|
||||||
|
|
||||||
public:
|
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(
|
virtual bool OnItemUse(
|
||||||
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
|
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
|
) override
|
||||||
{
|
{
|
||||||
BLOCKTYPE FacingBlock;
|
// Try to fill an End Portal Frame block:
|
||||||
NIBBLETYPE FacingMeta;
|
if (a_ClickedBlockFace != BLOCK_FACE_NONE)
|
||||||
a_World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, FacingBlock, FacingMeta);
|
|
||||||
switch (FacingBlock)
|
|
||||||
{
|
{
|
||||||
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.
|
// 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)
|
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())
|
if (!a_Player->IsGameModeCreative())
|
||||||
{
|
{
|
||||||
a_Player->GetInventory().RemoveOneEquippedItem();
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,190 +63,36 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool OnItemUse(
|
virtual bool OnItemUse(
|
||||||
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
|
cWorld * a_World,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
|
cPlayer * a_Player,
|
||||||
|
cBlockPluginInterface & a_PluginInterface,
|
||||||
|
const cItem & a_HeldItem,
|
||||||
|
const Vector3i a_ClickedBlockPos,
|
||||||
|
eBlockFace a_ClickedBlockFace
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
if (a_BlockFace != BLOCK_FACE_NONE)
|
if (a_ClickedBlockFace != BLOCK_FACE_NONE)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto & Random = GetRandomProvider();
|
|
||||||
|
|
||||||
if (a_Player->IsFishing())
|
if (a_Player->IsFishing())
|
||||||
{
|
{
|
||||||
cFloaterCallback FloaterInfo;
|
ReelIn(*a_World, *a_Player);
|
||||||
a_World->DoWithEntityByID(a_Player->GetFloaterID(), FloaterInfo);
|
|
||||||
a_Player->SetIsFishing(false);
|
|
||||||
|
|
||||||
if (FloaterInfo.IsAttached())
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
else if (FloaterInfo.CanPickup())
|
|
||||||
{
|
|
||||||
UInt32 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])
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
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
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cRoot::Get()->GetPluginManager()->CallHookPlayerFishing(*a_Player, Drops))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
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))
|
|
||||||
{
|
|
||||||
a_Player->UseEquippedItem(2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
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)));
|
// 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();
|
auto FloaterPtr = Floater.get();
|
||||||
if (!FloaterPtr->Initialize(std::move(Floater), *a_World))
|
if (!FloaterPtr->Initialize(std::move(Floater), *a_World))
|
||||||
{
|
{
|
||||||
|
@ -256,4 +102,206 @@ public:
|
||||||
}
|
}
|
||||||
return true;
|
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)
|
||||||
|
{
|
||||||
|
auto Speed = PlayerPos - a_Entity.GetPosition();
|
||||||
|
a_Entity.AddSpeed(Speed);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
a_Player.UseEquippedItem(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
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:
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
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
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
} ;
|
} ;
|
||||||
|
|
|
@ -7,26 +7,36 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cItemFlowerPotHandler :
|
class cItemFlowerPotHandler:
|
||||||
public cItemHandler
|
public cItemHandler
|
||||||
{
|
{
|
||||||
|
using Super = cItemHandler;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
cItemFlowerPotHandler(int a_ItemType) :
|
|
||||||
cItemHandler(a_ItemType)
|
cItemFlowerPotHandler(int a_ItemType):
|
||||||
|
Super(a_ItemType)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool IsPlaceable(void) override
|
virtual bool IsPlaceable(void) override
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool GetPlacementBlockTypeMeta(
|
virtual bool GetPlacementBlockTypeMeta(
|
||||||
cWorld * a_World, cPlayer * a_Player,
|
cWorld * a_World, cPlayer * a_Player,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
const Vector3i a_PlacedBlockPos,
|
||||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
eBlockFace a_ClickedBlockFace,
|
||||||
|
const Vector3i a_CursorPos,
|
||||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
|
|
|
@ -346,41 +346,44 @@ cItemHandler::cItemHandler(int a_ItemType)
|
||||||
|
|
||||||
|
|
||||||
bool cItemHandler::OnPlayerPlace(
|
bool cItemHandler::OnPlayerPlace(
|
||||||
cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
|
cWorld & a_World,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
cPlayer & a_Player,
|
||||||
int a_CursorX, int a_CursorY, int a_CursorZ
|
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;
|
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)
|
// The clicked block is outside the world, ignore this call altogether (#128)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
BLOCKTYPE ClickedBlock;
|
BLOCKTYPE ClickedBlockType;
|
||||||
NIBBLETYPE ClickedBlockMeta;
|
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());
|
cChunkInterface ChunkInterface(a_World.GetChunkMap());
|
||||||
|
|
||||||
// Check if the block ignores build collision (water, grass etc.):
|
// Check if the block ignores build collision (water, grass etc.):
|
||||||
auto blockHandler = BlockHandler(ClickedBlock);
|
auto HandlerB = BlockHandler(ClickedBlockType);
|
||||||
Vector3i absPos(a_BlockX, a_BlockY, a_BlockZ);
|
auto PlacedBlockPos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace);
|
||||||
if (blockHandler->DoesIgnoreBuildCollision(ChunkInterface, absPos, a_Player, ClickedBlockMeta))
|
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
|
else
|
||||||
{
|
{
|
||||||
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
|
if (!cChunkDef::IsValidHeight(PlacedBlockPos.y))
|
||||||
|
|
||||||
if ((a_BlockY < 0) || (a_BlockY >= cChunkDef::Height))
|
|
||||||
{
|
{
|
||||||
// The block is being placed outside the world, ignore this packet altogether (#128)
|
// The block is being placed outside the world, ignore this packet altogether (#128)
|
||||||
return false;
|
return false;
|
||||||
|
@ -388,11 +391,11 @@ bool cItemHandler::OnPlayerPlace(
|
||||||
|
|
||||||
NIBBLETYPE PlaceMeta;
|
NIBBLETYPE PlaceMeta;
|
||||||
BLOCKTYPE PlaceBlock;
|
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.
|
// 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.
|
// 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?
|
// 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
|
// 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:
|
// Get all the blocks to place:
|
||||||
sSetBlockVector blocks;
|
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:
|
// Handler refused the placement, send that information back to the client:
|
||||||
for (const auto & blk: blocks)
|
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();
|
a_Player.GetInventory().SendEquippedSlot();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -436,18 +440,19 @@ bool cItemHandler::OnPlayerPlace(
|
||||||
|
|
||||||
bool cItemHandler::GetBlocksToPlace(
|
bool cItemHandler::GetBlocksToPlace(
|
||||||
cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
|
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_PlacedBlockPos,
|
||||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
eBlockFace a_ClickedBlockFace,
|
||||||
|
const Vector3i a_CursorPos,
|
||||||
sSetBlockVector & a_BlocksToSet
|
sSetBlockVector & a_BlocksToSet
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
BLOCKTYPE BlockType;
|
BLOCKTYPE BlockType;
|
||||||
NIBBLETYPE BlockMeta;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
a_BlocksToSet.emplace_back(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta);
|
a_BlocksToSet.emplace_back(a_PlacedBlockPos, BlockType, BlockMeta);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -457,17 +462,15 @@ bool cItemHandler::GetBlocksToPlace(
|
||||||
|
|
||||||
bool cItemHandler::OnItemUse(
|
bool cItemHandler::OnItemUse(
|
||||||
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
|
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_World);
|
||||||
UNUSED(a_Player);
|
UNUSED(a_Player);
|
||||||
UNUSED(a_PluginInterface);
|
UNUSED(a_PluginInterface);
|
||||||
UNUSED(a_Item);
|
UNUSED(a_Item);
|
||||||
UNUSED(a_BlockX);
|
UNUSED(a_ClickedBlockPos);
|
||||||
UNUSED(a_BlockY);
|
UNUSED(a_ClickedBlockFace);
|
||||||
UNUSED(a_BlockZ);
|
|
||||||
UNUSED(a_BlockFace);
|
|
||||||
|
|
||||||
return false;
|
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_World);
|
||||||
UNUSED(a_Player);
|
UNUSED(a_Player);
|
||||||
UNUSED(a_Item);
|
UNUSED(a_HeldItem);
|
||||||
UNUSED(a_BlockX);
|
UNUSED(a_ClickedBlockPos);
|
||||||
UNUSED(a_BlockY);
|
UNUSED(a_ClickedBlockFace);
|
||||||
UNUSED(a_BlockZ);
|
|
||||||
UNUSED(a_Dir);
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -815,8 +822,8 @@ bool cItemHandler::CanHarvestBlock(BLOCKTYPE a_BlockType)
|
||||||
|
|
||||||
bool cItemHandler::GetPlacementBlockTypeMeta(
|
bool cItemHandler::GetPlacementBlockTypeMeta(
|
||||||
cWorld * a_World, cPlayer * a_Player,
|
cWorld * a_World, cPlayer * a_Player,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
const Vector3i a_PlacedBlockPos, eBlockFace a_ClickedBlockFace,
|
||||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
const Vector3i a_CursorPos,
|
||||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
@ -832,8 +839,8 @@ bool cItemHandler::GetPlacementBlockTypeMeta(
|
||||||
cChunkInterface ChunkInterface(a_World->GetChunkMap());
|
cChunkInterface ChunkInterface(a_World->GetChunkMap());
|
||||||
return BlockH->GetPlacementBlockTypeMeta(
|
return BlockH->GetPlacementBlockTypeMeta(
|
||||||
ChunkInterface, *a_Player,
|
ChunkInterface, *a_Player,
|
||||||
a_BlockX, a_BlockY, a_BlockZ, a_BlockFace,
|
a_PlacedBlockPos, a_ClickedBlockFace,
|
||||||
a_CursorX, a_CursorY, a_CursorZ,
|
a_CursorPos,
|
||||||
a_BlockType, a_BlockMeta
|
a_BlockType, a_BlockMeta
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,28 +38,39 @@ public:
|
||||||
|
|
||||||
|
|
||||||
/** Called when the player tries to place the item (right mouse button, IsPlaceable() == true).
|
/** 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.
|
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.
|
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.
|
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. */
|
Returns true if the placement succeeded, false if the placement was aborted for any reason. */
|
||||||
virtual bool OnPlayerPlace(
|
virtual bool OnPlayerPlace(
|
||||||
cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
|
cWorld & a_World,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
cPlayer & a_Player,
|
||||||
int a_CursorX, int a_CursorY, int a_CursorZ
|
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.
|
/** 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.
|
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.
|
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. */
|
If aborted, the server then sends all original blocks in the coords provided in a_BlocksToSet to the client. */
|
||||||
virtual bool GetBlocksToPlace(
|
virtual bool GetBlocksToPlace(
|
||||||
cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
|
cWorld & a_World,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
cPlayer & a_Player,
|
||||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
const cItem & a_EquippedItem,
|
||||||
sSetBlockVector & a_BlocksToSet
|
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. */
|
Returns true to allow placement, false to refuse. */
|
||||||
virtual bool GetPlacementBlockTypeMeta(
|
virtual bool GetPlacementBlockTypeMeta(
|
||||||
cWorld * a_World, cPlayer * a_Player,
|
cWorld * a_World, cPlayer * a_Player,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
const Vector3i a_PlacedBlockPos,
|
||||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
eBlockFace a_ClickedBlockFace,
|
||||||
|
const Vector3i a_CursorPos,
|
||||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
/** Called when the player tries to use the item (right mouse button).
|
/** 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(
|
virtual bool OnItemUse(
|
||||||
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
|
cWorld * a_World,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
|
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 */
|
/** Called when the client sends the SHOOT status in the lclk packet (releasing the bow). */
|
||||||
virtual void OnItemShoot(cPlayer *, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace)
|
virtual void OnItemShoot(cPlayer *, const Vector3i a_BlockPos, eBlockFace a_BlockFace)
|
||||||
{
|
{
|
||||||
UNUSED(a_BlockX);
|
UNUSED(a_BlockPos);
|
||||||
UNUSED(a_BlockY);
|
|
||||||
UNUSED(a_BlockZ);
|
|
||||||
UNUSED(a_BlockFace);
|
UNUSED(a_BlockFace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,9 +114,13 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Called while the player digs a block using this item */
|
/** 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);
|
virtual void OnEntityAttack(cPlayer * a_Attacker, cEntity * a_AttackedEntity);
|
||||||
|
|
||||||
/** Called after the player has eaten this item. */
|
/** Called after the player has eaten this item. */
|
||||||
|
|
|
@ -9,64 +9,68 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cItemHoeHandler :
|
class cItemHoeHandler:
|
||||||
public cItemHandler
|
public cItemHandler
|
||||||
{
|
{
|
||||||
|
using Super = cItemHandler;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
cItemHoeHandler(int a_ItemType)
|
|
||||||
: cItemHandler(a_ItemType)
|
cItemHoeHandler(int a_ItemType):
|
||||||
|
Super(a_ItemType)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool OnItemUse(
|
virtual bool OnItemUse(
|
||||||
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
|
cWorld * a_World,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
|
cPlayer * a_Player,
|
||||||
|
cBlockPluginInterface & a_PluginInterface,
|
||||||
|
const cItem & a_HeldItem,
|
||||||
|
const Vector3i a_ClickedBlockPos,
|
||||||
|
eBlockFace a_ClickedBlockFace
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
if ((a_BlockFace == BLOCK_FACE_NONE) || (a_BlockY >= cChunkDef::Height))
|
if ((a_ClickedBlockFace == BLOCK_FACE_NONE) || (a_ClickedBlockPos.y >= cChunkDef::Height))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
BLOCKTYPE UpperBlock = a_World->GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ);
|
|
||||||
|
|
||||||
BLOCKTYPE Block;
|
// Need air above the hoe-d block to transform it:
|
||||||
NIBBLETYPE BlockMeta;
|
BLOCKTYPE UpperBlockType = a_World->GetBlock(a_ClickedBlockPos.addedY(1));
|
||||||
a_World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, Block, BlockMeta);
|
if (UpperBlockType != E_BLOCK_AIR)
|
||||||
|
|
||||||
if (((Block == E_BLOCK_DIRT) || (Block == E_BLOCK_GRASS)) && (UpperBlock == E_BLOCK_AIR))
|
|
||||||
{
|
{
|
||||||
BLOCKTYPE NewBlock = E_BLOCK_FARMLAND;
|
return false;
|
||||||
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;
|
// 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))
|
||||||
|
{
|
||||||
|
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
|
virtual short GetDurabilityLossByAction(eDurabilityLostAction a_Action) override
|
||||||
{
|
{
|
||||||
switch (a_Action)
|
switch (a_Action)
|
||||||
|
|
|
@ -9,51 +9,59 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cItemItemFrameHandler :
|
class cItemItemFrameHandler:
|
||||||
public cItemHandler
|
public cItemHandler
|
||||||
{
|
{
|
||||||
public:
|
using Super = cItemHandler;
|
||||||
cItemItemFrameHandler(int a_ItemType)
|
|
||||||
: cItemHandler(a_ItemType)
|
|
||||||
{
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
cItemItemFrameHandler(int a_ItemType):
|
||||||
|
Super(a_ItemType)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool OnItemUse(
|
virtual bool OnItemUse(
|
||||||
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
|
cWorld * a_World,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
|
cPlayer * a_Player,
|
||||||
|
cBlockPluginInterface & a_PluginInterface,
|
||||||
|
const cItem & a_HeldItem,
|
||||||
|
const Vector3i a_ClickedBlockPos,
|
||||||
|
eBlockFace a_ClickedBlockFace
|
||||||
) override
|
) 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); // Make sure block that will be occupied is free
|
// Make sure block that will be occupied by the item frame is free now:
|
||||||
BLOCKTYPE Block = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
|
auto PlacePos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace);
|
||||||
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, true); // We want the clicked block, so go back again
|
BLOCKTYPE Block = a_World->GetBlock(PlacePos);
|
||||||
|
if (Block != E_BLOCK_AIR)
|
||||||
if (Block == E_BLOCK_AIR)
|
|
||||||
{
|
{
|
||||||
auto ItemFrame = cpp14::make_unique<cItemFrame>(a_BlockFace, Vector3i{a_BlockX, a_BlockY, a_BlockZ});
|
return false;
|
||||||
auto ItemFramePtr = ItemFrame.get();
|
|
||||||
if (!ItemFramePtr->Initialize(std::move(ItemFrame), *a_World))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!a_Player->IsGameModeCreative())
|
|
||||||
{
|
|
||||||
a_Player->GetInventory().RemoveOneEquippedItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
// 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 true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -19,17 +19,23 @@ public:
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool GetPlacementBlockTypeMeta(
|
virtual bool GetPlacementBlockTypeMeta(
|
||||||
cWorld * a_World, cPlayer * a_Player,
|
cWorld * a_World, cPlayer * a_Player,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
const Vector3i a_PlacedBlockPos,
|
||||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
eBlockFace a_ClickedBlockFace,
|
||||||
|
const Vector3i a_CursorPos,
|
||||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
bool res = Super::GetPlacementBlockTypeMeta(
|
bool res = Super::GetPlacementBlockTypeMeta(
|
||||||
a_World, a_Player,
|
a_World, a_Player,
|
||||||
a_BlockX, a_BlockY, a_BlockZ, a_BlockFace,
|
a_PlacedBlockPos,
|
||||||
a_CursorX, a_CursorY, a_CursorZ,
|
a_ClickedBlockFace,
|
||||||
|
a_CursorPos,
|
||||||
a_BlockType, a_BlockMeta
|
a_BlockType, a_BlockMeta
|
||||||
);
|
);
|
||||||
a_BlockMeta = a_BlockMeta | 0x4; // 0x4 bit set means this is a player-placed leaves block, not to be decayed
|
a_BlockMeta = a_BlockMeta | 0x4; // 0x4 bit set means this is a player-placed leaves block, not to be decayed
|
||||||
|
|
|
@ -9,23 +9,32 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cItemLighterHandler :
|
class cItemLighterHandler:
|
||||||
public cItemHandler
|
public cItemHandler
|
||||||
{
|
{
|
||||||
|
using Super = cItemHandler;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
cItemLighterHandler(int a_ItemType) :
|
|
||||||
cItemHandler(a_ItemType)
|
cItemLighterHandler(int a_ItemType):
|
||||||
|
Super(a_ItemType)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool OnItemUse(
|
virtual bool OnItemUse(
|
||||||
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
|
cWorld * a_World,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
|
cPlayer * a_Player,
|
||||||
|
cBlockPluginInterface & a_PluginInterface,
|
||||||
|
const cItem & a_HeldItem,
|
||||||
|
const Vector3i a_ClickedBlockPos,
|
||||||
|
eBlockFace a_ClickedBlockFace
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
if (a_BlockFace < 0)
|
if (a_ClickedBlockFace < 0)
|
||||||
{
|
{
|
||||||
return false;
|
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:
|
case E_BLOCK_TNT:
|
||||||
{
|
{
|
||||||
// Activate the TNT:
|
// Activate the TNT:
|
||||||
a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
|
a_World->SetBlock(a_ClickedBlockPos, 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->SpawnPrimedTNT(Vector3d(a_ClickedBlockPos) + Vector3d(0.5, 0.5, 0.5)); // 80 ticks to boom
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// Light a fire next to / on top of the block if air:
|
// Light a fire next to / on top of the block if air:
|
||||||
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
|
auto FirePos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace);
|
||||||
if ((a_BlockY < 0) || (a_BlockY >= cChunkDef::Height))
|
if (!cChunkDef::IsValidHeight(FirePos.y))
|
||||||
{
|
{
|
||||||
break;
|
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->SetBlock(FirePos, E_BLOCK_FIRE, 0);
|
||||||
a_World->BroadcastSoundEffect("item.flintandsteel.use", Vector3d(a_BlockX, a_BlockY, a_BlockZ), 1.0F, 1.04F);
|
a_World->BroadcastSoundEffect("item.flintandsteel.use", FirePos, 1.0f, 1.04f);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,9 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool IsPlaceable(void) override
|
virtual bool IsPlaceable(void) override
|
||||||
{
|
{
|
||||||
return false; // Set as not placeable so OnItemUse is called
|
return false; // Set as not placeable so OnItemUse is called
|
||||||
|
@ -30,16 +33,22 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool OnItemUse(
|
virtual bool OnItemUse(
|
||||||
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
|
cWorld * a_World,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
|
cPlayer * a_Player,
|
||||||
|
cBlockPluginInterface & a_PluginInterface,
|
||||||
|
const cItem & a_HeldItem,
|
||||||
|
const Vector3i a_ClickedBlockPos,
|
||||||
|
eBlockFace a_ClickedBlockFace
|
||||||
) override
|
) 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
|
// Clicked on a face of a submerged block; vanilla allows placement, so should we
|
||||||
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
|
auto PlacePos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace);
|
||||||
a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_LILY_PAD, 0);
|
a_World->SetBlock(PlacePos, E_BLOCK_LILY_PAD, 0);
|
||||||
if (!a_Player->IsGameModeCreative())
|
if (!a_Player->IsGameModeCreative())
|
||||||
{
|
{
|
||||||
a_Player->GetInventory().RemoveOneEquippedItem();
|
a_Player->GetInventory().RemoveOneEquippedItem();
|
||||||
|
@ -47,12 +56,12 @@ public:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
class cCallbacks :
|
class cCallbacks:
|
||||||
public cBlockTracer::cCallbacks
|
public cBlockTracer::cCallbacks
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
cCallbacks(void) :
|
cCallbacks():
|
||||||
m_HasHitFluid(false)
|
m_HasHitFluid(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -84,18 +93,14 @@ public:
|
||||||
Vector3i m_Pos;
|
Vector3i m_Pos;
|
||||||
bool m_HasHitFluid;
|
bool m_HasHitFluid;
|
||||||
|
|
||||||
};
|
} Callbacks;
|
||||||
|
auto Start = a_Player->GetEyePosition() + a_Player->GetLookVector();
|
||||||
cCallbacks Callbacks;
|
auto End = a_Player->GetEyePosition() + a_Player->GetLookVector() * 5;
|
||||||
cLineBlockTracer Tracer(*a_Player->GetWorld(), Callbacks);
|
cLineBlockTracer::Trace(*a_Player->GetWorld(), Callbacks, Start.x, Start.y, Start.z, End.x, End.y, End.z);
|
||||||
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);
|
|
||||||
|
|
||||||
if (Callbacks.m_HasHitFluid)
|
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())
|
if (!a_Player->IsGameModeCreative())
|
||||||
{
|
{
|
||||||
a_Player->GetInventory().RemoveOneEquippedItem();
|
a_Player->GetInventory().RemoveOneEquippedItem();
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../Entities/Minecart.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,18 +19,25 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool OnItemUse(
|
virtual bool OnItemUse(
|
||||||
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
|
cWorld * a_World,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
|
cPlayer * a_Player,
|
||||||
|
cBlockPluginInterface & a_PluginInterface,
|
||||||
|
const cItem & a_HeldItem,
|
||||||
|
const Vector3i a_ClickedBlockPos,
|
||||||
|
eBlockFace a_ClickedBlockFace
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
if (a_BlockFace < 0)
|
// Must be used on a block
|
||||||
|
if (a_ClickedBlockFace < 0)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that there's rail in there:
|
// 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)
|
switch (Block)
|
||||||
{
|
{
|
||||||
case E_BLOCK_MINECART_TRACKS:
|
case E_BLOCK_MINECART_TRACKS:
|
||||||
|
@ -50,15 +55,14 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
double x = static_cast<double>(a_BlockX) + 0.5;
|
// Spawn the minecart:
|
||||||
double y = static_cast<double>(a_BlockY) + 0.5;
|
auto SpawnPos = Vector3d(a_ClickedBlockPos) + Vector3d(0.5, 0.5, 0.5);
|
||||||
double z = static_cast<double>(a_BlockZ) + 0.5;
|
if (a_World->SpawnMinecart(SpawnPos, m_ItemType) == cEntity::INVALID_ID)
|
||||||
|
|
||||||
if (a_World->SpawnMinecart(x, y, z, m_ItemType) == cEntity::INVALID_ID)
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove the item from inventory:
|
||||||
if (!a_Player->IsGameModeCreative())
|
if (!a_Player->IsGameModeCreative())
|
||||||
{
|
{
|
||||||
a_Player->GetInventory().RemoveOneEquippedItem();
|
a_Player->GetInventory().RemoveOneEquippedItem();
|
||||||
|
|
|
@ -22,52 +22,60 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool OnPlayerPlace(
|
virtual bool OnPlayerPlace(
|
||||||
cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
|
cWorld & a_World,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
cPlayer & a_Player,
|
||||||
int a_CursorX, int a_CursorY, int a_CursorZ
|
const cItem & a_EquippedItem,
|
||||||
|
const Vector3i a_ClickedBlockPos,
|
||||||
|
eBlockFace a_ClickedBlockFace,
|
||||||
|
const Vector3i a_CursorPos
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
// Cannot place a head at "no face" and from the bottom:
|
// 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;
|
return true;
|
||||||
}
|
}
|
||||||
auto placedX = a_BlockX, placedY = a_BlockY, placedZ = a_BlockZ;
|
const auto PlacePos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace);
|
||||||
AddFaceDirection(placedY, placedY, placedZ, a_BlockFace);
|
|
||||||
|
|
||||||
// If the placed head is a wither, try to spawn the wither first:
|
// If the placed head is a wither, try to spawn the wither first:
|
||||||
if (a_EquippedItem.m_ItemDamage == E_META_HEAD_WITHER)
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
// Wither not created, proceed with regular head placement
|
// 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
|
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))
|
if (!Super::OnPlayerPlace(a_World, a_Player, a_EquippedItem, a_ClickedBlockPos, a_ClickedBlockFace, a_CursorPos))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
RegularHeadPlaced(a_World, a_Player, itemCopy, placedX, placedY, placedZ, a_BlockFace);
|
RegularHeadPlaced(a_World, a_Player, ItemCopy, PlacePos, a_ClickedBlockFace);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Called after placing a regular head block with no mob spawning.
|
/** Called after placing a regular head block with no mob spawning.
|
||||||
Adjusts the mob head entity based on the equipped item's data. */
|
Adjusts the mob head entity based on the equipped item's data. */
|
||||||
void RegularHeadPlaced(
|
void RegularHeadPlaced(
|
||||||
cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
|
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 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:
|
// 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)
|
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.
|
/** Spawns a wither if the wither skull placed at the specified coords completes wither's spawning formula.
|
||||||
Returns true if the wither was created. */
|
Returns true if the wither was created. */
|
||||||
bool TrySpawnWitherAround(
|
bool TrySpawnWitherAround(
|
||||||
cWorld & a_World, cPlayer & a_Player,
|
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:
|
// 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.
|
/** 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,
|
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.
|
but assumed to be a head instead.
|
||||||
|
@ -265,6 +279,9 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Awards the achievement to all players close to the specified point. */
|
/** Awards the achievement to all players close to the specified point. */
|
||||||
void AwardSpawnWitherAchievement(cWorld & a_World, Vector3i a_BlockPos)
|
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)
|
/** Converts the block face of the placement (which face of the block was clicked to place the head)
|
||||||
into the block's metadata value. */
|
into the block's metadata value. */
|
||||||
static NIBBLETYPE BlockFaceToBlockMeta(int a_BlockFace)
|
static NIBBLETYPE BlockFaceToBlockMeta(int a_BlockFace)
|
||||||
|
@ -303,21 +323,28 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool IsPlaceable(void) override
|
virtual bool IsPlaceable(void) override
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool GetPlacementBlockTypeMeta(
|
virtual bool GetPlacementBlockTypeMeta(
|
||||||
cWorld * a_World, cPlayer * a_Player,
|
cWorld * a_World, cPlayer * a_Player,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
const Vector3i a_PlacedBlockPos,
|
||||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
eBlockFace a_ClickedBlockFace,
|
||||||
|
const Vector3i a_CursorPos,
|
||||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
a_BlockType = E_BLOCK_HEAD;
|
a_BlockType = E_BLOCK_HEAD;
|
||||||
a_BlockMeta = BlockFaceToBlockMeta(a_BlockFace);
|
a_BlockMeta = BlockFaceToBlockMeta(a_ClickedBlockFace);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} ;
|
} ;
|
||||||
|
|
|
@ -8,47 +8,53 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cItemNetherWartHandler :
|
class cItemNetherWartHandler:
|
||||||
public cItemHandler
|
public cItemHandler
|
||||||
{
|
{
|
||||||
public:
|
using Super = cItemHandler;
|
||||||
cItemNetherWartHandler(int a_ItemType) :
|
|
||||||
cItemHandler(a_ItemType)
|
|
||||||
{
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
cItemNetherWartHandler(int a_ItemType):
|
||||||
|
Super(a_ItemType)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool IsPlaceable(void) override
|
virtual bool IsPlaceable(void) override
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool GetPlacementBlockTypeMeta(
|
virtual bool GetPlacementBlockTypeMeta(
|
||||||
cWorld * a_World, cPlayer * a_Player,
|
cWorld * a_World, cPlayer * a_Player,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
const Vector3i a_PlacedBlockPos,
|
||||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
eBlockFace a_ClickedBlockFace,
|
||||||
|
const Vector3i a_CursorPos,
|
||||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||||
) override
|
) 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only allow placement on farmland
|
// Only allow placement on soulsand
|
||||||
int X = a_BlockX;
|
if ((a_PlacedBlockPos.y < 1) || (a_World->GetBlock(a_PlacedBlockPos.addedY(-1)) != E_BLOCK_SOULSAND))
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
a_BlockMeta = 0;
|
a_BlockMeta = 0;
|
||||||
a_BlockType = E_BLOCK_NETHER_WART;
|
a_BlockType = E_BLOCK_NETHER_WART;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} ;
|
} ;
|
||||||
|
|
|
@ -10,82 +10,93 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cItemPaintingHandler :
|
class cItemPaintingHandler:
|
||||||
public cItemHandler
|
public cItemHandler
|
||||||
{
|
{
|
||||||
|
using Super = cItemHandler;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
cItemPaintingHandler(int a_ItemType)
|
|
||||||
: cItemHandler(a_ItemType)
|
cItemPaintingHandler(int a_ItemType):
|
||||||
|
Super(a_ItemType)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool OnItemUse(
|
virtual bool OnItemUse(
|
||||||
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
|
cWorld * a_World,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
|
cPlayer * a_Player,
|
||||||
|
cBlockPluginInterface & a_PluginInterface,
|
||||||
|
const cItem & a_HeldItem,
|
||||||
|
const Vector3i a_ClickedBlockPos,
|
||||||
|
eBlockFace a_ClickedBlockFace
|
||||||
) override
|
) 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); // Make sure block that will be occupied is free
|
// Make sure block that will be occupied is free:
|
||||||
BLOCKTYPE Block = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
|
auto PlacePos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace);
|
||||||
|
BLOCKTYPE PlaceBlockType = a_World->GetBlock(PlacePos);
|
||||||
if (Block == E_BLOCK_AIR)
|
if (PlaceBlockType != E_BLOCK_AIR)
|
||||||
{
|
{
|
||||||
static const struct // Define all the possible painting titles
|
return false;
|
||||||
{
|
|
||||||
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;
|
|
||||||
|
// 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))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!a_Player->IsGameModeCreative())
|
||||||
|
{
|
||||||
|
a_Player->GetInventory().RemoveOneEquippedItem();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,9 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// cItemHandler overrides:
|
// cItemHandler overrides:
|
||||||
virtual bool IsDrinkable(short a_ItemDamage) override
|
virtual bool IsDrinkable(short a_ItemDamage) override
|
||||||
{
|
{
|
||||||
|
@ -26,12 +29,19 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool OnItemUse(
|
virtual bool OnItemUse(
|
||||||
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
|
cWorld * a_World,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
|
cPlayer * a_Player,
|
||||||
|
cBlockPluginInterface & a_PluginInterface,
|
||||||
|
const cItem & a_HeldItem,
|
||||||
|
const Vector3i a_ClickedBlockPos,
|
||||||
|
eBlockFace a_ClickedBlockFace
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
short PotionDamage = a_Item.m_ItemDamage;
|
short PotionDamage = a_HeldItem.m_ItemDamage;
|
||||||
|
|
||||||
// Do not throw non-splash potions:
|
// Do not throw non-splash potions:
|
||||||
if (cEntityEffect::IsPotionDrinkable(PotionDamage))
|
if (cEntityEffect::IsPotionDrinkable(PotionDamage))
|
||||||
|
@ -59,6 +69,9 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool EatItem(cPlayer * a_Player, cItem * a_Item) override
|
virtual bool EatItem(cPlayer * a_Player, cItem * a_Item) override
|
||||||
{
|
{
|
||||||
short PotionDamage = a_Item->m_ItemDamage;
|
short PotionDamage = a_Item->m_ItemDamage;
|
||||||
|
|
|
@ -20,44 +20,50 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool OnPlayerPlace(
|
virtual bool OnPlayerPlace(
|
||||||
cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
|
cWorld & a_World,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
cPlayer & a_Player,
|
||||||
int a_CursorX, int a_CursorY, int a_CursorZ
|
const cItem & a_EquippedItem,
|
||||||
|
const Vector3i a_ClickedBlockPos,
|
||||||
|
eBlockFace a_ClickedBlockFace,
|
||||||
|
const Vector3i a_CursorPos
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
// First try spawning a snow golem or an iron golem:
|
// First try spawning a snow golem or an iron golem:
|
||||||
int PlacedBlockX = a_BlockX;
|
auto PlacePos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace);
|
||||||
int PlacedBlockY = a_BlockY;
|
if (TrySpawnGolem(a_World, a_Player, PlacePos))
|
||||||
int PlacedBlockZ = a_BlockZ;
|
|
||||||
AddFaceDirection(PlacedBlockX, PlacedBlockY, PlacedBlockZ, a_BlockFace);
|
|
||||||
if (TrySpawnGolem(a_World, a_Player, PlacedBlockX, PlacedBlockY, PlacedBlockZ))
|
|
||||||
{
|
{
|
||||||
// The client thinks that they placed the pumpkin, let them know it's been replaced:
|
// 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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// No golem at these coords, place the block normally:
|
// 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.
|
/** 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. */
|
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
|
// 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decide which golem to try spawning based on the block below the placed pumpkin:
|
// 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_SNOW_BLOCK: return TrySpawnSnowGolem(a_World, a_Player, a_PumpkinPos);
|
||||||
case E_BLOCK_IRON_BLOCK: return TrySpawnIronGolem(a_World, a_Player, a_BlockX, a_BlockY, a_BlockZ);
|
case E_BLOCK_IRON_BLOCK: return TrySpawnIronGolem(a_World, a_Player, a_PumpkinPos);
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// No golem here
|
// 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.
|
/** 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.
|
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. */
|
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:
|
// 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to place air blocks where the original recipe blocks were:
|
// Try to place air blocks where the original recipe blocks were:
|
||||||
sSetBlockVector AirBlocks;
|
sSetBlockVector AirBlocks;
|
||||||
AirBlocks.emplace_back(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0); // Head
|
AirBlocks.emplace_back(a_PumpkinPos, E_BLOCK_AIR, 0); // Head
|
||||||
AirBlocks.emplace_back(a_BlockX, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0); // Torso
|
AirBlocks.emplace_back(a_PumpkinPos.addedY(-1), 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.addedY(-2), E_BLOCK_AIR, 0); // Legs
|
||||||
if (!a_Player.PlaceBlocks(AirBlocks))
|
if (!a_Player.PlaceBlocks(AirBlocks))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Spawn the golem:
|
// 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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Spawns an iron golem if the shape matches the recipe, supposing that the block placed at the specified coords is a pumpkin.
|
/** 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.
|
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. */
|
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:
|
// 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the two arm directions (X, Z) using a loop over two sets of offset vectors:
|
// 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[] =
|
static const Vector3i ArmOffsets[] =
|
||||||
{
|
{
|
||||||
{1, 0, 0},
|
{1, 0, 0},
|
||||||
|
@ -115,8 +135,8 @@ public:
|
||||||
{
|
{
|
||||||
// If the arm blocks don't match, bail out of this loop repetition:
|
// If the arm blocks don't match, bail out of this loop repetition:
|
||||||
if (
|
if (
|
||||||
(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(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)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
@ -124,18 +144,19 @@ public:
|
||||||
|
|
||||||
// Try to place air blocks where the original recipe blocks were:
|
// Try to place air blocks where the original recipe blocks were:
|
||||||
sSetBlockVector AirBlocks;
|
sSetBlockVector AirBlocks;
|
||||||
AirBlocks.emplace_back(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0); // Head
|
AirBlocks.emplace_back(a_PumpkinPos, E_BLOCK_AIR, 0); // Head
|
||||||
AirBlocks.emplace_back(a_BlockX, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0); // Torso
|
AirBlocks.emplace_back(BodyPos, E_BLOCK_AIR, 0); // Torso
|
||||||
AirBlocks.emplace_back(a_BlockX, a_BlockY - 2, a_BlockZ, E_BLOCK_AIR, 0); // Legs
|
AirBlocks.emplace_back(BodyPos.addedY(-1), 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(BodyPos + ArmOffsets[i], 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(BodyPos - ArmOffsets[i], E_BLOCK_AIR, 0); // Arm
|
||||||
if (!a_Player.PlaceBlocks(AirBlocks))
|
if (!a_Player.PlaceBlocks(AirBlocks))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Spawn the golem:
|
// 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;
|
return true;
|
||||||
} // for i - ArmOffsets[]
|
} // for i - ArmOffsets[]
|
||||||
|
|
||||||
|
|
|
@ -7,36 +7,48 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cItemRedstoneDustHandler : public cItemHandler
|
class cItemRedstoneDustHandler:
|
||||||
|
public cItemHandler
|
||||||
{
|
{
|
||||||
|
using Super = cItemHandler;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
cItemRedstoneDustHandler(int a_ItemType)
|
|
||||||
: cItemHandler(a_ItemType)
|
cItemRedstoneDustHandler(int a_ItemType):
|
||||||
|
Super(a_ItemType)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool IsPlaceable(void) override
|
virtual bool IsPlaceable(void) override
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool GetPlacementBlockTypeMeta(
|
virtual bool GetPlacementBlockTypeMeta(
|
||||||
cWorld * a_World, cPlayer * a_Player,
|
cWorld * a_World, cPlayer * a_Player,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
const Vector3i a_PlacedBlockPos,
|
||||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
eBlockFace a_ClickedBlockFace,
|
||||||
|
const Vector3i a_CursorPos,
|
||||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
// Check if coords are out of range:
|
// Check the block below, if it supports dust on top of it:
|
||||||
if ((a_BlockY <= 0) || (a_BlockY >= cChunkDef::Height))
|
auto UnderPos = a_PlacedBlockPos.addedY(-1);
|
||||||
|
if (UnderPos.y < 0)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the block below, if it supports dust on top of it:
|
|
||||||
BLOCKTYPE BlockType;
|
BLOCKTYPE BlockType;
|
||||||
NIBBLETYPE BlockMeta;
|
NIBBLETYPE BlockMeta;
|
||||||
if (!a_World->GetBlockTypeMeta(a_BlockX, a_BlockY - 1, a_BlockZ, BlockType, BlockMeta))
|
if (!a_World->GetBlockTypeMeta(UnderPos, BlockType, BlockMeta))
|
||||||
{
|
{
|
||||||
return false;
|
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. */
|
/** 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)
|
static bool IsBlockTypeUnderSuitable(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,24 +8,36 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cItemRedstoneRepeaterHandler :
|
class cItemRedstoneRepeaterHandler:
|
||||||
public cItemHandler
|
public cItemHandler
|
||||||
{
|
{
|
||||||
|
using Super = cItemHandler;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
cItemRedstoneRepeaterHandler(int a_ItemType)
|
|
||||||
: cItemHandler(a_ItemType)
|
cItemRedstoneRepeaterHandler(int a_ItemType):
|
||||||
|
Super(a_ItemType)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool IsPlaceable() override
|
virtual bool IsPlaceable() override
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool GetPlacementBlockTypeMeta(
|
virtual bool GetPlacementBlockTypeMeta(
|
||||||
cWorld * a_World, cPlayer * a_Player,
|
cWorld * a_World, cPlayer * a_Player,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
const Vector3i a_PlacedBlockPos,
|
||||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
eBlockFace a_ClickedBlockFace,
|
||||||
|
const Vector3i a_CursorPos,
|
||||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
|
|
|
@ -17,24 +17,29 @@ public:
|
||||||
cItemSaplingHandler(int a_ItemType):
|
cItemSaplingHandler(int a_ItemType):
|
||||||
Super(a_ItemType)
|
Super(a_ItemType)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool GetPlacementBlockTypeMeta(
|
virtual bool GetPlacementBlockTypeMeta(
|
||||||
cWorld * a_World, cPlayer * a_Player,
|
cWorld * a_World, cPlayer * a_Player,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
const Vector3i a_PlacedBlockPos,
|
||||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
eBlockFace a_ClickedBlockFace,
|
||||||
|
const Vector3i a_CursorPos,
|
||||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
bool res = Super::GetPlacementBlockTypeMeta(
|
bool res = Super::GetPlacementBlockTypeMeta(
|
||||||
a_World, a_Player,
|
a_World, a_Player,
|
||||||
a_BlockX, a_BlockY, a_BlockZ, a_BlockFace,
|
a_PlacedBlockPos, a_ClickedBlockFace,
|
||||||
a_CursorX, a_CursorY, a_CursorZ,
|
a_CursorPos,
|
||||||
a_BlockType, a_BlockMeta
|
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;
|
return res;
|
||||||
}
|
}
|
||||||
} ;
|
} ;
|
||||||
|
|
|
@ -8,44 +8,53 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cItemSeedsHandler :
|
class cItemSeedsHandler:
|
||||||
public cItemHandler
|
public cItemHandler
|
||||||
{
|
{
|
||||||
|
using Super = cItemHandler;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
cItemSeedsHandler(int a_ItemType) :
|
|
||||||
cItemHandler(a_ItemType)
|
cItemSeedsHandler(int a_ItemType):
|
||||||
|
Super(a_ItemType)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool IsPlaceable(void) override
|
virtual bool IsPlaceable(void) override
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool GetPlacementBlockTypeMeta(
|
virtual bool GetPlacementBlockTypeMeta(
|
||||||
cWorld * a_World, cPlayer * a_Player,
|
cWorld * a_World, cPlayer * a_Player,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
const Vector3i a_PlacedBlockPos,
|
||||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
eBlockFace a_ClickedBlockFace,
|
||||||
|
const Vector3i a_CursorPos,
|
||||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||||
) override
|
) 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only allow placement on farmland
|
// Only allow placement on farmland
|
||||||
int X = a_BlockX;
|
if (a_World->GetBlock(a_PlacedBlockPos.addedY(-1)) != E_BLOCK_FARMLAND)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the produce block based on the seed item:
|
||||||
a_BlockMeta = 0;
|
a_BlockMeta = 0;
|
||||||
switch (m_ItemType)
|
switch (m_ItemType)
|
||||||
{
|
{
|
||||||
|
|
|
@ -22,25 +22,33 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool IsTool(void) override
|
virtual bool IsTool(void) override
|
||||||
{
|
{
|
||||||
return true;
|
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;
|
BLOCKTYPE Block;
|
||||||
NIBBLETYPE BlockMeta;
|
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))
|
if ((Block == E_BLOCK_LEAVES) || (Block == E_BLOCK_NEW_LEAVES))
|
||||||
{
|
{
|
||||||
cItems Drops;
|
a_World->DropBlockAsPickups(a_ClickedBlockPos, a_Player, &a_HeldItem);
|
||||||
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);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,6 +56,9 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool CanHarvestBlock(BLOCKTYPE a_BlockType) override
|
virtual bool CanHarvestBlock(BLOCKTYPE a_BlockType) override
|
||||||
{
|
{
|
||||||
switch (a_BlockType)
|
switch (a_BlockType)
|
||||||
|
@ -63,6 +74,9 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual short GetDurabilityLossByAction(eDurabilityLostAction a_Action) override
|
virtual short GetDurabilityLossByAction(eDurabilityLostAction a_Action) override
|
||||||
{
|
{
|
||||||
switch (a_Action)
|
switch (a_Action)
|
||||||
|
@ -93,5 +107,4 @@ public:
|
||||||
return Super::GetBlockBreakingStrength(a_Block);
|
return Super::GetBlockBreakingStrength(a_Block);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} ;
|
} ;
|
||||||
|
|
|
@ -24,58 +24,68 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool OnPlayerPlace(
|
virtual bool OnPlayerPlace(
|
||||||
cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
|
cWorld & a_World,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
cPlayer & a_Player,
|
||||||
int a_CursorX, int a_CursorY, int a_CursorZ
|
const cItem & a_EquippedItem,
|
||||||
|
const Vector3i a_ClickedBlockPos,
|
||||||
|
eBlockFace a_ClickedBlockFace,
|
||||||
|
const Vector3i a_CursorPos
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
// Check if placing on something ignoring build collision to edit the correct sign later on:
|
// Check if placing on something ignoring build collision to edit the correct sign later on:
|
||||||
BLOCKTYPE ClickedBlock;
|
BLOCKTYPE ClickedBlockType;
|
||||||
NIBBLETYPE ClickedBlockMeta;
|
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());
|
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 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use isReplacingClickedBlock to make sure we will edit the right sign:
|
// Use IsReplacingClickedBlock to make sure we will edit the right sign:
|
||||||
if (!isReplacingClickedBlock)
|
auto SignPos = IsReplacingClickedBlock ? a_ClickedBlockPos : AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace);
|
||||||
{
|
|
||||||
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
|
|
||||||
}
|
|
||||||
|
|
||||||
// After successfully placing the sign, open the sign editor for the player:
|
// 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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool IsPlaceable(void) override
|
virtual bool IsPlaceable(void) override
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool GetPlacementBlockTypeMeta(
|
virtual bool GetPlacementBlockTypeMeta(
|
||||||
cWorld * a_World, cPlayer * a_Player,
|
cWorld * a_World, cPlayer * a_Player,
|
||||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
const Vector3i a_PlacedBlockPos,
|
||||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
eBlockFace a_ClickedBlockFace,
|
||||||
|
const Vector3i a_CursorPos,
|
||||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||||
) override
|
) override
|
||||||
{
|
{
|
||||||
if (a_BlockFace == BLOCK_FACE_TOP)
|
if (a_ClickedBlockFace == BLOCK_FACE_TOP)
|
||||||
{
|
{
|
||||||
a_BlockMeta = cBlockSignPostHandler::RotationToMetaData(a_Player->GetYaw());
|
a_BlockMeta = cBlockSignPostHandler::RotationToMetaData(a_Player->GetYaw());
|
||||||
a_BlockType = E_BLOCK_SIGN_POST;
|
a_BlockType = E_BLOCK_SIGN_POST;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
a_BlockMeta = cBlockWallSignHandler::DirectionToMetaData(a_BlockFace);
|
a_BlockMeta = cBlockWallSignHandler::BlockFaceToMetaData(a_ClickedBlockFace);
|
||||||
a_BlockType = E_BLOCK_WALLSIGN;
|
a_BlockType = E_BLOCK_WALLSIGN;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue