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
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
{
2013-09-02 12:01:49 +01:00
SetRotation ( 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
{
SetRotation ( 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
{
SetRotation ( 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
{
SetRotation ( 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
{
SetRotation ( 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
{
SetRotation ( 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
{
SetRotation ( 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
{
SetRotation ( 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
{
SetRotation ( 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
{
SetRotation ( 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-13 22:37:09 +00:00
SetRotation ( 270 );
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
{
SetRotation ( 180 );
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
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cEmptyMinecart:
cEmptyMinecart :: cEmptyMinecart ( double a_X , double a_Y , double a_Z ) :
super ( mpNone , a_X , a_Y , a_Z )
{
}
void cEmptyMinecart :: OnRightClicked ( cPlayer & a_Player )
{
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!!