Files
source/Tactical/Vehicles.cpp
T
Wanne 6e2bdd557c ****************************************************************************
** Merged Source Code from Development trunk, for the Spring 2011 Release **
****************************************************************************
o Development Trunk (Revision: 4444):  https://81.169.133.124/source/ja2/branches/Wanne/JA2%201.13%20MP
o This trunk (the official 1.13 source trunk) will only be used for fixing bugs. No new features will be added here.
  New Features are only included in the Development trunk
o !!! After we have fixed a bug here in this trunk, we should MANUALLY merge the bugfix in the development trunk !!!

git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@4446 3b4a5df2-a311-0410-b5c6-a8a6f20db521
2011-05-26 11:04:47 +00:00

2612 lines
67 KiB
C++

#ifdef PRECOMPILEDHEADERS
#include "Tactical All.h"
#else
#include "Vehicles.h"
#include "String.h"
#include "Strategic Pathing.h"
#include "Assignments.h"
#include "Strategic Movement.h"
#include "Squads.h"
#include "Map Screen Helicopter.h"
#include "Game Clock.h"
#include "overhead.h"
#include "soldier profile.h"
#include "Sound Control.h"
#include "soundman.h"
#include "soldier add.h"
#include "interface panels.h"
#include "strategic.h"
#include "worlddef.h"
#include "tile animation.h"
#include "Isometric Utils.h"
#include "Mapscreen.h"
#include "message.h"
#include "interface.h"
#include "Random.h"
#include "text.h"
#include "explosion control.h"
#include "soldier create.h"
#include "animation control.h"
#include "strategicmap.h"
#include "Interface Control.h"
#include "Campaign Types.h"
#include "Map Screen Interface.h"
#include "jascreens.h"
#include "screenids.h"
#include "Quests.h"
#include "Tactical Save.h"
#include "Soldier macros.h"
#include "opplist.h"
#include "Soldier ani.h"
#include "GameSettings.h"
#include "Queen Command.h"
#endif
//INT8 gubVehicleMovementGroups[ MAX_VEHICLES ];
std::vector<INT8> gubVehicleMovementGroups (MAX_VEHICLES, 0);
// the list of vehicles
VEHICLETYPE *pVehicleList = NULL;
// number of vehicle slots on the list
UINT8 ubNumberOfVehicles = 0;
// the sqaud mvt groups
extern INT8 SquadMovementGroups[ ];
//ATE: These arrays below should all be in a large LUT which contains
// static info for each vehicle....
// the mvt groups associated with vehcile types
INT32 iMvtTypes[]={
CAR, // eldorado
CAR, // hummer
CAR, // ice cream truck
CAR, // jeep
CAR, // tank
AIR, // helicopter
};
INT32 iSeatingCapacities[]={
6, // eldorado
6, // hummer
6, // ice cream truck
6, // jeep
6, // tank
6, // helicopter
};
INT32 iEnterVehicleSndID[] = {
S_VECH1_INTO,
S_VECH1_INTO,
S_VECH1_INTO,
S_VECH1_INTO,
S_VECH1_INTO,
S_VECH1_INTO,
};
INT32 iMoveVehicleSndID[] = {
S_VECH1_MOVE,
S_VECH1_MOVE,
S_VECH1_MOVE,
S_VECH1_MOVE,
S_VECH1_MOVE,
S_VECH1_MOVE,
};
UINT8 ubVehicleTypeProfileID[ ] = {
PROF_ELDERODO,
PROF_HUMMER,
PROF_ICECREAM,
NPC164,
NPC164,
PROF_HELICOPTER
};
/*
// location of crits based on facing
INT8 bInternalCritHitsByLocation[ NUMBER_OF_EXTERNAL_HIT_LOCATIONS_ON_VEHICLE ][ NUMBER_OF_INTERNAL_HIT_LOCATIONS_IN_VEHICLE ]={
{ ENGINE_HIT_LOCATION, ENGINE_HIT_LOCATION, CREW_COMPARTMENT_HIT_LOCATION,CREW_COMPARTMENT_HIT_LOCATION, RF_TIRE_HIT_LOCATION, LF_TIRE_HIT_LOCATION }, // front
{ ENGINE_HIT_LOCATION, LF_TIRE_HIT_LOCATION, CREW_COMPARTMENT_HIT_LOCATION, CREW_COMPARTMENT_HIT_LOCATION, LR_TIRE_HIT_LOCATION, GAS_TANK_HIT_LOCATION}, // left side
{ ENGINE_HIT_LOCATION, RF_TIRE_HIT_LOCATION, CREW_COMPARTMENT_HIT_LOCATION, CREW_COMPARTMENT_HIT_LOCATION, RR_TIRE_HIT_LOCATION, GAS_TANK_HIT_LOCATION}, // right side
{ CREW_COMPARTMENT_HIT_LOCATION, CREW_COMPARTMENT_HIT_LOCATION, CREW_COMPARTMENT_HIT_LOCATION, RR_TIRE_HIT_LOCATION, LR_TIRE_HIT_LOCATION, GAS_TANK_HIT_LOCATION }, // rear
{ ENGINE_HIT_LOCATION, RF_TIRE_HIT_LOCATION, LF_TIRE_HIT_LOCATION, RR_TIRE_HIT_LOCATION,LR_TIRE_HIT_LOCATION, GAS_TANK_HIT_LOCATION,}, // bottom side
{ ENGINE_HIT_LOCATION, ENGINE_HIT_LOCATION, ENGINE_HIT_LOCATION, CREW_COMPARTMENT_HIT_LOCATION, CREW_COMPARTMENT_HIT_LOCATION, GAS_TANK_HIT_LOCATION }, // top
};
*/
// original armor values for vehicles
/*
ELDORADO_CAR = 0,
HUMMER,
ICE_CREAM_TRUCK,
JEEP_CAR,
TANK_CAR,
HELICOPTER,
*/
INT16 sVehicleArmourType[ NUMBER_OF_TYPES_OF_VEHICLES ] =
{
KEVLAR_VEST, // El Dorado
SPECTRA_VEST, // Hummer
KEVLAR_VEST, // Ice cream truck
KEVLAR_VEST, // Jeep
SPECTRA_VEST, // Tank - do we want this?
KEVLAR_VEST, // Helicopter
};
/*
INT16 sVehicleExternalOrigArmorValues[ NUMBER_OF_TYPES_OF_VEHICLES ][ NUMBER_OF_INTERNAL_HIT_LOCATIONS_IN_VEHICLE ]={
{ 100,100,100,100,100,100 }, // helicopter
{ 500,500,500,500,500,500 }, // hummer
};
*/
/*
// external armor values
INT16 sVehicleInternalOrigArmorValues[ NUMBER_OF_TYPES_OF_VEHICLES ][ NUMBER_OF_INTERNAL_HIT_LOCATIONS_IN_VEHICLE ]={
{ 250,250,250,250,250,250 }, // eldorado
{ 250,250,250,250,250,250 }, // hummer
{ 250,250,250,250,250,250 }, // ice cream
{ 250,250,250,250,250,250 }, // feep
{ 850,850,850,850,850,850 }, // tank
{ 50,50,50,50,50,50 }, // helicopter
};
*/
// ap cost per crit
#define COST_PER_ENGINE_CRIT 15
#define COST_PER_TIRE_HIT 5
//#define VEHICLE_MAX_INTERNAL 250
// set the driver of the vehicle
void SetDriver( INT32 iID, UINT8 ubID );
//void RemoveSoldierFromVehicleBetweenSectors( pSoldier, iId );
void TeleportVehicleToItsClosestSector( INT32 iVehicleId, UINT8 ubGroupID );
void InitAVehicle(int index, int x, int y) {
gubVehicleMovementGroups[ index ] = CreateNewVehicleGroupDepartingFromSector( x, y, index );
// Set persistent....
GROUP *pGroup = GetGroup( gubVehicleMovementGroups[ index ] );
AssertNotNIL(pGroup);
pGroup->fPersistant = TRUE;
}
// Loop through and create a few soldier squad ID's for vehicles
void InitAllVehicles( ) {
for( int cnt = 0; cnt < MAX_VEHICLES; cnt++ )
InitAVehicle(cnt, 1, 1);
}
void SetVehicleValuesIntoSoldierType( SOLDIERTYPE *pVehicle )
{
wcscpy( pVehicle->name, zVehicleName[ pVehicleList[ pVehicle->bVehicleID ].ubVehicleType ] );
pVehicle->ubProfile = pVehicleList[ pVehicle->bVehicleID ].ubProfileID;
// Init fuel!
pVehicle->sBreathRed = 10000;
pVehicle->bBreath = 100;
pVehicle->ubWhatKindOfMercAmI = MERC_TYPE__VEHICLE;
}
INT32 AddVehicleToList( INT16 sMapX, INT16 sMapY, INT32 sGridNo, UINT8 ubType )
{
// insert this vehicle into the list
// how many vehicles are there?
INT32 iVehicleIdValue = -1;
INT32 iCounter = 0, iCount = 0;
VEHICLETYPE *pTempList = NULL;
BOOLEAN fFoundEmpty = FALSE;
GROUP *pGroup;
if( pVehicleList != NULL )
{
// not the first, add to list
for( iCounter = 0; iCounter < ubNumberOfVehicles ; iCounter++ )
{
// might have an empty slot
if( pVehicleList[ iCounter ].fValid == FALSE )
{
iCount = iCounter;
iCounter = ubNumberOfVehicles;
fFoundEmpty = TRUE;
iVehicleIdValue = iCount;
}
}
}
if( fFoundEmpty == FALSE )
{
iCount = ubNumberOfVehicles;
}
if( iCount == 0 )
{
pVehicleList = (VEHICLETYPE *) MemAlloc( sizeof( VEHICLETYPE ) );
// Set!
memset( pVehicleList, 0, sizeof( VEHICLETYPE ) );
ubNumberOfVehicles = 1;
iVehicleIdValue = 0;
}
if( ( iVehicleIdValue == -1 ) && ( iCount != 0 ) && ( fFoundEmpty == FALSE ) )
{
// no empty slot found, need to realloc
pTempList = (VEHICLETYPE *) MemAlloc( sizeof( VEHICLETYPE ) * ubNumberOfVehicles );
// copy to temp
memcpy( pTempList, pVehicleList, sizeof( VEHICLETYPE ) * ubNumberOfVehicles );
// now realloc
pVehicleList = (VEHICLETYPE *) MemRealloc( pVehicleList, ( sizeof( VEHICLETYPE ) * ( ubNumberOfVehicles + 1 ) ) );
// memset the stuff
memset( pVehicleList, 0, ( sizeof( VEHICLETYPE ) * ( ubNumberOfVehicles + 1 ) ) );
// now copy the stuff back
memcpy( pVehicleList, pTempList, sizeof( VEHICLETYPE ) * ( ubNumberOfVehicles ) );
// now get rid of crap
MemFree( pTempList );
// now get the index value
iVehicleIdValue = ubNumberOfVehicles;
ubNumberOfVehicles++;
}
// found a slot
pVehicleList[ iCount ].ubMovementGroup = 0;
pVehicleList[ iCount ].sSectorX = sMapX;
pVehicleList[ iCount ].sSectorY = sMapY;
pVehicleList[ iCount ].sSectorZ = 0;
pVehicleList[ iCount ].sGridNo = sGridNo;
memset( pVehicleList[ iCount ].pPassengers, 0, 10 * sizeof( SOLDIERTYPE * ) );
pVehicleList[ iCount ].fValid = TRUE;
pVehicleList[ iCount ].ubVehicleType = ubType;
pVehicleList[ iCount ].pMercPath = NULL;
pVehicleList[ iCount ].fFunctional = TRUE;
pVehicleList[ iCount ].fDestroyed = FALSE;
pVehicleList[ iCount ].iMoveSound = iMoveVehicleSndID[ ubType ];
pVehicleList[ iCount ].iOutOfSound = iEnterVehicleSndID[ ubType ];
pVehicleList[ iCount ].ubProfileID = ubVehicleTypeProfileID[ ubType ];
pVehicleList[ iCount ].ubMovementGroup = gubVehicleMovementGroups[ iCount ];
// ATE: Add movement mask to group...
pGroup = GetGroup( pVehicleList[ iCount ].ubMovementGroup );
if( !pGroup )
{
// WANNE: Commented the following line, because we got a CTD when skyrider sees his heli in drassen!
//if( gfEditMode )
{
//This is okay, no groups exist, so simply return.
return iVehicleIdValue;
}
Assert( 0 );
}
// HEADROCK HAM 3.1: An INI setting allows us to turn the Hummer into a true offroad vehicle. It will use the
// "TRUCK" type movement, which allows it to go into mild non-road terrain. I wish I could come with a more
// subtle method than this crude override, but this is what I've got at the moment.
if (gGameExternalOptions.fHumveeOffroad && ubType == HUMMER)
{
pGroup->ubTransportationMask = TRUCK;
}
else
{
pGroup->ubTransportationMask = (UINT8)iMvtTypes[ ubType ];
}
// ARM: setup group movement defaults
pGroup->ubSectorX = ( UINT8 ) sMapX;
pGroup->ubNextX = ( UINT8 ) sMapX;
pGroup->ubSectorY = ( UINT8 ) sMapY;
pGroup->ubNextY = ( UINT8 ) sMapY;
pGroup->uiTraverseTime = 0;
pGroup->uiArrivalTime = 0;
SetUpArmorForVehicle( ( UINT8 )iCount );
return( iVehicleIdValue );
}
BOOLEAN RemoveVehicleFromList( INT32 iId )
{
// remove this vehicle from the list
// error check
if( ( iId >= ubNumberOfVehicles ) || ( iId < 0 ) )
{
return ( FALSE );
}
// clear remaining path nodes
if( pVehicleList[ iId ].pMercPath != NULL )
{
pVehicleList[ iId ].pMercPath = ClearStrategicPathList( pVehicleList[ iId ].pMercPath, 0 );
}
// zero out mem
memset( &( pVehicleList[ iId ] ), 0, sizeof( VEHICLETYPE ) );
return( TRUE );
}
void ClearOutVehicleList( void )
{
INT32 iCounter;
// empty out the vehicle list
if( pVehicleList )
{
for( iCounter = 0; iCounter < ubNumberOfVehicles ; iCounter++ )
{
// if there is a valid vehicle
if( pVehicleList[ iCounter ].fValid )
{
//if the vehicle has a valid path
if( pVehicleList[ iCounter ].pMercPath )
{
//toast the vehicle path
pVehicleList[ iCounter ].pMercPath = ClearStrategicPathList( pVehicleList[ iCounter ].pMercPath, 0 );
}
}
}
MemFree( pVehicleList );
pVehicleList = NULL;
ubNumberOfVehicles = 0;
}
/*
// empty out the vehicle list
if( pVehicleList )
{
MemFree( pVehicleList );
pVehicleList = NULL;
ubNumberOfVehicles = 0;
}
*/
}
BOOLEAN IsThisVehicleAccessibleToSoldier( SOLDIERTYPE *pSoldier, INT32 iId )
{
if( pSoldier == NULL )
{
return( FALSE );
}
if( ( iId >= ubNumberOfVehicles ) || ( iId < 0 ) )
{
return ( FALSE );
}
// now check if vehicle is valid
if( pVehicleList[ iId ].fValid == FALSE )
{
return( FALSE );
}
// if the soldier or the vehicle is between sectors
if( pSoldier->flags.fBetweenSectors || pVehicleList[ iId ].fBetweenSectors )
{
return( FALSE );
}
// any sector values off?
if( ( pSoldier->sSectorX != pVehicleList[ iId ].sSectorX ) ||
( pSoldier->sSectorY != pVehicleList[ iId ].sSectorY ) ||
( pSoldier->bSectorZ != pVehicleList[ iId ].sSectorZ ) )
{
return( FALSE );
}
// if vehicle is not ok to use then return false
if ( !OKUseVehicle( pVehicleList[ iId ].ubProfileID ) )
{
return( FALSE );
}
return( TRUE );
}
BOOLEAN AddSoldierToVehicle( SOLDIERTYPE *pSoldier, INT32 iId )
{
INT32 iCounter = 0;
UINT32 vCount = 0;
SOLDIERTYPE *pVehicleSoldier = NULL;
// Add Soldierto Vehicle
if( ( iId >= ubNumberOfVehicles ) || ( iId < 0 ) )
{
return ( FALSE );
}
// ok now check if any free slots in the vehicle
// now check if vehicle is valid
if( pVehicleList[ iId ].fValid == FALSE )
{
return( FALSE );
}
// get the vehicle soldiertype
pVehicleSoldier = GetSoldierStructureForVehicle( iId );
//CHRISL: Get number of vehicles currently in player team
for(int x = 0; x < giMAXIMUM_NUMBER_OF_PLAYER_SLOTS; x++)
{
if(MercPtrs[x]->bTeam == OUR_TEAM && (MercPtrs[x]->flags.uiStatusFlags & SOLDIER_VEHICLE) && MercPtrs[x]->bActive == TRUE)
vCount ++;
}
if( pVehicleSoldier )
{
if ( pVehicleSoldier->bTeam != gbPlayerNum )
{
// Can we add a new vehicle
if( vCount >= gGameExternalOptions.ubGameMaximumNumberOfPlayerVehicles )
{
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, TacticalStr[VEHICLE_CAN_NOT_BE_ADDED] );
return( FALSE );
}
// Change sides...
pVehicleSoldier = ChangeSoldierTeam( pVehicleSoldier, gbPlayerNum );
// add it to mapscreen list
fReBuildCharacterList = TRUE;
}
}
// If vehicle is empty, add to unique squad now that it has somebody in it!
if ( GetNumberInVehicle( iId ) == 0 && pVehicleSoldier )
{
// 2 ) Add to unique squad...
AddCharacterToUniqueSquad( pVehicleSoldier );
// ATE: OK funcky stuff here!
// We have now a guy on a squad group, remove him!
RemovePlayerFromGroup( SquadMovementGroups[ pVehicleSoldier->bAssignment ], pVehicleSoldier );
// I really have vehicles.\
// ONLY add to vehicle group once!
if ( !DoesPlayerExistInPGroup( pVehicleList[ iId ].ubMovementGroup, pVehicleSoldier ) )
{
//NOW.. add guy to vehicle group....
AddPlayerToGroup( pVehicleList[ iId ].ubMovementGroup, pVehicleSoldier );
}
else
{
pVehicleSoldier->ubGroupID = pVehicleList[ iId ].ubMovementGroup;
}
}
// check if the grunt is already here
for( iCounter = 0; iCounter < iSeatingCapacities[ pVehicleList[ iId ].ubVehicleType ]; iCounter++ )
{
if( pVehicleList[ iId ].pPassengers[ iCounter ] == pSoldier )
{
// guy found, no need to add
return( TRUE );
}
}
if ( pVehicleSoldier )
{
// can't call SelectSoldier in mapscreen, that will initialize interface panels!!!
if ( guiCurrentScreen == GAME_SCREEN )
{
SelectSoldier( pVehicleSoldier->ubID, FALSE, TRUE );
}
PlayJA2Sample( pVehicleList[ pVehicleSoldier->bVehicleID ].iOutOfSound, RATE_11025, SoundVolume( HIGHVOLUME, pVehicleSoldier->sGridNo ), 1, SoundDir( pVehicleSoldier->sGridNo ) );
}
for( iCounter = 0; iCounter < iSeatingCapacities[ pVehicleList[ iId ].ubVehicleType ]; iCounter++ )
{
// check if slot free
if( pVehicleList[ iId ].pPassengers[ iCounter ] == NULL )
{
// add person in
pVehicleList[ iId ].pPassengers[ iCounter ] = pSoldier;
if( pSoldier->bAssignment == VEHICLE )
{
TakeSoldierOutOfVehicle( pSoldier );
// NOTE: This will leave the soldier on a squad. Must be done PRIOR TO and in AS WELL AS the call
// to RemoveCharacterFromSquads() that's coming up, to permit direct vehicle->vehicle reassignment!
}
// if in a squad, remove from squad, if not, check if in vehicle, if so remove, if not, then check if in mvt group..if so, move and destroy group
if( pSoldier->bAssignment < ON_DUTY )
{
RemoveCharacterFromSquads( pSoldier );
}
else if( pSoldier->ubGroupID != 0 )
{
// destroy group and set to zero
RemoveGroup( pSoldier->ubGroupID );
pSoldier->ubGroupID = 0;
}
if( ( pSoldier->bAssignment != VEHICLE ) || ( pSoldier->iVehicleId != iId ) )
{
SetTimeOfAssignmentChangeForMerc( pSoldier );
}
// set thier assignment
ChangeSoldiersAssignment( pSoldier, VEHICLE );
// set vehicle id
pSoldier->iVehicleId = iId;
// if vehicle is part of mvt group, then add character to mvt group
if( pVehicleList[ iId ].ubMovementGroup != 0 )
{
// add character
AddPlayerToGroup( pVehicleList[ iId ].ubMovementGroup, pSoldier );
}
// Are we the first?
if ( GetNumberInVehicle( iId ) == 1 )
{
// Set as driver...
pSoldier->flags.uiStatusFlags |= SOLDIER_DRIVER;
SetDriver( iId , pSoldier->ubID );
}
else
{
// Set as driver...
pSoldier->flags.uiStatusFlags |= SOLDIER_PASSENGER;
}
// Remove soldier's graphic
pSoldier->RemoveSoldierFromGridNo( );
if ( pVehicleSoldier )
{
// Set gridno for vehicle.....
pSoldier->EVENT_SetSoldierPosition( pVehicleSoldier->dXPos, pVehicleSoldier->dYPos );
// Stop from any movement.....
pSoldier->EVENT_StopMerc( pSoldier->sGridNo, pSoldier->ubDirection );
// can't call SetCurrentSquad OR SelectSoldier in mapscreen, that will initialize interface panels!!!
if ( guiCurrentScreen == GAME_SCREEN )
{
SetCurrentSquad( pVehicleSoldier->bAssignment, TRUE );
}
}
return( TRUE );
}
}
// no slots, leave
return( FALSE );
}
void SetSoldierExitVehicleInsertionData( SOLDIERTYPE *pSoldier, INT32 iId, UINT8 iOldGroupID )
{
GROUP *pGroup;
if ( iId == iHelicopterVehicleId && !pSoldier->bInSector )
{
if( pSoldier->sSectorX != BOBBYR_SHIPPING_DEST_SECTOR_X || pSoldier->sSectorY != BOBBYR_SHIPPING_DEST_SECTOR_Y || pSoldier->bSectorZ != BOBBYR_SHIPPING_DEST_SECTOR_Z )
{
if( NumHostilesInSector( pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ ) > 0 && iOldGroupID != 0 && gGameExternalOptions.ubSkyriderHotLZ == 2 )
{
pGroup = GetGroup( iOldGroupID );
if( pGroup->ubSectorX < pGroup->ubPrevX )
{
pSoldier->ubStrategicInsertionCode = INSERTION_CODE_EAST;
}
else if( pGroup->ubSectorX > pGroup->ubPrevX )
{
pSoldier->ubStrategicInsertionCode = INSERTION_CODE_WEST;
}
else if( pGroup->ubSectorY < pGroup->ubPrevY )
{
pSoldier->ubStrategicInsertionCode = INSERTION_CODE_SOUTH;
}
else if( pGroup->ubSectorY > pGroup->ubPrevY )
{
pSoldier->ubStrategicInsertionCode = INSERTION_CODE_NORTH;
}
else
{
Assert(0);
return;
}
}
else
{
// Not anything different here - just use center gridno......
pSoldier->ubStrategicInsertionCode = INSERTION_CODE_CENTER;
}
}
else
{
// This is drassen, make insertion gridno specific...
pSoldier->ubStrategicInsertionCode = INSERTION_CODE_GRIDNO;
pSoldier->usStrategicInsertionData = 10125;
}
}
}
BOOLEAN RemoveSoldierFromVehicle( SOLDIERTYPE *pSoldier, INT32 iId )
{
// remove soldier from vehicle
INT32 iCounter = 0;
BOOLEAN fSoldierLeft = FALSE;
BOOLEAN fSoldierFound = FALSE;
SOLDIERTYPE *pVehicleSoldier;
UINT8 iOldGroupID=0;
if( ( iId >= ubNumberOfVehicles ) || ( iId < 0 ) )
{
return( FALSE );
}
// now check if vehicle is valid
if( pVehicleList[ iId ].fValid == FALSE )
{
return( FALSE );
}
// now look for the grunt
for( iCounter = 0; iCounter < iSeatingCapacities[ pVehicleList[ iId ].ubVehicleType ]; iCounter++ )
{
if( pVehicleList[ iId ].pPassengers[ iCounter ] == pSoldier )
{
fSoldierFound = TRUE;
iOldGroupID = pVehicleList[ iId ].pPassengers[ iCounter ]->ubGroupID;
pVehicleList[ iId ].pPassengers[ iCounter ]->ubGroupID = 0;
pVehicleList[ iId ].pPassengers[ iCounter ]->sSectorY = pVehicleList[ iId ].sSectorY;
pVehicleList[ iId ].pPassengers[ iCounter ]->sSectorX = pVehicleList[ iId ].sSectorX;
pVehicleList[ iId ].pPassengers[ iCounter ]->bSectorZ = ( INT8 )pVehicleList[ iId ].sSectorZ;
pVehicleList[ iId ].pPassengers[ iCounter ] = NULL;
pSoldier->flags.uiStatusFlags &= ( ~( SOLDIER_DRIVER | SOLDIER_PASSENGER ) );
// check if anyone left in vehicle
fSoldierLeft = FALSE;
for( iCounter = 0; iCounter < iSeatingCapacities[ pVehicleList[ iId ].ubVehicleType ]; iCounter++ )
{
if( pVehicleList[ iId ].pPassengers[ iCounter ] != NULL )
{
fSoldierLeft = TRUE;
}
}
if( pVehicleList[ iId ].ubMovementGroup != 0 )
{
RemovePlayerFromGroup( pVehicleList[ iId ].ubMovementGroup, pSoldier );
/* ARM 20-01-99, now gonna disallow exiting vehicles between sectors except if merc is leaving (fired, dies, contract runs out)
in which case we don't need to give them up for anything movement related since they're gone.
// check if vehicle was between sectors, if so, grunt must go it on foot
if( pVehicleList[ iId ].fBetweenSectors == TRUE )
{
RemoveSoldierFromVehicleBetweenSectors( pSoldier, iId );
}
*/
}
break;
}
}
if ( !fSoldierFound )
{
return( FALSE );
}
// Are we the last?
//if ( GetNumberInVehicle( iId ) == 0 )
if( fSoldierLeft == FALSE )
{
// is the vehicle the helicopter?..it can continue moving when no soldiers aboard (Skyrider remains)
if( iId != iHelicopterVehicleId )
{
pVehicleSoldier = GetSoldierStructureForVehicle( iId );
Assert ( pVehicleSoldier );
if ( pVehicleSoldier )
{
// and he has a route set
if ( GetLengthOfMercPath( pVehicleSoldier ) > 0 )
{
// cancel the entire path (also handles reversing directions)
CancelPathForVehicle( &( pVehicleList[ iId ] ), FALSE );
}
// if the vehicle was abandoned between sectors
if ( pVehicleList[ iId ].fBetweenSectors )
{
// teleport it to the closer of its current and next sectors (it beats having it arrive empty later)
TeleportVehicleToItsClosestSector( iId, pVehicleSoldier->ubGroupID );
}
// Remove vehicle from squad.....
RemoveCharacterFromSquads( pVehicleSoldier );
// ATE: Add him back to vehicle group!
if ( !DoesPlayerExistInPGroup( pVehicleList[ iId ].ubMovementGroup, pVehicleSoldier ) )
{
AddPlayerToGroup( pVehicleList[ iId ].ubMovementGroup, pVehicleSoldier );
}
ChangeSoldiersAssignment( pVehicleSoldier, ASSIGNMENT_EMPTY );
/* ARM Removed Feb. 17, 99 - causes pVehicleSoldier->ubGroupID to become 0, which will cause assert later on
RemovePlayerFromGroup( pVehicleSoldier->ubGroupID, pVehicleSoldier );
*/
/*
// Change sides...
pVehicleSoldier = ChangeSoldierTeam( pVehicleSoldier, CIV_TEAM );
// subtract it from mapscreen list
fReBuildCharacterList = TRUE;
RemoveCharacterFromSquads( pVehicleSoldier );
*/
}
}
}
// if he got out of the chopper
if ( iId == iHelicopterVehicleId )
{
// and he's alive
if ( pSoldier->stats.bLife >= OKLIFE )
{
// mark the sector as visited (flying around in the chopper doesn't, so this does it as soon as we get off it)
SetSectorFlag( pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ, SF_ALREADY_VISITED );
}
SetSoldierExitVehicleInsertionData( pSoldier, iId, iOldGroupID );
// Update in sector if this is the current sector.....
if ( pSoldier->sSectorX == gWorldSectorX && pSoldier->sSectorY == gWorldSectorY && pSoldier->bSectorZ == gbWorldSectorZ )
{
UpdateMercInSector( pSoldier, gWorldSectorX, gWorldSectorY, gbWorldSectorZ );
}
}
// soldier successfully removed
return( TRUE );
}
/*
void RemoveSoldierFromVehicleBetweenSectors( pSoldier, iId )
{
GROUP *pGroup;
INT32 iCurrentCostInTime = 0;
INT8 bDelta = 0;
UINT8 ubCurrent, ubNext, ubDirection, ubSector;
UINT8 ubNextX, ubNextY, ubPrevX, ubPrevY;
UINT32 uiTraverseTime, uiArriveTime;
UINT8 ubGroupId;
float flTripFractionCovered;
// set up a mvt group for the grunt
pSoldier->flags.fBetweenSectors = TRUE;
// ok, the guy wasn't in a squad
// get his mvt groups position and set the squads to this
GetGroupPosition(&ubNextX, &ubNextY, &ubPrevX, &ubPrevY, &uiTraverseTime, &uiArriveTime, pVehicleList[ iId ].ubMovementGroup );
ubGroupId = CreateNewPlayerGroupDepartingFromSector( ( INT8 ) ( pSoldier->sSectorX ) , ( INT8 ) ( pSoldier->sSectorY ) );
// assign to a group
AddPlayerToGroup( ubGroupId, pSoldier );
// get the group
pGroup = GetGroup( ubGroupId );
// find total time for traversal between sectors for foot mvt type
// get current and next sector values (DON'T use prevX, prevY, that's the sector BEFORE the current one!!!)
ubCurrent = CALCULATE_STRATEGIC_INDEX( pGroup->ubSectorX, pGroup->ubSectorY );
ubNext = CALCULATE_STRATEGIC_INDEX( ubNextX, ubNextY );
// handle errors
Assert( ubCurrent != ubNext );
if ( ubCurrent == ubNext )
continue;
// which direction are we moving in?
bDelta = (INT8) ubNext - ubCurrent;
if( bDelta > 0 )
{
if( bDelta % SOUTH_MOVE == 0 )
{
ubDirection = SOUTH_STRATEGIC_MOVE;
}
else
{
ubDirection = EAST_STRATEGIC_MOVE;
}
}
else
{
if( bDelta % NORTH_MOVE == 0 )
{
ubDirection = NORTH_STRATEGIC_MOVE;
}
else
{
ubDirection = WEST_STRATEGIC_MOVE;
}
}
// calculate how long the entire trip would have taken on foot
ubSector = ( UINT8 ) SECTOR( pGroup->ubSectorX, pGroup->ubSectorY );
iCurrentCostInTime = GetSectorMvtTimeForGroup( ubSector, ubDirection, pGroup );
if( iCurrentCostInTime == 0xffffffff )
{
AssertMsg( 0, String("Group %d (%s) attempting illegal move from sector %d, dir %d (%s).",
pGroup->ubGroupID, ( pGroup->fPlayer ) ? "Player" : "AI",
ubSector, ubDirection,
gszTerrain[SectorInfo[ubSector].ubTraversability[ubDirection]] ) );
}
// figure out what how far along ( percentage ) the vehicle's trip duration we bailed out at
flTripFractionCovered = ( uiTraverseTime - uiArriveTime + GetWorldTotalMin( ) ) / (float)uiTraverseTime;
// calculate how much longer we have to go on foot to get there
uiArriveTime = ( UINT32 )( ( ( 1.0 - flTripFractionCovered ) * ( float )iCurrentCostInTime ) + GetWorldTotalMin( ) );
SetGroupPosition( ubNextX, ubNextY, ubPrevX, ubPrevY, iCurrentCostInTime, uiArriveTime, pSoldier->ubGroupID );
// ARM: if this is ever reactivated, there seem to be the following additional problems:
1) The soldier removed isn't showing any DEST. Must set up his strategic path/destination.
2) The arrive time seems to be much later than it should have been, suggesting the math above is wrong somehow
3) Reassigning multiple mercs at once out of a vehicle onroute doesn't work 'cause the group is between sectors so only
the first merc gets added successfully, the others all fail.
}
*/
BOOLEAN MoveCharactersPathToVehicle( SOLDIERTYPE *pSoldier )
{
INT32 iId;
// valid soldier?
if( pSoldier == NULL )
{
return ( FALSE );
}
// check if character is in fact in a vehicle
if( ( pSoldier->bAssignment != VEHICLE ) && ( ! ( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) ) )
{
// now clear soldier's path
pSoldier->pMercPath = ClearStrategicPathList( pSoldier->pMercPath, 0 );
return( FALSE );
}
if( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE )
{
// grab the id the character is
iId = pSoldier->bVehicleID;
}
else
{
// grab the id the character is
iId = pSoldier->iVehicleId;
}
// check if vehicle is valid
if( iId != -1 )
{
// check if vehicle has mvt group, if not, get one for it
if( ( iId >= ubNumberOfVehicles ) || ( iId < 0 ) )
{
// now clear soldier's path
pSoldier->pMercPath = ClearStrategicPathList( pSoldier->pMercPath, 0 );
return ( FALSE );
}
// now check if vehicle is valid
if( pVehicleList[ iId ].fValid == FALSE )
{
// now clear soldier's path
pSoldier->pMercPath = ClearStrategicPathList( pSoldier->pMercPath, 0 );
return( FALSE );
}
}
// valid vehicle
// now clear soldier's path
pVehicleList[ iId ].pMercPath = ClearStrategicPathList( pVehicleList[ iId ].pMercPath, pVehicleList[ iId ].ubMovementGroup );
// now copy over
pVehicleList[ iId ].pMercPath = CopyPaths( pSoldier->pMercPath, pVehicleList[ iId ].pMercPath );
// move to beginning
pVehicleList[ iId ].pMercPath = MoveToBeginningOfPathList( pVehicleList[ iId ].pMercPath );
// now clear soldier's path
pSoldier->pMercPath = ClearStrategicPathList( pSoldier->pMercPath, 0 );
return( TRUE );
}
BOOLEAN CopyVehiclePathToSoldier( SOLDIERTYPE *pSoldier )
{
INT32 iId;
// valid soldier?
if( pSoldier == NULL )
{
return ( FALSE );
}
// check if character is in fact in a vehicle
if( ( pSoldier->bAssignment != VEHICLE ) && ( ! ( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) ) )
{
return( FALSE );
}
if( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE )
{
// grab the id the character is
iId = pSoldier->bVehicleID;
}
else
{
// grab the id the character is
iId = pSoldier->iVehicleId;
}
// check if vehicle is valid
if( iId != -1 )
{
// check if vehicle has mvt group, if not, get one for it
if( ( iId >= ubNumberOfVehicles ) || ( iId < 0 ) )
{
return ( FALSE );
}
// now check if vehicle is valid
if( pVehicleList[ iId ].fValid == FALSE )
{
return( FALSE );
}
}
// reset mvt group for the grunt
// ATE: NOT if we are the vehicle
if ( !( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) )
{
pSoldier->ubGroupID = pVehicleList[ iId ].ubMovementGroup;
}
// valid vehicle
// clear grunt path
if( pSoldier->pMercPath )
{
// clear soldier's path
pSoldier->pMercPath = ClearStrategicPathList( pSoldier->pMercPath, 0 );
}
// now copy over
pSoldier->pMercPath = CopyPaths(pVehicleList[ iId ].pMercPath, pSoldier->pMercPath );
return( TRUE );
}
BOOLEAN IsVehicle(SOLDIERTYPE *pSoldier)
{
switch(pSoldier->ubProfile)
{
case PROF_HUMMER:
case PROF_ELDERODO:
case PROF_ICECREAM:
return(TRUE);
default:
return(FALSE);
}
return(FALSE);
}
BOOLEAN SetUpMvtGroupForVehicle( SOLDIERTYPE *pSoldier )
{
// given this grunt, find out if asscoiated vehicle has a mvt group, if so, set this grunts mvt group tho the vehicle
// for pathing purposes, will be reset to zero in copying of path
INT32 iId = 0;
#ifndef RELEASE_WITH_DEBUG_INFO
//INT32 iCounter = 0;
#endif // RELEASE_WITH_DEBUG_INFO
// check if character is in fact in a vehicle
if( ( pSoldier->bAssignment != VEHICLE ) && ( ! ( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) ) )
{
return( FALSE );
}
if( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE )
{
// grab the id the character is
iId = pSoldier->bVehicleID;
}
else
{
// grab the id the character is
iId = pSoldier->iVehicleId;
}
if( pSoldier->pMercPath )
{
// clear soldier's path
pSoldier->pMercPath = ClearStrategicPathList( pSoldier->pMercPath, pSoldier->ubGroupID );
}
// if no group, create one for vehicle
//if( pVehicleList[ iId ].ubMovementGroup == 0 )
//{
// get the vehicle a mvt group
//pVehicleList[ iId ].ubMovementGroup = CreateNewVehicleGroupDepartingFromSector( ( UINT8 )( pVehicleList[ iId ].sSectorX ), ( UINT8 )( pVehicleList[ iId ].sSectorY ), iId );
//pVehicleList[ iId ].ubMovementGroup = CreateNewVehicleGroupDepartingFromSector( ( UINT8 )( pVehicleList[ iId ].sSectorX ), ( UINT8 )( pVehicleList[ iId ].sSectorY ), iId );
// add everyone in vehicle to this mvt group
//for( iCounter = 0; iCounter < iSeatingCapacities[ pVehicleList[ iId ].ubVehicleType ]; iCounter++ )
//{
// if( pVehicleList[ iId ].pPassengers[ iCounter ] != NULL )
// {
// // add character
// AddPlayerToGroup( pVehicleList[ iId ].ubMovementGroup, pVehicleList[ iId ].pPassengers[ iCounter ] );
// }
//}
//}
CopyVehiclePathToSoldier( pSoldier );
// set up mvt group
pSoldier->ubGroupID = pVehicleList[ iId ].ubMovementGroup;
return ( TRUE );
}
BOOLEAN VehicleIdIsValid( INT32 iId )
{
// check if vehicle has mvt group, if not, get one for it
if( ( iId >= ubNumberOfVehicles ) || ( iId < 0 ) )
{
return ( FALSE );
}
// now check if vehicle is valid
if( pVehicleList[ iId ].fValid == FALSE )
{
return( FALSE );
}
return( TRUE );
}
// get travel time of vehicle
INT32 GetTravelTimeOfVehicle( INT32 iId )
{
GROUP *pGroup;
// valid vehicle?
if( VehicleIdIsValid( iId ) == FALSE )
{
return( 0 );
}
// no mvt group?
if( pVehicleList[ iId ].ubMovementGroup == 0 )
{
return ( 0 );
}
pGroup = GetGroup( pVehicleList[ iId ].ubMovementGroup );
if( pGroup == NULL )
{
pVehicleList[ iId ].ubMovementGroup = 0;
return( 0 );
}
return( CalculateTravelTimeOfGroupId( pVehicleList[ iId ].ubMovementGroup ) );
}
void UpdatePositionOfMercsInVehicle( INT32 iId )
{
INT32 iCounter = 0;
// update the position of all the grunts in the vehicle
if( VehicleIdIsValid( iId ) == FALSE )
{
return;
}
// go through list of mercs in vehicle and set all thier states as arrived
for( iCounter = 0; iCounter < iSeatingCapacities[ pVehicleList[ iId ].ubVehicleType ]; iCounter++ )
{
if( pVehicleList[ iId ].pPassengers[ iCounter ] != NULL )
{
pVehicleList[ iId ].pPassengers[ iCounter ]->sSectorY = pVehicleList[ iId ].sSectorY;
pVehicleList[ iId ].pPassengers[ iCounter ]->sSectorX = pVehicleList[ iId ].sSectorX;
pVehicleList[ iId ].pPassengers[ iCounter ]->flags.fBetweenSectors = FALSE;
}
}
return;
}
INT32 GivenMvtGroupIdFindVehicleId( UINT8 ubGroupId )
{
INT32 iCounter = 0;
// given the id of a mvt group, find a vehicle in this group
if( ubGroupId == 0 )
{
return ( -1 );
}
for( iCounter = 0; iCounter < ubNumberOfVehicles ; iCounter++ )
{
// might have an empty slot
if( pVehicleList[ iCounter ].fValid == TRUE )
{
if( pVehicleList[ iCounter ].ubMovementGroup == ubGroupId )
{
return( iCounter );
}
}
}
return( -1 );
}
// add all people in this vehicle to the mvt group for benifit of prebattle interface
BOOLEAN AddVehicleMembersToMvtGroup( INT32 iId )
{
INT32 iCounter = 0;
if( VehicleIdIsValid( iId ) == FALSE )
{
return( FALSE );
}
// clear the vehicle people list out
// RemoveAllPlayersFromGroup( pVehicleList[ iId ].ubMovementGroup );
// go through list of mercs in vehicle and set all thier states as arrived
for( iCounter = 0; iCounter < iSeatingCapacities[ pVehicleList[ iId ].ubVehicleType ]; iCounter++ )
{
if( pVehicleList[ iId ].pPassengers[ iCounter ] != NULL )
{
AddPlayerToGroup( pVehicleList[ iId ].ubMovementGroup , pVehicleList[ iId ].pPassengers[ iCounter ] );
}
}
return( TRUE );
}
BOOLEAN InjurePersonInVehicle( INT32 iId, SOLDIERTYPE *pSoldier, UINT8 ubPointsOfDmg )
{
// find this person, see if they have this many pts left, if not, kill them
// find if vehicle is valid
if( VehicleIdIsValid( iId ) == FALSE )
{
return ( FALSE );
}
// check if soldier is valid
if( pSoldier == NULL )
{
return ( FALSE );
}
// now check hpts of merc
if( pSoldier->stats.bLife == 0 )
{
// guy is dead, leave
return( FALSE );
}
// see if we will infact kill them
if( ubPointsOfDmg >= pSoldier->stats.bLife )
{
return( KillPersonInVehicle( iId, pSoldier ) );
}
// otherwise hurt them
pSoldier->SoldierTakeDamage( 0, ubPointsOfDmg, ubPointsOfDmg, TAKE_DAMAGE_GUNFIRE, NOBODY, NOWHERE, 0, TRUE );
pSoldier->HandleSoldierTakeDamageFeedback( );
return( TRUE );
}
BOOLEAN KillPersonInVehicle( INT32 iId, SOLDIERTYPE *pSoldier )
{
// find if vehicle is valid
if( VehicleIdIsValid( iId ) == FALSE )
{
return ( FALSE );
}
// check if soldier is valid
if( pSoldier == NULL )
{
return ( FALSE );
}
// now check hpts of merc
if( pSoldier->stats.bLife == 0 )
{
// guy is dead, leave
return( FALSE );
}
// otherwise hurt them
pSoldier->SoldierTakeDamage( 0, 100, 100, TAKE_DAMAGE_BLOODLOSS, NOBODY, NOWHERE, 0, TRUE );
return( TRUE );
}
BOOLEAN KillAllInVehicle( INT32 iId )
{
INT32 iCounter = 0;
// find if vehicle is valid
if( VehicleIdIsValid( iId ) == FALSE )
{
return ( FALSE );
}
// go through list of occupants and kill them
for( iCounter = 0; iCounter < iSeatingCapacities[ pVehicleList[ iId ].ubVehicleType ]; iCounter++ )
{
if( pVehicleList[ iId ].pPassengers[ iCounter ] != NULL )
{
if( KillPersonInVehicle( iId , pVehicleList[ iId ].pPassengers[ iCounter ] ) == FALSE )
{
return( FALSE );
}
}
}
return ( TRUE );
}
INT32 GetNumberInVehicle( INT32 iId )
{
// go through list of occupants in vehicles and count them
INT32 iCounter = 0;
INT32 iCount = 0;
// find if vehicle is valid
if( VehicleIdIsValid( iId ) == FALSE )
{
return ( 0 );
}
for( iCounter = 0; iCounter < iSeatingCapacities[ pVehicleList[ iId ].ubVehicleType ]; iCounter++ )
{
if( pVehicleList[ iId ].pPassengers[ iCounter ] != NULL )
{
iCount++;
}
}
return( iCount );
}
INT32 GetNumberOfNonEPCsInVehicle( INT32 iId )
{
// go through list of occupants in vehicles and count them
INT32 iCounter = 0;
INT32 iCount = 0;
// find if vehicle is valid
if( VehicleIdIsValid( iId ) == FALSE )
{
return ( 0 );
}
for( iCounter = 0; iCounter < iSeatingCapacities[ pVehicleList[ iId ].ubVehicleType ]; iCounter++ )
{
if( pVehicleList[ iId ].pPassengers[ iCounter ] != NULL && !AM_AN_EPC( pVehicleList[ iId ].pPassengers[ iCounter ] ) )
{
iCount++;
}
}
return( iCount );
}
BOOLEAN IsRobotControllerInVehicle( INT32 iId )
{
// go through list of occupants in vehicles and count them
INT32 iCounter = 0;
SOLDIERTYPE * pSoldier;
// find if vehicle is valid
if( VehicleIdIsValid( iId ) == FALSE )
{
return ( 0 );
}
for( iCounter = 0; iCounter < iSeatingCapacities[ pVehicleList[ iId ].ubVehicleType ]; iCounter++ )
{
pSoldier = pVehicleList[ iId ].pPassengers[ iCounter ];
if ( pSoldier != NULL && pSoldier->ControllingRobot( ) )
{
return( TRUE );
}
}
return( FALSE );
}
BOOLEAN AnyAccessibleVehiclesInSoldiersSector( SOLDIERTYPE *pSoldier )
{
INT32 iCounter = 0;
for( iCounter = 0; iCounter < ubNumberOfVehicles ; iCounter++ )
{
if ( pVehicleList[ iCounter ].fValid == TRUE )
{
if ( IsThisVehicleAccessibleToSoldier( pSoldier, iCounter ) )
{
return( TRUE );
}
}
}
return( FALSE );
}
SOLDIERTYPE *GetDriver( INT32 iID )
{
return( MercPtrs[ pVehicleList[ iID ].ubDriver ] );
}
void SetDriver( INT32 iID, UINT8 ubID )
{
pVehicleList[ iID ].ubDriver = ubID;
}
#ifdef JA2TESTVERSION
void VehicleTest( void )
{
SetUpHelicopterForPlayer( 9,1, SKYRIDER );
}
#endif
BOOLEAN IsEnoughSpaceInVehicle( INT32 iID )
{
// find if vehicle is valid
if( VehicleIdIsValid( iID ) == FALSE )
{
return ( FALSE );
}
if ( GetNumberInVehicle( iID ) == iSeatingCapacities[ pVehicleList[ iID ].ubVehicleType ] )
{
return( FALSE );
}
return( TRUE );
}
BOOLEAN PutSoldierInVehicle( SOLDIERTYPE *pSoldier, INT8 bVehicleId )
{
SOLDIERTYPE *pVehicleSoldier = NULL;
if( ( pSoldier->sSectorX != gWorldSectorX ) || ( pSoldier->sSectorY != gWorldSectorY ) || ( pSoldier->bSectorZ != 0 ) || ( bVehicleId == iHelicopterVehicleId ) )
{
// add the soldier
return( AddSoldierToVehicle( pSoldier, bVehicleId ) );
}
else
{
// grab the soldier struct for the vehicle
pVehicleSoldier = GetSoldierStructureForVehicle( bVehicleId );
// enter the vehicle
return( EnterVehicle( pVehicleSoldier, pSoldier ) );
}
}
BOOLEAN TakeSoldierOutOfVehicle( SOLDIERTYPE *pSoldier )
{
// if not in vehicle, don't take out, not much point, now is there?
if( pSoldier->bAssignment != VEHICLE )
{
return( FALSE );
}
if( ( pSoldier->sSectorX != gWorldSectorX ) || ( pSoldier->sSectorY != gWorldSectorY ) || ( pSoldier->bSectorZ != 0 ) || !pSoldier->bInSector )
{
// add the soldier
return( RemoveSoldierFromVehicle( pSoldier, pSoldier->iVehicleId ) );
}
else
{
// helicopter isn't a soldiertype instance
if( pSoldier->iVehicleId == iHelicopterVehicleId )
{
return( RemoveSoldierFromVehicle( pSoldier, pSoldier->iVehicleId ) );
}
else
{
// exit the vehicle
return( ExitVehicle( pSoldier ) );
}
}
}
BOOLEAN EnterVehicle( SOLDIERTYPE *pVehicle, SOLDIERTYPE *pSoldier )
{
// TEST IF IT'S VALID...
if ( pVehicle->flags.uiStatusFlags & SOLDIER_VEHICLE )
{
// Is there room...
if ( IsEnoughSpaceInVehicle( pVehicle->bVehicleID ) )
{
// OK, add....
AddSoldierToVehicle( pSoldier, pVehicle->bVehicleID );
if ( !(guiTacticalInterfaceFlags & INTERFACE_MAPSCREEN ) )
{
// Change to team panel if we are not already...
SetCurrentInterfacePanel( TEAM_PANEL );
}
return( TRUE );
}
}
return( FALSE );
}
SOLDIERTYPE *GetVehicleSoldierPointerFromPassenger( SOLDIERTYPE *pSrcSoldier )
{
UINT32 cnt;
SOLDIERTYPE *pSoldier;
// End the turn of player charactors
cnt = gTacticalStatus.Team[ gbPlayerNum ].bFirstID;
// look for all mercs on the same team,
for ( pSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; cnt++,pSoldier++)
{
if ( pSoldier->bActive && pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE )
{
// Check ubID....
if ( pSoldier->bVehicleID == pSrcSoldier->iVehicleId )
{
return( pSoldier );
}
}
}
return( NULL );
}
BOOLEAN ExitVehicle( SOLDIERTYPE *pSoldier )
{
SOLDIERTYPE *pVehicle;
UINT8 ubDirection;
INT32 sGridNo;
// Get vehicle from soldier...
pVehicle = GetVehicleSoldierPointerFromPassenger( pSoldier );
if ( pVehicle == NULL )
{
return( FALSE );
}
// TEST IF IT'S VALID...
if ( pVehicle->flags.uiStatusFlags & SOLDIER_VEHICLE )
{
sGridNo = FindGridNoFromSweetSpotWithStructDataFromSoldier( pSoldier, pSoldier->usUIMovementMode, 5, &ubDirection, 3, pVehicle );
if (TileIsOutOfBounds(sGridNo))
{
// ATE: BUT we need a place, widen the search
sGridNo = FindGridNoFromSweetSpotWithStructDataFromSoldier( pSoldier, pSoldier->usUIMovementMode, 20, &ubDirection, 3, pVehicle );
}
// OK, remove....
RemoveSoldierFromVehicle( pSoldier, pVehicle->bVehicleID );
// Were we the driver, and if so, pick another....
pSoldier->sInsertionGridNo = sGridNo;
pSoldier->ubStrategicInsertionCode = INSERTION_CODE_GRIDNO;
pSoldier->usStrategicInsertionData = pSoldier->sInsertionGridNo;
pSoldier->iVehicleId = -1;
//AllTeamsLookForAll( FALSE );
pSoldier->aiData.bOppList[ pVehicle->ubID ] = 1;
// Add to sector....
pSoldier->EVENT_SetSoldierPosition( CenterX( sGridNo ), CenterY( sGridNo ) );
// Update visiblity.....
HandleSight(pSoldier,SIGHT_LOOK | SIGHT_RADIO );
// Add to unique squad....
AddCharacterToUniqueSquad( pSoldier );
// can't call SetCurrentSquad OR SelectSoldier in mapscreen, that will initialize interface panels!!!
if ( guiCurrentScreen == GAME_SCREEN )
{
SetCurrentSquad( pSoldier->bAssignment, TRUE );
SelectSoldier( pSoldier->ubID, FALSE, TRUE );
}
PlayJA2Sample( pVehicleList[ pVehicle->bVehicleID ].iOutOfSound, RATE_11025, SoundVolume( HIGHVOLUME, pVehicle->sGridNo ), 1, SoundDir( pVehicle->sGridNo ) );
return( TRUE );
}
return( FALSE );
}
void AddPassangersToTeamPanel( INT32 iId )
{
INT32 cnt;
for( cnt = 0; cnt < iSeatingCapacities[ pVehicleList[ iId ].ubVehicleType ]; cnt++ )
{
if( pVehicleList[ iId ].pPassengers[ cnt ] != NULL )
{
// add character
AddPlayerToInterfaceTeamSlot( pVehicleList[ iId ].pPassengers[ cnt ]->ubID );
}
}
}
void VehicleTakeDamage( UINT8 ubID, UINT8 ubReason, INT16 sDamage, INT32 sGridNo, UINT8 ubAttackerID )
{
if ( ubReason != TAKE_DAMAGE_GAS )
{
PlayJA2Sample( (UINT32)( S_METAL_IMPACT3 ), RATE_11025, SoundVolume( MIDVOLUME, sGridNo ), 1, SoundDir( sGridNo ) );
}
// check if there was in fact damage done to the vehicle
if( ( ubReason == TAKE_DAMAGE_HANDTOHAND ) || ( ubReason == TAKE_DAMAGE_GAS ) )
{
// nope
return;
}
if( pVehicleList[ ubID ].fDestroyed == FALSE )
{
switch( ubReason )
{
case( TAKE_DAMAGE_GUNFIRE ):
case( TAKE_DAMAGE_EXPLOSION):
case( TAKE_DAMAGE_STRUCTURE_EXPLOSION):
HandleCriticalHitForVehicleInLocation( ubID, sDamage, sGridNo, ubAttackerID );
break;
}
}
}
void HandleCriticalHitForVehicleInLocation( UINT8 ubID, INT16 sDmg, INT32 sGridNo, UINT8 ubAttackerID )
{
// check state the armor was s'posed to be in vs. the current state..the difference / orig state is % chance
// that a critical hit will occur
SOLDIERTYPE *pSoldier;
BOOLEAN fMadeCorpse = FALSE;
#if 0
{
// injure someone inside
iRand = Random( iSeatingCapacities[ pVehicleList[ ubID ].ubVehicleType ] );
if( pVehicleList[ ubID ].pPassengers[ iRand ] )
{
// hurt this person
InjurePersonInVehicle( ( INT16 )ubID, pVehicleList[ ubID ].pPassengers[ iRand ], ( UINT8 )( sDmg / 2 ) );
}
}
ScreenMsg( FONT_BLACK, MSG_INTERFACE, sCritLocationStrings[ iCrit ] );
}
#endif
pSoldier = GetSoldierStructureForVehicle( ubID );
if ( sDmg > pSoldier->stats.bLife )
{
pSoldier->stats.bLife = 0;
}
else
{
// Decrease Health
pSoldier->stats.bLife -= sDmg;
}
if ( pSoldier->stats.bLife < OKLIFE )
{
pSoldier->stats.bLife = 0;
}
//Show damage
pSoldier->sDamage += sDmg;
if ( pSoldier->bInSector && pSoldier->bVisible != -1 )
{
// If we are already dead, don't show damage!
if ( sDmg != 0 )
{
// Display damage
INT16 sMercScreenX, sMercScreenY, sOffsetX, sOffsetY;
// Set Damage display counter
pSoldier->flags.fDisplayDamage = TRUE;
pSoldier->bDisplayDamageCount = 0;
GetSoldierScreenPos( pSoldier, &sMercScreenX, &sMercScreenY );
GetSoldierAnimOffsets( pSoldier, &sOffsetX, &sOffsetY );
pSoldier->sDamageX = sOffsetX;
pSoldier->sDamageY = sOffsetY;
}
}
if ( pSoldier->stats.bLife == 0 && !pVehicleList[ ubID ].fDestroyed )
{
pVehicleList[ ubID ].fDestroyed = TRUE;
// Explode vehicle...
IgniteExplosion( ubAttackerID, CenterX( sGridNo ), CenterY( sGridNo ), 0, sGridNo, GREAT_BIG_EXPLOSION, 0 );
if ( pSoldier != NULL )
{
// Tacticlly remove soldier....
// pSoldier->EVENT_InitNewSoldierAnim( VEHICLE_DIE, 0, FALSE );
//TacticalRemoveSoldier( pSoldier->ubID );
CheckForAndHandleSoldierDeath( pSoldier, &fMadeCorpse );
}
// Kill all in vehicle...
KillAllInVehicle( ubID );
}
return;
}
BOOLEAN DoesVehicleNeedAnyRepairs( INT32 iVehicleId )
{
SOLDIERTYPE *pVehicleSoldier = NULL;
// is the vehicle in fact a valid vehicle
if( VehicleIdIsValid( iVehicleId ) == FALSE )
{
// nope
return( FALSE );
}
// Skyrider isn't damagable/repairable
if ( iVehicleId == iHelicopterVehicleId )
{
return( FALSE );
}
// get the vehicle soldiertype
pVehicleSoldier = GetSoldierStructureForVehicle( iVehicleId );
if ( pVehicleSoldier->stats.bLife != pVehicleSoldier->stats.bLifeMax )
{
return( TRUE );
}
// everything is in perfect condition
return( FALSE);
}
INT8 RepairVehicle( INT32 iVehicleId, INT8 bRepairPtsLeft, BOOLEAN *pfNothingToRepair )
{
SOLDIERTYPE *pVehicleSoldier = NULL;
INT8 bRepairPtsUsed = 0;
INT8 bOldLife;
// is the vehicle in fact a valid vehicle
if( VehicleIdIsValid( iVehicleId ) == FALSE )
{
// nope
return( bRepairPtsUsed );
}
// Skyrider isn't damagable/repairable
if ( iVehicleId == iHelicopterVehicleId )
{
return( bRepairPtsUsed );
}
// get the vehicle soldiertype
pVehicleSoldier = GetSoldierStructureForVehicle( iVehicleId );
if ( !DoesVehicleNeedAnyRepairs( iVehicleId ) )
{
return( bRepairPtsUsed );
}
bOldLife = pVehicleSoldier->stats.bLife;
// Repair
pVehicleSoldier->stats.bLife += ( bRepairPtsLeft / VEHICLE_REPAIR_POINTS_DIVISOR );
// Check
if ( pVehicleSoldier->stats.bLife > pVehicleSoldier->stats.bLifeMax )
{
pVehicleSoldier->stats.bLife = pVehicleSoldier->stats.bLifeMax;
}
// Calculate pts used;
bRepairPtsUsed = ( pVehicleSoldier->stats.bLife - bOldLife ) * VEHICLE_REPAIR_POINTS_DIVISOR;
// ARM: personally, I'd love to know where in Arulco the mechanic gets the PARTS to do this stuff, but hey, it's a game!
(*pfNothingToRepair) = !DoesVehicleNeedAnyRepairs( iVehicleId );
return( bRepairPtsUsed );
}
/*
INT16 GetOrigInternalArmorValueForVehicleInLocation( UINT8 ubID, UINT8 ubLocation )
{
INT16 sArmorValue = 0;
sArmorValue = sVehicleInternalOrigArmorValues[ pVehicleList[ ubID ].ubVehicleType ][ ubLocation ];
// return the armor value
return( sArmorValue );
}
*/
SOLDIERTYPE * GetSoldierStructureForVehicle( INT32 iId )
{
for( INT32 iCounter = 0; iCounter < TOTAL_SOLDIERS; iCounter++ )
{
SOLDIERTYPE *pSoldier = &Menptr[ iCounter ];
if( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE )
{
if ( pSoldier->bActive )
{
if( pSoldier->bVehicleID == iId )
{
return( pSoldier );
}
}
}
}
// Didn't find the vehicle
return( 0 );
}
void SetUpArmorForVehicle( UINT8 ubID )
{
/*
// set up the internal and external armor for vehicles
for( iCounter = 0; iCounter < NUMBER_OF_INTERNAL_HIT_LOCATIONS_IN_VEHICLE; iCounter++ )
{
pVehicleList[ ubID ].sInternalHitLocations[ iCounter ] = sVehicleInternalOrigArmorValues[ pVehicleList[ ubID ].ubVehicleType ][ iCounter ];
}
for( iCounter = 0; iCounter < NUMBER_OF_EXTERNAL_HIT_LOCATIONS_ON_VEHICLE; iCounter++ )
{
pVehicleList[ ubID ].sExternalArmorLocationsStatus[ iCounter ] = 100;
}
*/
// for armour type, store the index into the armour table itself
pVehicleList[ ubID ].sArmourType = Item[ sVehicleArmourType[ pVehicleList[ ubID ].ubVehicleType ] ].ubClassIndex;
return;
}
void AdjustVehicleAPs( SOLDIERTYPE *pSoldier, INT16 *pubPoints )
{
INT16 pubDeducations = 0;
INT32 iCounter = 0;
(*pubPoints) += 35;
// check for state of critcals
// handle for each engine crit
pubDeducations += pVehicleList[ pSoldier->bVehicleID ].sCriticalHits[ ENGINE_HIT_LOCATION ] * COST_PER_ENGINE_CRIT;
// handle each tire
for( iCounter = RF_TIRE_HIT_LOCATION; iCounter < LR_TIRE_HIT_LOCATION; iCounter++ )
{
if( pVehicleList[ pSoldier->bVehicleID ].sCriticalHits[ iCounter ] )
{
pubDeducations += COST_PER_TIRE_HIT;
}
}
// make sure we don't go too far
if( pubDeducations > (*pubPoints) )
{
pubDeducations = (*pubPoints);
}
// now deduct pts
(*pubPoints) -= pubDeducations;
}
BOOLEAN SaveVehicleInformationToSaveGameFile( HWFILE hFile )
{
UINT32 uiNumBytesWritten;
PathStPtr pTempPathPtr;
UINT32 uiNodeCount=0;
UINT8 cnt;
VEHICLETYPE TempVehicle;
UINT8 ubPassengerCnt=0;
//Save the number of elements
FileWrite( hFile, &ubNumberOfVehicles, sizeof( UINT8 ), &uiNumBytesWritten );
if( uiNumBytesWritten != sizeof( UINT8 ) )
{
return( FALSE );
}
//loop through all the vehicles and save each one
for( cnt=0; cnt< ubNumberOfVehicles; cnt++ )
{
//save if the vehicle spot is valid
FileWrite( hFile, &pVehicleList[cnt].fValid, sizeof( BOOLEAN ), &uiNumBytesWritten );
if( uiNumBytesWritten != sizeof( BOOLEAN ) )
{
return( FALSE );
}
if( pVehicleList[cnt].fValid )
{
// copy the node into the temp vehicle buffer ( need to do this because we cant save the pointers
// to the soldier, therefore save the soldier ubProfile
memcpy( &TempVehicle, &pVehicleList[cnt], sizeof( VEHICLETYPE ) );
//loop through the passengers
for( ubPassengerCnt=0; ubPassengerCnt<10; ubPassengerCnt++)
{
TempVehicle.pPassengers[ ubPassengerCnt ] = ( SOLDIERTYPE * )NO_PROFILE;
//if there is a passenger here
if( pVehicleList[cnt].pPassengers[ ubPassengerCnt ] )
{
//assign the passengers profile to the struct
// ! The pointer to the passenger is converted to a byte so that the Id of the soldier can be saved.
// ! This means that the pointer contains a bogus pointer, but a real ID for the soldier.
// ! When reloading, this bogus pointer is converted to a byte to contain the id of the soldier so
// ! we can get the REAL pointer to the soldier
TempVehicle.pPassengers[ ubPassengerCnt ] = ( SOLDIERTYPE * ) pVehicleList[cnt].pPassengers[ ubPassengerCnt ]->ubProfile;
}
}
//save the vehicle info
FileWrite( hFile, &TempVehicle, sizeof( VEHICLETYPE ), &uiNumBytesWritten );
if( uiNumBytesWritten != sizeof( VEHICLETYPE ) )
{
return( FALSE );
}
//count the number of nodes in the vehicles path
uiNodeCount=0;
pTempPathPtr = pVehicleList[cnt].pMercPath;
while( pTempPathPtr )
{
uiNodeCount++;
pTempPathPtr = pTempPathPtr->pNext;
}
//Save the number of nodes
FileWrite( hFile, &uiNodeCount, sizeof( UINT32 ), &uiNumBytesWritten );
if( uiNumBytesWritten != sizeof( UINT32 ) )
{
return( FALSE );
}
//save all the nodes
pTempPathPtr = pVehicleList[cnt].pMercPath;
while( pTempPathPtr )
{
//Save the node
FileWrite( hFile, pTempPathPtr, sizeof( PathSt ), &uiNumBytesWritten );
if( uiNumBytesWritten != sizeof( PathSt ) )
{
return( FALSE );
}
pTempPathPtr = pTempPathPtr->pNext;
}
}
}
return( TRUE );
}
BOOLEAN LoadVehicleInformationFromSavedGameFile( HWFILE hFile, UINT32 uiSavedGameVersion )
{
UINT32 uiNumBytesRead;
UINT32 uiTotalNodeCount=0;
UINT8 cnt;
UINT32 uiNodeCount=0;
PathSt *pPath=NULL;
UINT8 ubPassengerCnt=0;
PathSt *pTempPath;
//Clear out th vehicle list
ClearOutVehicleList( );
//Load the number of elements
FileRead( hFile, &ubNumberOfVehicles, sizeof( UINT8 ), &uiNumBytesRead );
if( uiNumBytesRead != sizeof( UINT8 ) )
{
return( FALSE );
}
if( ubNumberOfVehicles != 0 )
{
//allocate memory to hold the vehicle list
pVehicleList = (VEHICLETYPE *)MemAlloc( sizeof( VEHICLETYPE ) * ubNumberOfVehicles );
if( pVehicleList == NULL )
return( FALSE );
memset( pVehicleList, 0, sizeof( VEHICLETYPE ) * ubNumberOfVehicles );
//loop through all the vehicles and load each one
for( cnt=0; cnt< ubNumberOfVehicles; cnt++ )
{
//Load if the vehicle spot is valid
FileRead( hFile, &pVehicleList[cnt].fValid, sizeof( BOOLEAN ), &uiNumBytesRead );
if( uiNumBytesRead != sizeof( BOOLEAN ) )
{
return( FALSE );
}
if( pVehicleList[cnt].fValid )
{
//load the vehicle info
FileRead( hFile, &pVehicleList[cnt], sizeof( VEHICLETYPE ), &uiNumBytesRead );
if( uiNumBytesRead != sizeof( VEHICLETYPE ) )
{
return( FALSE );
}
//
// Build the passenger list
//
//loop through all the passengers
for(ubPassengerCnt=0; ubPassengerCnt<10; ubPassengerCnt++)
{
if ( uiSavedGameVersion < 86 )
{
if( pVehicleList[cnt].pPassengers[ubPassengerCnt] != 0 )
{
// ! The id of the soldier was saved in the passenger pointer. The passenger pointer is converted back
// ! to a UINT8 so we can get the REAL pointer to the soldier.
pVehicleList[cnt].pPassengers[ubPassengerCnt] = FindSoldierByProfileID( (UINT8)pVehicleList[cnt].pPassengers[ ubPassengerCnt ], FALSE );
}
}
else
{
if( pVehicleList[cnt].pPassengers[ubPassengerCnt] != ( SOLDIERTYPE * )NO_PROFILE )
{
// ! The id of the soldier was saved in the passenger pointer. The passenger pointer is converted back
// ! to a UINT8 so we can get the REAL pointer to the soldier.
pVehicleList[cnt].pPassengers[ubPassengerCnt] = FindSoldierByProfileID( (UINT8)pVehicleList[cnt].pPassengers[ ubPassengerCnt ], FALSE );
}
else
{
pVehicleList[cnt].pPassengers[ubPassengerCnt] = NULL;
}
}
}
//Load the number of nodes
FileRead( hFile, &uiTotalNodeCount, sizeof( UINT32 ), &uiNumBytesRead );
if( uiNumBytesRead != sizeof( UINT32 ) )
{
return( FALSE );
}
if( uiTotalNodeCount != 0 )
{
pPath = NULL;
pVehicleList[cnt].pMercPath = NULL;
//loop through each node
for( uiNodeCount=0; uiNodeCount<uiTotalNodeCount; uiNodeCount++ )
{
//allocate memory to hold the vehicle path
pTempPath = (PathSt *)MemAlloc( sizeof( PathSt ) );
if( pTempPath == NULL )
return( FALSE );
memset( pTempPath, 0, sizeof( PathSt ) );
//Load all the nodes
FileRead( hFile, pTempPath, sizeof( PathSt ), &uiNumBytesRead );
if( uiNumBytesRead != sizeof( PathSt ) )
{
return( FALSE );
}
//
//Setup the pointer info
//
if( pVehicleList[cnt].pMercPath == NULL )
pVehicleList[cnt].pMercPath = pTempPath;
//if there is a previous node
if( pPath != NULL )
{
pPath->pNext = pTempPath;
pTempPath->pPrev = pPath;
}
else
pTempPath->pPrev = NULL;
pTempPath->pNext = NULL;
pPath = pTempPath;
}
}
else
{
pVehicleList[cnt].pMercPath = NULL;
}
}
}
}
return( TRUE );
}
void SetVehicleSectorValues( INT32 iVehId, UINT8 ubSectorX, UINT8 ubSectorY )
{
pVehicleList[ iVehId ].sSectorX = ubSectorX;
pVehicleList[ iVehId ].sSectorY = ubSectorY;
gMercProfiles[ pVehicleList[ iVehId ].ubProfileID ].sSectorX = ubSectorX;
gMercProfiles[ pVehicleList[ iVehId ].ubProfileID ].sSectorY = ubSectorY;
}
void UpdateAllVehiclePassengersGridNo( SOLDIERTYPE *pSoldier )
{
INT32 iCounter, iId;
SOLDIERTYPE *pPassenger;
// If not a vehicle, ignore!
if ( !( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) )
{
return;
}
iId = pSoldier->bVehicleID;
// Loop through passengers and update each guy's position
for( iCounter = 0; iCounter < iSeatingCapacities[ pVehicleList[ iId ].ubVehicleType ]; iCounter++ )
{
if( pVehicleList[ iId ].pPassengers[ iCounter ] != NULL )
{
pPassenger = pVehicleList[ iId ].pPassengers[ iCounter ];
// Set gridno.....
pPassenger->EVENT_SetSoldierPosition( pSoldier->dXPos, pSoldier->dYPos );
}
}
}
BOOLEAN SaveVehicleMovementInfoToSavedGameFile( HWFILE hFile )
{
UINT32 uiNumBytesWritten = 0;
//Save all the vehicle movement id's
// FileWrite( hFile, gubVehicleMovementGroups, sizeof( INT8 ) * 5, &uiNumBytesWritten );
// if( uiNumBytesWritten != sizeof( INT8 ) * 5 )
// {
// return(FALSE);
// }
for (int cnt=0; cnt<5; ++cnt) {
FileWrite( hFile, &gubVehicleMovementGroups[cnt], sizeof( INT8 ), &uiNumBytesWritten );
if( uiNumBytesWritten != sizeof( INT8 ) ) {
return(FALSE);
}
}
return( TRUE );
}
BOOLEAN LoadVehicleMovementInfoFromSavedGameFile( HWFILE hFile )
{
GROUP *pGroup = NULL;
UINT32 uiNumBytesRead=0;
//Load in the Squad movement id's
// FileRead( hFile, gubVehicleMovementGroups, sizeof( INT8 ) * 5, &uiNumBytesRead );
// if( uiNumBytesRead != sizeof( INT8 ) * 5 )
// {
// return(FALSE);
// }
for (int cnt=0; cnt<5; ++cnt) {
FileRead( hFile, &gubVehicleMovementGroups[cnt], sizeof( INT8 ), &uiNumBytesRead );
if( uiNumBytesRead != sizeof( INT8 ) ) {
return(FALSE);
}
}
for( int cnt = 5; cnt < MAX_VEHICLES; cnt++ )
{
// create mvt groups
gubVehicleMovementGroups[ cnt ] = CreateNewVehicleGroupDepartingFromSector( 1, 1, cnt );
// Set persistent....
pGroup = GetGroup( gubVehicleMovementGroups[ cnt ] );
pGroup->fPersistant = TRUE;
}
return( TRUE );
}
BOOLEAN NewSaveVehicleMovementInfoToSavedGameFile( HWFILE hFile )
{
UINT32 uiNumBytesWritten = 0;
//Save all the vehicle movement id's
// FileWrite( hFile, gubVehicleMovementGroups, sizeof( INT8 ) * MAX_VEHICLES, &uiNumBytesWritten );
// if( uiNumBytesWritten != sizeof( INT8 ) * MAX_VEHICLES )
// {
// return(FALSE);
// }
for (int cnt=0; cnt<MAX_VEHICLES; ++cnt) {
FileWrite( hFile, &gubVehicleMovementGroups[cnt], sizeof( INT8 ), &uiNumBytesWritten );
if( uiNumBytesWritten != sizeof( INT8 ) ) {
return(FALSE);
}
}
return( TRUE );
}
BOOLEAN NewLoadVehicleMovementInfoFromSavedGameFile( HWFILE hFile )
{
UINT32 uiNumBytesRead=0;
//Load in the Squad movement id's
// FileRead( hFile, gubVehicleMovementGroups, sizeof( INT8 ) * MAX_VEHICLES, &uiNumBytesRead );
// if( uiNumBytesRead != sizeof( INT8 ) * MAX_VEHICLES )
// {
// return(FALSE);
// }
for (int cnt=0; cnt<MAX_VEHICLES; ++cnt) {
FileRead( hFile, &gubVehicleMovementGroups[cnt], sizeof( INT8 ), &uiNumBytesRead );
if( uiNumBytesRead != sizeof( INT8 ) ) {
return(FALSE);
}
}
return( TRUE );
}
BOOLEAN OKUseVehicle( UINT8 ubProfile )
{
if ( ubProfile == PROF_HUMMER )
{
return( CheckFact( FACT_OK_USE_HUMMER, NO_PROFILE ) );
}
else if ( ubProfile == PROF_ICECREAM )
{
return( CheckFact( FACT_OK_USE_ICECREAM, NO_PROFILE ) );
}
else if ( ubProfile == PROF_HELICOPTER )
{
// don't allow mercs to get inside vehicle if it's grounded (enemy controlled, Skyrider owed money, etc.)
return( CanHelicopterFly() );
}
else
{
return( TRUE );
}
}
void TeleportVehicleToItsClosestSector( INT32 iVehicleId, UINT8 ubGroupID )
{
GROUP *pGroup = NULL;
UINT32 uiTimeToNextSector;
UINT32 uiTimeToLastSector;
INT16 sPrevX, sPrevY, sNextX, sNextY;
pGroup = GetGroup( ubGroupID );
Assert( pGroup );
Assert( pGroup->uiTraverseTime != -1 );
Assert( ( pGroup->uiTraverseTime > 0 ) && ( pGroup->uiTraverseTime != 0xffffffff ) );
Assert( pGroup->uiArrivalTime >= GetWorldTotalMin() );
uiTimeToNextSector = pGroup->uiArrivalTime - GetWorldTotalMin();
Assert( pGroup->uiTraverseTime >= uiTimeToNextSector );
uiTimeToLastSector = pGroup->uiTraverseTime - uiTimeToNextSector;
if ( uiTimeToNextSector >= uiTimeToLastSector )
{
// go to the last sector
sPrevX = pGroup->ubNextX;
sPrevY = pGroup->ubNextY;
sNextX = pGroup->ubSectorX;
sNextY = pGroup->ubSectorY;
}
else
{
// go to the next sector
sPrevX = pGroup->ubSectorX;
sPrevY = pGroup->ubSectorY;
sNextX = pGroup->ubNextX;
sNextY = pGroup->ubNextY;
}
// make it arrive immediately, not eventually (it's driverless)
SetGroupArrivalTime( pGroup, GetWorldTotalMin() );
// change where it is and where it's going, then make it arrive there. Don't check for battle
PlaceGroupInSector( ubGroupID, sPrevX, sPrevY, sNextX, sNextY, 0, FALSE );
}
void AddVehicleFuelToSave( )
{
INT32 iCounter;
SOLDIERTYPE *pVehicleSoldier = NULL;
for( iCounter = 0; iCounter < ubNumberOfVehicles ; iCounter++ )
{
// might have an empty slot
if( pVehicleList[ iCounter ].fValid )
{
// get the vehicle soldiertype
pVehicleSoldier = GetSoldierStructureForVehicle( iCounter );
if( pVehicleSoldier )
{
// Init fuel!
pVehicleSoldier->sBreathRed = 10000;
pVehicleSoldier->bBreath = 100;
}
}
}
}
BOOLEAN CanSoldierDriveVehicle( SOLDIERTYPE *pSoldier, INT32 iVehicleId, BOOLEAN fIgnoreAsleep )
{
Assert( pSoldier );
if ( pSoldier->bAssignment != VEHICLE )
{
// not in a vehicle!
return( FALSE );
}
if ( pSoldier->iVehicleId != iVehicleId )
{
// not in THIS vehicle!
return( FALSE );
}
if ( iVehicleId == iHelicopterVehicleId )
{
// only Skyrider can pilot the helicopter
return( FALSE );
}
if( !fIgnoreAsleep && ( pSoldier->flags.fMercAsleep == TRUE ) )
{
// asleep!
return( FALSE );
}
if( ( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) || AM_A_ROBOT( pSoldier ) || AM_AN_EPC( pSoldier ) )
{
// vehicles, robot, and EPCs can't drive!
return (FALSE);
}
// too wounded to drive
if( pSoldier->stats.bLife < OKLIFE )
{
return (FALSE);
}
// too tired to drive
if( pSoldier->bBreathMax <= BREATHMAX_ABSOLUTE_MINIMUM )
{
return (FALSE);
}
// yup, he could drive this vehicle
return( TRUE );
}
BOOLEAN SoldierMustDriveVehicle( SOLDIERTYPE *pSoldier, INT32 iVehicleId, BOOLEAN fTryingToTravel )
{
Assert( pSoldier );
// error check
if( ( iVehicleId >= ubNumberOfVehicles ) || ( iVehicleId < 0 ) )
{
return ( FALSE );
}
// if vehicle is not going anywhere, then nobody has to be driving it!
// need the path length check in case we're doing a test while actually in a sector even though we're moving!
if ( !fTryingToTravel && ( !pVehicleList[ iVehicleId ].fBetweenSectors ) && ( GetLengthOfPath( pVehicleList[ iVehicleId ].pMercPath ) == 0 ) )
{
return( FALSE );
}
// if he CAN drive it (don't care if he is currently asleep)
if ( CanSoldierDriveVehicle( pSoldier, iVehicleId, TRUE ) )
{
// and he's the ONLY one aboard who can do so
if ( OnlythisCanDriveVehicle( pSoldier, iVehicleId ) )
{
return( TRUE );
}
// (if there are multiple possible drivers, than the assumption is that this guy ISN'T driving, so he CAN sleep)
}
return( FALSE );
}
BOOLEAN OnlythisCanDriveVehicle( SOLDIERTYPE *pthis, INT32 iVehicleId )
{
INT32 iCounter = 0;
SOLDIERTYPE *pSoldier = NULL;
for( iCounter = gTacticalStatus.Team[ OUR_TEAM ].bFirstID; iCounter <= gTacticalStatus.Team[ OUR_TEAM ].bLastID; iCounter++ )
{
// get the current soldier
pSoldier = &Menptr[ iCounter ];
// skip checking THIS soldier, we wanna know about everyone else
if ( pSoldier == pthis )
{
continue;
}
if( pSoldier->bActive )
{
// don't count mercs who are asleep here
if ( CanSoldierDriveVehicle( pSoldier, iVehicleId, FALSE ) )
{
// this guy can drive it, too
return( FALSE );
}
}
}
// you're da man!
return( TRUE );
}
BOOLEAN IsSoldierInThisVehicleSquad( SOLDIERTYPE *pSoldier, INT8 bSquadNumber )
{
INT32 iVehicleId;
SOLDIERTYPE *pVehicleSoldier;
Assert( pSoldier );
Assert( ( bSquadNumber >= 0 ) && ( bSquadNumber < NUMBER_OF_SQUADS ) );
// not in a vehicle?
if( pSoldier->bAssignment != VEHICLE )
{
return( FALSE );
}
// get vehicle ID
iVehicleId = pSoldier->iVehicleId;
// if in helicopter
if ( iVehicleId == iHelicopterVehicleId )
{
// they don't get a squad #
return( FALSE );
}
pVehicleSoldier = GetSoldierStructureForVehicle( iVehicleId );
Assert( pVehicleSoldier );
// check squad vehicle is on
if ( pVehicleSoldier->bAssignment != bSquadNumber )
{
return( FALSE );
}
// yes, he's in a vehicle assigned to this squad
return( TRUE );
}
SOLDIERTYPE* PickRandomPassengerFromVehicle( SOLDIERTYPE *pSoldier )
{
// WDS - make number of mercenaries, etc. be configurable
std::vector<UINT8> ubMercsInSector (CODE_MAXIMUM_NUMBER_OF_PLAYER_SLOTS, 0);
// UINT8 ubMercsInSector[ CODE_MAXIMUM_NUMBER_OF_PLAYER_SLOTS ] = { 0 };
UINT8 ubNumMercs = 0;
UINT8 ubChosenMerc;
INT32 iCounter, iId;
// If not a vehicle, ignore!
if ( !( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) )
{
return( NULL );
}
iId = pSoldier->bVehicleID;
// Loop through passengers and update each guy's position
for( iCounter = 0; iCounter < iSeatingCapacities[ pVehicleList[ iId ].ubVehicleType ]; iCounter++ )
{
if( pVehicleList[ iId ].pPassengers[ iCounter ] != NULL )
{
ubMercsInSector[ ubNumMercs ] = (UINT8)iCounter;
ubNumMercs++;
}
}
if ( ubNumMercs > 0 )
{
ubChosenMerc = (UINT8)Random( ubNumMercs );
// If we are air raid, AND red exists somewhere...
return( pVehicleList[ iId ].pPassengers[ ubChosenMerc ] );
}
return( NULL );
}
BOOLEAN DoesVehicleHaveAnyPassengers( INT32 iVehicleID )
{
if( !GetNumberInVehicle( iVehicleID ) )
{
return FALSE;
}
return TRUE;
}
BOOLEAN DoesVehicleGroupHaveAnyPassengers( GROUP *pGroup )
{
INT32 iVehicleID;
iVehicleID = GivenMvtGroupIdFindVehicleId( pGroup->ubGroupID );
if( iVehicleID == -1 )
{
#ifdef JA2BETAVERSION
AssertMsg( iVehicleID != -1, "DoesVehicleGroupHaveAnyPassengers() for vehicle group. Invalid iVehicleID." );
#endif
return FALSE;
}
return DoesVehicleHaveAnyPassengers( iVehicleID );
}