From ff4be64edc85bffb2fe73790b1ce6413d5449990 Mon Sep 17 00:00:00 2001 From: Marvin Kopf Date: Sat, 10 Dec 2016 09:53:35 +0100 Subject: Powered rails can kick-start minecarts (#3472) --- src/Entities/Minecart.cpp | 92 ++++++++++++++++++++++++++++++----------------- src/Entities/Minecart.h | 2 ++ 2 files changed, 62 insertions(+), 32 deletions(-) diff --git a/src/Entities/Minecart.cpp b/src/Entities/Minecart.cpp index 88b5959d5..c75c8288c 100644 --- a/src/Entities/Minecart.cpp +++ b/src/Entities/Minecart.cpp @@ -445,6 +445,21 @@ void cMinecart::HandlePoweredRailPhysics(NIBBLETYPE a_RailMeta) AddSpeedZ(AccelDecelNegSpeed); } } + // If rail is powered check for nearby blocks that could kick-start the minecart + else if ((a_RailMeta & 0x8) == 0x8) + { + bool IsBlockZP = IsSolidBlockAtOffset(0, 0, 1); + bool IsBlockZM = IsSolidBlockAtOffset(0, 0, -1); + // Only kick-start the minecart if a block is on one side, but not both + if (IsBlockZM && !IsBlockZP) + { + AddSpeedZ(AccelDecelSpeed); + } + else if (!IsBlockZM && IsBlockZP) + { + AddSpeedZ(AccelDecelNegSpeed); + } + } break; } case E_META_RAIL_XM_XP: // EASTWEST @@ -471,6 +486,21 @@ void cMinecart::HandlePoweredRailPhysics(NIBBLETYPE a_RailMeta) AddSpeedX(AccelDecelNegSpeed); } } + // If rail is powered check for nearby blocks that could kick-start the minecart + else if ((a_RailMeta & 0x8) == 0x8) + { + bool IsBlockXP = IsSolidBlockAtOffset(1, 0, 0); + bool IsBlockXM = IsSolidBlockAtOffset(-1, 0, 0); + // Only kick-start the minecart if a block is on one side, but not both + if (IsBlockXM && !IsBlockXP) + { + AddSpeedX(AccelDecelSpeed); + } + else if (!IsBlockXM && IsBlockXP) + { + AddSpeedX(AccelDecelNegSpeed); + } + } break; } case E_META_RAIL_ASCEND_XM: // ASCEND EAST @@ -698,6 +728,20 @@ void cMinecart::SnapToRail(NIBBLETYPE a_RailMeta) +bool cMinecart::IsSolidBlockAtOffset(int a_XOffset, int a_YOffset, int a_ZOffset) +{ + BLOCKTYPE Block = m_World->GetBlock(POSX_TOINT + a_XOffset, POSY_TOINT + a_YOffset, POSZ_TOINT + a_ZOffset); + if (IsBlockRail(Block) || !cBlockInfo::IsSolid(Block)) + { + return false; + } + return true; +} + + + + + bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta) { switch (a_RailMeta) @@ -706,8 +750,7 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta) { if (GetSpeedZ() > 0) { - BLOCKTYPE Block = m_World->GetBlock(POSX_TOINT, POSY_TOINT, static_cast(ceil(GetPosZ()))); - if (!IsBlockRail(Block) && cBlockInfo::IsSolid(Block)) + if (IsSolidBlockAtOffset(0, 0, 1)) { // We could try to detect a block in front based purely on coordinates, but xoft made a bounding box system - why not use? :P cBoundingBox bbBlock(Vector3d(POSX_TOINT, POSY_TOINT, static_cast(ceil(GetPosZ()))), 0.5, 1); @@ -723,8 +766,7 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta) } else if (GetSpeedZ() < 0) { - BLOCKTYPE Block = m_World->GetBlock(POSX_TOINT, POSY_TOINT, POSZ_TOINT - 1); - if (!IsBlockRail(Block) && cBlockInfo::IsSolid(Block)) + if (IsSolidBlockAtOffset(0, 0, -1)) { cBoundingBox bbBlock(Vector3d(POSX_TOINT, POSY_TOINT, POSZ_TOINT - 1), 0.5, 1); cBoundingBox bbMinecart(Vector3d(GetPosX(), floor(GetPosY()), GetPosZ() - 1), GetWidth() / 2, GetHeight()); @@ -743,8 +785,7 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta) { if (GetSpeedX() > 0) { - BLOCKTYPE Block = m_World->GetBlock(static_cast(ceil(GetPosX())), POSY_TOINT, POSZ_TOINT); - if (!IsBlockRail(Block) && cBlockInfo::IsSolid(Block)) + if (IsSolidBlockAtOffset(1, 0, 0)) { cBoundingBox bbBlock(Vector3d(static_cast(ceil(GetPosX())), POSY_TOINT, POSZ_TOINT), 0.5, 1); cBoundingBox bbMinecart(Vector3d(GetPosX(), floor(GetPosY()), GetPosZ()), GetWidth() / 2, GetHeight()); @@ -759,8 +800,7 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta) } else if (GetSpeedX() < 0) { - BLOCKTYPE Block = m_World->GetBlock(POSX_TOINT - 1, POSY_TOINT, POSZ_TOINT); - if (!IsBlockRail(Block) && cBlockInfo::IsSolid(Block)) + if (IsSolidBlockAtOffset(-1, 0, 0)) { cBoundingBox bbBlock(Vector3d(POSX_TOINT - 1, POSY_TOINT, POSZ_TOINT), 0.5, 1); cBoundingBox bbMinecart(Vector3d(GetPosX() - 1, floor(GetPosY()), GetPosZ()), GetWidth() / 2, GetHeight()); @@ -777,13 +817,10 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta) } case E_META_RAIL_CURVED_ZM_XM: { - BLOCKTYPE BlockXM = m_World->GetBlock(POSX_TOINT - 1, POSY_TOINT, POSZ_TOINT); - BLOCKTYPE BlockZM = m_World->GetBlock(POSX_TOINT, POSY_TOINT, POSZ_TOINT - 1); + bool IsBlockXM = IsSolidBlockAtOffset(-1, 0, 0); + bool IsBlockZM = IsSolidBlockAtOffset(0, 0, -1); - if ( - ((GetSpeedZ() < 0) && (!IsBlockRail(BlockZM) && cBlockInfo::IsSolid(BlockZM))) || - ((GetSpeedX() < 0) && (!IsBlockRail(BlockXM) && cBlockInfo::IsSolid(BlockXM))) - ) + if (((GetSpeedZ() < 0) && IsBlockZM) || ((GetSpeedX() < 0) && IsBlockXM)) { SetSpeed(0, 0, 0); SetPosition(POSX_TOINT + 0.5, GetPosY(), POSZ_TOINT + 0.5); @@ -794,13 +831,10 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta) } case E_META_RAIL_CURVED_ZM_XP: { - BLOCKTYPE BlockXP = m_World->GetBlock(POSX_TOINT + 1, POSY_TOINT, POSZ_TOINT); - BLOCKTYPE BlockZM = m_World->GetBlock(POSX_TOINT, POSY_TOINT, POSZ_TOINT - 1); + bool IsBlockXP = IsSolidBlockAtOffset(1, 0, 0); + bool IsBlockZM = IsSolidBlockAtOffset(0, 0, -1); - if ( - ((GetSpeedZ() < 0) && (!IsBlockRail(BlockZM) && cBlockInfo::IsSolid(BlockZM))) || - ((GetSpeedX() > 0) && (!IsBlockRail(BlockXP) && cBlockInfo::IsSolid(BlockXP))) - ) + if (((GetSpeedZ() < 0) && IsBlockZM) || ((GetSpeedX() > 0) && IsBlockXP)) { SetSpeed(0, 0, 0); SetPosition(POSX_TOINT + 0.5, GetPosY(), POSZ_TOINT + 0.5); @@ -811,13 +845,10 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta) } case E_META_RAIL_CURVED_ZP_XM: { - BLOCKTYPE BlockXM = m_World->GetBlock(POSX_TOINT - 1, POSY_TOINT, POSZ_TOINT); - BLOCKTYPE BlockZP = m_World->GetBlock(POSX_TOINT, POSY_TOINT, POSZ_TOINT + 1); + bool IsBlockXM = IsSolidBlockAtOffset(-1, 0, 0); + bool IsBlockZP = IsSolidBlockAtOffset(0, 0, +1); - if ( - ((GetSpeedZ() > 0) && (!IsBlockRail(BlockZP) && cBlockInfo::IsSolid(BlockZP))) || - ((GetSpeedX() < 0) && (!IsBlockRail(BlockXM) && cBlockInfo::IsSolid(BlockXM))) - ) + if (((GetSpeedZ() > 0) && IsBlockZP) || ((GetSpeedX() < 0) && IsBlockXM)) { SetSpeed(0, 0, 0); SetPosition(POSX_TOINT + 0.5, GetPosY(), POSZ_TOINT + 0.5); @@ -828,13 +859,10 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta) } case E_META_RAIL_CURVED_ZP_XP: { - BLOCKTYPE BlockXP = m_World->GetBlock(POSX_TOINT + 1, POSY_TOINT, POSZ_TOINT); - BLOCKTYPE BlockZP = m_World->GetBlock(POSX_TOINT, POSY_TOINT, POSZ_TOINT + 1); + bool IsBlockXP = IsSolidBlockAtOffset(1, 0, 0); + bool IsBlockZP = IsSolidBlockAtOffset(0, 0, 1); - if ( - ((GetSpeedZ() > 0) && (!IsBlockRail(BlockZP) && cBlockInfo::IsSolid(BlockZP))) || - ((GetSpeedX() > 0) && (!IsBlockRail(BlockXP) && cBlockInfo::IsSolid(BlockXP))) - ) + if (((GetSpeedZ() > 0) && IsBlockZP) || ((GetSpeedX() > 0) && IsBlockXP)) { SetSpeed(0, 0, 0); SetPosition(POSX_TOINT + 0.5, GetPosY(), POSZ_TOINT + 0.5); diff --git a/src/Entities/Minecart.h b/src/Entities/Minecart.h index f68b2f72b..f1f499328 100644 --- a/src/Entities/Minecart.h +++ b/src/Entities/Minecart.h @@ -78,6 +78,8 @@ protected: void SnapToRail(NIBBLETYPE a_RailMeta); /** Tests if a solid block is in front of a cart, and stops the cart (and returns true) if so; returns false if no obstruction */ bool TestBlockCollision(NIBBLETYPE a_RailMeta); + /** Tests if a solid block is at a specific offset of the minecart position */ + bool IsSolidBlockAtOffset(int a_XOffset, int a_YOffset, int a_ZOffset); /** Tests if this mincecart's bounding box is intersecting another entity's bounding box (collision) and pushes mincecart away if necessary */ bool TestEntityCollision(NIBBLETYPE a_RailMeta); -- cgit v1.2.3