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"
2013-08-19 11:39:13 +02:00
# include "../World.h"
# 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"
2013-07-29 12:13:03 +01:00
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
cMinecart : : cMinecart ( ePayload a_Payload , double a_X , double a_Y , double a_Z ) :
super ( etMinecart , a_X , a_Y , a_Z , 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
{
2013-08-28 22:13:27 +01:00
SetMass ( 20.f ) ;
SetMaxHealth ( 6 ) ;
2013-09-02 12:01:49 +01:00
SetHealth ( 6 ) ;
2014-01-13 22:37:09 +00:00
SetWidth ( 1.2 ) ;
SetHeight ( 0.9 ) ;
2013-07-29 12:13:03 +01:00
}
void cMinecart : : SpawnOn ( cClientHandle & a_ClientHandle )
{
2013-08-29 13:47:22 +01:00
char SubType = 0 ;
2013-08-28 22:13:27 +01:00
switch ( m_Payload )
2013-07-29 12:13:03 +01:00
{
2013-08-29 13:47:22 +01:00
case mpNone : SubType = 0 ; break ;
case mpChest : SubType = 1 ; break ;
case mpFurnace : SubType = 2 ; break ;
case mpTNT : SubType = 3 ; break ;
case mpHopper : SubType = 5 ; break ;
2013-07-29 12:13:03 +01:00
default :
{
ASSERT ( ! " Unknown payload, cannot spawn on client " ) ;
return ;
}
}
2013-08-29 14:00:39 +01:00
a_ClientHandle . SendSpawnVehicle ( * this , 10 , SubType ) ; // 10 = Minecarts, SubType = What type of Minecart
2014-01-12 18:04:41 +01:00
a_ClientHandle . SendEntityMetadata ( * this ) ;
2013-07-29 12:13:03 +01:00
}
2013-09-02 12:01:49 +01:00
void cMinecart : : HandlePhysics ( float a_Dt , cChunk & a_Chunk )
2013-07-29 12:13:03 +01:00
{
2014-01-13 22:37:09 +00:00
if ( IsDestroyed ( ) ) // Mainly to stop detector rails triggering again after minecart is dead
{
return ;
}
2013-09-22 21:43:00 +02:00
int PosY = ( int ) floor ( GetPosY ( ) ) ;
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
super : : HandlePhysics ( a_Dt , a_Chunk ) ;
BroadcastMovementUpdate ( ) ;
return ;
}
int RelPosX = ( int ) floor ( GetPosX ( ) ) - a_Chunk . GetPosX ( ) * cChunkDef : : Width ;
int RelPosZ = ( int ) floor ( GetPosZ ( ) ) - a_Chunk . GetPosZ ( ) * cChunkDef : : Width ;
cChunk * Chunk = a_Chunk . GetRelNeighborChunkAdjustCoords ( RelPosX , RelPosZ ) ;
if ( Chunk = = NULL )
{
// 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 ;
Chunk - > GetBlockTypeMeta ( RelPosX , PosY , RelPosZ , InsideType , InsideMeta ) ;
if ( ! IsBlockRail ( InsideType ) )
2013-09-22 21:43:00 +02:00
{
2014-01-13 22:37:09 +00:00
Chunk - > GetBlockTypeMeta ( RelPosX , PosY + 1 , RelPosZ , InsideType , InsideMeta ) ; // When an descending minecart hits a flat rail, it goes through the ground; check for this
if ( IsBlockRail ( InsideType ) ) AddPosY ( 1 ) ; // Push cart upwards
2013-09-22 21:43:00 +02:00
}
2014-01-12 13:28:37 +00:00
if ( IsBlockRail ( InsideType ) )
2013-09-22 21:43:00 +02:00
{
2014-01-13 22:37:09 +00:00
bool WasDetectorRail = false ;
2014-01-12 13:28:37 +00:00
SnapToRail ( InsideMeta ) ;
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
2014-01-13 22:37:09 +00:00
AddPosition ( GetSpeed ( ) * ( a_Dt / 1000 ) ) ; // Commit changes; as we use our own engine when on rails, this needs to be done, whereas it is normally in Entity.cpp
if ( m_bIsOnDetectorRail & & ! WasDetectorRail )
{
m_World - > SetBlock ( m_DetectorRailPosition . x , m_DetectorRailPosition . y , m_DetectorRailPosition . z , E_BLOCK_DETECTOR_RAIL , m_World - > GetBlockMeta ( m_DetectorRailPosition ) & 0x07 ) ;
m_bIsOnDetectorRail = false ;
}
2014-01-12 13:28:37 +00:00
}
else
{
2014-01-13 22:37:09 +00:00
// Not on rail, default physics
2014-01-12 13:28:37 +00: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
super : : HandlePhysics ( a_Dt , * Chunk ) ;
2013-09-02 12:01:49 +01:00
}
2014-01-12 13:28:37 +00: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
}
2014-01-13 22:37:09 +00:00
void cMinecart : : HandleRailPhysics ( NIBBLETYPE a_RailMeta , float 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
*/
2014-01-12 13:28:37 +00:00
switch ( a_RailMeta )
2013-08-27 20:38:11 +01:00
{
2013-09-03 12:33:54 +01: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 ) ;
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
if ( TestBlockCollision ( a_RailMeta ) ) return ;
2013-09-02 12:01:49 +01:00
2014-01-12 13:28:37 +00:00
if ( GetSpeedZ ( ) ! = 0 ) // 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
2014-01-12 13:28:37 +00:00
AddSpeedZ ( - 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
2014-01-12 13:28:37 +00:00
AddSpeedZ ( 0.1 ) ;
2013-08-27 20:38:11 +01:00
}
}
2013-09-02 12:01:49 +01:00
break ;
}
2013-09-03 12:33:54 +01: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 ) ;
SetSpeedY ( 0 ) ;
SetSpeedZ ( 0 ) ;
2013-08-27 20:38:11 +01:00
2014-01-13 22:37:09 +00:00
if ( TestBlockCollision ( a_RailMeta ) ) return ;
2014-01-12 13:28:37 +00:00
if ( GetSpeedX ( ) ! = 0 )
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
{
2014-01-12 13:28:37 +00:00
AddSpeedX ( - 0.1 ) ;
2013-09-02 12:01:49 +01:00
}
else
{
2014-01-12 13:28:37 +00:00
AddSpeedX ( 0.1 ) ;
2013-08-27 20:38:11 +01:00
}
}
2013-09-02 12:01:49 +01:00
break ;
}
2013-09-03 12:33:54 +01: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
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-01-12 13:28:37 +00:00
if ( GetSpeedZ ( ) < = MAX_SPEED ) // Speed limit
2013-08-27 20:38:11 +01:00
{
2014-01-12 13:28:37 +00: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-01-12 13:28:37 +00: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
}
break ;
}
2013-09-03 12:33:54 +01: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
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-01-12 13:28:37 +00:00
AddSpeedZ ( - 1 ) ; // Slow down
SetSpeedY ( GetSpeedZ ( ) ) ; // Upward movement positive
2013-09-02 12:01:49 +01:00
}
else
{
2014-01-12 13:28:37 +00:00
if ( GetSpeedZ ( ) > = MAX_SPEED_NEGATIVE ) // Speed limit
2013-08-27 20:38:11 +01:00
{
2013-09-02 12:01:49 +01:00
// SpeedZ NEGATIVE, going NORTH
2014-01-12 13:28:37 +00:00
AddSpeedZ ( - 0.5 ) ; // Speed up
SetSpeedY ( GetSpeedZ ( ) ) ; // Downward movement negative
2013-08-27 20:38:11 +01:00
}
}
2013-09-02 12:01:49 +01:00
break ;
}
2013-09-03 12:33:54 +01: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-01-12 13:28:37 +00:00
SetSpeedZ ( 0 ) ;
2013-08-27 20:38:11 +01:00
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
if ( GetSpeedX ( ) < = MAX_SPEED )
2013-08-27 20:38:11 +01:00
{
2014-01-12 13:28:37 +00: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
}
break ;
}
2013-09-03 12:33:54 +01: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
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
{
2014-01-12 13:28:37 +00:00
if ( GetSpeedX ( ) > = MAX_SPEED_NEGATIVE )
2013-08-27 20:38:11 +01:00
{
2014-01-12 13:28:37 +00:00
AddSpeedX ( - 0.5 ) ;
SetSpeedY ( GetSpeedX ( ) ) ;
2013-08-27 20:38:11 +01:00
}
}
2013-09-02 12:01:49 +01:00
break ;
}
2013-09-03 12:33:54 +01:00
case E_META_RAIL_CURVED_ZM_XM : // Ends pointing NORTH and WEST
2013-09-02 12:01:49 +01:00
{
2014-01-16 19:00:49 +00:00
SetYaw ( 315 ) ; // Set correct rotation server side
2014-01-13 22:37:09 +00:00
SetPosY ( floor ( GetPosY ( ) ) + 0.55 ) ; // Levitate dat cart
if ( TestBlockCollision ( a_RailMeta ) ) return ;
2013-09-02 12:01:49 +01:00
2014-01-12 13:28:37 +00:00
if ( GetSpeedZ ( ) > 0 ) // Cart moving south
2013-09-02 12:01:49 +01:00
{
2014-01-13 22:37:09 +00:00
int OldX = ( int ) floor ( GetPosX ( ) ) ;
AddSpeedX ( - GetSpeedZ ( ) + 0.5 ) ; // See below
AddPosX ( - GetSpeedZ ( ) * ( a_Dt / 1000 ) ) ; // Diagonally move southwest (which will make cart hit a southwest rail)
// If we are already at southwest rail, set Z speed to zero as we can be moving so fast, MCS doesn't tick fast enough to active the handle for the rail...
// ...and so we derail unexpectedly.
if ( GetPosX ( ) < = OldX - 1 ) SetSpeedZ ( 0 ) ;
2013-09-02 12:01:49 +01:00
}
2014-01-12 13:28:37 +00:00
else if ( GetSpeedX ( ) > 0 ) // Cart moving east
2013-09-02 12:01:49 +01:00
{
2014-01-13 22:37:09 +00:00
int OldZ = ( int ) floor ( GetPosZ ( ) ) ;
AddSpeedZ ( - GetSpeedX ( ) + 0.5 ) ;
AddPosZ ( - GetSpeedX ( ) * ( a_Dt / 1000 ) ) ; // Diagonally move northeast
if ( GetPosZ ( ) < = OldZ - 1 ) SetSpeedX ( 0 ) ;
2013-09-02 12:01:49 +01:00
}
break ;
}
2013-09-03 12:33:54 +01: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 ) ;
if ( TestBlockCollision ( a_RailMeta ) ) return ;
2013-09-02 12:01:49 +01:00
2014-01-12 13:28:37 +00:00
if ( GetSpeedZ ( ) > 0 )
2013-09-02 12:01:49 +01:00
{
2014-01-13 22:37:09 +00:00
int OldX = ( int ) floor ( GetPosX ( ) ) ;
AddSpeedX ( GetSpeedZ ( ) - 0.5 ) ;
AddPosX ( GetSpeedZ ( ) * ( a_Dt / 1000 ) ) ;
if ( GetPosX ( ) > = OldX + 1 ) SetSpeedZ ( 0 ) ;
2013-09-02 12:01:49 +01:00
}
2014-01-12 13:28:37 +00:00
else if ( GetSpeedX ( ) < 0 )
2013-09-02 12:01:49 +01:00
{
2014-01-13 22:37:09 +00:00
int OldZ = ( int ) floor ( GetPosZ ( ) ) ;
AddSpeedZ ( GetSpeedX ( ) + 0.5 ) ;
AddPosZ ( GetSpeedX ( ) * ( a_Dt / 1000 ) ) ;
if ( GetPosZ ( ) < = OldZ - 1 ) SetSpeedX ( 0 ) ;
2013-09-02 12:01:49 +01:00
}
break ;
}
2013-09-03 12:33:54 +01: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 ) ;
if ( TestBlockCollision ( a_RailMeta ) ) return ;
2013-09-02 12:01:49 +01:00
2014-01-12 13:28:37 +00:00
if ( GetSpeedZ ( ) < 0 )
2013-09-02 12:01:49 +01:00
{
2014-01-13 22:37:09 +00:00
int OldX = ( int ) floor ( GetPosX ( ) ) ;
AddSpeedX ( GetSpeedZ ( ) + 0.5 ) ;
AddPosX ( GetSpeedZ ( ) * ( a_Dt / 1000 ) ) ;
if ( GetPosX ( ) < = OldX - 1 ) SetSpeedZ ( 0 ) ;
2013-09-02 12:01:49 +01:00
}
2014-01-12 13:28:37 +00:00
else if ( GetSpeedX ( ) > 0 )
2013-09-02 12:01:49 +01:00
{
2014-01-13 22:37:09 +00:00
int OldZ = ( int ) floor ( GetPosZ ( ) ) ;
AddSpeedZ ( GetSpeedX ( ) - 0.5 ) ;
AddPosZ ( GetSpeedX ( ) * ( a_Dt / 1000 ) ) ;
if ( GetPosZ ( ) > = OldZ + 1 ) SetSpeedX ( 0 ) ;
2013-09-02 12:01:49 +01:00
}
break ;
}
2013-09-03 12:33:54 +01: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 ) ;
if ( TestBlockCollision ( a_RailMeta ) ) return ;
2013-09-02 12:01:49 +01:00
2014-01-12 13:28:37 +00:00
if ( GetSpeedZ ( ) < 0 )
2013-09-02 12:01:49 +01:00
{
2014-01-13 22:37:09 +00:00
int OldX = ( int ) floor ( GetPosX ( ) ) ;
AddSpeedX ( - GetSpeedZ ( ) - 0.5 ) ;
AddPosX ( - GetSpeedZ ( ) * ( a_Dt / 1000 ) ) ;
if ( GetPosX ( ) > = OldX + 1 ) SetSpeedZ ( 0 ) ;
2013-09-02 12:01:49 +01:00
}
2014-01-12 13:28:37 +00:00
else if ( GetSpeedX ( ) < 0 )
2013-08-27 20:38:11 +01:00
{
2014-01-13 22:37:09 +00:00
int OldZ = ( int ) floor ( GetPosZ ( ) ) ;
AddSpeedZ ( - GetSpeedX ( ) - 0.5 ) ;
AddPosZ ( - GetSpeedX ( ) * ( a_Dt / 1000 ) ) ;
if ( GetPosZ ( ) > = OldZ + 1 ) SetSpeedX ( 0 ) ;
2013-08-27 20:38:11 +01:00
}
2013-09-02 12:01:49 +01:00
break ;
}
default :
{
ASSERT ( ! " Unhandled rail meta! " ) ; // Dun dun DUN!
break ;
2013-08-27 20:38:11 +01:00
}
}
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
void cMinecart : : HandlePoweredRailPhysics ( NIBBLETYPE a_RailMeta )
{
2014-01-13 22:37:09 +00:00
// Initialise to 'slow down' values
int AccelDecelSpeed = - 1 ;
int AccelDecelNegSpeed = 1 ;
2014-01-12 13:28:37 +00:00
if ( ( a_RailMeta & 0x8 ) = = 0x8 )
{
2014-01-13 22:37:09 +00:00
// Rail powered - set variables to 'speed up' values
AccelDecelSpeed = 1 ;
AccelDecelNegSpeed = - 1 ;
}
switch ( a_RailMeta & 0x07 )
{
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 ) ;
if ( TestBlockCollision ( a_RailMeta ) ) return ;
2014-01-12 13:28:37 +00:00
2014-01-13 22:37:09 +00:00
if ( GetSpeedZ ( ) ! = 0 )
{
if ( GetSpeedZ ( ) > 0 )
2014-01-12 13:28:37 +00:00
{
2014-01-13 22:37:09 +00:00
AddSpeedZ ( AccelDecelNegSpeed ) ;
}
else
{
AddSpeedZ ( AccelDecelSpeed ) ;
2014-01-12 13:28:37 +00:00
}
}
2014-01-13 22:37:09 +00:00
break ;
}
case E_META_RAIL_XM_XP : // EASTWEST
{
2014-01-16 19:00:49 +00:00
SetYaw ( 180 ) ;
2014-01-13 22:37:09 +00:00
SetPosY ( floor ( GetPosY ( ) ) + 0.55 ) ;
SetSpeedY ( 0 ) ;
SetSpeedZ ( 0 ) ;
2014-01-12 13:28:37 +00:00
2014-01-13 22:37:09 +00:00
if ( TestBlockCollision ( a_RailMeta ) ) return ;
if ( GetSpeedX ( ) ! = 0 )
{
if ( GetSpeedX ( ) > 0 )
2014-01-12 13:28:37 +00:00
{
2014-01-13 22:37:09 +00:00
AddSpeedX ( AccelDecelSpeed ) ;
}
else
{
AddSpeedX ( AccelDecelNegSpeed ) ;
2014-01-12 13:28:37 +00:00
}
}
2014-01-13 22:37:09 +00:00
break ;
2014-01-12 13:28:37 +00:00
}
}
}
2014-01-13 22:37:09 +00:00
void cMinecart : : HandleDetectorRailPhysics ( NIBBLETYPE a_RailMeta , float a_Dt )
{
m_bIsOnDetectorRail = true ;
m_DetectorRailPosition = Vector3i ( ( int ) floor ( GetPosX ( ) ) , ( int ) floor ( GetPosY ( ) ) , ( int ) floor ( GetPosZ ( ) ) ) ;
m_World - > SetBlockMeta ( m_DetectorRailPosition , a_RailMeta | 0x08 ) ;
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 :
{
SetSpeedZ ( 0 ) ;
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 :
{
SetSpeedX ( 0 ) ;
2014-01-13 22:37:09 +00:00
SetPosX ( floor ( GetPosX ( ) ) + 0.5 ) ;
2014-01-12 13:28:37 +00:00
break ;
}
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
2014-01-13 22:37:09 +00:00
bool cMinecart : : TestBlockCollision ( NIBBLETYPE a_RailMeta )
{
switch ( a_RailMeta )
{
case E_META_RAIL_ZM_ZP :
{
if ( GetSpeedZ ( ) > 0 )
{
BLOCKTYPE Block = m_World - > GetBlock ( ( int ) floor ( GetPosX ( ) ) , ( int ) floor ( GetPosY ( ) ) , ( int ) ceil ( GetPosZ ( ) ) ) ;
if ( ! IsBlockRail ( Block ) & & g_BlockIsSolid [ Block ] )
{
// 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 ( ( int ) floor ( GetPosX ( ) ) , ( int ) floor ( GetPosY ( ) ) , ( int ) ceil ( GetPosZ ( ) ) ) , 0.5 , 1 ) ;
cBoundingBox bbMinecart ( Vector3d ( GetPosX ( ) , floor ( GetPosY ( ) ) , GetPosZ ( ) ) , GetWidth ( ) / 2 , GetHeight ( ) ) ;
if ( bbBlock . DoesIntersect ( bbMinecart ) )
{
SetSpeed ( 0 , 0 , 0 ) ;
SetPosZ ( floor ( GetPosZ ( ) ) + 0.4 ) ;
return true ;
}
}
}
else
{
BLOCKTYPE Block = m_World - > GetBlock ( ( int ) floor ( GetPosX ( ) ) , ( int ) floor ( GetPosY ( ) ) , ( int ) floor ( GetPosZ ( ) ) - 1 ) ;
if ( ! IsBlockRail ( Block ) & & g_BlockIsSolid [ Block ] )
{
cBoundingBox bbBlock ( Vector3d ( ( int ) floor ( GetPosX ( ) ) , ( int ) floor ( GetPosY ( ) ) , ( int ) floor ( GetPosZ ( ) ) - 1 ) , 0.5 , 1 ) ;
cBoundingBox bbMinecart ( Vector3d ( GetPosX ( ) , floor ( GetPosY ( ) ) , GetPosZ ( ) - 1 ) , GetWidth ( ) / 2 , GetHeight ( ) ) ;
if ( bbBlock . DoesIntersect ( bbMinecart ) )
{
SetSpeed ( 0 , 0 , 0 ) ;
SetPosZ ( floor ( GetPosZ ( ) ) + 0.65 ) ;
return true ;
}
}
}
break ;
}
case E_META_RAIL_XM_XP :
{
if ( GetSpeedX ( ) > 0 )
{
BLOCKTYPE Block = m_World - > GetBlock ( ( int ) ceil ( GetPosX ( ) ) , ( int ) floor ( GetPosY ( ) ) , ( int ) floor ( GetPosZ ( ) ) ) ;
if ( ! IsBlockRail ( Block ) & & g_BlockIsSolid [ Block ] )
{
cBoundingBox bbBlock ( Vector3d ( ( int ) ceil ( GetPosX ( ) ) , ( int ) floor ( GetPosY ( ) ) , ( int ) floor ( GetPosZ ( ) ) ) , 0.5 , 1 ) ;
cBoundingBox bbMinecart ( Vector3d ( GetPosX ( ) , floor ( GetPosY ( ) ) , GetPosZ ( ) ) , GetWidth ( ) / 2 , GetHeight ( ) ) ;
if ( bbBlock . DoesIntersect ( bbMinecart ) )
{
SetSpeed ( 0 , 0 , 0 ) ;
SetPosX ( floor ( GetPosX ( ) ) + 0.4 ) ;
return true ;
}
}
}
else
{
BLOCKTYPE Block = m_World - > GetBlock ( ( int ) floor ( GetPosX ( ) ) - 1 , ( int ) floor ( GetPosY ( ) ) , ( int ) floor ( GetPosZ ( ) ) ) ;
if ( ! IsBlockRail ( Block ) & & g_BlockIsSolid [ Block ] )
{
cBoundingBox bbBlock ( Vector3d ( ( int ) floor ( GetPosX ( ) ) - 1 , ( int ) floor ( GetPosY ( ) ) , ( int ) floor ( GetPosZ ( ) ) ) , 0.5 , 1 ) ;
cBoundingBox bbMinecart ( Vector3d ( GetPosX ( ) - 1 , floor ( GetPosY ( ) ) , GetPosZ ( ) ) , GetWidth ( ) / 2 , GetHeight ( ) ) ;
if ( bbBlock . DoesIntersect ( bbMinecart ) )
{
SetSpeed ( 0 , 0 , 0 ) ;
SetPosX ( floor ( GetPosX ( ) ) + 0.65 ) ;
return true ;
}
}
}
break ;
}
case E_META_RAIL_CURVED_ZM_XM :
case E_META_RAIL_CURVED_ZM_XP :
case E_META_RAIL_CURVED_ZP_XM :
case E_META_RAIL_CURVED_ZP_XP :
{
BLOCKTYPE BlockXM = m_World - > GetBlock ( ( int ) floor ( GetPosX ( ) ) - 1 , ( int ) floor ( GetPosY ( ) ) , ( int ) floor ( GetPosZ ( ) ) ) ;
BLOCKTYPE BlockXP = m_World - > GetBlock ( ( int ) floor ( GetPosX ( ) ) + 1 , ( int ) floor ( GetPosY ( ) ) , ( int ) floor ( GetPosZ ( ) ) ) ;
BLOCKTYPE BlockZM = m_World - > GetBlock ( ( int ) floor ( GetPosX ( ) ) , ( int ) floor ( GetPosY ( ) ) , ( int ) floor ( GetPosZ ( ) ) + 1 ) ;
BLOCKTYPE BlockZP = m_World - > GetBlock ( ( int ) floor ( GetPosX ( ) ) , ( int ) floor ( GetPosY ( ) ) , ( int ) floor ( GetPosZ ( ) ) + 1 ) ;
if (
( ! IsBlockRail ( BlockXM ) & & g_BlockIsSolid [ BlockXM ] ) | |
( ! IsBlockRail ( BlockXP ) & & g_BlockIsSolid [ BlockXP ] ) | |
( ! IsBlockRail ( BlockZM ) & & g_BlockIsSolid [ BlockZM ] ) | |
( ! IsBlockRail ( BlockZP ) & & g_BlockIsSolid [ BlockZP ] )
)
{
SetSpeed ( 0 , 0 , 0 ) ;
SetPosition ( ( int ) floor ( GetPosX ( ) ) + 0.5 , GetPosY ( ) , ( int ) floor ( GetPosZ ( ) ) + 0.5 ) ;
return true ;
}
break ;
}
default : break ;
}
return false ;
}
2013-09-02 12:01:49 +01:00
void cMinecart : : DoTakeDamage ( TakeDamageInfo & TDI )
{
2014-01-12 13:28:37 +00:00
if ( TDI . Attacker - > IsPlayer ( ) & & ( ( cPlayer * ) TDI . Attacker ) - > IsGameModeCreative ( ) )
{
Destroy ( ) ;
TDI . FinalDamage = GetMaxHealth ( ) ; // Instant hit for creative
super : : DoTakeDamage ( TDI ) ;
return ; // No drops for creative
}
2013-10-08 19:20:49 +01:00
m_LastDamage = TDI . FinalDamage ;
2013-09-02 12:01:49 +01:00
super : : DoTakeDamage ( TDI ) ;
2013-10-08 19:20:49 +01:00
m_World - > BroadcastEntityMetadata ( * this ) ;
2013-09-09 18:55:42 +01:00
if ( GetHealth ( ) < = 0 )
2013-09-02 12:01:49 +01:00
{
2014-01-12 13:28:37 +00:00
Destroy ( ) ;
2013-10-08 19:20:49 +01:00
cItems Drops ;
switch ( m_Payload )
{
case mpNone :
{
Drops . push_back ( cItem ( E_ITEM_MINECART , 1 , 0 ) ) ;
break ;
}
case mpChest :
{
Drops . push_back ( cItem ( E_ITEM_CHEST_MINECART , 1 , 0 ) ) ;
break ;
}
case mpFurnace :
{
Drops . push_back ( cItem ( E_ITEM_FURNACE_MINECART , 1 , 0 ) ) ;
break ;
}
case mpTNT :
{
2013-10-09 21:02:59 +01:00
Drops . push_back ( cItem ( E_ITEM_MINECART_WITH_TNT , 1 , 0 ) ) ;
2013-10-08 19:20:49 +01:00
break ;
}
case mpHopper :
{
2013-10-09 21:02:59 +01:00
Drops . push_back ( cItem ( E_ITEM_MINECART_WITH_HOPPER , 1 , 0 ) ) ;
2013-10-08 19:20:49 +01:00
break ;
}
default :
{
ASSERT ( ! " Unhandled minecart type when spawning pickup! " ) ;
return ;
}
}
m_World - > SpawnItemPickups ( Drops , GetPosX ( ) , GetPosY ( ) , GetPosZ ( ) ) ;
2013-09-02 12:01:49 +01:00
}
2013-07-29 12:13:03 +01:00
}
2014-01-13 22:37:09 +00:00
void cMinecart : : Destroyed ( )
{
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-07-29 12:13:03 +01:00
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2014-01-12 18:04:41 +01:00
// cRideableMinecart:
2013-07-29 12:13:03 +01:00
2014-01-12 18:04:41 +01:00
cRideableMinecart : : cRideableMinecart ( double a_X , double a_Y , double a_Z , const cItem & a_Content , int a_Height ) :
2014-01-12 15:27:50 +01:00
super ( mpNone , a_X , a_Y , a_Z ) ,
m_Content ( a_Content ) ,
m_Height ( a_Height )
2013-07-29 12:13:03 +01:00
{
}
2014-01-12 18:04:41 +01:00
void cRideableMinecart : : OnRightClicked ( cPlayer & a_Player )
2013-07-29 12:13:03 +01:00
{
if ( m_Attachee ! = NULL )
{
if ( m_Attachee - > GetUniqueID ( ) = = a_Player . GetUniqueID ( ) )
{
// This player is already sitting in, they want out.
a_Player . Detach ( ) ;
return ;
}
if ( m_Attachee - > IsPlayer ( ) )
{
// Another player is already sitting in here, cannot attach
return ;
}
// Detach whatever is sitting in this minecart now:
m_Attachee - > Detach ( ) ;
}
// Attach the player to this minecart
a_Player . AttachTo ( this ) ;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cMinecartWithChest:
cMinecartWithChest : : cMinecartWithChest ( double a_X , double a_Y , double a_Z ) :
super ( mpChest , a_X , a_Y , a_Z )
{
}
void cMinecartWithChest : : SetSlot ( int a_Idx , const cItem & a_Item )
{
ASSERT ( ( a_Idx > = 0 ) & & ( a_Idx < ARRAYCOUNT ( m_Items ) ) ) ;
m_Items [ a_Idx ] = a_Item ;
}
void cMinecartWithChest : : OnRightClicked ( cPlayer & a_Player )
{
// Show the chest UI window to the player
// TODO
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cMinecartWithFurnace:
cMinecartWithFurnace : : cMinecartWithFurnace ( double a_X , double a_Y , double a_Z ) :
2013-10-08 19:20:49 +01:00
super ( mpFurnace , a_X , a_Y , a_Z ) ,
2014-01-15 14:38:54 +01:00
m_IsFueled ( false ) ,
m_FueledTimeLeft ( - 1 )
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-01-15 14:03:09 +01:00
if ( ! m_IsFueled ) // We don't want to change the direction by right clicking it.
{
AddSpeed ( a_Player . GetLookVector ( ) . x , 0 , a_Player . GetLookVector ( ) . z ) ;
}
2013-10-08 19:20:49 +01:00
m_IsFueled = true ;
2014-01-15 14:38:54 +01: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
}
2014-01-15 14:03:09 +01:00
void cMinecartWithFurnace : : Tick ( float a_Dt , cChunk & a_Chunk )
{
super : : Tick ( a_Dt , a_Chunk ) ;
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 ) ;
}
}
2013-08-16 11:23:24 +01:00
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cMinecartWithTNT:
cMinecartWithTNT : : cMinecartWithTNT ( double a_X , double a_Y , double a_Z ) :
super ( mpTNT , a_X , a_Y , a_Z )
{
}
// TODO: Make it activate when passing over activator rail
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cMinecartWithHopper:
cMinecartWithHopper : : cMinecartWithHopper ( double a_X , double a_Y , double a_Z ) :
super ( mpHopper , a_X , a_Y , a_Z )
{
}
// TODO: Make it suck up blocks and travel further than any other cart and physics and put and take blocks
// AND AVARYTHING!!