Files
source/Tactical/Squads.cpp
T
Overhaul 7a27e7105d New attack busy system
Added missing #includes

Added LUA scripting and console

Changed the way tracers are visualized, so they work more like real tracers instead of a light fountain

Fixed signedness of many grid variables used in GetMouseMapPos calls

Fixed enemy weapon choosing:  Sometimes a mortar is chosen but later rejected, but the grenade class was not reset.  Caused assertion failure

Added checks so enemies don't try to chuck RPG grenades with their hands

Now possible to shoot a someone in the head if he's in water

Fixed InitSightArrays to also clear soldier interrupt duel points.  This was causing an assertion failure elsewhere in the code because the interrupt list still had soldiers on it sometimes when this function was called.

Soldiers are much less willing to forfeit their turn over an attempt to use more APs than they have

Removed early setting of muzzle flash.  This would allow enemies to get an interrupt before you even fired.

Fixed item dropping by AI.  If AI tried to drop something while standing it would cause deadlock

Change to greatly speed up closing the sector inventory window in an unloaded sector

Added conditional compile flag to always give robot weapon ready advantage, even for 360 degree sighting


Check builddefines.h for the conditional flags.  Of greatest interest might be LUA_CONSOLE.  This will cause the game to bring up a command console when run.  However this console is severely lacking in many areas.  If anybody knows of an open-source terminal/console that could be used instead, it would be appreciated.  The existing console does bad things when you try to close it, and since it counts as a separate app, it pauses the game while it has focus.

