Files
source/Tactical/Squads.cpp
T
Wanne 47db604b50 *** Merged Code from Multiplayer Branch Revision 2960 ***
- Virtual File System (VFS) by birdflu. This is needed for Multiplayer and is also used for Single Player. Very neat system :-)
- Multiplayer Version 1.1 + some additional features and bugfixes
* INFO: If you compile a new EXE and want to test, be sure to also use the latest SVN GameDir files in your JA2 install directory *




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

1606 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"
#include "GameSettings.h"
#endif
#include <vector>
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->flags.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 ]->flags.fBetweenSectors;
}
else
{
// remove them
RemoveCharacterFromSquads( pCharacter );
}
/*
if( fBetweenSectors == TRUE )
{
pCharacter->flags.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->flags.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 ) )
{
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 );
}
// WDS - make number of mercenaries, etc. be configurable
void SortSquadByID( INT8 bSquadValue )
{
for(unsigned idx1 = 0; idx1 < NUMBER_OF_SOLDIERS_PER_SQUAD-1; ++idx1) {
if (Squad[bSquadValue][idx1]) {
for(unsigned idx2 = idx1+1; idx2 < NUMBER_OF_SOLDIERS_PER_SQUAD; ++idx2) {
if (Squad[bSquadValue][idx2] &&
(Squad[bSquadValue][idx2]->ubID < Squad[bSquadValue][idx1]->ubID)) {
SOLDIERTYPE *temp = Squad[bSquadValue][idx1];
Squad[bSquadValue][idx1] = Squad[bSquadValue][idx2];
Squad[bSquadValue][idx2] = temp;
}
}
}
}
}
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->flags.fBetweenSectors )&&( pCharacter->flags.uiStatusFlags & SOLDIER_VEHICLE ) )
{
ubGroupId = CreateNewPlayerGroupDepartingFromSector( ( INT8 ) ( pCharacter->sSectorX ) , ( INT8 ) ( pCharacter->sSectorY ) );
// assign to a group
AddPlayerToGroup( ubGroupId, pCharacter );
}
RebuildSquad( ( INT8 )iCounterA );
if( pCharacter->stats.bLife == 0 )
{
AddDeadCharacterToSquadDeadGuys( pCharacter, iCounterA );
}
//if we are not loading a saved game
// OJW - 20090427 - fix bug leaving gamescree/tactical for MAIN_MENU
if( !(gTacticalStatus.uiFlags & LOADING_SAVED_GAME ) && guiCurrentScreen == GAME_SCREEN && guiPendingScreen != MAINMENU_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->stats.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 ) && Squad[ bSquadValue ][ bCounter ]->ControllingRobot( ) )
{
// 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 != NOBODY )
{
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;
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
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 ]->stats.bLife >= OKLIFE )
{
MercPtrs[ ubLoop ]->PositionSoldierLight( );
}
}
// 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 ]->flags.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 ]->flags.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->flags.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 ]->flags.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 ]->flags.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->flags.uiStatusFlags & SOLDIER_VEHICLE ) )
{
bSquadCount++;
}
}
}
// return number found
return( bSquadCount );
}
BOOLEAN DoesVehicleExistInSquad( INT8 bSquadValue )
{
SOLDIERTYPE *pSoldier;
INT8 bCounter = 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->flags.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;
}
}
}