2013-07-29 12:13:03 +01:00
// Minecart.cpp
// Implements the cMinecart class representing a minecart in the world
2014-01-13 22:37:09 +00:00
// Handles physics when a minecart is on any type of rail (overrides simulator in Entity.cpp)
2013-08-27 20:38:11 +01:00
// Indiana Jones!
2013-07-29 12:13:03 +01:00
#include "Globals.h"
#include "Minecart.h"
2020-04-03 08:57:01 +02:00
#include "../BlockInfo.h"
2013-08-19 11:39:13 +02:00
#include "../ClientHandle.h"
2013-09-22 21:43:00 +02:00
#include "../Chunk.h"
2013-07-29 12:13:03 +01:00
#include "Player.h"
2014-01-13 22:37:09 +00:00
#include "../BoundingBox.h"
2014-12-13 15:06:55 +01:00
#include "../UI/MinecartWithChestWindow.h"
2013-07-29 12:13:03 +01:00
2014-09-22 18:23:56 -04:00
#define NO_SPEED 0.0
2014-01-12 13:28:37 +00:00
#define MAX_SPEED 8
#define MAX_SPEED_NEGATIVE -MAX_SPEED
2013-07-29 12:13:03 +01:00
2017-09-11 22:20:49 +01:00
class cMinecartCollisionCallback
2014-01-18 20:58:26 +00:00
{
public :
2015-03-21 15:18:17 +01:00
cMinecartCollisionCallback ( Vector3d a_Pos , double a_Height , double a_Width , UInt32 a_UniqueID , UInt32 a_AttacheeUniqueID ) :
2016-02-23 22:27:42 +01:00
m_DoesIntersect ( false ),
2014-02-05 09:43:49 -08:00
m_CollidedEntityPos ( 0 , 0 , 0 ),
2014-01-18 20:58:26 +00:00
m_Pos ( a_Pos ),
m_Height ( a_Height ),
m_Width ( a_Width ),
m_UniqueID ( a_UniqueID ),
m_AttacheeUniqueID ( a_AttacheeUniqueID )
{
}
2017-09-11 22:20:49 +01:00
bool operator () ( cEntity & a_Entity )
2014-01-18 20:58:26 +00:00
{
2016-10-12 14:38:45 +02:00
if (
(
2017-09-11 22:20:49 +01:00
! a_Entity . IsPlayer () ||
static_cast < cPlayer &> ( a_Entity ). IsGameModeSpectator () // Spectators doesn't collide with anything
2016-10-12 14:38:45 +02:00
) &&
2017-09-11 22:20:49 +01:00
! a_Entity . IsMob () &&
! a_Entity . IsMinecart () &&
! a_Entity . IsBoat ()
2016-10-12 14:38:45 +02:00
)
2014-01-18 20:58:26 +00:00
{
return false ;
}
2017-09-11 22:20:49 +01:00
else if (( a_Entity . GetUniqueID () == m_UniqueID ) || ( a_Entity . GetUniqueID () == m_AttacheeUniqueID ))
2014-01-18 20:58:26 +00:00
{
return false ;
}
2017-09-11 22:20:49 +01:00
cBoundingBox bbEntity ( a_Entity . GetPosition (), a_Entity . GetWidth () / 2 , a_Entity . GetHeight ());
2014-01-18 20:58:26 +00:00
cBoundingBox bbMinecart ( Vector3d ( m_Pos . x , floor ( m_Pos . y ), m_Pos . z ), m_Width / 2 , m_Height );
if ( bbEntity . DoesIntersect ( bbMinecart ))
{
2017-09-11 22:20:49 +01:00
m_CollidedEntityPos = a_Entity . GetPosition ();
2016-02-23 22:27:42 +01:00
m_DoesIntersect = true ;
2014-01-18 20:58:26 +00:00
return true ;
}
return false ;
}
bool FoundIntersection ( void ) const
{
2016-02-23 22:27:42 +01:00
return m_DoesIntersect ;
2014-01-18 20:58:26 +00:00
}
Vector3d GetCollidedEntityPosition ( void ) const
{
return m_CollidedEntityPos ;
}
protected :
2016-02-23 22:27:42 +01:00
bool m_DoesIntersect ;
2014-01-18 20:58:26 +00:00
Vector3d m_CollidedEntityPos ;
Vector3d m_Pos ;
double m_Height , m_Width ;
2015-03-21 15:18:17 +01:00
UInt32 m_UniqueID ;
UInt32 m_AttacheeUniqueID ;
2014-01-18 20:58:26 +00:00
};
2013-07-29 12:13:03 +01:00
2019-09-29 14:59:24 +02:00
////////////////////////////////////////////////////////////////////////////////
// cMinecart:
cMinecart :: cMinecart ( ePayload a_Payload , Vector3d a_Pos ) :
2020-04-13 18:38:06 +02:00
Super ( etMinecart , a_Pos , 0.98 , 0.7 ),
2013-10-08 19:20:49 +01:00
m_Payload ( a_Payload ),
2014-01-13 22:37:09 +00:00
m_LastDamage ( 0 ),
m_DetectorRailPosition ( 0 , 0 , 0 ),
m_bIsOnDetectorRail ( false )
2013-07-29 12:13:03 +01:00
{
2015-03-30 19:42:32 -04:00
SetMass ( 20.0f );
SetGravity ( - 16.0f );
2015-03-31 11:03:35 -04:00
SetAirDrag ( 0.05f );
2013-08-28 22:13:27 +01:00
SetMaxHealth ( 6 );
2013-09-02 12:01:49 +01:00
SetHealth ( 6 );
2014-01-18 20:58:26 +00:00
SetWidth ( 1 );
2014-01-13 22:37:09 +00:00
SetHeight ( 0.9 );
2013-07-29 12:13:03 +01:00
}
2018-07-26 22:24:36 +01:00
2013-07-29 12:13:03 +01:00
void cMinecart :: SpawnOn ( cClientHandle & a_ClientHandle )
{
2020-04-20 20:46:04 +01:00
a_ClientHandle . SendSpawnEntity ( * this );
2014-01-12 18:04:41 +01:00
a_ClientHandle . SendEntityMetadata ( * this );
2013-07-29 12:13:03 +01:00
}
2015-01-11 21:12:26 +00:00
void cMinecart :: HandlePhysics ( std :: chrono :: milliseconds a_Dt , cChunk & a_Chunk )
2013-07-29 12:13:03 +01:00
{
2016-02-07 19:07:14 +02:00
ASSERT ( IsTicking ());
2014-01-13 22:37:09 +00:00
2014-04-17 18:50:25 +01:00
int PosY = POSY_TOINT ;
2013-09-22 21:43:00 +02:00
if (( PosY <= 0 ) || ( PosY >= cChunkDef :: Height ))
2013-09-02 12:01:49 +01:00
{
2013-09-22 21:43:00 +02:00
// Outside the world, just process normal falling physics
2020-04-13 18:38:06 +02:00
Super :: HandlePhysics ( a_Dt , a_Chunk );
2013-09-22 21:43:00 +02:00
BroadcastMovementUpdate ();
return ;
}
2016-02-05 23:45:45 +02:00
2021-01-18 16:09:10 +00:00
auto relPos = cChunkDef :: AbsoluteToRelative ( GetPosition ());
2019-10-11 11:02:53 +02:00
auto chunk = a_Chunk . GetRelNeighborChunkAdjustCoords ( relPos );
if ( chunk == nullptr )
2013-09-22 21:43:00 +02:00
{
// Inside an unloaded chunk, bail out all processing
return ;
}
2013-09-02 12:01:49 +01:00
2014-01-12 13:28:37 +00:00
BLOCKTYPE InsideType ;
NIBBLETYPE InsideMeta ;
2019-10-11 11:02:53 +02:00
chunk -> GetBlockTypeMeta ( relPos , InsideType , InsideMeta );
2014-01-12 13:28:37 +00:00
if ( ! IsBlockRail ( InsideType ))
2013-09-22 21:43:00 +02:00
{
2014-12-05 16:59:11 +01:00
// When a descending minecart hits a flat rail, it goes through the ground; check for this
2019-10-11 11:02:53 +02:00
chunk -> GetBlockTypeMeta ( relPos . addedY ( 1 ), InsideType , InsideMeta );
2014-12-05 16:59:11 +01:00
if ( IsBlockRail ( InsideType ))
{
// Push cart upwards
AddPosY ( 1 );
}
2020-05-04 21:04:21 +00:00
else
{
// When a minecart gets to a descending rail, it should go down.
chunk -> GetBlockTypeMeta ( relPos . addedY ( - 1 ), InsideType , InsideMeta );
if ( IsBlockRail ( InsideType ))
{
// Push cart downwards
AddPosY ( - 1 );
}
}
2013-09-22 21:43:00 +02:00
}
2014-01-12 13:28:37 +00:00
2014-01-19 18:27:06 +00:00
bool WasDetectorRail = false ;
2014-01-12 13:28:37 +00:00
if ( IsBlockRail ( InsideType ))
2013-09-22 21:43:00 +02:00
{
2014-01-19 18:27:06 +00:00
if ( InsideType == E_BLOCK_RAIL )
{
SnapToRail ( InsideMeta );
}
else
{
SnapToRail ( InsideMeta & 0x07 );
}
2014-01-12 13:28:37 +00:00
switch ( InsideType )
2013-09-02 12:01:49 +01:00
{
2014-01-13 22:37:09 +00:00
case E_BLOCK_RAIL : HandleRailPhysics ( InsideMeta , a_Dt ); break ;
2014-01-12 13:28:37 +00:00
case E_BLOCK_ACTIVATOR_RAIL : break ;
case E_BLOCK_POWERED_RAIL : HandlePoweredRailPhysics ( InsideMeta ); break ;
2014-01-13 22:37:09 +00:00
case E_BLOCK_DETECTOR_RAIL :
{
HandleDetectorRailPhysics ( InsideMeta , a_Dt );
WasDetectorRail = true ;
break ;
}
2014-01-12 13:28:37 +00:00
default : VERIFY ( ! "Unhandled rail type despite checking if block was rail!" ); break ;
2013-09-02 12:01:49 +01:00
}
2014-01-12 13:28:37 +00:00
2015-01-18 11:02:17 +01:00
AddPosition ( GetSpeed () * ( static_cast < double > ( a_Dt . count ()) / 1000 )); // Commit changes; as we use our own engine when on rails, this needs to be done, whereas it is normally in Entity.cpp
2014-01-12 13:28:37 +00:00
}
else
{
2014-01-13 22:37:09 +00:00
// Not on rail, default physics
2014-07-17 22:15:34 +02:00
SetPosY ( floor ( GetPosY ()) + 0.35 ); // HandlePhysics overrides this if minecart can fall, else, it is to stop ground clipping minecart bottom when off-rail
2020-04-13 18:38:06 +02:00
Super :: HandlePhysics ( a_Dt , * chunk );
2013-09-02 12:01:49 +01:00
}
2014-01-19 18:27:06 +00:00
2014-04-17 18:50:25 +01:00
if ( m_bIsOnDetectorRail && ! Vector3i ( POSX_TOINT , POSY_TOINT , POSZ_TOINT ). Equals ( m_DetectorRailPosition ))
2014-01-19 18:27:06 +00:00
{
2019-10-11 11:02:53 +02:00
m_World -> SetBlock ( m_DetectorRailPosition , E_BLOCK_DETECTOR_RAIL , m_World -> GetBlockMeta ( m_DetectorRailPosition ) & 0x07 );
2014-01-19 18:27:06 +00:00
m_bIsOnDetectorRail = false ;
}
else if ( WasDetectorRail )
{
m_bIsOnDetectorRail = true ;
2014-04-17 18:50:25 +01:00
m_DetectorRailPosition = Vector3i ( POSX_TOINT , POSY_TOINT , POSZ_TOINT );
2014-01-19 18:27:06 +00:00
}
2016-02-05 23:45:45 +02:00
2014-01-13 22:37:09 +00:00
// Broadcast positioning changes to client
2014-01-12 13:28:37 +00:00
BroadcastMovementUpdate ();
2013-09-02 12:01:49 +01:00
}
2015-01-16 13:42:44 +00:00
void cMinecart :: HandleRailPhysics ( NIBBLETYPE a_RailMeta , std :: chrono :: milliseconds a_Dt )
2013-09-02 12:01:49 +01:00
{
2013-08-27 20:38:11 +01:00
/*
NOTE: Please bear in mind that taking away from negatives make them even more negative,
2013-08-29 13:47:22 +01:00
adding to negatives make them positive, etc.
2013-08-27 20:38:11 +01:00
*/
2016-02-05 23:45:45 +02:00
2014-01-12 13:28:37 +00:00
switch ( a_RailMeta )
2013-08-27 20:38:11 +01:00
{
2014-07-17 22:15:34 +02:00
case E_META_RAIL_ZM_ZP : // NORTHSOUTH
2013-08-27 20:38:11 +01:00
{
2014-01-16 19:00:49 +00:00
SetYaw ( 270 );
2014-01-12 13:28:37 +00:00
SetPosY ( floor ( GetPosY ()) + 0.55 );
2014-07-17 22:15:34 +02:00
SetSpeedY ( 0 ); // Don't move vertically as on ground
SetSpeedX ( 0 ); // Correct diagonal movement from curved rails
2014-01-13 22:37:09 +00:00
2014-01-18 20:58:26 +00:00
// Execute both the entity and block collision checks
2020-05-04 21:04:21 +00:00
auto BlckCol = TestBlockCollision ( a_RailMeta );
auto EntCol = TestEntityCollision ( a_RailMeta );
2014-12-05 16:59:11 +01:00
if ( EntCol || BlckCol )
{
return ;
}
2016-02-05 23:45:45 +02:00
2014-09-22 18:23:56 -04:00
if ( GetSpeedZ () != NO_SPEED ) // Don't do anything if cart is stationary
2013-08-27 20:38:11 +01:00
{
2014-01-12 13:28:37 +00:00
if ( GetSpeedZ () > 0 )
2013-09-02 12:01:49 +01:00
{
// Going SOUTH, slow down
2017-10-21 17:53:24 +01:00
ApplyAcceleration ({ 0.0 , 0.0 , 1.0 }, - 0.1 );
2013-09-02 12:01:49 +01:00
}
else
2013-08-27 20:38:11 +01:00
{
2013-09-02 12:01:49 +01:00
// Going NORTH, slow down
2017-10-21 17:53:24 +01:00
ApplyAcceleration ({ 0.0 , 0.0 , - 1.0 }, - 0.1 );
2013-08-27 20:38:11 +01:00
}
}
2020-05-04 21:04:21 +00:00
return ;
2013-09-02 12:01:49 +01:00
}
2014-07-17 22:15:34 +02:00
case E_META_RAIL_XM_XP : // EASTWEST
2013-09-02 12:01:49 +01:00
{
2014-01-16 19:00:49 +00:00
SetYaw ( 180 );
2014-01-12 13:28:37 +00:00
SetPosY ( floor ( GetPosY ()) + 0.55 );
2014-09-22 18:23:56 -04:00
SetSpeedY ( NO_SPEED );
SetSpeedZ ( NO_SPEED );
2013-08-27 20:38:11 +01:00
2020-05-04 21:04:21 +00:00
auto BlckCol = TestBlockCollision ( a_RailMeta );
auto EntCol = TestEntityCollision ( a_RailMeta );
2014-12-05 16:59:11 +01:00
if ( EntCol || BlckCol )
{
return ;
}
2014-01-13 22:37:09 +00:00
2014-09-22 18:23:56 -04:00
if ( GetSpeedX () != NO_SPEED )
2013-09-02 12:01:49 +01:00
{
2014-01-12 13:28:37 +00:00
if ( GetSpeedX () > 0 )
2013-08-27 20:38:11 +01:00
{
2017-10-21 17:53:24 +01:00
ApplyAcceleration ({ 1.0 , 0.0 , 0.0 }, - 0.1 );
2013-09-02 12:01:49 +01:00
}
else
{
2017-10-21 17:53:24 +01:00
ApplyAcceleration ({ - 1.0 , 0.0 , 0.0 }, - 0.1 );
2013-08-27 20:38:11 +01:00
}
}
2020-05-04 21:04:21 +00:00
return ;
2013-09-02 12:01:49 +01:00
}
2014-07-17 22:15:34 +02:00
case E_META_RAIL_ASCEND_ZM : // ASCEND NORTH
2013-09-02 12:01:49 +01:00
{
2014-01-16 19:00:49 +00:00
SetYaw ( 270 );
2014-01-12 13:28:37 +00:00
SetSpeedX ( 0 );
2013-08-27 20:38:11 +01:00
2020-05-04 21:04:21 +00:00
auto BlckCol = TestBlockCollision ( a_RailMeta );
auto EntCol = TestEntityCollision ( a_RailMeta );
if ( EntCol || BlckCol )
{
return ;
}
2014-01-12 13:28:37 +00:00
if ( GetSpeedZ () >= 0 )
2013-08-27 20:38:11 +01:00
{
2013-09-02 12:01:49 +01:00
// SpeedZ POSITIVE, going SOUTH
2016-02-21 02:46:36 +01:00
AddSpeedZ ( 0.5 ); // Speed up
SetSpeedY ( - GetSpeedZ ()); // Downward movement is negative (0 minus positive numbers is negative)
2013-08-27 20:38:11 +01:00
}
2013-09-02 12:01:49 +01:00
else
{
// SpeedZ NEGATIVE, going NORTH
2014-07-17 22:15:34 +02:00
AddSpeedZ ( 1 ); // Slow down
SetSpeedY ( - GetSpeedZ ()); // Upward movement is positive (0 minus negative number is positive number)
2013-09-02 12:01:49 +01:00
}
2020-05-04 21:04:21 +00:00
return ;
2013-09-02 12:01:49 +01:00
}
2014-07-17 22:15:34 +02:00
case E_META_RAIL_ASCEND_ZP : // ASCEND SOUTH
2013-09-02 12:01:49 +01:00
{
2014-01-16 19:00:49 +00:00
SetYaw ( 270 );
2014-01-12 13:28:37 +00:00
SetSpeedX ( 0 );
2013-08-27 20:38:11 +01:00
2020-05-04 21:04:21 +00:00
auto BlckCol = TestBlockCollision ( a_RailMeta );
auto EntCol = TestEntityCollision ( a_RailMeta );
if ( EntCol || BlckCol )
{
return ;
}
2014-01-12 13:28:37 +00:00
if ( GetSpeedZ () > 0 )
2013-08-27 20:38:11 +01:00
{
2013-09-02 12:01:49 +01:00
// SpeedZ POSITIVE, going SOUTH
2014-07-17 22:15:34 +02:00
AddSpeedZ ( - 1 ); // Slow down
SetSpeedY ( GetSpeedZ ()); // Upward movement positive
2013-09-02 12:01:49 +01:00
}
else
{
2016-02-21 02:46:36 +01:00
// SpeedZ NEGATIVE, going NORTH
AddSpeedZ ( - 0.5 ); // Speed up
SetSpeedY ( GetSpeedZ ()); // Downward movement negative
2013-08-27 20:38:11 +01:00
}
2020-05-04 21:04:21 +00:00
return ;
2013-09-02 12:01:49 +01:00
}
2014-07-17 22:15:34 +02:00
case E_META_RAIL_ASCEND_XM : // ASCEND EAST
2013-09-02 12:01:49 +01:00
{
2014-01-16 19:00:49 +00:00
SetYaw ( 180 );
2014-09-22 18:23:56 -04:00
SetSpeedZ ( NO_SPEED );
2013-08-27 20:38:11 +01:00
2020-05-04 21:04:21 +00:00
auto BlckCol = TestBlockCollision ( a_RailMeta );
auto EntCol = TestEntityCollision ( a_RailMeta );
if ( EntCol || BlckCol )
{
return ;
}
2014-09-22 18:23:56 -04:00
if ( GetSpeedX () >= NO_SPEED )
2013-08-27 20:38:11 +01:00
{
2016-02-21 02:46:36 +01:00
AddSpeedX ( 0.5 );
SetSpeedY ( - GetSpeedX ());
2013-08-27 20:38:11 +01:00
}
2013-09-02 12:01:49 +01:00
else
{
2014-01-12 13:28:37 +00:00
AddSpeedX ( 1 );
SetSpeedY ( - GetSpeedX ());
2013-09-02 12:01:49 +01:00
}
2020-05-04 21:04:21 +00:00
return ;
2013-09-02 12:01:49 +01:00
}
2014-07-17 22:15:34 +02:00
case E_META_RAIL_ASCEND_XP : // ASCEND WEST
2013-09-02 12:01:49 +01:00
{
2014-01-16 19:00:49 +00:00
SetYaw ( 180 );
2014-01-12 13:28:37 +00:00
SetSpeedZ ( 0 );
2013-08-27 20:38:11 +01:00
2020-05-04 21:04:21 +00:00
auto BlckCol = TestBlockCollision ( a_RailMeta );
auto EntCol = TestEntityCollision ( a_RailMeta );
if ( EntCol || BlckCol )
{
return ;
}
2014-01-12 13:28:37 +00:00
if ( GetSpeedX () > 0 )
2013-08-27 20:38:11 +01:00
{
2014-01-12 13:28:37 +00:00
AddSpeedX ( - 1 );
SetSpeedY ( GetSpeedX ());
2013-09-02 12:01:49 +01:00
}
else
{
2016-02-21 02:46:36 +01:00
AddSpeedX ( - 0.5 );
SetSpeedY ( GetSpeedX ());
2013-08-27 20:38:11 +01:00
}
2020-05-04 21:04:21 +00:00
return ;
2013-09-02 12:01:49 +01:00
}
2014-07-17 22:15:34 +02:00
case E_META_RAIL_CURVED_ZM_XM : // Ends pointing NORTH and WEST
2013-09-02 12:01:49 +01:00
{
2014-07-17 22:15:34 +02:00
SetYaw ( 315 ); // Set correct rotation server side
SetPosY ( floor ( GetPosY ()) + 0.55 ); // Levitate dat cart
2014-01-19 19:31:17 +00:00
SetSpeedY ( 0 );
2014-01-13 22:37:09 +00:00
2020-05-04 21:04:21 +00:00
auto BlckCol = TestBlockCollision ( a_RailMeta );
auto EntCol = TestEntityCollision ( a_RailMeta );
if ( EntCol || BlckCol )
{
return ;
}
2014-01-18 20:58:26 +00:00
// SnapToRail handles turning
2013-09-02 12:01:49 +01:00
2020-05-04 21:04:21 +00:00
return ;
2013-09-02 12:01:49 +01:00
}
2014-07-17 22:15:34 +02:00
case E_META_RAIL_CURVED_ZM_XP : // Curved NORTH EAST
2013-09-02 12:01:49 +01:00
{
2014-01-16 19:00:49 +00:00
SetYaw ( 225 );
2014-01-13 22:37:09 +00:00
SetPosY ( floor ( GetPosY ()) + 0.55 );
2014-01-19 19:31:17 +00:00
SetSpeedY ( 0 );
2014-01-13 22:37:09 +00:00
2020-05-04 21:04:21 +00:00
auto BlckCol = TestBlockCollision ( a_RailMeta );
auto EntCol = TestEntityCollision ( a_RailMeta );
if ( EntCol || BlckCol )
{
return ;
}
2013-09-02 12:01:49 +01:00
2020-05-04 21:04:21 +00:00
return ;
2013-09-02 12:01:49 +01:00
}
2014-07-17 22:15:34 +02:00
case E_META_RAIL_CURVED_ZP_XM : // Curved SOUTH WEST
2013-09-02 12:01:49 +01:00
{
2014-01-16 19:00:49 +00:00
SetYaw ( 135 );
2014-01-13 22:37:09 +00:00
SetPosY ( floor ( GetPosY ()) + 0.55 );
2014-01-19 19:31:17 +00:00
SetSpeedY ( 0 );
2014-01-13 22:37:09 +00:00
2020-05-04 21:04:21 +00:00
auto BlckCol = TestBlockCollision ( a_RailMeta );
auto EntCol = TestEntityCollision ( a_RailMeta );
if ( EntCol || BlckCol )
{
return ;
}
2013-09-02 12:01:49 +01:00
2020-05-04 21:04:21 +00:00
return ;
2013-09-02 12:01:49 +01:00
}
2014-07-17 22:15:34 +02:00
case E_META_RAIL_CURVED_ZP_XP : // Curved SOUTH EAST
2013-09-02 12:01:49 +01:00
{
2014-01-16 19:00:49 +00:00
SetYaw ( 45 );
2014-01-13 22:37:09 +00:00
SetPosY ( floor ( GetPosY ()) + 0.55 );
2014-01-19 19:31:17 +00:00
SetSpeedY ( 0 );
2014-01-13 22:37:09 +00:00
2020-05-04 21:04:21 +00:00
auto BlckCol = TestBlockCollision ( a_RailMeta );
auto EntCol = TestEntityCollision ( a_RailMeta );
if ( EntCol || BlckCol )
{
return ;
}
2013-09-02 12:01:49 +01:00
2020-05-04 21:04:21 +00:00
return ;
2013-08-27 20:38:11 +01:00
}
}
2020-05-04 21:04:21 +00:00
UNREACHABLE ( "Unsupported rail meta type" );
2014-01-12 13:28:37 +00:00
}
2013-09-02 12:01:49 +01:00
2013-08-27 20:38:11 +01:00
2013-09-02 12:01:49 +01:00
2014-01-12 13:28:37 +00:00
2018-07-26 22:24:36 +01:00
2014-01-12 13:28:37 +00:00
void cMinecart :: HandlePoweredRailPhysics ( NIBBLETYPE a_RailMeta )
{
2017-10-21 17:53:24 +01:00
// If the rail is powered set to speed up else slow down.
const bool IsRailPowered = (( a_RailMeta & 0x8 ) == 0x8 );
const double Acceleration = IsRailPowered ? 1.0 : - 2.0 ;
2014-01-13 22:37:09 +00:00
switch ( a_RailMeta & 0x07 )
{
2014-07-17 22:15:34 +02:00
case E_META_RAIL_ZM_ZP : // NORTHSOUTH
2014-01-12 13:28:37 +00:00
{
2014-01-16 19:00:49 +00:00
SetYaw ( 270 );
2014-01-13 22:37:09 +00:00
SetPosY ( floor ( GetPosY ()) + 0.55 );
SetSpeedY ( 0 );
SetSpeedX ( 0 );
2014-01-19 19:31:17 +00:00
bool BlckCol = TestBlockCollision ( a_RailMeta ), EntCol = TestEntityCollision ( a_RailMeta );
2014-12-05 16:59:11 +01:00
if ( EntCol || BlckCol )
{
return ;
}
2016-02-05 23:45:45 +02:00
2014-09-22 18:23:56 -04:00
if ( GetSpeedZ () != NO_SPEED )
2014-01-13 22:37:09 +00:00
{
2014-09-22 18:23:56 -04:00
if ( GetSpeedZ () > NO_SPEED )
2014-01-12 13:28:37 +00:00
{
2017-10-21 17:53:24 +01:00
ApplyAcceleration ({ 0.0 , 0.0 , 1.0 }, Acceleration );
2014-01-13 22:37:09 +00:00
}
else
{
2017-10-21 17:53:24 +01:00
ApplyAcceleration ({ 0.0 , 0.0 , - 1.0 }, Acceleration );
2014-01-12 13:28:37 +00:00
}
}
2016-12-10 09:53:35 +01:00
// If rail is powered check for nearby blocks that could kick-start the minecart
2017-10-21 17:53:24 +01:00
else if ( IsRailPowered )
2016-12-10 09:53:35 +01:00
{
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 )
{
2017-10-21 17:53:24 +01:00
ApplyAcceleration ({ 0.0 , 0.0 , 1.0 }, Acceleration );
2016-12-10 09:53:35 +01:00
}
else if ( ! IsBlockZM && IsBlockZP )
{
2017-10-21 17:53:24 +01:00
ApplyAcceleration ({ 0.0 , 0.0 , - 1.0 }, Acceleration );
2016-12-10 09:53:35 +01:00
}
}
2014-01-13 22:37:09 +00:00
break ;
}
2014-07-17 22:15:34 +02:00
case E_META_RAIL_XM_XP : // EASTWEST
2014-01-13 22:37:09 +00:00
{
2014-01-16 19:00:49 +00:00
SetYaw ( 180 );
2014-01-13 22:37:09 +00:00
SetPosY ( floor ( GetPosY ()) + 0.55 );
2014-09-22 18:23:56 -04:00
SetSpeedY ( NO_SPEED );
SetSpeedZ ( NO_SPEED );
2014-01-12 13:28:37 +00:00
2014-01-19 19:31:17 +00:00
bool BlckCol = TestBlockCollision ( a_RailMeta ), EntCol = TestEntityCollision ( a_RailMeta );
2014-12-05 16:59:11 +01:00
if ( EntCol || BlckCol )
{
return ;
}
2014-01-13 22:37:09 +00:00
2014-09-22 18:23:56 -04:00
if ( GetSpeedX () != NO_SPEED )
2014-01-13 22:37:09 +00:00
{
2014-09-22 18:23:56 -04:00
if ( GetSpeedX () > NO_SPEED )
2014-01-12 13:28:37 +00:00
{
2017-10-21 17:53:24 +01:00
ApplyAcceleration ({ 1.0 , 0.0 , 0.0 }, Acceleration );
2014-01-13 22:37:09 +00:00
}
else
{
2017-10-21 17:53:24 +01:00
ApplyAcceleration ({ - 1.0 , 0.0 , 0.0 }, Acceleration );
2014-01-12 13:28:37 +00:00
}
}
2016-12-10 09:53:35 +01:00
// If rail is powered check for nearby blocks that could kick-start the minecart
2017-10-21 17:53:24 +01:00
else if ( IsRailPowered )
2016-12-10 09:53:35 +01:00
{
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 )
{
2017-10-21 17:53:24 +01:00
ApplyAcceleration ({ 1.0 , 0.0 , 0.0 }, Acceleration );
2016-12-10 09:53:35 +01:00
}
else if ( ! IsBlockXM && IsBlockXP )
{
2017-10-21 17:53:24 +01:00
ApplyAcceleration ({ - 1.0 , 0.0 , 0.0 }, Acceleration );
2016-12-10 09:53:35 +01:00
}
}
2014-01-13 22:37:09 +00:00
break ;
2014-01-12 13:28:37 +00:00
}
2014-07-17 22:15:34 +02:00
case E_META_RAIL_ASCEND_XM : // ASCEND EAST
2014-01-19 19:31:17 +00:00
{
SetYaw ( 180 );
2014-09-22 18:23:56 -04:00
SetSpeedZ ( NO_SPEED );
2014-01-19 19:31:17 +00:00
2014-09-22 18:23:56 -04:00
if ( GetSpeedX () >= NO_SPEED )
2014-01-19 19:31:17 +00:00
{
2017-10-21 17:53:24 +01:00
ApplyAcceleration ({ 1.0 , 0.0 , 0.0 }, Acceleration );
2016-02-21 02:46:36 +01:00
SetSpeedY ( - GetSpeedX ());
2014-01-19 19:31:17 +00:00
}
else
{
2017-10-21 17:53:24 +01:00
ApplyAcceleration ({ - 1.0 , 0.0 , 0.0 }, Acceleration );
2014-01-19 19:31:17 +00:00
SetSpeedY ( - GetSpeedX ());
}
break ;
2014-07-17 22:59:02 +02:00
}
2014-07-17 22:15:34 +02:00
case E_META_RAIL_ASCEND_XP : // ASCEND WEST
2014-01-24 19:39:39 +00:00
{
SetYaw ( 180 );
2014-09-22 18:23:56 -04:00
SetSpeedZ ( NO_SPEED );
2014-01-24 19:39:39 +00:00
2014-09-22 18:23:56 -04:00
if ( GetSpeedX () > NO_SPEED )
2014-01-24 19:39:39 +00:00
{
2017-10-21 17:53:24 +01:00
ApplyAcceleration ({ 1.0 , 0.0 , 0.0 }, Acceleration );
2014-01-24 19:39:39 +00:00
SetSpeedY ( GetSpeedX ());
}
else
{
2017-10-21 17:53:24 +01:00
ApplyAcceleration ({ - 1.0 , 0.0 , 0.0 }, Acceleration );
2016-02-21 02:46:36 +01:00
SetSpeedY ( GetSpeedX ());
2014-01-24 19:39:39 +00:00
}
break ;
2014-07-17 22:59:02 +02:00
}
2014-07-17 22:15:34 +02:00
case E_META_RAIL_ASCEND_ZM : // ASCEND NORTH
2014-01-24 19:39:39 +00:00
{
SetYaw ( 270 );
2014-09-22 18:23:56 -04:00
SetSpeedX ( NO_SPEED );
2014-01-24 19:39:39 +00:00
2014-09-22 18:23:56 -04:00
if ( GetSpeedZ () >= NO_SPEED )
2014-01-24 19:39:39 +00:00
{
2017-10-21 17:53:24 +01:00
ApplyAcceleration ({ 0.0 , 0.0 , 1.0 }, Acceleration );
2016-02-21 02:46:36 +01:00
SetSpeedY ( - GetSpeedZ ());
2014-01-24 19:39:39 +00:00
}
else
{
2017-10-21 17:53:24 +01:00
ApplyAcceleration ({ 0.0 , 0.0 , - 1.0 }, Acceleration );
2014-01-24 19:39:39 +00:00
SetSpeedY ( - GetSpeedZ ());
}
break ;
}
2014-07-17 22:15:34 +02:00
case E_META_RAIL_ASCEND_ZP : // ASCEND SOUTH
2014-01-24 19:39:39 +00:00
{
SetYaw ( 270 );
2014-09-22 18:23:56 -04:00
SetSpeedX ( NO_SPEED );
2014-01-24 19:39:39 +00:00
2014-09-22 18:23:56 -04:00
if ( GetSpeedZ () > NO_SPEED )
2014-01-24 19:39:39 +00:00
{
2017-10-21 17:53:24 +01:00
ApplyAcceleration ({ 0.0 , 0.0 , 1.0 }, Acceleration );
2014-01-24 19:39:39 +00:00
SetSpeedY ( GetSpeedZ ());
}
else
{
2017-10-21 17:53:24 +01:00
ApplyAcceleration ({ 0.0 , 0.0 , - 1.0 }, Acceleration );
2016-02-21 02:46:36 +01:00
SetSpeedY ( GetSpeedZ ());
2014-01-24 19:39:39 +00:00
}
break ;
2014-01-19 19:31:17 +00:00
}
default : ASSERT ( ! "Unhandled powered rail metadata!" ); break ;
2014-01-12 13:28:37 +00:00
}
}
2015-01-16 13:42:44 +00:00
void cMinecart :: HandleDetectorRailPhysics ( NIBBLETYPE a_RailMeta , std :: chrono :: milliseconds a_Dt )
2014-01-13 22:37:09 +00:00
{
m_World -> SetBlockMeta ( m_DetectorRailPosition , a_RailMeta | 0x08 );
2014-01-19 19:31:17 +00:00
// No special handling
HandleRailPhysics ( a_RailMeta & 0x07 , a_Dt );
}
2018-07-26 22:24:36 +01:00
2015-01-16 13:42:44 +00:00
void cMinecart :: HandleActivatorRailPhysics ( NIBBLETYPE a_RailMeta , std :: chrono :: milliseconds a_Dt )
2014-01-19 19:31:17 +00:00
{
2014-01-13 22:37:09 +00:00
HandleRailPhysics ( a_RailMeta & 0x07 , a_Dt );
}
2014-01-12 13:28:37 +00:00
void cMinecart :: SnapToRail ( NIBBLETYPE a_RailMeta )
{
switch ( a_RailMeta )
{
case E_META_RAIL_ASCEND_XM :
case E_META_RAIL_ASCEND_XP :
case E_META_RAIL_XM_XP :
{
2014-09-22 18:23:56 -04:00
SetSpeedZ ( NO_SPEED );
2014-01-13 22:37:09 +00:00
SetPosZ ( floor ( GetPosZ ()) + 0.5 );
2014-01-12 13:28:37 +00:00
break ;
}
case E_META_RAIL_ASCEND_ZM :
case E_META_RAIL_ASCEND_ZP :
case E_META_RAIL_ZM_ZP :
{
2014-09-22 18:23:56 -04:00
SetSpeedX ( NO_SPEED );
2014-01-13 22:37:09 +00:00
SetPosX ( floor ( GetPosX ()) + 0.5 );
2014-01-12 13:28:37 +00:00
break ;
}
2014-01-19 18:27:06 +00:00
// Curved rail physics: once minecart has reached more than half of the block in the direction that it is travelling in, jerk it in the direction of curvature
2014-01-18 20:58:26 +00:00
case E_META_RAIL_CURVED_ZM_XM :
{
2014-01-19 18:27:06 +00:00
if ( GetPosZ () > floor ( GetPosZ ()) + 0.5 )
{
2014-09-22 18:23:56 -04:00
if ( GetSpeedZ () > NO_SPEED )
2014-01-19 18:27:06 +00:00
{
SetSpeedX ( - GetSpeedZ () * 0.7 );
}
2014-09-22 18:23:56 -04:00
SetSpeedZ ( NO_SPEED );
2014-01-19 18:27:06 +00:00
SetPosZ ( floor ( GetPosZ ()) + 0.5 );
}
else if ( GetPosX () > floor ( GetPosX ()) + 0.5 )
2014-01-18 20:58:26 +00:00
{
if ( GetSpeedX () > 0 )
{
SetSpeedZ ( - GetSpeedX () * 0.7 );
}
2014-09-22 18:23:56 -04:00
SetSpeedX ( NO_SPEED );
2014-01-18 20:58:26 +00:00
SetPosX ( floor ( GetPosX ()) + 0.5 );
}
2014-09-22 18:23:56 -04:00
SetSpeedY ( NO_SPEED );
2014-01-19 18:27:06 +00:00
break ;
}
case E_META_RAIL_CURVED_ZM_XP :
{
if ( GetPosZ () > floor ( GetPosZ ()) + 0.5 )
2014-01-18 20:58:26 +00:00
{
2014-09-22 18:23:56 -04:00
if ( GetSpeedZ () > NO_SPEED )
2014-01-18 20:58:26 +00:00
{
2014-01-19 18:27:06 +00:00
SetSpeedX ( GetSpeedZ () * 0.7 );
2014-01-18 20:58:26 +00:00
}
2014-09-22 18:23:56 -04:00
SetSpeedZ ( NO_SPEED );
2014-01-18 20:58:26 +00:00
SetPosZ ( floor ( GetPosZ ()) + 0.5 );
}
2014-01-19 18:27:06 +00:00
else if ( GetPosX () < floor ( GetPosX ()) + 0.5 )
2014-01-18 20:58:26 +00:00
{
2014-09-22 18:23:56 -04:00
if ( GetSpeedX () < NO_SPEED )
2014-01-18 20:58:26 +00:00
{
SetSpeedZ ( GetSpeedX () * 0.7 );
}
2014-09-22 18:23:56 -04:00
SetSpeedX ( NO_SPEED );
2014-01-18 20:58:26 +00:00
SetPosX ( floor ( GetPosX ()) + 0.5 );
}
2014-09-22 18:23:56 -04:00
SetSpeedY ( NO_SPEED );
2014-01-18 20:58:26 +00:00
break ;
}
case E_META_RAIL_CURVED_ZP_XM :
{
if ( GetPosZ () < floor ( GetPosZ ()) + 0.5 )
{
2014-09-22 18:23:56 -04:00
if ( GetSpeedZ () < NO_SPEED )
2014-01-18 20:58:26 +00:00
{
SetSpeedX ( GetSpeedZ () * 0.7 );
}
2014-09-22 18:23:56 -04:00
SetSpeedZ ( NO_SPEED );
2014-01-18 20:58:26 +00:00
SetPosZ ( floor ( GetPosZ ()) + 0.5 );
}
2014-01-19 18:27:06 +00:00
else if ( GetPosX () > floor ( GetPosX ()) + 0.5 )
2014-01-18 20:58:26 +00:00
{
2014-09-22 18:23:56 -04:00
if ( GetSpeedX () > NO_SPEED )
2014-01-18 20:58:26 +00:00
{
SetSpeedZ ( GetSpeedX () * 0.7 );
}
2014-09-22 18:23:56 -04:00
SetSpeedX ( NO_SPEED );
2014-01-18 20:58:26 +00:00
SetPosX ( floor ( GetPosX ()) + 0.5 );
}
2014-09-22 18:23:56 -04:00
SetSpeedY ( NO_SPEED );
2014-01-18 20:58:26 +00:00
break ;
}
case E_META_RAIL_CURVED_ZP_XP :
{
if ( GetPosZ () < floor ( GetPosZ ()) + 0.5 )
{
2014-09-22 18:23:56 -04:00
if ( GetSpeedZ () < NO_SPEED )
2014-01-18 20:58:26 +00:00
{
SetSpeedX ( - GetSpeedZ () * 0.7 );
}
2014-09-22 18:23:56 -04:00
SetSpeedZ ( NO_SPEED );
2014-01-18 20:58:26 +00:00
SetPosZ ( floor ( GetPosZ ()) + 0.5 );
}
2014-01-19 18:27:06 +00:00
else if ( GetPosX () < floor ( GetPosX ()) + 0.5 )
2014-01-18 20:58:26 +00:00
{
2014-09-22 18:23:56 -04:00
if ( GetSpeedX () < NO_SPEED )
2014-01-18 20:58:26 +00:00
{
SetSpeedZ ( - GetSpeedX () * 0.7 );
}
2014-09-22 18:23:56 -04:00
SetSpeedX ( NO_SPEED );
2014-01-18 20:58:26 +00:00
SetPosX ( floor ( GetPosX ()) + 0.5 );
}
2014-01-19 19:31:17 +00:00
SetSpeedY ( 0 );
2014-01-18 20:58:26 +00:00
break ;
}
2014-01-12 13:28:37 +00:00
default : break ;
}
2013-09-02 12:01:49 +01:00
}
2013-08-27 20:38:11 +01:00
2013-09-02 12:01:49 +01:00
2020-05-04 21:04:21 +00:00
bool cMinecart :: IsSolidBlockAtPosition ( Vector3i a_Pos )
{
BLOCKTYPE Block = m_World -> GetBlock ( a_Pos );
return ! IsBlockRail ( Block ) && cBlockInfo :: IsSolid ( Block );
}
2016-12-10 09:53:35 +01:00
bool cMinecart :: IsSolidBlockAtOffset ( int a_XOffset , int a_YOffset , int a_ZOffset )
{
2020-05-04 21:04:21 +00:00
return IsSolidBlockAtPosition ({ POSX_TOINT + a_XOffset , POSY_TOINT + a_YOffset , POSZ_TOINT + a_ZOffset });
}
bool cMinecart :: IsBlockCollisionAtOffset ( Vector3i a_Offset )
{
auto BlockPosition = GetPosition (). Floor () + a_Offset ;
if ( ! IsSolidBlockAtPosition ( BlockPosition ))
2016-12-10 09:53:35 +01:00
{
return false ;
}
2020-05-04 21:04:21 +00:00
auto bbBlock = cBoundingBox (
static_cast < Vector3d > ( BlockPosition ),
static_cast < Vector3d > ( BlockPosition + Vector3i ( 1 , 1 , 1 ))
);
return GetBoundingBox (). DoesIntersect ( bbBlock );
2016-12-10 09:53:35 +01:00
}
2014-01-13 22:37:09 +00:00
bool cMinecart :: TestBlockCollision ( NIBBLETYPE a_RailMeta )
{
2020-05-04 21:04:21 +00:00
auto SpeedX = GetSpeedX ();
auto SpeedZ = GetSpeedZ ();
// Don't do anything if minecarts aren't moving.
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wfloat-equal"
#endif
if (( SpeedX == 0 ) && ( SpeedZ == 0 ))
{
return false ;
}
#ifdef __clang__
#pragma clang diagnostic pop
#endif
auto StopTheCart = true ;
auto StopOffset = Vector3d ();
2014-01-13 22:37:09 +00:00
switch ( a_RailMeta )
{
case E_META_RAIL_ZM_ZP :
{
2020-05-04 21:04:21 +00:00
if ( SpeedZ > 0 )
2014-01-13 22:37:09 +00:00
{
2020-05-04 21:04:21 +00:00
StopOffset = Vector3d ( 0 , 0 , 0.4 );
StopTheCart = IsBlockCollisionAtOffset ({ 0 , 0 , 1 });
2014-01-13 22:37:09 +00:00
}
2020-05-04 21:04:21 +00:00
else // SpeedZ < 0
2014-01-13 22:37:09 +00:00
{
2020-05-04 21:04:21 +00:00
StopTheCart = IsBlockCollisionAtOffset ({ 0 , 0 , - 1 });
StopOffset = Vector3d ( 0 , 0 , 0.65 );
2014-01-13 22:37:09 +00:00
}
break ;
}
case E_META_RAIL_XM_XP :
{
2020-05-04 21:04:21 +00:00
if ( SpeedX > 0 )
2014-01-13 22:37:09 +00:00
{
2020-05-04 21:04:21 +00:00
StopTheCart = IsBlockCollisionAtOffset ({ 1 , 0 , 0 });
StopOffset = Vector3d ( 0.4 , 0 , 0 );
2014-01-13 22:37:09 +00:00
}
2020-05-04 21:04:21 +00:00
else // SpeedX < 0
2014-01-13 22:37:09 +00:00
{
2020-05-04 21:04:21 +00:00
StopTheCart = IsBlockCollisionAtOffset ({ - 1 , 0 , 0 });
StopOffset = Vector3d ( 0.65 , 0 , 0 );
2014-01-13 22:37:09 +00:00
}
break ;
2014-07-17 22:59:02 +02:00
}
2020-05-04 21:04:21 +00:00
// Ascending rails check for one block on the way up, two on the way down.
case E_META_RAIL_ASCEND_XM :
2016-02-23 22:27:42 +01:00
{
2020-05-04 21:04:21 +00:00
StopOffset = Vector3d ( 0.5 , 0 , 0 );
2016-02-23 22:27:42 +01:00
2020-05-04 21:04:21 +00:00
if ( SpeedX < 0 )
{
StopTheCart = IsBlockCollisionAtOffset ({ - 1 , 1 , 0 });
}
else // SpeedX > 0
2016-02-23 22:27:42 +01:00
{
2020-05-04 21:04:21 +00:00
StopTheCart = IsBlockCollisionAtOffset ({ 1 , 0 , 0 }) || IsBlockCollisionAtOffset ({ 1 , 1 , 0 });
2016-02-23 22:27:42 +01:00
}
2020-05-04 21:04:21 +00:00
break ;
}
case E_META_RAIL_ASCEND_XP :
{
StopOffset = Vector3d ( 0.5 , 0 , 0 );
2016-02-23 22:27:42 +01:00
2020-05-04 21:04:21 +00:00
if ( SpeedX > 0 )
{
StopTheCart = IsBlockCollisionAtOffset ({ 1 , 1 , 0 });
}
else // SpeedX < 0
{
StopTheCart = IsBlockCollisionAtOffset ({ - 1 , 0 , 0 }) || IsBlockCollisionAtOffset ({ - 1 , 1 , 0 });
}
2016-02-23 22:27:42 +01:00
break ;
}
2020-05-04 21:04:21 +00:00
case E_META_RAIL_ASCEND_ZM :
2016-02-23 22:27:42 +01:00
{
2020-05-04 21:04:21 +00:00
StopOffset = Vector3d ( 0 , 0 , 0.5 );
2016-02-23 22:27:42 +01:00
2020-05-04 21:04:21 +00:00
if ( SpeedZ < 0 )
2016-02-23 22:27:42 +01:00
{
2020-05-04 21:04:21 +00:00
StopTheCart = IsBlockCollisionAtOffset ({ 0 , 1 , - 1 });
2016-02-23 22:27:42 +01:00
}
2020-05-04 21:04:21 +00:00
else // SpeedZ > 0
{
StopTheCart = IsBlockCollisionAtOffset ({ 0 , 0 , 1 }) || IsBlockCollisionAtOffset ({ 0 , 1 , 1 });
}
break ;
}
case E_META_RAIL_ASCEND_ZP :
{
StopOffset = Vector3d ( 0 , 0 , 0.5 );
2016-02-23 22:27:42 +01:00
2020-05-04 21:04:21 +00:00
if ( SpeedZ > 0 )
{
StopTheCart = IsBlockCollisionAtOffset ({ 0 , 1 , 1 });
}
else // SpeedZ < 0
{
StopTheCart = IsBlockCollisionAtOffset ({ 0 , 0 , - 1 }) || IsBlockCollisionAtOffset ({ 0 , 1 , - 1 });
}
2016-02-23 22:27:42 +01:00
break ;
}
2020-05-04 21:04:21 +00:00
// Curved rails allow movement across both the x and z axes. But when the cart is
// moving towards one of the rail endpoints, it will always have velocity towards
// the direction of that endpoint in the same axis.
case E_META_RAIL_CURVED_ZP_XP :
{
StopOffset = Vector3d ( 0.5 , 0 , 0.5 );
if ( SpeedZ > 0 )
{
StopTheCart = IsBlockCollisionAtOffset ({ 0 , 0 , 1 });
break ;
}
if ( SpeedX > 0 )
{
StopTheCart = IsBlockCollisionAtOffset ({ 1 , 0 , 0 });
break ;
}
break ;
}
2014-01-13 22:37:09 +00:00
case E_META_RAIL_CURVED_ZP_XM :
{
2020-05-04 21:04:21 +00:00
StopOffset = Vector3d ( 0.5 , 0 , 0.5 );
2016-02-23 22:27:42 +01:00
2020-05-04 21:04:21 +00:00
if ( SpeedZ > 0 )
2016-02-23 22:27:42 +01:00
{
2020-05-04 21:04:21 +00:00
StopTheCart = IsBlockCollisionAtOffset ({ 0 , 0 , 1 });
break ;
}
if ( SpeedX < 0 )
{
StopTheCart = IsBlockCollisionAtOffset ({ - 1 , 0 , 0 });
break ;
2016-02-23 22:27:42 +01:00
}
break ;
}
2020-05-04 21:04:21 +00:00
case E_META_RAIL_CURVED_ZM_XM :
2016-02-23 22:27:42 +01:00
{
2020-05-04 21:04:21 +00:00
StopOffset = Vector3d ( 0.5 , 0 , 0.5 );
2016-02-23 22:27:42 +01:00
2020-05-04 21:04:21 +00:00
if ( SpeedZ < 0 )
{
StopTheCart = IsBlockCollisionAtOffset ({ 0 , 0 , - 1 });
break ;
}
if ( SpeedX < 0 )
2014-01-13 22:37:09 +00:00
{
2020-05-04 21:04:21 +00:00
StopTheCart = IsBlockCollisionAtOffset ({ - 1 , 0 , 0 });
break ;
2014-01-13 22:37:09 +00:00
}
2016-02-23 22:27:42 +01:00
2014-01-13 22:37:09 +00:00
break ;
2020-05-04 21:04:21 +00:00
}
case E_META_RAIL_CURVED_ZM_XP :
{
StopOffset = Vector3d ( 0.5 , 0 , 0.5 );
if ( SpeedZ < 0 )
{
StopTheCart = IsBlockCollisionAtOffset ({ 0 , 0 , - 1 });
break ;
}
if ( SpeedX > 0 )
{
StopTheCart = IsBlockCollisionAtOffset ({ 1 , 0 , 0 });
break ;
}
break ;
2014-01-13 22:37:09 +00:00
}
}
2020-05-04 21:04:21 +00:00
if ( StopTheCart )
{
SetSpeed ( 0 , 0 , 0 );
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wfloat-equal"
#endif
if ( StopOffset . x != 0 )
{
SetPosX ( POSX_TOINT + StopOffset . x );
}
if ( StopOffset . z != 0 )
{
SetPosZ ( POSZ_TOINT + StopOffset . z );
}
#ifdef __clang__
#pragma clang diagnostic pop
#endif
return true ;
}
2014-01-13 22:37:09 +00:00
return false ;
}
2018-07-26 22:24:36 +01:00
2014-01-18 20:58:26 +00:00
bool cMinecart :: TestEntityCollision ( NIBBLETYPE a_RailMeta )
{
2015-03-21 15:18:17 +01:00
cMinecartCollisionCallback MinecartCollisionCallback (
GetPosition (), GetHeight (), GetWidth (), GetUniqueID (),
(( m_Attachee == nullptr ) ? cEntity :: INVALID_ID : m_Attachee -> GetUniqueID ())
);
2014-01-19 18:42:05 +00:00
int ChunkX , ChunkZ ;
2014-04-17 18:50:25 +01:00
cChunkDef :: BlockToChunk ( POSX_TOINT , POSZ_TOINT , ChunkX , ChunkZ );
2014-01-19 18:42:05 +00:00
m_World -> ForEachEntityInChunk ( ChunkX , ChunkZ , MinecartCollisionCallback );
if ( ! MinecartCollisionCallback . FoundIntersection ())
{
return false ;
}
2014-01-18 20:58:26 +00:00
switch ( a_RailMeta )
{
case E_META_RAIL_ZM_ZP :
{
2014-01-19 18:42:05 +00:00
if ( MinecartCollisionCallback . GetCollidedEntityPosition (). z >= GetPosZ ())
2014-01-18 20:58:26 +00:00
{
2016-02-16 17:02:05 +01:00
if ( GetSpeedZ () > 0 ) // True if minecart is moving into the direction of the entity
2014-01-18 20:58:26 +00:00
{
2016-02-16 17:02:05 +01:00
SetSpeedZ ( 0 ); // Entity handles the pushing
2014-01-18 20:58:26 +00:00
}
}
2016-02-16 17:02:05 +01:00
else // if (MinecartCollisionCallback.GetCollidedEntityPosition().z < GetPosZ())
2014-01-19 18:42:05 +00:00
{
2016-02-16 17:02:05 +01:00
if ( GetSpeedZ () < 0 ) // True if minecart is moving into the direction of the entity
2014-01-19 18:42:05 +00:00
{
2016-02-16 17:02:05 +01:00
SetSpeedZ ( 0 ); // Entity handles the pushing
2014-01-19 18:42:05 +00:00
}
}
return true ;
2014-01-18 20:58:26 +00:00
}
case E_META_RAIL_XM_XP :
{
2014-01-19 18:42:05 +00:00
if ( MinecartCollisionCallback . GetCollidedEntityPosition (). x >= GetPosX ())
{
2016-02-16 17:02:05 +01:00
if ( GetSpeedX () > 0 ) // True if minecart is moving into the direction of the entity
2014-01-19 18:42:05 +00:00
{
2016-02-16 17:02:05 +01:00
SetSpeedX ( 0 ); // Entity handles the pushing
2014-01-19 18:42:05 +00:00
}
}
2016-02-16 17:02:05 +01:00
else // if (MinecartCollisionCallback.GetCollidedEntityPosition().x < GetPosX())
2014-01-19 18:42:05 +00:00
{
2016-02-16 17:02:05 +01:00
if ( GetSpeedX () < 0 ) // True if minecart is moving into the direction of the entity
2014-01-19 18:42:05 +00:00
{
2016-02-16 17:02:05 +01:00
SetSpeedX ( 0 ); // Entity handles the pushing
2014-01-19 18:42:05 +00:00
}
}
return true ;
2014-07-17 22:59:02 +02:00
}
2014-01-18 20:58:26 +00:00
case E_META_RAIL_CURVED_ZM_XM :
2014-08-13 18:53:23 +02:00
case E_META_RAIL_CURVED_ZP_XP :
{
2014-08-14 14:29:46 +02:00
Vector3d Distance = MinecartCollisionCallback . GetCollidedEntityPosition () - Vector3d ( GetPosX (), 0 , GetPosZ ());
2014-08-13 18:53:23 +02:00
2014-08-15 13:40:56 +02:00
// Prevent division by small numbers
2014-09-22 03:22:36 -04:00
if ( std :: abs ( Distance . z ) < 0.001 )
2014-08-15 17:54:43 +02:00
{
Distance . z = 0.001 ;
}
2014-08-13 19:18:11 +02:00
2014-08-15 13:40:56 +02:00
/* Check to which side the minecart is to be pushed.
2015-05-09 09:25:09 +02:00
Let's consider a z-x-coordinate system where the minecart is the center (0, 0).
2014-08-15 14:00:51 +02:00
The minecart moves along the line x = -z, the perpendicular line to this is x = z.
2014-08-15 13:43:45 +02:00
In order to decide to which side the minecart is to be pushed, it must be checked on what side of the perpendicular line the pushing entity is located. */
2014-08-14 14:29:46 +02:00
if (
(( Distance . z > 0 ) && (( Distance . x / Distance . z ) >= 1 )) ||
(( Distance . z < 0 ) && (( Distance . x / Distance . z ) <= 1 ))
)
2014-08-18 01:57:44 +02:00
{
2014-08-24 15:03:02 +02:00
// Moving -X +Z
2014-08-30 22:11:09 +02:00
if (( - GetSpeedX () * 0.4 / sqrt ( 2.0 )) < 0.01 )
2014-08-18 01:57:44 +02:00
{
2014-08-24 15:03:02 +02:00
// ~ SpeedX >= 0 Immobile or not moving in the "right" direction. Give it a bump!
2014-08-30 22:11:09 +02:00
AddSpeedX ( - 4 / sqrt ( 2.0 ));
AddSpeedZ ( 4 / sqrt ( 2.0 ));
2014-08-13 18:53:23 +02:00
}
2014-08-18 01:57:44 +02:00
else
{
2014-08-24 15:03:02 +02:00
// ~ SpeedX < 0 Moving in the "right" direction. Only accelerate it a bit.
2014-08-30 22:11:09 +02:00
SetSpeedX ( GetSpeedX () * 0.4 / sqrt ( 2.0 ));
SetSpeedZ ( GetSpeedZ () * 0.4 / sqrt ( 2.0 ));
2014-08-13 18:53:23 +02:00
}
2014-08-18 01:57:44 +02:00
}
2014-08-30 22:11:09 +02:00
else if (( GetSpeedX () * 0.4 / sqrt ( 2.0 )) < 0.01 )
2014-08-18 01:57:44 +02:00
{
2014-08-28 17:04:26 +03:00
// Moving +X -Z
2014-08-24 15:03:02 +02:00
// ~ SpeedX <= 0 Immobile or not moving in the "right" direction
2014-08-30 22:11:09 +02:00
AddSpeedX ( 4 / sqrt ( 2.0 ));
AddSpeedZ ( - 4 / sqrt ( 2.0 ));
2014-08-13 19:47:43 +02:00
}
2014-08-18 01:57:44 +02:00
else
{
2014-08-24 15:03:02 +02:00
// ~ SpeedX > 0 Moving in the "right" direction
2014-08-30 22:11:09 +02:00
SetSpeedX ( GetSpeedX () * 0.4 / sqrt ( 2.0 ));
SetSpeedZ ( GetSpeedZ () * 0.4 / sqrt ( 2.0 ));
2014-08-13 18:53:23 +02:00
}
break ;
}
2014-01-18 20:58:26 +00:00
case E_META_RAIL_CURVED_ZM_XP :
case E_META_RAIL_CURVED_ZP_XM :
{
2014-08-14 14:29:46 +02:00
Vector3d Distance = MinecartCollisionCallback . GetCollidedEntityPosition () - Vector3d ( GetPosX (), 0 , GetPosZ ());
2014-08-13 18:53:23 +02:00
2014-08-15 13:40:56 +02:00
// Prevent division by small numbers
2014-09-22 03:22:36 -04:00
if ( std :: abs ( Distance . z ) < 0.001 )
2014-08-15 17:54:43 +02:00
{
Distance . z = 0.001 ;
}
2014-08-13 19:16:00 +02:00
2014-08-15 13:40:56 +02:00
/* Check to which side the minecart is to be pushed.
2015-05-09 09:25:09 +02:00
Let's consider a z-x-coordinate system where the minecart is the center (0, 0).
2014-08-15 14:00:51 +02:00
The minecart moves along the line x = z, the perpendicular line to this is x = -z.
2014-08-15 13:40:56 +02:00
In order to decide to which side the minecart is to be pushed, it must be checked on what side of the perpendicular line the pushing entity is located. */
2014-08-18 01:57:44 +02:00
if (
2014-08-14 14:29:46 +02:00
(( Distance . z > 0 ) && (( Distance . x / Distance . z ) <= - 1 )) ||
(( Distance . z < 0 ) && (( Distance . x / Distance . z ) >= - 1 ))
)
2014-08-13 18:53:23 +02:00
{
2014-08-24 15:03:02 +02:00
// Moving +X +Z
2014-08-18 01:57:44 +02:00
if (( GetSpeedX () * 0.4 ) < 0.01 )
{
2014-08-24 15:03:02 +02:00
// ~ SpeedX <= 0 Immobile or not moving in the "right" direction
2014-08-30 22:11:09 +02:00
AddSpeedX ( 4 / sqrt ( 2.0 ));
AddSpeedZ ( 4 / sqrt ( 2.0 ));
2014-08-13 18:53:23 +02:00
}
2014-08-18 01:57:44 +02:00
else
{
2014-08-24 15:03:02 +02:00
// ~ SpeedX > 0 Moving in the "right" direction
2014-08-30 22:11:09 +02:00
SetSpeedX ( GetSpeedX () * 0.4 / sqrt ( 2.0 ));
SetSpeedZ ( GetSpeedZ () * 0.4 / sqrt ( 2.0 ));
2014-08-13 18:53:23 +02:00
}
2014-08-18 01:57:44 +02:00
}
else if (( - GetSpeedX () * 0.4 ) < 0.01 )
{
2014-08-24 15:03:02 +02:00
// Moving -X -Z
// ~ SpeedX >= 0 Immobile or not moving in the "right" direction
2014-08-30 22:11:09 +02:00
AddSpeedX ( - 4 / sqrt ( 2.0 ));
AddSpeedZ ( - 4 / sqrt ( 2.0 ));
2014-08-13 19:47:43 +02:00
}
2014-08-18 01:57:44 +02:00
else
{
2014-08-24 15:03:02 +02:00
// ~ SpeedX < 0 Moving in the "right" direction
2014-08-30 22:11:09 +02:00
SetSpeedX ( GetSpeedX () * 0.4 / sqrt ( 2.0 ));
SetSpeedZ ( GetSpeedZ () * 0.4 / sqrt ( 2.0 ));
2014-08-13 18:53:23 +02:00
}
2014-01-18 20:58:26 +00:00
break ;
}
default : break ;
}
2014-01-19 18:42:05 +00:00
2014-01-18 20:58:26 +00:00
return false ;
}
2014-01-13 22:37:09 +00:00
2014-04-26 00:32:30 +02:00
bool cMinecart :: DoTakeDamage ( TakeDamageInfo & TDI )
2013-09-02 12:01:49 +01:00
{
2015-05-24 12:56:56 +01:00
if (( TDI . Attacker != nullptr ) && TDI . Attacker -> IsPlayer () && static_cast < cPlayer *> ( TDI . Attacker ) -> IsGameModeCreative ())
2014-01-12 13:28:37 +00:00
{
2019-08-08 13:51:38 +03:00
TDI . FinalDamage = GetMaxHealth (); // Instant hit for creative
2014-04-26 00:32:30 +02:00
SetInvulnerableTicks ( 0 );
2020-04-13 18:38:06 +02:00
return Super :: DoTakeDamage ( TDI ); // No drops for creative
2014-01-12 13:28:37 +00:00
}
2019-08-08 13:51:38 +03:00
m_LastDamage = static_cast < int > ( TDI . FinalDamage );
2020-04-13 18:38:06 +02:00
if ( ! Super :: DoTakeDamage ( TDI ))
2014-04-26 00:32:30 +02:00
{
return false ;
}
2013-09-02 12:01:49 +01:00
2013-10-08 19:20:49 +01:00
m_World -> BroadcastEntityMetadata ( * this );
2021-01-02 13:50:34 +00:00
return true ;
}
2016-02-05 23:45:45 +02:00
2021-01-02 13:50:34 +00:00
void cMinecart :: KilledBy ( TakeDamageInfo & a_TDI )
{
Super :: KilledBy ( a_TDI );
Destroy ();
}
void cMinecart :: OnRemoveFromWorld ( cWorld & a_World )
{
if ( m_bIsOnDetectorRail )
{
m_World -> SetBlock ( m_DetectorRailPosition . x , m_DetectorRailPosition . y , m_DetectorRailPosition . z , E_BLOCK_DETECTOR_RAIL , m_World -> GetBlockMeta ( m_DetectorRailPosition ) & 0x07 );
2013-09-02 12:01:49 +01:00
}
2021-01-02 13:50:34 +00:00
Super :: OnRemoveFromWorld ( a_World );
2013-07-29 12:13:03 +01:00
}
2017-10-21 17:53:24 +01:00
void cMinecart :: ApplyAcceleration ( Vector3d a_ForwardDirection , double a_Acceleration )
{
double CurSpeed = GetSpeed (). Dot ( a_ForwardDirection );
double NewSpeed = CurSpeed + a_Acceleration ;
if ( NewSpeed < 0.0 )
{
// Prevent deceleration from turning the minecart around.
NewSpeed = 0.0 ;
}
auto Acceleration = a_ForwardDirection * ( NewSpeed - CurSpeed );
AddSpeed ( Acceleration );
}
2016-02-21 02:46:36 +01:00
void cMinecart :: DoSetSpeed ( double a_SpeedX , double a_SpeedY , double a_SpeedZ )
{
if ( a_SpeedX > MAX_SPEED )
{
a_SpeedX = MAX_SPEED ;
}
else if ( a_SpeedX < MAX_SPEED_NEGATIVE )
{
a_SpeedX = MAX_SPEED_NEGATIVE ;
}
if ( a_SpeedY > MAX_SPEED )
{
a_SpeedY = MAX_SPEED ;
}
else if ( a_SpeedY < MAX_SPEED_NEGATIVE )
{
a_SpeedY = MAX_SPEED_NEGATIVE ;
}
if ( a_SpeedZ > MAX_SPEED )
{
a_SpeedZ = MAX_SPEED ;
}
else if ( a_SpeedZ < MAX_SPEED_NEGATIVE )
{
a_SpeedZ = MAX_SPEED_NEGATIVE ;
}
2020-04-13 18:38:06 +02:00
Super :: DoSetSpeed ( a_SpeedX , a_SpeedY , a_SpeedZ );
2016-02-21 02:46:36 +01:00
}
2014-07-17 22:15:34 +02:00
////////////////////////////////////////////////////////////////////////////////
2014-01-12 18:04:41 +01:00
// cRideableMinecart:
2013-07-29 12:13:03 +01:00
2019-09-29 14:59:24 +02:00
cRideableMinecart :: cRideableMinecart ( Vector3d a_Pos , const cItem & a_Content , int a_Height ) :
2020-04-13 18:38:06 +02:00
Super ( mpNone , a_Pos ),
2014-01-12 15:27:50 +01:00
m_Content ( a_Content ),
m_Height ( a_Height )
2013-07-29 12:13:03 +01:00
{
}
2021-01-02 13:50:34 +00:00
void cRideableMinecart :: GetDrops ( cItems & a_Drops , cEntity * a_Killer )
{
a_Drops . emplace_back ( E_ITEM_MINECART );
}
2014-01-12 18:04:41 +01:00
void cRideableMinecart :: OnRightClicked ( cPlayer & a_Player )
2013-07-29 12:13:03 +01:00
{
2020-04-13 18:38:06 +02:00
Super :: OnRightClicked ( a_Player );
2014-09-01 21:05:45 +02:00
2014-10-20 21:55:07 +01:00
if ( m_Attachee != nullptr )
2013-07-29 12:13:03 +01:00
{
if ( m_Attachee -> GetUniqueID () == a_Player . GetUniqueID ())
{
// This player is already sitting in, they want out.
a_Player . Detach ();
return ;
}
2016-02-05 23:45:45 +02:00
2013-07-29 12:13:03 +01:00
if ( m_Attachee -> IsPlayer ())
{
// Another player is already sitting in here, cannot attach
return ;
}
2016-02-05 23:45:45 +02:00
2013-07-29 12:13:03 +01:00
// Detach whatever is sitting in this minecart now:
m_Attachee -> Detach ();
}
2016-02-05 23:45:45 +02:00
2013-07-29 12:13:03 +01:00
// Attach the player to this minecart
a_Player . AttachTo ( this );
}
2014-07-17 22:15:34 +02:00
////////////////////////////////////////////////////////////////////////////////
2013-07-29 12:13:03 +01:00
// cMinecartWithChest:
2019-09-29 14:59:24 +02:00
cMinecartWithChest :: cMinecartWithChest ( Vector3d a_Pos ) :
2020-04-13 18:38:06 +02:00
Super ( mpChest , a_Pos ),
2014-09-28 13:11:41 +01:00
cEntityWindowOwner ( this ),
m_Contents ( ContentsWidth , ContentsHeight )
2013-07-29 12:13:03 +01:00
{
2014-09-12 23:18:02 +01:00
m_Contents . AddListener ( * this );
2013-07-29 12:13:03 +01:00
}
2021-01-02 13:50:34 +00:00
void cMinecartWithChest :: GetDrops ( cItems & a_Drops , cEntity * a_Killer )
{
m_Contents . CopyToItems ( a_Drops );
a_Drops . emplace_back ( E_ITEM_CHEST_MINECART );
}
void cMinecartWithChest :: OnRemoveFromWorld ( cWorld & a_World )
{
const auto Window = GetWindow ();
if ( Window != nullptr )
{
Window -> OwnerDestroyed ();
}
Super :: OnRemoveFromWorld ( a_World );
}
2014-09-12 23:18:02 +01:00
void cMinecartWithChest :: OnRightClicked ( cPlayer & a_Player )
2013-07-29 12:13:03 +01:00
{
2014-09-12 23:18:02 +01:00
// If the window is not created, open it anew:
cWindow * Window = GetWindow ();
2014-10-20 21:55:07 +01:00
if ( Window == nullptr )
2014-09-12 23:18:02 +01:00
{
OpenNewWindow ();
Window = GetWindow ();
}
// Open the window for the player:
2014-10-20 21:55:07 +01:00
if ( Window != nullptr )
2014-09-12 23:18:02 +01:00
{
if ( a_Player . GetWindow () != Window )
{
2017-05-29 21:33:30 +02:00
a_Player . OpenWindow ( * Window );
2014-09-12 23:18:02 +01:00
}
}
2013-07-29 12:13:03 +01:00
}
2014-09-12 23:18:02 +01:00
void cMinecartWithChest :: OpenNewWindow ()
{
OpenWindow ( new cMinecartWithChestWindow ( this ));
}
2014-07-17 22:15:34 +02:00
////////////////////////////////////////////////////////////////////////////////
2013-07-29 12:13:03 +01:00
// cMinecartWithFurnace:
2019-09-29 14:59:24 +02:00
cMinecartWithFurnace :: cMinecartWithFurnace ( Vector3d a_Pos ) :
2020-04-13 18:38:06 +02:00
Super ( mpFurnace , a_Pos ),
2014-02-05 09:43:49 -08:00
m_FueledTimeLeft ( - 1 ),
m_IsFueled ( false )
2013-07-29 12:13:03 +01:00
{
}
2021-01-02 13:50:34 +00:00
void cMinecartWithFurnace :: GetDrops ( cItems & a_Drops , cEntity * a_Killer )
{
a_Drops . emplace_back ( E_ITEM_FURNACE_MINECART );
}
2013-07-29 12:13:03 +01:00
void cMinecartWithFurnace :: OnRightClicked ( cPlayer & a_Player )
{
2013-10-08 19:20:49 +01:00
if ( a_Player . GetEquippedItem (). m_ItemType == E_ITEM_COAL )
{
if ( ! a_Player . IsGameModeCreative ())
{
a_Player . GetInventory (). RemoveOneEquippedItem ();
}
2014-07-17 22:15:34 +02:00
if ( ! m_IsFueled ) // We don't want to change the direction by right clicking it.
2014-01-15 14:03:09 +01:00
{
AddSpeed ( a_Player . GetLookVector (). x , 0 , a_Player . GetLookVector (). z );
}
2013-10-08 19:20:49 +01:00
m_IsFueled = true ;
2014-07-17 22:15:34 +02:00
m_FueledTimeLeft = m_FueledTimeLeft + 600 ; // The minecart will be active 600 more ticks.
2013-10-08 19:20:49 +01:00
m_World -> BroadcastEntityMetadata ( * this );
}
2013-07-29 12:13:03 +01:00
}
2015-01-11 21:12:26 +00:00
void cMinecartWithFurnace :: Tick ( std :: chrono :: milliseconds a_Dt , cChunk & a_Chunk )
2014-01-15 14:03:09 +01:00
{
2020-04-13 18:38:06 +02:00
Super :: Tick ( a_Dt , a_Chunk );
2016-09-03 14:31:27 +03:00
if ( ! IsTicking ())
{
// The base class tick destroyed us
return ;
}
2014-01-15 14:03:09 +01:00
if ( m_IsFueled )
{
2014-01-15 14:38:54 +01:00
m_FueledTimeLeft -- ;
if ( m_FueledTimeLeft < 0 )
{
m_IsFueled = false ;
m_World -> BroadcastEntityMetadata ( * this );
return ;
}
2014-01-15 14:03:09 +01:00
if ( GetSpeed (). Length () > 6 )
{
return ;
}
AddSpeed ( GetSpeed () / 4 );
}
}
2014-07-17 22:15:34 +02:00
////////////////////////////////////////////////////////////////////////////////
2013-08-16 11:23:24 +01:00
// cMinecartWithTNT:
2019-09-29 14:59:24 +02:00
cMinecartWithTNT :: cMinecartWithTNT ( Vector3d a_Pos ) :
2020-04-13 18:38:06 +02:00
Super ( mpTNT , a_Pos )
2013-08-16 11:23:24 +01:00
{
}
// TODO: Make it activate when passing over activator rail
2021-01-02 13:50:34 +00:00
void cMinecartWithTNT :: GetDrops ( cItems & a_Drops , cEntity * a_Killer )
{
a_Drops . emplace_back ( E_ITEM_MINECART_WITH_TNT );
}
2014-07-17 22:15:34 +02:00
////////////////////////////////////////////////////////////////////////////////
2013-08-16 11:23:24 +01:00
// cMinecartWithHopper:
2019-09-29 14:59:24 +02:00
cMinecartWithHopper :: cMinecartWithHopper ( Vector3d a_Pos ) :
2020-04-13 18:38:06 +02:00
Super ( mpHopper , a_Pos )
2013-08-16 11:23:24 +01:00
{
}
// TODO: Make it suck up blocks and travel further than any other cart and physics and put and take blocks
2014-02-05 09:43:49 -08:00
// AND AVARYTHING!!
2021-01-02 13:50:34 +00:00
void cMinecartWithHopper :: GetDrops ( cItems & a_Drops , cEntity * a_Killer )
{
a_Drops . emplace_back ( E_ITEM_MINECART_WITH_HOPPER );
}