LUA scripting is very limited, basically just proof of concept.  There is one global variable, the Soldiers array.  An array index gives you the soldier in that slot in the currently loaded sector.  The soldier has a few things that can be accessed:  name (short name); fullname (long name); grid (current grid #, can be changed); walkto(grid) (function to walk to another grid); runto(grid) (function to run to another grid)


git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@924 3b4a5df2-a311-0410-b5c6-a8a6f20db521
2007-06-09 09:01:04 +00:00

1590 lines
38 KiB
C++

#ifdef PRECOMPILEDHEADERS
#include "Tactical All.h"
#else
#include "Types.h"
#include "Squads.h"
#include "Strategic Pathing.h"
#include "Strategicmap.h"
#include "Faces.h"
#include "Strategic Movement.h"
#include "Assignments.h"
#include "OverHead.h"
#include "RenderWorld.h"
#include "Interface.h"
#include "Vehicles.h"
#include "Map Screen Helicopter.h"
#include "Soldier Profile.h"
#include "Debug.h"
#include "jascreens.h"
#include "screenids.h"
#include "Soldier macros.h"
#endif
typedef struct
{
INT16 uiID; // The soldiers ID
INT16 sPadding[ 5 ];
// INT8 bSquadValue; // The squad id
} SAVE_SQUAD_INFO_STRUCT;
// squad array
SOLDIERTYPE *Squad[ NUMBER_OF_SQUADS ][ NUMBER_OF_SOLDIERS_PER_SQUAD ];
// list of dead guys for squads...in id values -> -1 means no one home
INT16 sDeadMercs[ NUMBER_OF_SQUADS ][ NUMBER_OF_SOLDIERS_PER_SQUAD ];
// the movement group ids
INT8 SquadMovementGroups[ NUMBER_OF_SQUADS ];
BOOLEAN fExitingVehicleToSquad = FALSE;
extern void CheckForAndAddMercToTeamPanel( SOLDIERTYPE *pSoldier );
extern void RemoveAllPlayersFromSlot( );
extern INT32 iHelicopterVehicleId;
// update current merc selected in tactical
void UpdateCurrentlySelectedMerc( SOLDIERTYPE *pSoldier, INT8 bSquadValue );
// is the passed squad between sectors?
void RebuildSquad( INT8 bSquadValue );
BOOLEAN AddDeadCharacterToSquadDeadGuys( SOLDIERTYPE *pSoldier, INT32 iSquadValue );
BOOLEAN IsDeadGuyOnAnySquad( SOLDIERTYPE *pSoldier );
INT32 iCurrentTacticalSquad = FIRST_SQUAD;
void InitSquads( void )
{
// init the squad lists to NULL ptrs.
INT32 iCounterB = 0;
INT32 iCounter =0;
GROUP *pGroup = NULL;
// null each list of ptrs.
for( iCounter = 0; iCounter < NUMBER_OF_SQUADS; iCounter++ )
{
for( iCounterB =0; iCounterB < NUMBER_OF_SOLDIERS_PER_SQUAD; iCounterB++ )
{
// squad, soldier
Squad[ iCounter ][ iCounterB ]= NULL;
}
// create mvt groups
SquadMovementGroups[ iCounter ] = CreateNewPlayerGroupDepartingFromSector( 1, 1 );
// Set persistent....
pGroup = GetGroup( SquadMovementGroups[ iCounter ] );
pGroup->fPersistant = TRUE;
}
memset( sDeadMercs, -1, sizeof( INT16 ) * NUMBER_OF_SQUADS * NUMBER_OF_SOLDIERS_PER_SQUAD );
return;
}
BOOLEAN IsThisSquadFull( INT8 bSquadValue )
{
INT32 iCounter = 0;
// run through entries in the squad list, make sure there is a free entry
for( iCounter = 0; iCounter < NUMBER_OF_SOLDIERS_PER_SQUAD; iCounter++ )
{
// check this slot
if( Squad[ bSquadValue ][ iCounter ] == NULL )
{
// a free slot found - not full
return( FALSE );
}
}
// no free slots - it's full
return( TRUE );
}
INT8 GetFirstEmptySquad( void )
{
UINT8 ubCounter = 0;
for( ubCounter = 0; ubCounter < NUMBER_OF_SQUADS; ubCounter++ )
{
if( SquadIsEmpty( ubCounter ) == TRUE )
{
// empty squad, return value
return( ubCounter );
}
}
// not found - none are completely empty (shouldn't ever happen!)
Assert( FALSE );
return( -1 );
}
BOOLEAN AddCharacterToSquad( SOLDIERTYPE *pCharacter, INT8 bSquadValue )
{
INT8 bCounter =0;
INT16 sX, sY;
INT8 bZ;
// BOOLEAN fBetweenSectors = FALSE;
GROUP *pGroup;
BOOLEAN fNewSquad;
// add character to squad...return success or failure
// run through list of people in squad, find first free slo
if( fExitingVehicleToSquad )
{
return( FALSE );
}
// ATE: If any vehicle exists in this squad AND we're not set to
// a driver or or passenger, when return false
if ( DoesVehicleExistInSquad( bSquadValue ) )
{
// We're not allowing anybody to go on a vehicle if they are not passengers!
// NB: We obviously need to make sure that REAL passengers have their
// flags set before adding them to a squad!
if ( !( pCharacter->uiStatusFlags & ( SOLDIER_PASSENGER | SOLDIER_DRIVER | SOLDIER_VEHICLE ) ) )
{
return( FALSE );
}
}
// if squad is on the move, can't add someone
if( IsThisSquadOnTheMove( bSquadValue ) == TRUE )
{
// nope, go away now
return( FALSE );
}
for( bCounter =0; bCounter < NUMBER_OF_SOLDIERS_PER_SQUAD; bCounter++ )
{
// check if on current squad and current slot?
if( Squad[ bSquadValue ][ bCounter ] == pCharacter )
{
// 'successful of sorts, if there, then he's 'added'
return ( TRUE );
}
// free slot, add here
if( Squad[ bSquadValue ][ bCounter ] == NULL )
{
// check if squad empty, if not check sector x,y,z are the same as this guys
if( SquadIsEmpty( bSquadValue ) == FALSE )
{
GetLocationOfSquad( &sX, &sY, &bZ, bSquadValue );
// if not same, return false
if( ( pCharacter->sSectorX != sX ) || ( pCharacter -> sSectorY != sY ) ||( pCharacter->bSectorZ != bZ) )
{
return ( FALSE );
}
// remove them
RemoveCharacterFromSquads( pCharacter );
// fBetweenSectors = Squad[ bSquadValue ][ 0 ]->fBetweenSectors;
}
else
{
// remove them
RemoveCharacterFromSquads( pCharacter );
}
/*
if( fBetweenSectors == TRUE )
{
pCharacter->fBetweenSectors = TRUE;
}
*/
// copy path of squad to this char
CopyPathOfSquadToCharacter( pCharacter, bSquadValue );
// check if old mvt group
if( pCharacter -> ubGroupID != 0 )
{
// in valid group, remove from that group
RemovePlayerFromGroup( pCharacter -> ubGroupID , pCharacter );
// character not on a reserved group
if( ( pCharacter->bAssignment >= ON_DUTY ) && ( pCharacter->bAssignment != VEHICLE ) )
{
// get the group from the character
pGroup = GetGroup( pCharacter -> ubGroupID );
// if valid group, delete it
if( pGroup )
{
RemoveGroupFromList( pGroup );
}
}
}
if( ( pCharacter->bAssignment == VEHICLE ) && ( pCharacter->iVehicleId == iHelicopterVehicleId ) && ( pCharacter-> iVehicleId != -1 ) )
{
// if creating a new squad from guys exiting the chopper
fNewSquad = SquadIsEmpty( bSquadValue );
RemoveSoldierFromHelicopter( pCharacter );
AddPlayerToGroup( SquadMovementGroups[ bSquadValue ], pCharacter );
SetGroupSectorValue( pCharacter->sSectorX, pCharacter->sSectorY, pCharacter->bSectorZ, SquadMovementGroups[ bSquadValue ] );
pCharacter -> ubGroupID = SquadMovementGroups[ bSquadValue ];
// if we've just started a new squad
if ( fNewSquad )
{
// set mvt group for
GROUP *pGroup;
// grab group
pGroup = GetGroup( pVehicleList[ iHelicopterVehicleId ].ubMovementGroup );
Assert( pGroup );
if( pGroup )
{
// set where it is and where it's going, then make it arrive there. Don't check for battle
PlaceGroupInSector( SquadMovementGroups[ bSquadValue ], pGroup->ubPrevX, pGroup->ubPrevY, pGroup->ubSectorX, pGroup->ubSectorY, pGroup->ubSectorZ, FALSE );
}
}
}
else if( ( pCharacter->bAssignment == VEHICLE ) && ( pCharacter-> iVehicleId != -1 ) )
{
fExitingVehicleToSquad = TRUE;
// remove from vehicle
TakeSoldierOutOfVehicle( pCharacter );
fExitingVehicleToSquad = FALSE;
AddPlayerToGroup( SquadMovementGroups[ bSquadValue ], pCharacter );
SetGroupSectorValue( pCharacter->sSectorX, pCharacter->sSectorY, pCharacter->bSectorZ, SquadMovementGroups[ bSquadValue ] );
pCharacter -> ubGroupID = SquadMovementGroups[ bSquadValue ];
}
else
{
AddPlayerToGroup( SquadMovementGroups[ bSquadValue ], pCharacter );
SetGroupSectorValue( pCharacter->sSectorX, pCharacter->sSectorY, pCharacter->bSectorZ, SquadMovementGroups[ bSquadValue ] );
pCharacter -> ubGroupID = SquadMovementGroups[ bSquadValue ];
}
// assign here
Squad[ bSquadValue ][ bCounter ] = pCharacter;
if( ( pCharacter->bAssignment != bSquadValue ) )
{
// check to see if we should wake them up
if ( pCharacter->fMercAsleep )
{
// try to wake him up
SetMercAwake( pCharacter, FALSE, FALSE );
}
SetTimeOfAssignmentChangeForMerc( pCharacter );
}
// set squad value
ChangeSoldiersAssignment( pCharacter, bSquadValue );
if ( pCharacter->bOldAssignment < ON_DUTY )
{
pCharacter->bOldAssignment = bSquadValue;
}
// if current tactical sqaud...upadte panel
if( NumberOfPeopleInSquad( ( INT8 )iCurrentTacticalSquad ) == 0 )
{
SetCurrentSquad( bSquadValue, TRUE );
}
if( bSquadValue == ( INT8 ) iCurrentTacticalSquad )
{
CheckForAndAddMercToTeamPanel( Squad[ iCurrentTacticalSquad ][ bCounter ] );
}
if ( pCharacter->ubID == gusSelectedSoldier )
{
SetCurrentSquad( bSquadValue, TRUE );
}
return ( TRUE );
}
}
return ( FALSE );
}
// find the first slot we can fit the guy in
BOOLEAN AddCharacterToAnySquad( SOLDIERTYPE *pCharacter )
{
// add character to any squad, if character is assigned to a squad, returns TRUE
INT8 bCounter = 0;
INT8 bFirstEmptySquad = -1;
// remove them from current squad
RemoveCharacterFromSquads( pCharacter );
// first look for a compatible NON-EMPTY squad (don't start new squad if we don't have to)
for( bCounter = 0; bCounter < NUMBER_OF_SQUADS; bCounter++ )
{
if( SquadIsEmpty( bCounter ) == FALSE )
{
if( AddCharacterToSquad( pCharacter, bCounter ) == TRUE )
{
return ( TRUE );
}
}
else
{
if ( bFirstEmptySquad == -1 )
{
bFirstEmptySquad = bCounter;
}
}
}
// no non-empty compatible squads were found
// try the first empty one (and there better be one)
if ( bFirstEmptySquad != -1 )
{
if( AddCharacterToSquad( pCharacter, bFirstEmptySquad ) == TRUE )
{
return ( TRUE );
}
}
// should never happen!
Assert( FALSE );
return( FALSE );
}
// find the first slot we can fit the guy in
INT8 AddCharacterToUniqueSquad( SOLDIERTYPE *pCharacter )
{
// add character to any squad, if character is assigned to a squad, returns TRUE
INT8 bCounter = 0;
// check if character on a squad
// remove them
RemoveCharacterFromSquads( pCharacter );
for( bCounter = 0; bCounter < NUMBER_OF_SQUADS; bCounter++ )
{
if( SquadIsEmpty( bCounter ) == TRUE )
{
if( AddCharacterToSquad( pCharacter, bCounter ) == TRUE )
{
return ( bCounter );
}
}
}
return( -1 );
}
BOOLEAN SquadIsEmpty( INT8 bSquadValue )
{
// run through this squad's slots and find if they ALL are empty
INT32 iCounter = 0;
for( iCounter = 0; iCounter < NUMBER_OF_SOLDIERS_PER_SQUAD ; iCounter++ )
{
if( Squad[ bSquadValue ][ iCounter ] != NULL )
{
return ( FALSE );
}
}
return( TRUE );
}
// find and remove characters from any squad
BOOLEAN RemoveCharacterFromSquads( SOLDIERTYPE *pCharacter )
{
INT32 iCounterA = 0;
INT32 iCounter = 0;
UINT8 ubGroupId = 0;
// find character and remove.. check characters in all squads
// squad?
for( iCounterA = 0; iCounterA < NUMBER_OF_SQUADS ; iCounterA++ )
{
// slot?
for( iCounter = 0; iCounter < NUMBER_OF_SOLDIERS_PER_SQUAD ; iCounter++ )
{
// check if on current squad and current slot?
if( Squad[ iCounterA ][ iCounter ] == pCharacter )
{
// found and nulled
Squad[ iCounterA ][ iCounter ] = NULL;
// Release memory for his personal path, BUT DON'T CLEAR HIS GROUP'S PATH/WAYPOINTS (pass in groupID -1).
// Just because one guy leaves a group is no reason to cancel movement for the rest of the group.
pCharacter -> pMercPath = ClearStrategicPathList( pCharacter -> pMercPath, -1 );
// remove character from mvt group
RemovePlayerFromGroup( SquadMovementGroups[ iCounterA ], pCharacter );
// reset player mvt group id value
pCharacter -> ubGroupID = 0;
if( ( pCharacter->fBetweenSectors )&&( pCharacter-> uiStatusFlags & SOLDIER_VEHICLE ) )
{
ubGroupId = CreateNewPlayerGroupDepartingFromSector( ( INT8 ) ( pCharacter -> sSectorX ) , ( INT8 ) ( pCharacter -> sSectorY ) );
// assign to a group
AddPlayerToGroup( ubGroupId, pCharacter );
}
RebuildSquad( ( INT8 )iCounterA );
if( pCharacter->bLife == 0 )
{
AddDeadCharacterToSquadDeadGuys( pCharacter, iCounterA );
}
//if we are not loading a saved game
if( !(gTacticalStatus.uiFlags & LOADING_SAVED_GAME ) && guiCurrentScreen == GAME_SCREEN )
{
UpdateCurrentlySelectedMerc( pCharacter, ( INT8 )iCounterA );
}
return ( TRUE );
}
}
}
// not found
return ( FALSE );
}
BOOLEAN RemoveCharacterFromASquad( SOLDIERTYPE *pCharacter, INT8 bSquadValue )
{
INT32 iCounter =0, iCounterA = 0;
// remove character from particular squad..return if successful
for( iCounter = 0; iCounter < NUMBER_OF_SOLDIERS_PER_SQUAD ; iCounter++ )
{
// check if on current squad and current slot?
if( Squad[ bSquadValue ][ iCounter ] == pCharacter )
{
UpdateCurrentlySelectedMerc( pCharacter, bSquadValue );
// found and nulled
Squad[ bSquadValue ][ iCounter ] = NULL;
// remove character from mvt group
RemovePlayerFromGroup( SquadMovementGroups[ bSquadValue ], pCharacter );
if( pCharacter->bLife == 0 )
{
AddDeadCharacterToSquadDeadGuys( pCharacter, iCounterA );
}
RebuildSquad( bSquadValue );
// found
return ( TRUE );
}
}
// not found
return ( FALSE );
}
BOOLEAN IsCharacterInSquad( SOLDIERTYPE *pCharacter, INT8 bSquadValue )
{
INT32 iCounter =0;
// find character in particular squad..return if successful
for( iCounter = 0; iCounter < NUMBER_OF_SOLDIERS_PER_SQUAD ; iCounter++ )
{
// check if on current squad and current slot?
if( Squad[ bSquadValue ][ iCounter ] == pCharacter )
{
// found
return ( TRUE );
}
}
// not found
return ( FALSE );
}
INT8 SlotCharacterIsInSquad( SOLDIERTYPE *pCharacter, INT8 bSquadValue )
{
INT8 bCounter =0;
// find character in particular squad..return slot if successful, else -1
for( bCounter = 0; bCounter < NUMBER_OF_SOLDIERS_PER_SQUAD ; bCounter++ )
{
// check if on current squad and current slot?
if( Squad[ bSquadValue ][ bCounter ] == pCharacter )
{
// found
return ( bCounter );
}
}
// not found
return ( -1 );
}
INT8 SquadCharacterIsIn( SOLDIERTYPE *pCharacter )
{
// returns which squad character is in, -1 if none found
INT8 iCounterA =0, iCounter = 0;
// squad?
for( iCounterA = 0; iCounterA < NUMBER_OF_SQUADS ; iCounterA++ )
{
// slot?
for( iCounter = 0; iCounter < NUMBER_OF_SOLDIERS_PER_SQUAD ; iCounter++ )
{
// check if on current squad and current slot?
if( Squad[ iCounterA ][ iCounter ] == pCharacter )
{
// return value
return ( iCounterA );
}
}
}
// return failure
return ( -1 );
}
INT8 NumberOfPeopleInSquad( INT8 bSquadValue )
{
INT8 bCounter = 0;
INT8 bSquadCount = 0;
if( bSquadValue == NO_CURRENT_SQUAD )
{
return( 0 );
}
// find number of characters in particular squad.
for( bCounter = 0; bCounter < NUMBER_OF_SOLDIERS_PER_SQUAD ; bCounter++ )
{
// valid slot?
if( Squad[ bSquadValue ][ bCounter ] != NULL )
{
// yep
bSquadCount++;
}
}
// return number found
return( bSquadCount );
}
INT8 NumberOfNonEPCsInSquad( INT8 bSquadValue )
{
INT8 bCounter = 0;
INT8 bSquadCount = 0;
if( bSquadValue == NO_CURRENT_SQUAD )
{
return( 0 );
}
// find number of characters in particular squad.
for( bCounter = 0; bCounter < NUMBER_OF_SOLDIERS_PER_SQUAD ; bCounter++ )
{
// valid slot?
if( Squad[ bSquadValue ][ bCounter ] != NULL && !AM_AN_EPC( Squad[ bSquadValue ][ bCounter ] ) )
{
// yep
bSquadCount++;
}
}
// return number found
return( bSquadCount );
}
BOOLEAN IsRobotControllerInSquad( INT8 bSquadValue )
{
INT8 bCounter = 0;
if( bSquadValue == NO_CURRENT_SQUAD )
{
return( 0 );
}
// find number of characters in particular squad.
for( bCounter = 0; bCounter < NUMBER_OF_SOLDIERS_PER_SQUAD ; bCounter++ )
{
// valid slot?
if ( ( Squad[ bSquadValue ][ bCounter ] != NULL ) && ControllingRobot( Squad[ bSquadValue ][ bCounter ] ) )
{
// yep
return( TRUE );
}
}
// return number found
return( FALSE );
}
BOOLEAN SectorSquadIsIn(INT8 bSquadValue, INT16 *sMapX, INT16 *sMapY, INT16 *sMapZ )
{
// returns if there is anyone on the squad and what sector ( strategic ) they are in
INT8 bCounter =0;
Assert( bSquadValue < ON_DUTY );
for( bCounter = 0; bCounter < NUMBER_OF_SOLDIERS_PER_SQUAD ; bCounter++ )
{
// if valid soldier, get current sector and return
if( Squad[ bSquadValue ][ bCounter ] != NULL )
{
*sMapX = Squad[ bSquadValue ][ bCounter ] -> sSectorX;
*sMapY = Squad[ bSquadValue ][ bCounter ] -> sSectorY;
*sMapZ = ( INT16 )Squad[ bSquadValue ][ bCounter ] -> bSectorZ;
return ( TRUE );
}
}
// return there is no squad
return ( FALSE );
}
BOOLEAN CopyPathOfSquadToCharacter( SOLDIERTYPE *pCharacter, INT8 bSquadValue )
{
// copy path from squad to character
INT8 bCounter = 0;
for( bCounter = 0; bCounter < NUMBER_OF_SOLDIERS_PER_SQUAD ; bCounter++ )
{
if( ( Squad[ bSquadValue ][ bCounter ] != pCharacter ) &&( Squad[ bSquadValue ][ bCounter ] != NULL ) )
{
// valid character, copy paths
pCharacter -> pMercPath = CopyPaths( Squad[ bSquadValue ][ bCounter ] -> pMercPath, pCharacter -> pMercPath);
// return success
return ( TRUE );
}
}
// return failure
return ( FALSE );
}
BOOLEAN CopyPathOfCharacterToSquad( SOLDIERTYPE *pCharacter, INT8 bSquadValue )
{
// copy path of this character to members of squad
BOOLEAN fSuccess = FALSE;
INT8 bCounter =0;
// anyone else on squad?
if( NumberOfPeopleInSquad( bSquadValue ) < 2)
{
// nope
// return failure
return ( FALSE );
}
// copy each person on squad, skip this character
for( bCounter = 0; bCounter < NUMBER_OF_SOLDIERS_PER_SQUAD ; bCounter++ )
{
if( ( Squad[ bSquadValue ][ bCounter ] != pCharacter ) &&( Squad[ bSquadValue ][ bCounter ] != NULL ) )
{
// valid character, copy paths
// first empty path
Squad[ bSquadValue ][ bCounter ] -> pMercPath = ClearStrategicPathList( Squad[ bSquadValue ][ bCounter ] -> pMercPath, -1 );
// then copy
Squad[ bSquadValue ][ bCounter ] -> pMercPath = CopyPaths( pCharacter -> pMercPath, Squad[ bSquadValue ][ bCounter ] -> pMercPath );
// successful at least once
fSuccess = TRUE;
}
}
// return success?
return ( fSuccess );
}
INT32 CurrentSquad( void )
{
// returns which squad is current squad
return( iCurrentTacticalSquad );
}
BOOLEAN SetCurrentSquad( INT32 iCurrentSquad, BOOLEAN fForce )
{
// set the current tactical squad
INT32 iCounter = 0;
// ARM: can't call SetCurrentSquad() in mapscreen, it calls SelectSoldier(), that will initialize interface panels!!!
// ATE: Adjusted conditions a bit ( sometimes were not getting selected )
if ( guiCurrentScreen == LAPTOP_SCREEN || guiCurrentScreen == MAP_SCREEN )
{
return( FALSE );
}
// ATE; Added to allow us to have NO current squad
if ( iCurrentSquad == NO_CURRENT_SQUAD )
{
// set current squad and return success
iCurrentTacticalSquad = iCurrentSquad;
// cleat list
RemoveAllPlayersFromSlot( );
// set all auto faces inactive
SetAllAutoFacesInactive( );
return( FALSE );
}
// check if valid value passed
if( ( iCurrentSquad >= NUMBER_OF_SQUADS )||( iCurrentSquad < 0 ) )
{
// no
return ( FALSE );
}
// check if squad is current
if( iCurrentSquad == iCurrentTacticalSquad && !fForce )
{
return ( TRUE );
}
// set current squad and return success
iCurrentTacticalSquad = iCurrentSquad;
// cleat list
RemoveAllPlayersFromSlot( );
// set all auto faces inactive
SetAllAutoFacesInactive( );
if( iCurrentTacticalSquad != NO_CURRENT_SQUAD )
{
for( iCounter = 0; iCounter < NUMBER_OF_SOLDIERS_PER_SQUAD; iCounter++ )
{
if( Squad[ iCurrentTacticalSquad ][ iCounter ] != NULL )
{
// squad set, now add soldiers in
CheckForAndAddMercToTeamPanel( Squad[ iCurrentTacticalSquad ][ iCounter ] );
}
}
}
// check if the currently selected guy is on this squad, if not, get the first one on the new squad
if ( gusSelectedSoldier != NO_SOLDIER )
{
if( Menptr[ gusSelectedSoldier ].bAssignment != iCurrentTacticalSquad )
{
// ATE: Changed this to FALSE for ackoledgement sounds.. sounds bad if just starting/entering sector..
SelectSoldier( Squad[ iCurrentTacticalSquad ][ 0 ]->ubID, FALSE, TRUE );
}
}
else
{
// ATE: Changed this to FALSE for ackoledgement sounds.. sounds bad if just starting/entering sector..
SelectSoldier( Squad[ iCurrentTacticalSquad ][ 0 ]->ubID, FALSE, TRUE );
}
return ( TRUE );
}
void RebuildCurrentSquad( void )
{
// rebuilds current squad to reset faces in tactical
INT32 iCounter = 0;
INT32 iCount = 0;
SOLDIERTYPE *pDeadSoldier = NULL;
// check if valid value passed
if( ( iCurrentTacticalSquad >= NUMBER_OF_SQUADS ) || ( iCurrentTacticalSquad < 0 ) )
{
// no
return;
}
// set default squad..just inc ase we no longer have a valid squad
SetDefaultSquadOnSectorEntry( TRUE );
// cleat list
RemoveAllPlayersFromSlot( );
// set all auto faces inactive
SetAllAutoFacesInactive( );
gfPausedTacticalRenderInterfaceFlags = DIRTYLEVEL2;
if( iCurrentTacticalSquad != NO_CURRENT_SQUAD )
{
for( iCounter = 0; iCounter < NUMBER_OF_SOLDIERS_PER_SQUAD; iCounter++ )
{
if( Squad[ iCurrentTacticalSquad ][ iCounter ] != NULL )
{
// squad set, now add soldiers in
CheckForAndAddMercToTeamPanel( Squad[ iCurrentTacticalSquad ][ iCounter ] );
}
}
for( iCounter = 0; iCounter < NUMBER_OF_SOLDIERS_PER_SQUAD; iCounter++ )
{
if( sDeadMercs[ iCurrentTacticalSquad ][ iCounter ] != -1 )
{
pDeadSoldier = FindSoldierByProfileID( ( UINT8 )( sDeadMercs[ iCurrentTacticalSquad ][ iCounter ] ), TRUE );
if( pDeadSoldier )
{
// squad set, now add soldiers in
CheckForAndAddMercToTeamPanel( pDeadSoldier );
}
}
}
}
}
void ExamineCurrentSquadLights( void )
{
// rebuilds current squad to reset faces in tactical
INT32 iCounter = 0;
UINT8 ubLoop;
// OK, we should add lights for any guy currently bInSector who is not bad OKLIFE...
ubLoop = gTacticalStatus.Team[ gbPlayerNum ].bFirstID;
for ( ; ubLoop <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; ubLoop++)
{
if ( MercPtrs[ ubLoop ]->bInSector && MercPtrs[ ubLoop ]->bLife >= OKLIFE )
{
PositionSoldierLight( MercPtrs[ ubLoop ] );
}
}
// check if valid value passed
//if( ( iCurrentTacticalSquad >= NUMBER_OF_SQUADS ) || ( iCurrentTacticalSquad < 0 ) )
//{
// no
// return;
//}
//for( iCounter = 0; iCounter < NUMBER_OF_SOLDIERS_PER_SQUAD; iCounter++ )
//{
// if( Squad[ iCurrentTacticalSquad ][ iCounter ] != NULL )
// {
// PositionSoldierLight( Squad[ iCurrentTacticalSquad ][ iCounter ] );
// }
//}
}
BOOLEAN GetSoldiersInSquad( INT32 iCurrentSquad, SOLDIERTYPE *pSoldierArray[] )
{
INT32 iCounter = 0;
// will get the soldiertype pts for every merc in this squad
// check if valid value passed
if( ( iCurrentSquad >= NUMBER_OF_SQUADS ) || ( iCurrentSquad < 0 ) )
{
// no
return ( FALSE );
}
// copy pts values over
for( iCounter = 0; iCounter < NUMBER_OF_SOLDIERS_PER_SQUAD; iCounter++ )
{
pSoldierArray[ iCounter ] = Squad[ iCurrentSquad ][ iCounter ];
}
return ( TRUE );
}
BOOLEAN IsSquadOnCurrentTacticalMap( INT32 iCurrentSquad )
{
INT32 iCounter = 0;
// check to see if this squad is on the current map
// check if valid value passed
if( ( iCurrentSquad >= NUMBER_OF_SQUADS ) || ( iCurrentSquad < 0 ) )
{
// no
return ( FALSE );
}
// go through memebrs of squad...if anyone on this map, return true
for( iCounter = 0; iCounter < NUMBER_OF_SOLDIERS_PER_SQUAD; iCounter++ )
{
if( Squad[ iCurrentSquad ][ iCounter ] != NULL )
{
// ATE; Added more checks here for being in sector ( fBetweenSectors and SectorZ )
if( ( Squad[ iCurrentSquad ][ iCounter ]->sSectorX == gWorldSectorX ) && ( Squad[ iCurrentSquad ][ iCounter ]->sSectorY == gWorldSectorY ) && Squad[ iCurrentSquad ][ iCounter ]->bSectorZ == gbWorldSectorZ && Squad[ iCurrentSquad ][ iCounter ]->fBetweenSectors != TRUE )
{
return( TRUE );
}
}
}
return( FALSE );
}
void SetDefaultSquadOnSectorEntry( BOOLEAN fForce )
{
INT32 iCounter = 0;
// check if selected squad is in current sector, if so, do nothing, if not...first first case that they are
if( IsSquadOnCurrentTacticalMap( iCurrentTacticalSquad ) == TRUE )
{
// is in sector, leave
return;
}
//otherwise...
// find first squad availiable
for( iCounter = 0; iCounter < NUMBER_OF_SQUADS; iCounter++ )
{
if( IsSquadOnCurrentTacticalMap( iCounter ) == TRUE )
{
// squad in sector...set as current
SetCurrentSquad( iCounter, fForce );
return;
}
}
// If here, set to no current squad
SetCurrentSquad( NO_CURRENT_SQUAD, FALSE );
return;
}
INT32 GetLastSquadActive( void )
{
// find id of last squad in the list with active mercs in it
INT32 iCounter =0, iCounterB = 0;
INT32 iLastSquad = 0;
for( iCounter = 0; iCounter < NUMBER_OF_SQUADS; iCounter++ )
{
for( iCounterB = 0; iCounterB < NUMBER_OF_SOLDIERS_PER_SQUAD; iCounterB++ )
{
if( Squad[ iCounter ][ iCounterB ] != NULL )
{
iLastSquad = iCounter;
}
}
}
return ( iLastSquad );
}
void GetSquadPosition( UINT8 *ubNextX, UINT8 *ubNextY, UINT8 *ubPrevX, UINT8 *ubPrevY, UINT32 *uiTraverseTime, UINT32 *uiArriveTime, UINT8 ubSquadValue )
{
// grab the mvt group for this squad and find all this information
if( SquadMovementGroups[ ubSquadValue ] == 0 )
{
*ubNextX = 0;
*ubNextY = 0;
*ubPrevX = 0;
*ubPrevY = 0;
*uiTraverseTime = 0;
*uiArriveTime = 0;
return;
}
// grab this squads mvt position
GetGroupPosition( ubNextX, ubNextY, ubPrevX, ubPrevY, uiTraverseTime, uiArriveTime, SquadMovementGroups[ ubSquadValue ] );
return;
}
void SetSquadPositionBetweenSectors( UINT8 ubNextX, UINT8 ubNextY, UINT8 ubPrevX, UINT8 ubPrevY, UINT32 uiTraverseTime, UINT32 uiArriveTime, UINT8 ubSquadValue )
{
// set mvt group position for squad for
if( SquadMovementGroups[ ubSquadValue ] == 0 )
{
return;
}
SetGroupPosition( ubNextX, ubNextY, ubPrevX, ubPrevY, uiTraverseTime, uiArriveTime, SquadMovementGroups[ ubSquadValue ] );
return;
}
BOOLEAN SaveSquadInfoToSavedGameFile( HWFILE hFile )
{
SAVE_SQUAD_INFO_STRUCT sSquadSaveStruct[ NUMBER_OF_SQUADS ][ NUMBER_OF_SOLDIERS_PER_SQUAD ];
UINT32 uiNumBytesWritten = 0;
UINT32 uiSaveSize=0;
//Reset the current squad info
INT32 iCounterB = 0;
INT32 iCounter =0;
for( iCounter = 0; iCounter < NUMBER_OF_SQUADS; iCounter++ )
{
for( iCounterB =0; iCounterB < NUMBER_OF_SOLDIERS_PER_SQUAD; iCounterB++ )
{
if( Squad[ iCounter ][ iCounterB ] )
sSquadSaveStruct[ iCounter ][ iCounterB ].uiID = Squad[ iCounter ][ iCounterB ]->ubID;
else
sSquadSaveStruct[ iCounter ][ iCounterB ].uiID = -1;
}
}
//Save the squad info to the Saved Game File
uiSaveSize = sizeof( SAVE_SQUAD_INFO_STRUCT ) * NUMBER_OF_SQUADS * NUMBER_OF_SOLDIERS_PER_SQUAD;
FileWrite( hFile, sSquadSaveStruct, uiSaveSize, &uiNumBytesWritten );
if( uiNumBytesWritten != uiSaveSize )
{
return(FALSE);
}
//Save all the squad movement id's
FileWrite( hFile, SquadMovementGroups, sizeof( INT8 ) * NUMBER_OF_SQUADS, &uiNumBytesWritten );
if( uiNumBytesWritten != sizeof( INT8 ) * NUMBER_OF_SQUADS )
{
return(FALSE);
}
return( TRUE );
}
BOOLEAN LoadSquadInfoFromSavedGameFile( HWFILE hFile )
{
SAVE_SQUAD_INFO_STRUCT sSquadSaveStruct[ NUMBER_OF_SQUADS ][ NUMBER_OF_SOLDIERS_PER_SQUAD ];
UINT32 uiNumBytesRead=0;
UINT32 uiSaveSize=0;
//Reset the current squad info
INT32 iCounterB = 0;
INT32 iCounter =0;
// null each list of ptrs.
for( iCounter = 0; iCounter < NUMBER_OF_SQUADS; iCounter++ )
{
for( iCounterB =0; iCounterB < NUMBER_OF_SOLDIERS_PER_SQUAD; iCounterB++ )
{
// squad, soldier
Squad[ iCounter ][ iCounterB ]= NULL;
}
}
// Load in the squad info
uiSaveSize = sizeof( SAVE_SQUAD_INFO_STRUCT ) * NUMBER_OF_SQUADS * NUMBER_OF_SOLDIERS_PER_SQUAD;
FileRead( hFile, sSquadSaveStruct, uiSaveSize, &uiNumBytesRead );
if( uiNumBytesRead != uiSaveSize )
{
return(FALSE);
}
// Loop through the array loaded in
for( iCounter = 0; iCounter < NUMBER_OF_SQUADS; iCounter++ )
{
for( iCounterB =0; iCounterB < NUMBER_OF_SOLDIERS_PER_SQUAD; iCounterB++ )
{
if( sSquadSaveStruct[ iCounter ][ iCounterB ].uiID != -1 )
Squad[ iCounter ][ iCounterB ] = &Menptr[ sSquadSaveStruct[ iCounter ][ iCounterB ].uiID ];
else
Squad[ iCounter ][ iCounterB ] = NULL;
}
}
//Load in the Squad movement id's
FileRead( hFile, SquadMovementGroups, sizeof( INT8 ) * NUMBER_OF_SQUADS, &uiNumBytesRead );
if( uiNumBytesRead != sizeof( INT8 ) * NUMBER_OF_SQUADS )
{
return(FALSE);
}
return( TRUE );
}
void GetLocationOfSquad( INT16 *sX, INT16 *sY, INT8 *bZ, INT8 bSquadValue )
{
// run through list of guys, once valid merc found, get his sector x and y and z
INT32 iCounter = 0;
for( iCounter = 0; iCounter < NUMBER_OF_SOLDIERS_PER_SQUAD; iCounter++ )
{
if( Squad[ bSquadValue ][ iCounter ] )
{
// valid guy
*sX = Squad[ bSquadValue ][ iCounter ]->sSectorX;
*sY = Squad[ bSquadValue ][ iCounter ]->sSectorY;
*bZ = Squad[ bSquadValue ][ iCounter ]->bSectorZ;
}
}
return;
}
BOOLEAN IsThisSquadOnTheMove( INT8 bSquadValue )
{
INT32 iCounter = 0;
for( iCounter = 0; iCounter < NUMBER_OF_SOLDIERS_PER_SQUAD; iCounter++ )
{
if( Squad[ bSquadValue ][ iCounter ] )
{
return( Squad[ bSquadValue ][ iCounter ]->fBetweenSectors );
}
}
return( FALSE );
}
// rebuild this squad after someone has been removed, to 'squeeze' together any empty spots
void RebuildSquad( INT8 bSquadValue )
{
INT32 iCounter = 0, iCounterB = 0;
for( iCounterB = 0; iCounterB <NUMBER_OF_SOLDIERS_PER_SQUAD - 1; iCounterB++ )
{
for( iCounter = 0 ;iCounter < NUMBER_OF_SOLDIERS_PER_SQUAD - 1; iCounter++ )
{
if( Squad[ bSquadValue ][ iCounter ] == NULL )
{
if( Squad[ bSquadValue ][ iCounter + 1 ] != NULL )
{
Squad[ bSquadValue ][ iCounter ] = Squad[ bSquadValue ][ iCounter + 1 ];
Squad[ bSquadValue ][ iCounter + 1 ] = NULL;
}
}
}
}
return;
}
void UpdateCurrentlySelectedMerc( SOLDIERTYPE *pSoldier, INT8 bSquadValue )
{
UINT8 ubID;
// if this squad is the current one and and the psoldier is the currently selected soldier, get rid of 'em
if( bSquadValue != iCurrentTacticalSquad )
{
return;
}
// Are we the selected guy?
if( gusSelectedSoldier == pSoldier->ubID )
{
ubID = FindNextActiveAndAliveMerc( pSoldier, FALSE, FALSE );
if ( ubID != NOBODY && ubID != gusSelectedSoldier )
{
SelectSoldier( ubID, FALSE, FALSE );
}
else
{
gusSelectedSoldier = NOBODY;
// ATE: Make sure we are in TEAM panel at this point!
SetCurrentInterfacePanel( TEAM_PANEL );
}
}
return;
}
BOOLEAN IsSquadInSector( SOLDIERTYPE *pSoldier, UINT8 ubSquad )
{
if( pSoldier == NULL )
{
return( FALSE );
}
if( pSoldier->fBetweenSectors == TRUE )
{
return( FALSE );
}
if( pSoldier->bAssignment == IN_TRANSIT )
{
return( FALSE );
}
if( pSoldier->bAssignment == ASSIGNMENT_POW )
{
return( FALSE );
}
if( SquadIsEmpty( ubSquad ) == TRUE )
{
return( TRUE );
}
if( ( pSoldier->sSectorX != Squad[ ubSquad ][ 0 ]->sSectorX ) ||( pSoldier->sSectorY != Squad[ ubSquad ][ 0 ]->sSectorY ) || ( pSoldier->bSectorZ != Squad[ ubSquad ][ 0 ]->bSectorZ ) )
{
return( FALSE );
}
if( Squad[ ubSquad ][ 0 ]->fBetweenSectors == TRUE )
{
return( FALSE );
}
return( TRUE );
}
BOOLEAN IsAnyMercOnSquadAsleep( UINT8 ubSquadValue )
{
INT32 iCounter = 0;
if( SquadIsEmpty( ubSquadValue ) == TRUE )
{
return( FALSE );
}
for( iCounter = 0 ;iCounter < NUMBER_OF_SOLDIERS_PER_SQUAD - 1; iCounter++ )
{
if( Squad[ ubSquadValue ][ iCounter ] != NULL )
{
if( Squad[ ubSquadValue ][ iCounter ]-> fMercAsleep )
{
return( TRUE );
}
}
}
return( FALSE );
}
BOOLEAN AddDeadCharacterToSquadDeadGuys( SOLDIERTYPE *pSoldier, INT32 iSquadValue )
{
INT32 iCounter = 0;
SOLDIERTYPE *pTempSoldier = NULL;
// is dead guy in any squad
if( IsDeadGuyOnAnySquad( pSoldier ) == TRUE )
{
return( TRUE );
}
// first find out if the guy is in the list
for( iCounter = 0; iCounter < NUMBER_OF_SOLDIERS_PER_SQUAD; iCounter++ )
{
// valid soldier?
if( sDeadMercs[ iSquadValue ][ iCounter ] != -1 )
{
pTempSoldier = FindSoldierByProfileID( ( UINT8 )( sDeadMercs[ iSquadValue ][ iCounter ] ), TRUE );
if( pSoldier == pTempSoldier )
{
return( TRUE );
}
}
}
// now insert the guy
for( iCounter = 0; iCounter < NUMBER_OF_SOLDIERS_PER_SQUAD; iCounter++ )
{
// valid soldier?
if( sDeadMercs[ iSquadValue ][ iCounter ] != -1 )
{
// yep
pTempSoldier = FindSoldierByProfileID( ( UINT8 )( sDeadMercs[ iSquadValue ][ iCounter ] ), TRUE );
// valid soldier?
if( pTempSoldier == NULL )
{
// nope
sDeadMercs[ iSquadValue ][ iCounter ] = pSoldier->ubProfile;
return( TRUE );
}
}
else
{
// nope
sDeadMercs[ iSquadValue ][ iCounter ] = pSoldier->ubProfile;
return( TRUE );
}
}
// no go
return( FALSE );
}
BOOLEAN IsDeadGuyOnAnySquad( SOLDIERTYPE *pSoldier )
{
INT32 iCounterA = 0, iCounter = 0;
// squad?
for( iCounterA = 0; iCounterA < NUMBER_OF_SQUADS; iCounterA++ )
{
// slot?
for( iCounter = 0; iCounter < NUMBER_OF_SOLDIERS_PER_SQUAD; iCounter++ )
{
if( sDeadMercs[ iCounterA ][ iCounter ] == pSoldier->ubProfile )
{
return( TRUE );
}
}
}
return ( FALSE );
}
BOOLEAN IsDeadGuyInThisSquadSlot( INT8 bSlotId, INT8 bSquadValue , INT8 *bNumberOfDeadGuysSoFar )
{
INT32 iCounter = 0, iCount = 0;
// see if we have gone too far?
if( bSlotId < *bNumberOfDeadGuysSoFar )
{
// reset
*bNumberOfDeadGuysSoFar = 0;
}
for( iCounter = 0; iCounter < NUMBER_OF_SOLDIERS_PER_SQUAD; iCounter++ )
{
if( sDeadMercs[ bSquadValue ][ iCounter ] != -1 )
{
// not gone far enough yet
if( *bNumberOfDeadGuysSoFar > iCounter )
{
iCount++;
}
else
{
// far enough, start checking
bNumberOfDeadGuysSoFar++;
return( TRUE );
}
}
}
return( FALSE );
}
BOOLEAN SoldierIsDeadAndWasOnSquad( SOLDIERTYPE *pSoldier, INT8 bSquadValue )
{
INT32 iCounter = 0;
if( bSquadValue == NO_CURRENT_SQUAD )
{
return( FALSE );
}
// check if guy is on squad
for( iCounter = 0; iCounter < NUMBER_OF_SOLDIERS_PER_SQUAD; iCounter++ )
{
if( pSoldier->ubProfile == sDeadMercs[ bSquadValue ][ iCounter ] )
{
return( TRUE );
}
}
return( FALSE );
}
BOOLEAN ResetDeadSquadMemberList( INT32 iSquadValue )
{
memset( sDeadMercs[ iSquadValue ], -1, sizeof( INT16 ) * NUMBER_OF_SOLDIERS_PER_SQUAD );
return( TRUE );
}
// this passed soldier on the current squad int he tactical map
BOOLEAN IsMercOnCurrentSquad( SOLDIERTYPE *pSoldier )
{
INT32 iCounter = 0;
// valid soldier?
if( pSoldier == NULL )
{
// no
return( FALSE );
}
// active grunt?
if( pSoldier->bActive == FALSE )
{
// no
return( FALSE );
}
// current squad valid?
if( iCurrentTacticalSquad >= NUMBER_OF_SQUADS )
{
// no
return( FALSE );
}
for( iCounter = 0; iCounter < NUMBER_OF_SOLDIERS_PER_SQUAD; iCounter++ )
{
if( Squad[ iCurrentTacticalSquad ][ iCounter ] == pSoldier )
{
// found him
return( TRUE );
}
}
return( FALSE );
}
INT8 NumberOfPlayerControllableMercsInSquad( INT8 bSquadValue )
{
SOLDIERTYPE *pSoldier;
INT8 bCounter = 0;
INT8 bSquadCount = 0;
if( bSquadValue == NO_CURRENT_SQUAD )
{
return( 0 );
}
// find number of characters in particular squad.
for( bCounter = 0; bCounter < NUMBER_OF_SOLDIERS_PER_SQUAD ; bCounter++ )
{
// valid slot?
if( Squad[ bSquadValue ][ bCounter ] != NULL )
{
// yep
pSoldier = Squad[ bSquadValue ][ bCounter ] ;
//Kris: This breaks the CLIENT of this function, tactical traversal. Do NOT check for EPCS or ROBOT here.
//if ( !AM_AN_EPC( pSoldier ) && !AM_A_ROBOT( pSoldier ) &&
if( !( pSoldier->uiStatusFlags & SOLDIER_VEHICLE ) )
{
bSquadCount++;
}
}
}
// return number found
return( bSquadCount );
}
BOOLEAN DoesVehicleExistInSquad( INT8 bSquadValue )
{
SOLDIERTYPE *pSoldier;
INT8 bCounter = 0;
INT8 bSquadCount = 0;
if( bSquadValue == NO_CURRENT_SQUAD )
{
return( FALSE );
}
// find number of characters in particular squad.
for( bCounter = 0; bCounter < NUMBER_OF_SOLDIERS_PER_SQUAD ; bCounter++ )
{
// valid slot?
if( Squad[ bSquadValue ][ bCounter ] != NULL )
{
// yep
pSoldier = Squad[ bSquadValue ][ bCounter ] ;
// If we are an EPC or ROBOT, don't allow this
if ( ( pSoldier->uiStatusFlags & SOLDIER_VEHICLE ) )
{
return( TRUE );
}
}
}
return(FALSE );
}
void CheckSquadMovementGroups( void )
{
INT32 iSquad;
GROUP * pGroup;
for( iSquad = 0; iSquad < NUMBER_OF_SQUADS; iSquad++ )
{
pGroup = GetGroup( SquadMovementGroups[ iSquad ] );
if ( pGroup == NULL )
{
// recreate group
SquadMovementGroups[ iSquad ] = CreateNewPlayerGroupDepartingFromSector( 1, 1 );
// Set persistent....
pGroup = GetGroup( SquadMovementGroups[ iSquad ] );
Assert( pGroup );
pGroup->fPersistant = TRUE;
}
}
}