2007-01-15 12:09:25 -08:00
/*
This file is part of Warzone 2100.
Copyright ( C ) 1999 - 2004 Eidos Interactive
2013-01-16 12:34:57 -08:00
Copyright ( C ) 2005 - 2013 Warzone 2100 Project
2007-01-15 12:09:25 -08:00
Warzone 2100 is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
Warzone 2100 is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with Warzone 2100 ; if not , write to the Free Software
Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
2007-06-28 10:47:08 -07:00
/*
* Move . c
*
* Routines for moving units about the map
*
2006-05-27 09:37:17 -07:00
*/
2007-07-16 02:38:35 -07:00
# include "lib/framework/frame.h"
2006-09-23 10:24:55 -07:00
# include "lib/framework/trig.h"
2009-02-10 09:23:09 -08:00
# include "lib/framework/math_ext.h"
2007-07-13 14:33:12 -07:00
# include "lib/gamelib/gtime.h"
2008-03-16 05:39:08 -07:00
# include "lib/gamelib/animobj.h"
# include "lib/netplay/netplay.h"
2007-07-13 14:33:12 -07:00
# include "lib/sound/audio.h"
# include "lib/sound/audio_id.h"
2009-02-14 21:16:34 -08:00
# include "console.h"
2007-06-28 10:47:08 -07:00
# include "move.h"
2008-03-16 05:39:08 -07:00
# include "objects.h"
2007-06-28 10:47:08 -07:00
# include "visibility.h"
# include "map.h"
# include "fpath.h"
# include "loop.h"
# include "geometry.h"
# include "anim_id.h"
# include "action.h"
# include "display3d.h"
# include "order.h"
# include "astar.h"
# include "combat.h"
# include "mapgrid.h"
# include "display.h" // needed for widgetsOn flag.
# include "effects.h"
# include "power.h"
# include "scores.h"
2007-07-13 14:33:12 -07:00
# include "multiplay.h"
# include "multigifts.h"
2010-02-06 09:14:43 -08:00
# include "random.h"
2012-04-24 18:16:51 -07:00
# include "mission.h"
2007-06-28 10:47:08 -07:00
# include "drive.h"
2012-06-02 10:35:02 -07:00
# include "qtscript.h"
2007-06-28 10:47:08 -07:00
/* max and min vtol heights above terrain */
# define VTOL_HEIGHT_MIN 250
# define VTOL_HEIGHT_LEVEL 300
# define VTOL_HEIGHT_MAX 350
// Maximum size of an object for collision
# define OBJ_MAXRADIUS (TILE_UNITS * 4)
// how long a shuffle can propagate before they all stop
# define MOVE_SHUFFLETIME 10000
// Length of time a droid has to be stationery to be considered blocked
# define BLOCK_TIME 6000
# define SHUFFLE_BLOCK_TIME 2000
// How long a droid has to be stationary before stopping trying to move
# define BLOCK_PAUSETIME 1500
# define BLOCK_PAUSERELEASE 500
// How far a droid has to move before it is no longer 'stationary'
# define BLOCK_DIST 64
// How far a droid has to rotate before it is no longer 'stationary'
# define BLOCK_DIR 90
// How far out from an obstruction to start avoiding it
# define AVOID_DIST (TILE_UNITS*2)
2012-05-02 07:12:05 -07:00
// Speed to approach a final way point, if possible.
2007-06-28 10:47:08 -07:00
# define MIN_END_SPEED 60
// distance from final way point to start slowing
# define END_SPEED_RANGE (3 * TILE_UNITS)
// how long to pause after firing a FOM_NO weapon
# define FOM_MOVEPAUSE 1500
// distance to consider droids for a shuffle
# define SHUFFLE_DIST (3*TILE_UNITS / 2)
// how far to move for a shuffle
# define SHUFFLE_MOVE (2*TILE_UNITS / 2)
2011-12-17 02:00:23 -08:00
/// Extra precision added to movement calculations.
# define EXTRA_BITS 8
# define EXTRA_PRECISION (1 << EXTRA_BITS)
2007-06-28 10:47:08 -07:00
/* Function prototypes */
2010-03-01 05:50:53 -08:00
static void moveUpdatePersonModel ( DROID * psDroid , SDWORD speed , uint16_t direction ) ;
2007-06-28 10:47:08 -07:00
2010-07-11 12:49:28 -07:00
const char * moveDescription ( MOVE_STATUS status )
{
switch ( status )
{
case MOVEINACTIVE : return " Inactive " ;
case MOVENAVIGATE : return " Navigate " ;
case MOVETURN : return " Turn " ;
case MOVEPAUSE : return " Pause " ;
case MOVEPOINTTOPOINT : return " P2P " ;
case MOVETURNTOTARGET : return " Turn2target " ;
case MOVEHOVER : return " Hover " ;
case MOVEDRIVE : return " Drive " ;
case MOVEWAITROUTE : return " Waitroute " ;
case MOVESHUFFLE : return " Shuffle " ;
}
return " Error " ; // satisfy compiler
}
2008-06-28 08:25:58 -07:00
/** Set a target location in world coordinates for a droid to move to
2009-03-11 04:51:40 -07:00
* @ return true if the routing was successful , if false then the calling code
2008-04-20 15:43:14 -07:00
* should not try to route here again for a while
* @ todo Document what " should not try to route here again for a while " means .
*/
2011-06-12 07:40:31 -07:00
static bool moveDroidToBase ( DROID * psDroid , UDWORD x , UDWORD y , bool bFormation , FPATH_MOVETYPE moveType )
2007-06-28 10:47:08 -07:00
{
FPATH_RETVAL retVal = FPR_OK ;
2008-03-24 07:21:08 -07:00
CHECK_DROID ( psDroid ) ;
2007-06-28 10:47:08 -07:00
2008-01-12 10:04:39 -08:00
// in multiPlayer make Transporter move like the vtols
2012-02-25 16:21:29 -08:00
if ( ( psDroid - > droidType = = DROID_TRANSPORTER | | psDroid - > droidType = = DROID_SUPERTRANSPORTER ) & & game . maxPlayers = = 0 )
2007-06-28 10:47:08 -07:00
{
2008-04-15 15:54:37 -07:00
fpathSetDirectRoute ( psDroid , x , y ) ;
2007-06-28 10:47:08 -07:00
psDroid - > sMove . Status = MOVENAVIGATE ;
2011-02-27 03:10:40 -08:00
psDroid - > sMove . pathIndex = 0 ;
2008-03-24 09:51:17 -07:00
return true ;
2007-06-28 10:47:08 -07:00
}
2011-09-10 17:33:59 -07:00
// NOTE: While Vtols can fly, then can't go through things, like the transporter.
2012-02-25 16:21:29 -08:00
else if ( ( game . maxPlayers > 0 & & ( psDroid - > droidType = = DROID_TRANSPORTER | | psDroid - > droidType = = DROID_SUPERTRANSPORTER ) ) )
2007-06-28 10:47:08 -07:00
{
2008-04-15 15:54:37 -07:00
fpathSetDirectRoute ( psDroid , x , y ) ;
2007-06-28 10:47:08 -07:00
retVal = FPR_OK ;
}
else
{
2011-06-12 07:40:31 -07:00
retVal = fpathDroidRoute ( psDroid , x , y , moveType ) ;
2007-06-28 10:47:08 -07:00
}
if ( retVal = = FPR_OK )
{
// bit of a hack this - john
// if astar doesn't have a complete route, it returns a route to the nearest clear tile.
// the location of the clear tile is in DestinationX,DestinationY.
// reset x,y to this position so the formation gets set up correctly
2011-01-07 15:20:12 -08:00
x = psDroid - > sMove . destination . x ;
y = psDroid - > sMove . destination . y ;
2007-06-28 10:47:08 -07:00
2010-07-11 12:49:28 -07:00
objTrace ( psDroid - > id , " unit %d: path ok - base Speed %u, speed %d, target(%u|%d, %u|%d) " ,
( int ) psDroid - > id , psDroid - > baseSpeed , psDroid - > sMove . speed , x , map_coord ( x ) , y , map_coord ( y ) ) ;
2008-01-13 08:57:06 -08:00
2007-06-28 10:47:08 -07:00
psDroid - > sMove . Status = MOVENAVIGATE ;
2011-02-27 03:10:40 -08:00
psDroid - > sMove . pathIndex = 0 ;
2007-06-28 10:47:08 -07:00
}
else if ( retVal = = FPR_WAIT )
{
2008-08-02 07:37:53 -07:00
// the route will be calculated by the path-finding thread
2007-06-28 10:47:08 -07:00
psDroid - > sMove . Status = MOVEWAITROUTE ;
2011-01-07 15:20:12 -08:00
psDroid - > sMove . destination . x = x ;
psDroid - > sMove . destination . y = y ;
2007-06-28 10:47:08 -07:00
}
else // if (retVal == FPR_FAILED)
{
2008-05-11 07:58:20 -07:00
objTrace ( psDroid - > id , " Path to (%d, %d) failed for droid %d " , ( int ) x , ( int ) y , ( int ) psDroid - > id ) ;
2007-06-28 10:47:08 -07:00
psDroid - > sMove . Status = MOVEINACTIVE ;
actionDroid ( psDroid , DACTION_SULK ) ;
2008-03-24 09:51:17 -07:00
return ( false ) ;
2007-06-28 10:47:08 -07:00
}
2008-03-24 07:21:08 -07:00
CHECK_DROID ( psDroid ) ;
2008-03-24 09:51:17 -07:00
return true ;
2007-06-28 10:47:08 -07:00
}
2008-04-20 15:43:14 -07:00
/** Move a droid to a location, joining a formation
* @ see moveDroidToBase ( ) for the parameter and return value specification
*/
2011-06-12 07:40:31 -07:00
bool moveDroidTo ( DROID * psDroid , UDWORD x , UDWORD y , FPATH_MOVETYPE moveType )
2007-06-28 10:47:08 -07:00
{
2011-06-12 07:40:31 -07:00
return moveDroidToBase ( psDroid , x , y , true , moveType ) ;
2007-06-28 10:47:08 -07:00
}
2008-04-20 15:43:14 -07:00
/** Move a droid to a location, not joining a formation
* @ see moveDroidToBase ( ) for the parameter and return value specification
*/
2011-06-12 07:40:31 -07:00
bool moveDroidToNoFormation ( DROID * psDroid , UDWORD x , UDWORD y , FPATH_MOVETYPE moveType )
2007-06-28 10:47:08 -07:00
{
2008-03-25 12:23:26 -07:00
ASSERT ( x > 0 & & y > 0 , " Bad movement position " ) ;
2011-06-12 07:40:31 -07:00
return moveDroidToBase ( psDroid , x , y , false , moveType ) ;
2007-06-28 10:47:08 -07:00
}
2008-04-20 15:43:14 -07:00
/** Move a droid directly to a location.
* @ note This is ( or should be ) used for VTOLs only .
*/
void moveDroidToDirect ( DROID * psDroid , UDWORD x , UDWORD y )
2007-06-28 10:47:08 -07:00
{
2008-07-07 03:15:00 -07:00
ASSERT ( psDroid ! = NULL & & isVtolDroid ( psDroid ) ,
2006-08-23 05:58:48 -07:00
" moveUnitToDirect: only valid for a vtol unit " ) ;
2007-06-28 10:47:08 -07:00
2008-04-15 15:54:37 -07:00
fpathSetDirectRoute ( psDroid , x , y ) ;
2007-06-28 10:47:08 -07:00
psDroid - > sMove . Status = MOVENAVIGATE ;
2011-02-27 03:10:40 -08:00
psDroid - > sMove . pathIndex = 0 ;
2007-06-28 10:47:08 -07:00
}
2008-04-20 15:43:14 -07:00
/** Turn a droid towards a given location.
*/
2007-06-28 10:47:08 -07:00
void moveTurnDroid ( DROID * psDroid , UDWORD x , UDWORD y )
{
2010-02-28 15:14:52 -08:00
uint16_t moveDir = calcDirection ( psDroid - > pos . x , psDroid - > pos . y , x , y ) ;
2007-06-28 10:47:08 -07:00
2010-02-28 15:14:52 -08:00
if ( psDroid - > rot . direction ! = moveDir )
2007-06-28 10:47:08 -07:00
{
2011-01-07 15:20:12 -08:00
psDroid - > sMove . target . x = x ;
psDroid - > sMove . target . y = y ;
2007-06-28 10:47:08 -07:00
psDroid - > sMove . Status = MOVETURNTOTARGET ;
}
}
// Tell a droid to move out the way for a shuffle
2011-01-07 15:20:12 -08:00
static void moveShuffleDroid ( DROID * psDroid , Vector2i s )
2007-06-28 10:47:08 -07:00
{
2011-01-07 15:20:12 -08:00
SDWORD mx , my ;
2011-03-12 17:32:15 -08:00
bool frontClear = true , leftClear = true , rightClear = true ;
2007-06-28 10:47:08 -07:00
SDWORD lvx , lvy , rvx , rvy , svx , svy ;
SDWORD shuffleMove ;
2008-03-24 07:21:08 -07:00
CHECK_DROID ( psDroid ) ;
2011-01-07 15:20:12 -08:00
uint16_t shuffleDir = iAtan2 ( s ) ;
int32_t shuffleMag = iHypot ( s ) ;
2007-06-28 10:47:08 -07:00
if ( shuffleMag = = 0 )
{
return ;
}
shuffleMove = SHUFFLE_MOVE ;
// calculate the possible movement vectors
2012-02-28 00:12:46 -08:00
svx = s . x * shuffleMove / shuffleMag ; // Straight in the direction of s.
svy = s . y * shuffleMove / shuffleMag ;
2007-06-28 10:47:08 -07:00
2012-02-28 00:12:46 -08:00
lvx = - svy ; // 90° to the... right?
lvy = svx ;
2007-06-28 10:47:08 -07:00
2012-02-28 00:12:46 -08:00
rvx = svy ; // 90° to the... left?
rvy = - svx ;
2007-06-28 10:47:08 -07:00
// check for blocking tiles
2007-12-15 07:39:29 -08:00
if ( fpathBlockingTile ( map_coord ( ( SDWORD ) psDroid - > pos . x + lvx ) ,
2008-05-07 09:37:46 -07:00
map_coord ( ( SDWORD ) psDroid - > pos . y + lvy ) , getPropulsionStats ( psDroid ) - > propulsionType ) )
2007-06-28 10:47:08 -07:00
{
2008-03-24 09:51:17 -07:00
leftClear = false ;
2007-06-28 10:47:08 -07:00
}
2007-12-15 07:39:29 -08:00
else if ( fpathBlockingTile ( map_coord ( ( SDWORD ) psDroid - > pos . x + rvx ) ,
2008-05-07 09:37:46 -07:00
map_coord ( ( SDWORD ) psDroid - > pos . y + rvy ) , getPropulsionStats ( psDroid ) - > propulsionType ) )
2007-06-28 10:47:08 -07:00
{
2008-03-24 09:51:17 -07:00
rightClear = false ;
2007-06-28 10:47:08 -07:00
}
2007-12-15 07:39:29 -08:00
else if ( fpathBlockingTile ( map_coord ( ( SDWORD ) psDroid - > pos . x + svx ) ,
2008-05-07 09:37:46 -07:00
map_coord ( ( SDWORD ) psDroid - > pos . y + svy ) , getPropulsionStats ( psDroid ) - > propulsionType ) )
2007-06-28 10:47:08 -07:00
{
2008-03-24 09:51:17 -07:00
frontClear = false ;
2007-06-28 10:47:08 -07:00
}
// find any droids that could block the shuffle
2013-02-09 03:33:00 -08:00
static GridList gridList ; // static to avoid allocations.
gridList = gridStartIterate ( psDroid - > pos . x , psDroid - > pos . y , SHUFFLE_DIST ) ;
for ( GridIterator gi = gridList . begin ( ) ; gi ! = gridList . end ( ) ; + + gi )
2007-06-28 10:47:08 -07:00
{
2013-02-09 03:33:00 -08:00
DROID * psCurr = castDroid ( * gi ) ;
2012-02-28 00:12:46 -08:00
if ( psCurr = = NULL | | psCurr - > died | | psCurr = = psDroid )
2007-06-28 10:47:08 -07:00
{
2012-02-28 00:12:46 -08:00
continue ;
}
uint16_t droidDir = iAtan2 ( removeZ ( psCurr - > pos - psDroid - > pos ) ) ;
int diff = angleDelta ( shuffleDir - droidDir ) ;
if ( diff > - DEG ( 135 ) & & diff < - DEG ( 45 ) )
{
leftClear = false ;
}
else if ( diff > DEG ( 45 ) & & diff < DEG ( 135 ) )
{
rightClear = false ;
2007-06-28 10:47:08 -07:00
}
}
// calculate a target
if ( leftClear )
{
mx = lvx ;
my = lvy ;
}
else if ( rightClear )
{
mx = rvx ;
my = rvy ;
}
else if ( frontClear )
{
mx = svx ;
my = svy ;
}
else
{
// nowhere to shuffle to, quit
return ;
}
// check the location for vtols
2012-02-28 00:51:37 -08:00
Vector2i tar = removeZ ( psDroid - > pos ) + Vector2i ( mx , my ) ;
2008-07-07 03:15:00 -07:00
if ( isVtolDroid ( psDroid ) )
2007-06-28 10:47:08 -07:00
{
2012-02-28 00:51:37 -08:00
actionVTOLLandingPos ( psDroid , & tar ) ;
2007-06-28 10:47:08 -07:00
}
2011-01-07 15:20:12 -08:00
2007-06-28 10:47:08 -07:00
// set up the move state
2011-01-07 15:20:12 -08:00
if ( psDroid - > sMove . Status ! = MOVESHUFFLE )
{
psDroid - > sMove . shuffleStart = gameTime ;
}
2010-02-09 14:35:23 -08:00
psDroid - > sMove . Status = MOVESHUFFLE ;
2011-01-07 15:20:12 -08:00
psDroid - > sMove . src = removeZ ( psDroid - > pos ) ;
2012-02-28 00:51:37 -08:00
psDroid - > sMove . target = tar ;
2007-06-28 10:47:08 -07:00
psDroid - > sMove . numPoints = 0 ;
2011-02-27 03:10:40 -08:00
psDroid - > sMove . pathIndex = 0 ;
2007-06-28 10:47:08 -07:00
2008-03-24 07:21:08 -07:00
CHECK_DROID ( psDroid ) ;
2007-06-28 10:47:08 -07:00
}
2008-04-20 15:43:14 -07:00
/** Stop a droid from moving.
*/
2007-06-28 10:47:08 -07:00
void moveStopDroid ( DROID * psDroid )
{
PROPULSION_STATS * psPropStats ;
2008-03-24 07:21:08 -07:00
CHECK_DROID ( psDroid ) ;
2007-06-28 10:47:08 -07:00
2013-05-09 04:24:19 -07:00
psPropStats = asPropulsionStats + psDroid - > asBits [ COMP_PROPULSION ] ;
2007-04-03 06:20:41 -07:00
ASSERT ( psPropStats ! = NULL ,
2006-08-23 05:58:48 -07:00
" moveUpdateUnit: invalid propulsion stats pointer " ) ;
2007-06-28 10:47:08 -07:00
2008-07-10 10:59:35 -07:00
if ( psPropStats - > propulsionType = = PROPULSION_TYPE_LIFT )
2007-06-28 10:47:08 -07:00
{
psDroid - > sMove . Status = MOVEHOVER ;
}
else
{
psDroid - > sMove . Status = MOVEINACTIVE ;
}
}
2008-04-20 15:43:14 -07:00
/** Stops a droid dead in its tracks.
* Doesn ' t allow for any little skidding bits .
* @ param psDroid the droid to stop from moving
*/
2007-06-28 10:47:08 -07:00
void moveReallyStopDroid ( DROID * psDroid )
{
2008-03-24 07:21:08 -07:00
CHECK_DROID ( psDroid ) ;
2007-06-28 10:47:08 -07:00
2008-03-24 07:21:08 -07:00
psDroid - > sMove . Status = MOVEINACTIVE ;
psDroid - > sMove . speed = 0 ;
2007-06-28 10:47:08 -07:00
}
# define PITCH_LIMIT 150
2006-11-26 03:20:44 -08:00
/* Get pitch and roll from direction and tile data */
2007-06-28 10:47:08 -07:00
void updateDroidOrientation ( DROID * psDroid )
{
2010-02-28 11:13:12 -08:00
int32_t hx0 , hx1 , hy0 , hy1 ;
int newPitch , deltaPitch , pitchLimit ;
int32_t dzdx , dzdy , dzdv , dzdw ;
const int d = 20 ;
int32_t vX , vY ;
2008-03-24 07:21:08 -07:00
2012-02-25 16:21:29 -08:00
if ( psDroid - > droidType = = DROID_PERSON | | cyborgDroid ( psDroid ) | | psDroid - > droidType = = DROID_TRANSPORTER | | psDroid - > droidType = = DROID_SUPERTRANSPORTER
2010-01-24 10:25:27 -08:00
| | isFlying ( psDroid ) )
2007-06-28 10:47:08 -07:00
{
2010-01-24 10:25:27 -08:00
/* The ground doesn't affect the pitch/roll of these droids*/
2007-06-28 10:47:08 -07:00
return ;
}
2010-02-28 11:13:12 -08:00
// Find the height of 4 points around the droid.
// hy0
// hx0 * hx1 (* = droid)
// hy1
hx1 = map_Height ( psDroid - > pos . x + d , psDroid - > pos . y ) ;
hx0 = map_Height ( MAX ( 0 , psDroid - > pos . x - d ) , psDroid - > pos . y ) ;
hy1 = map_Height ( psDroid - > pos . x , psDroid - > pos . y + d ) ;
hy0 = map_Height ( psDroid - > pos . x , MAX ( 0 , psDroid - > pos . y - d ) ) ;
2007-06-28 10:47:08 -07:00
//update height in case were in the bottom of a trough
2010-02-28 11:13:12 -08:00
psDroid - > pos . z = MAX ( psDroid - > pos . z , ( hx0 + hx1 ) / 2 ) ;
psDroid - > pos . z = MAX ( psDroid - > pos . z , ( hy0 + hy1 ) / 2 ) ;
// Vector of length 65536 pointing in direction droid is facing.
2010-02-28 15:14:52 -08:00
vX = iSin ( psDroid - > rot . direction ) ;
vY = iCos ( psDroid - > rot . direction ) ;
2010-02-28 11:13:12 -08:00
// Calculate pitch of ground.
dzdx = hx1 - hx0 ; // 2*d*∂z(x, y)/∂x of ground
dzdy = hy1 - hy0 ; // 2*d*∂z(x, y)/∂y of ground
dzdv = dzdx * vX + dzdy * vY ; // 2*d*∂z(x, y)/∂v << 16 of ground, where v is the direction the droid is facing.
newPitch = iAtan2 ( dzdv , ( 2 * d ) < < 16 ) ; // pitch = atan(∂z(x, y)/∂v)/2π << 16
2010-03-05 01:06:07 -08:00
deltaPitch = angleDelta ( newPitch - psDroid - > rot . pitch ) ;
2007-06-28 10:47:08 -07:00
2010-02-28 15:14:52 -08:00
// Limit the rate the front comes down to simulate momentum
2010-02-28 11:13:12 -08:00
pitchLimit = gameTimeAdjustedIncrement ( DEG ( PITCH_LIMIT ) ) ;
deltaPitch = MAX ( deltaPitch , - pitchLimit ) ;
// Update pitch.
2010-02-28 15:14:52 -08:00
psDroid - > rot . pitch + = deltaPitch ;
2010-02-28 11:13:12 -08:00
// Calculate and update roll of ground (not taking pitch into account, but good enough).
2010-02-28 15:14:52 -08:00
dzdw = dzdx * vY - dzdy * vX ; // 2*d*∂z(x, y)/∂w << 16 of ground, where w is at right angles to the direction the droid is facing.
psDroid - > rot . roll = iAtan2 ( dzdw , ( 2 * d ) < < 16 ) ; // pitch = atan(∂z(x, y)/∂w)/2π << 16
2007-06-28 10:47:08 -07:00
}
2011-02-25 12:30:13 -08:00
struct BLOCKING_CALLBACK_DATA
2010-10-17 14:36:48 -07:00
{
PROPULSION_TYPE propulsionType ;
bool blocking ;
2012-06-13 04:32:33 -07:00
Vector2i src ;
2011-12-24 11:55:28 -08:00
Vector2i dst ;
2011-02-25 12:30:13 -08:00
} ;
2010-10-17 14:36:48 -07:00
2011-12-24 11:55:28 -08:00
static bool moveBlockingTileCallback ( Vector2i pos , int32_t dist , void * data_ )
2010-10-17 14:36:48 -07:00
{
BLOCKING_CALLBACK_DATA * data = ( BLOCKING_CALLBACK_DATA * ) data_ ;
2012-06-13 04:32:33 -07:00
data - > blocking | = pos ! = data - > src & & pos ! = data - > dst & & fpathBlockingTile ( map_coord ( pos . x ) , map_coord ( pos . y ) , data - > propulsionType ) ;
2010-10-17 14:36:48 -07:00
return ! data - > blocking ;
}
// Returns -1 - distance if the direct path to the waypoint is blocked, otherwise returns the distance to the waypoint.
static int32_t moveDirectPathToWaypoint ( DROID * psDroid , unsigned positionIndex )
{
2010-12-21 12:51:29 -08:00
Vector2i src = removeZ ( psDroid - > pos ) ;
2010-10-17 14:36:48 -07:00
Vector2i dst = psDroid - > sMove . asPath [ positionIndex ] ;
2010-12-21 12:51:29 -08:00
Vector2i delta = dst - src ;
int32_t dist = iHypot ( delta ) ;
2010-10-17 14:36:48 -07:00
BLOCKING_CALLBACK_DATA data ;
data . propulsionType = getPropulsionStats ( psDroid ) - > propulsionType ;
data . blocking = false ;
2012-06-13 04:32:33 -07:00
data . src = src ;
2011-12-24 11:55:28 -08:00
data . dst = dst ;
rayCast ( src , dst , & moveBlockingTileCallback , & data ) ;
2010-10-17 14:36:48 -07:00
return data . blocking ? - 1 - dist : dist ;
}
// Returns true if still able to find the path.
static bool moveBestTarget ( DROID * psDroid )
{
2011-02-27 03:10:40 -08:00
int positionIndex = std : : max ( psDroid - > sMove . pathIndex - 1 , 0 ) ;
2010-10-17 14:36:48 -07:00
int32_t dist = moveDirectPathToWaypoint ( psDroid , positionIndex ) ;
if ( dist > = 0 )
{
// Look ahead in the path.
while ( dist > = 0 & & dist < TILE_UNITS * 5 )
{
+ + positionIndex ;
if ( positionIndex > = psDroid - > sMove . numPoints )
{
dist = - 1 ;
break ; // Reached end of path.
}
dist = moveDirectPathToWaypoint ( psDroid , positionIndex ) ;
}
if ( dist < 0 )
{
- - positionIndex ;
}
}
else
{
// Lost sight of path, backtrack.
while ( dist < 0 & & dist > = - TILE_UNITS * 7 & & positionIndex > 0 )
{
- - positionIndex ;
dist = moveDirectPathToWaypoint ( psDroid , positionIndex ) ;
}
if ( dist < 0 )
{
return false ; // Couldn't find path, and backtracking didn't help.
}
}
2011-02-27 03:10:40 -08:00
psDroid - > sMove . pathIndex = positionIndex + 1 ;
2011-01-07 15:20:12 -08:00
psDroid - > sMove . src = removeZ ( psDroid - > pos ) ;
psDroid - > sMove . target = psDroid - > sMove . asPath [ positionIndex ] ;
2010-10-17 14:36:48 -07:00
return true ;
}
2007-06-28 10:47:08 -07:00
/* Get the next target point from the route */
2011-02-27 03:10:40 -08:00
static bool moveNextTarget ( DROID * psDroid )
2007-06-28 10:47:08 -07:00
{
2008-03-24 07:21:08 -07:00
CHECK_DROID ( psDroid ) ;
2007-06-28 10:47:08 -07:00
// See if there is anything left in the move list
2011-02-27 03:10:40 -08:00
if ( psDroid - > sMove . pathIndex = = psDroid - > sMove . numPoints )
2007-06-28 10:47:08 -07:00
{
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
2011-02-27 03:10:40 -08:00
if ( psDroid - > sMove . pathIndex = = 0 )
2007-06-28 10:47:08 -07:00
{
2011-01-07 15:20:12 -08:00
psDroid - > sMove . src = removeZ ( psDroid - > pos ) ;
2007-06-28 10:47:08 -07:00
}
else
{
2011-02-27 03:10:40 -08:00
psDroid - > sMove . src = psDroid - > sMove . asPath [ psDroid - > sMove . pathIndex - 1 ] ;
2007-06-28 10:47:08 -07:00
}
2011-02-27 03:10:40 -08:00
psDroid - > sMove . target = psDroid - > sMove . asPath [ psDroid - > sMove . pathIndex ] ;
+ + psDroid - > sMove . pathIndex ;
2007-06-28 10:47:08 -07:00
2008-03-24 07:21:08 -07:00
CHECK_DROID ( psDroid ) ;
2008-03-24 09:51:17 -07:00
return true ;
2007-06-28 10:47:08 -07:00
}
2007-06-02 09:37:37 -07:00
// Watermelon:fix these magic number...the collision radius should be based on pie imd radius not some static int's...
2007-06-28 10:47:08 -07:00
static int mvPersRad = 20 , mvCybRad = 30 , mvSmRad = 40 , mvMedRad = 50 , mvLgRad = 60 ;
// Get the radius of a base object for collision
2008-04-15 16:11:42 -07:00
static SDWORD moveObjRadius ( const BASE_OBJECT * psObj )
2007-06-28 10:47:08 -07:00
{
switch ( psObj - > type )
{
2008-04-15 16:11:42 -07:00
case OBJ_DROID :
2007-06-28 10:47:08 -07:00
{
2008-04-15 16:11:42 -07:00
const DROID * psDroid = ( const DROID * ) psObj ;
if ( psDroid - > droidType = = DROID_PERSON )
2007-06-28 10:47:08 -07:00
{
2008-04-15 16:11:42 -07:00
return mvPersRad ;
2007-06-28 10:47:08 -07:00
}
2008-04-15 16:11:42 -07:00
else if ( cyborgDroid ( psDroid ) )
{
return mvCybRad ;
}
else
{
2013-05-09 04:24:19 -07:00
const BODY_STATS * psBdyStats = & asBodyStats [ psDroid - > asBits [ COMP_BODY ] ] ;
2008-04-15 16:11:42 -07:00
switch ( psBdyStats - > size )
{
case SIZE_LIGHT :
return mvSmRad ;
case SIZE_MEDIUM :
return mvMedRad ;
case SIZE_HEAVY :
return mvLgRad ;
case SIZE_SUPER_HEAVY :
return 130 ;
default :
return psDroid - > sDisplay . imd - > radius ;
}
}
break ;
2007-06-28 10:47:08 -07:00
}
2008-04-15 16:11:42 -07:00
case OBJ_STRUCTURE :
return psObj - > sDisplay . imd - > radius / 2 ;
case OBJ_FEATURE :
return psObj - > sDisplay . imd - > radius / 2 ;
default :
2008-08-02 09:32:48 -07:00
ASSERT ( false , " unknown object type " ) ;
2008-04-15 16:11:42 -07:00
return 0 ;
}
2007-06-28 10:47:08 -07:00
}
// see if a Droid has run over a person
2010-05-25 09:56:27 -07:00
static void moveCheckSquished ( DROID * psDroid , int32_t emx , int32_t emy )
2007-06-28 10:47:08 -07:00
{
2010-05-25 09:56:27 -07:00
int32_t rad , radSq , objR , xdiff , ydiff , distSq ;
const int32_t droidR = moveObjRadius ( ( BASE_OBJECT * ) psDroid ) ;
2011-12-17 05:57:51 -08:00
const int32_t mx = gameTimeAdjustedAverage ( emx , EXTRA_PRECISION ) ;
const int32_t my = gameTimeAdjustedAverage ( emy , EXTRA_PRECISION ) ;
2007-06-28 10:47:08 -07:00
2013-02-09 03:33:00 -08:00
static GridList gridList ; // static to avoid allocations.
gridList = gridStartIterate ( psDroid - > pos . x , psDroid - > pos . y , OBJ_MAXRADIUS ) ;
for ( GridIterator gi = gridList . begin ( ) ; gi ! = gridList . end ( ) ; + + gi )
2007-06-28 10:47:08 -07:00
{
2013-02-09 03:33:00 -08:00
BASE_OBJECT * psObj = * gi ;
2010-01-16 14:51:26 -08:00
if ( psObj - > type ! = OBJ_DROID | | ( ( DROID * ) psObj ) - > droidType ! = DROID_PERSON )
2007-06-28 10:47:08 -07:00
{
// ignore everything but people
continue ;
}
2010-01-16 14:51:26 -08:00
ASSERT ( psObj - > type = = OBJ_DROID & & ( ( DROID * ) psObj ) - > droidType = = DROID_PERSON , " squished - eerk " ) ;
2007-06-28 10:47:08 -07:00
2010-01-16 14:51:26 -08:00
objR = moveObjRadius ( psObj ) ;
2007-06-28 10:47:08 -07:00
rad = droidR + objR ;
radSq = rad * rad ;
2010-01-16 14:51:26 -08:00
xdiff = psDroid - > pos . x + mx - psObj - > pos . x ;
ydiff = psDroid - > pos . y + my - psObj - > pos . y ;
2007-06-28 10:47:08 -07:00
distSq = xdiff * xdiff + ydiff * ydiff ;
if ( ( ( 2 * radSq ) / 3 ) > distSq )
{
2010-01-16 14:51:26 -08:00
if ( ( psDroid - > player ! = psObj - > player ) & & ! aiCheckAlliances ( psDroid - > player , psObj - > player ) )
2007-06-28 10:47:08 -07:00
{
// run over a bloke - kill him
2011-12-28 05:42:41 -08:00
destroyDroid ( ( DROID * ) psObj , gameTime ) ;
2007-06-28 10:47:08 -07:00
scoreUpdateVar ( WD_BARBARIANS_MOWED_DOWN ) ;
}
}
}
}
// See if the droid has been stopped long enough to give up on the move
2011-03-12 17:32:15 -08:00
static bool moveBlocked ( DROID * psDroid )
2007-06-28 10:47:08 -07:00
{
SDWORD xdiff , ydiff , diffSq ;
UDWORD blockTime ;
2010-02-09 14:35:23 -08:00
if ( psDroid - > sMove . bumpTime = = 0 | | psDroid - > sMove . bumpTime > gameTime )
2007-06-28 10:47:08 -07:00
{
// no bump - can't be blocked
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
// See if the block can be cancelled
2010-03-05 01:06:07 -08:00
if ( abs ( angleDelta ( psDroid - > rot . direction - psDroid - > sMove . bumpDir ) ) > DEG ( BLOCK_DIR ) )
2007-06-28 10:47:08 -07:00
{
// Move on, clear the bump
psDroid - > sMove . bumpTime = 0 ;
psDroid - > sMove . lastBump = 0 ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
2007-12-15 07:39:29 -08:00
xdiff = ( SDWORD ) psDroid - > pos . x - ( SDWORD ) psDroid - > sMove . bumpX ;
ydiff = ( SDWORD ) psDroid - > pos . y - ( SDWORD ) psDroid - > sMove . bumpY ;
2007-06-28 10:47:08 -07:00
diffSq = xdiff * xdiff + ydiff * ydiff ;
if ( diffSq > BLOCK_DIST * BLOCK_DIST )
{
// Move on, clear the bump
psDroid - > sMove . bumpTime = 0 ;
psDroid - > sMove . lastBump = 0 ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
if ( psDroid - > sMove . Status = = MOVESHUFFLE )
{
blockTime = SHUFFLE_BLOCK_TIME ;
}
else
{
blockTime = BLOCK_TIME ;
}
if ( gameTime - psDroid - > sMove . bumpTime > blockTime )
{
// Stopped long enough - blocked
psDroid - > sMove . bumpTime = 0 ;
psDroid - > sMove . lastBump = 0 ;
2012-10-27 09:50:10 -07:00
if ( ! isHumanPlayer ( psDroid - > player ) & & bMultiPlayer )
{
psDroid - > lastFrustratedTime = gameTime ;
objTrace ( psDroid - > id , " FRUSTRATED " ) ;
}
else
{
objTrace ( psDroid - > id , " BLOCKED " ) ;
}
2007-06-28 10:47:08 -07:00
// if the unit cannot see the next way point - reroute it's got stuck
2012-10-27 09:50:10 -07:00
if ( ( bMultiPlayer | | psDroid - > player = = selectedPlayer | | psDroid - > lastFrustratedTime = = gameTime )
& & psDroid - > sMove . pathIndex ! = psDroid - > sMove . numPoints )
2007-06-28 10:47:08 -07:00
{
2011-01-07 15:20:12 -08:00
objTrace ( psDroid - > id , " Trying to reroute to (%d,%d) " , psDroid - > sMove . destination . x , psDroid - > sMove . destination . y ) ;
moveDroidTo ( psDroid , psDroid - > sMove . destination . x , psDroid - > sMove . destination . y ) ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
2008-03-24 09:51:17 -07:00
return true ;
2007-06-28 10:47:08 -07:00
}
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
2006-05-27 09:37:17 -07:00
// Calculate the actual movement to slide around
2010-05-25 09:56:27 -07:00
static void moveCalcSlideVector ( DROID * psDroid , int32_t objX , int32_t objY , int32_t * pMx , int32_t * pMy )
2007-06-28 10:47:08 -07:00
{
2010-05-25 09:56:27 -07:00
int32_t dirX , dirY , dirMagSq , dotRes ;
2011-12-17 05:57:51 -08:00
const int32_t mx = * pMx ;
const int32_t my = * pMy ;
2007-06-28 10:47:08 -07:00
// Calculate the vector to the obstruction
2010-05-25 09:56:27 -07:00
const int32_t obstX = psDroid - > pos . x - objX ;
const int32_t obstY = psDroid - > pos . y - objY ;
2007-06-28 10:47:08 -07:00
// if the target dir is the same, don't need to slide
if ( obstX * mx + obstY * my > = 0 )
{
return ;
}
// Choose the tangent vector to this on the same side as the target
2010-03-05 05:42:57 -08:00
dotRes = obstY * mx - obstX * my ;
2007-06-28 10:47:08 -07:00
if ( dotRes > = 0 )
{
dirX = obstY ;
dirY = - obstX ;
}
else
{
dirX = - obstY ;
dirY = obstX ;
2010-03-05 05:42:57 -08:00
dotRes = - dotRes ;
2007-06-28 10:47:08 -07:00
}
2010-05-25 09:56:27 -07:00
dirMagSq = MAX ( 1 , dirX * dirX + dirY * dirY ) ;
2007-06-28 10:47:08 -07:00
// Calculate the component of the movement in the direction of the tangent vector
2011-12-17 05:57:51 -08:00
* pMx = ( int64_t ) dirX * dotRes / dirMagSq ;
* pMy = ( int64_t ) dirY * dotRes / dirMagSq ;
2007-06-28 10:47:08 -07:00
}
2011-03-02 03:59:56 -08:00
static void moveOpenGates ( DROID * psDroid , Vector2i tile )
{
// is the new tile a gate?
if ( ! worldOnMap ( tile . x , tile . y ) )
{
return ;
}
MAPTILE * psTile = mapTile ( tile ) ;
if ( ! isFlying ( psDroid ) & & psTile & & psTile - > psObject & & psTile - > psObject - > type = = OBJ_STRUCTURE & & aiCheckAlliances ( psTile - > psObject - > player , psDroid - > player ) )
{
requestOpenGate ( ( STRUCTURE * ) psTile - > psObject ) ; // If it's a friendly gate, open it. (It would be impolite to open an enemy gate.)
}
}
static void moveOpenGates ( DROID * psDroid )
{
Vector2i pos = removeZ ( psDroid - > pos ) + iSinCosR ( psDroid - > sMove . moveDir , psDroid - > sMove . speed * SAS_OPEN_SPEED / GAME_TICKS_PER_SEC ) ;
moveOpenGates ( psDroid , map_coord ( pos ) ) ;
}
2007-06-28 10:47:08 -07:00
// see if a droid has run into a blocking tile
2010-03-05 05:42:57 -08:00
// TODO See if this function can be simplified.
2010-05-25 09:56:27 -07:00
static void moveCalcBlockingSlide ( DROID * psDroid , int32_t * pmx , int32_t * pmy , uint16_t tarDir , uint16_t * pSlideDir )
2007-06-28 10:47:08 -07:00
{
2010-05-25 09:56:27 -07:00
PROPULSION_TYPE propulsion = getPropulsionStats ( psDroid ) - > propulsionType ;
2007-06-28 10:47:08 -07:00
SDWORD horizX , horizY , vertX , vertY ;
2010-11-16 09:33:20 -08:00
uint16_t slideDir ;
2010-05-25 09:56:27 -07:00
// calculate the new coords and see if they are on a different tile
2011-12-17 05:57:51 -08:00
const int32_t mx = gameTimeAdjustedAverage ( * pmx , EXTRA_PRECISION ) ;
const int32_t my = gameTimeAdjustedAverage ( * pmy , EXTRA_PRECISION ) ;
2010-05-25 09:56:27 -07:00
const int32_t tx = map_coord ( psDroid - > pos . x ) ;
const int32_t ty = map_coord ( psDroid - > pos . y ) ;
const int32_t nx = psDroid - > pos . x + mx ;
const int32_t ny = psDroid - > pos . y + my ;
const int32_t ntx = map_coord ( nx ) ;
const int32_t nty = map_coord ( ny ) ;
const int32_t blkCX = world_coord ( ntx ) + TILE_UNITS / 2 ;
const int32_t blkCY = world_coord ( nty ) + TILE_UNITS / 2 ;
2007-06-28 10:47:08 -07:00
2008-03-24 07:21:08 -07:00
CHECK_DROID ( psDroid ) ;
2010-02-18 11:35:37 -08:00
// is the new tile a gate?
2011-03-02 03:59:56 -08:00
moveOpenGates ( psDroid , Vector2i ( ntx , nty ) ) ;
2010-02-18 11:35:37 -08:00
2007-06-28 10:47:08 -07:00
// is the new tile blocking?
2011-02-28 13:58:19 -08:00
if ( ! fpathBlockingTile ( ntx , nty , propulsion ) )
2007-06-28 10:47:08 -07:00
{
// not blocking, don't change the move vector
return ;
}
// if the droid is shuffling - just stop
if ( psDroid - > sMove . Status = = MOVESHUFFLE )
{
2010-03-02 10:26:06 -08:00
objTrace ( psDroid - > id , " Was shuffling, now stopped " ) ;
2007-06-28 10:47:08 -07:00
psDroid - > sMove . Status = MOVEINACTIVE ;
}
// note the bump time and position if necessary
2008-07-07 03:15:00 -07:00
if ( ! isVtolDroid ( psDroid ) & &
2007-06-28 10:47:08 -07:00
psDroid - > sMove . bumpTime = = 0 )
{
psDroid - > sMove . bumpTime = gameTime ;
psDroid - > sMove . lastBump = 0 ;
psDroid - > sMove . pauseTime = 0 ;
2007-12-15 07:39:29 -08:00
psDroid - > sMove . bumpX = psDroid - > pos . x ;
psDroid - > sMove . bumpY = psDroid - > pos . y ;
2010-02-28 15:14:52 -08:00
psDroid - > sMove . bumpDir = psDroid - > rot . direction ;
2007-06-28 10:47:08 -07:00
}
if ( tx ! = ntx & & ty ! = nty )
{
// moved diagonally
// figure out where the other two possible blocking tiles are
horizX = mx < 0 ? ntx + 1 : ntx - 1 ;
horizY = nty ;
vertX = ntx ;
vertY = my < 0 ? nty + 1 : nty - 1 ;
2008-05-07 09:37:46 -07:00
if ( fpathBlockingTile ( horizX , horizY , propulsion ) & & fpathBlockingTile ( vertX , vertY , propulsion ) )
2007-06-28 10:47:08 -07:00
{
// in a corner - choose an arbitrary slide
2010-02-06 09:14:43 -08:00
if ( gameRand ( 2 ) = = 0 )
2007-06-28 10:47:08 -07:00
{
2007-07-14 03:59:04 -07:00
* pmx = 0 ;
2007-06-28 10:47:08 -07:00
* pmy = - * pmy ;
}
else
{
* pmx = - * pmx ;
2007-07-14 03:59:04 -07:00
* pmy = 0 ;
2007-06-28 10:47:08 -07:00
}
}
2008-05-07 09:37:46 -07:00
else if ( fpathBlockingTile ( horizX , horizY , propulsion ) )
2007-06-28 10:47:08 -07:00
{
2007-07-14 03:59:04 -07:00
* pmy = 0 ;
2007-06-28 10:47:08 -07:00
}
2008-05-07 09:37:46 -07:00
else if ( fpathBlockingTile ( vertX , vertY , propulsion ) )
2007-06-28 10:47:08 -07:00
{
2007-07-14 03:59:04 -07:00
* pmx = 0 ;
2007-06-28 10:47:08 -07:00
}
else
{
moveCalcSlideVector ( psDroid , blkCX , blkCY , pmx , pmy ) ;
}
}
else if ( tx ! = ntx )
{
// moved horizontally - see which half of the tile were in
2007-12-15 07:39:29 -08:00
if ( ( psDroid - > pos . y & TILE_MASK ) > TILE_UNITS / 2 )
2007-06-28 10:47:08 -07:00
{
// top half
2008-05-07 09:37:46 -07:00
if ( fpathBlockingTile ( ntx , nty + 1 , propulsion ) )
2007-06-28 10:47:08 -07:00
{
2007-07-14 03:59:04 -07:00
* pmx = 0 ;
2007-06-28 10:47:08 -07:00
}
else
{
moveCalcSlideVector ( psDroid , blkCX , blkCY , pmx , pmy ) ;
}
}
else
{
// bottom half
2008-05-07 09:37:46 -07:00
if ( fpathBlockingTile ( ntx , nty - 1 , propulsion ) )
2007-06-28 10:47:08 -07:00
{
2007-07-14 03:59:04 -07:00
* pmx = 0 ;
2007-06-28 10:47:08 -07:00
}
else
{
moveCalcSlideVector ( psDroid , blkCX , blkCY , pmx , pmy ) ;
}
}
}
else if ( ty ! = nty )
{
// moved vertically
2007-12-15 07:39:29 -08:00
if ( ( psDroid - > pos . x & TILE_MASK ) > TILE_UNITS / 2 )
2007-06-28 10:47:08 -07:00
{
// top half
2008-05-07 09:37:46 -07:00
if ( fpathBlockingTile ( ntx + 1 , nty , propulsion ) )
2007-06-28 10:47:08 -07:00
{
2007-07-14 03:59:04 -07:00
* pmy = 0 ;
2007-06-28 10:47:08 -07:00
}
else
{
moveCalcSlideVector ( psDroid , blkCX , blkCY , pmx , pmy ) ;
}
}
else
{
// bottom half
2008-05-07 09:37:46 -07:00
if ( fpathBlockingTile ( ntx - 1 , nty , propulsion ) )
2007-06-28 10:47:08 -07:00
{
2007-07-14 03:59:04 -07:00
* pmy = 0 ;
2007-06-28 10:47:08 -07:00
}
else
{
moveCalcSlideVector ( psDroid , blkCX , blkCY , pmx , pmy ) ;
}
}
}
else // if (tx == ntx && ty == nty)
{
// on a blocking tile - see if we need to jump off
2010-05-19 13:23:32 -07:00
int intx = psDroid - > pos . x & TILE_MASK ;
int inty = psDroid - > pos . y & TILE_MASK ;
2011-03-12 17:32:15 -08:00
bool bJumped = false ;
2008-03-24 13:27:49 -07:00
int jumpx = psDroid - > pos . x ;
int jumpy = psDroid - > pos . y ;
2007-06-28 10:47:08 -07:00
if ( intx < TILE_UNITS / 2 )
{
if ( inty < TILE_UNITS / 2 )
{
// top left
2008-05-07 09:37:46 -07:00
if ( ( mx < 0 ) & & fpathBlockingTile ( tx - 1 , ty , propulsion ) )
2007-06-28 10:47:08 -07:00
{
2008-03-24 09:51:17 -07:00
bJumped = true ;
2007-06-28 10:47:08 -07:00
jumpy = ( jumpy & ~ TILE_MASK ) - 1 ;
}
2008-05-07 09:37:46 -07:00
if ( ( my < 0 ) & & fpathBlockingTile ( tx , ty - 1 , propulsion ) )
2007-06-28 10:47:08 -07:00
{
2008-03-24 09:51:17 -07:00
bJumped = true ;
2007-06-28 10:47:08 -07:00
jumpx = ( jumpx & ~ TILE_MASK ) - 1 ;
}
}
else
{
// bottom left
2008-05-07 09:37:46 -07:00
if ( ( mx < 0 ) & & fpathBlockingTile ( tx - 1 , ty , propulsion ) )
2007-06-28 10:47:08 -07:00
{
2008-03-24 09:51:17 -07:00
bJumped = true ;
2007-06-28 10:47:08 -07:00
jumpy = ( jumpy & ~ TILE_MASK ) + TILE_UNITS ;
}
2008-05-07 09:37:46 -07:00
if ( ( my > = 0 ) & & fpathBlockingTile ( tx , ty + 1 , propulsion ) )
2007-06-28 10:47:08 -07:00
{
2008-03-24 09:51:17 -07:00
bJumped = true ;
2007-06-28 10:47:08 -07:00
jumpx = ( jumpx & ~ TILE_MASK ) - 1 ;
}
}
}
else
{
if ( inty < TILE_UNITS / 2 )
{
// top right
2008-05-07 09:37:46 -07:00
if ( ( mx > = 0 ) & & fpathBlockingTile ( tx + 1 , ty , propulsion ) )
2007-06-28 10:47:08 -07:00
{
2008-03-24 09:51:17 -07:00
bJumped = true ;
2007-06-28 10:47:08 -07:00
jumpy = ( jumpy & ~ TILE_MASK ) - 1 ;
}
2008-05-07 09:37:46 -07:00
if ( ( my < 0 ) & & fpathBlockingTile ( tx , ty - 1 , propulsion ) )
2007-06-28 10:47:08 -07:00
{
2008-03-24 09:51:17 -07:00
bJumped = true ;
2007-06-28 10:47:08 -07:00
jumpx = ( jumpx & ~ TILE_MASK ) + TILE_UNITS ;
}
}
else
{
// bottom right
2008-05-07 09:37:46 -07:00
if ( ( mx > = 0 ) & & fpathBlockingTile ( tx + 1 , ty , propulsion ) )
2007-06-28 10:47:08 -07:00
{
2008-03-24 09:51:17 -07:00
bJumped = true ;
2007-06-28 10:47:08 -07:00
jumpy = ( jumpy & ~ TILE_MASK ) + TILE_UNITS ;
}
2008-05-07 09:37:46 -07:00
if ( ( my > = 0 ) & & fpathBlockingTile ( tx , ty + 1 , propulsion ) )
2007-06-28 10:47:08 -07:00
{
2008-03-24 09:51:17 -07:00
bJumped = true ;
2007-06-28 10:47:08 -07:00
jumpx = ( jumpx & ~ TILE_MASK ) + TILE_UNITS ;
}
}
}
if ( bJumped )
{
2008-03-24 13:27:49 -07:00
psDroid - > pos . x = MAX ( 0 , jumpx ) ;
psDroid - > pos . y = MAX ( 0 , jumpy ) ;
2007-07-14 03:59:04 -07:00
* pmx = 0 ;
* pmy = 0 ;
2007-06-28 10:47:08 -07:00
}
else
{
moveCalcSlideVector ( psDroid , blkCX , blkCY , pmx , pmy ) ;
}
}
2010-03-05 05:42:57 -08:00
slideDir = iAtan2 ( * pmx , * pmy ) ;
2007-06-28 10:47:08 -07:00
if ( ntx ! = tx )
{
// hit a horizontal block
2010-03-01 13:19:20 -08:00
if ( ( tarDir < DEG ( 90 ) | | tarDir > DEG ( 270 ) ) & &
( slideDir > = DEG ( 90 ) & & slideDir < = DEG ( 270 ) ) )
2007-06-28 10:47:08 -07:00
{
slideDir = tarDir ;
}
2010-03-01 13:19:20 -08:00
else if ( ( tarDir > = DEG ( 90 ) & & tarDir < = DEG ( 270 ) ) & &
( slideDir < DEG ( 90 ) | | slideDir > DEG ( 270 ) ) )
2007-06-28 10:47:08 -07:00
{
slideDir = tarDir ;
}
}
if ( nty ! = ty )
{
// hit a vertical block
2010-03-01 13:19:20 -08:00
if ( ( tarDir < DEG ( 180 ) ) & &
( slideDir > = DEG ( 180 ) ) )
2007-06-28 10:47:08 -07:00
{
slideDir = tarDir ;
}
2010-03-01 13:19:20 -08:00
else if ( ( tarDir > = DEG ( 180 ) ) & &
( slideDir < DEG ( 180 ) ) )
2007-06-28 10:47:08 -07:00
{
slideDir = tarDir ;
}
}
* pSlideDir = slideDir ;
2008-03-24 07:21:08 -07:00
CHECK_DROID ( psDroid ) ;
2007-06-28 10:47:08 -07:00
}
// see if a droid has run into another droid
// Only consider stationery droids
2010-05-25 09:56:27 -07:00
static void moveCalcDroidSlide ( DROID * psDroid , int * pmx , int * pmy )
2007-06-28 10:47:08 -07:00
{
2010-05-25 09:56:27 -07:00
int32_t droidR , rad , radSq , objR , xdiff , ydiff , distSq , spmx , spmy ;
2011-03-12 17:32:15 -08:00
bool bLegs ;
2007-06-28 10:47:08 -07:00
2008-03-24 07:21:08 -07:00
CHECK_DROID ( psDroid ) ;
2008-03-24 09:51:17 -07:00
bLegs = false ;
2008-08-02 09:32:48 -07:00
if ( psDroid - > droidType = = DROID_PERSON | | cyborgDroid ( psDroid ) )
2007-06-28 10:47:08 -07:00
{
2008-03-24 09:51:17 -07:00
bLegs = true ;
2007-06-28 10:47:08 -07:00
}
2011-12-17 05:57:51 -08:00
spmx = gameTimeAdjustedAverage ( * pmx , EXTRA_PRECISION ) ;
spmy = gameTimeAdjustedAverage ( * pmy , EXTRA_PRECISION ) ;
2007-06-28 10:47:08 -07:00
droidR = moveObjRadius ( ( BASE_OBJECT * ) psDroid ) ;
2012-03-16 01:41:48 -07:00
BASE_OBJECT * psObst = NULL ;
2013-02-09 03:33:00 -08:00
static GridList gridList ; // static to avoid allocations.
gridList = gridStartIterate ( psDroid - > pos . x , psDroid - > pos . y , OBJ_MAXRADIUS ) ;
for ( GridIterator gi = gridList . begin ( ) ; gi ! = gridList . end ( ) ; + + gi )
2007-06-28 10:47:08 -07:00
{
2012-03-16 01:41:48 -07:00
BASE_OBJECT * psObj = * gi ;
if ( psObj - > died )
{
continue ;
}
2010-01-16 14:51:26 -08:00
if ( psObj - > type = = OBJ_DROID )
2007-06-28 10:47:08 -07:00
{
2012-02-27 18:17:47 -08:00
if ( ( ( DROID * ) psObj ) - > droidType = = DROID_TRANSPORTER | | ( ( DROID * ) psObj ) - > droidType = = DROID_SUPERTRANSPORTER )
2007-06-28 10:47:08 -07:00
{
2013-11-18 22:50:11 -08:00
// ignore transporters
2007-06-28 10:47:08 -07:00
continue ;
}
2010-01-16 14:51:26 -08:00
if ( ! bLegs & & ( ( DROID * ) psObj ) - > droidType = = DROID_PERSON )
2007-06-28 10:47:08 -07:00
{
// everything else doesn't avoid people
continue ;
}
2012-10-27 09:50:10 -07:00
if ( psObj - > player = = psDroid - > player
& & psDroid - > lastFrustratedTime > 0
& & gameTime - psDroid - > lastFrustratedTime < FRUSTRATED_TIME )
{
continue ; // clip straight through own units when sufficient frustrated -- using cheat codes!
}
2007-06-28 10:47:08 -07:00
}
else
{
// ignore anything that isn't a droid
continue ;
}
2010-01-16 14:51:26 -08:00
objR = moveObjRadius ( psObj ) ;
2007-06-28 10:47:08 -07:00
rad = droidR + objR ;
radSq = rad * rad ;
2010-05-25 09:56:27 -07:00
xdiff = psDroid - > pos . x + spmx - psObj - > pos . x ;
ydiff = psDroid - > pos . y + spmy - psObj - > pos . y ;
2007-12-24 05:57:19 -08:00
distSq = xdiff * xdiff + ydiff * ydiff ;
2010-05-25 09:56:27 -07:00
if ( xdiff * spmx + ydiff * spmy > = 0 )
2007-06-28 10:47:08 -07:00
{
// object behind
continue ;
}
if ( radSq > distSq )
{
2010-03-07 08:41:34 -08:00
if ( psObst ! = NULL )
2007-06-28 10:47:08 -07:00
{
// hit more than one droid - stop
2010-05-25 09:56:27 -07:00
* pmx = 0 ;
* pmy = 0 ;
2007-06-28 10:47:08 -07:00
psObst = NULL ;
break ;
}
else
{
2010-01-16 14:51:26 -08:00
psObst = psObj ;
2007-06-28 10:47:08 -07:00
// note the bump time and position if necessary
if ( psDroid - > sMove . bumpTime = = 0 )
{
psDroid - > sMove . bumpTime = gameTime ;
psDroid - > sMove . lastBump = 0 ;
psDroid - > sMove . pauseTime = 0 ;
2007-12-15 07:39:29 -08:00
psDroid - > sMove . bumpX = psDroid - > pos . x ;
psDroid - > sMove . bumpY = psDroid - > pos . y ;
2010-02-28 15:14:52 -08:00
psDroid - > sMove . bumpDir = psDroid - > rot . direction ;
2007-06-28 10:47:08 -07:00
}
else
{
psDroid - > sMove . lastBump = ( UWORD ) ( gameTime - psDroid - > sMove . bumpTime ) ;
}
// tell inactive droids to get out the way
2009-06-04 10:19:13 -07:00
if ( psObst - > type = = OBJ_DROID )
2007-06-28 10:47:08 -07:00
{
2009-06-04 10:19:13 -07:00
DROID * psShuffleDroid = ( DROID * ) psObst ;
2013-11-18 22:28:14 -08:00
if ( aiCheckAlliances ( psObst - > player , psDroid - > player )
& & psShuffleDroid - > action ! = DACTION_WAITDURINGREARM
& & psShuffleDroid - > sMove . Status = = MOVEINACTIVE )
2007-06-28 10:47:08 -07:00
{
2013-11-18 22:28:14 -08:00
moveShuffleDroid ( psShuffleDroid , psDroid - > sMove . target - removeZ ( psDroid - > pos ) ) ;
2007-06-28 10:47:08 -07:00
}
}
}
}
}
if ( psObst ! = NULL )
{
2013-11-18 22:28:14 -08:00
// Try to slide round it
moveCalcSlideVector ( psDroid , psObst - > pos . x , psObst - > pos . y , pmx , pmy ) ;
2007-06-28 10:47:08 -07:00
}
2008-03-24 07:21:08 -07:00
CHECK_DROID ( psDroid ) ;
2007-06-28 10:47:08 -07:00
}
// get an obstacle avoidance vector
2011-01-07 15:20:12 -08:00
static Vector2i moveGetObstacleVector ( DROID * psDroid , Vector2i dest )
2007-06-28 10:47:08 -07:00
{
2010-07-15 11:02:15 -07:00
int32_t numObst = 0 , distTot = 0 ;
2011-01-07 15:20:12 -08:00
Vector2i dir ( 0 , 0 ) ;
2013-05-09 04:24:19 -07:00
PROPULSION_STATS * psPropStats = asPropulsionStats + psDroid - > asBits [ COMP_PROPULSION ] ;
2007-06-28 10:47:08 -07:00
2008-05-07 09:37:46 -07:00
ASSERT ( psPropStats , " invalid propulsion stats pointer " ) ;
2007-06-28 10:47:08 -07:00
2011-11-26 08:37:46 -08:00
int ourMaxSpeed = psPropStats - > maxSpeed ;
int ourRadius = moveObjRadius ( psDroid ) ;
if ( ourMaxSpeed = = 0 )
{
return dest ; // No point deciding which way to go, if we can't move...
}
2007-06-28 10:47:08 -07:00
// scan the neighbours for obstacles
2013-02-09 03:33:00 -08:00
static GridList gridList ; // static to avoid allocations.
gridList = gridStartIterate ( psDroid - > pos . x , psDroid - > pos . y , AVOID_DIST ) ;
for ( GridIterator gi = gridList . begin ( ) ; gi ! = gridList . end ( ) ; + + gi )
2007-06-28 10:47:08 -07:00
{
2013-02-09 03:33:00 -08:00
if ( * gi = = psDroid )
2011-11-26 08:37:46 -08:00
{
continue ; // Don't try to avoid ourselves.
}
2013-02-09 03:33:00 -08:00
DROID * psObstacle = castDroid ( * gi ) ;
2011-11-26 08:37:46 -08:00
if ( psObstacle = = NULL )
2007-06-28 10:47:08 -07:00
{
2010-01-16 14:51:26 -08:00
// Object wrong type to worry about.
2007-06-28 10:47:08 -07:00
continue ;
}
2006-05-27 09:37:17 -07:00
2007-06-28 10:47:08 -07:00
// vtol droids only avoid each other and don't affect ground droids
2011-11-26 08:37:46 -08:00
if ( isVtolDroid ( psDroid ) ! = isVtolDroid ( psObstacle ) )
2007-06-28 10:47:08 -07:00
{
continue ;
}
2012-02-27 18:17:47 -08:00
if ( ( psObstacle - > droidType = = DROID_TRANSPORTER | | psObstacle - > droidType = = DROID_SUPERTRANSPORTER ) | |
2011-11-26 08:37:46 -08:00
( psObstacle - > droidType = = DROID_PERSON & &
psObstacle - > player ! = psDroid - > player ) )
2007-06-28 10:47:08 -07:00
{
// don't avoid people on the other side - run over them
continue ;
}
2011-11-26 08:37:46 -08:00
2013-05-09 04:24:19 -07:00
PROPULSION_STATS * obstaclePropStats = asPropulsionStats + psObstacle - > asBits [ COMP_PROPULSION ] ;
2011-11-26 08:37:46 -08:00
int obstacleMaxSpeed = obstaclePropStats - > maxSpeed ;
int obstacleRadius = moveObjRadius ( psObstacle ) ;
int totalRadius = ourRadius + obstacleRadius ;
// Try to guess where the obstacle will be when we get close.
// Velocity guess 1: Guess the velocity the droid is actually moving at.
Vector2i obstVelocityGuess1 = iSinCosR ( psObstacle - > sMove . moveDir , psObstacle - > sMove . speed ) ;
// Velocity guess 2: Guess the velocity the droid wants to move at.
Vector2i obstTargetDiff = psObstacle - > sMove . target - psObstacle - > pos ;
Vector2i obstVelocityGuess2 = iSinCosR ( iAtan2 ( obstTargetDiff ) , obstacleMaxSpeed * std : : min ( iHypot ( obstTargetDiff ) , AVOID_DIST ) / AVOID_DIST ) ;
if ( moveBlocked ( psObstacle ) )
{
obstVelocityGuess2 = Vector2i ( 0 , 0 ) ; // This obstacle isn't going anywhere, even if it wants to.
//obstVelocityGuess2 = -obstVelocityGuess2;
}
// Guess the average of the two guesses.
Vector2i obstVelocityGuess = ( obstVelocityGuess1 + obstVelocityGuess2 ) / 2 ;
// Find the guessed obstacle speed and direction, clamped to half our speed.
int obstSpeedGuess = std : : min ( iHypot ( obstVelocityGuess ) , ourMaxSpeed / 2 ) ;
uint16_t obstDirectionGuess = iAtan2 ( obstVelocityGuess ) ;
// Position of obstacle relative to us.
Vector2i diff = removeZ ( psObstacle - > pos - psDroid - > pos ) ;
// Find very approximate position of obstacle relative to us when we get close, based on our guesses.
Vector2i deltaDiff = iSinCosR ( obstDirectionGuess , ( int64_t ) std : : max ( iHypot ( diff ) - totalRadius * 2 / 3 , 0 ) * obstSpeedGuess / ourMaxSpeed ) ;
2012-06-13 00:38:10 -07:00
if ( ! fpathBlockingTile ( map_coord ( psObstacle - > pos . x + deltaDiff . x ) , map_coord ( psObstacle - > pos . y + deltaDiff . y ) , obstaclePropStats - > propulsionType ) ) // Don't assume obstacle can go through cliffs.
2011-11-26 08:37:46 -08:00
{
diff + = deltaDiff ;
}
2011-01-07 15:20:12 -08:00
if ( diff * dest < 0 )
2007-06-28 10:47:08 -07:00
{
// object behind
continue ;
}
2011-11-26 08:37:46 -08:00
int centreDist = std : : max ( iHypot ( diff ) , 1 ) ;
int dist = std : : max ( centreDist - totalRadius , 1 ) ;
2007-06-28 10:47:08 -07:00
2011-11-26 08:37:46 -08:00
dir + = diff * 65536 / ( centreDist * dist ) ;
distTot + = 65536 / dist ;
2010-07-15 11:02:15 -07:00
numObst + = 1 ;
2007-06-28 10:47:08 -07:00
}
2013-11-06 15:17:07 -08:00
if ( dir = = Vector2i ( 0 , 0 ) | | numObst = = 0 )
2007-06-28 10:47:08 -07:00
{
2011-01-07 15:20:12 -08:00
return dest ;
}
2010-07-15 11:02:15 -07:00
2011-11-26 08:37:46 -08:00
dir = Vector2i ( dir . x / numObst , dir . y / numObst ) ;
2011-01-07 15:20:12 -08:00
distTot / = numObst ;
2007-06-28 10:47:08 -07:00
2011-01-07 15:20:12 -08:00
// Create the avoid vector
2011-11-26 08:37:46 -08:00
Vector2i o ( dir . y , - dir . x ) ;
2011-01-07 15:20:12 -08:00
Vector2i avoid = dest * o < 0 ? - o : o ;
2007-06-28 10:47:08 -07:00
2011-11-26 08:37:46 -08:00
// Normalise dest and avoid.
dest = dest * 32768 / ( iHypot ( dest ) + 1 ) ;
avoid = avoid * 32768 / ( iHypot ( avoid ) + 1 ) ;
2011-01-07 15:20:12 -08:00
// combine the avoid vector and the target vector
2011-11-26 08:37:46 -08:00
int ratio = std : : min ( distTot * ourRadius / 2 , 65536 ) ;
2007-06-28 10:47:08 -07:00
2011-11-26 08:37:46 -08:00
return dest * ( 65536 - ratio ) + avoid * ratio ;
2007-06-28 10:47:08 -07:00
}
2007-07-14 13:13:24 -07:00
/*!
* Get a direction for a droid to avoid obstacles etc .
* \ param psDroid Which droid to examine
* \ return The normalised direction vector
*/
2010-03-01 12:39:26 -08:00
static uint16_t moveGetDirection ( DROID * psDroid )
2007-07-14 13:13:24 -07:00
{
2010-12-21 12:51:29 -08:00
Vector2i src = removeZ ( psDroid - > pos ) ; // Do not want precice precision here, would overflow.
2011-01-07 15:20:12 -08:00
Vector2i target = psDroid - > sMove . target ;
2010-12-21 12:51:29 -08:00
Vector2i dest = target - src ;
2007-10-27 16:49:41 -07:00
2007-07-14 13:13:24 -07:00
// Transporters don't need to avoid obstacles, but everyone else should
2012-02-25 19:35:21 -08:00
if ( psDroid - > droidType ! = DROID_TRANSPORTER & & psDroid - > droidType ! = DROID_SUPERTRANSPORTER )
2007-06-28 10:47:08 -07:00
{
2011-01-07 15:20:12 -08:00
dest = moveGetObstacleVector ( psDroid , dest ) ;
2007-06-28 10:47:08 -07:00
}
2007-07-14 13:13:24 -07:00
2010-12-21 12:51:29 -08:00
return iAtan2 ( dest ) ;
2007-06-28 10:47:08 -07:00
}
// Check if a droid has got to a way point
2011-02-27 03:10:40 -08:00
static bool moveReachedWayPoint ( DROID * psDroid )
2007-06-28 10:47:08 -07:00
{
// Calculate the vector to the droid
2011-01-07 15:20:12 -08:00
const Vector2i droid = removeZ ( psDroid - > pos ) - psDroid - > sMove . target ;
2011-02-27 03:10:40 -08:00
const bool last = psDroid - > sMove . pathIndex = = psDroid - > sMove . numPoints ;
2012-02-28 00:12:46 -08:00
int sqprecision = last ? ( ( TILE_UNITS / 4 ) * ( TILE_UNITS / 4 ) ) : ( ( TILE_UNITS / 2 ) * ( TILE_UNITS / 2 ) ) ;
2007-06-28 10:47:08 -07:00
2012-02-28 00:12:46 -08:00
if ( last & & psDroid - > sMove . bumpTime ! = 0 )
2007-06-28 10:47:08 -07:00
{
2012-02-28 00:12:46 -08:00
// Make waypoint tolerance 1 tile after 0 seconds, 2 tiles after 3 seconds, X tiles after (X + 1)² seconds.
sqprecision = ( gameTime - psDroid - > sMove . bumpTime + GAME_TICKS_PER_SEC ) * ( TILE_UNITS * TILE_UNITS / GAME_TICKS_PER_SEC ) ;
2007-06-28 10:47:08 -07:00
}
2010-10-16 11:53:06 -07:00
// Else check current waypoint
2011-01-07 15:20:12 -08:00
return droid * droid < sqprecision ;
2007-06-28 10:47:08 -07:00
}
# define MAX_SPEED_PITCH 60
2011-11-20 14:15:31 -08:00
/** Calculate the new speed for a droid based on factors like pitch.
2008-04-20 15:43:14 -07:00
* @ todo Remove hack for steep slopes not properly marked as blocking on some maps .
*/
2007-06-28 10:47:08 -07:00
SDWORD moveCalcDroidSpeed ( DROID * psDroid )
{
2010-02-28 15:14:52 -08:00
const uint16_t maxPitch = DEG ( MAX_SPEED_PITCH ) ;
2011-11-20 14:15:31 -08:00
UDWORD mapX , mapY ;
2010-02-28 15:14:52 -08:00
int speed , pitch ;
WEAPON_STATS * psWStats ;
2007-06-28 10:47:08 -07:00
2008-03-24 07:21:08 -07:00
CHECK_DROID ( psDroid ) ;
2012-04-24 18:16:51 -07:00
// NOTE: This screws up since the transporter is offscreen still (on a mission!), and we are trying to find terrainType of a tile (that is offscreen!)
if ( psDroid - > droidType = = DROID_TRANSPORTER & & missionIsOffworld ( ) )
{
2013-05-09 04:24:19 -07:00
PROPULSION_STATS * propulsion = asPropulsionStats + psDroid - > asBits [ COMP_PROPULSION ] ;
2012-04-24 18:16:51 -07:00
speed = propulsion - > maxSpeed ;
}
else
{
mapX = map_coord ( psDroid - > pos . x ) ;
mapY = map_coord ( psDroid - > pos . y ) ;
2013-05-09 04:24:19 -07:00
speed = calcDroidSpeed ( psDroid - > baseSpeed , terrainType ( mapTile ( mapX , mapY ) ) , psDroid - > asBits [ COMP_PROPULSION ] , getDroidEffectiveLevel ( psDroid ) ) ;
2012-04-24 18:16:51 -07:00
}
2007-06-28 10:47:08 -07:00
// now offset the speed for the slope of the droid
2010-03-05 01:06:07 -08:00
pitch = angleDelta ( psDroid - > rot . pitch ) ;
2010-02-28 15:14:52 -08:00
speed = ( maxPitch - pitch ) * speed / maxPitch ;
2009-06-17 00:06:06 -07:00
if ( speed < = 10 )
2008-03-20 08:50:28 -07:00
{
2008-03-29 06:27:54 -07:00
// Very nasty hack to deal with buggy maps, where some cliffs are
2008-03-20 08:50:28 -07:00
// not properly marked as being cliffs, but too steep to drive over.
// This confuses the heck out of the path-finding code! - Per
speed = 10 ;
}
2007-06-28 10:47:08 -07:00
// stop droids that have just fired a no fire while moving weapon
2006-11-04 14:56:28 -08:00
if ( psDroid - > numWeaps > 0 )
2007-06-28 10:47:08 -07:00
{
2006-11-04 14:56:28 -08:00
if ( psDroid - > asWeaps [ 0 ] . nStat > 0 & & psDroid - > asWeaps [ 0 ] . lastFired + FOM_MOVEPAUSE > gameTime )
2007-06-28 10:47:08 -07:00
{
2006-11-04 14:56:28 -08:00
psWStats = asWeaponStats + psDroid - > asWeaps [ 0 ] . nStat ;
2012-12-10 07:48:22 -08:00
if ( ! psWStats - > fireOnMove )
2006-11-04 14:56:28 -08:00
{
speed = 0 ;
}
2007-06-28 10:47:08 -07:00
}
}
// slow down shuffling VTOLs
2008-07-07 03:15:00 -07:00
if ( isVtolDroid ( psDroid ) & &
2007-06-28 10:47:08 -07:00
( psDroid - > sMove . Status = = MOVESHUFFLE ) & &
( speed > MIN_END_SPEED ) )
{
speed = MIN_END_SPEED ;
}
2008-03-24 07:21:08 -07:00
CHECK_DROID ( psDroid ) ;
2007-06-28 10:47:08 -07:00
return speed ;
}
2008-04-20 15:43:14 -07:00
/** Determine whether a droid has stopped moving.
* @ return true if the droid doesn ' t move , false if it ' s moving .
*/
2011-03-12 17:32:15 -08:00
static bool moveDroidStopped ( DROID * psDroid , SDWORD speed )
2007-06-28 10:47:08 -07:00
{
2010-02-09 14:35:23 -08:00
if ( psDroid - > sMove . Status = = MOVEINACTIVE & & speed = = 0 & & psDroid - > sMove . speed = = 0 )
2007-06-28 10:47:08 -07:00
{
2008-03-24 09:51:17 -07:00
return true ;
2007-06-28 10:47:08 -07:00
}
else
{
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
}
2011-11-28 12:22:16 -08:00
// Direction is target direction.
2010-03-01 05:50:53 -08:00
static void moveUpdateDroidDirection ( DROID * psDroid , SDWORD * pSpeed , uint16_t direction ,
2011-11-28 12:22:16 -08:00
uint16_t iSpinAngle , int iSpinSpeed , int iTurnSpeed , uint16_t * pDroidDir )
2007-06-28 10:47:08 -07:00
{
2010-03-01 05:50:53 -08:00
* pDroidDir = psDroid - > rot . direction ;
2007-06-28 10:47:08 -07:00
// don't move if in MOVEPAUSE state
if ( psDroid - > sMove . Status = = MOVEPAUSE )
{
return ;
}
2011-11-28 12:22:16 -08:00
int diff = angleDelta ( direction - * pDroidDir ) ;
// Turn while moving - slow down speed depending on target angle so that we can turn faster
2012-02-12 04:11:39 -08:00
* pSpeed = std : : max < int > ( * pSpeed * ( iSpinAngle - abs ( diff ) ) / iSpinAngle , 0 ) ;
2011-11-28 12:22:16 -08:00
// iTurnSpeed is turn speed at max velocity, increase turn speed up to iSpinSpeed when slowing down
int turnSpeed = std : : min < int > ( iTurnSpeed + int64_t ( iSpinSpeed - iTurnSpeed ) * abs ( diff ) / iSpinAngle , iSpinSpeed ) ;
2010-11-27 13:08:39 -08:00
// Calculate the maximum change in direction
2011-11-28 12:22:16 -08:00
int maxChange = gameTimeAdjustedAverage ( turnSpeed ) ;
2010-11-27 13:08:39 -08:00
// Move *pDroidDir towards target, by at most maxChange.
* pDroidDir + = clip ( diff , - maxChange , maxChange ) ;
2007-06-28 10:47:08 -07:00
}
// Calculate current speed perpendicular to droids direction
2010-06-26 12:34:36 -07:00
static int moveCalcPerpSpeed ( DROID * psDroid , uint16_t iDroidDir , SDWORD iSkidDecel )
2007-06-28 10:47:08 -07:00
{
2012-03-30 00:30:31 -07:00
int adiff = angleDelta ( iDroidDir - psDroid - > sMove . moveDir ) ;
int perpSpeed = iSinR ( abs ( adiff ) , psDroid - > sMove . speed ) ;
2007-06-28 10:47:08 -07:00
// decelerate the perpendicular speed
2011-12-17 04:06:48 -08:00
perpSpeed = MAX ( 0 , perpSpeed - gameTimeAdjustedAverage ( iSkidDecel ) ) ;
2007-06-28 10:47:08 -07:00
return perpSpeed ;
}
2010-06-26 12:34:36 -07:00
static void moveCombineNormalAndPerpSpeeds ( DROID * psDroid , int fNormalSpeed , int fPerpSpeed , uint16_t iDroidDir )
2007-06-28 10:47:08 -07:00
{
2010-03-01 13:19:20 -08:00
int16_t adiff ;
2010-06-26 12:34:36 -07:00
int relDir ;
int finalSpeed ;
2007-06-28 10:47:08 -07:00
/* set current direction */
2010-03-01 13:19:20 -08:00
psDroid - > rot . direction = iDroidDir ;
2007-06-28 10:47:08 -07:00
/* set normal speed and direction if perpendicular speed is zero */
2007-07-14 03:59:04 -07:00
if ( fPerpSpeed = = 0 )
2007-06-28 10:47:08 -07:00
{
psDroid - > sMove . speed = fNormalSpeed ;
2010-03-01 13:19:20 -08:00
psDroid - > sMove . moveDir = iDroidDir ;
2007-06-28 10:47:08 -07:00
return ;
}
2010-03-01 13:19:20 -08:00
finalSpeed = iHypot ( fNormalSpeed , fPerpSpeed ) ;
2007-06-28 10:47:08 -07:00
// calculate the angle between the droid facing and movement direction
2010-03-01 13:19:20 -08:00
relDir = iAtan2 ( fPerpSpeed , fNormalSpeed ) ;
2007-06-28 10:47:08 -07:00
// choose the finalDir on the same side as the old movement direction
2010-03-05 01:06:07 -08:00
adiff = angleDelta ( iDroidDir - psDroid - > sMove . moveDir ) ;
2007-06-28 10:47:08 -07:00
2010-03-01 13:19:20 -08:00
psDroid - > sMove . moveDir = adiff < 0 ? iDroidDir + relDir : iDroidDir - relDir ; // Cast wrapping intended.
2007-06-28 10:47:08 -07:00
psDroid - > sMove . speed = finalSpeed ;
}
// Calculate the current speed in the droids normal direction
2010-06-26 12:34:36 -07:00
static int moveCalcNormalSpeed ( DROID * psDroid , int fSpeed , uint16_t iDroidDir , SDWORD iAccel , SDWORD iDecel )
2007-06-28 10:47:08 -07:00
{
2010-03-03 02:16:53 -08:00
uint16_t adiff ;
2010-06-26 12:34:36 -07:00
int normalSpeed ;
2007-06-28 10:47:08 -07:00
2010-03-03 02:16:53 -08:00
adiff = ( uint16_t ) ( iDroidDir - psDroid - > sMove . moveDir ) ; // Cast wrapping intended.
normalSpeed = iCosR ( adiff , psDroid - > sMove . speed ) ;
2007-06-28 10:47:08 -07:00
if ( normalSpeed < fSpeed )
{
// accelerate
2011-12-17 04:06:48 -08:00
normalSpeed + = gameTimeAdjustedAverage ( iAccel ) ;
2007-06-28 10:47:08 -07:00
if ( normalSpeed > fSpeed )
{
normalSpeed = fSpeed ;
}
}
else
{
// decelerate
2011-12-17 04:06:48 -08:00
normalSpeed - = gameTimeAdjustedAverage ( iDecel ) ;
2007-06-28 10:47:08 -07:00
if ( normalSpeed < fSpeed )
{
normalSpeed = fSpeed ;
}
}
return normalSpeed ;
}
2010-05-25 09:56:27 -07:00
static void moveGetDroidPosDiffs ( DROID * psDroid , int32_t * pDX , int32_t * pDY )
2007-06-28 10:47:08 -07:00
{
2011-12-17 05:57:51 -08:00
int32_t move = psDroid - > sMove . speed * EXTRA_PRECISION ; // high precision
2007-06-28 10:47:08 -07:00
2010-05-25 09:56:27 -07:00
* pDX = iSinR ( psDroid - > sMove . moveDir , move ) ;
* pDY = iCosR ( psDroid - > sMove . moveDir , move ) ;
2007-06-28 10:47:08 -07:00
}
// see if the droid is close to the final way point
2007-03-16 13:23:35 -07:00
static void moveCheckFinalWaypoint ( DROID * psDroid , SDWORD * pSpeed )
2007-06-28 10:47:08 -07:00
{
2012-05-02 07:12:05 -07:00
int minEndSpeed = ( * pSpeed + 2 ) / 3 ;
minEndSpeed = std : : min ( minEndSpeed , MIN_END_SPEED ) ;
2007-06-28 10:47:08 -07:00
// don't do this for VTOLs doing attack runs
2008-07-07 03:15:00 -07:00
if ( isVtolDroid ( psDroid ) & & ( psDroid - > action = = DACTION_VTOLATTACK ) )
2007-06-28 10:47:08 -07:00
{
return ;
}
2012-05-02 07:12:05 -07:00
if ( psDroid - > sMove . Status ! = MOVESHUFFLE & &
psDroid - > sMove . pathIndex = = psDroid - > sMove . numPoints )
2007-06-28 10:47:08 -07:00
{
2011-01-07 15:20:12 -08:00
Vector2i diff = removeZ ( psDroid - > pos ) - psDroid - > sMove . target ;
int distSq = diff * diff ;
2007-06-28 10:47:08 -07:00
if ( distSq < END_SPEED_RANGE * END_SPEED_RANGE )
{
2012-05-02 07:12:05 -07:00
* pSpeed = ( * pSpeed - minEndSpeed ) * distSq / ( END_SPEED_RANGE * END_SPEED_RANGE ) + minEndSpeed ;
2007-06-28 10:47:08 -07:00
}
}
}
2010-05-25 09:56:27 -07:00
static void moveUpdateDroidPos ( DROID * psDroid , int32_t dx , int32_t dy )
2007-06-28 10:47:08 -07:00
{
2010-05-25 09:56:27 -07:00
Position newPos ; // high precision coordinates (unusable for squared calculations)
2008-03-24 07:21:08 -07:00
CHECK_DROID ( psDroid ) ;
2009-03-08 10:57:44 -07:00
if ( psDroid - > sMove . Status = = MOVEPAUSE | | isDead ( ( BASE_OBJECT * ) psDroid ) )
2007-06-28 10:47:08 -07:00
{
// don't actually move if the move is paused
return ;
}
2011-12-17 05:57:51 -08:00
psDroid - > pos . x + = gameTimeAdjustedAverage ( dx , EXTRA_PRECISION ) ;
psDroid - > pos . y + = gameTimeAdjustedAverage ( dy , EXTRA_PRECISION ) ;
2007-06-28 10:47:08 -07:00
/* impact if about to go off map else update coordinates */
2010-05-19 13:23:32 -07:00
if ( worldOnMap ( psDroid - > pos . x , psDroid - > pos . y ) = = false )
2007-06-28 10:47:08 -07:00
{
2008-01-17 13:00:39 -08:00
/* transporter going off-world will trigger next map, and is ok */
2012-02-25 16:21:29 -08:00
ASSERT ( psDroid - > droidType = = DROID_TRANSPORTER | | psDroid - > droidType = = DROID_SUPERTRANSPORTER , " droid trying to move off the map! " ) ;
2012-02-25 19:35:21 -08:00
if ( psDroid - > droidType ! = DROID_TRANSPORTER & & psDroid - > droidType ! = DROID_SUPERTRANSPORTER )
2007-06-28 10:47:08 -07:00
{
/* dreadful last-ditch crash-avoiding hack - sort this! - GJ */
2011-12-28 05:42:41 -08:00
destroyDroid ( psDroid , gameTime ) ;
2008-01-13 09:50:29 -08:00
return ;
2007-06-28 10:47:08 -07:00
}
}
// lovely hack to keep transporters just on the map
// two weeks to go and the hacks just get better !!!
2012-02-25 16:21:29 -08:00
if ( psDroid - > droidType = = DROID_TRANSPORTER | | psDroid - > droidType = = DROID_SUPERTRANSPORTER )
2007-06-28 10:47:08 -07:00
{
2007-12-15 07:39:29 -08:00
if ( psDroid - > pos . x = = 0 )
2007-06-28 10:47:08 -07:00
{
2007-12-15 07:39:29 -08:00
psDroid - > pos . x = 1 ;
2007-06-28 10:47:08 -07:00
}
2007-12-15 07:39:29 -08:00
if ( psDroid - > pos . y = = 0 )
2007-06-28 10:47:08 -07:00
{
2007-12-15 07:39:29 -08:00
psDroid - > pos . y = 1 ;
2007-06-28 10:47:08 -07:00
}
}
2008-03-24 07:21:08 -07:00
CHECK_DROID ( psDroid ) ;
2007-06-28 10:47:08 -07:00
}
/* Update a tracked droids position and speed given target values */
2010-03-01 05:50:53 -08:00
static void moveUpdateGroundModel ( DROID * psDroid , SDWORD speed , uint16_t direction )
2007-06-28 10:47:08 -07:00
{
2010-08-15 03:28:58 -07:00
int fPerpSpeed , fNormalSpeed ;
2010-03-01 05:50:53 -08:00
uint16_t iDroidDir ;
2010-03-01 13:19:20 -08:00
uint16_t slideDir ;
2007-06-28 10:47:08 -07:00
PROPULSION_STATS * psPropStats ;
2012-08-12 06:02:11 -07:00
int32_t spinSpeed , spinAngle , turnSpeed , dx , dy , bx , by ;
2007-06-28 10:47:08 -07:00
2008-03-24 13:27:49 -07:00
CHECK_DROID ( psDroid ) ;
2007-06-28 10:47:08 -07:00
// nothing to do if the droid is stopped
2008-03-24 09:51:17 -07:00
if ( moveDroidStopped ( psDroid , speed ) = = true )
2007-06-28 10:47:08 -07:00
{
return ;
}
2013-05-09 04:24:19 -07:00
psPropStats = asPropulsionStats + psDroid - > asBits [ COMP_PROPULSION ] ;
2012-08-12 06:02:11 -07:00
spinSpeed = psDroid - > baseSpeed * psPropStats - > spinSpeed ;
turnSpeed = psDroid - > baseSpeed * psPropStats - > turnSpeed ;
spinAngle = DEG ( psPropStats - > spinAngle ) ;
2007-06-28 10:47:08 -07:00
moveCheckFinalWaypoint ( psDroid , & speed ) ;
2011-11-28 12:22:16 -08:00
moveUpdateDroidDirection ( psDroid , & speed , direction , spinAngle , spinSpeed , turnSpeed , & iDroidDir ) ;
2007-06-28 10:47:08 -07:00
2012-08-12 06:02:11 -07:00
fNormalSpeed = moveCalcNormalSpeed ( psDroid , speed , iDroidDir , psPropStats - > acceleration , psPropStats - > deceleration ) ;
fPerpSpeed = moveCalcPerpSpeed ( psDroid , iDroidDir , psPropStats - > skidDeceleration ) ;
2007-06-28 10:47:08 -07:00
2010-03-01 13:19:20 -08:00
moveCombineNormalAndPerpSpeeds ( psDroid , fNormalSpeed , fPerpSpeed , iDroidDir ) ;
2010-05-25 09:56:27 -07:00
moveGetDroidPosDiffs ( psDroid , & dx , & dy ) ;
2011-03-02 03:59:56 -08:00
moveOpenGates ( psDroid ) ;
2007-06-28 10:47:08 -07:00
moveCheckSquished ( psDroid , dx , dy ) ;
2010-05-25 09:56:27 -07:00
moveCalcDroidSlide ( psDroid , & dx , & dy ) ;
2007-06-28 10:47:08 -07:00
bx = dx ;
by = dy ;
2010-03-01 13:19:20 -08:00
moveCalcBlockingSlide ( psDroid , & bx , & by , direction , & slideDir ) ;
2007-06-28 10:47:08 -07:00
if ( bx ! = dx | | by ! = dy )
{
2011-11-28 12:22:16 -08:00
moveUpdateDroidDirection ( psDroid , & speed , slideDir , spinAngle , psDroid - > baseSpeed * DEG ( 1 ) , psDroid - > baseSpeed * DEG ( 1 ) / 3 , & iDroidDir ) ;
2010-03-01 05:50:53 -08:00
psDroid - > rot . direction = iDroidDir ;
2007-06-28 10:47:08 -07:00
}
2010-05-25 09:56:27 -07:00
moveUpdateDroidPos ( psDroid , bx , by ) ;
2007-06-28 10:47:08 -07:00
//set the droid height here so other routines can use it
2007-12-15 07:39:29 -08:00
psDroid - > pos . z = map_Height ( psDroid - > pos . x , psDroid - > pos . y ) ; //jps 21july96
2007-06-28 10:47:08 -07:00
updateDroidOrientation ( psDroid ) ;
}
/* Update a persons position and speed given target values */
2010-03-01 05:50:53 -08:00
static void moveUpdatePersonModel ( DROID * psDroid , SDWORD speed , uint16_t direction )
2007-06-28 10:47:08 -07:00
{
2010-08-15 03:28:58 -07:00
int fPerpSpeed , fNormalSpeed ;
2012-08-12 06:02:11 -07:00
int32_t spinSpeed , turnSpeed , dx , dy ;
2010-03-01 05:50:53 -08:00
uint16_t iDroidDir ;
2010-03-01 13:19:20 -08:00
uint16_t slideDir ;
2012-08-12 06:02:11 -07:00
PROPULSION_STATS * psPropStats ;
2007-06-28 10:47:08 -07:00
2008-03-24 13:56:06 -07:00
CHECK_DROID ( psDroid ) ;
2007-06-28 10:47:08 -07:00
// nothing to do if the droid is stopped
2008-03-24 09:51:17 -07:00
if ( moveDroidStopped ( psDroid , speed ) = = true )
2007-06-28 10:47:08 -07:00
{
if ( psDroid - > droidType = = DROID_PERSON & &
2011-12-30 08:43:49 -08:00
psDroid - > order . type ! = DORDER_RUNBURN & &
2007-06-28 10:47:08 -07:00
( psDroid - > action = = DACTION_ATTACK | |
psDroid - > action = = DACTION_ROTATETOATTACK ) )
{
/* remove previous anim */
if ( psDroid - > psCurAnim ! = NULL & &
psDroid - > psCurAnim - > psAnim - > uwID ! = ID_ANIM_DROIDFIRE )
{
2008-10-16 10:40:58 -07:00
const bool bRet = animObj_Remove ( psDroid - > psCurAnim , psDroid - > psCurAnim - > psAnim - > uwID ) ;
ASSERT ( bRet , " animObj_Remove failed " ) ;
2007-06-28 10:47:08 -07:00
psDroid - > psCurAnim = NULL ;
}
/* add firing anim */
if ( psDroid - > psCurAnim = = NULL )
{
psDroid - > psCurAnim = animObj_Add ( psDroid , ID_ANIM_DROIDFIRE , 0 , 0 ) ;
}
else
{
2008-03-24 09:51:17 -07:00
psDroid - > psCurAnim - > bVisible = true ;
2007-06-28 10:47:08 -07:00
}
return ;
}
/* don't show move animations if inactive */
if ( psDroid - > psCurAnim ! = NULL )
{
2008-03-24 09:51:17 -07:00
psDroid - > psCurAnim - > bVisible = false ;
2007-06-28 10:47:08 -07:00
}
return ;
}
2013-05-09 04:24:19 -07:00
psPropStats = asPropulsionStats + psDroid - > asBits [ COMP_PROPULSION ] ;
2012-08-12 06:02:11 -07:00
spinSpeed = psDroid - > baseSpeed * psPropStats - > spinSpeed ;
turnSpeed = psDroid - > baseSpeed * psPropStats - > turnSpeed ;
2007-06-28 10:47:08 -07:00
2012-08-12 06:02:11 -07:00
moveUpdateDroidDirection ( psDroid , & speed , direction , DEG ( psPropStats - > spinAngle ) , spinSpeed , turnSpeed , & iDroidDir ) ;
2007-06-28 10:47:08 -07:00
2012-08-12 06:02:11 -07:00
fNormalSpeed = moveCalcNormalSpeed ( psDroid , speed , iDroidDir , psPropStats - > acceleration , psPropStats - > deceleration ) ;
2009-08-24 09:23:34 -07:00
2007-06-28 10:47:08 -07:00
/* people don't skid at the moment so set zero perpendicular speed */
2007-07-14 03:59:04 -07:00
fPerpSpeed = 0 ;
2007-06-28 10:47:08 -07:00
2010-03-01 13:19:20 -08:00
moveCombineNormalAndPerpSpeeds ( psDroid , fNormalSpeed , fPerpSpeed , iDroidDir ) ;
2007-06-28 10:47:08 -07:00
moveGetDroidPosDiffs ( psDroid , & dx , & dy ) ;
2011-03-02 03:59:56 -08:00
moveOpenGates ( psDroid ) ;
2007-06-28 10:47:08 -07:00
moveCalcDroidSlide ( psDroid , & dx , & dy ) ;
2010-03-01 13:19:20 -08:00
moveCalcBlockingSlide ( psDroid , & dx , & dy , direction , & slideDir ) ;
2007-06-28 10:47:08 -07:00
moveUpdateDroidPos ( psDroid , dx , dy ) ;
//set the droid height here so other routines can use it
2007-12-15 07:39:29 -08:00
psDroid - > pos . z = map_Height ( psDroid - > pos . x , psDroid - > pos . y ) ; //jps 21july96
2007-06-28 10:47:08 -07:00
/* update anim if moving and not on fire */
if ( psDroid - > droidType = = DROID_PERSON & & speed ! = 0 & &
2011-12-30 08:43:49 -08:00
psDroid - > order . type ! = DORDER_RUNBURN )
2007-06-28 10:47:08 -07:00
{
/* remove previous anim */
if ( psDroid - > psCurAnim ! = NULL & &
( psDroid - > psCurAnim - > psAnim - > uwID ! = ID_ANIM_DROIDRUN | |
psDroid - > psCurAnim - > psAnim - > uwID ! = ID_ANIM_DROIDRUN ) )
{
2008-10-16 10:40:58 -07:00
const bool bRet = animObj_Remove ( psDroid - > psCurAnim , psDroid - > psCurAnim - > psAnim - > uwID ) ;
ASSERT ( bRet , " animObj_Remove failed " ) ;
2007-06-28 10:47:08 -07:00
psDroid - > psCurAnim = NULL ;
}
/* if no anim currently attached, get one */
if ( psDroid - > psCurAnim = = NULL )
{
// Only add the animation if the droid is on screen, saves memory and time.
2007-12-15 07:39:29 -08:00
if ( clipXY ( psDroid - > pos . x , psDroid - > pos . y ) ) {
2006-08-22 07:28:49 -07:00
debug ( LOG_NEVER , " Added person run anim \n " ) ;
2007-06-28 10:47:08 -07:00
psDroid - > psCurAnim = animObj_Add ( ( BASE_OBJECT * ) psDroid ,
ID_ANIM_DROIDRUN , 0 , 0 ) ;
}
} else {
// If the droid went off screen then remove the animation, saves memory and time.
2007-12-15 07:39:29 -08:00
if ( ! clipXY ( psDroid - > pos . x , psDroid - > pos . y ) ) {
2008-10-16 10:40:58 -07:00
const bool bRet = animObj_Remove ( psDroid - > psCurAnim , psDroid - > psCurAnim - > psAnim - > uwID ) ;
ASSERT ( bRet , " animObj_Remove failed " ) ;
2007-06-28 10:47:08 -07:00
psDroid - > psCurAnim = NULL ;
2006-08-22 07:28:49 -07:00
debug ( LOG_NEVER , " Removed person run anim \n " ) ;
2007-06-28 10:47:08 -07:00
}
}
}
/* show anim */
if ( psDroid - > psCurAnim ! = NULL )
{
2008-03-24 09:51:17 -07:00
psDroid - > psCurAnim - > bVisible = true ;
2007-06-28 10:47:08 -07:00
}
2008-03-24 13:56:06 -07:00
CHECK_DROID ( psDroid ) ;
2007-06-28 10:47:08 -07:00
}
2010-06-26 12:34:36 -07:00
# define VTOL_VERTICAL_SPEED (((psDroid->baseSpeed / 4) > 60) ? ((SDWORD)psDroid->baseSpeed / 4) : 60)
2007-06-28 10:47:08 -07:00
/* primitive 'bang-bang' vtol height controller */
2010-08-15 11:42:40 -07:00
static void moveAdjustVtolHeight ( DROID * psDroid , int32_t iMapHeight )
2007-06-28 10:47:08 -07:00
{
2010-05-19 13:23:32 -07:00
int32_t iMinHeight , iMaxHeight , iLevelHeight ;
2012-02-25 16:21:29 -08:00
if ( ( psDroid - > droidType = = DROID_TRANSPORTER | | psDroid - > droidType = = DROID_SUPERTRANSPORTER ) & & ! bMultiPlayer )
2007-06-28 10:47:08 -07:00
{
iMinHeight = 2 * VTOL_HEIGHT_MIN ;
iLevelHeight = 2 * VTOL_HEIGHT_LEVEL ;
iMaxHeight = 2 * VTOL_HEIGHT_MAX ;
}
else
{
iMinHeight = VTOL_HEIGHT_MIN ;
iLevelHeight = VTOL_HEIGHT_LEVEL ;
iMaxHeight = VTOL_HEIGHT_MAX ;
}
2007-12-15 07:39:29 -08:00
if ( psDroid - > pos . z > = ( iMapHeight + iMaxHeight ) )
2007-06-28 10:47:08 -07:00
{
psDroid - > sMove . iVertSpeed = ( SWORD ) - VTOL_VERTICAL_SPEED ;
}
2007-12-15 07:39:29 -08:00
else if ( psDroid - > pos . z < ( iMapHeight + iMinHeight ) )
2007-06-28 10:47:08 -07:00
{
psDroid - > sMove . iVertSpeed = ( SWORD ) VTOL_VERTICAL_SPEED ;
}
2007-12-15 07:39:29 -08:00
else if ( ( psDroid - > pos . z < iLevelHeight ) & &
2007-06-28 10:47:08 -07:00
( psDroid - > sMove . iVertSpeed < 0 ) )
{
psDroid - > sMove . iVertSpeed = 0 ;
}
2007-12-15 07:39:29 -08:00
else if ( ( psDroid - > pos . z > iLevelHeight ) & &
2007-06-28 10:47:08 -07:00
( psDroid - > sMove . iVertSpeed > 0 ) )
{
psDroid - > sMove . iVertSpeed = 0 ;
}
}
// set a vtol to be hovering in the air
void moveMakeVtolHover ( DROID * psDroid )
{
psDroid - > sMove . Status = MOVEHOVER ;
2010-08-15 11:42:40 -07:00
psDroid - > pos . z = map_Height ( psDroid - > pos . x , psDroid - > pos . y ) + VTOL_HEIGHT_LEVEL ;
2007-06-28 10:47:08 -07:00
}
2010-03-01 05:50:53 -08:00
static void moveUpdateVtolModel ( DROID * psDroid , SDWORD speed , uint16_t direction )
2007-06-28 10:47:08 -07:00
{
2010-08-15 03:28:58 -07:00
int fPerpSpeed , fNormalSpeed ;
2010-03-01 05:50:53 -08:00
uint16_t iDroidDir ;
2010-03-01 13:19:20 -08:00
uint16_t slideDir ;
2012-08-12 06:02:11 -07:00
int32_t spinSpeed , turnSpeed , iMapZ , iSpinSpeed , iTurnSpeed , dx , dy ;
2010-03-01 05:50:53 -08:00
uint16_t targetRoll ;
2012-08-12 06:02:11 -07:00
PROPULSION_STATS * psPropStats ;
2007-06-28 10:47:08 -07:00
2008-03-24 13:56:06 -07:00
CHECK_DROID ( psDroid ) ;
2007-06-28 10:47:08 -07:00
// nothing to do if the droid is stopped
2008-03-24 09:51:17 -07:00
if ( moveDroidStopped ( psDroid , speed ) = = true )
2007-06-28 10:47:08 -07:00
{
return ;
}
2013-05-09 04:24:19 -07:00
psPropStats = asPropulsionStats + psDroid - > asBits [ COMP_PROPULSION ] ;
2012-08-12 13:29:06 -07:00
spinSpeed = DEG ( psPropStats - > spinSpeed ) ;
turnSpeed = DEG ( psPropStats - > turnSpeed ) ;
2012-08-12 06:02:11 -07:00
2007-06-28 10:47:08 -07:00
moveCheckFinalWaypoint ( psDroid , & speed ) ;
2012-02-25 16:21:29 -08:00
if ( psDroid - > droidType = = DROID_TRANSPORTER | | psDroid - > droidType = = DROID_SUPERTRANSPORTER )
2007-06-28 10:47:08 -07:00
{
2012-08-12 13:29:06 -07:00
moveUpdateDroidDirection ( psDroid , & speed , direction , DEG ( psPropStats - > spinAngle ) , spinSpeed , turnSpeed , & iDroidDir ) ;
2007-06-28 10:47:08 -07:00
}
else
{
2012-08-12 06:02:11 -07:00
iSpinSpeed = std : : max < int > ( psDroid - > baseSpeed * DEG ( 1 ) / 2 , spinSpeed ) ;
iTurnSpeed = std : : max < int > ( psDroid - > baseSpeed * DEG ( 1 ) / 8 , turnSpeed ) ;
2012-08-12 13:29:06 -07:00
moveUpdateDroidDirection ( psDroid , & speed , direction , DEG ( psPropStats - > spinAngle ) , iSpinSpeed , iTurnSpeed , & iDroidDir ) ;
2007-06-28 10:47:08 -07:00
}
2012-08-12 06:02:11 -07:00
fNormalSpeed = moveCalcNormalSpeed ( psDroid , speed , iDroidDir , psPropStats - > acceleration , psPropStats - > deceleration ) ;
fPerpSpeed = moveCalcPerpSpeed ( psDroid , iDroidDir , psPropStats - > skidDeceleration ) ;
2007-06-28 10:47:08 -07:00
2010-03-01 13:19:20 -08:00
moveCombineNormalAndPerpSpeeds ( psDroid , fNormalSpeed , fPerpSpeed , iDroidDir ) ;
2007-06-28 10:47:08 -07:00
moveGetDroidPosDiffs ( psDroid , & dx , & dy ) ;
2013-11-18 22:50:11 -08:00
/* set slide blocking tile for map edge */
if ( psDroid - > droidType ! = DROID_TRANSPORTER & & psDroid - > droidType ! = DROID_SUPERTRANSPORTER )
2007-06-28 10:47:08 -07:00
{
2010-03-01 13:19:20 -08:00
moveCalcBlockingSlide ( psDroid , & dx , & dy , direction , & slideDir ) ;
2007-06-28 10:47:08 -07:00
}
moveUpdateDroidPos ( psDroid , dx , dy ) ;
/* update vtol orientation */
2010-03-05 05:42:57 -08:00
targetRoll = clip ( 4 * angleDelta ( psDroid - > sMove . moveDir - psDroid - > rot . direction ) , - DEG ( 60 ) , DEG ( 60 ) ) ;
2010-03-05 01:06:07 -08:00
psDroid - > rot . roll = psDroid - > rot . roll + ( uint16_t ) gameTimeAdjustedIncrement ( 3 * angleDelta ( targetRoll - psDroid - > rot . roll ) ) ;
2007-06-28 10:47:08 -07:00
2011-04-11 09:26:28 -07:00
/* do vertical movement - only if on the map */
if ( worldOnMap ( psDroid - > pos . x , psDroid - > pos . y ) )
{
iMapZ = map_Height ( psDroid - > pos . x , psDroid - > pos . y ) ;
psDroid - > pos . z = MAX ( iMapZ , psDroid - > pos . z + gameTimeAdjustedIncrement ( psDroid - > sMove . iVertSpeed ) ) ;
moveAdjustVtolHeight ( psDroid , iMapZ ) ;
}
2007-06-28 10:47:08 -07:00
}
2010-03-01 05:50:53 -08:00
static void moveUpdateCyborgModel ( DROID * psDroid , SDWORD moveSpeed , uint16_t moveDir , UBYTE oldStatus )
2007-06-28 10:47:08 -07:00
{
2008-03-24 13:56:06 -07:00
CHECK_DROID ( psDroid ) ;
2007-06-28 10:47:08 -07:00
// nothing to do if the droid is stopped
2013-05-25 05:47:13 -07:00
if ( moveDroidStopped ( psDroid , moveSpeed ) = = true )
2007-06-28 10:47:08 -07:00
{
2013-05-25 05:47:13 -07:00
if ( psDroid - > psCurAnim ! = NULL )
2007-06-28 10:47:08 -07:00
{
2008-10-16 10:40:58 -07:00
if ( ! animObj_Remove ( psDroid - > psCurAnim , psDroid - > psCurAnim - > uwID ) )
2007-06-28 10:47:08 -07:00
{
2008-10-16 10:40:58 -07:00
debug ( LOG_NEVER , " couldn't remove walk anim " ) ;
2007-06-28 10:47:08 -07:00
}
psDroid - > psCurAnim = NULL ;
}
return ;
}
2013-05-25 05:47:13 -07:00
if ( psDroid - > psCurAnim = = NULL )
2007-06-28 10:47:08 -07:00
{
2013-05-25 05:47:13 -07:00
// Only add the animation if the droid is on screen, saves memory and time.
if ( clipXY ( psDroid - > pos . x , psDroid - > pos . y ) )
2007-06-28 10:47:08 -07:00
{
2013-05-25 05:47:13 -07:00
if ( psDroid - > droidType = = DROID_CYBORG_SUPER )
2007-06-28 10:47:08 -07:00
{
2013-05-25 05:47:13 -07:00
psDroid - > psCurAnim = animObj_Add ( psDroid , ID_ANIM_SUPERCYBORG_RUN , 0 , 0 ) ;
2007-06-28 10:47:08 -07:00
}
2013-05-25 05:47:13 -07:00
else if ( cyborgDroid ( psDroid ) )
2008-01-13 08:57:06 -08:00
{
2013-05-25 05:47:13 -07:00
psDroid - > psCurAnim = animObj_Add ( psDroid , ID_ANIM_CYBORG_RUN , 0 , 0 ) ;
2007-06-28 10:47:08 -07:00
}
}
}
2013-05-25 05:47:13 -07:00
// If the droid went off screen then remove the animation, saves memory and time
else if ( ! clipXY ( psDroid - > pos . x , psDroid - > pos . y ) )
2007-06-28 10:47:08 -07:00
{
2013-05-25 05:47:13 -07:00
const bool bRet = animObj_Remove ( psDroid - > psCurAnim , psDroid - > psCurAnim - > psAnim - > uwID ) ;
ASSERT ( bRet , " animObj_Remove failed " ) ;
psDroid - > psCurAnim = NULL ;
2007-06-28 10:47:08 -07:00
}
2013-05-25 05:47:13 -07:00
/* use baba person movement */
moveUpdatePersonModel ( psDroid , moveSpeed , moveDir ) ;
2010-02-28 15:14:52 -08:00
psDroid - > rot . pitch = 0 ;
psDroid - > rot . roll = 0 ;
2007-06-28 10:47:08 -07:00
}
2010-02-27 20:49:39 -08:00
static void moveDescending ( DROID * psDroid )
2007-06-28 10:47:08 -07:00
{
2010-08-15 11:42:40 -07:00
int32_t iMapHeight = map_Height ( psDroid - > pos . x , psDroid - > pos . y ) ;
2010-02-28 03:41:16 -08:00
psDroid - > sMove . speed = 0 ;
if ( psDroid - > pos . z > iMapHeight )
2007-06-28 10:47:08 -07:00
{
/* descending */
psDroid - > sMove . iVertSpeed = ( SWORD ) - VTOL_VERTICAL_SPEED ;
}
else
{
/* on floor - stop */
2010-02-28 03:41:16 -08:00
psDroid - > pos . z = iMapHeight ;
2007-06-28 10:47:08 -07:00
psDroid - > sMove . iVertSpeed = 0 ;
2010-02-28 03:41:16 -08:00
2010-02-27 20:49:39 -08:00
/* reset move state */
psDroid - > sMove . Status = MOVEINACTIVE ;
2007-06-28 10:47:08 -07:00
2010-02-27 20:49:39 -08:00
/* conform to terrain */
updateDroidOrientation ( psDroid ) ;
2007-06-28 10:47:08 -07:00
}
}
2011-03-12 17:32:15 -08:00
bool moveCheckDroidMovingAndVisible ( void * psObj )
2007-06-28 10:47:08 -07:00
{
2007-04-12 03:31:11 -07:00
DROID * psDroid = ( DROID * ) psObj ;
2007-06-28 10:47:08 -07:00
2007-04-12 03:31:11 -07:00
if ( psDroid = = NULL )
2007-06-28 10:47:08 -07:00
{
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
/* check for dead, not moving or invisible to player */
if ( psDroid - > died | | moveDroidStopped ( psDroid , 0 ) | |
2012-02-25 16:21:29 -08:00
( ( psDroid - > droidType = = DROID_TRANSPORTER | | psDroid - > droidType = = DROID_SUPERTRANSPORTER ) & & psDroid - > order . type = = DORDER_NONE ) | |
2008-11-15 06:28:04 -08:00
! ( psDroid - > visible [ selectedPlayer ] ) )
2007-06-28 10:47:08 -07:00
{
psDroid - > iAudioID = NO_SOUND ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
2007-04-12 03:31:11 -07:00
2008-03-24 09:51:17 -07:00
return true ;
2007-06-28 10:47:08 -07:00
}
2007-03-16 13:23:35 -07:00
static void movePlayDroidMoveAudio ( DROID * psDroid )
2007-06-28 10:47:08 -07:00
{
SDWORD iAudioID = NO_SOUND ;
PROPULSION_TYPES * psPropType ;
UBYTE iPropType = 0 ;
2007-04-03 06:20:41 -07:00
ASSERT ( psDroid ! = NULL ,
2006-08-23 05:58:48 -07:00
" movePlayUnitMoveAudio: unit pointer invalid \n " ) ;
2007-06-28 10:47:08 -07:00
if ( ( psDroid ! = NULL ) & &
2008-11-15 06:28:04 -08:00
( psDroid - > visible [ selectedPlayer ] ) )
2007-06-28 10:47:08 -07:00
{
2013-05-09 04:24:19 -07:00
iPropType = asPropulsionStats [ ( psDroid ) - > asBits [ COMP_PROPULSION ] ] . propulsionType ;
2007-06-28 10:47:08 -07:00
psPropType = & asPropulsionTypes [ iPropType ] ;
/* play specific wheeled and transporter or stats-specified noises */
2008-07-10 10:59:35 -07:00
if ( iPropType = = PROPULSION_TYPE_WHEELED & & psDroid - > droidType ! = DROID_CONSTRUCT )
2007-06-28 10:47:08 -07:00
{
iAudioID = ID_SOUND_TREAD ;
}
2012-02-25 16:21:29 -08:00
else if ( psDroid - > droidType = = DROID_TRANSPORTER | | psDroid - > droidType = = DROID_SUPERTRANSPORTER )
2007-06-28 10:47:08 -07:00
{
iAudioID = ID_SOUND_BLIMP_FLIGHT ;
}
2008-07-10 10:59:35 -07:00
else if ( iPropType = = PROPULSION_TYPE_LEGGED & & cyborgDroid ( psDroid ) )
2007-06-28 10:47:08 -07:00
{
iAudioID = ID_SOUND_CYBORG_MOVE ;
}
else
{
iAudioID = psPropType - > moveID ;
}
if ( iAudioID ! = NO_SOUND )
{
if ( audio_PlayObjDynamicTrack ( psDroid , iAudioID ,
moveCheckDroidMovingAndVisible ) )
{
psDroid - > iAudioID = iAudioID ;
}
}
}
}
2011-03-12 17:32:15 -08:00
static bool moveDroidStartCallback ( void * psObj )
2007-06-28 10:47:08 -07:00
{
2007-04-12 03:31:11 -07:00
DROID * psDroid = ( DROID * ) psObj ;
2007-06-28 10:47:08 -07:00
2007-04-12 03:31:11 -07:00
if ( psDroid = = NULL )
2007-06-28 10:47:08 -07:00
{
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
2006-05-27 09:37:17 -07:00
2007-04-12 03:31:11 -07:00
movePlayDroidMoveAudio ( psDroid ) ;
2007-06-28 10:47:08 -07:00
2008-03-24 09:51:17 -07:00
return true ;
2007-06-28 10:47:08 -07:00
}
2011-03-12 17:32:15 -08:00
static void movePlayAudio ( DROID * psDroid , bool bStarted , bool bStoppedBefore , SDWORD iMoveSpeed )
2007-06-28 10:47:08 -07:00
{
UBYTE propType ;
PROPULSION_STATS * psPropStats ;
PROPULSION_TYPES * psPropType ;
2011-03-12 17:32:15 -08:00
bool bStoppedNow ;
2007-06-28 10:47:08 -07:00
SDWORD iAudioID = NO_SOUND ;
AUDIO_CALLBACK pAudioCallback = NULL ;
/* get prop stats */
2013-05-09 04:24:19 -07:00
psPropStats = asPropulsionStats + psDroid - > asBits [ COMP_PROPULSION ] ;
2007-04-03 06:20:41 -07:00
ASSERT ( psPropStats ! = NULL ,
2006-08-23 05:58:48 -07:00
" moveUpdateUnit: invalid propulsion stats pointer " ) ;
2007-06-28 10:47:08 -07:00
propType = psPropStats - > propulsionType ;
psPropType = & asPropulsionTypes [ propType ] ;
/* get current droid motion status */
bStoppedNow = moveDroidStopped ( psDroid , iMoveSpeed ) ;
if ( bStarted )
{
/* play start audio */
2008-07-10 10:59:35 -07:00
if ( ( propType = = PROPULSION_TYPE_WHEELED & & psDroid - > droidType ! = DROID_CONSTRUCT )
2008-01-13 08:57:06 -08:00
| | psPropType - > startID = = NO_SOUND )
2007-06-28 10:47:08 -07:00
{
movePlayDroidMoveAudio ( psDroid ) ;
return ;
}
2012-02-25 16:21:29 -08:00
else if ( psDroid - > droidType = = DROID_TRANSPORTER | | psDroid - > droidType = = DROID_SUPERTRANSPORTER )
2007-06-28 10:47:08 -07:00
{
iAudioID = ID_SOUND_BLIMP_TAKE_OFF ;
}
else
{
iAudioID = psPropType - > startID ;
}
pAudioCallback = moveDroidStartCallback ;
}
else if ( ! bStoppedBefore & & bStoppedNow & &
( psPropType - > shutDownID ! = NO_SOUND ) )
{
/* play stop audio */
2012-02-25 16:21:29 -08:00
if ( psDroid - > droidType = = DROID_TRANSPORTER | | psDroid - > droidType = = DROID_SUPERTRANSPORTER )
2007-06-28 10:47:08 -07:00
{
iAudioID = ID_SOUND_BLIMP_LAND ;
}
2008-07-10 10:59:35 -07:00
else if ( propType ! = PROPULSION_TYPE_WHEELED | | psDroid - > droidType = = DROID_CONSTRUCT )
2007-06-28 10:47:08 -07:00
{
iAudioID = psPropType - > shutDownID ;
}
}
2008-01-13 08:57:06 -08:00
else if ( ! bStoppedBefore & & ! bStoppedNow & & psDroid - > iAudioID = = NO_SOUND )
2007-06-28 10:47:08 -07:00
{
/* play move audio */
movePlayDroidMoveAudio ( psDroid ) ;
return ;
}
if ( ( iAudioID ! = NO_SOUND ) & &
2008-11-15 06:28:04 -08:00
( psDroid - > visible [ selectedPlayer ] ) )
2007-06-28 10:47:08 -07:00
{
if ( audio_PlayObjDynamicTrack ( psDroid , iAudioID ,
pAudioCallback ) )
{
psDroid - > iAudioID = iAudioID ;
}
}
}
2010-12-08 08:29:39 -08:00
static bool pickupOilDrum ( int toPlayer , int fromPlayer )
{
addPower ( toPlayer , OILDRUM_POWER ) ; // give power
if ( toPlayer = = selectedPlayer )
{
CONPRINTF ( ConsoleString , ( ConsoleString , _ ( " You found %u power in an oil drum. " ) , OILDRUM_POWER ) ) ;
}
return true ;
}
2007-06-28 10:47:08 -07:00
// called when a droid moves to a new tile.
// use to pick up oil, etc..
static void checkLocalFeatures ( DROID * psDroid )
{
2009-02-27 19:36:26 -08:00
// NOTE: Why not do this for AI units also?
2012-03-10 22:19:46 -08:00
if ( ( ! isHumanPlayer ( psDroid - > player ) & & psDroid - > order . type ! = DORDER_RECOVER ) | | isVtolDroid ( psDroid ) ) // VTOLs can't pick up features!
2007-06-28 10:47:08 -07:00
{
return ;
}
2006-05-27 09:37:17 -07:00
// scan the neighbours
2010-01-16 14:51:26 -08:00
# define DROIDDIST ((TILE_UNITS*5) / 2)
2013-02-09 03:33:00 -08:00
static GridList gridList ; // static to avoid allocations.
gridList = gridStartIterate ( psDroid - > pos . x , psDroid - > pos . y , DROIDDIST ) ;
for ( GridIterator gi = gridList . begin ( ) ; gi ! = gridList . end ( ) ; + + gi )
2007-06-28 10:47:08 -07:00
{
2013-02-09 03:33:00 -08:00
BASE_OBJECT * psObj = * gi ;
2010-12-08 08:29:39 -08:00
bool pickedUp = false ;
if ( psObj - > type = = OBJ_FEATURE & & ! psObj - > died )
{
switch ( ( ( FEATURE * ) psObj ) - > psStats - > subType )
{
case FEAT_OIL_DRUM :
pickedUp = pickupOilDrum ( psDroid - > player , psObj - > player ) ;
2012-06-02 10:35:02 -07:00
triggerEventPickup ( ( FEATURE * ) psObj , psDroid ) ;
2010-12-08 08:29:39 -08:00
break ;
case FEAT_GEN_ARTE :
pickedUp = pickupArtefact ( psDroid - > player , psObj - > player ) ;
2012-06-02 10:35:02 -07:00
triggerEventPickup ( ( FEATURE * ) psObj , psDroid ) ;
2010-12-08 08:29:39 -08:00
break ;
default :
break ;
}
}
if ( ! pickedUp )
2007-06-28 10:47:08 -07:00
{
2010-12-08 08:29:39 -08:00
// Object is not a living oil drum or artefact.
2007-06-28 10:47:08 -07:00
continue ;
}
2010-11-02 15:27:46 -07:00
turnOffMultiMsg ( true ) ;
removeFeature ( ( FEATURE * ) psObj ) ; // remove artifact+.
turnOffMultiMsg ( false ) ;
2009-02-27 19:36:26 -08:00
}
2007-06-28 10:47:08 -07:00
}
/* Frame update for the movement of a tracked droid */
void moveUpdateDroid ( DROID * psDroid )
{
2010-01-24 07:17:05 -08:00
UDWORD oldx , oldy ;
2007-06-28 10:47:08 -07:00
UBYTE oldStatus = psDroid - > sMove . Status ;
2007-04-27 03:21:17 -07:00
SDWORD moveSpeed ;
2010-02-28 15:14:52 -08:00
uint16_t moveDir ;
2007-06-28 10:47:08 -07:00
PROPULSION_STATS * psPropStats ;
2010-01-24 07:17:05 -08:00
Vector3i pos ;
2011-03-12 17:32:15 -08:00
bool bStarted = false , bStopped ;
2007-06-28 10:47:08 -07:00
2008-03-24 07:21:08 -07:00
CHECK_DROID ( psDroid ) ;
2007-06-28 10:47:08 -07:00
2013-05-09 04:24:19 -07:00
psPropStats = asPropulsionStats + psDroid - > asBits [ COMP_PROPULSION ] ;
2009-08-24 09:23:34 -07:00
ASSERT_OR_RETURN ( , psPropStats ! = NULL , " Invalid propulsion stats pointer " ) ;
2007-06-28 10:47:08 -07:00
2008-03-24 13:56:06 -07:00
// If the droid has been attacked by an EMP weapon, it is temporarily disabled
if ( psDroid - > lastHitWeapon = = WSC_EMP )
{
if ( gameTime - psDroid - > timeLastHit < EMP_DISABLE_TIME )
{
// Get out without updating
return ;
}
}
2007-06-28 10:47:08 -07:00
/* save current motion status of droid */
bStopped = moveDroidStopped ( psDroid , 0 ) ;
moveSpeed = 0 ;
2010-02-28 15:14:52 -08:00
moveDir = psDroid - > rot . direction ;
2007-06-28 10:47:08 -07:00
switch ( psDroid - > sMove . Status )
{
case MOVEINACTIVE :
if ( ( psDroid - > droidType = = DROID_PERSON ) & &
( psDroid - > psCurAnim ! = NULL ) & &
( psDroid - > psCurAnim - > psAnim - > uwID = = ID_ANIM_DROIDRUN ) )
{
2008-03-24 09:51:17 -07:00
psDroid - > psCurAnim - > bVisible = false ;
2007-06-28 10:47:08 -07:00
}
break ;
case MOVESHUFFLE :
2010-02-09 14:35:23 -08:00
if ( moveReachedWayPoint ( psDroid ) | | ( psDroid - > sMove . shuffleStart + MOVE_SHUFFLETIME ) < gameTime )
2007-06-28 10:47:08 -07:00
{
2010-02-09 14:35:23 -08:00
if ( psPropStats - > propulsionType = = PROPULSION_TYPE_LIFT )
2007-06-28 10:47:08 -07:00
{
2010-02-09 14:35:23 -08:00
psDroid - > sMove . Status = MOVEHOVER ;
2007-06-28 10:47:08 -07:00
}
else
{
2010-02-09 14:35:23 -08:00
psDroid - > sMove . Status = MOVEINACTIVE ;
2007-06-28 10:47:08 -07:00
}
}
2010-02-09 14:35:23 -08:00
else
{
// Calculate a target vector
2010-03-01 12:39:26 -08:00
moveDir = moveGetDirection ( psDroid ) ;
2007-06-28 10:47:08 -07:00
2010-02-09 14:35:23 -08:00
moveSpeed = moveCalcDroidSpeed ( psDroid ) ;
}
2007-06-28 10:47:08 -07:00
break ;
case MOVEWAITROUTE :
2011-01-07 15:20:12 -08:00
moveDroidTo ( psDroid , psDroid - > sMove . destination . x , psDroid - > sMove . destination . y ) ;
2010-07-18 05:13:18 -07:00
moveSpeed = MAX ( 0 , psDroid - > sMove . speed - 1 ) ;
2012-03-04 08:52:17 -08:00
if ( psDroid - > sMove . Status ! = MOVENAVIGATE )
{
break ;
}
// No break.
2007-06-28 10:47:08 -07:00
case MOVENAVIGATE :
// Get the next control point
if ( ! moveNextTarget ( psDroid ) )
{
// No more waypoints - finish
2008-07-10 10:59:35 -07:00
if ( psPropStats - > propulsionType = = PROPULSION_TYPE_LIFT )
2007-06-28 10:47:08 -07:00
{
psDroid - > sMove . Status = MOVEHOVER ;
}
else
{
psDroid - > sMove . Status = MOVEINACTIVE ;
}
break ;
}
2008-07-07 03:15:00 -07:00
if ( isVtolDroid ( psDroid ) )
2007-06-28 10:47:08 -07:00
{
2010-02-28 15:14:52 -08:00
psDroid - > rot . pitch = 0 ;
2007-06-28 10:47:08 -07:00
}
psDroid - > sMove . Status = MOVEPOINTTOPOINT ;
psDroid - > sMove . bumpTime = 0 ;
2010-07-18 05:13:18 -07:00
moveSpeed = MAX ( 0 , psDroid - > sMove . speed - 1 ) ;
2007-06-28 10:47:08 -07:00
/* save started status for movePlayAudio */
2007-07-14 03:59:04 -07:00
if ( psDroid - > sMove . speed = = 0 )
2007-06-28 10:47:08 -07:00
{
2008-03-24 09:51:17 -07:00
bStarted = true ;
2007-06-28 10:47:08 -07:00
}
2012-03-04 08:52:17 -08:00
// No break.
2007-06-28 10:47:08 -07:00
case MOVEPOINTTOPOINT :
case MOVEPAUSE :
// moving between two way points
2010-10-31 00:55:02 -07:00
if ( psDroid - > sMove . numPoints = = 0 )
{
debug ( LOG_WARNING , " No path to follow, but psDroid->sMove.Status = %d " , psDroid - > sMove . Status ) ;
}
else
{
ASSERT_OR_RETURN ( , psDroid - > sMove . asPath ! = NULL , " NULL path of non-zero length! " ) ;
}
2007-06-28 10:47:08 -07:00
2010-10-17 14:36:48 -07:00
// Get the best control point.
2010-10-31 00:55:02 -07:00
if ( psDroid - > sMove . numPoints = = 0 | | ! moveBestTarget ( psDroid ) )
2010-10-17 14:36:48 -07:00
{
// Got stuck somewhere, can't find the path.
2011-01-07 15:20:12 -08:00
moveDroidTo ( psDroid , psDroid - > sMove . destination . x , psDroid - > sMove . destination . y ) ;
2010-10-17 14:36:48 -07:00
}
2007-06-28 10:47:08 -07:00
// See if the target point has been reached
if ( moveReachedWayPoint ( psDroid ) )
{
// Got there - move onto the next waypoint
if ( ! moveNextTarget ( psDroid ) )
{
// No more waypoints - finish
2008-07-10 10:59:35 -07:00
if ( psPropStats - > propulsionType = = PROPULSION_TYPE_LIFT )
2007-06-28 10:47:08 -07:00
{
2012-02-28 01:29:39 -08:00
// check the location for vtols
Vector2i tar = removeZ ( psDroid - > pos ) ;
if ( psDroid - > order . type ! = DORDER_PATROL & & psDroid - > order . type ! = DORDER_CIRCLE // Not doing an order which means we never land (which means we might want to land).
2012-03-13 09:02:38 -07:00
& & psDroid - > action ! = DACTION_MOVETOREARM & & psDroid - > action ! = DACTION_MOVETOREARMPOINT
2012-02-28 01:29:39 -08:00
& & actionVTOLLandingPos ( psDroid , & tar ) // Can find a sensible place to land.
& & map_coord ( tar ) ! = map_coord ( psDroid - > sMove . destination ) ) // We're not at the right place to land.
{
psDroid - > sMove . destination = tar ;
moveDroidTo ( psDroid , psDroid - > sMove . destination . x , psDroid - > sMove . destination . y ) ;
}
else
{
psDroid - > sMove . Status = MOVEHOVER ;
}
2007-06-28 10:47:08 -07:00
}
else
{
psDroid - > sMove . Status = MOVETURN ;
}
2010-03-02 10:26:06 -08:00
objTrace ( psDroid - > id , " Arrived at destination! " ) ;
2007-06-28 10:47:08 -07:00
break ;
}
}
2010-03-01 12:39:26 -08:00
moveDir = moveGetDirection ( psDroid ) ;
2007-06-28 10:47:08 -07:00
moveSpeed = moveCalcDroidSpeed ( psDroid ) ;
2006-05-27 09:37:17 -07:00
2007-06-28 10:47:08 -07:00
if ( ( psDroid - > sMove . bumpTime ! = 0 ) & &
( psDroid - > sMove . pauseTime + psDroid - > sMove . bumpTime + BLOCK_PAUSETIME < gameTime ) )
{
if ( psDroid - > sMove . Status = = MOVEPOINTTOPOINT )
{
psDroid - > sMove . Status = MOVEPAUSE ;
}
else
{
psDroid - > sMove . Status = MOVEPOINTTOPOINT ;
}
psDroid - > sMove . pauseTime = ( UWORD ) ( gameTime - psDroid - > sMove . bumpTime ) ;
}
if ( ( psDroid - > sMove . Status = = MOVEPAUSE ) & &
( psDroid - > sMove . bumpTime ! = 0 ) & &
( psDroid - > sMove . lastBump > psDroid - > sMove . pauseTime ) & &
( psDroid - > sMove . lastBump + psDroid - > sMove . bumpTime + BLOCK_PAUSERELEASE < gameTime ) )
{
psDroid - > sMove . Status = MOVEPOINTTOPOINT ;
}
break ;
case MOVETURN :
// Turn the droid to it's final facing
2010-10-16 11:49:52 -07:00
if ( psPropStats - > propulsionType = = PROPULSION_TYPE_LIFT )
2007-06-28 10:47:08 -07:00
{
2010-10-16 11:49:52 -07:00
psDroid - > sMove . Status = MOVEPOINTTOPOINT ;
2007-06-28 10:47:08 -07:00
}
else
{
2010-10-16 11:49:52 -07:00
psDroid - > sMove . Status = MOVEINACTIVE ;
2007-06-28 10:47:08 -07:00
}
break ;
case MOVETURNTOTARGET :
moveSpeed = 0 ;
2011-01-07 15:20:12 -08:00
moveDir = iAtan2 ( psDroid - > sMove . target - removeZ ( psDroid - > pos ) ) ;
2007-06-28 10:47:08 -07:00
break ;
case MOVEHOVER :
2010-02-27 20:49:39 -08:00
moveDescending ( psDroid ) ;
2007-06-28 10:47:08 -07:00
break ;
2009-03-11 07:19:46 -07:00
// Driven around by the player.
2007-06-28 10:47:08 -07:00
case MOVEDRIVE :
driveSetDroidMove ( psDroid ) ;
2007-12-24 05:57:19 -08:00
moveSpeed = driveGetMoveSpeed ( ) ; //psDroid->sMove.speed;
2010-02-28 15:14:52 -08:00
moveDir = DEG ( driveGetMoveDir ( ) ) ; //psDroid->sMove.dir;
2007-06-28 10:47:08 -07:00
break ;
default :
2008-03-24 09:51:17 -07:00
ASSERT ( false , " moveUpdateUnit: unknown move state " ) ;
2007-06-28 10:47:08 -07:00
break ;
}
// Update the movement model for the droid
2007-12-15 07:39:29 -08:00
oldx = psDroid - > pos . x ;
oldy = psDroid - > pos . y ;
2007-06-28 10:47:08 -07:00
if ( psDroid - > droidType = = DROID_PERSON )
{
2010-03-01 05:50:53 -08:00
moveUpdatePersonModel ( psDroid , moveSpeed , moveDir ) ;
2007-06-28 10:47:08 -07:00
}
2007-07-13 13:58:37 -07:00
else if ( cyborgDroid ( psDroid ) )
2007-06-28 10:47:08 -07:00
{
2010-03-01 05:50:53 -08:00
moveUpdateCyborgModel ( psDroid , moveSpeed , moveDir , oldStatus ) ;
2007-06-28 10:47:08 -07:00
}
2008-07-10 10:59:35 -07:00
else if ( psPropStats - > propulsionType = = PROPULSION_TYPE_LIFT )
2007-06-28 10:47:08 -07:00
{
2010-03-01 05:50:53 -08:00
moveUpdateVtolModel ( psDroid , moveSpeed , moveDir ) ;
2007-06-28 10:47:08 -07:00
}
else
{
2010-03-01 05:50:53 -08:00
moveUpdateGroundModel ( psDroid , moveSpeed , moveDir ) ;
2007-06-28 10:47:08 -07:00
}
2007-12-15 07:39:29 -08:00
if ( map_coord ( oldx ) ! = map_coord ( psDroid - > pos . x )
| | map_coord ( oldy ) ! = map_coord ( psDroid - > pos . y ) )
2007-06-28 10:47:08 -07:00
{
2010-01-28 05:10:42 -08:00
visTilesUpdate ( ( BASE_OBJECT * ) psDroid ) ;
2007-06-28 10:47:08 -07:00
// object moved from one tile to next, check to see if droid is near stuff.(oil)
checkLocalFeatures ( psDroid ) ;
2012-12-01 14:38:04 -08:00
triggerEventDroidMoved ( psDroid , oldx , oldy ) ;
2007-06-28 10:47:08 -07:00
}
// See if it's got blocked
2008-07-10 10:59:35 -07:00
if ( ( psPropStats - > propulsionType ! = PROPULSION_TYPE_LIFT ) & & moveBlocked ( psDroid ) )
2007-06-28 10:47:08 -07:00
{
2008-05-11 07:58:20 -07:00
objTrace ( psDroid - > id , " status: id %d blocked " , ( int ) psDroid - > id ) ;
2007-06-28 10:47:08 -07:00
psDroid - > sMove . Status = MOVETURN ;
}
// // If were in drive mode and the droid is a follower then stop it when it gets within
// // range of the driver.
// if(driveIsFollower(psDroid)) {
// if(DoFollowRangeCheck) {
// if(driveInDriverRange(psDroid)) {
// psDroid->sMove.Status = MOVEINACTIVE;
2008-03-24 09:51:17 -07:00
//// ClearFollowRangeCheck = true;
2007-06-28 10:47:08 -07:00
// } else {
2008-03-24 09:51:17 -07:00
// AllInRange = false;
2007-06-28 10:47:08 -07:00
// }
// }
// }
/* If it's sitting in water then it's got to go with the flow! */
2009-10-31 12:29:56 -07:00
if ( worldOnMap ( psDroid - > pos . x , psDroid - > pos . y ) & & terrainType ( mapTile ( map_coord ( psDroid - > pos . x ) , map_coord ( psDroid - > pos . y ) ) ) = = TER_WATER )
2007-06-28 10:47:08 -07:00
{
2006-05-27 09:37:17 -07:00
updateDroidOrientation ( psDroid ) ;
2007-06-28 10:47:08 -07:00
}
2011-02-03 15:20:46 -08:00
if ( psDroid - > sMove . Status = = MOVETURNTOTARGET & & psDroid - > rot . direction = = moveDir )
{
if ( psPropStats - > propulsionType = = PROPULSION_TYPE_LIFT )
{
psDroid - > sMove . Status = MOVEPOINTTOPOINT ;
}
else
{
psDroid - > sMove . Status = MOVEINACTIVE ;
}
objTrace ( psDroid - > id , " MOVETURNTOTARGET complete " ) ;
}
2013-01-27 06:10:56 -08:00
if ( psDroid - > periodicalDamageStart ! = 0 & & psDroid - > droidType ! = DROID_PERSON & & psDroid - > visible [ selectedPlayer ] )
2007-06-28 10:47:08 -07:00
{
2007-12-15 07:39:29 -08:00
pos . x = psDroid - > pos . x + ( 18 - rand ( ) % 36 ) ;
pos . z = psDroid - > pos . y + ( 18 - rand ( ) % 36 ) ;
2007-12-21 09:34:23 -08:00
pos . y = psDroid - > pos . z + ( psDroid - > sDisplay . imd - > max . y / 3 ) ;
2012-02-24 00:12:21 -08:00
addEffect ( & pos , EFFECT_EXPLOSION , EXPLOSION_TYPE_SMALL , false , NULL , 0 , gameTime - deltaGameTime + 1 ) ;
2007-06-28 10:47:08 -07:00
}
movePlayAudio ( psDroid , bStarted , bStopped , moveSpeed ) ;
2009-10-31 12:29:56 -07:00
ASSERT ( droidOnMap ( psDroid ) , " %s moved off map (%u, %u)->(%u, %u) " , droidGetName ( psDroid ) , oldx , oldy , ( UDWORD ) psDroid - > pos . x , ( UDWORD ) psDroid - > pos . y ) ;
2008-03-24 07:21:08 -07:00
CHECK_DROID ( psDroid ) ;
2007-06-28 10:47:08 -07:00
}