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);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool GetPlacementBlockTypeMeta(
|
||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
cChunkInterface & a_ChunkInterface,
|
||||
cPlayer & a_Player,
|
||||
const Vector3i a_PlacedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||
) 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;
|
||||
}
|
||||
@ -58,11 +71,19 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool IsUseable() override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
||||
{
|
||||
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);
|
||||
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)
|
||||
{
|
||||
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");
|
||||
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
|
||||
{
|
||||
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(Coords);
|
||||
if ((Meta & 0x4) == 0x4)
|
||||
// Is foot end
|
||||
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 (
|
||||
(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 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_BlockPos, Meta & 0x0b); // Clear the "occupied" bit of the bed's block
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -32,10 +32,30 @@ public:
|
||||
|
||||
|
||||
// Overrides:
|
||||
virtual void OnBroken(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta) override;
|
||||
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 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;
|
||||
virtual void OnBroken(
|
||||
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface,
|
||||
const 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_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
|
||||
{
|
||||
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;
|
||||
}
|
||||
BLOCKTYPE BlockType;
|
||||
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));
|
||||
}
|
||||
@ -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)
|
||||
{
|
||||
|
@ -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(Pos);
|
||||
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockPos);
|
||||
|
||||
Vector3d SoundPos(Pos);
|
||||
|
||||
// If button is already on do nothing
|
||||
// If button is already on, do nothing:
|
||||
if (Meta & 0x08)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set p the ON bit to on
|
||||
// Set the ON bit to on
|
||||
Meta |= 0x08;
|
||||
|
||||
a_ChunkInterface.SetBlockMeta({a_BlockX, a_BlockY, a_BlockZ}, Meta, false);
|
||||
a_WorldInterface.WakeUpSimulators(Pos);
|
||||
a_WorldInterface.GetBroadcastManager().BroadcastSoundEffect("block.stone_button.click_on", SoundPos, 0.5f, 0.6f);
|
||||
a_ChunkInterface.SetBlockMeta(a_BlockPos, Meta, false);
|
||||
a_WorldInterface.WakeUpSimulators(a_BlockPos);
|
||||
a_WorldInterface.GetBroadcastManager().BroadcastSoundEffect("block.stone_button.click_on", a_BlockPos, 0.5f, 0.6f);
|
||||
|
||||
// Queue a button reset (unpress)
|
||||
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
|
||||
a_World.SetBlockMeta(Pos.x, Pos.y, Pos.z, a_World.GetBlockMeta(Pos) & 0x07, false);
|
||||
a_World.WakeUpSimulators(Pos);
|
||||
a_World.BroadcastSoundEffect("block.stone_button.click_off", SoundPos, 0.5f, 0.5f);
|
||||
a_World.SetBlockMeta(a_BlockPos, a_World.GetBlockMeta(a_BlockPos) & 0x07, false);
|
||||
a_World.WakeUpSimulators(a_BlockPos);
|
||||
a_World.BroadcastSoundEffect("block.stone_button.click_off", a_BlockPos, 0.5f, 0.5f);
|
||||
}
|
||||
}
|
||||
);
|
||||
@ -61,23 +65,38 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool IsUseable(void) override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool GetPlacementBlockTypeMeta(
|
||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
cChunkInterface & a_ChunkInterface,
|
||||
cPlayer & a_Player,
|
||||
const Vector3i a_PlacedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||
) override
|
||||
{
|
||||
a_BlockType = m_BlockType;
|
||||
a_BlockMeta = BlockFaceToMetaData(a_BlockFace);
|
||||
a_BlockMeta = BlockFaceToMetaData(a_ClickedBlockFace);
|
||||
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)
|
||||
{
|
||||
switch (a_BlockFace)
|
||||
@ -97,6 +116,11 @@ public:
|
||||
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)
|
||||
{
|
||||
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;
|
||||
a_Chunk.UnboundedRelGetBlockMeta(a_RelX, a_RelY, a_RelZ, Meta);
|
||||
auto Meta = a_Chunk.GetMeta(a_RelPos);
|
||||
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);
|
||||
BLOCKTYPE BlockIsOn; a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ, BlockIsOn);
|
||||
|
||||
return (a_RelY > 0) && (cBlockInfo::FullyOccupiesVoxel(BlockIsOn));
|
||||
return cBlockInfo::FullyOccupiesVoxel(SupportBlockType);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
||||
{
|
||||
UNUSED(a_Meta);
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
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))
|
||||
{
|
||||
// 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
|
||||
static const struct
|
||||
static const Vector3i Coords[] =
|
||||
{
|
||||
int x, z;
|
||||
} Coords[] =
|
||||
{
|
||||
{-1, 0},
|
||||
{ 1, 0},
|
||||
{ 0, -1},
|
||||
{ 0, 1},
|
||||
} ;
|
||||
{-1, 0, 0},
|
||||
{ 1, 0, 0},
|
||||
{ 0, 0, -1},
|
||||
{ 0, 0, 1},
|
||||
};
|
||||
for (size_t i = 0; i < ARRAYCOUNT(Coords); i++)
|
||||
{
|
||||
BLOCKTYPE BlockType;
|
||||
NIBBLETYPE BlockMeta;
|
||||
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) ||
|
||||
(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))
|
||||
{
|
||||
@ -31,11 +38,11 @@ public:
|
||||
|
||||
if (Meta >= 5)
|
||||
{
|
||||
a_ChunkInterface.DigBlock(a_WorldInterface, {a_BlockX, a_BlockY, a_BlockZ});
|
||||
a_ChunkInterface.DigBlock(a_WorldInterface, a_BlockPos);
|
||||
}
|
||||
else
|
||||
{
|
||||
a_ChunkInterface.SetBlockMeta({a_BlockX, a_BlockY, a_BlockZ}, Meta + 1);
|
||||
a_ChunkInterface.SetBlockMeta(a_BlockPos, Meta + 1);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -14,14 +14,14 @@
|
||||
|
||||
|
||||
|
||||
class cBlockCarpetHandler :
|
||||
class cBlockCarpetHandler:
|
||||
public cBlockHandler
|
||||
{
|
||||
using Super = cBlockHandler;
|
||||
|
||||
public:
|
||||
|
||||
cBlockCarpetHandler(BLOCKTYPE a_BlockType) :
|
||||
cBlockCarpetHandler(BLOCKTYPE a_BlockType):
|
||||
Super(a_BlockType)
|
||||
{
|
||||
}
|
||||
@ -31,9 +31,11 @@ public:
|
||||
|
||||
|
||||
virtual bool GetPlacementBlockTypeMeta(
|
||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
cChunkInterface & a_ChunkInterface,
|
||||
cPlayer & a_Player,
|
||||
const Vector3i a_PlacedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||
) 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();
|
||||
switch (EquippedItem.m_ItemType)
|
||||
{
|
||||
@ -42,7 +49,7 @@ public:
|
||||
{
|
||||
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:
|
||||
if (!a_Player.IsGameModeCreative())
|
||||
{
|
||||
@ -55,7 +62,7 @@ public:
|
||||
{
|
||||
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:
|
||||
if (!a_Player.IsGameModeCreative())
|
||||
{
|
||||
@ -68,7 +75,7 @@ public:
|
||||
{
|
||||
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:
|
||||
if (!a_Player.IsGameModeCreative())
|
||||
{
|
||||
@ -82,8 +89,8 @@ public:
|
||||
// Refill cauldron with water bottles.
|
||||
if ((Meta < 3) && (EquippedItem.m_ItemDamage == 0))
|
||||
{
|
||||
a_ChunkInterface.SetBlockMeta(Vector3i(a_BlockX, a_BlockY, a_BlockZ), ++Meta);
|
||||
// Give empty bottle when the gamemode is not creative:
|
||||
a_ChunkInterface.SetBlockMeta(Vector3i(a_BlockPos), ++Meta);
|
||||
// Give back an empty bottle when the gamemode is not creative:
|
||||
if (!a_Player.IsGameModeCreative())
|
||||
{
|
||||
a_Player.ReplaceOneEquippedItemTossRest(cItem(E_ITEM_GLASS_BOTTLE));
|
||||
|
@ -27,14 +27,16 @@ public:
|
||||
|
||||
|
||||
virtual bool GetPlacementBlockTypeMeta(
|
||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
cChunkInterface & a_ChunkInterface,
|
||||
cPlayer & a_Player,
|
||||
const Vector3i a_PlacedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||
) override
|
||||
{
|
||||
// Is there a doublechest already next to this block?
|
||||
if (!CanBeAt(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ))
|
||||
// Cannot place right next to double-chest:
|
||||
if (!CanBeAt(a_ChunkInterface, a_PlacedBlockPos))
|
||||
{
|
||||
// Yup, cannot form a triple-chest, refuse:
|
||||
return false;
|
||||
@ -42,13 +44,13 @@ public:
|
||||
|
||||
// Try to read double-chest information:
|
||||
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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
@ -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;
|
||||
int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width;
|
||||
return CanBeAt(a_ChunkInterface, BlockX, a_RelY, BlockZ);
|
||||
auto BlockPos = a_Chunk.RelativeToAbsolute(a_RelPos);
|
||||
return CanBeAt(a_ChunkInterface, BlockPos);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
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;
|
||||
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.
|
||||
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));
|
||||
AddFaceDirection(a_RelX, a_RelY, a_RelZ, BlockFace, true);
|
||||
|
||||
// Check that we're attached to a jungle log block:
|
||||
eBlockFace BlockFace = MetaToBlockFace(a_Chunk.GetMeta(a_RelPos));
|
||||
auto LogPos = AddFaceDirection(a_RelPos, BlockFace, true);
|
||||
BLOCKTYPE BlockType;
|
||||
NIBBLETYPE BlockMeta;
|
||||
a_Chunk.UnboundedRelGetBlock(a_RelX, a_RelY, a_RelZ, BlockType, BlockMeta);
|
||||
|
||||
return ((BlockType == E_BLOCK_LOG) && ((BlockMeta & 0x3) == E_META_LOG_JUNGLE));
|
||||
a_Chunk.UnboundedRelGetBlock(LogPos, BlockType, BlockMeta);
|
||||
return ((BlockType == E_BLOCK_LOG) && ((BlockMeta & 0x03) == 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});
|
||||
Meta ^= 0x04; // Toggle 3rd (addition / subtraction) bit with XOR
|
||||
a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta);
|
||||
// Toggle the 3rd bit (addition / subtraction):
|
||||
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockPos);
|
||||
Meta ^= 0x04;
|
||||
a_ChunkInterface.SetBlockMeta(a_BlockPos, Meta);
|
||||
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);
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
return cItem(E_ITEM_COMPARATOR, 1, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
inline static bool IsInSubtractionMode(NIBBLETYPE a_Meta)
|
||||
{
|
||||
return ((a_Meta & 0x4) == 0x4);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
inline static bool IsOn(NIBBLETYPE a_Meta)
|
||||
{
|
||||
return ((a_Meta & 0x8) == 0x8);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
inline static Vector3i GetSideCoordinate(Vector3i a_Position, NIBBLETYPE a_Meta, bool a_bInverse)
|
||||
{
|
||||
if (!a_bInverse)
|
||||
@ -98,6 +167,10 @@ public:
|
||||
return a_Position;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
inline static Vector3i GetRearCoordinate(Vector3i a_Position, NIBBLETYPE a_Meta)
|
||||
{
|
||||
switch (a_Meta)
|
||||
@ -117,6 +190,10 @@ public:
|
||||
return a_Position;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
inline static Vector3i GetFrontCoordinate(Vector3i a_Position, NIBBLETYPE a_Meta)
|
||||
{
|
||||
switch (a_Meta)
|
||||
@ -136,6 +213,10 @@ public:
|
||||
return a_Position;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
||||
{
|
||||
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
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
BLOCKTYPE BelowBlock = a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ);
|
||||
BLOCKTYPE BelowBlock = a_Chunk.GetBlock(a_RelPos.addedY(-1));
|
||||
switch (BelowBlock)
|
||||
{
|
||||
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_BlockFace);
|
||||
UNUSED(a_CursorX);
|
||||
UNUSED(a_CursorY);
|
||||
UNUSED(a_CursorZ);
|
||||
UNUSED(a_CursorPos);
|
||||
|
||||
switch (a_ChunkInterface.GetBlock({a_BlockX, a_BlockY, a_BlockZ}))
|
||||
switch (a_ChunkInterface.GetBlock(a_BlockPos))
|
||||
{
|
||||
default:
|
||||
{
|
||||
@ -61,14 +66,14 @@ bool cBlockDoorHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterfac
|
||||
case E_BLOCK_SPRUCE_DOOR:
|
||||
case E_BLOCK_OAK_DOOR:
|
||||
{
|
||||
ChangeDoor(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ);
|
||||
a_Player.GetWorld()->BroadcastSoundParticleEffect(EffectID::SFX_RANDOM_WOODEN_DOOR_OPEN, {a_BlockX, a_BlockY, a_BlockZ}, 0, a_Player.GetClientHandle());
|
||||
ChangeDoor(a_ChunkInterface, a_BlockPos);
|
||||
a_Player.GetWorld()->BroadcastSoundParticleEffect(EffectID::SFX_RANDOM_WOODEN_DOOR_OPEN, a_BlockPos, 0, a_Player.GetClientHandle());
|
||||
break;
|
||||
}
|
||||
// Prevent iron door from opening on player click
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -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_BlockFace);
|
||||
|
||||
a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
|
||||
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta({a_BlockX, a_BlockY, a_BlockZ});
|
||||
a_WorldInterface.SendBlockTo(a_BlockPos, a_Player);
|
||||
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockPos);
|
||||
|
||||
if (Meta & 0x8)
|
||||
if (Meta & 0x08)
|
||||
{
|
||||
// Current block is top of the door
|
||||
a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY - 1, a_BlockZ, a_Player);
|
||||
// Current block is top of the door, send the bottom part:
|
||||
a_WorldInterface.SendBlockTo(a_BlockPos.addedY(-1), a_Player);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Current block is bottom of the door
|
||||
a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY + 1, a_BlockZ, a_Player);
|
||||
// Current block is bottom of the door, send the top part:
|
||||
a_WorldInterface.SendBlockTo(a_BlockPos.addedY(1), a_Player);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,37 +20,63 @@ public:
|
||||
|
||||
cBlockDoorHandler(BLOCKTYPE a_BlockType);
|
||||
|
||||
virtual void OnBroken(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta) override;
|
||||
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 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 OnBroken(
|
||||
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface,
|
||||
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 MetaRotateCW(NIBBLETYPE a_Meta) override;
|
||||
virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override;
|
||||
virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool GetPlacementBlockTypeMeta(
|
||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
cChunkInterface & a_ChunkInterface,
|
||||
cPlayer & a_Player,
|
||||
const Vector3i a_PlacedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||
) override
|
||||
{
|
||||
// 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 (
|
||||
!CanReplaceBlock(a_ChunkInterface.GetBlock({a_BlockX, a_BlockY, a_BlockZ})) ||
|
||||
!CanReplaceBlock(a_ChunkInterface.GetBlock({a_BlockX, a_BlockY + 1, a_BlockZ}))
|
||||
!CanReplaceBlock(a_ChunkInterface.GetBlock(PlacedPos)) ||
|
||||
!CanReplaceBlock(a_ChunkInterface.GetBlock(PlacedPos.addedY(1)))
|
||||
)
|
||||
{
|
||||
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;
|
||||
@ -93,11 +119,19 @@ public:
|
||||
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. */
|
||||
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.
|
||||
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);
|
||||
}
|
||||
|
||||
@ -201,17 +235,17 @@ public:
|
||||
/** Returns the complete meta composed from the both parts of the door as (TopMeta << 4) | BottomMeta
|
||||
The coords may point to either part of the door.
|
||||
The returned value has bit 3 (0x08) set iff the coords point to the top part of the door.
|
||||
Fails gracefully for (invalid) doors on the world's top and bottom. */
|
||||
static NIBBLETYPE GetCompleteDoorMeta(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||
Fails silently for (invalid) doors on the world's top and bottom. */
|
||||
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)
|
||||
{
|
||||
// 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));
|
||||
}
|
||||
// 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
|
||||
{
|
||||
// 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));
|
||||
}
|
||||
// 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. */
|
||||
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))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
NIBBLETYPE Meta = GetCompleteDoorMeta(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ);
|
||||
NIBBLETYPE Meta = GetCompleteDoorMeta(a_ChunkInterface, a_BlockPos);
|
||||
bool IsOpened = ((Meta & 0x04) != 0);
|
||||
if (IsOpened == a_Open)
|
||||
{
|
||||
@ -255,14 +289,14 @@ public:
|
||||
if ((Meta & 0x08) == 0)
|
||||
{
|
||||
// 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
|
||||
{
|
||||
// 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 */
|
||||
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
|
||||
{
|
||||
using Super = cBlockHandler;
|
||||
|
||||
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);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool IsUseable(void) override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
||||
{
|
||||
UNUSED(a_Meta);
|
||||
|
@ -7,22 +7,26 @@
|
||||
|
||||
|
||||
|
||||
class cBlockEndPortalFrameHandler :
|
||||
class cBlockEndPortalFrameHandler:
|
||||
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_XP,
|
||||
E_META_END_PORTAL_FRAME_ZP,
|
||||
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(
|
||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
cChunkInterface & a_ChunkInterface,
|
||||
cPlayer & a_Player,
|
||||
const Vector3i a_PlacedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||
) 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
|
||||
{
|
||||
using Super = cBlockHandler;
|
||||
|
||||
public:
|
||||
|
||||
// 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 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 MAX_COORD = 0.6;
|
||||
|
||||
cBlockFenceHandler(BLOCKTYPE a_BlockType)
|
||||
: cBlockHandler(a_BlockType)
|
||||
cBlockFenceHandler(BLOCKTYPE 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
|
||||
{
|
||||
bool XMSolid = cBlockInfo::IsSolid(a_XM);
|
||||
@ -76,9 +83,20 @@ public:
|
||||
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);
|
||||
|
||||
if (KnotAlreadyExists)
|
||||
@ -89,7 +107,7 @@ public:
|
||||
// New knot? needs to init and produce sound effect
|
||||
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();
|
||||
|
||||
NewLeashKnotPtr->TiePlayersLeashedMobs(a_Player, KnotAlreadyExists);
|
||||
@ -112,11 +130,25 @@ public:
|
||||
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
|
||||
{
|
||||
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());
|
||||
OldMetaData ^= 4; // Toggle the gate
|
||||
|
||||
if ((OldMetaData & 1) == (NewMetaData & 1))
|
||||
{
|
||||
// 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
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
||||
{
|
||||
UNUSED(a_Meta);
|
||||
|
@ -7,12 +7,15 @@
|
||||
|
||||
|
||||
|
||||
class cBlockFlowerHandler :
|
||||
class cBlockFlowerHandler:
|
||||
public cBlockHandler
|
||||
{
|
||||
using Super = cBlockHandler;
|
||||
|
||||
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
|
||||
{
|
||||
UNUSED(a_Meta);
|
||||
|
@ -90,30 +90,31 @@ public:
|
||||
// Y Coord out of range
|
||||
continue;
|
||||
}
|
||||
auto chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(Pos);
|
||||
if (chunk == nullptr)
|
||||
auto Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(Pos);
|
||||
if (Chunk == nullptr)
|
||||
{
|
||||
// Unloaded chunk
|
||||
continue;
|
||||
}
|
||||
chunk->GetBlockTypeMeta(Pos, DestBlock, DestMeta);
|
||||
Chunk->GetBlockTypeMeta(Pos, DestBlock, DestMeta);
|
||||
if ((DestBlock != E_BLOCK_DIRT) || (DestMeta != E_META_DIRT_NORMAL))
|
||||
{
|
||||
// Not a regular dirt block
|
||||
continue;
|
||||
}
|
||||
BLOCKTYPE Above = chunk->GetBlock(AbovePos);
|
||||
NIBBLETYPE light = std::max(chunk->GetBlockLight(AbovePos), chunk->GetTimeAlteredLight(chunk->GetSkyLight(AbovePos)));
|
||||
if ((light > 4) &&
|
||||
cBlockInfo::IsTransparent(Above) &&
|
||||
(!IsBlockLava(Above)) &&
|
||||
(!IsBlockWaterOrIce(Above))
|
||||
auto AboveDestPos = Pos.addedY(1);
|
||||
auto AboveBlockType = Chunk->GetBlock(AboveDestPos);
|
||||
auto Light = std::max(Chunk->GetBlockLight(AboveDestPos), Chunk->GetTimeAlteredLight(Chunk->GetSkyLight(AboveDestPos)));
|
||||
if ((Light > 4) &&
|
||||
cBlockInfo::IsTransparent(AboveBlockType) &&
|
||||
(!IsBlockLava(AboveBlockType)) &&
|
||||
(!IsBlockWaterOrIce(AboveBlockType))
|
||||
)
|
||||
{
|
||||
auto absPos = chunk->RelativeToAbsolute(Pos);
|
||||
if (!cRoot::Get()->GetPluginManager()->CallHookBlockSpread(*chunk->GetWorld(), absPos.x, absPos.y, absPos.z, ssGrassSpread))
|
||||
auto AbsPos = Chunk->RelativeToAbsolute(Pos);
|
||||
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
|
||||
|
@ -406,8 +406,9 @@ cBlockHandler::cBlockHandler(BLOCKTYPE a_BlockType)
|
||||
|
||||
bool cBlockHandler::GetPlacementBlockTypeMeta(
|
||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
const Vector3i a_ClickedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
@ -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(Vector3d a_Position, const BLOCKTYPE a_BlockType, const NIBBLETYPE a_BlockMeta)
|
||||
bool cBlockHandler::IsInsideBlock(const Vector3d a_RelPosition, 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
|
||||
)
|
||||
{
|
||||
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())
|
||||
{
|
||||
|
@ -44,19 +44,28 @@ public:
|
||||
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);
|
||||
|
||||
/** 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.
|
||||
Also, the handler should set a_BlockType and a_BlockMeta to correct values for the newly placed block.
|
||||
Called by cItemHandler::GetPlacementBlockTypeMeta() if the item is a block */
|
||||
a_PlacedBlockPos is the coords of the block being placed
|
||||
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(
|
||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
cChunkInterface & a_ChunkInterface,
|
||||
cPlayer & a_Player,
|
||||
const Vector3i a_PlacedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||
);
|
||||
|
||||
/** 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(). */
|
||||
virtual void OnPlacedByPlayer(
|
||||
@ -118,18 +127,37 @@ public:
|
||||
cChunkInterface & a_ChunkInterface,
|
||||
cWorldInterface & a_WorldInterface,
|
||||
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
|
||||
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, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) { return false; }
|
||||
/** Called when the user right clicks the block and the block is useable.
|
||||
a_CursorPos is the cursor position within the clicked block face.
|
||||
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.
|
||||
It forces the server to send the real state of a block to the client to prevent client assuming the operation is 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) {}
|
||||
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,
|
||||
const Vector3i a_BlockPos,
|
||||
eBlockFace a_BlockFace
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
/** 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.
|
||||
@ -145,41 +173,37 @@ public:
|
||||
);
|
||||
|
||||
/** Checks if the block can stay at the specified relative coords in the chunk */
|
||||
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk);
|
||||
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 */
|
||||
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.
|
||||
If it returns true, OnUse() is called */
|
||||
virtual bool IsUseable(void);
|
||||
|
||||
/** 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);
|
||||
|
||||
/** 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
|
||||
@param a_Pos Position of the block
|
||||
@param a_Player Player trying to build on the block
|
||||
@param a_Meta Meta value of the block currently at a_Pos
|
||||
*/
|
||||
virtual bool DoesIgnoreBuildCollision(cChunkInterface & ChunkInterface, Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta);
|
||||
@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);
|
||||
|
||||
/** Returns if this block drops if it gets destroyed by an unsuitable situation.
|
||||
Default: true */
|
||||
virtual bool DoesDropOnUnsuitable(void);
|
||||
|
||||
/** Tests if a_Position is inside the block where a_Position 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 */
|
||||
virtual bool IsInsideBlock(Vector3d a_Position, const BLOCKTYPE a_BlockType, const NIBBLETYPE a_BlockMeta);
|
||||
/** Tests if a_RelPosition is inside the block, where a_RelPosition is relative to the origin of the block.
|
||||
Coords in a_RelPosition are guaranteed to be in the [0..1] range. */
|
||||
virtual bool IsInsideBlock(const Vector3d a_RelPosition, const NIBBLETYPE a_BlockMeta);
|
||||
|
||||
/** 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()),
|
||||
|
@ -24,16 +24,18 @@ public:
|
||||
|
||||
|
||||
virtual bool GetPlacementBlockTypeMeta(
|
||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
cChunkInterface & a_ChunkInterface,
|
||||
cPlayer & a_Player,
|
||||
const Vector3i a_PlacedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||
) override
|
||||
{
|
||||
a_BlockType = m_BlockType;
|
||||
|
||||
// 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_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> >
|
||||
{
|
||||
using Super = cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x07, 0x02, 0x05, 0x03, 0x04>>;
|
||||
@ -25,24 +25,26 @@ public:
|
||||
|
||||
|
||||
virtual bool GetPlacementBlockTypeMeta(
|
||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
cChunkInterface & a_ChunkInterface,
|
||||
cPlayer & a_Player,
|
||||
const Vector3i a_PlacedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||
) 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);
|
||||
|
||||
if (a_BlockFace == BLOCK_FACE_BOTTOM)
|
||||
a_ClickedBlockFace = FindSuitableBlockFace(a_ChunkInterface, a_PlacedBlockPos);
|
||||
if (a_ClickedBlockFace == BLOCK_FACE_NONE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
a_BlockType = m_BlockType;
|
||||
a_BlockMeta = DirectionToMetaData(a_BlockFace);
|
||||
a_BlockMeta = BlockFaceToMetaData(a_ClickedBlockFace);
|
||||
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_ZP: return 0x3;
|
||||
@ -65,14 +68,15 @@ public:
|
||||
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)
|
||||
{
|
||||
@ -88,47 +92,51 @@ public:
|
||||
|
||||
|
||||
|
||||
/** Finds a suitable Direction for the Ladder. Returns BLOCK_FACE_BOTTOM on failure */
|
||||
static eBlockFace FindSuitableBlockFace(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||
/** Finds a suitable block face value for the Ladder.
|
||||
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++)
|
||||
{
|
||||
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 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;
|
||||
}
|
||||
|
||||
AddFaceDirection( a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, true);
|
||||
|
||||
return cBlockInfo::IsSolid(a_ChunkInterface.GetBlock({a_BlockX, a_BlockY, a_BlockZ}));
|
||||
auto NeighborPos = AddFaceDirection(a_LadderPos, a_NeighborBlockFace, true);
|
||||
return cBlockInfo::IsSolid(a_ChunkInterface.GetBlock(NeighborPos));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
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
|
||||
eBlockFace BlockFace = MetaDataToDirection(a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ));
|
||||
int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width;
|
||||
int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width;
|
||||
return LadderCanBePlacedAt(a_ChunkInterface, BlockX, a_RelY, BlockZ, BlockFace);
|
||||
auto NeighborBlockFace = MetaDataToBlockFace(a_Chunk.GetMeta(a_RelPos));
|
||||
auto LadderAbsPos = a_Chunk.RelativeToAbsolute(a_RelPos);
|
||||
return LadderCanBePlacedAt(a_ChunkInterface, LadderAbsPos, NeighborBlockFace);
|
||||
}
|
||||
|
||||
|
||||
|
@ -6,14 +6,14 @@
|
||||
#include "BlockSlab.h"
|
||||
|
||||
|
||||
class cBlockLeverHandler :
|
||||
class cBlockLeverHandler:
|
||||
public cMetaRotator<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, false>
|
||||
{
|
||||
using Super = cMetaRotator<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, false>;
|
||||
|
||||
public:
|
||||
|
||||
cBlockLeverHandler(BLOCKTYPE a_BlockType) :
|
||||
cBlockLeverHandler(BLOCKTYPE 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
|
||||
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_WorldInterface.WakeUpSimulators(Coords);
|
||||
a_WorldInterface.GetBroadcastManager().BroadcastSoundEffect("block.lever.click", Vector3d(Coords), 0.5f, (Meta & 0x08) ? 0.6f : 0.5f);
|
||||
a_ChunkInterface.SetBlockMeta(a_BlockPos, Meta);
|
||||
a_WorldInterface.WakeUpSimulators(a_BlockPos);
|
||||
a_WorldInterface.GetBroadcastManager().BroadcastSoundEffect("block.lever.click", a_BlockPos, 0.5f, (Meta & 0x08) ? 0.6f : 0.5f);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -58,14 +64,16 @@ public:
|
||||
|
||||
|
||||
virtual bool GetPlacementBlockTypeMeta(
|
||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
cChunkInterface & a_ChunkInterface,
|
||||
cPlayer & a_Player,
|
||||
const Vector3i a_PlacedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||
) override
|
||||
{
|
||||
a_BlockType = m_BlockType;
|
||||
a_BlockMeta = LeverDirectionToMetaData(a_BlockFace);
|
||||
a_BlockMeta = LeverDirectionToMetaData(a_ClickedBlockFace);
|
||||
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)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
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);
|
||||
|
||||
eBlockFace Face = BlockMetaDataToBlockFace(Meta);
|
||||
|
||||
AddFaceDirection(a_RelX, a_RelY, a_RelZ, Face, true);
|
||||
|
||||
if ((a_RelY < 0) || (a_RelY >= cChunkDef::Height -1))
|
||||
// Find the type of block the lever is attached to:
|
||||
auto Meta = a_Chunk.GetMeta(a_RelPos);
|
||||
auto NeighborFace = BlockMetaDataToBlockFace(Meta);
|
||||
auto NeighborPos = AddFaceDirection(a_RelPos, NeighborFace, true);
|
||||
if (!cChunkDef::IsValidHeight(NeighborPos.y))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
BLOCKTYPE NeighborBlockType;
|
||||
if (!a_Chunk.UnboundedRelGetBlock(NeighborPos, NeighborBlockType, Meta))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
BLOCKTYPE BlockIsOn;
|
||||
a_Chunk.UnboundedRelGetBlock(a_RelX, a_RelY, a_RelZ, BlockIsOn, Meta);
|
||||
|
||||
|
||||
if (cBlockInfo::FullyOccupiesVoxel(BlockIsOn))
|
||||
// Allow any full block or the "good" side of a half-slab:
|
||||
if (cBlockInfo::FullyOccupiesVoxel(NeighborBlockType))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (cBlockSlabHandler::IsAnySlabType(BlockIsOn))
|
||||
else if (cBlockSlabHandler::IsAnySlabType(NeighborBlockType))
|
||||
{
|
||||
// Check if the slab is turned up side down
|
||||
if (((Meta & 0x08) == 0x08) && (Face == BLOCK_FACE_TOP))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return (
|
||||
(((Meta & 0x08) == 0x08) && (NeighborFace == BLOCK_FACE_TOP)) ||
|
||||
(((Meta & 0x08) == 0) && (NeighborFace == BLOCK_FACE_BOTTOM))
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -19,6 +19,10 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
||||
{
|
||||
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;
|
||||
}
|
||||
BLOCKTYPE UnderType;
|
||||
NIBBLETYPE UnderMeta;
|
||||
a_Chunk.GetBlockTypeMeta(a_RelX, a_RelY - 1, a_RelZ, UnderType, UnderMeta);
|
||||
a_Chunk.GetBlockTypeMeta(UnderPos, UnderType, UnderMeta);
|
||||
return (
|
||||
(((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
|
||||
|
@ -8,22 +8,38 @@
|
||||
|
||||
|
||||
|
||||
class cBlockMobSpawnerHandler :
|
||||
class cBlockMobSpawnerHandler:
|
||||
public cBlockHandler
|
||||
{
|
||||
using Super = cBlockHandler;
|
||||
|
||||
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
|
||||
{
|
||||
return true;
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
|
||||
|
||||
/** Handler for the small (singleblock) mushrooms. */
|
||||
class cBlockMushroomHandler:
|
||||
public cClearMetaOnDrop<cBlockHandler>
|
||||
{
|
||||
@ -19,18 +20,26 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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_CACTUS:
|
||||
@ -45,6 +54,10 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
||||
{
|
||||
UNUSED(a_Meta);
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
|
||||
|
||||
class cBlockNetherWartHandler :
|
||||
class cBlockNetherWartHandler:
|
||||
public 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:
|
||||
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:
|
||||
cBlockPlanksHandler(BLOCKTYPE a_BlockType)
|
||||
: cBlockHandler(a_BlockType)
|
||||
|
||||
cBlockPlanksHandler(BLOCKTYPE a_BlockType):
|
||||
Super(a_BlockType)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool GetPlacementBlockTypeMeta(
|
||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
cChunkInterface & a_ChunkInterface,
|
||||
cPlayer & a_Player,
|
||||
const Vector3i a_PlacedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||
) override
|
||||
{
|
||||
@ -27,6 +37,10 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
||||
{
|
||||
switch (a_Meta)
|
||||
|
@ -7,25 +7,33 @@
|
||||
|
||||
|
||||
|
||||
class cBlockPortalHandler :
|
||||
class cBlockPortalHandler:
|
||||
public cBlockHandler
|
||||
{
|
||||
using Super = cBlockHandler;
|
||||
public:
|
||||
cBlockPortalHandler(BLOCKTYPE a_BlockType)
|
||||
: cBlockHandler(a_BlockType)
|
||||
|
||||
cBlockPortalHandler(BLOCKTYPE a_BlockType):
|
||||
Super(a_BlockType)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool GetPlacementBlockTypeMeta(
|
||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
cChunkInterface & a_ChunkInterface,
|
||||
cPlayer & a_Player,
|
||||
const Vector3i a_PlacedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||
) 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
|
||||
// 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_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
|
||||
}
|
||||
|
||||
switch (a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ))
|
||||
switch (a_Chunk.GetMeta(a_RelPos))
|
||||
{
|
||||
case 0x1:
|
||||
{
|
||||
@ -91,8 +99,7 @@ public:
|
||||
for (const auto & Direction : PortalCheck)
|
||||
{
|
||||
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))
|
||||
{
|
||||
return false;
|
||||
@ -115,8 +122,7 @@ public:
|
||||
for (const auto & Direction : PortalCheck)
|
||||
{
|
||||
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))
|
||||
{
|
||||
return false;
|
||||
@ -128,6 +134,10 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
case E_BLOCK_ACACIA_FENCE:
|
||||
@ -47,6 +51,10 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
||||
{
|
||||
UNUSED(a_Meta);
|
||||
|
@ -7,42 +7,57 @@
|
||||
|
||||
|
||||
|
||||
class cBlockQuartzHandler : public cBlockHandler
|
||||
class cBlockQuartzHandler:
|
||||
public cBlockHandler
|
||||
{
|
||||
using Super = cBlockHandler;
|
||||
|
||||
public:
|
||||
cBlockQuartzHandler(BLOCKTYPE a_BlockType)
|
||||
: cBlockHandler(a_BlockType)
|
||||
|
||||
cBlockQuartzHandler(BLOCKTYPE a_BlockType):
|
||||
Super(a_BlockType)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool GetPlacementBlockTypeMeta(
|
||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
cChunkInterface & a_ChunkInterface,
|
||||
cPlayer & a_Player,
|
||||
const Vector3i a_PlacedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||
) override
|
||||
{
|
||||
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;
|
||||
return true;
|
||||
}
|
||||
|
||||
a_BlockMeta = BlockFaceToMetaData(a_BlockFace, Meta);
|
||||
a_BlockMeta = BlockFaceToMetaData(a_ClickedBlockFace);
|
||||
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)
|
||||
{
|
||||
case BLOCK_FACE_YM:
|
||||
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:
|
||||
@ -57,15 +72,17 @@ public:
|
||||
return 0x3; // East or west
|
||||
}
|
||||
|
||||
case BLOCK_FACE_NONE:
|
||||
default:
|
||||
{
|
||||
ASSERT(!"Unhandled block face!");
|
||||
return a_QuartzMeta; // No idea, give a special meta (all sides the same)
|
||||
return E_META_QUARTZ_PILLAR;
|
||||
}
|
||||
}
|
||||
UNREACHABLE("Unsupported block face");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
||||
{
|
||||
UNUSED(a_Meta);
|
||||
|
@ -28,21 +28,26 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool GetPlacementBlockTypeMeta(
|
||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
cChunkInterface & a_ChunkInterface,
|
||||
cPlayer & a_Player,
|
||||
const Vector3i a_PlacedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||
) override
|
||||
{
|
||||
a_BlockType = m_BlockType;
|
||||
Vector3i Pos{ a_BlockX, a_BlockY, a_BlockZ };
|
||||
a_BlockMeta = FindMeta(a_ChunkInterface, Pos);
|
||||
return a_Player.GetWorld()->DoWithChunkAt(Pos,
|
||||
[this, Pos, &a_ChunkInterface](cChunk & a_Chunk)
|
||||
a_BlockMeta = FindMeta(a_ChunkInterface, a_PlacedBlockPos);
|
||||
return a_Player.GetWorld()->DoWithChunkAt(a_PlacedBlockPos,
|
||||
[this, a_PlacedBlockPos, &a_ChunkInterface](cChunk & a_Chunk)
|
||||
{
|
||||
auto RelPos = cChunkDef::AbsoluteToRelative(Pos);
|
||||
return CanBeAt(a_ChunkInterface, RelPos.x, RelPos.y, RelPos.z, a_Chunk);
|
||||
auto RelPos = cChunkDef::AbsoluteToRelative(a_PlacedBlockPos);
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ);
|
||||
NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelPos);
|
||||
switch (Meta)
|
||||
{
|
||||
case E_META_RAIL_ASCEND_XP:
|
||||
@ -132,19 +137,16 @@ public:
|
||||
{
|
||||
// Mapping between the meta and the neighbors that need checking
|
||||
Meta -= E_META_RAIL_ASCEND_XP; // Base index at zero
|
||||
static const struct
|
||||
static const Vector3i Coords[] =
|
||||
{
|
||||
int x, z;
|
||||
} Coords[] =
|
||||
{
|
||||
{ 1, 0}, // east, XP
|
||||
{-1, 0}, // west, XM
|
||||
{ 0, -1}, // north, ZM
|
||||
{ 0, 1}, // south, ZP
|
||||
{ 1, 0, 0}, // east, XP
|
||||
{-1, 0, 0}, // west, XM
|
||||
{ 0, 0, -1}, // north, ZM
|
||||
{ 0, 0, 1}, // south, ZP
|
||||
} ;
|
||||
BLOCKTYPE BlockType;
|
||||
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
|
||||
return true;
|
||||
@ -155,6 +157,10 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
NIBBLETYPE FindMeta(cChunkInterface & a_ChunkInterface, Vector3i a_BlockPos)
|
||||
{
|
||||
NIBBLETYPE Meta = 0;
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
|
||||
|
||||
class cBlockRedstoneHandler :
|
||||
class cBlockRedstoneHandler:
|
||||
public 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;
|
||||
}
|
||||
|
||||
BLOCKTYPE BelowBlock;
|
||||
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))
|
||||
{
|
||||
@ -46,11 +50,19 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
||||
{
|
||||
UNUSED(a_Meta);
|
||||
|
@ -17,31 +17,39 @@ public:
|
||||
|
||||
using Super::Super; // Inherit constructor from base
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool OnUse(
|
||||
cChunkInterface & a_ChunkInterface,
|
||||
cWorldInterface & a_WorldInterface,
|
||||
cPlayer & a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ,
|
||||
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player,
|
||||
const Vector3i a_BlockPos,
|
||||
eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ
|
||||
const Vector3i a_CursorPos
|
||||
) override
|
||||
{
|
||||
Vector3i BlockPos{a_BlockX, a_BlockY, a_BlockZ};
|
||||
a_ChunkInterface.SetBlock(BlockPos, E_BLOCK_REDSTONE_ORE_GLOWING, 0);
|
||||
a_ChunkInterface.SetBlock(a_BlockPos, E_BLOCK_REDSTONE_ORE_GLOWING, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual void OnDigging(
|
||||
cChunkInterface & a_ChunkInterface,
|
||||
cWorldInterface & a_WorldInterface,
|
||||
cPlayer & a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ
|
||||
const Vector3i a_BlockPos
|
||||
) override
|
||||
{
|
||||
Vector3i BlockPos{a_BlockX, a_BlockY, a_BlockZ};
|
||||
a_ChunkInterface.SetBlock(BlockPos, E_BLOCK_REDSTONE_ORE_GLOWING, 0);
|
||||
a_ChunkInterface.SetBlock(a_BlockPos, E_BLOCK_REDSTONE_ORE_GLOWING, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool IsUseable() override
|
||||
{
|
||||
return true;
|
||||
@ -61,6 +69,10 @@ public:
|
||||
|
||||
using Super::Super; // Inherit constructor from base
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual void OnUpdate(
|
||||
cChunkInterface & a_ChunkInterface,
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
|
||||
a_WorldInterface.SendBlockTo(a_BlockPos, a_Player);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool IsUseable(void) override
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
BLOCKTYPE BelowBlock;
|
||||
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))
|
||||
{
|
||||
@ -66,17 +96,29 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
||||
{
|
||||
UNUSED(a_Meta);
|
||||
return 11;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
inline static Vector3i GetLeftCoordinateOffset(NIBBLETYPE a_Meta)
|
||||
{
|
||||
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)
|
||||
{
|
||||
return -GetRearCoordinateOffset(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
|
||||
|
@ -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(
|
||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
cChunkInterface & a_ChunkInterface,
|
||||
cPlayer & a_Player,
|
||||
const Vector3i a_PlacedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||
) override
|
||||
{
|
||||
a_BlockType = m_BlockType;
|
||||
NIBBLETYPE Meta = static_cast<NIBBLETYPE>(a_Player.GetEquippedItem().m_ItemDamage);
|
||||
a_BlockMeta = BlockFaceToMetaData(a_BlockFace, Meta);
|
||||
a_BlockMeta = BlockFaceToMetaData(a_ClickedBlockFace, Meta);
|
||||
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;
|
||||
}
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Converts the (player) rotation to placed-signpost block meta. */
|
||||
static NIBBLETYPE RotationToMetaData(double a_Rotation)
|
||||
{
|
||||
a_Rotation += 180 + (180 / 16); // So it's not aligned with axis
|
||||
@ -56,16 +60,28 @@ public:
|
||||
return (static_cast<char>(a_Rotation)) % 16;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override
|
||||
{
|
||||
return (a_Meta + 4) & 0x0f;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override
|
||||
{
|
||||
return (a_Meta + 12) & 0x0f;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override
|
||||
{
|
||||
// Mirrors signs over the XY plane (North-South Mirroring)
|
||||
@ -75,6 +91,10 @@ public:
|
||||
return (a_Meta < 0x08) ? (0x08 - a_Meta) : (0x18 - a_Meta);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override
|
||||
{
|
||||
// Mirrors signs over the YZ plane (East-West Mirroring)
|
||||
@ -84,6 +104,10 @@ public:
|
||||
return 0x0f - a_Meta;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
||||
{
|
||||
UNUSED(a_Meta);
|
||||
|
@ -44,9 +44,11 @@ public:
|
||||
|
||||
|
||||
virtual bool GetPlacementBlockTypeMeta(
|
||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
cChunkInterface & a_ChunkInterface,
|
||||
cPlayer & a_Player,
|
||||
const Vector3i a_PlacedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||
) override
|
||||
{
|
||||
@ -54,18 +56,18 @@ public:
|
||||
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)
|
||||
switch (a_BlockFace)
|
||||
switch (a_ClickedBlockFace)
|
||||
{
|
||||
case BLOCK_FACE_TOP:
|
||||
{
|
||||
// Bottom half slab block
|
||||
a_BlockMeta = Meta & 0x7;
|
||||
a_BlockMeta = Meta & 0x07;
|
||||
break;
|
||||
}
|
||||
case BLOCK_FACE_BOTTOM:
|
||||
{
|
||||
// Top half slab block
|
||||
a_BlockMeta = Meta | 0x8;
|
||||
a_BlockMeta = Meta | 0x08;
|
||||
break;
|
||||
}
|
||||
case BLOCK_FACE_EAST:
|
||||
@ -73,15 +75,15 @@ public:
|
||||
case BLOCK_FACE_SOUTH:
|
||||
case BLOCK_FACE_WEST:
|
||||
{
|
||||
if (a_CursorY > 7)
|
||||
if (a_CursorPos.y > 7)
|
||||
{
|
||||
// Cursor at top half of block, place top slab
|
||||
a_BlockMeta = Meta | 0x8; break;
|
||||
a_BlockMeta = Meta | 0x08; break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 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;
|
||||
@ -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
|
||||
// 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_BlockMeta = a_BlockMeta & 0x7;
|
||||
a_BlockMeta = a_BlockMeta & 0x07;
|
||||
}
|
||||
|
||||
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)))
|
||||
{
|
||||
@ -125,7 +133,7 @@ public:
|
||||
}
|
||||
|
||||
// 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 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
|
||||
{
|
||||
using Super = cBlockHandler;
|
||||
|
@ -10,30 +10,40 @@
|
||||
class cBlockSnowHandler :
|
||||
public cBlockHandler
|
||||
{
|
||||
using Super = cBlockHandler;
|
||||
|
||||
public:
|
||||
|
||||
enum
|
||||
{
|
||||
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(
|
||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
cChunkInterface & a_ChunkInterface,
|
||||
cPlayer & a_Player,
|
||||
const Vector3i a_PlacedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||
) override
|
||||
{
|
||||
a_BlockType = m_BlockType;
|
||||
|
||||
// Check if incrementing existing snow height:
|
||||
BLOCKTYPE BlockBeforePlacement;
|
||||
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))
|
||||
{
|
||||
// Only increment if:
|
||||
@ -45,16 +55,19 @@ public:
|
||||
|
||||
// First time placement, check placement is valid
|
||||
a_BlockMeta = 0;
|
||||
|
||||
BLOCKTYPE BlockBelow;
|
||||
NIBBLETYPE MetaBelow;
|
||||
return (
|
||||
(a_BlockY > 0) &&
|
||||
a_ChunkInterface.GetBlockTypeMeta({a_BlockX, a_BlockY - 1, a_BlockZ}, BlockBelow, MetaBelow) &&
|
||||
(a_PlacedBlockPos.y > 0) &&
|
||||
a_ChunkInterface.GetBlockTypeMeta(a_PlacedBlockPos.addedY(-1), BlockBelow, MetaBelow) &&
|
||||
CanBeOn(BlockBelow, MetaBelow)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
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))
|
||||
@ -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);
|
||||
NIBBLETYPE MetaBelow = a_Chunk.GetMeta(a_RelX, a_RelY - 1, a_RelZ);
|
||||
|
||||
return CanBeOn(BlockBelow, MetaBelow);
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
auto BelowPos = a_RelPos.addedY(-1);
|
||||
auto BlockBelow = a_Chunk.GetBlock(BelowPos);
|
||||
auto MetaBelow = a_Chunk.GetMeta(BelowPos);
|
||||
return CanBeOn(BlockBelow, MetaBelow);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool DoesDropOnUnsuitable(void) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
||||
{
|
||||
UNUSED(a_Meta);
|
||||
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:
|
||||
|
||||
/** 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):
|
||||
Super(a_BlockType)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool GetPlacementBlockTypeMeta(
|
||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
cChunkInterface & a_ChunkInterface,
|
||||
cPlayer & a_Player,
|
||||
const Vector3i a_PlacedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||
) override
|
||||
{
|
||||
UNUSED(a_ChunkInterface);
|
||||
UNUSED(a_BlockX);
|
||||
UNUSED(a_BlockY);
|
||||
UNUSED(a_BlockZ);
|
||||
UNUSED(a_CursorX);
|
||||
UNUSED(a_CursorZ);
|
||||
UNUSED(a_PlacedBlockPos);
|
||||
UNUSED(a_CursorPos);
|
||||
a_BlockType = m_BlockType;
|
||||
a_BlockMeta = RotationToMetaData(a_Player.GetYaw());
|
||||
switch (a_BlockFace)
|
||||
switch (a_ClickedBlockFace)
|
||||
{
|
||||
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
|
||||
@ -45,7 +47,7 @@ public:
|
||||
case BLOCK_FACE_WEST:
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
@ -56,6 +58,10 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static NIBBLETYPE RotationToMetaData(double a_Rotation)
|
||||
{
|
||||
a_Rotation += 90 + 45; // So its not aligned with axis
|
||||
@ -81,12 +87,20 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual NIBBLETYPE MetaMirrorXZ(NIBBLETYPE a_Meta) override
|
||||
{
|
||||
// Toggle bit 3:
|
||||
return (a_Meta & 0x0b) | ((~a_Meta) & 0x04);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
||||
{
|
||||
UNUSED(a_Meta);
|
||||
@ -114,12 +128,16 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** EXCEPTION a.k.a. why is this removed:
|
||||
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
|
||||
two in sync by assuming that if a player hit ANY of the stair's bounding cube, it counts as the ground. */
|
||||
#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
|
||||
{
|
||||
@ -127,19 +145,19 @@ public:
|
||||
}
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
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_GRASS:
|
||||
case E_BLOCK_FARMLAND:
|
||||
case E_BLOCK_SAND:
|
||||
{
|
||||
static const struct
|
||||
static const Vector3i Coords[] =
|
||||
{
|
||||
int x, z;
|
||||
} Coords[] =
|
||||
{
|
||||
{-1, 0},
|
||||
{ 1, 0},
|
||||
{ 0, -1},
|
||||
{ 0, 1},
|
||||
{-1, -1, 0},
|
||||
{ 1, -1, 0},
|
||||
{ 0, -1, -1},
|
||||
{ 0, -1, 1},
|
||||
} ;
|
||||
a_RelY -= 1;
|
||||
for (size_t i = 0; i < ARRAYCOUNT(Coords); i++)
|
||||
{
|
||||
BLOCKTYPE BlockType;
|
||||
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
|
||||
return true;
|
||||
|
@ -10,17 +10,34 @@
|
||||
class cBlockTNTHandler :
|
||||
public cBlockHandler
|
||||
{
|
||||
using Super = cBlockHandler;
|
||||
|
||||
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
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
BLOCKTYPE BelowBlock = a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ);
|
||||
BLOCKTYPE BelowBlock = a_Chunk.GetBlock(a_RelPos.addedY(-1));
|
||||
return IsBlockTypeOfDirt(BelowBlock);
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
|
||||
|
||||
class cBlockTorchHandler :
|
||||
class cBlockTorchHandler:
|
||||
public 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(
|
||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
cChunkInterface & a_ChunkInterface,
|
||||
cPlayer & a_Player,
|
||||
const Vector3i a_PlacedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||
) override
|
||||
{
|
||||
BLOCKTYPE Block;
|
||||
NIBBLETYPE Meta;
|
||||
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, true); // Set to clicked block
|
||||
a_ChunkInterface.GetBlockTypeMeta({a_BlockX, a_BlockY, a_BlockZ}, Block, Meta);
|
||||
|
||||
if (!CanBePlacedOn(Block, Meta, a_BlockFace)) // Try to preserve original direction
|
||||
BLOCKTYPE ClickedBlockType;
|
||||
NIBBLETYPE ClickedBlockMeta;
|
||||
auto ClickedBlockPos = AddFaceDirection(a_PlacedBlockPos, a_ClickedBlockFace, true);
|
||||
a_ChunkInterface.GetBlockTypeMeta(ClickedBlockPos, ClickedBlockType, ClickedBlockMeta);
|
||||
if (!CanBePlacedOn(ClickedBlockType, ClickedBlockMeta, a_ClickedBlockFace))
|
||||
{
|
||||
// Torch couldn't be placed on whatever face was clicked, last ditch resort - find another face
|
||||
|
||||
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, false); // Reset to torch block
|
||||
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)
|
||||
// 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
|
||||
if (a_ClickedBlockFace == BLOCK_FACE_NONE)
|
||||
{
|
||||
// No attachable face found - don't place the torch
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
a_BlockType = m_BlockType;
|
||||
a_BlockMeta = DirectionToMetaData(a_BlockFace);
|
||||
a_BlockMeta = BlockFaceToMetaData(a_ClickedBlockFace);
|
||||
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_TOP: return E_META_TORCH_FLOOR;
|
||||
@ -69,7 +76,12 @@ public:
|
||||
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)
|
||||
{
|
||||
@ -88,6 +100,11 @@ public:
|
||||
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)
|
||||
{
|
||||
switch (a_BlockType)
|
||||
@ -115,7 +132,7 @@ public:
|
||||
case E_BLOCK_STONE_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));
|
||||
}
|
||||
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;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Reset coords in preparation for next iteration
|
||||
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, Face, false);
|
||||
}
|
||||
}
|
||||
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 CanBePlacedOn(BlockInQuestion, BlockInQuestionMeta, Face);
|
||||
return CanBePlacedOn(NeighborBlockType, NeighborBlockMeta, Face);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
||||
{
|
||||
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)
|
||||
{
|
||||
@ -41,36 +48,56 @@ public:
|
||||
}
|
||||
|
||||
// Flip the ON bit on / off using the XOR bitwise operation
|
||||
NIBBLETYPE Meta = (a_ChunkInterface.GetBlockMeta({a_BlockX, a_BlockY, a_BlockZ}) ^ 0x04);
|
||||
a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta);
|
||||
a_WorldInterface.GetBroadcastManager().BroadcastSoundParticleEffect(EffectID::SFX_RANDOM_FENCE_GATE_OPEN, { a_BlockX, a_BlockY, a_BlockZ }, 0, a_Player.GetClientHandle());
|
||||
NIBBLETYPE Meta = (a_ChunkInterface.GetBlockMeta(a_BlockPos) ^ 0x04);
|
||||
a_ChunkInterface.SetBlockMeta(a_BlockPos, Meta);
|
||||
a_WorldInterface.GetBroadcastManager().BroadcastSoundParticleEffect(EffectID::SFX_RANDOM_FENCE_GATE_OPEN, a_BlockPos, 0, a_Player.GetClientHandle());
|
||||
|
||||
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);
|
||||
a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
|
||||
a_WorldInterface.SendBlockTo(a_BlockPos, a_Player);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool GetPlacementBlockTypeMeta(
|
||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
cChunkInterface & a_ChunkInterface,
|
||||
cPlayer & a_Player,
|
||||
const Vector3i a_PlacedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||
) override
|
||||
{
|
||||
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;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
inline static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_BlockFace)
|
||||
{
|
||||
switch (a_BlockFace)
|
||||
@ -90,6 +117,10 @@ public:
|
||||
UNREACHABLE("Unsupported block face");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
inline static eBlockFace BlockMetaDataToBlockFace(NIBBLETYPE a_Meta)
|
||||
{
|
||||
switch (a_Meta & 0x3)
|
||||
@ -106,6 +137,10 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
||||
{
|
||||
UNUSED(a_Meta);
|
||||
|
@ -24,14 +24,16 @@ public:
|
||||
|
||||
|
||||
virtual bool GetPlacementBlockTypeMeta(
|
||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
cChunkInterface & a_ChunkInterface,
|
||||
cPlayer & a_Player,
|
||||
const Vector3i a_PlacedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||
) override
|
||||
{
|
||||
a_BlockType = m_BlockType;
|
||||
a_BlockMeta = DirectionToMetadata(a_BlockFace);
|
||||
a_BlockMeta = DirectionToMetadata(a_ClickedBlockFace);
|
||||
|
||||
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;
|
||||
a_Chunk.UnboundedRelGetBlockMeta(a_RelX, a_RelY, a_RelZ, Meta);
|
||||
|
||||
AddFaceDirection(a_RelX, a_RelY, a_RelZ, MetadataToDirection(Meta), true);
|
||||
BLOCKTYPE BlockIsOn;
|
||||
a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ, BlockIsOn);
|
||||
|
||||
return ((a_RelY > 0) && cBlockInfo::FullyOccupiesVoxel(BlockIsOn));
|
||||
auto Meta = a_Chunk.GetMeta(a_RelPos);
|
||||
auto NeighborPos = AddFaceDirection(a_RelPos, MetadataToDirection(Meta), true);
|
||||
if (!cChunkDef::IsValidHeight(NeighborPos.y))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
BLOCKTYPE NeighborBlockType;
|
||||
a_Chunk.UnboundedRelGetBlockType(a_RelPos, NeighborBlockType);
|
||||
return cBlockInfo::FullyOccupiesVoxel(NeighborBlockType);
|
||||
}
|
||||
|
||||
|
||||
|
@ -23,23 +23,25 @@ public:
|
||||
|
||||
|
||||
virtual bool GetPlacementBlockTypeMeta(
|
||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
cChunkInterface & a_ChunkInterface,
|
||||
cPlayer & a_Player,
|
||||
const Vector3i a_PlacedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||
) override
|
||||
{
|
||||
// TODO: Disallow placement where the vine doesn't attach to something properly
|
||||
BLOCKTYPE BlockType = 0;
|
||||
NIBBLETYPE BlockMeta;
|
||||
a_ChunkInterface.GetBlockTypeMeta({a_BlockX, a_BlockY, a_BlockZ}, BlockType, BlockMeta);
|
||||
a_ChunkInterface.GetBlockTypeMeta(a_PlacedBlockPos, BlockType, BlockMeta);
|
||||
if (BlockType == m_BlockType)
|
||||
{
|
||||
a_BlockMeta = BlockMeta | DirectionToMetaData(a_BlockFace);
|
||||
a_BlockMeta = BlockMeta | DirectionToMetaData(a_ClickedBlockFace);
|
||||
}
|
||||
else
|
||||
{
|
||||
a_BlockMeta = DirectionToMetaData(a_BlockFace);
|
||||
a_BlockMeta = DirectionToMetaData(a_ClickedBlockFace);
|
||||
}
|
||||
a_BlockType = m_BlockType;
|
||||
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;
|
||||
int BlockZ = (a_Chunk.GetPosZ() * cChunkDef::Width) + a_RelZ;
|
||||
GetBlockCoordsBehindTheSign(a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ), BlockX, BlockZ);
|
||||
BLOCKTYPE Type = a_ChunkInterface.GetBlock({BlockX, a_RelY, BlockZ});
|
||||
|
||||
return ((Type == E_BLOCK_WALLSIGN) || (Type == E_BLOCK_SIGN_POST) || cBlockInfo::IsSolid(Type));
|
||||
auto NeighborPos = a_RelPos + GetOffsetBehindTheSign(a_Chunk.GetMeta(a_RelPos));
|
||||
BLOCKTYPE NeighborType;
|
||||
if (!a_Chunk.UnboundedRelGetBlockType(NeighborPos, NeighborType))
|
||||
{
|
||||
// The neighbor is not accessible (unloaded chunk), bail out without changing this
|
||||
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)
|
||||
{
|
||||
case 2: a_BlockZ++; break;
|
||||
case 3: a_BlockZ--; break;
|
||||
case 4: a_BlockX++; break;
|
||||
case 5: a_BlockX--; break;
|
||||
default: break;
|
||||
case 2: return Vector3i( 0, 0, 1);
|
||||
case 3: return Vector3i( 0, 0, -1);
|
||||
case 4: return Vector3i( 1, 0, 0);
|
||||
case 5: return Vector3i(-1, 0, 0);
|
||||
}
|
||||
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_ZP: return 0x03;
|
||||
|
@ -12,24 +12,46 @@
|
||||
class cBlockWorkbenchHandler:
|
||||
public cBlockHandler
|
||||
{
|
||||
using Super = cBlockHandler;
|
||||
|
||||
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);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool IsUseable(void) override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
|
||||
{
|
||||
UNUSED(a_Meta);
|
||||
|
@ -189,7 +189,8 @@ public:
|
||||
|
||||
cYawRotator(BLOCKTYPE a_BlockType):
|
||||
Super(a_BlockType)
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -197,13 +198,14 @@ public:
|
||||
|
||||
virtual bool GetPlacementBlockTypeMeta(
|
||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
const Vector3i a_BlockPos,
|
||||
eBlockFace a_BlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||
) override
|
||||
{
|
||||
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;
|
||||
}
|
||||
@ -259,25 +261,29 @@ class cPitchYawRotator:
|
||||
public cYawRotator<Base, BitMask, North, East, South, West>
|
||||
{
|
||||
using Super = cYawRotator<Base, BitMask, North, East, South, West>;
|
||||
|
||||
public:
|
||||
|
||||
cPitchYawRotator(BLOCKTYPE a_BlockType):
|
||||
Super(a_BlockType)
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool GetPlacementBlockTypeMeta(
|
||||
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
cChunkInterface & a_ChunkInterface,
|
||||
cPlayer & a_Player,
|
||||
const Vector3i a_PlacedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||
) override
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -60,6 +60,12 @@ public:
|
||||
/** 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;
|
||||
|
||||
/** 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 */
|
||||
virtual bool ForEachPlayer(cPlayerListCallback a_Callback) = 0;
|
||||
|
||||
|
@ -572,7 +572,7 @@ public:
|
||||
|
||||
/** Converts the coord relative to this chunk into an absolute coord.
|
||||
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});
|
||||
}
|
||||
|
@ -555,8 +555,17 @@ struct sSetBlock
|
||||
/** Returns the absolute Z coord of the stored block. */
|
||||
int GetZ(void) const { return m_RelZ + cChunkDef::Width * m_ChunkZ; }
|
||||
|
||||
/** Returns the absolute position of the stored block. */
|
||||
Vector3i GetPos(void) const { return Vector3i(GetX(), GetY(), GetZ()); }
|
||||
/** Returns the absolute coords of the stored block. */
|
||||
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;
|
||||
|
@ -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->OnItemShoot(m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
|
||||
ItemHandler->OnItemShoot(m_Player, {a_BlockX, a_BlockY, a_BlockZ}, a_BlockFace);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -1294,10 +1294,10 @@ void cClientHandle::HandleBlockDigStarted(int a_BlockX, int a_BlockY, int a_Bloc
|
||||
cWorld * World = m_Player->GetWorld();
|
||||
cChunkInterface ChunkInterface(World->GetChunkMap());
|
||||
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());
|
||||
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
|
||||
// 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();
|
||||
FLOGD("HandleRightClick: {0}, face {1}, Hand: {2}, HeldItem: {3}; Dist: {4:.02f}",
|
||||
Vector3i{a_BlockX, a_BlockY, a_BlockZ}, a_BlockFace, a_Hand, ItemToFullString(HeldItem), Dist
|
||||
auto ClickedBlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ);
|
||||
auto CursorPos = Vector3i(a_CursorX, a_CursorY, a_CursorZ);
|
||||
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:
|
||||
@ -1464,7 +1466,7 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
|
||||
{
|
||||
BLOCKTYPE BlockType;
|
||||
NIBBLETYPE BlockMeta;
|
||||
World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta);
|
||||
World->GetBlockTypeMeta(ClickedBlockPos, BlockType, BlockMeta);
|
||||
cBlockHandler * BlockHandler = cBlockInfo::GetHandler(BlockType);
|
||||
|
||||
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());
|
||||
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
|
||||
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)
|
||||
{
|
||||
// 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
|
||||
{
|
||||
// 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:
|
||||
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)
|
||||
@ -1507,7 +1509,7 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
|
||||
return;
|
||||
}
|
||||
// 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
|
||||
{
|
||||
@ -1516,7 +1518,7 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
|
||||
{
|
||||
// All plugins agree with using the item
|
||||
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);
|
||||
Success = true;
|
||||
}
|
||||
@ -1827,7 +1829,7 @@ void cClientHandle::HandleUseItem(eHand a_Hand)
|
||||
{
|
||||
// All plugins agree with using the item
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
{
|
||||
@ -2652,7 +2654,7 @@ void cClientHandle::SendExplosion(double a_BlockX, double a_BlockY, double a_Blo
|
||||
// Update the statistics:
|
||||
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 SendExperience (void);
|
||||
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 SendHealth (void);
|
||||
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.
|
||||
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) */
|
||||
static const struct
|
||||
{
|
||||
int x, y, z;
|
||||
} BlockSampleOffsets[] =
|
||||
static const Vector3i BlockSampleOffsets[] =
|
||||
{
|
||||
{ 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)
|
||||
@ -354,26 +351,26 @@ void cPawn::HandleFalling(void)
|
||||
/* We go through the blocks that we consider "relevant" */
|
||||
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))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
BLOCKTYPE Block = GetWorld()->GetBlock(BlockTestPosition);
|
||||
BLOCKTYPE BlockType = GetWorld()->GetBlock(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 */
|
||||
if (j == 0)
|
||||
{
|
||||
IsFootInWater |= IsBlockWater(Block);
|
||||
IsFootInLiquid |= IsFootInWater || IsBlockLava(Block) || (Block == E_BLOCK_COBWEB); // okay so cobweb is not _technically_ a liquid...
|
||||
IsFootOnSlimeBlock |= (Block == E_BLOCK_SLIME_BLOCK);
|
||||
IsFootInWater |= IsBlockWater(BlockType);
|
||||
IsFootInLiquid |= IsFootInWater || IsBlockLava(BlockType) || (BlockType == E_BLOCK_COBWEB); // okay so cobweb is not _technically_ a liquid...
|
||||
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 ((cBlockInfo::IsSolid(Block)) && (cBlockInfo::GetHandler(Block)->IsInsideBlock(CrossTestPosition - BlockTestPosition, Block, BlockMeta)))
|
||||
if ((cBlockInfo::IsSolid(BlockType)) && (cBlockInfo::GetHandler(BlockType)->IsInsideBlock(CrossTestPosition - BlockTestPosition, BlockMeta)))
|
||||
{
|
||||
OnGround = true;
|
||||
}
|
||||
|
@ -8,43 +8,52 @@
|
||||
|
||||
|
||||
|
||||
class cItemArmorHandler :
|
||||
class cItemArmorHandler:
|
||||
public cItemHandler
|
||||
{
|
||||
using Super = cItemHandler;
|
||||
|
||||
public:
|
||||
cItemArmorHandler(int a_ItemType) :
|
||||
cItemHandler(a_ItemType)
|
||||
|
||||
cItemArmorHandler(int a_ItemType):
|
||||
Super(a_ItemType)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Move the armor to the armor slot of the player's inventory */
|
||||
virtual bool OnItemUse(
|
||||
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
|
||||
cWorld * a_World,
|
||||
cPlayer * a_Player,
|
||||
cBlockPluginInterface & a_PluginInterface,
|
||||
const cItem & a_HeldItem,
|
||||
const Vector3i a_ClickedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace
|
||||
) override
|
||||
{
|
||||
int SlotNum;
|
||||
if (ItemCategory::IsHelmet(a_Item.m_ItemType))
|
||||
if (ItemCategory::IsHelmet(a_HeldItem.m_ItemType))
|
||||
{
|
||||
SlotNum = 0;
|
||||
}
|
||||
else if (ItemCategory::IsChestPlate(a_Item.m_ItemType))
|
||||
else if (ItemCategory::IsChestPlate(a_HeldItem.m_ItemType))
|
||||
{
|
||||
SlotNum = 1;
|
||||
}
|
||||
else if (ItemCategory::IsLeggings(a_Item.m_ItemType))
|
||||
else if (ItemCategory::IsLeggings(a_HeldItem.m_ItemType))
|
||||
{
|
||||
SlotNum = 2;
|
||||
}
|
||||
else if (ItemCategory::IsBoots(a_Item.m_ItemType))
|
||||
else if (ItemCategory::IsBoots(a_HeldItem.m_ItemType))
|
||||
{
|
||||
SlotNum = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGWARNING("Used unknown armor: %i", a_Item.m_ItemType);
|
||||
LOGWARNING("Used unknown armor: %i", a_HeldItem.m_ItemType);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -53,9 +62,9 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
a_Player->GetInventory().SetArmorSlot(SlotNum, a_Item.CopyOne());
|
||||
a_Player->GetInventory().SetArmorSlot(SlotNum, a_HeldItem.CopyOne());
|
||||
|
||||
cItem Item(a_Item);
|
||||
cItem Item(a_HeldItem);
|
||||
Item.m_ItemCount--;
|
||||
if (Item.m_ItemCount <= 0)
|
||||
{
|
||||
@ -67,6 +76,8 @@ public:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool CanRepairWithRawMaterial(short a_ItemType) override
|
||||
{
|
||||
switch (m_ItemType)
|
||||
|
@ -9,51 +9,60 @@
|
||||
|
||||
|
||||
|
||||
class cItemBedHandler :
|
||||
class cItemBedHandler:
|
||||
public cItemHandler
|
||||
{
|
||||
using Super = cItemHandler;
|
||||
|
||||
public:
|
||||
cItemBedHandler(int a_ItemType) :
|
||||
cItemHandler(a_ItemType)
|
||||
|
||||
cItemBedHandler(int a_ItemType):
|
||||
Super(a_ItemType)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool IsPlaceable(void) override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool GetBlocksToPlace(
|
||||
cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
cWorld & a_World,
|
||||
cPlayer & a_Player,
|
||||
const cItem & a_EquippedItem,
|
||||
const Vector3i a_PlacedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
sSetBlockVector & a_BlocksToPlace
|
||||
) override
|
||||
{
|
||||
// Can only be placed on the floor:
|
||||
if (a_BlockFace != BLOCK_FACE_TOP)
|
||||
if (a_ClickedBlockFace != BLOCK_FACE_TOP)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// The "foot" block:
|
||||
NIBBLETYPE BlockMeta = cBlockBedHandler::YawToMetaData(a_Player.GetYaw());
|
||||
a_BlocksToPlace.emplace_back(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_BED, BlockMeta);
|
||||
a_BlocksToPlace.emplace_back(a_PlacedBlockPos, E_BLOCK_BED, BlockMeta);
|
||||
|
||||
// Check if there is empty space for the "head" block:
|
||||
// (Vanilla only allows beds to be placed into air)
|
||||
Vector3i Direction = cBlockBedHandler::MetaDataToDirection(BlockMeta);
|
||||
if (a_World.GetBlock(a_BlockX + Direction.x, a_BlockY, a_BlockZ + Direction.z) != E_BLOCK_AIR)
|
||||
auto Direction = cBlockBedHandler::MetaDataToDirection(BlockMeta);
|
||||
auto HeadPos = a_PlacedBlockPos + Direction;
|
||||
if (a_World.GetBlock(HeadPos) != E_BLOCK_AIR)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
a_BlocksToPlace.emplace_back(a_BlockX + Direction.x, a_BlockY, a_BlockZ + Direction.z, E_BLOCK_BED, BlockMeta | 0x08);
|
||||
a_BlocksToPlace.emplace_back(HeadPos, E_BLOCK_BED, BlockMeta | 0x08);
|
||||
return true;
|
||||
}
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
@ -15,43 +15,50 @@ class cItemBigFlowerHandler:
|
||||
|
||||
public:
|
||||
|
||||
cItemBigFlowerHandler(void):
|
||||
cItemBigFlowerHandler():
|
||||
Super(E_BLOCK_BIG_FLOWER)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool GetBlocksToPlace(
|
||||
cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
sSetBlockVector & a_BlocksToSet
|
||||
cWorld & a_World,
|
||||
cPlayer & a_Player,
|
||||
const cItem & a_EquippedItem,
|
||||
const Vector3i a_PlacedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
sSetBlockVector & a_BlocksToPlace
|
||||
) override
|
||||
{
|
||||
// Can only be placed on dirt:
|
||||
if ((a_BlockY <= 0) || !IsBlockTypeOfDirt(a_World.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ)))
|
||||
if ((a_PlacedBlockPos.y <= 0) || !IsBlockTypeOfDirt(a_World.GetBlock(a_PlacedBlockPos.addedY(-1))))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Needs at least two free blocks to build in
|
||||
if (a_BlockY >= cChunkDef::Height - 1)
|
||||
if (a_PlacedBlockPos.y >= cChunkDef::Height - 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto TopPos = a_PlacedBlockPos.addedY(1);
|
||||
BLOCKTYPE TopType;
|
||||
NIBBLETYPE TopMeta;
|
||||
a_World.GetBlockTypeMeta(a_BlockX, a_BlockY + 1, a_BlockZ, TopType, TopMeta);
|
||||
a_World.GetBlockTypeMeta(TopPos, TopType, TopMeta);
|
||||
cChunkInterface ChunkInterface(a_World.GetChunkMap());
|
||||
|
||||
if (!BlockHandler(TopType)->DoesIgnoreBuildCollision(ChunkInterface, { a_BlockX, a_BlockY + 1, a_BlockZ }, a_Player, TopMeta))
|
||||
if (!BlockHandler(TopType)->DoesIgnoreBuildCollision(ChunkInterface, TopPos, a_Player, TopMeta))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
a_BlocksToSet.emplace_back(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_BIG_FLOWER, a_EquippedItem.m_ItemDamage & 0x07);
|
||||
a_BlocksToSet.emplace_back(a_BlockX, a_BlockY + 1, a_BlockZ, E_BLOCK_BIG_FLOWER, E_META_BIG_FLOWER_TOP);
|
||||
a_BlocksToPlace.emplace_back(a_PlacedBlockPos, E_BLOCK_BIG_FLOWER, a_EquippedItem.m_ItemDamage & 0x07);
|
||||
a_BlocksToPlace.emplace_back(TopPos, E_BLOCK_BIG_FLOWER, E_META_BIG_FLOWER_TOP);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
@ -22,24 +22,32 @@ public:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool OnItemUse(
|
||||
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
|
||||
cWorld * a_World,
|
||||
cPlayer * a_Player,
|
||||
cBlockPluginInterface & a_PluginInterface,
|
||||
const cItem & a_HeldItem,
|
||||
const Vector3i a_ClickedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace
|
||||
) override
|
||||
{
|
||||
if ((a_BlockFace != BLOCK_FACE_YM) && (a_BlockFace != BLOCK_FACE_NONE))
|
||||
// Only allow placing blocks on top of blocks, or when not in range of dest block:
|
||||
if ((a_ClickedBlockFace != BLOCK_FACE_YM) && (a_ClickedBlockFace != BLOCK_FACE_NONE))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
class cCallbacks :
|
||||
// Find the actual placement position by tracing line of sight until non-air block:
|
||||
class cCallbacks:
|
||||
public cBlockTracer::cCallbacks
|
||||
{
|
||||
public:
|
||||
Vector3d m_Pos;
|
||||
bool m_HasFound;
|
||||
|
||||
cCallbacks(void) :
|
||||
cCallbacks():
|
||||
m_HasFound(false)
|
||||
{
|
||||
}
|
||||
@ -55,27 +63,21 @@ public:
|
||||
return false;
|
||||
}
|
||||
} Callbacks;
|
||||
|
||||
cLineBlockTracer Tracer(*a_World, Callbacks);
|
||||
Vector3d Start(a_Player->GetEyePosition() + a_Player->GetLookVector());
|
||||
Vector3d End(a_Player->GetEyePosition() + a_Player->GetLookVector() * 5);
|
||||
|
||||
Tracer.Trace(Start.x, Start.y, Start.z, End.x, End.y, End.z);
|
||||
|
||||
auto Start = a_Player->GetEyePosition() + a_Player->GetLookVector();
|
||||
auto End = a_Player->GetEyePosition() + a_Player->GetLookVector() * 5;
|
||||
cLineBlockTracer::Trace(*a_World, Callbacks, Start, End);
|
||||
if (!Callbacks.m_HasFound)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto x = Callbacks.m_Pos.x;
|
||||
auto y = Callbacks.m_Pos.y;
|
||||
auto z = Callbacks.m_Pos.z;
|
||||
auto bx = FloorC(x);
|
||||
auto by = FloorC(y);
|
||||
auto bz = FloorC(z);
|
||||
|
||||
// Block above must be air to spawn a boat (prevents spawning a boat underwater)
|
||||
BLOCKTYPE BlockAbove = a_World->GetBlock(bx, by + 1, bz);
|
||||
auto PosAbove = Callbacks.m_Pos.Floor().addedY(1);
|
||||
if (!cChunkDef::IsValidHeight(PosAbove.y))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
BLOCKTYPE BlockAbove = a_World->GetBlock(PosAbove);
|
||||
if (BlockAbove != E_BLOCK_AIR)
|
||||
{
|
||||
return false;
|
||||
|
@ -9,19 +9,28 @@
|
||||
|
||||
|
||||
|
||||
class cItemBottleHandler :
|
||||
class cItemBottleHandler:
|
||||
public cItemHandler
|
||||
{
|
||||
using Super = cItemHandler;
|
||||
|
||||
public:
|
||||
cItemBottleHandler() :
|
||||
cItemHandler(E_ITEM_GLASS_BOTTLE)
|
||||
|
||||
cItemBottleHandler():
|
||||
Super(E_ITEM_GLASS_BOTTLE)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Searches for a water source block in the line of sight.
|
||||
Returns true and sets a_BlockPos if a water source block is found within line-of-sight.
|
||||
Returns false if not. */
|
||||
bool GetBlockFromTrace(cWorld * a_World, cPlayer * a_Player, Vector3i & a_BlockPos)
|
||||
{
|
||||
class cCallbacks :
|
||||
class cCallbacks:
|
||||
public cBlockTracer::cCallbacks
|
||||
{
|
||||
public:
|
||||
@ -29,7 +38,7 @@ public:
|
||||
bool m_HasHitFluid;
|
||||
|
||||
|
||||
cCallbacks(void) :
|
||||
cCallbacks():
|
||||
m_HasHitFluid(false)
|
||||
{
|
||||
}
|
||||
@ -49,31 +58,32 @@ public:
|
||||
return false;
|
||||
}
|
||||
} Callbacks;
|
||||
|
||||
cLineBlockTracer Tracer(*a_World, Callbacks);
|
||||
Vector3d Start(a_Player->GetEyePosition() + a_Player->GetLookVector());
|
||||
Vector3d End(a_Player->GetEyePosition() + a_Player->GetLookVector() * 5);
|
||||
|
||||
Tracer.Trace(Start.x, Start.y, Start.z, End.x, End.y, End.z);
|
||||
|
||||
auto Start = a_Player->GetEyePosition() + a_Player->GetLookVector();
|
||||
auto End = a_Player->GetEyePosition() + a_Player->GetLookVector() * 5;
|
||||
cLineBlockTracer::Trace(*a_World, Callbacks, Start, End);
|
||||
if (!Callbacks.m_HasHitFluid)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
a_BlockPos = Callbacks.m_Pos;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool OnItemUse(
|
||||
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
|
||||
) override
|
||||
cWorld * a_World,
|
||||
cPlayer * a_Player,
|
||||
cBlockPluginInterface & a_PluginInterface,
|
||||
const cItem & a_HeldItem,
|
||||
const Vector3i a_ClickedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace
|
||||
) override
|
||||
{
|
||||
if (a_BlockFace != BLOCK_FACE_NONE)
|
||||
if (a_ClickedBlockFace != BLOCK_FACE_NONE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -22,9 +22,15 @@ public:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool OnItemUse(
|
||||
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
|
||||
cWorld * a_World,
|
||||
cPlayer * a_Player,
|
||||
cBlockPluginInterface & a_PluginInterface,
|
||||
const cItem & a_HeldItem,
|
||||
const Vector3i a_ClickedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace
|
||||
) override
|
||||
{
|
||||
ASSERT(a_Player != nullptr);
|
||||
@ -41,9 +47,10 @@ public:
|
||||
|
||||
|
||||
|
||||
virtual void OnItemShoot(cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override
|
||||
virtual void OnItemShoot(cPlayer * a_Player, const Vector3i a_BlockPos, eBlockFace a_BlockFace) override
|
||||
{
|
||||
// Actual shot - produce the arrow with speed based on the ticks that the bow was charged
|
||||
// Actual shot - produce the arrow with speed based on the number of ticks that the bow was charged
|
||||
UNUSED(a_BlockPos);
|
||||
ASSERT(a_Player != nullptr);
|
||||
|
||||
int BowCharge = a_Player->FinishChargingBow();
|
||||
@ -88,7 +95,6 @@ public:
|
||||
|
||||
a_Player->UseEquippedItem();
|
||||
}
|
||||
|
||||
if (a_Player->GetEquippedItem().m_Enchantments.GetLevel(cEnchantments::enchFlame) > 0)
|
||||
{
|
||||
ArrowPtr->StartBurning(100);
|
||||
|
@ -7,12 +7,15 @@
|
||||
|
||||
|
||||
|
||||
class cItemBrewingStandHandler :
|
||||
class cItemBrewingStandHandler:
|
||||
public cItemHandler
|
||||
{
|
||||
using Super = cItemHandler;
|
||||
|
||||
public:
|
||||
cItemBrewingStandHandler(int a_ItemType) :
|
||||
cItemHandler(a_ItemType)
|
||||
|
||||
cItemBrewingStandHandler(int a_ItemType):
|
||||
Super(a_ItemType)
|
||||
{
|
||||
}
|
||||
|
||||
@ -25,8 +28,9 @@ public:
|
||||
|
||||
virtual bool GetPlacementBlockTypeMeta(
|
||||
cWorld * a_World, cPlayer * a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
const Vector3i a_PlacedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||
) override
|
||||
{
|
||||
|
@ -16,25 +16,34 @@
|
||||
class cItemBucketHandler :
|
||||
public cItemHandler
|
||||
{
|
||||
using Super = cItemHandler;
|
||||
|
||||
public:
|
||||
cItemBucketHandler(int a_ItemType) :
|
||||
cItemHandler(a_ItemType)
|
||||
|
||||
cItemBucketHandler(int a_ItemType):
|
||||
Super(a_ItemType)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool OnItemUse(
|
||||
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
|
||||
cWorld * a_World,
|
||||
cPlayer * a_Player,
|
||||
cBlockPluginInterface & a_PluginInterface,
|
||||
const cItem & a_HeldItem,
|
||||
const Vector3i a_ClickedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace
|
||||
) override
|
||||
{
|
||||
switch (m_ItemType)
|
||||
{
|
||||
case E_ITEM_BUCKET: return ScoopUpFluid(a_World, a_Player, a_Item, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
|
||||
case E_ITEM_LAVA_BUCKET: return PlaceFluid (a_World, a_Player, a_PluginInterface, a_Item, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, E_BLOCK_LAVA);
|
||||
case E_ITEM_WATER_BUCKET: return PlaceFluid (a_World, a_Player, a_PluginInterface, a_Item, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, E_BLOCK_WATER);
|
||||
case E_ITEM_BUCKET: return ScoopUpFluid(a_World, a_Player, a_HeldItem, a_ClickedBlockPos, a_ClickedBlockFace);
|
||||
case E_ITEM_LAVA_BUCKET: return PlaceFluid (a_World, a_Player, a_PluginInterface, a_HeldItem, a_ClickedBlockPos, a_ClickedBlockFace, E_BLOCK_LAVA);
|
||||
case E_ITEM_WATER_BUCKET: return PlaceFluid (a_World, a_Player, a_PluginInterface, a_HeldItem, a_ClickedBlockPos, a_ClickedBlockFace, E_BLOCK_WATER);
|
||||
default:
|
||||
{
|
||||
ASSERT(!"Unhandled ItemType");
|
||||
@ -45,7 +54,9 @@ public:
|
||||
|
||||
|
||||
|
||||
bool ScoopUpFluid(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace)
|
||||
|
||||
|
||||
bool ScoopUpFluid(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, const Vector3i a_ClickedBlockPos, eBlockFace a_ClickedBlockFace)
|
||||
{
|
||||
// Players can't pick up fluid while in adventure mode.
|
||||
if (a_Player->IsGameModeAdventure())
|
||||
@ -53,7 +64,8 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a_BlockFace != BLOCK_FACE_NONE)
|
||||
// Needs a valid clicked block:
|
||||
if (a_ClickedBlockFace != BLOCK_FACE_NONE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -114,7 +126,7 @@ public:
|
||||
|
||||
bool PlaceFluid(
|
||||
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, BLOCKTYPE a_FluidBlock
|
||||
const Vector3i a_BlockPos, eBlockFace a_BlockFace, BLOCKTYPE a_FluidBlock
|
||||
)
|
||||
{
|
||||
// Players can't place fluid while in adventure mode.
|
||||
@ -219,6 +231,8 @@ public:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool GetPlacementCoordsFromTrace(cWorld * a_World, cPlayer * a_Player, Vector3i & a_BlockPos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta, eBlockFace & a_BlockFace)
|
||||
{
|
||||
class cCallbacks :
|
||||
|
@ -7,12 +7,15 @@
|
||||
|
||||
|
||||
|
||||
class cItemCakeHandler :
|
||||
class cItemCakeHandler:
|
||||
public cItemHandler
|
||||
{
|
||||
using Super = cItemHandler;
|
||||
|
||||
public:
|
||||
cItemCakeHandler(int a_ItemType) :
|
||||
cItemHandler(a_ItemType)
|
||||
|
||||
cItemCakeHandler(int a_ItemType):
|
||||
Super(a_ItemType)
|
||||
{
|
||||
}
|
||||
|
||||
@ -25,8 +28,9 @@ public:
|
||||
|
||||
virtual bool GetPlacementBlockTypeMeta(
|
||||
cWorld * a_World, cPlayer * a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
const Vector3i a_PlacedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||
) override
|
||||
{
|
||||
|
@ -7,12 +7,15 @@
|
||||
|
||||
|
||||
|
||||
class cItemCauldronHandler :
|
||||
class cItemCauldronHandler:
|
||||
public cItemHandler
|
||||
{
|
||||
using Super = cItemHandler;
|
||||
|
||||
public:
|
||||
cItemCauldronHandler(int a_ItemType) :
|
||||
cItemHandler(a_ItemType)
|
||||
|
||||
cItemCauldronHandler(int a_ItemType):
|
||||
Super(a_ItemType)
|
||||
{
|
||||
}
|
||||
|
||||
@ -25,8 +28,9 @@ public:
|
||||
|
||||
virtual bool GetPlacementBlockTypeMeta(
|
||||
cWorld * a_World, cPlayer * a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
const Vector3i a_PlacedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||
) override
|
||||
{
|
||||
|
@ -25,56 +25,57 @@ public:
|
||||
/** We need an OnPlayerPlace override because we're processing neighbor chests and changing their metas,
|
||||
the parent class cannot do that. */
|
||||
virtual bool OnPlayerPlace(
|
||||
cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ
|
||||
cWorld & a_World,
|
||||
cPlayer & a_Player,
|
||||
const cItem & a_EquippedItem,
|
||||
const Vector3i a_ClickedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos
|
||||
) override
|
||||
{
|
||||
if (a_BlockFace < 0)
|
||||
if (a_ClickedBlockFace < 0)
|
||||
{
|
||||
// Clicked in air
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((a_BlockY < 0) || (a_BlockY >= cChunkDef::Height))
|
||||
if (!cChunkDef::IsValidHeight(a_ClickedBlockPos.y))
|
||||
{
|
||||
// The clicked block is outside the world, ignore this call altogether (#128)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the block ignores build collision (water, grass etc.):
|
||||
BLOCKTYPE clickedBlock;
|
||||
NIBBLETYPE clickedBlockMeta;
|
||||
Vector3i blockPos(a_BlockX, a_BlockY, a_BlockZ);
|
||||
a_World.GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, clickedBlock, clickedBlockMeta);
|
||||
BLOCKTYPE ClickedBlockType;
|
||||
NIBBLETYPE ClickedBlockMeta;
|
||||
a_World.GetBlockTypeMeta(a_ClickedBlockPos, ClickedBlockType, ClickedBlockMeta);
|
||||
cChunkInterface ChunkInterface(a_World.GetChunkMap());
|
||||
auto blockHandler = BlockHandler(clickedBlock);
|
||||
if (blockHandler->DoesIgnoreBuildCollision(ChunkInterface, blockPos, a_Player, clickedBlockMeta))
|
||||
auto blockHandler = BlockHandler(ClickedBlockType);
|
||||
Vector3i PlacePos;
|
||||
if (blockHandler->DoesIgnoreBuildCollision(ChunkInterface, a_ClickedBlockPos, a_Player, ClickedBlockMeta))
|
||||
{
|
||||
blockHandler->OnPlayerBreakingBlock(ChunkInterface, a_World, a_Player, blockPos);
|
||||
blockHandler->OnPlayerBreakingBlock(ChunkInterface, a_World, a_Player, a_ClickedBlockPos);
|
||||
PlacePos = a_ClickedBlockPos;
|
||||
}
|
||||
else
|
||||
{
|
||||
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
|
||||
|
||||
if ((a_BlockY < 0) || (a_BlockY >= cChunkDef::Height))
|
||||
PlacePos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace);
|
||||
if (!cChunkDef::IsValidHeight(PlacePos.y))
|
||||
{
|
||||
// The block is being placed outside the world, ignore this packet altogether (#128)
|
||||
return false;
|
||||
}
|
||||
|
||||
NIBBLETYPE PlaceMeta;
|
||||
// Check if the chest can overwrite the block at PlacePos:
|
||||
BLOCKTYPE PlaceBlock;
|
||||
a_World.GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, PlaceBlock, PlaceMeta);
|
||||
|
||||
// Clicked on side of block, make sure that placement won't be cancelled if there is a slab able to be double slabbed.
|
||||
// No need to do combinability (dblslab) checks, client will do that here.
|
||||
if (blockHandler->DoesIgnoreBuildCollision(ChunkInterface, blockPos, a_Player, clickedBlockMeta))
|
||||
NIBBLETYPE PlaceMeta;
|
||||
a_World.GetBlockTypeMeta(PlacePos, PlaceBlock, PlaceMeta);
|
||||
blockHandler = BlockHandler(PlaceBlock);
|
||||
if (!blockHandler->DoesIgnoreBuildCollision(ChunkInterface, PlacePos, a_Player, PlaceMeta))
|
||||
{
|
||||
// Tried to place a block into another?
|
||||
// Happens when you place a block aiming at side of block with a torch on it or stem beside it
|
||||
return false;
|
||||
}
|
||||
blockHandler->OnPlayerBreakingBlock(ChunkInterface, a_World, a_Player, PlacePos);
|
||||
}
|
||||
|
||||
// Check that there is at most one single neighbor of the same chest type:
|
||||
@ -88,7 +89,8 @@ public:
|
||||
int NeighborIdx = -1;
|
||||
for (size_t i = 0; i < ARRAYCOUNT(CrossCoords); i++)
|
||||
{
|
||||
if (a_World.GetBlock(a_BlockX + CrossCoords[i].x, a_BlockY, a_BlockZ + CrossCoords[i].z) != m_ItemType)
|
||||
auto NeighborPos = PlacePos + CrossCoords[i];
|
||||
if (a_World.GetBlock(NeighborPos) != m_ItemType)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@ -100,12 +102,11 @@ public:
|
||||
NeighborIdx = static_cast<int>(i);
|
||||
|
||||
// Check that this neighbor is a single chest:
|
||||
int bx = a_BlockX + CrossCoords[i].x;
|
||||
int bz = a_BlockZ + CrossCoords[i].z;
|
||||
for (size_t j = 0; j < ARRAYCOUNT(CrossCoords); j++)
|
||||
{
|
||||
if (a_World.GetBlock(bx + CrossCoords[j].x, a_BlockY, bz + CrossCoords[j].z) == m_ItemType)
|
||||
if (a_World.GetBlock(NeighborPos + CrossCoords[j]) == m_ItemType)
|
||||
{
|
||||
// Trying to place next to a dblchest
|
||||
return false;
|
||||
}
|
||||
} // for j
|
||||
@ -133,13 +134,14 @@ public:
|
||||
}
|
||||
default:
|
||||
{
|
||||
// No neighbor, place based on yaw:
|
||||
Meta = cBlockChestHandler::PlayerYawToMetaData(yaw);
|
||||
break;
|
||||
}
|
||||
} // switch (NeighborIdx)
|
||||
|
||||
// Place the new chest:
|
||||
if (!a_Player.PlaceBlock(a_BlockX, a_BlockY, a_BlockZ, ChestBlockType, Meta))
|
||||
if (!a_Player.PlaceBlock(PlacePos.x, PlacePos.y, PlacePos.z, ChestBlockType, Meta))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -147,10 +149,10 @@ public:
|
||||
// Adjust the existing chest, if any:
|
||||
if (NeighborIdx != -1)
|
||||
{
|
||||
a_World.FastSetBlock(a_BlockX + CrossCoords[NeighborIdx].x, a_BlockY, a_BlockZ + CrossCoords[NeighborIdx].z, ChestBlockType, Meta);
|
||||
a_World.FastSetBlock(PlacePos + CrossCoords[NeighborIdx], ChestBlockType, Meta);
|
||||
}
|
||||
|
||||
// Remove the "placed" item:
|
||||
// Remove the "placed" item from inventory:
|
||||
if (a_Player.IsGameModeSurvival())
|
||||
{
|
||||
a_Player.GetInventory().RemoveOneEquippedItem();
|
||||
|
@ -8,24 +8,36 @@
|
||||
|
||||
|
||||
|
||||
class cItemComparatorHandler :
|
||||
class cItemComparatorHandler:
|
||||
public cItemHandler
|
||||
{
|
||||
using Super = cItemHandler;
|
||||
|
||||
public:
|
||||
cItemComparatorHandler(int a_ItemType) :
|
||||
|
||||
cItemComparatorHandler(int a_ItemType):
|
||||
cItemHandler(a_ItemType)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool IsPlaceable(void) override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool GetPlacementBlockTypeMeta(
|
||||
cWorld * a_World, cPlayer * a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
const Vector3i a_PlacedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||
) override
|
||||
{
|
||||
|
@ -9,38 +9,45 @@
|
||||
|
||||
|
||||
|
||||
class cItemDoorHandler :
|
||||
class cItemDoorHandler:
|
||||
public cItemHandler
|
||||
{
|
||||
using Super = cItemHandler;
|
||||
|
||||
public:
|
||||
cItemDoorHandler(int a_ItemType) :
|
||||
cItemHandler(a_ItemType)
|
||||
|
||||
cItemDoorHandler(int a_ItemType):
|
||||
Super(a_ItemType)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool GetBlocksToPlace(
|
||||
cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
const Vector3i a_PlacedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
sSetBlockVector & a_BlocksToSet
|
||||
) override
|
||||
{
|
||||
// Vanilla only allows door placement while clicking on the top face of the block below the door:
|
||||
if (a_BlockFace != BLOCK_FACE_TOP)
|
||||
if (a_ClickedBlockFace != BLOCK_FACE_TOP)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Door (bottom block) can be placed in Y range of [1, 254]:
|
||||
if ((a_BlockY < 1) || (a_BlockY >= cChunkDef::Height - 2))
|
||||
if ((a_PlacedBlockPos.y < 1) || (a_PlacedBlockPos.y >= cChunkDef::Height - 2))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// The door needs a compatible block below it:
|
||||
if (!cBlockDoorHandler::CanBeOn(a_World.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ), a_World.GetBlockMeta(a_BlockX, a_BlockY - 1, a_BlockZ)))
|
||||
auto BelowPos = a_PlacedBlockPos.addedY(-1);
|
||||
if (!cBlockDoorHandler::CanBeOn(a_World.GetBlock(BelowPos), a_World.GetBlockMeta(BelowPos)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -64,8 +71,9 @@ public:
|
||||
}
|
||||
|
||||
// Check the two blocks that will get replaced by the door:
|
||||
BLOCKTYPE LowerBlockType = a_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ);
|
||||
BLOCKTYPE UpperBlockType = a_World.GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ);
|
||||
auto UpperBlockPos = a_PlacedBlockPos.addedY(1);
|
||||
BLOCKTYPE LowerBlockType = a_World.GetBlock(a_PlacedBlockPos);
|
||||
BLOCKTYPE UpperBlockType = a_World.GetBlock(UpperBlockPos);
|
||||
if (
|
||||
!cBlockDoorHandler::CanReplaceBlock(LowerBlockType) ||
|
||||
!cBlockDoorHandler::CanReplaceBlock(UpperBlockType))
|
||||
@ -78,10 +86,10 @@ public:
|
||||
Vector3i RelDirToOutside = cBlockDoorHandler::GetRelativeDirectionToOutside(LowerBlockMeta);
|
||||
Vector3i LeftNeighborPos = RelDirToOutside;
|
||||
LeftNeighborPos.TurnCW();
|
||||
LeftNeighborPos.Move(a_BlockX, a_BlockY, a_BlockZ);
|
||||
LeftNeighborPos.Move(a_PlacedBlockPos);
|
||||
Vector3i RightNeighborPos = RelDirToOutside;
|
||||
RightNeighborPos.TurnCCW();
|
||||
RightNeighborPos.Move(a_BlockX, a_BlockY, a_BlockZ);
|
||||
RightNeighborPos.Move(a_PlacedBlockPos);
|
||||
|
||||
// Decide whether the hinge is on the left (default) or on the right:
|
||||
NIBBLETYPE UpperBlockMeta = 0x08;
|
||||
@ -89,7 +97,7 @@ public:
|
||||
BLOCKTYPE RightNeighborBlock = a_World.GetBlock(RightNeighborPos);
|
||||
/*
|
||||
// DEBUG:
|
||||
FLOGD("Door being placed at {0}", Vector3i{a_BlockX, a_BlockY, a_BlockZ});
|
||||
FLOGD("Door being placed at {0}", a_PlacedBlockPos);
|
||||
FLOGD("RelDirToOutside: {0}", RelDirToOutside);
|
||||
FLOGD("Left neighbor at {0}: {1} ({2})", LeftNeighborPos, LeftNeighborBlock, ItemTypeToString(LeftNeighborBlock));
|
||||
FLOGD("Right neighbor at {0}: {1} ({2})", RightNeighborPos, RightNeighborBlock, ItemTypeToString(RightNeighborBlock));
|
||||
@ -108,12 +116,14 @@ public:
|
||||
}
|
||||
|
||||
// Set the blocks:
|
||||
a_BlocksToSet.emplace_back(a_BlockX, a_BlockY, a_BlockZ, BlockType, LowerBlockMeta);
|
||||
a_BlocksToSet.emplace_back(a_BlockX, a_BlockY + 1, a_BlockZ, BlockType, UpperBlockMeta);
|
||||
a_BlocksToSet.emplace_back(a_PlacedBlockPos, BlockType, LowerBlockMeta);
|
||||
a_BlocksToSet.emplace_back(UpperBlockPos, BlockType, UpperBlockMeta);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool IsPlaceable(void) override
|
||||
{
|
||||
return true;
|
||||
|
@ -26,14 +26,18 @@ public:
|
||||
|
||||
|
||||
virtual bool OnItemUse(
|
||||
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
|
||||
cWorld * a_World,
|
||||
cPlayer * a_Player,
|
||||
cBlockPluginInterface & a_PluginInterface,
|
||||
const cItem & a_HeldItem,
|
||||
const Vector3i a_ClickedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace
|
||||
) override
|
||||
{
|
||||
if ((a_Item.m_ItemDamage == E_META_DYE_WHITE) && (a_BlockFace != BLOCK_FACE_NONE))
|
||||
if ((a_HeldItem.m_ItemDamage == E_META_DYE_WHITE) && (a_ClickedBlockFace != BLOCK_FACE_NONE))
|
||||
{
|
||||
// Bonemeal (white dye) is used to fertilize plants:
|
||||
if (fertilizePlant(*a_World, {a_BlockX, a_BlockY, a_BlockZ}))
|
||||
if (FertilizePlant(*a_World, a_ClickedBlockPos))
|
||||
{
|
||||
if (a_Player->IsGameModeSurvival())
|
||||
{
|
||||
@ -42,7 +46,7 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((a_Item.m_ItemDamage == E_META_DYE_BROWN) && (a_BlockFace >= BLOCK_FACE_ZM) && (a_BlockFace <= BLOCK_FACE_XP))
|
||||
else if ((a_HeldItem.m_ItemDamage == E_META_DYE_BROWN) && (a_ClickedBlockFace >= BLOCK_FACE_ZM) && (a_ClickedBlockFace <= BLOCK_FACE_XP))
|
||||
{
|
||||
// Players can't place blocks while in adventure mode.
|
||||
if (a_Player->IsGameModeAdventure())
|
||||
@ -53,25 +57,24 @@ public:
|
||||
// Cocoa (brown dye) can be planted on jungle logs:
|
||||
BLOCKTYPE BlockType;
|
||||
NIBBLETYPE BlockMeta;
|
||||
a_World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta);
|
||||
a_World->GetBlockTypeMeta(a_ClickedBlockPos, BlockType, BlockMeta);
|
||||
|
||||
// Check if the block that the player clicked is a jungle log.
|
||||
if ((BlockType != E_BLOCK_LOG) || ((BlockMeta & 0x3) != E_META_LOG_JUNGLE))
|
||||
if ((BlockType != E_BLOCK_LOG) || ((BlockMeta & 0x03) != E_META_LOG_JUNGLE))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the location from the new cocoa pod.
|
||||
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, false);
|
||||
BlockMeta = cBlockCocoaPodHandler::BlockFaceToMeta(a_BlockFace);
|
||||
auto CocoaPos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace, false);
|
||||
BlockMeta = cBlockCocoaPodHandler::BlockFaceToMeta(a_ClickedBlockFace);
|
||||
|
||||
if (a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) != E_BLOCK_AIR)
|
||||
// Place the cocoa pod:
|
||||
if (a_World->GetBlock(CocoaPos) != E_BLOCK_AIR)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Place the cocoa pod:
|
||||
if (a_Player->PlaceBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_COCOA_POD, BlockMeta))
|
||||
if (a_Player->PlaceBlock(CocoaPos.x, CocoaPos.y, CocoaPos.z, E_BLOCK_COCOA_POD, BlockMeta))
|
||||
{
|
||||
if (a_Player->IsGameModeSurvival())
|
||||
{
|
||||
@ -97,7 +100,7 @@ public:
|
||||
Returns true if the plant was fertilized successfully, false if not / not a plant.
|
||||
Note that successful fertilization doesn't mean successful growth - for blocks that have only a chance to grow,
|
||||
fertilization success is reported even in the case when the chance fails (bonemeal still needs to be consumed). */
|
||||
bool fertilizePlant(cWorld & a_World, Vector3i a_BlockPos)
|
||||
bool FertilizePlant(cWorld & a_World, Vector3i a_BlockPos)
|
||||
{
|
||||
BLOCKTYPE blockType;
|
||||
NIBBLETYPE blockMeta;
|
||||
|
@ -23,15 +23,19 @@ public:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool OnItemUse(
|
||||
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
|
||||
cWorld * a_World,
|
||||
cPlayer * a_Player,
|
||||
cBlockPluginInterface & a_PluginInterface,
|
||||
const cItem & a_HeldItem,
|
||||
const Vector3i a_ClickedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace
|
||||
) override
|
||||
{
|
||||
UNUSED(a_Item);
|
||||
UNUSED(a_BlockX);
|
||||
UNUSED(a_BlockZ);
|
||||
UNUSED(a_BlockFace);
|
||||
UNUSED(a_HeldItem);
|
||||
UNUSED(a_ClickedBlockFace);
|
||||
|
||||
// The map center is fixed at the central point of the 8x8 block of chunks you are standing in when you right-click it.
|
||||
|
||||
@ -40,22 +44,14 @@ public:
|
||||
int CenterX = FloorC(a_Player->GetPosX() / RegionWidth) * RegionWidth + (RegionWidth / 2);
|
||||
int CenterZ = FloorC(a_Player->GetPosZ() / RegionWidth) * RegionWidth + (RegionWidth / 2);
|
||||
|
||||
cMap * NewMap = a_World->GetMapManager().CreateMap(CenterX, CenterZ, DEFAULT_SCALE);
|
||||
|
||||
// Remove empty map from inventory
|
||||
if (!a_Player->GetInventory().RemoveOneEquippedItem())
|
||||
{
|
||||
ASSERT(!"Inventory mismatch");
|
||||
return true;
|
||||
}
|
||||
|
||||
auto NewMap = a_World->GetMapManager().CreateMap(CenterX, CenterZ, DEFAULT_SCALE);
|
||||
if (NewMap == nullptr)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
a_Player->GetInventory().AddItem(cItem(E_ITEM_MAP, 1, static_cast<short>(NewMap->GetID() & 0x7fff)));
|
||||
|
||||
// Replace map in the inventory:
|
||||
a_Player->ReplaceOneEquippedItemTossRest(cItem(E_ITEM_MAP, 1, static_cast<short>(NewMap->GetID() & 0x7fff)));
|
||||
return true;
|
||||
}
|
||||
} ;
|
||||
|
@ -8,46 +8,53 @@
|
||||
|
||||
|
||||
|
||||
class cItemEyeOfEnderHandler :
|
||||
class cItemEyeOfEnderHandler:
|
||||
public cItemThrowableHandler
|
||||
{
|
||||
typedef cItemThrowableHandler super;
|
||||
using Super = cItemThrowableHandler;
|
||||
|
||||
public:
|
||||
cItemEyeOfEnderHandler(void) :
|
||||
super(E_ITEM_EYE_OF_ENDER, cProjectileEntity::pkSnowball, 30)
|
||||
|
||||
cItemEyeOfEnderHandler():
|
||||
Super(E_ITEM_EYE_OF_ENDER, cProjectileEntity::pkSnowball, 30)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool OnItemUse(
|
||||
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
|
||||
const Vector3i a_ClickedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace
|
||||
) override
|
||||
{
|
||||
BLOCKTYPE FacingBlock;
|
||||
NIBBLETYPE FacingMeta;
|
||||
a_World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, FacingBlock, FacingMeta);
|
||||
switch (FacingBlock)
|
||||
// Try to fill an End Portal Frame block:
|
||||
if (a_ClickedBlockFace != BLOCK_FACE_NONE)
|
||||
{
|
||||
case E_BLOCK_END_PORTAL_FRAME:
|
||||
BLOCKTYPE FacingBlock;
|
||||
NIBBLETYPE FacingMeta;
|
||||
a_World->GetBlockTypeMeta(a_ClickedBlockPos, FacingBlock, FacingMeta);
|
||||
if (FacingBlock == E_BLOCK_END_PORTAL_FRAME)
|
||||
{
|
||||
// Fill the portal frame. E_META_END_PORTAL_EYE is the bit for holding the eye of ender.
|
||||
if ((FacingMeta & E_META_END_PORTAL_FRAME_EYE) != E_META_END_PORTAL_FRAME_EYE)
|
||||
{
|
||||
a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_END_PORTAL_FRAME, FacingMeta | E_META_END_PORTAL_FRAME_EYE);
|
||||
a_World->SetBlock(a_ClickedBlockPos, E_BLOCK_END_PORTAL_FRAME, FacingMeta | E_META_END_PORTAL_FRAME_EYE);
|
||||
if (!a_Player->IsGameModeCreative())
|
||||
{
|
||||
a_Player->GetInventory().RemoveOneEquippedItem();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
// TODO: Create projectile for Eye Of Ender
|
||||
// return cItemThrowableHandler::OnItemUse(a_World, a_Player, a_PluginInterface, a_Item, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Create projectile for Eye Of Ender
|
||||
// return Super::OnItemUse(a_World, a_Player, a_PluginInterface, a_Item, a_ClickedBlockPos, a_ClickedBlockFace);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -63,190 +63,36 @@ public:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool OnItemUse(
|
||||
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
|
||||
cWorld * a_World,
|
||||
cPlayer * a_Player,
|
||||
cBlockPluginInterface & a_PluginInterface,
|
||||
const cItem & a_HeldItem,
|
||||
const Vector3i a_ClickedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace
|
||||
) override
|
||||
{
|
||||
if (a_BlockFace != BLOCK_FACE_NONE)
|
||||
if (a_ClickedBlockFace != BLOCK_FACE_NONE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto & Random = GetRandomProvider();
|
||||
|
||||
if (a_Player->IsFishing())
|
||||
{
|
||||
cFloaterCallback FloaterInfo;
|
||||
a_World->DoWithEntityByID(a_Player->GetFloaterID(), FloaterInfo);
|
||||
a_Player->SetIsFishing(false);
|
||||
|
||||
if (FloaterInfo.IsAttached())
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
ReelIn(*a_World, *a_Player);
|
||||
}
|
||||
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();
|
||||
if (!FloaterPtr->Initialize(std::move(Floater), *a_World))
|
||||
{
|
||||
@ -256,4 +102,206 @@ public:
|
||||
}
|
||||
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
|
||||
{
|
||||
using Super = cItemHandler;
|
||||
|
||||
public:
|
||||
cItemFlowerPotHandler(int a_ItemType) :
|
||||
cItemHandler(a_ItemType)
|
||||
|
||||
cItemFlowerPotHandler(int a_ItemType):
|
||||
Super(a_ItemType)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool IsPlaceable(void) override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool GetPlacementBlockTypeMeta(
|
||||
cWorld * a_World, cPlayer * a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
const Vector3i a_PlacedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||
) override
|
||||
{
|
||||
|
@ -346,41 +346,44 @@ cItemHandler::cItemHandler(int a_ItemType)
|
||||
|
||||
|
||||
bool cItemHandler::OnPlayerPlace(
|
||||
cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ
|
||||
cWorld & a_World,
|
||||
cPlayer & a_Player,
|
||||
const cItem & a_EquippedItem,
|
||||
const Vector3i a_ClickedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos
|
||||
)
|
||||
{
|
||||
if (a_BlockFace < 0)
|
||||
if (a_ClickedBlockFace == BLOCK_FACE_NONE)
|
||||
{
|
||||
// Clicked in air
|
||||
// Clicked in the air, no placement possible
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((a_BlockY < 0) || (a_BlockY >= cChunkDef::Height))
|
||||
if (!cChunkDef::IsValidHeight(a_ClickedBlockPos.y))
|
||||
{
|
||||
// The clicked block is outside the world, ignore this call altogether (#128)
|
||||
return false;
|
||||
}
|
||||
|
||||
BLOCKTYPE ClickedBlock;
|
||||
BLOCKTYPE ClickedBlockType;
|
||||
NIBBLETYPE ClickedBlockMeta;
|
||||
|
||||
a_World.GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, ClickedBlock, ClickedBlockMeta);
|
||||
a_World.GetBlockTypeMeta(a_ClickedBlockPos, ClickedBlockType, ClickedBlockMeta);
|
||||
cChunkInterface ChunkInterface(a_World.GetChunkMap());
|
||||
|
||||
// Check if the block ignores build collision (water, grass etc.):
|
||||
auto blockHandler = BlockHandler(ClickedBlock);
|
||||
Vector3i absPos(a_BlockX, a_BlockY, a_BlockZ);
|
||||
if (blockHandler->DoesIgnoreBuildCollision(ChunkInterface, absPos, a_Player, ClickedBlockMeta))
|
||||
auto HandlerB = BlockHandler(ClickedBlockType);
|
||||
auto PlacedBlockPos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace);
|
||||
if (HandlerB->DoesIgnoreBuildCollision(ChunkInterface, a_ClickedBlockPos, a_Player, ClickedBlockMeta))
|
||||
{
|
||||
a_World.DropBlockAsPickups(absPos, &a_Player, nullptr);
|
||||
// Replace the clicked block:
|
||||
a_World.DropBlockAsPickups(a_ClickedBlockPos, &a_Player, nullptr);
|
||||
PlacedBlockPos = a_ClickedBlockPos;
|
||||
}
|
||||
else
|
||||
{
|
||||
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
|
||||
|
||||
if ((a_BlockY < 0) || (a_BlockY >= cChunkDef::Height))
|
||||
if (!cChunkDef::IsValidHeight(PlacedBlockPos.y))
|
||||
{
|
||||
// The block is being placed outside the world, ignore this packet altogether (#128)
|
||||
return false;
|
||||
@ -388,11 +391,11 @@ bool cItemHandler::OnPlayerPlace(
|
||||
|
||||
NIBBLETYPE PlaceMeta;
|
||||
BLOCKTYPE PlaceBlock;
|
||||
a_World.GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, PlaceBlock, PlaceMeta);
|
||||
a_World.GetBlockTypeMeta(PlacedBlockPos, PlaceBlock, PlaceMeta);
|
||||
|
||||
// Clicked on side of block, make sure that placement won't be cancelled if there is a slab able to be double slabbed.
|
||||
// No need to do combinability (dblslab) checks, client will do that here.
|
||||
if (!BlockHandler(PlaceBlock)->DoesIgnoreBuildCollision(ChunkInterface, { a_BlockX, a_BlockY, a_BlockZ }, a_Player, PlaceMeta))
|
||||
if (!BlockHandler(PlaceBlock)->DoesIgnoreBuildCollision(ChunkInterface, PlacedBlockPos, a_Player, PlaceMeta))
|
||||
{
|
||||
// Tried to place a block into another?
|
||||
// Happens when you place a block aiming at side of block with a torch on it or stem beside it
|
||||
@ -402,14 +405,15 @@ bool cItemHandler::OnPlayerPlace(
|
||||
|
||||
// Get all the blocks to place:
|
||||
sSetBlockVector blocks;
|
||||
if (!GetBlocksToPlace(a_World, a_Player, a_EquippedItem, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, blocks))
|
||||
if (!GetBlocksToPlace(a_World, a_Player, a_EquippedItem, PlacedBlockPos, a_ClickedBlockFace, a_CursorPos, blocks))
|
||||
{
|
||||
// Handler refused the placement, send that information back to the client:
|
||||
for (const auto & blk: blocks)
|
||||
{
|
||||
a_World.SendBlockTo(blk.GetX(), blk.GetY(), blk.GetZ(), a_Player);
|
||||
const auto & AbsPos = blk.GetAbsolutePos();
|
||||
a_World.SendBlockTo(AbsPos, a_Player);
|
||||
}
|
||||
a_World.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
|
||||
a_World.SendBlockTo(PlacedBlockPos, a_Player);
|
||||
a_Player.GetInventory().SendEquippedSlot();
|
||||
return false;
|
||||
}
|
||||
@ -436,18 +440,19 @@ bool cItemHandler::OnPlayerPlace(
|
||||
|
||||
bool cItemHandler::GetBlocksToPlace(
|
||||
cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
const Vector3i a_PlacedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
sSetBlockVector & a_BlocksToSet
|
||||
)
|
||||
{
|
||||
BLOCKTYPE BlockType;
|
||||
NIBBLETYPE BlockMeta;
|
||||
if (!GetPlacementBlockTypeMeta(&a_World, &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta))
|
||||
if (!GetPlacementBlockTypeMeta(&a_World, &a_Player, a_PlacedBlockPos, a_ClickedBlockFace, a_CursorPos, BlockType, BlockMeta))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
a_BlocksToSet.emplace_back(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta);
|
||||
a_BlocksToSet.emplace_back(a_PlacedBlockPos, BlockType, BlockMeta);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -457,17 +462,15 @@ bool cItemHandler::GetBlocksToPlace(
|
||||
|
||||
bool cItemHandler::OnItemUse(
|
||||
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
|
||||
const Vector3i a_ClickedBlockPos, eBlockFace a_ClickedBlockFace
|
||||
)
|
||||
{
|
||||
UNUSED(a_World);
|
||||
UNUSED(a_Player);
|
||||
UNUSED(a_PluginInterface);
|
||||
UNUSED(a_Item);
|
||||
UNUSED(a_BlockX);
|
||||
UNUSED(a_BlockY);
|
||||
UNUSED(a_BlockZ);
|
||||
UNUSED(a_BlockFace);
|
||||
UNUSED(a_ClickedBlockPos);
|
||||
UNUSED(a_ClickedBlockFace);
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -476,15 +479,19 @@ bool cItemHandler::OnItemUse(
|
||||
|
||||
|
||||
|
||||
bool cItemHandler::OnDiggingBlock(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir)
|
||||
bool cItemHandler::OnDiggingBlock(
|
||||
cWorld * a_World,
|
||||
cPlayer * a_Player,
|
||||
const cItem & a_HeldItem,
|
||||
const Vector3i a_ClickedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace
|
||||
)
|
||||
{
|
||||
UNUSED(a_World);
|
||||
UNUSED(a_Player);
|
||||
UNUSED(a_Item);
|
||||
UNUSED(a_BlockX);
|
||||
UNUSED(a_BlockY);
|
||||
UNUSED(a_BlockZ);
|
||||
UNUSED(a_Dir);
|
||||
UNUSED(a_HeldItem);
|
||||
UNUSED(a_ClickedBlockPos);
|
||||
UNUSED(a_ClickedBlockFace);
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -815,8 +822,8 @@ bool cItemHandler::CanHarvestBlock(BLOCKTYPE a_BlockType)
|
||||
|
||||
bool cItemHandler::GetPlacementBlockTypeMeta(
|
||||
cWorld * a_World, cPlayer * a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
const Vector3i a_PlacedBlockPos, eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||
)
|
||||
{
|
||||
@ -832,8 +839,8 @@ bool cItemHandler::GetPlacementBlockTypeMeta(
|
||||
cChunkInterface ChunkInterface(a_World->GetChunkMap());
|
||||
return BlockH->GetPlacementBlockTypeMeta(
|
||||
ChunkInterface, *a_Player,
|
||||
a_BlockX, a_BlockY, a_BlockZ, a_BlockFace,
|
||||
a_CursorX, a_CursorY, a_CursorZ,
|
||||
a_PlacedBlockPos, a_ClickedBlockFace,
|
||||
a_CursorPos,
|
||||
a_BlockType, a_BlockMeta
|
||||
);
|
||||
}
|
||||
|
@ -38,28 +38,39 @@ public:
|
||||
|
||||
|
||||
/** Called when the player tries to place the item (right mouse button, IsPlaceable() == true).
|
||||
The block coords are for the block that has been clicked.
|
||||
a_ClickedBlockPos is the (neighbor) block that has been clicked to place this item.
|
||||
a_ClickedBlockFace is the face of the neighbor that has been clicked to place this item.
|
||||
a_CursorPos is the position of the player's cursor within a_ClickedBlockFace.
|
||||
The default handler uses GetBlocksToPlace() and places the returned blocks.
|
||||
Override if the item needs advanced processing, such as spawning a mob based on the blocks being placed.
|
||||
If the block placement is refused inside this call, it will automatically revert the client-side changes.
|
||||
Returns true if the placement succeeded, false if the placement was aborted for any reason. */
|
||||
virtual bool OnPlayerPlace(
|
||||
cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ
|
||||
cWorld & a_World,
|
||||
cPlayer & a_Player,
|
||||
const cItem & a_EquippedItem,
|
||||
const Vector3i a_ClickedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos
|
||||
);
|
||||
|
||||
|
||||
/** Called from OnPlayerPlace() to determine the blocks that the current placement operation should set.
|
||||
The block coords are where the new (main) block should be placed.
|
||||
a_PlacedBlockPos points to the location where the new block should be set.
|
||||
a_ClickedBlockFace is the block face of the neighbor that was clicked to place this block.
|
||||
a_CursorPos is the position of the mouse cursor within the clicked (neighbor's) block face.
|
||||
The blocks in a_BlocksToPlace will be sent through cPlayer::PlaceBlocks() after returning from this function.
|
||||
The default handler uses GetPlacementBlockTypeMeta() and provides that as the single block at the specified coords.
|
||||
Returns true if the placement succeeded, false if the placement was aborted for any reason.
|
||||
If aborted, the server then sends all original blocks in the coords provided in a_BlocksToSet to the client. */
|
||||
virtual bool GetBlocksToPlace(
|
||||
cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
sSetBlockVector & a_BlocksToSet
|
||||
cWorld & a_World,
|
||||
cPlayer & a_Player,
|
||||
const cItem & a_EquippedItem,
|
||||
const Vector3i a_PlacedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
sSetBlockVector & a_BlocksToPlace
|
||||
);
|
||||
|
||||
|
||||
@ -68,26 +79,29 @@ public:
|
||||
Returns true to allow placement, false to refuse. */
|
||||
virtual bool GetPlacementBlockTypeMeta(
|
||||
cWorld * a_World, cPlayer * a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
const Vector3i a_PlacedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||
);
|
||||
|
||||
|
||||
/** Called when the player tries to use the item (right mouse button).
|
||||
Return false to abort the usage. DEFAULT: False */
|
||||
Descendants can return false to abort the usage (default behavior). */
|
||||
virtual bool OnItemUse(
|
||||
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
|
||||
cWorld * a_World,
|
||||
cPlayer * a_Player,
|
||||
cBlockPluginInterface & a_PluginInterface,
|
||||
const cItem & a_HeldItem,
|
||||
const Vector3i a_ClickedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace
|
||||
);
|
||||
|
||||
|
||||
/** Called when the client sends the SHOOT status in the lclk packet */
|
||||
virtual void OnItemShoot(cPlayer *, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace)
|
||||
/** Called when the client sends the SHOOT status in the lclk packet (releasing the bow). */
|
||||
virtual void OnItemShoot(cPlayer *, const Vector3i a_BlockPos, eBlockFace a_BlockFace)
|
||||
{
|
||||
UNUSED(a_BlockX);
|
||||
UNUSED(a_BlockY);
|
||||
UNUSED(a_BlockZ);
|
||||
UNUSED(a_BlockPos);
|
||||
UNUSED(a_BlockFace);
|
||||
}
|
||||
|
||||
@ -100,9 +114,13 @@ public:
|
||||
}
|
||||
|
||||
/** Called while the player digs a block using this item */
|
||||
virtual bool OnDiggingBlock(cWorld * a_World, cPlayer * a_Player, const cItem & a_HeldItem, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace);
|
||||
virtual bool OnDiggingBlock(
|
||||
cWorld * a_World, cPlayer * a_Player, const cItem & a_HeldItem,
|
||||
const Vector3i a_ClickedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace
|
||||
);
|
||||
|
||||
/** Called when a player attacks a other entity. */
|
||||
/** Called when a player attacks an entity with this item in hand. */
|
||||
virtual void OnEntityAttack(cPlayer * a_Attacker, cEntity * a_AttackedEntity);
|
||||
|
||||
/** Called after the player has eaten this item. */
|
||||
|
@ -9,64 +9,68 @@
|
||||
|
||||
|
||||
|
||||
class cItemHoeHandler :
|
||||
class cItemHoeHandler:
|
||||
public cItemHandler
|
||||
{
|
||||
using Super = cItemHandler;
|
||||
|
||||
public:
|
||||
cItemHoeHandler(int a_ItemType)
|
||||
: cItemHandler(a_ItemType)
|
||||
|
||||
cItemHoeHandler(int a_ItemType):
|
||||
Super(a_ItemType)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool OnItemUse(
|
||||
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
|
||||
cWorld * a_World,
|
||||
cPlayer * a_Player,
|
||||
cBlockPluginInterface & a_PluginInterface,
|
||||
const cItem & a_HeldItem,
|
||||
const Vector3i a_ClickedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace
|
||||
) override
|
||||
{
|
||||
if ((a_BlockFace == BLOCK_FACE_NONE) || (a_BlockY >= cChunkDef::Height))
|
||||
if ((a_ClickedBlockFace == BLOCK_FACE_NONE) || (a_ClickedBlockPos.y >= cChunkDef::Height))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
BLOCKTYPE UpperBlock = a_World->GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ);
|
||||
|
||||
BLOCKTYPE Block;
|
||||
NIBBLETYPE BlockMeta;
|
||||
a_World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, Block, BlockMeta);
|
||||
|
||||
if (((Block == E_BLOCK_DIRT) || (Block == E_BLOCK_GRASS)) && (UpperBlock == E_BLOCK_AIR))
|
||||
// Need air above the hoe-d block to transform it:
|
||||
BLOCKTYPE UpperBlockType = a_World->GetBlock(a_ClickedBlockPos.addedY(1));
|
||||
if (UpperBlockType != E_BLOCK_AIR)
|
||||
{
|
||||
BLOCKTYPE NewBlock = E_BLOCK_FARMLAND;
|
||||
if (Block == E_BLOCK_DIRT)
|
||||
{
|
||||
switch (BlockMeta)
|
||||
{
|
||||
case E_META_DIRT_COARSE:
|
||||
{
|
||||
// Transform to normal dirt
|
||||
NewBlock = E_BLOCK_DIRT;
|
||||
break;
|
||||
}
|
||||
case E_META_DIRT_PODZOL:
|
||||
{
|
||||
// You can't transform this block with a hoe in vanilla
|
||||
return false;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, NewBlock, 0);
|
||||
a_World->BroadcastSoundEffect("item.hoe.till", {a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5}, 1.0f, 0.8f);
|
||||
a_Player->UseEquippedItem();
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
// 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
|
||||
{
|
||||
switch (a_Action)
|
||||
|
@ -9,51 +9,59 @@
|
||||
|
||||
|
||||
|
||||
class cItemItemFrameHandler :
|
||||
class cItemItemFrameHandler:
|
||||
public cItemHandler
|
||||
{
|
||||
public:
|
||||
cItemItemFrameHandler(int a_ItemType)
|
||||
: cItemHandler(a_ItemType)
|
||||
{
|
||||
using Super = cItemHandler;
|
||||
|
||||
public:
|
||||
|
||||
cItemItemFrameHandler(int a_ItemType):
|
||||
Super(a_ItemType)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool OnItemUse(
|
||||
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
|
||||
cWorld * a_World,
|
||||
cPlayer * a_Player,
|
||||
cBlockPluginInterface & a_PluginInterface,
|
||||
const cItem & a_HeldItem,
|
||||
const Vector3i a_ClickedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace
|
||||
) override
|
||||
{
|
||||
if ((a_BlockFace == BLOCK_FACE_NONE) || (a_BlockFace == BLOCK_FACE_YP) || (a_BlockFace == BLOCK_FACE_YM))
|
||||
// Can only place on a side face:
|
||||
if ((a_ClickedBlockFace == BLOCK_FACE_NONE) || (a_ClickedBlockFace == BLOCK_FACE_YP) || (a_ClickedBlockFace == BLOCK_FACE_YM))
|
||||
{
|
||||
// Client sends this if clicked on top or bottom face
|
||||
return false;
|
||||
}
|
||||
|
||||
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); // Make sure block that will be occupied is free
|
||||
BLOCKTYPE Block = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
|
||||
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, true); // We want the clicked block, so go back again
|
||||
|
||||
if (Block == E_BLOCK_AIR)
|
||||
// Make sure block that will be occupied by the item frame is free now:
|
||||
auto PlacePos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace);
|
||||
BLOCKTYPE Block = a_World->GetBlock(PlacePos);
|
||||
if (Block != E_BLOCK_AIR)
|
||||
{
|
||||
auto ItemFrame = cpp14::make_unique<cItemFrame>(a_BlockFace, Vector3i{a_BlockX, a_BlockY, a_BlockZ});
|
||||
auto ItemFramePtr = ItemFrame.get();
|
||||
if (!ItemFramePtr->Initialize(std::move(ItemFrame), *a_World))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!a_Player->IsGameModeCreative())
|
||||
{
|
||||
a_Player->GetInventory().RemoveOneEquippedItem();
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
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(
|
||||
cWorld * a_World, cPlayer * a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
const Vector3i a_PlacedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||
) override
|
||||
{
|
||||
bool res = Super::GetPlacementBlockTypeMeta(
|
||||
a_World, a_Player,
|
||||
a_BlockX, a_BlockY, a_BlockZ, a_BlockFace,
|
||||
a_CursorX, a_CursorY, a_CursorZ,
|
||||
a_PlacedBlockPos,
|
||||
a_ClickedBlockFace,
|
||||
a_CursorPos,
|
||||
a_BlockType, a_BlockMeta
|
||||
);
|
||||
a_BlockMeta = a_BlockMeta | 0x4; // 0x4 bit set means this is a player-placed leaves block, not to be decayed
|
||||
|
@ -9,23 +9,32 @@
|
||||
|
||||
|
||||
|
||||
class cItemLighterHandler :
|
||||
class cItemLighterHandler:
|
||||
public cItemHandler
|
||||
{
|
||||
using Super = cItemHandler;
|
||||
|
||||
public:
|
||||
cItemLighterHandler(int a_ItemType) :
|
||||
cItemHandler(a_ItemType)
|
||||
|
||||
cItemLighterHandler(int a_ItemType):
|
||||
Super(a_ItemType)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool OnItemUse(
|
||||
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
|
||||
cWorld * a_World,
|
||||
cPlayer * a_Player,
|
||||
cBlockPluginInterface & a_PluginInterface,
|
||||
const cItem & a_HeldItem,
|
||||
const Vector3i a_ClickedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace
|
||||
) override
|
||||
{
|
||||
if (a_BlockFace < 0)
|
||||
if (a_ClickedBlockFace < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -51,27 +60,27 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
switch (a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ))
|
||||
switch (a_World->GetBlock(a_ClickedBlockPos))
|
||||
{
|
||||
case E_BLOCK_TNT:
|
||||
{
|
||||
// Activate the TNT:
|
||||
a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
|
||||
a_World->SpawnPrimedTNT({a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5}); // 80 ticks to boom
|
||||
a_World->SetBlock(a_ClickedBlockPos, E_BLOCK_AIR, 0);
|
||||
a_World->SpawnPrimedTNT(Vector3d(a_ClickedBlockPos) + Vector3d(0.5, 0.5, 0.5)); // 80 ticks to boom
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
// Light a fire next to / on top of the block if air:
|
||||
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
|
||||
if ((a_BlockY < 0) || (a_BlockY >= cChunkDef::Height))
|
||||
auto FirePos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace);
|
||||
if (!cChunkDef::IsValidHeight(FirePos.y))
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_AIR)
|
||||
if (a_World->GetBlock(FirePos) == E_BLOCK_AIR)
|
||||
{
|
||||
a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_FIRE, 0);
|
||||
a_World->BroadcastSoundEffect("item.flintandsteel.use", Vector3d(a_BlockX, a_BlockY, a_BlockZ), 1.0F, 1.04F);
|
||||
a_World->SetBlock(FirePos, E_BLOCK_FIRE, 0);
|
||||
a_World->BroadcastSoundEffect("item.flintandsteel.use", FirePos, 1.0f, 1.04f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,9 @@ public:
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool IsPlaceable(void) override
|
||||
{
|
||||
return false; // Set as not placeable so OnItemUse is called
|
||||
@ -30,16 +33,22 @@ public:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool OnItemUse(
|
||||
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
|
||||
cWorld * a_World,
|
||||
cPlayer * a_Player,
|
||||
cBlockPluginInterface & a_PluginInterface,
|
||||
const cItem & a_HeldItem,
|
||||
const Vector3i a_ClickedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace
|
||||
) override
|
||||
{
|
||||
if (a_BlockFace > BLOCK_FACE_NONE)
|
||||
if (a_ClickedBlockFace > BLOCK_FACE_NONE)
|
||||
{
|
||||
// Clicked on the side of a submerged block; vanilla allows placement, so should we
|
||||
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
|
||||
a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_LILY_PAD, 0);
|
||||
// Clicked on a face of a submerged block; vanilla allows placement, so should we
|
||||
auto PlacePos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace);
|
||||
a_World->SetBlock(PlacePos, E_BLOCK_LILY_PAD, 0);
|
||||
if (!a_Player->IsGameModeCreative())
|
||||
{
|
||||
a_Player->GetInventory().RemoveOneEquippedItem();
|
||||
@ -47,12 +56,12 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
class cCallbacks :
|
||||
class cCallbacks:
|
||||
public cBlockTracer::cCallbacks
|
||||
{
|
||||
public:
|
||||
|
||||
cCallbacks(void) :
|
||||
cCallbacks():
|
||||
m_HasHitFluid(false)
|
||||
{
|
||||
}
|
||||
@ -84,18 +93,14 @@ public:
|
||||
Vector3i m_Pos;
|
||||
bool m_HasHitFluid;
|
||||
|
||||
};
|
||||
|
||||
cCallbacks Callbacks;
|
||||
cLineBlockTracer Tracer(*a_Player->GetWorld(), Callbacks);
|
||||
Vector3d Start(a_Player->GetEyePosition() + a_Player->GetLookVector());
|
||||
Vector3d End(a_Player->GetEyePosition() + a_Player->GetLookVector() * 5);
|
||||
|
||||
Tracer.Trace(Start.x, Start.y, Start.z, End.x, End.y, End.z);
|
||||
} Callbacks;
|
||||
auto Start = a_Player->GetEyePosition() + a_Player->GetLookVector();
|
||||
auto End = a_Player->GetEyePosition() + a_Player->GetLookVector() * 5;
|
||||
cLineBlockTracer::Trace(*a_Player->GetWorld(), Callbacks, Start.x, Start.y, Start.z, End.x, End.y, End.z);
|
||||
|
||||
if (Callbacks.m_HasHitFluid)
|
||||
{
|
||||
a_World->SetBlock(Callbacks.m_Pos.x, Callbacks.m_Pos.y, Callbacks.m_Pos.z, E_BLOCK_LILY_PAD, 0);
|
||||
a_World->SetBlock(Callbacks.m_Pos, E_BLOCK_LILY_PAD, 0);
|
||||
if (!a_Player->IsGameModeCreative())
|
||||
{
|
||||
a_Player->GetInventory().RemoveOneEquippedItem();
|
||||
|
@ -1,8 +1,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../Entities/Minecart.h"
|
||||
|
||||
|
||||
|
||||
|
||||
@ -21,18 +19,25 @@ public:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool OnItemUse(
|
||||
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
|
||||
cWorld * a_World,
|
||||
cPlayer * a_Player,
|
||||
cBlockPluginInterface & a_PluginInterface,
|
||||
const cItem & a_HeldItem,
|
||||
const Vector3i a_ClickedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace
|
||||
) override
|
||||
{
|
||||
if (a_BlockFace < 0)
|
||||
// Must be used on a block
|
||||
if (a_ClickedBlockFace < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that there's rail in there:
|
||||
BLOCKTYPE Block = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
|
||||
BLOCKTYPE Block = a_World->GetBlock(a_ClickedBlockPos);
|
||||
switch (Block)
|
||||
{
|
||||
case E_BLOCK_MINECART_TRACKS:
|
||||
@ -50,15 +55,14 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
double x = static_cast<double>(a_BlockX) + 0.5;
|
||||
double y = static_cast<double>(a_BlockY) + 0.5;
|
||||
double z = static_cast<double>(a_BlockZ) + 0.5;
|
||||
|
||||
if (a_World->SpawnMinecart(x, y, z, m_ItemType) == cEntity::INVALID_ID)
|
||||
// Spawn the minecart:
|
||||
auto SpawnPos = Vector3d(a_ClickedBlockPos) + Vector3d(0.5, 0.5, 0.5);
|
||||
if (a_World->SpawnMinecart(SpawnPos, m_ItemType) == cEntity::INVALID_ID)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove the item from inventory:
|
||||
if (!a_Player->IsGameModeCreative())
|
||||
{
|
||||
a_Player->GetInventory().RemoveOneEquippedItem();
|
||||
|
@ -22,52 +22,60 @@ public:
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool OnPlayerPlace(
|
||||
cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ
|
||||
cWorld & a_World,
|
||||
cPlayer & a_Player,
|
||||
const cItem & a_EquippedItem,
|
||||
const Vector3i a_ClickedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos
|
||||
) override
|
||||
{
|
||||
// Cannot place a head at "no face" and from the bottom:
|
||||
if ((a_BlockFace == BLOCK_FACE_NONE) || (a_BlockFace == BLOCK_FACE_BOTTOM))
|
||||
if ((a_ClickedBlockFace == BLOCK_FACE_NONE) || (a_ClickedBlockFace == BLOCK_FACE_BOTTOM))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
auto placedX = a_BlockX, placedY = a_BlockY, placedZ = a_BlockZ;
|
||||
AddFaceDirection(placedY, placedY, placedZ, a_BlockFace);
|
||||
const auto PlacePos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace);
|
||||
|
||||
// If the placed head is a wither, try to spawn the wither first:
|
||||
if (a_EquippedItem.m_ItemDamage == E_META_HEAD_WITHER)
|
||||
{
|
||||
if (TrySpawnWitherAround(a_World, a_Player, {placedX, placedY, placedZ}))
|
||||
if (TrySpawnWitherAround(a_World, a_Player, PlacePos))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// Wither not created, proceed with regular head placement
|
||||
}
|
||||
|
||||
cItem itemCopy(a_EquippedItem); // Make a copy in case this is the player's last head item and OnPlayerPlace removes it
|
||||
if (!Super::OnPlayerPlace(a_World, a_Player, a_EquippedItem, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ))
|
||||
cItem ItemCopy(a_EquippedItem); // Make a copy in case this is the player's last head item and OnPlayerPlace removes it
|
||||
if (!Super::OnPlayerPlace(a_World, a_Player, a_EquippedItem, a_ClickedBlockPos, a_ClickedBlockFace, a_CursorPos))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
RegularHeadPlaced(a_World, a_Player, itemCopy, placedX, placedY, placedZ, a_BlockFace);
|
||||
RegularHeadPlaced(a_World, a_Player, ItemCopy, PlacePos, a_ClickedBlockFace);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Called after placing a regular head block with no mob spawning.
|
||||
Adjusts the mob head entity based on the equipped item's data. */
|
||||
void RegularHeadPlaced(
|
||||
cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
|
||||
const Vector3i a_PlacePos, eBlockFace a_ClickedBlockFace
|
||||
)
|
||||
{
|
||||
auto HeadType = static_cast<eMobHeadType>(a_EquippedItem.m_ItemDamage);
|
||||
auto BlockMeta = static_cast<NIBBLETYPE>(a_BlockFace);
|
||||
auto BlockMeta = static_cast<NIBBLETYPE>(a_ClickedBlockFace);
|
||||
|
||||
// Use a callback to set the properties of the mob head block entity:
|
||||
a_World.DoWithBlockEntityAt(a_BlockX, a_BlockY, a_BlockZ, [&](cBlockEntity & a_BlockEntity)
|
||||
a_World.DoWithBlockEntityAt(a_PlacePos.x, a_PlacePos.y, a_PlacePos.z, [&](cBlockEntity & a_BlockEntity)
|
||||
{
|
||||
if (a_BlockEntity.GetBlockType() != E_BLOCK_HEAD)
|
||||
{
|
||||
@ -90,11 +98,14 @@ public:
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Spawns a wither if the wither skull placed at the specified coords completes wither's spawning formula.
|
||||
Returns true if the wither was created. */
|
||||
bool TrySpawnWitherAround(
|
||||
cWorld & a_World, cPlayer & a_Player,
|
||||
Vector3i a_BlockPos
|
||||
const Vector3i a_BlockPos
|
||||
)
|
||||
{
|
||||
// No wither can be created at Y < 2 - not enough space for the formula:
|
||||
@ -183,6 +194,9 @@ public:
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Tries to spawn a wither from the specified image at the specified offset from the placed head block.
|
||||
PlacedHead coords are used to override the block query - at those coords the block is not queried from the world,
|
||||
but assumed to be a head instead.
|
||||
@ -265,6 +279,9 @@ public:
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Awards the achievement to all players close to the specified point. */
|
||||
void AwardSpawnWitherAchievement(cWorld & a_World, Vector3i a_BlockPos)
|
||||
{
|
||||
@ -283,6 +300,9 @@ public:
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Converts the block face of the placement (which face of the block was clicked to place the head)
|
||||
into the block's metadata value. */
|
||||
static NIBBLETYPE BlockFaceToBlockMeta(int a_BlockFace)
|
||||
@ -303,21 +323,28 @@ public:
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool IsPlaceable(void) override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool GetPlacementBlockTypeMeta(
|
||||
cWorld * a_World, cPlayer * a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
const Vector3i a_PlacedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||
) override
|
||||
{
|
||||
a_BlockType = E_BLOCK_HEAD;
|
||||
a_BlockMeta = BlockFaceToBlockMeta(a_BlockFace);
|
||||
a_BlockMeta = BlockFaceToBlockMeta(a_ClickedBlockFace);
|
||||
return true;
|
||||
}
|
||||
} ;
|
||||
|
@ -8,47 +8,53 @@
|
||||
|
||||
|
||||
|
||||
class cItemNetherWartHandler :
|
||||
class cItemNetherWartHandler:
|
||||
public cItemHandler
|
||||
{
|
||||
public:
|
||||
cItemNetherWartHandler(int a_ItemType) :
|
||||
cItemHandler(a_ItemType)
|
||||
{
|
||||
using Super = cItemHandler;
|
||||
|
||||
public:
|
||||
|
||||
cItemNetherWartHandler(int a_ItemType):
|
||||
Super(a_ItemType)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool IsPlaceable(void) override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool GetPlacementBlockTypeMeta(
|
||||
cWorld * a_World, cPlayer * a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
const Vector3i a_PlacedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||
) override
|
||||
{
|
||||
if (a_BlockFace != BLOCK_FACE_TOP)
|
||||
// Only allow planting nether wart onto the top side of the block:
|
||||
if (a_ClickedBlockFace != BLOCK_FACE_TOP)
|
||||
{
|
||||
// Only allow planting nether wart from the top side of the block
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only allow placement on farmland
|
||||
int X = a_BlockX;
|
||||
int Y = a_BlockY;
|
||||
int Z = a_BlockZ;
|
||||
AddFaceDirection(X, Y, Z, a_BlockFace, true);
|
||||
if (a_World->GetBlock(X, Y, Z) != E_BLOCK_SOULSAND)
|
||||
// Only allow placement on soulsand
|
||||
if ((a_PlacedBlockPos.y < 1) || (a_World->GetBlock(a_PlacedBlockPos.addedY(-1)) != E_BLOCK_SOULSAND))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
a_BlockMeta = 0;
|
||||
a_BlockType = E_BLOCK_NETHER_WART;
|
||||
|
||||
return true;
|
||||
}
|
||||
} ;
|
||||
|
@ -10,82 +10,93 @@
|
||||
|
||||
|
||||
|
||||
class cItemPaintingHandler :
|
||||
class cItemPaintingHandler:
|
||||
public cItemHandler
|
||||
{
|
||||
using Super = cItemHandler;
|
||||
|
||||
public:
|
||||
cItemPaintingHandler(int a_ItemType)
|
||||
: cItemHandler(a_ItemType)
|
||||
|
||||
cItemPaintingHandler(int a_ItemType):
|
||||
Super(a_ItemType)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool OnItemUse(
|
||||
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
|
||||
cWorld * a_World,
|
||||
cPlayer * a_Player,
|
||||
cBlockPluginInterface & a_PluginInterface,
|
||||
const cItem & a_HeldItem,
|
||||
const Vector3i a_ClickedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace
|
||||
) override
|
||||
{
|
||||
if ((a_BlockFace == BLOCK_FACE_NONE) || (a_BlockFace == BLOCK_FACE_YM) || (a_BlockFace == BLOCK_FACE_YP))
|
||||
// Paintings can't be flatly placed:
|
||||
if (
|
||||
(a_ClickedBlockFace == BLOCK_FACE_NONE) ||
|
||||
(a_ClickedBlockFace == BLOCK_FACE_YM) ||
|
||||
(a_ClickedBlockFace == BLOCK_FACE_YP)
|
||||
)
|
||||
{
|
||||
// Paintings can't be flatly placed
|
||||
return false;
|
||||
}
|
||||
|
||||
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); // Make sure block that will be occupied is free
|
||||
BLOCKTYPE Block = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
|
||||
|
||||
if (Block == E_BLOCK_AIR)
|
||||
// Make sure block that will be occupied is free:
|
||||
auto PlacePos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace);
|
||||
BLOCKTYPE PlaceBlockType = a_World->GetBlock(PlacePos);
|
||||
if (PlaceBlockType != E_BLOCK_AIR)
|
||||
{
|
||||
static const struct // Define all the possible painting titles
|
||||
{
|
||||
AString Title;
|
||||
} gPaintingTitlesList[] =
|
||||
{
|
||||
{ "Kebab" },
|
||||
{ "Aztec" },
|
||||
{ "Alban" },
|
||||
{ "Aztec2" },
|
||||
{ "Bomb" },
|
||||
{ "Plant" },
|
||||
{ "Wasteland" },
|
||||
{ "Wanderer" },
|
||||
{ "Graham" },
|
||||
{ "Pool" },
|
||||
{ "Courbet" },
|
||||
{ "Sunset" },
|
||||
{ "Sea" },
|
||||
{ "Creebet" },
|
||||
{ "Match" },
|
||||
{ "Bust" },
|
||||
{ "Stage" },
|
||||
{ "Void" },
|
||||
{ "SkullAndRoses" },
|
||||
{ "Wither" },
|
||||
{ "Fighters" },
|
||||
{ "Skeleton" },
|
||||
{ "DonkeyKong" },
|
||||
{ "Pointer" },
|
||||
{ "Pigscene" },
|
||||
{ "BurningSkull" }
|
||||
};
|
||||
|
||||
auto Painting = cpp14::make_unique<cPainting>(gPaintingTitlesList[a_World->GetTickRandomNumber(ARRAYCOUNT(gPaintingTitlesList) - 1)].Title, a_BlockFace, Vector3i{a_BlockX, a_BlockY, a_BlockZ});
|
||||
auto PaintingPtr = Painting.get();
|
||||
if (!PaintingPtr->Initialize(std::move(Painting), *a_World))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!a_Player->IsGameModeCreative())
|
||||
{
|
||||
a_Player->GetInventory().RemoveOneEquippedItem();
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
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:
|
||||
virtual bool IsDrinkable(short a_ItemDamage) override
|
||||
{
|
||||
@ -26,12 +29,19 @@ public:
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool OnItemUse(
|
||||
cWorld * a_World, cPlayer * a_Player, cBlockPluginInterface & a_PluginInterface, const cItem & a_Item,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
|
||||
cWorld * a_World,
|
||||
cPlayer * a_Player,
|
||||
cBlockPluginInterface & a_PluginInterface,
|
||||
const cItem & a_HeldItem,
|
||||
const Vector3i a_ClickedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace
|
||||
) override
|
||||
{
|
||||
short PotionDamage = a_Item.m_ItemDamage;
|
||||
short PotionDamage = a_HeldItem.m_ItemDamage;
|
||||
|
||||
// Do not throw non-splash potions:
|
||||
if (cEntityEffect::IsPotionDrinkable(PotionDamage))
|
||||
@ -59,6 +69,9 @@ public:
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool EatItem(cPlayer * a_Player, cItem * a_Item) override
|
||||
{
|
||||
short PotionDamage = a_Item->m_ItemDamage;
|
||||
|
@ -20,44 +20,50 @@ public:
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool OnPlayerPlace(
|
||||
cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ
|
||||
cWorld & a_World,
|
||||
cPlayer & a_Player,
|
||||
const cItem & a_EquippedItem,
|
||||
const Vector3i a_ClickedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos
|
||||
) override
|
||||
{
|
||||
// First try spawning a snow golem or an iron golem:
|
||||
int PlacedBlockX = a_BlockX;
|
||||
int PlacedBlockY = a_BlockY;
|
||||
int PlacedBlockZ = a_BlockZ;
|
||||
AddFaceDirection(PlacedBlockX, PlacedBlockY, PlacedBlockZ, a_BlockFace);
|
||||
if (TrySpawnGolem(a_World, a_Player, PlacedBlockX, PlacedBlockY, PlacedBlockZ))
|
||||
auto PlacePos = AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace);
|
||||
if (TrySpawnGolem(a_World, a_Player, PlacePos))
|
||||
{
|
||||
// The client thinks that they placed the pumpkin, let them know it's been replaced:
|
||||
a_Player.SendBlocksAround(PlacedBlockX, PlacedBlockY, PlacedBlockZ);
|
||||
a_Player.SendBlocksAround(PlacePos.x, PlacePos.y, PlacePos.z);
|
||||
return true;
|
||||
}
|
||||
|
||||
// No golem at these coords, place the block normally:
|
||||
return Super::OnPlayerPlace(a_World, a_Player, a_EquippedItem, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ);
|
||||
return Super::OnPlayerPlace(a_World, a_Player, a_EquippedItem, a_ClickedBlockPos, a_ClickedBlockFace, a_CursorPos);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Spawns a snow / iron golem if the shape matches the recipe, supposing that the block placed at the specified coords is a pumpkin.
|
||||
Returns true if the golem blocks are removed (for spawning), false if the recipe is not matched. */
|
||||
bool TrySpawnGolem(cWorld & a_World, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||
bool TrySpawnGolem(cWorld & a_World, cPlayer & a_Player, const Vector3i a_PumpkinPos)
|
||||
{
|
||||
// A golem can't form with a pumpkin below level 2 or above level 255
|
||||
if ((a_BlockY < 2) || (a_BlockY >= cChunkDef::Height))
|
||||
if ((a_PumpkinPos.y < 2) || (a_PumpkinPos.y >= cChunkDef::Height))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Decide which golem to try spawning based on the block below the placed pumpkin:
|
||||
switch (a_World.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ))
|
||||
switch (a_World.GetBlock(a_PumpkinPos.addedY(-1)))
|
||||
{
|
||||
case E_BLOCK_SNOW_BLOCK: return TrySpawnSnowGolem(a_World, a_Player, a_BlockX, a_BlockY, a_BlockZ);
|
||||
case E_BLOCK_IRON_BLOCK: return TrySpawnIronGolem(a_World, a_Player, a_BlockX, a_BlockY, a_BlockZ);
|
||||
case E_BLOCK_SNOW_BLOCK: return TrySpawnSnowGolem(a_World, a_Player, a_PumpkinPos);
|
||||
case E_BLOCK_IRON_BLOCK: return TrySpawnIronGolem(a_World, a_Player, a_PumpkinPos);
|
||||
default:
|
||||
{
|
||||
// No golem here
|
||||
@ -67,45 +73,59 @@ public:
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Spawns a snow golem if the shape matches the recipe, supposing that the block placed at the specified coords is a pumpkin.
|
||||
Returns true if the golem blocks are removed (for spawning), false if the recipe is not matched.
|
||||
Assumes that the block below the specified block has already been checked and is a snow block. */
|
||||
bool TrySpawnSnowGolem(cWorld & a_World, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||
bool TrySpawnSnowGolem(cWorld & a_World, cPlayer & a_Player, const Vector3i a_PumpkinPos)
|
||||
{
|
||||
ASSERT(a_PumpkinPos.y > 1);
|
||||
ASSERT(a_World.GetBlock(a_PumpkinPos.addedY(-1)) == E_BLOCK_SNOW);
|
||||
|
||||
// Need one more snow block 2 blocks below the pumpkin:
|
||||
if (a_World.GetBlock(a_BlockX, a_BlockY - 2, a_BlockZ) != E_BLOCK_SNOW_BLOCK)
|
||||
if (a_World.GetBlock(a_PumpkinPos.addedY(-2)) != E_BLOCK_SNOW_BLOCK)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Try to place air blocks where the original recipe blocks were:
|
||||
sSetBlockVector AirBlocks;
|
||||
AirBlocks.emplace_back(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0); // Head
|
||||
AirBlocks.emplace_back(a_BlockX, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0); // Torso
|
||||
AirBlocks.emplace_back(a_BlockX, a_BlockY - 2, a_BlockZ, E_BLOCK_AIR, 0); // Legs
|
||||
AirBlocks.emplace_back(a_PumpkinPos, E_BLOCK_AIR, 0); // Head
|
||||
AirBlocks.emplace_back(a_PumpkinPos.addedY(-1), E_BLOCK_AIR, 0); // Torso
|
||||
AirBlocks.emplace_back(a_PumpkinPos.addedY(-2), E_BLOCK_AIR, 0); // Legs
|
||||
if (!a_Player.PlaceBlocks(AirBlocks))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Spawn the golem:
|
||||
a_World.SpawnMob(static_cast<double>(a_BlockX) + 0.5, a_BlockY - 2, static_cast<double>(a_BlockZ) + 0.5, mtSnowGolem, false);
|
||||
auto GolemPos = Vector3d(a_PumpkinPos) + Vector3d(0.5, -2, 0.5);
|
||||
a_World.SpawnMob(GolemPos.x, GolemPos.y, GolemPos.z, mtSnowGolem, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Spawns an iron golem if the shape matches the recipe, supposing that the block placed at the specified coords is a pumpkin.
|
||||
Returns true if the golem blocks are removed (for spawning), false if the recipe is not matched.
|
||||
Assumes that the block below the specified block has already been checked and is an iron block. */
|
||||
bool TrySpawnIronGolem(cWorld & a_World, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||
bool TrySpawnIronGolem(cWorld & a_World, cPlayer & a_Player, const Vector3i a_PumpkinPos)
|
||||
{
|
||||
ASSERT(a_PumpkinPos.y > 1);
|
||||
ASSERT(a_World.GetBlock(a_PumpkinPos.addedY(-1)) == E_BLOCK_IRON_BLOCK);
|
||||
|
||||
// Need one more iron block 2 blocks below the pumpkin:
|
||||
if (a_World.GetBlock(a_BlockX, a_BlockY - 2, a_BlockZ) != E_BLOCK_IRON_BLOCK)
|
||||
if (a_World.GetBlock(a_PumpkinPos.addedY(-2)) != E_BLOCK_IRON_BLOCK)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check the two arm directions (X, Z) using a loop over two sets of offset vectors:
|
||||
auto BodyPos = a_PumpkinPos.addedY(-1);
|
||||
static const Vector3i ArmOffsets[] =
|
||||
{
|
||||
{1, 0, 0},
|
||||
@ -115,8 +135,8 @@ public:
|
||||
{
|
||||
// If the arm blocks don't match, bail out of this loop repetition:
|
||||
if (
|
||||
(a_World.GetBlock(a_BlockX + ArmOffsets[i].x, a_BlockY - 1, a_BlockZ + ArmOffsets[i].z) != E_BLOCK_IRON_BLOCK) ||
|
||||
(a_World.GetBlock(a_BlockX - ArmOffsets[i].x, a_BlockY - 1, a_BlockZ - ArmOffsets[i].z) != E_BLOCK_IRON_BLOCK)
|
||||
(a_World.GetBlock(BodyPos + ArmOffsets[i]) != E_BLOCK_IRON_BLOCK) ||
|
||||
(a_World.GetBlock(BodyPos - ArmOffsets[i]) != E_BLOCK_IRON_BLOCK)
|
||||
)
|
||||
{
|
||||
continue;
|
||||
@ -124,18 +144,19 @@ public:
|
||||
|
||||
// Try to place air blocks where the original recipe blocks were:
|
||||
sSetBlockVector AirBlocks;
|
||||
AirBlocks.emplace_back(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0); // Head
|
||||
AirBlocks.emplace_back(a_BlockX, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0); // Torso
|
||||
AirBlocks.emplace_back(a_BlockX, a_BlockY - 2, a_BlockZ, E_BLOCK_AIR, 0); // Legs
|
||||
AirBlocks.emplace_back(a_BlockX + ArmOffsets[i].x, a_BlockY - 1, a_BlockZ + ArmOffsets[i].z, E_BLOCK_AIR, 0); // Arm
|
||||
AirBlocks.emplace_back(a_BlockX - ArmOffsets[i].x, a_BlockY - 1, a_BlockZ - ArmOffsets[i].z, E_BLOCK_AIR, 0); // Arm
|
||||
AirBlocks.emplace_back(a_PumpkinPos, E_BLOCK_AIR, 0); // Head
|
||||
AirBlocks.emplace_back(BodyPos, E_BLOCK_AIR, 0); // Torso
|
||||
AirBlocks.emplace_back(BodyPos.addedY(-1), E_BLOCK_AIR, 0); // Legs
|
||||
AirBlocks.emplace_back(BodyPos + ArmOffsets[i], E_BLOCK_AIR, 0); // Arm
|
||||
AirBlocks.emplace_back(BodyPos - ArmOffsets[i], E_BLOCK_AIR, 0); // Arm
|
||||
if (!a_Player.PlaceBlocks(AirBlocks))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Spawn the golem:
|
||||
a_World.SpawnMob(static_cast<double>(a_BlockX) + 0.5, a_BlockY - 2, static_cast<double>(a_BlockZ) + 0.5, mtIronGolem, false);
|
||||
auto GolemPos = Vector3d(a_PumpkinPos) + Vector3d(0.5, -2, 0.5);
|
||||
a_World.SpawnMob(GolemPos.x, GolemPos.y, GolemPos.z, mtIronGolem, false);
|
||||
return true;
|
||||
} // for i - ArmOffsets[]
|
||||
|
||||
|
@ -7,36 +7,48 @@
|
||||
|
||||
|
||||
|
||||
class cItemRedstoneDustHandler : public cItemHandler
|
||||
class cItemRedstoneDustHandler:
|
||||
public cItemHandler
|
||||
{
|
||||
using Super = cItemHandler;
|
||||
|
||||
public:
|
||||
cItemRedstoneDustHandler(int a_ItemType)
|
||||
: cItemHandler(a_ItemType)
|
||||
|
||||
cItemRedstoneDustHandler(int a_ItemType):
|
||||
Super(a_ItemType)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool IsPlaceable(void) override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool GetPlacementBlockTypeMeta(
|
||||
cWorld * a_World, cPlayer * a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
const Vector3i a_PlacedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||
) override
|
||||
{
|
||||
// Check if coords are out of range:
|
||||
if ((a_BlockY <= 0) || (a_BlockY >= cChunkDef::Height))
|
||||
// Check the block below, if it supports dust on top of it:
|
||||
auto UnderPos = a_PlacedBlockPos.addedY(-1);
|
||||
if (UnderPos.y < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check the block below, if it supports dust on top of it:
|
||||
BLOCKTYPE BlockType;
|
||||
NIBBLETYPE BlockMeta;
|
||||
if (!a_World->GetBlockTypeMeta(a_BlockX, a_BlockY - 1, a_BlockZ, BlockType, BlockMeta))
|
||||
if (!a_World->GetBlockTypeMeta(UnderPos, BlockType, BlockMeta))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -51,6 +63,9 @@ public:
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Returns true if the specified block type / meta is suitable to have redstone dust on top of it. */
|
||||
static bool IsBlockTypeUnderSuitable(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
|
||||
{
|
||||
|
@ -8,24 +8,36 @@
|
||||
|
||||
|
||||
|
||||
class cItemRedstoneRepeaterHandler :
|
||||
class cItemRedstoneRepeaterHandler:
|
||||
public cItemHandler
|
||||
{
|
||||
using Super = cItemHandler;
|
||||
|
||||
public:
|
||||
cItemRedstoneRepeaterHandler(int a_ItemType)
|
||||
: cItemHandler(a_ItemType)
|
||||
|
||||
cItemRedstoneRepeaterHandler(int a_ItemType):
|
||||
Super(a_ItemType)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool IsPlaceable() override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool GetPlacementBlockTypeMeta(
|
||||
cWorld * a_World, cPlayer * a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
const Vector3i a_PlacedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||
) override
|
||||
{
|
||||
|
@ -17,24 +17,29 @@ public:
|
||||
cItemSaplingHandler(int a_ItemType):
|
||||
Super(a_ItemType)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool GetPlacementBlockTypeMeta(
|
||||
cWorld * a_World, cPlayer * a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
const Vector3i a_PlacedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||
) override
|
||||
{
|
||||
bool res = Super::GetPlacementBlockTypeMeta(
|
||||
a_World, a_Player,
|
||||
a_BlockX, a_BlockY, a_BlockZ, a_BlockFace,
|
||||
a_CursorX, a_CursorY, a_CursorZ,
|
||||
a_PlacedBlockPos, a_ClickedBlockFace,
|
||||
a_CursorPos,
|
||||
a_BlockType, a_BlockMeta
|
||||
);
|
||||
// Only the lowest 3 bits are important
|
||||
a_BlockMeta = a_BlockMeta & 0x7;
|
||||
|
||||
// Allow only the lowest 3 bits (top bit is for growth):
|
||||
a_BlockMeta = a_BlockMeta & 0x07;
|
||||
return res;
|
||||
}
|
||||
} ;
|
||||
|
@ -8,44 +8,53 @@
|
||||
|
||||
|
||||
|
||||
class cItemSeedsHandler :
|
||||
class cItemSeedsHandler:
|
||||
public cItemHandler
|
||||
{
|
||||
using Super = cItemHandler;
|
||||
|
||||
public:
|
||||
cItemSeedsHandler(int a_ItemType) :
|
||||
cItemHandler(a_ItemType)
|
||||
|
||||
cItemSeedsHandler(int a_ItemType):
|
||||
Super(a_ItemType)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool IsPlaceable(void) override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool GetPlacementBlockTypeMeta(
|
||||
cWorld * a_World, cPlayer * a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
const Vector3i a_PlacedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||
) override
|
||||
{
|
||||
if (a_BlockFace != BLOCK_FACE_TOP)
|
||||
// Only allow planting seeds from the top side of the block:
|
||||
if ((a_ClickedBlockFace != BLOCK_FACE_TOP) || (a_PlacedBlockPos.y <= 0))
|
||||
{
|
||||
// Only allow planting seeds from the top side of the block
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only allow placement on farmland
|
||||
int X = a_BlockX;
|
||||
int Y = a_BlockY;
|
||||
int Z = a_BlockZ;
|
||||
AddFaceDirection(X, Y, Z, a_BlockFace, true);
|
||||
if (a_World->GetBlock(X, Y, Z) != E_BLOCK_FARMLAND)
|
||||
if (a_World->GetBlock(a_PlacedBlockPos.addedY(-1)) != E_BLOCK_FARMLAND)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the produce block based on the seed item:
|
||||
a_BlockMeta = 0;
|
||||
switch (m_ItemType)
|
||||
{
|
||||
|
@ -22,25 +22,33 @@ public:
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool IsTool(void) override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
virtual bool OnDiggingBlock(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir) override
|
||||
|
||||
|
||||
|
||||
virtual bool OnDiggingBlock(
|
||||
cWorld * a_World,
|
||||
cPlayer * a_Player,
|
||||
const cItem & a_HeldItem,
|
||||
const Vector3i a_ClickedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace
|
||||
) override
|
||||
{
|
||||
BLOCKTYPE Block;
|
||||
NIBBLETYPE BlockMeta;
|
||||
a_World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, Block, BlockMeta);
|
||||
a_World->GetBlockTypeMeta(a_ClickedBlockPos, Block, BlockMeta);
|
||||
|
||||
if ((Block == E_BLOCK_LEAVES) || (Block == E_BLOCK_NEW_LEAVES))
|
||||
{
|
||||
cItems Drops;
|
||||
Drops.Add(Block, 1, BlockMeta & 3);
|
||||
a_World->SpawnItemPickups(Drops, a_BlockX, a_BlockY, a_BlockZ);
|
||||
|
||||
a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
|
||||
a_World->DropBlockAsPickups(a_ClickedBlockPos, a_Player, &a_HeldItem);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -48,6 +56,9 @@ public:
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool CanHarvestBlock(BLOCKTYPE a_BlockType) override
|
||||
{
|
||||
switch (a_BlockType)
|
||||
@ -63,6 +74,9 @@ public:
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual short GetDurabilityLossByAction(eDurabilityLostAction a_Action) override
|
||||
{
|
||||
switch (a_Action)
|
||||
@ -93,5 +107,4 @@ public:
|
||||
return Super::GetBlockBreakingStrength(a_Block);
|
||||
}
|
||||
}
|
||||
|
||||
} ;
|
||||
|
@ -24,58 +24,68 @@ public:
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool OnPlayerPlace(
|
||||
cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ
|
||||
cWorld & a_World,
|
||||
cPlayer & a_Player,
|
||||
const cItem & a_EquippedItem,
|
||||
const Vector3i a_ClickedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos
|
||||
) override
|
||||
{
|
||||
// Check if placing on something ignoring build collision to edit the correct sign later on:
|
||||
BLOCKTYPE ClickedBlock;
|
||||
BLOCKTYPE ClickedBlockType;
|
||||
NIBBLETYPE ClickedBlockMeta;
|
||||
a_World.GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, ClickedBlock, ClickedBlockMeta);
|
||||
a_World.GetBlockTypeMeta(a_ClickedBlockPos, ClickedBlockType, ClickedBlockMeta);
|
||||
cChunkInterface ChunkInterface(a_World.GetChunkMap());
|
||||
bool isReplacingClickedBlock = BlockHandler(ClickedBlock)->DoesIgnoreBuildCollision(ChunkInterface, { a_BlockX, a_BlockY, a_BlockZ }, a_Player, ClickedBlockMeta);
|
||||
bool IsReplacingClickedBlock = BlockHandler(ClickedBlockType)->DoesIgnoreBuildCollision(ChunkInterface, a_ClickedBlockPos, a_Player, ClickedBlockMeta);
|
||||
|
||||
// If the regular placement doesn't work, do no further processing:
|
||||
if (!Super::OnPlayerPlace(a_World, a_Player, a_EquippedItem, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ))
|
||||
if (!Super::OnPlayerPlace(a_World, a_Player, a_EquippedItem, a_ClickedBlockPos, a_ClickedBlockFace, a_CursorPos))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Use isReplacingClickedBlock to make sure we will edit the right sign:
|
||||
if (!isReplacingClickedBlock)
|
||||
{
|
||||
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
|
||||
}
|
||||
// Use IsReplacingClickedBlock to make sure we will edit the right sign:
|
||||
auto SignPos = IsReplacingClickedBlock ? a_ClickedBlockPos : AddFaceDirection(a_ClickedBlockPos, a_ClickedBlockFace);
|
||||
|
||||
// After successfully placing the sign, open the sign editor for the player:
|
||||
a_Player.GetClientHandle()->SendEditSign(a_BlockX, a_BlockY, a_BlockZ);
|
||||
a_Player.GetClientHandle()->SendEditSign(SignPos.x, SignPos.y, SignPos.z);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool IsPlaceable(void) override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
virtual bool GetPlacementBlockTypeMeta(
|
||||
cWorld * a_World, cPlayer * a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
int a_CursorX, int a_CursorY, int a_CursorZ,
|
||||
const Vector3i a_PlacedBlockPos,
|
||||
eBlockFace a_ClickedBlockFace,
|
||||
const Vector3i a_CursorPos,
|
||||
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
|
||||
) override
|
||||
{
|
||||
if (a_BlockFace == BLOCK_FACE_TOP)
|
||||
if (a_ClickedBlockFace == BLOCK_FACE_TOP)
|
||||
{
|
||||
a_BlockMeta = cBlockSignPostHandler::RotationToMetaData(a_Player->GetYaw());
|
||||
a_BlockType = E_BLOCK_SIGN_POST;
|
||||
}
|
||||
else
|
||||
{
|
||||
a_BlockMeta = cBlockWallSignHandler::DirectionToMetaData(a_BlockFace);
|
||||
a_BlockMeta = cBlockWallSignHandler::BlockFaceToMetaData(a_ClickedBlockFace);
|
||||
a_BlockType = E_BLOCK_WALLSIGN;
|
||||
}
|
||||
return true;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user