Files
source/Strategic/Queen Command.cpp
T
Overhaul 6ec2c5da7d Initialized many variables
Fix for enemy invasions and reinforcements


git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@1192 3b4a5df2-a311-0410-b5c6-a8a6f20db521
2007-08-13 03:39:54 +00:00

2101 lines
67 KiB
C++

//Queen Command.c
#ifdef PRECOMPILEDHEADERS
#include "Strategic All.h"
#include "GameSettings.h"
#else
#include "Queen Command.h"
#include "Strategic Event Handler.h"
#include "Overhead Types.h"
#include "strategicmap.h"
#include "Soldier Init List.h"
#include "debug.h"
#include "Random.h"
#include "Strategic Movement.h"
#include "Overhead.h"
#include "Strategic Pathing.h"
#include "strategic.h"
#include "message.h"
#include "Map Edgepoints.h"
#include "PreBattle Interface.h"
#include "strategic status.h"
#include "squads.h"
#include "assignments.h"
#include "items.h"
#include "tactical save.h"
#include "Soldier Ani.h"
#include "Strategic AI.h"
#include "GameSettings.h"
#include "MessageBoxScreen.h"
#include "screenids.h"
#include "Strategic Town Loyalty.h"
#include "Soldier Profile.h"
#include "Quests.h"
#include "jascreens.h"
#include "Auto Resolve.h"
#include "Game Event Hook.h"
#include "Animation Data.h"
#include "Game Clock.h"
#include "renderworld.h"
#include "Town Militia.h"
#include "Dialogue Control.h"
#include "Campaign Init.h"
#include "meanwhile.h"
#include "Soldier macros.h"
#include "Morale.h"
#endif
#ifdef JA2BETAVERSION
extern BOOLEAN gfClearCreatureQuest;
#endif
#include "Reinforcement.h"
#include "MilitiaSquads.h"
//The sector information required for the strategic AI. Contains the number of enemy troops,
//as well as intentions, etc.
SECTORINFO SectorInfo[256];
UNDERGROUND_SECTORINFO *gpUndergroundSectorInfoHead = NULL;
extern UNDERGROUND_SECTORINFO* gpUndergroundSectorInfoTail;
BOOLEAN gfPendingEnemies = FALSE;
extern void BuildUndergroundSectorInfoList();
extern void EndCreatureQuest();
extern GARRISON_GROUP *gGarrisonGroup;
extern INT32 giGarrisonArraySize;
#ifdef JA2TESTVERSION
extern BOOLEAN gfOverrideSector;
#endif
INT16 gsInterrogationGridNo[3] = { 7756, 7757, 7758 };
extern void Ensure_RepairedGarrisonGroup( GARRISON_GROUP **ppGarrison, INT32 *pGarraySize );
void ValidateEnemiesHaveWeapons()
{
#ifdef JA2BETAVERSION
SGPRect CenteringRect= {0, 0, 639, 479 };
INT32 i, iErrorDialog;
SOLDIERTYPE *pSoldier;
INT32 iNumInvalid = 0;
for( i = gTacticalStatus.Team[ ENEMY_TEAM ].bFirstID; i <= gTacticalStatus.Team[ ENEMY_TEAM ].bLastID; i++ )
{
pSoldier = MercPtrs[ i ];
if( !pSoldier->bActive || !pSoldier->bInSector )
{
continue;
}
if( !pSoldier->inv[ HANDPOS ].usItem )
{
iNumInvalid++;
}
}
// do message box and return
if( iNumInvalid )
{
CHAR16 str[ 100 ];
swprintf( str, L"%d enemies have been added without any weapons! KM:0. Please note sector.", iNumInvalid );
iErrorDialog = DoMessageBox( MSG_BOX_BASIC_STYLE, str, GAME_SCREEN, MSG_BOX_FLAG_OK, NULL, &CenteringRect );
}
#endif
}
//Counts enemies and crepitus, but not bloodcats.
UINT8 NumHostilesInSector( INT16 sSectorX, INT16 sSectorY, INT16 sSectorZ )
{
UINT8 ubNumHostiles = 0;
Assert( sSectorX >= 1 && sSectorX <= 16 );
Assert( sSectorY >= 1 && sSectorY <= 16 );
Assert( sSectorZ >= 0 && sSectorZ <= 3 );
if( sSectorZ )
{
UNDERGROUND_SECTORINFO *pSector;
pSector = FindUnderGroundSector( sSectorX, sSectorY, (UINT8)sSectorZ );
if( pSector )
{
ubNumHostiles = (UINT8)(pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumCreatures);
}
}
else
{
SECTORINFO *pSector;
GROUP *pGroup;
//Count stationary hostiles
pSector = &SectorInfo[ SECTOR( sSectorX, sSectorY ) ];
ubNumHostiles = (UINT8)(pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumCreatures);
//Count mobile enemies
pGroup = gpGroupList;
while( pGroup )
{
if( !pGroup->fPlayer && !pGroup->fVehicle && pGroup->ubSectorX == sSectorX && pGroup->ubSectorY == sSectorY)
{
ubNumHostiles += pGroup->ubGroupSize;
}
pGroup = pGroup->next;
}
}
return ubNumHostiles;
}
UINT8 NumEnemiesInAnySector( INT16 sSectorX, INT16 sSectorY, INT16 sSectorZ )
{
UINT8 ubNumEnemies = 0;
Assert( sSectorX >= 1 && sSectorX <= 16 );
Assert( sSectorY >= 1 && sSectorY <= 16 );
Assert( sSectorZ >= 0 && sSectorZ <= 3 );
if( sSectorZ )
{
UNDERGROUND_SECTORINFO *pSector;
pSector = FindUnderGroundSector( sSectorX, sSectorY, (UINT8)sSectorZ );
if( pSector )
{
ubNumEnemies = (UINT8)(pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites);
}
}
else
{
SECTORINFO *pSector;
GROUP *pGroup;
//Count stationary enemies
pSector = &SectorInfo[ SECTOR( sSectorX, sSectorY ) ];
ubNumEnemies = (UINT8)(pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites);
//Count mobile enemies
pGroup = gpGroupList;
while( pGroup )
{
if( !pGroup->fPlayer && !pGroup->fVehicle && pGroup->ubSectorX == sSectorX && pGroup->ubSectorY == sSectorY )
{
ubNumEnemies += pGroup->ubGroupSize;
}
pGroup = pGroup->next;
}
}
return ubNumEnemies;
}
UINT8 NumEnemiesInSector( INT16 sSectorX, INT16 sSectorY )
{
SECTORINFO *pSector;
GROUP *pGroup;
UINT8 ubNumTroops;
//Assert( sSectorX >= 1 && sSectorX <= 16 );
//Assert( sSectorY >= 1 && sSectorY <= 16 );
pSector = &SectorInfo[ SECTOR( sSectorX, sSectorY ) ];
ubNumTroops = (UINT8)(pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites);
pGroup = gpGroupList;
while( pGroup )
{
if( !pGroup->fPlayer && !pGroup->fVehicle && pGroup->ubSectorX == sSectorX && pGroup->ubSectorY == sSectorY )
{
ubNumTroops += pGroup->ubGroupSize;
}
pGroup = pGroup->next;
}
return ubNumTroops;
}
UINT8 NumStationaryEnemiesInSector( INT16 sSectorX, INT16 sSectorY )
{
SECTORINFO *pSector;
Assert( sSectorX >= 1 && sSectorX <= 16 );
Assert( sSectorY >= 1 && sSectorY <= 16 );
pSector = &SectorInfo[ SECTOR( sSectorX, sSectorY ) ];
if( pSector->ubGarrisonID == NO_GARRISON )
{ //If no garrison, no stationary.
return( 0 );
}
Ensure_RepairedGarrisonGroup( &gGarrisonGroup, &giGarrisonArraySize ); /* added NULL fix, 2007-03-03, Sgt. Kolja */
// don't count roadblocks as stationary garrison, we want to see how many enemies are in them, not question marks
if ( gGarrisonGroup[ pSector->ubGarrisonID ].ubComposition == ROADBLOCK )
{
// pretend they're not stationary
return( 0 );
}
return (UINT8)(pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites);
}
UINT8 NumMobileEnemiesInSector( INT16 sSectorX, INT16 sSectorY )
{
GROUP *pGroup;
SECTORINFO *pSector;
UINT8 ubNumTroops;
Assert( sSectorX >= 1 && sSectorX <= 16 );
Assert( sSectorY >= 1 && sSectorY <= 16 );
ubNumTroops = 0;
pGroup = gpGroupList;
while( pGroup )
{
if( !pGroup->fPlayer && !pGroup->fVehicle && pGroup->ubSectorX == sSectorX && pGroup->ubSectorY == sSectorY )
{
ubNumTroops += pGroup->ubGroupSize;
}
pGroup = pGroup->next;
}
pSector = &SectorInfo[ SECTOR( sSectorX, sSectorY ) ];
if( pSector->ubGarrisonID == ROADBLOCK )
{ //consider these troops as mobile troops even though they are in a garrison
ubNumTroops += (UINT8)(pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites);
}
return ubNumTroops;
}
void GetNumberOfMobileEnemiesInSector( INT16 sSectorX, INT16 sSectorY, UINT8 *pubNumAdmins, UINT8 *pubNumTroops, UINT8 *pubNumElites )
{
GROUP *pGroup;
SECTORINFO *pSector;
Assert( sSectorX >= 1 && sSectorX <= 16 );
Assert( sSectorY >= 1 && sSectorY <= 16 );
//Now count the number of mobile groups in the sector.
*pubNumTroops = *pubNumElites = *pubNumAdmins = 0;
pGroup = gpGroupList;
while( pGroup )
{
if( !pGroup->fPlayer && !pGroup->fVehicle && pGroup->ubSectorX == sSectorX && pGroup->ubSectorY == sSectorY )
{
*pubNumTroops += pGroup->pEnemyGroup->ubNumTroops;
*pubNumElites += pGroup->pEnemyGroup->ubNumElites;
*pubNumAdmins += pGroup->pEnemyGroup->ubNumAdmins;
}
pGroup = pGroup->next;
}
pSector = &SectorInfo[ SECTOR( sSectorX, sSectorY ) ];
if( pSector->ubGarrisonID == ROADBLOCK )
{ //consider these troops as mobile troops even though they are in a garrison
*pubNumAdmins += pSector->ubNumAdmins;
*pubNumTroops += pSector->ubNumTroops;
*pubNumElites += pSector->ubNumElites;
}
}
void GetNumberOfMobileEnemiesInSectorWithoutRoadBlock( INT16 sSectorX, INT16 sSectorY, UINT8 *pubNumAdmins, UINT8 *pubNumTroops, UINT8 *pubNumElites )
{
GROUP *pGroup;
Assert( sSectorX >= 1 && sSectorX <= 16 );
Assert( sSectorY >= 1 && sSectorY <= 16 );
//Now count the number of mobile groups in the sector.
*pubNumTroops = *pubNumElites = *pubNumAdmins = 0;
pGroup = gpGroupList;
while( pGroup )
{
if( !pGroup->fPlayer && !pGroup->fVehicle && pGroup->ubSectorX == sSectorX && pGroup->ubSectorY == sSectorY )
{
*pubNumTroops += pGroup->pEnemyGroup->ubNumTroops;
*pubNumElites += pGroup->pEnemyGroup->ubNumElites;
*pubNumAdmins += pGroup->pEnemyGroup->ubNumAdmins;
}
pGroup = pGroup->next;
}
}
void GetNumberOfStationaryEnemiesInSector( INT16 sSectorX, INT16 sSectorY, UINT8 *pubNumAdmins, UINT8 *pubNumTroops, UINT8 *pubNumElites )
{
SECTORINFO *pSector;
Assert( sSectorX >= 1 && sSectorX <= 16 );
Assert( sSectorY >= 1 && sSectorY <= 16 );
pSector = &SectorInfo[ SECTOR( sSectorX, sSectorY ) ];
//grab the number of each type in the stationary sector
*pubNumAdmins = pSector->ubNumAdmins;
*pubNumTroops = pSector->ubNumTroops;
*pubNumElites = pSector->ubNumElites;
}
void GetNumberOfEnemiesInSector( INT16 sSectorX, INT16 sSectorY, UINT8 *pubNumAdmins, UINT8 *pubNumTroops, UINT8 *pubNumElites )
{
UINT8 ubNumAdmins, ubNumTroops, ubNumElites;
GetNumberOfStationaryEnemiesInSector( sSectorX, sSectorY, pubNumAdmins, pubNumTroops, pubNumElites );
GetNumberOfMobileEnemiesInSector( sSectorX, sSectorY, &ubNumAdmins, &ubNumTroops, &ubNumElites );
*pubNumAdmins += ubNumAdmins;
*pubNumTroops += ubNumTroops;
*pubNumElites += ubNumElites;
}
void EndTacticalBattleForEnemy()
{
GROUP *pGroup;
INT32 i, iNumMilitia = 0, iNumEnemies = 0;
//Clear enemies in battle for all stationary groups in the sector.
if( gbWorldSectorZ > 0 )
{
UNDERGROUND_SECTORINFO *pSector;
pSector = FindUnderGroundSector( gWorldSectorX, gWorldSectorY, gbWorldSectorZ );
pSector->ubAdminsInBattle = 0;
pSector->ubTroopsInBattle = 0;
pSector->ubElitesInBattle = 0;
}
else if( !gbWorldSectorZ )
{
SECTORINFO *pSector;
pSector = &SectorInfo[ SECTOR( gWorldSectorX, gWorldSectorY ) ];
//grab the number of each type in the stationary sector
pSector->ubAdminsInBattle = 0;
pSector->ubTroopsInBattle = 0;
pSector->ubElitesInBattle = 0;
pSector->ubNumCreatures = 0;
pSector->ubCreaturesInBattle = 0;
}
else // negative
return;
//Clear this value so that profiled enemies can be added into battles in the future.
gfProfiledEnemyAdded = FALSE;
//Clear enemies in battle for all mobile groups in the sector.
pGroup = gpGroupList;
while( pGroup )
{
if( !pGroup->fPlayer && !pGroup->fVehicle && pGroup->ubSectorX == gWorldSectorX && pGroup->ubSectorY == gWorldSectorY )
{
pGroup->pEnemyGroup->ubTroopsInBattle = 0;
pGroup->pEnemyGroup->ubElitesInBattle = 0;
pGroup->pEnemyGroup->ubAdminsInBattle = 0;
}
pGroup = pGroup->next;
}
//Check to see if any of our mercs have abandoned the militia during a battle. This is cause for a rather
//severe loyalty blow.
for( i = gTacticalStatus.Team[ MILITIA_TEAM ].bFirstID; i <= gTacticalStatus.Team[ MILITIA_TEAM ].bLastID; i++ )
{
if( MercPtrs[ i ]->bActive && MercPtrs[ i ]->bInSector && MercPtrs[ i ]->bLife >= OKLIFE )
{ //found one live militia, so look for any enemies/creatures.
// NOTE: this is relying on ENEMY_TEAM being immediately followed by CREATURE_TEAM
for( i = gTacticalStatus.Team[ ENEMY_TEAM ].bFirstID; i <= gTacticalStatus.Team[ CREATURE_TEAM ].bLastID; i++ )
{
if( MercPtrs[ i ]->bActive && MercPtrs[ i ]->bInSector && MercPtrs[ i ]->bLife >= OKLIFE )
{ //confirmed at least one enemy here, so do the loyalty penalty.
HandleGlobalLoyaltyEvent( GLOBAL_LOYALTY_ABANDON_MILITIA, gWorldSectorX, gWorldSectorY, 0 );
break;
}
}
break;
}
}
}
UINT8 NumFreeEnemySlots()
{
UINT8 ubNumFreeSlots = 0;
INT32 i;
SOLDIERTYPE *pSoldier;
//Count the number of free enemy slots. It is possible to have multiple groups exceed the maximum.
for( i = gTacticalStatus.Team[ ENEMY_TEAM ].bFirstID; i <= gTacticalStatus.Team[ ENEMY_TEAM].bLastID; i++ )
{
pSoldier = &Menptr[ i ];
if( !pSoldier->bActive )
ubNumFreeSlots++;
}
return ubNumFreeSlots;
}
//Called when entering a sector so the campaign AI can automatically insert the
//correct number of troops of each type based on the current number in the sector
//in global focus (gWorldSectorX/Y)
BOOLEAN PrepareEnemyForSectorBattle()
{
SECTORINFO *pSector;
GROUP *pGroup;
SOLDIERTYPE *pSoldier;
UINT8 ubNumAdmins, ubNumTroops, ubNumElites;
UINT8 ubTotalAdmins, ubTotalElites, ubTotalTroops;
UINT8 ubStationaryEnemies;
INT32 i, num;
INT16 sNumSlots;
gfPendingEnemies = FALSE;
if( gbWorldSectorZ > 0 )
return PrepareEnemyForUndergroundBattle();
// Reinforcement groups? Bring it on! That is, if this is an enemy invasion.
if( gGameExternalOptions.gfAllowReinforcements &&
!( (GetTownIdForSector( gWorldSectorX, gWorldSectorY ) == OMERTA )&&( gGameOptions.ubDifficultyLevel != DIF_LEVEL_INSANE ) ) &&
gpBattleGroup && !gpBattleGroup->fPlayer )
{
UINT16 pusMoveDir[4][3];
UINT8 ubDirNumber = 0, ubIndex;
GROUP *pGroup;
SECTORINFO *pThisSector;
//The enemy has instigated the battle which means they are the ones entering the conflict.
//The player was actually in the sector first, and the enemy doesn't use reinforced placements
HandleArrivalOfReinforcements( gpBattleGroup );
// They arrived in multiple groups, so here they come
pThisSector = &SectorInfo[ SECTOR( gWorldSectorX, gWorldSectorY ) ];
GenerateDirectionInfos( gWorldSectorX, gWorldSectorY, &ubDirNumber, pusMoveDir,
( GetTownIdForSector( gWorldSectorX, gWorldSectorY ) != BLANK_SECTOR ? TRUE : FALSE ), TRUE, IS_ONLY_IN_CITIES );
for( ubIndex = 0; ubIndex < ubDirNumber; ubIndex++ )
{
while ( NumMobileEnemiesInSector( SECTORX( pusMoveDir[ ubIndex ][ 0 ] ), SECTORY( pusMoveDir[ ubIndex ][ 0 ] ) ) && GetEnemyGroupInSector( SECTORX( pusMoveDir[ ubIndex][ 0 ] ), SECTORY( pusMoveDir[ ubIndex ][ 0 ] ) ) )
{
pGroup = GetEnemyGroupInSector( SECTORX( pusMoveDir[ ubIndex][ 0 ] ), SECTORY( pusMoveDir[ ubIndex ][ 0 ] ) );
pGroup->ubPrevX = pGroup->ubSectorX;
pGroup->ubPrevY = pGroup->ubSectorY;
pGroup->ubSectorX = pGroup->ubNextX = (UINT8)gWorldSectorX;
pGroup->ubSectorY = pGroup->ubNextY = (UINT8)gWorldSectorY;
}
}
//It is now possible that other enemy groups have also arrived. Add them in the same manner.
pGroup = gpGroupList;
while( pGroup )
{
if( pGroup != gpBattleGroup && !pGroup->fPlayer && !pGroup->fVehicle &&
pGroup->ubSectorX == gpBattleGroup->ubSectorX &&
pGroup->ubSectorY == gpBattleGroup->ubSectorY &&
!pGroup->pEnemyGroup->ubAdminsInBattle &&
!pGroup->pEnemyGroup->ubTroopsInBattle &&
!pGroup->pEnemyGroup->ubElitesInBattle )
{
HandleArrivalOfReinforcements( pGroup );
}
pGroup = pGroup->next;
}
ValidateEnemiesHaveWeapons();
return ( ( BOOLEAN) ( gpBattleGroup->ubGroupSize > 0 ) );
}
if( !gbWorldSectorZ )
{
if( NumEnemiesInSector( gWorldSectorX, gWorldSectorY ) > 32 )
{
gfPendingEnemies = TRUE;
}
}
pSector = &SectorInfo[ SECTOR( gWorldSectorX, gWorldSectorY ) ];
if( pSector->uiFlags & SF_USE_MAP_SETTINGS )
{ //count the number of enemy placements in a map and use those
SOLDIERINITNODE *curr;
curr = gSoldierInitHead;
ubTotalAdmins = ubTotalTroops = ubTotalElites = 0;
while( curr )
{
if( curr->pBasicPlacement->bTeam == ENEMY_TEAM )
{
switch( curr->pBasicPlacement->ubSoldierClass )
{
case SOLDIER_CLASS_ADMINISTRATOR: ubTotalAdmins++; break;
case SOLDIER_CLASS_ARMY: ubTotalTroops++; break;
case SOLDIER_CLASS_ELITE: ubTotalElites++; break;
}
}
curr = curr->next;
}
pSector->ubNumAdmins = ubTotalAdmins;
pSector->ubNumTroops = ubTotalTroops;
pSector->ubNumElites = ubTotalElites;
pSector->ubAdminsInBattle = 0;
pSector->ubTroopsInBattle = 0;
pSector->ubElitesInBattle = 0;
}
else
{
ubTotalAdmins = (UINT8)(pSector->ubNumAdmins - pSector->ubAdminsInBattle);
ubTotalTroops = (UINT8)(pSector->ubNumTroops - pSector->ubTroopsInBattle);
ubTotalElites = (UINT8)(pSector->ubNumElites - pSector->ubElitesInBattle);
}
ubStationaryEnemies = (UINT8)(ubTotalAdmins + ubTotalTroops + ubTotalElites);
if( ubStationaryEnemies > 32 )
{
#ifdef JA2BETAVERSION
ScreenMsg( FONT_RED, MSG_ERROR, L"The total stationary enemy forces in sector %c%d is %d. (max %d)",
gWorldSectorY + 'A' - 1, gWorldSectorX, ubTotalAdmins + ubTotalTroops + ubTotalElites, 32 );
#endif
ubTotalAdmins = min( 32, ubTotalAdmins );
ubTotalTroops = min( 32-ubTotalAdmins, ubTotalTroops );
ubTotalElites = min( 32-ubTotalAdmins+ubTotalTroops, ubTotalElites );
}
pSector->ubAdminsInBattle += ubTotalAdmins;
pSector->ubTroopsInBattle += ubTotalTroops;
pSector->ubElitesInBattle += ubTotalElites;
#ifdef JA2TESTVERSION
if( gfOverrideSector )
{
//if there are no troops in the current groups, then we're done.
if( !ubTotalAdmins && !ubTotalTroops && !ubTotalElites )
return FALSE;
AddSoldierInitListEnemyDefenceSoldiers( ubTotalAdmins, ubTotalTroops, ubTotalElites );
ValidateEnemiesHaveWeapons();
return TRUE;
}
#endif
//Search for movement groups that happen to be in the sector.
sNumSlots = NumFreeEnemySlots();
//Test: All slots should be free at this point!
if( sNumSlots != gTacticalStatus.Team[ENEMY_TEAM].bLastID - gTacticalStatus.Team[ENEMY_TEAM].bFirstID + 1 )
{
#ifdef JA2BETAVERSION
ScreenMsg( FONT_RED, MSG_ERROR, L"All enemy slots should be free at this point. Only %d of %d are available.\nTrying to add %d admins, %d troops, and %d elites.",
sNumSlots, gTacticalStatus.Team[ENEMY_TEAM].bLastID - gTacticalStatus.Team[ENEMY_TEAM].bFirstID + 1 ,
ubTotalAdmins, ubTotalTroops, ubTotalElites );
#endif
}
//Subtract the total number of stationary enemies from the available slots, as stationary forces take
//precendence in combat. The mobile forces that could also be in the same sector are considered later if
//all the slots fill up.
sNumSlots -= ubTotalAdmins + ubTotalTroops + ubTotalElites;
//Now, process all of the groups and search for both enemy and player groups in the sector.
//For enemy groups, we fill up the slots until we have none left or all of the groups have been
//processed.
for( pGroup = gpGroupList;
pGroup;
pGroup = pGroup->next)
{
if( !pGroup->fPlayer && !pGroup->fVehicle &&
pGroup->ubSectorX == gWorldSectorX && pGroup->ubSectorY == gWorldSectorY && !gbWorldSectorZ )
{ //Process enemy group in sector.
if( sNumSlots > 0 )
{
ubNumAdmins = (UINT8)(pGroup->pEnemyGroup->ubNumAdmins - pGroup->pEnemyGroup->ubAdminsInBattle);
sNumSlots -= ubNumAdmins;
if( sNumSlots < 0 )
{ //adjust the value to zero
ubNumAdmins += sNumSlots;
sNumSlots = 0;
gfPendingEnemies = TRUE;
}
pGroup->pEnemyGroup->ubAdminsInBattle += ubNumAdmins;
ubTotalAdmins += ubNumAdmins;
}
if( sNumSlots > 0 )
{ //Add regular army forces.
ubNumTroops = (UINT8)(pGroup->pEnemyGroup->ubNumTroops - pGroup->pEnemyGroup->ubTroopsInBattle);
sNumSlots -= ubNumTroops;
if( sNumSlots < 0 )
{ //adjust the value to zero
ubNumTroops += sNumSlots;
sNumSlots = 0;
gfPendingEnemies = TRUE;
}
pGroup->pEnemyGroup->ubTroopsInBattle += ubNumTroops;
ubTotalTroops += ubNumTroops;
}
if( sNumSlots > 0 )
{ //Add elite troops
ubNumElites = (UINT8)(pGroup->pEnemyGroup->ubNumElites - pGroup->pEnemyGroup->ubElitesInBattle);
sNumSlots -= ubNumElites;
if( sNumSlots < 0 )
{ //adjust the value to zero
ubNumElites += sNumSlots;
sNumSlots = 0;
gfPendingEnemies = TRUE;
}
pGroup->pEnemyGroup->ubElitesInBattle += ubNumElites;
ubTotalElites += ubNumElites;
}
//NOTE:
//no provisions for profile troop leader or retreat groups yet.
}
if( pGroup->fPlayer && !pGroup->fVehicle && !pGroup->fBetweenSectors &&
pGroup->ubSectorX == gWorldSectorX && pGroup->ubSectorY == gWorldSectorY && !gbWorldSectorZ )
{ //TEMP: The player path needs to get destroyed, otherwise, it'll be impossible to move the
// group after the battle is resolved.
// no one in the group any more continue loop
if( pGroup->pPlayerList == NULL )
{
continue;
}
// clear the movt for this grunt and his buddies
RemoveGroupWaypoints( pGroup->ubGroupID );
}
}
//if there are no troops in the current groups, then we're done.
if( !ubTotalAdmins && !ubTotalTroops && !ubTotalElites )
{
return FALSE;
}
AddSoldierInitListEnemyDefenceSoldiers( ubTotalAdmins, ubTotalTroops, ubTotalElites );
//Now, we have to go through all of the enemies in the new map, and assign their respective groups if
//in a mobile group, but only for the ones that were assigned from the
sNumSlots = 32 - ubStationaryEnemies;
pGroup = gpGroupList;
while( pGroup && sNumSlots )
{
i = gTacticalStatus.Team[ ENEMY_TEAM ].bFirstID;
pSoldier = &Menptr[ i ];
if( !pGroup->fPlayer && !pGroup->fVehicle && pGroup->ubSectorX == gWorldSectorX && pGroup->ubSectorY == gWorldSectorY && !gbWorldSectorZ )
{
num = pGroup->ubGroupSize;
ubNumAdmins = pGroup->pEnemyGroup->ubAdminsInBattle;
ubNumTroops = pGroup->pEnemyGroup->ubTroopsInBattle;
ubNumElites = pGroup->pEnemyGroup->ubElitesInBattle;
while( num && sNumSlots && i <= gTacticalStatus.Team[ ENEMY_TEAM ].bLastID )
{
while( !pSoldier->bActive || pSoldier->ubGroupID )
{
pSoldier = &Menptr[ ++i ];
if( i > gTacticalStatus.Team[ ENEMY_TEAM ].bLastID )
{
AssertMsg( 0, "Failed to assign battle counters for enemies properly. Please send save. KM:0." );
}
}
switch( pSoldier->ubSoldierClass )
{
case SOLDIER_CLASS_ADMINISTRATOR:
if( ubNumAdmins )
{
num--;
sNumSlots--;
ubNumAdmins--;
pSoldier->ubGroupID = pGroup->ubGroupID;
}
break;
case SOLDIER_CLASS_ARMY:
if( ubNumTroops )
{
num--;
sNumSlots--;
ubNumTroops--;
pSoldier->ubGroupID = pGroup->ubGroupID;
}
break;
case SOLDIER_CLASS_ELITE:
if( ubNumElites )
{
num--;
sNumSlots--;
ubNumElites--;
pSoldier->ubGroupID = pGroup->ubGroupID;
}
break;
}
pSoldier = &Menptr[ ++i ];
}
}
pGroup = pGroup->next;
}
ValidateEnemiesHaveWeapons();
return TRUE;
}
BOOLEAN PrepareEnemyForUndergroundBattle()
{
UNDERGROUND_SECTORINFO *pUnderground;
UINT8 ubTotalAdmins, ubTotalTroops, ubTotalElites;
pUnderground = gpUndergroundSectorInfoHead;
while( pUnderground )
{
if( pUnderground->ubSectorX == gWorldSectorX &&
pUnderground->ubSectorY == gWorldSectorY &&
pUnderground->ubSectorZ == gbWorldSectorZ )
{ //This is the sector we are going to be fighting in.
if( pUnderground->ubNumAdmins || pUnderground->ubNumTroops || pUnderground->ubNumElites )
{
ubTotalAdmins = (UINT8)(pUnderground->ubNumAdmins - pUnderground->ubAdminsInBattle);
ubTotalTroops = (UINT8)(pUnderground->ubNumTroops - pUnderground->ubTroopsInBattle);
ubTotalElites = (UINT8)(pUnderground->ubNumElites - pUnderground->ubElitesInBattle);
pUnderground->ubAdminsInBattle += ubTotalAdmins;
pUnderground->ubTroopsInBattle += ubTotalTroops;
pUnderground->ubElitesInBattle += ubTotalElites;
AddSoldierInitListEnemyDefenceSoldiers( pUnderground->ubNumAdmins, pUnderground->ubNumTroops, pUnderground->ubNumElites );
ValidateEnemiesHaveWeapons();
}
return ( ( BOOLEAN) ( pUnderground->ubNumAdmins + pUnderground->ubNumTroops + pUnderground->ubNumElites > 0 ) );
}
pUnderground = pUnderground->next;
}
// underground sector not found in list
Assert( FALSE );
return FALSE;
}
//The queen AI layer must process the event by subtracting forces, etc.
void ProcessQueenCmdImplicationsOfDeath( SOLDIERTYPE *pSoldier )
{
INT32 iNumEnemiesInSector;
SECTORINFO *pSector;
// CHAR16 str[128];
INT32 iMaxEnemyGroupSize = gGameExternalOptions.iMaxEnemyGroupSize;
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"QueenCommand");
EvaluateDeathEffectsToSoldierInitList( pSoldier );
switch( pSoldier->ubProfile )
{
case MIKE:
case IGGY:
if( pSoldier->ubProfile == IGGY && !gubFact[ FACT_IGGY_AVAILABLE_TO_ARMY ] )
{ //Iggy is on our team!
break;
}
if( !pSoldier->bSectorZ )
{
pSector = &SectorInfo[ SECTOR( pSoldier->sSectorX, pSoldier->sSectorY ) ];
if( pSector->ubNumElites )
{
pSector->ubNumElites--;
}
if( pSector->ubElitesInBattle )
{
pSector->ubElitesInBattle--;
}
}
else
{
UNDERGROUND_SECTORINFO *pUnderground;
pUnderground = FindUnderGroundSector( (UINT8)pSoldier->sSectorX, (UINT8)pSoldier->sSectorY, (UINT8)pSoldier->bSectorZ );
Assert( pUnderground );
if( pUnderground->ubNumElites )
{
pUnderground->ubNumElites--;
}
if( pUnderground->ubElitesInBattle )
{
pUnderground->ubElitesInBattle--;
}
}
break;
}
if( pSoldier->bNeutral || pSoldier->bTeam != ENEMY_TEAM && pSoldier->bTeam != CREATURE_TEAM )
return;
//we are recording an enemy death
if( pSoldier->ubGroupID )
{ //The enemy was in a mobile group
GROUP *pGroup;
pGroup = GetGroup( pSoldier->ubGroupID );
if( !pGroup )
{
#ifdef JA2BETAVERSION
CHAR16 str[256];
swprintf( str, L"Enemy soldier killed with ubGroupID of %d, and the group doesn't exist!", pSoldier->ubGroupID );
DoScreenIndependantMessageBox( str, MSG_BOX_FLAG_OK, NULL );
#endif
return;
}
if( pGroup->fPlayer )
{
#ifdef JA2BETAVERSION
CHAR16 str[256];
swprintf( str, L"Attempting to process player group thinking it's an enemy group in ProcessQueenCmdImplicationsOfDeath()", pSoldier->ubGroupID );
DoScreenIndependantMessageBox( str, MSG_BOX_FLAG_OK, NULL );
#endif
return;
}
switch( pSoldier->ubSoldierClass )
{
case SOLDIER_CLASS_ELITE:
#ifdef JA2BETAVERSION
if( !pGroup->pEnemyGroup->ubNumElites )
{
//swprintf( str, L"Enemy elite killed with ubGroupID of %d, but the group doesn't contain elites!", pGroup->ubGroupID );
//DoScreenIndependantMessageBox( str, MSG_BOX_FLAG_OK, NULL );
break;
}
if( guiCurrentScreen == GAME_SCREEN )
{
if( pGroup->ubGroupSize <= iMaxEnemyGroupSize && pGroup->pEnemyGroup->ubNumElites != pGroup->pEnemyGroup->ubElitesInBattle && !gfPendingEnemies ||
pGroup->ubGroupSize > iMaxEnemyGroupSize || pGroup->pEnemyGroup->ubNumElites > 50 || pGroup->pEnemyGroup->ubElitesInBattle > 50 )
{
DoScreenIndependantMessageBox( L"Group elite counters are bad. What were the last 2-3 things to die, and how? Save game and send to KM with info!!!", MSG_BOX_FLAG_OK, NULL );
}
}
#endif
if( pGroup->pEnemyGroup->ubNumElites )
{
pGroup->pEnemyGroup->ubNumElites--;
}
if( pGroup->pEnemyGroup->ubElitesInBattle )
{
pGroup->pEnemyGroup->ubElitesInBattle--;
}
break;
case SOLDIER_CLASS_ARMY:
#ifdef JA2BETAVERSION
if( !pGroup->pEnemyGroup->ubNumTroops )
{
//swprintf( str, L"Enemy troop killed with ubGroupID of %d, but the group doesn't contain elites!", pGroup->ubGroupID );
//DoScreenIndependantMessageBox( str, MSG_BOX_FLAG_OK, NULL );
break;
}
if( guiCurrentScreen == GAME_SCREEN )
{
if( pGroup->ubGroupSize <= iMaxEnemyGroupSize && pGroup->pEnemyGroup->ubNumTroops != pGroup->pEnemyGroup->ubTroopsInBattle && !gfPendingEnemies ||
pGroup->ubGroupSize > iMaxEnemyGroupSize || pGroup->pEnemyGroup->ubNumTroops > 50 || pGroup->pEnemyGroup->ubTroopsInBattle > 50 )
{
DoScreenIndependantMessageBox( L"Group troop counters are bad. What were the last 2-3 things to die, and how? Save game and send to KM with info!!!", MSG_BOX_FLAG_OK, NULL );
}
}
#endif
if( pGroup->pEnemyGroup->ubNumTroops )
{
pGroup->pEnemyGroup->ubNumTroops--;
}
if( pGroup->pEnemyGroup->ubTroopsInBattle )
{
pGroup->pEnemyGroup->ubTroopsInBattle--;
}
break;
case SOLDIER_CLASS_ADMINISTRATOR:
#ifdef JA2BETAVERSION
if( !pGroup->pEnemyGroup->ubNumAdmins )
{
//swprintf( str, L"Enemy administrator killed with ubGroupID of %d, but the group doesn't contain elites!", pGroup->ubGroupID );
//DoScreenIndependantMessageBox( str, MSG_BOX_FLAG_OK, NULL );
break;
}
if( guiCurrentScreen == GAME_SCREEN )
{
if( pGroup->ubGroupSize <= iMaxEnemyGroupSize && pGroup->pEnemyGroup->ubNumAdmins != pGroup->pEnemyGroup->ubAdminsInBattle && !gfPendingEnemies ||
pGroup->ubGroupSize > iMaxEnemyGroupSize || pGroup->pEnemyGroup->ubNumAdmins > 50 || pGroup->pEnemyGroup->ubAdminsInBattle > 50 )
{
DoScreenIndependantMessageBox( L"Group admin counters are bad. What were the last 2-3 things to die, and how? Save game and send to KM with info!!!", MSG_BOX_FLAG_OK, NULL );
}
}
#endif
if( pGroup->pEnemyGroup->ubNumAdmins )
{
pGroup->pEnemyGroup->ubNumAdmins--;
}
if( pGroup->pEnemyGroup->ubAdminsInBattle )
{
pGroup->pEnemyGroup->ubAdminsInBattle--;
}
break;
}
if( pGroup->ubGroupSize )
pGroup->ubGroupSize--;
RecalculateGroupWeight( pGroup );
if( !pGroup->ubGroupSize )
{
RemovePGroup( pGroup );
}
}
else
{ //The enemy was in a stationary defence group
if( !gbWorldSectorZ || IsAutoResolveActive() )
{ //ground level (SECTORINFO)
SECTORINFO *pSector;
#ifdef JA2BETAVERSION
UINT32 ubTotalEnemies;
#endif
// if( !IsAutoResolveActive() )
// {
pSector = &SectorInfo[ SECTOR( pSoldier->sSectorX, pSoldier->sSectorY ) ];
// }
// else
// {
// pSector = &SectorInfo[ GetAutoResolveSectorID() ];
// }
#ifdef JA2BETAVERSION
ubTotalEnemies = pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites;
#endif
switch( pSoldier->ubSoldierClass )
{
case SOLDIER_CLASS_ADMINISTRATOR:
#ifdef JA2BETAVERSION
if( guiCurrentScreen == GAME_SCREEN )
{
if( ubTotalEnemies <= 32 && pSector->ubNumAdmins != pSector->ubAdminsInBattle ||
!pSector->ubNumAdmins || !pSector->ubAdminsInBattle ||
pSector->ubNumAdmins > 100 || pSector->ubAdminsInBattle > 32 )
{
DoScreenIndependantMessageBox( L"Sector admin counters are bad. What were the last 2-3 things to die, and how? Save game and send to KM with info!!!", MSG_BOX_FLAG_OK, NULL );
}
}
#endif
if( pSector->ubNumAdmins )
{
pSector->ubNumAdmins--;
}
if( pSector->ubAdminsInBattle )
{
pSector->ubAdminsInBattle--;
}
break;
case SOLDIER_CLASS_ARMY:
#ifdef JA2BETAVERSION
if( guiCurrentScreen == GAME_SCREEN )
{
if( ubTotalEnemies <= 32 && pSector->ubNumTroops != pSector->ubTroopsInBattle ||
!pSector->ubNumTroops || !pSector->ubTroopsInBattle ||
pSector->ubNumTroops > 100 || pSector->ubTroopsInBattle > 32 )
{
DoScreenIndependantMessageBox( L"Sector troop counters are bad. What were the last 2-3 things to die, and how? Save game and send to KM with info!!!", MSG_BOX_FLAG_OK, NULL );
}
}
#endif
if( pSector->ubNumTroops )
{
pSector->ubNumTroops--;
}
if( pSector->ubTroopsInBattle )
{
pSector->ubTroopsInBattle--;
}
break;
case SOLDIER_CLASS_ELITE:
#ifdef JA2BETAVERSION
if( guiCurrentScreen == GAME_SCREEN )
{
if( ubTotalEnemies <= 32 && pSector->ubNumElites != pSector->ubElitesInBattle ||
!pSector->ubNumElites || !pSector->ubElitesInBattle ||
pSector->ubNumElites > 100 || pSector->ubElitesInBattle > 32 )
{
DoScreenIndependantMessageBox( L"Sector elite counters are bad. What were the last 2-3 things to die, and how? Save game and send to KM with info!!!", MSG_BOX_FLAG_OK, NULL );
}
}
#endif
if( pSector->ubNumElites )
{
pSector->ubNumElites--;
}
if( pSector->ubElitesInBattle )
{
pSector->ubElitesInBattle--;
}
break;
case SOLDIER_CLASS_CREATURE:
if( pSoldier->ubBodyType != BLOODCAT )
{
#ifdef JA2BETAVERSION
if( guiCurrentScreen == GAME_SCREEN )
{
if( ubTotalEnemies <= (UINT32)iMaxEnemyGroupSize && pSector->ubNumCreatures != pSector->ubCreaturesInBattle ||
!pSector->ubNumCreatures || !pSector->ubCreaturesInBattle ||
pSector->ubNumCreatures > 50 || pSector->ubCreaturesInBattle > 50 )
{
DoScreenIndependantMessageBox( L"Sector creature counters are bad. What were the last 2-3 things to die, and how? Save game and send to KM with info!!!", MSG_BOX_FLAG_OK, NULL );
}
}
#endif
if( pSector->ubNumCreatures )
{
pSector->ubNumCreatures--;
}
if( pSector->ubCreaturesInBattle )
{
pSector->ubCreaturesInBattle--;
}
}
else
{
if( pSector->bBloodCats )
{
pSector->bBloodCats--;
}
}
break;
}
RecalculateSectorWeight( (UINT8)SECTOR( pSoldier->sSectorX, pSoldier->sSectorY ) );
}
else
{ //basement level (UNDERGROUND_SECTORINFO)
UNDERGROUND_SECTORINFO *pSector = FindUnderGroundSector( gWorldSectorX, gWorldSectorY, gbWorldSectorZ );
#ifdef JA2BETAVERSION
UINT32 ubTotalEnemies = pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites;
#endif
if( pSector )
{
switch( pSoldier->ubSoldierClass )
{
case SOLDIER_CLASS_ADMINISTRATOR:
#ifdef JA2BETAVERSION
if( ubTotalEnemies <= (UINT32)iMaxEnemyGroupSize && pSector->ubNumAdmins != pSector->ubAdminsInBattle ||
!pSector->ubNumAdmins || !pSector->ubAdminsInBattle ||
pSector->ubNumAdmins > 100 || pSector->ubAdminsInBattle > iMaxEnemyGroupSize )
{
DoScreenIndependantMessageBox( L"Underground sector admin counters are bad. What were the last 2-3 things to die, and how? Save game and send to KM with info!!!", MSG_BOX_FLAG_OK, NULL );
}
#endif
if( pSector->ubNumAdmins )
{
pSector->ubNumAdmins--;
}
if( pSector->ubAdminsInBattle )
{
pSector->ubAdminsInBattle--;
}
break;
case SOLDIER_CLASS_ARMY:
#ifdef JA2BETAVERSION
if( ubTotalEnemies <= (UINT32)iMaxEnemyGroupSize && pSector->ubNumTroops != pSector->ubTroopsInBattle ||
!pSector->ubNumTroops || !pSector->ubTroopsInBattle ||
pSector->ubNumTroops > 100 || pSector->ubTroopsInBattle > iMaxEnemyGroupSize )
{
DoScreenIndependantMessageBox( L"Underground sector troop counters are bad. What were the last 2-3 things to die, and how? Save game and send to KM with info!!!", MSG_BOX_FLAG_OK, NULL );
}
#endif
if( pSector->ubNumTroops )
{
pSector->ubNumTroops--;
}
if( pSector->ubTroopsInBattle )
{
pSector->ubTroopsInBattle--;
}
break;
case SOLDIER_CLASS_ELITE:
#ifdef JA2BETAVERSION
if( ubTotalEnemies <= (UINT32)iMaxEnemyGroupSize && pSector->ubNumElites != pSector->ubElitesInBattle ||
!pSector->ubNumElites || !pSector->ubElitesInBattle ||
pSector->ubNumElites > 100 || pSector->ubElitesInBattle > iMaxEnemyGroupSize )
{
DoScreenIndependantMessageBox( L"Underground sector elite counters are bad. What were the last 2-3 things to die, and how? Save game and send to KM with info!!!", MSG_BOX_FLAG_OK, NULL );
}
#endif
if( pSector->ubNumElites )
{
pSector->ubNumElites--;
}
if( pSector->ubElitesInBattle )
{
pSector->ubElitesInBattle--;
}
break;
case SOLDIER_CLASS_CREATURE:
#ifdef JA2BETAVERSION
if( ubTotalEnemies <= (UINT32)iMaxEnemyGroupSize && pSector->ubNumCreatures != pSector->ubCreaturesInBattle ||
!pSector->ubNumCreatures || !pSector->ubCreaturesInBattle ||
pSector->ubNumCreatures > 50 || pSector->ubCreaturesInBattle > 50 )
{
DoScreenIndependantMessageBox( L"Underground sector creature counters are bad. What were the last 2-3 things to die, and how? Save game and send to KM with info!!!", MSG_BOX_FLAG_OK, NULL );
}
#endif
if( pSector->ubNumCreatures )
{
pSector->ubNumCreatures--;
}
if( pSector->ubCreaturesInBattle )
{
pSector->ubCreaturesInBattle--;
}
if( !pSector->ubNumCreatures && gWorldSectorX != 9 && gWorldSectorY != 10 )
{ //If the player has successfully killed all creatures in ANY underground sector except J9
//then cancel any pending creature town attack.
DeleteAllStrategicEventsOfType( EVENT_CREATURE_ATTACK );
}
// a monster has died. Post an event to immediately check whether a mine has been cleared.
AddStrategicEventUsingSeconds( EVENT_CHECK_IF_MINE_CLEARED, GetWorldTotalSeconds() + 15, 0);
if( pSoldier->ubBodyType == QUEENMONSTER )
{
//Need to call this, as the queen is really big, and killing her leaves a bunch
//of bad tiles in behind her. Calling this function cleans it up.
InvalidateWorldRedundency();
//Now that the queen is dead, turn off the creature quest.
EndCreatureQuest();
EndQuest( QUEST_CREATURES, gWorldSectorX, gWorldSectorY );
}
break;
}
}
}
}
if( !pSoldier->bSectorZ )
{
pSector = &SectorInfo[ SECTOR( pSoldier->sSectorX, pSoldier->sSectorY ) ];
iNumEnemiesInSector = NumEnemiesInSector( pSoldier->sSectorX, pSoldier->sSectorY );
if( iNumEnemiesInSector )
{
if( pSector->bLastKnownEnemies >= 0 )
{
pSector->bLastKnownEnemies = (INT8)iNumEnemiesInSector;
}
}
else
{
pSector->bLastKnownEnemies = 0;
}
}
}
//Well, not so rarely with mobile reinforcements!
//Rarely, there will be more enemies than supported by the engine. In this case, these
//soldiers are waiting for a slot to be free so that they can enter the battle. This
//essentially allows for an infinite number of troops, though only 32 at a time can fight.
//This is also called whenever an enemy group's reinforcements arrive because the code is
//identical, though it is highly likely that they will all be successfully added on the first call.
void AddPossiblePendingEnemiesToBattle()
{
UINT8 ubSlots, ubNumAvailable;
UINT8 ubNumElites, ubNumTroops, ubNumAdmins;
UINT8 ubNumGroupsInSector;
UINT8 ubGroupIndex;
GROUP *pGroup;
SECTORINFO *pSector = &SectorInfo[ SECTOR( gWorldSectorX, gWorldSectorY ) ];
GROUP **pGroupInSectorList;
static UINT8 ubPredefinedInsertionCode = 255;
// check if no world is loaded
if ( !gWorldSectorX && !gWorldSectorY && (gbWorldSectorZ == -1) )
return;
if( ( !PlayerMercsInSector( (UINT8)gWorldSectorX, (UINT8)gWorldSectorY, 0 ) && !CountAllMilitiaInSector( gWorldSectorX, gWorldSectorY ) )
|| !NumEnemiesInSector( gWorldSectorX, gWorldSectorY ) ) return;
ubSlots = NumFreeEnemySlots();
if( !ubSlots )
{ //no available slots to add enemies to. Try again later...
return;
}
if( !gfPendingEnemies )
{
//Optimization. No point in checking for group reinforcements if we know that there aren't any more enemies that can
//be added to this battle. This changes whenever a new enemy group arrives at the scene.
while (ubSlots)
{
UINT8 ubInsertionCode = 255;
if( gTacticalStatus.Team[ ENEMY_TEAM ].bAwareOfOpposition == TRUE )
ubInsertionCode = DoReinforcementAsPendingEnemy( gWorldSectorX, gWorldSectorY );
if (ubInsertionCode == 255)
{
break;
}
// Assume we added one since there are supposedly more available and room for them
ubSlots--;
}
return;
}
if( pSector->ubNumElites + pSector->ubNumTroops + pSector->ubNumAdmins )
{
ubNumElites = ubNumTroops = ubNumAdmins = 0;
ubNumAvailable = pSector->ubNumElites + pSector->ubNumTroops + pSector->ubNumAdmins - pSector->ubElitesInBattle - pSector->ubTroopsInBattle - pSector->ubAdminsInBattle;
while( ubNumAvailable && ubSlots )
{
// So they just magically appear out of nowhere from the edge?
//This group has enemies waiting for a chance to enter the battle.
if( pSector->ubElitesInBattle < pSector->ubNumElites )
{ //Add an elite troop
pSector->ubElitesInBattle++;
ubNumAvailable--;
ubSlots--;
ubNumElites++;
}
else if( pSector->ubTroopsInBattle < pSector->ubNumTroops )
{ //Add a regular troop.
pSector->ubTroopsInBattle++;
ubNumAvailable--;
ubSlots--;
ubNumTroops++;
}
else if( pSector->ubAdminsInBattle < pSector->ubNumAdmins )
{ //Add an elite troop
pSector->ubAdminsInBattle++;
ubNumAvailable--;
ubSlots--;
ubNumAdmins++;
}
else
{
AssertMsg( 0, "AddPossiblePendingEnemiesToBattle(): Logic Error -- by Kris" );
}
}
if( ubNumAdmins || ubNumTroops || ubNumElites )
{ //This group has contributed forces, then add them now, because different
//groups appear on different sides of the map.
UINT8 ubStrategicInsertionCode = ubPredefinedInsertionCode;
//First, determine which entrypoint to use, based on the travel direction of the group.
if( ubStrategicInsertionCode == 255 )
{
if( NumEnemiesInSector( gWorldSectorX + 1, gWorldSectorY ) )
ubStrategicInsertionCode = INSERTION_CODE_EAST;
else if( NumEnemiesInSector( gWorldSectorX - 1, gWorldSectorY ) )
ubStrategicInsertionCode = INSERTION_CODE_WEST;
else if( NumEnemiesInSector( gWorldSectorX, gWorldSectorY + 1 ) )
ubStrategicInsertionCode = INSERTION_CODE_SOUTH;
else if( NumEnemiesInSector( gWorldSectorX, gWorldSectorY - 1 ) )
ubStrategicInsertionCode = INSERTION_CODE_NORTH;
}
if( ubStrategicInsertionCode == 255 )
{
if( !CountAllMilitiaInSector( gWorldSectorX + 1, gWorldSectorY ) )
ubStrategicInsertionCode = INSERTION_CODE_EAST;
else if( !CountAllMilitiaInSector( gWorldSectorX - 1, gWorldSectorY ) )
ubStrategicInsertionCode = INSERTION_CODE_WEST;
else if( !CountAllMilitiaInSector( gWorldSectorX, gWorldSectorY + 1 ) )
ubStrategicInsertionCode = INSERTION_CODE_SOUTH;
else if( !CountAllMilitiaInSector( gWorldSectorX, gWorldSectorY - 1 ) )
ubStrategicInsertionCode = INSERTION_CODE_NORTH;
}
if( ubStrategicInsertionCode < INSERTION_CODE_NORTH ||ubStrategicInsertionCode > INSERTION_CODE_WEST )
ubStrategicInsertionCode = INSERTION_CODE_NORTH + Random( 4 );
AddEnemiesToBattle( 0, ubStrategicInsertionCode, ubNumAdmins, ubNumTroops, ubNumElites, FALSE );
gfPendingEnemies = TRUE;
}
}
ubPredefinedInsertionCode = 255;
// Figure out which groups are in the sector, so we can have reinforcements arrive at random
for (ubNumGroupsInSector = 0, pGroup = gpGroupList; pGroup; pGroup = pGroup->next)
{
if( !pGroup->fPlayer && !pGroup->fVehicle && pGroup->ubSectorX == gWorldSectorX && pGroup->ubSectorY == gWorldSectorY && !gbWorldSectorZ )
ubNumGroupsInSector++;
}
pGroupInSectorList = (GROUP**) MemAlloc( ubNumGroupsInSector * sizeof( GROUP*));
for (ubNumGroupsInSector = 0, pGroup = gpGroupList; pGroup; pGroup = pGroup->next)
{
if( !pGroup->fPlayer && !pGroup->fVehicle && pGroup->ubSectorX == gWorldSectorX && pGroup->ubSectorY == gWorldSectorY && !gbWorldSectorZ )
{
pGroupInSectorList[ ubNumGroupsInSector++] = pGroup;
}
}
while( ubSlots && ubNumGroupsInSector )
{
UINT8 ubInsertionCode = 255;
ubGroupIndex = Random( ubNumGroupsInSector);
pGroup = pGroupInSectorList[ ubGroupIndex];
ubNumAvailable = pGroup->ubGroupSize - pGroup->pEnemyGroup->ubElitesInBattle - pGroup->pEnemyGroup->ubTroopsInBattle - pGroup->pEnemyGroup->ubAdminsInBattle;
if (!ubNumAvailable)
{
// Looks like we picked an empty group. Make a note of it
pGroupInSectorList[ ubGroupIndex] = pGroupInSectorList[ --ubNumGroupsInSector ];
continue;
}
if( pGroup->ubPrevX && pGroup->ubPrevY )
{
if( pGroup->ubSectorX < pGroup->ubPrevX )
ubInsertionCode = INSERTION_CODE_EAST;
else if( pGroup->ubSectorX > pGroup->ubPrevX )
ubInsertionCode = INSERTION_CODE_WEST;
else if( pGroup->ubSectorY < pGroup->ubPrevY )
ubInsertionCode = INSERTION_CODE_SOUTH;
else if( pGroup->ubSectorY > pGroup->ubPrevY )
ubInsertionCode = INSERTION_CODE_NORTH;
else
{
Assert(0);
}
}
else if( pGroup->ubNextX && pGroup->ubNextY )
{
if( pGroup->ubSectorX < pGroup->ubNextX )
ubInsertionCode = INSERTION_CODE_EAST;
else if( pGroup->ubSectorX > pGroup->ubNextX )
ubInsertionCode = INSERTION_CODE_WEST;
else if( pGroup->ubSectorY < pGroup->ubNextY )
ubInsertionCode = INSERTION_CODE_SOUTH;
else if( pGroup->ubSectorY > pGroup->ubNextY )
ubInsertionCode = INSERTION_CODE_NORTH;
else
{
Assert(0);
}
}
else
{
// The group has no movement orders. Where did it come from?
Assert(0);
}
if( pGroup->pEnemyGroup->ubElitesInBattle < pGroup->pEnemyGroup->ubNumElites )
{ //Add an elite troop
pGroup->pEnemyGroup->ubElitesInBattle++;
ubSlots--;
AddEnemiesToBattle( pGroup, ubInsertionCode, 0, 0, 1, FALSE );
}
else if( pGroup->pEnemyGroup->ubTroopsInBattle < pGroup->pEnemyGroup->ubNumTroops )
{ //Add a regular troop.
pGroup->pEnemyGroup->ubTroopsInBattle++;
ubSlots--;
AddEnemiesToBattle( pGroup, ubInsertionCode, 0, 1, 0, FALSE );
}
else if( pGroup->pEnemyGroup->ubAdminsInBattle < pGroup->pEnemyGroup->ubNumAdmins )
{ //Add an admin troop
pGroup->pEnemyGroup->ubAdminsInBattle++;
ubSlots--;
AddEnemiesToBattle( pGroup, ubInsertionCode, 1, 0, 0, FALSE );
}
else
{
AssertMsg( 0, "AddPossiblePendingEnemiesToBattle(): Logic Error -- by Kris" );
}
}
MemFree( pGroupInSectorList);
if( ubSlots )
{ //After going through the process, we have finished with some free slots and no more enemies to add.
//So, we can turn off the flag, as this check is no longer needed.
gfPendingEnemies = FALSE;
}
}
void NotifyPlayersOfNewEnemies()
{
INT32 iSoldiers, iChosenSoldier, i;
SOLDIERTYPE *pSoldier;
BOOLEAN fIgnoreBreath = FALSE;
iSoldiers = 0;
for( i = gTacticalStatus.Team[ OUR_TEAM ].bFirstID; i <= gTacticalStatus.Team[ OUR_TEAM ].bLastID; i++ )
{ //find a merc that is aware.
pSoldier = MercPtrs[ i ];
if( pSoldier->bInSector && pSoldier->bActive && pSoldier->bLife >= OKLIFE && pSoldier->bBreath >= OKBREATH )
{
iSoldiers++;
}
}
if( !iSoldiers )
{ // look for an out of breath merc.
fIgnoreBreath = TRUE;
for( i = gTacticalStatus.Team[ OUR_TEAM ].bFirstID; i <= gTacticalStatus.Team[ OUR_TEAM ].bLastID; i++ )
{ //find a merc that is aware.
pSoldier = MercPtrs[ i ];
if( pSoldier->bInSector && pSoldier->bActive && pSoldier->bLife >= OKLIFE )
{
iSoldiers++;
}
}
}
if( iSoldiers )
{
iChosenSoldier = Random( iSoldiers );
for( i = gTacticalStatus.Team[ OUR_TEAM ].bFirstID; i <= gTacticalStatus.Team[ OUR_TEAM ].bLastID; i++ )
{ //find a merc that is aware.
pSoldier = MercPtrs[ i ];
if( pSoldier->bInSector && pSoldier->bActive && pSoldier->bLife >= OKLIFE &&
( ( pSoldier->bBreath >= OKBREATH ) || fIgnoreBreath ) )
{
if( !iChosenSoldier )
{
// ATE: This is to allow special handling of initial heli drop
if ( !DidGameJustStart() )
{
TacticalCharacterDialogueWithSpecialEvent( pSoldier, QUOTE_ENEMY_PRESENCE, 0, 0, 0 );
}
return;
}
iChosenSoldier--;
}
}
}
else
{ //There is either nobody here or our mercs can't talk
}
}
void AddEnemiesToBattle( GROUP *pGroup, UINT8 ubStrategicInsertionCode, UINT8 ubNumAdmins, UINT8 ubNumTroops, UINT8 ubNumElites, BOOLEAN fMagicallyAppeared )
{
SOLDIERTYPE *pSoldier;
MAPEDGEPOINTINFO MapEdgepointInfo;
UINT8 ubCurrSlot;
UINT8 ubTotalSoldiers;
UINT8 bDesiredDirection=0;
switch( ubStrategicInsertionCode )
{
case INSERTION_CODE_NORTH: bDesiredDirection = SOUTHEAST; break;
case INSERTION_CODE_EAST: bDesiredDirection = SOUTHWEST; break;
case INSERTION_CODE_SOUTH: bDesiredDirection = NORTHWEST; break;
case INSERTION_CODE_WEST: bDesiredDirection = NORTHEAST; break;
default: AssertMsg( 0, "Illegal direction passed to AddEnemiesToBattle()" ); break;
}
#ifdef JA2TESTVERSION
ScreenMsg( FONT_RED, MSG_INTERFACE, L"Enemy reinforcements have arrived! (%d admins, %d troops, %d elite)", ubNumAdmins, ubNumTroops, ubNumElites );
#endif
if( fMagicallyAppeared )
{ //update the strategic counters
if( !gbWorldSectorZ )
{
SECTORINFO *pSector = &SectorInfo[ SECTOR( gWorldSectorX, gWorldSectorY ) ];
pSector->ubNumAdmins += ubNumAdmins;
pSector->ubAdminsInBattle += ubNumAdmins;
pSector->ubNumTroops += ubNumTroops;
pSector->ubTroopsInBattle += ubNumTroops;
pSector->ubNumElites += ubNumElites;
pSector->ubElitesInBattle += ubNumElites;
}
else
{
UNDERGROUND_SECTORINFO *pSector = FindUnderGroundSector( gWorldSectorX, gWorldSectorY, gbWorldSectorZ );
if( pSector )
{
pSector->ubNumAdmins += ubNumAdmins;
pSector->ubAdminsInBattle += ubNumAdmins;
pSector->ubNumTroops += ubNumTroops;
pSector->ubTroopsInBattle += ubNumTroops;
pSector->ubNumElites += ubNumElites;
pSector->ubElitesInBattle += ubNumElites;
}
}
//Because the enemies magically appeared, have one of our soldiers say something...
NotifyPlayersOfNewEnemies();
}
ubTotalSoldiers = ubNumAdmins + ubNumTroops + ubNumElites;
ChooseMapEdgepoints( &MapEdgepointInfo, ubStrategicInsertionCode, (UINT8)(ubNumAdmins+ubNumElites+ubNumTroops) );
ubCurrSlot = 0;
while( ubTotalSoldiers )
{
if( ubNumElites && Random( ubTotalSoldiers ) < ubNumElites )
{
ubNumElites--;
ubTotalSoldiers--;
pSoldier = TacticalCreateEliteEnemy();
if( pGroup )
{
pSoldier->ubGroupID = pGroup->ubGroupID;
}
pSoldier->ubInsertionDirection = bDesiredDirection;
//Setup the position
if( ubCurrSlot < MapEdgepointInfo.ubNumPoints )
{ //using an edgepoint
pSoldier->ubStrategicInsertionCode = INSERTION_CODE_GRIDNO;
pSoldier->usStrategicInsertionData = MapEdgepointInfo.sGridNo[ ubCurrSlot++ ];
}
else
{ //no edgepoints left, so put him at the entrypoint.
pSoldier->ubStrategicInsertionCode = ubStrategicInsertionCode;
}
UpdateMercInSector( pSoldier, gWorldSectorX, gWorldSectorY, 0 );
}
else if( ubNumTroops && (UINT8)Random( ubTotalSoldiers ) < (UINT8)(ubNumElites + ubNumTroops) )
{
ubNumTroops--;
ubTotalSoldiers--;
pSoldier = TacticalCreateArmyTroop();
if( pGroup )
{
pSoldier->ubGroupID = pGroup->ubGroupID;
}
pSoldier->ubInsertionDirection = bDesiredDirection;
//Setup the position
if( ubCurrSlot < MapEdgepointInfo.ubNumPoints )
{ //using an edgepoint
pSoldier->ubStrategicInsertionCode = INSERTION_CODE_GRIDNO;
pSoldier->usStrategicInsertionData = MapEdgepointInfo.sGridNo[ ubCurrSlot++ ];
}
else
{ //no edgepoints left, so put him at the entrypoint.
pSoldier->ubStrategicInsertionCode = ubStrategicInsertionCode;
}
UpdateMercInSector( pSoldier, gWorldSectorX, gWorldSectorY, 0 );
}
else if( ubNumAdmins && (UINT8)Random( ubTotalSoldiers ) < (UINT8)(ubNumElites + ubNumTroops + ubNumAdmins) )
{
ubNumAdmins--;
ubTotalSoldiers--;
pSoldier = TacticalCreateAdministrator();
if( pGroup )
{
pSoldier->ubGroupID = pGroup->ubGroupID;
}
pSoldier->ubInsertionDirection = bDesiredDirection;
//Setup the position
if( ubCurrSlot < MapEdgepointInfo.ubNumPoints )
{ //using an edgepoint
pSoldier->ubStrategicInsertionCode = INSERTION_CODE_GRIDNO;
pSoldier->usStrategicInsertionData = MapEdgepointInfo.sGridNo[ ubCurrSlot++ ];
}
else
{ //no edgepoints left, so put him at the entrypoint.
pSoldier->ubStrategicInsertionCode = ubStrategicInsertionCode;
}
UpdateMercInSector( pSoldier, gWorldSectorX, gWorldSectorY, 0 );
}
}
}
BOOLEAN SaveUnderGroundSectorInfoToSaveGame( HWFILE hFile )
{
UINT32 uiNumBytesWritten;
UINT32 uiNumOfRecords=0;
UNDERGROUND_SECTORINFO *TempNode = gpUndergroundSectorInfoHead;
//Loop through all the nodes to count how many there are
while( TempNode )
{
uiNumOfRecords++;
TempNode = TempNode->next;
}
//Write how many nodes there are
FileWrite( hFile, &uiNumOfRecords, sizeof( UINT32 ), &uiNumBytesWritten );
if( uiNumBytesWritten != sizeof( UINT32 ) )
{
return(FALSE);
}
TempNode = gpUndergroundSectorInfoHead;
//Go through each node and save it.
while( TempNode )
{
FileWrite( hFile, TempNode, sizeof( UNDERGROUND_SECTORINFO ), &uiNumBytesWritten );
if( uiNumBytesWritten != sizeof( UNDERGROUND_SECTORINFO ) )
{
return(FALSE);
}
TempNode = TempNode->next;
}
return( TRUE );
}
BOOLEAN LoadUnderGroundSectorInfoFromSavedGame( HWFILE hFile )
{
UINT32 uiNumBytesRead;
UINT32 uiNumOfRecords=0;
UINT32 cnt=0;
UNDERGROUND_SECTORINFO *TempNode = NULL;
UNDERGROUND_SECTORINFO *TempSpot = NULL;
//Clear the current LL
TrashUndergroundSectorInfo();
//Read in the number of nodes stored
FileRead( hFile, &uiNumOfRecords, sizeof( UINT32 ), &uiNumBytesRead );
if( uiNumBytesRead != sizeof( UINT32 ) )
{
return(FALSE);
}
for( cnt = 0; cnt< uiNumOfRecords; cnt ++)
{
//Malloc space for the new node
TempNode = (UNDERGROUND_SECTORINFO *) MemAlloc( sizeof( UNDERGROUND_SECTORINFO ) );
if( TempNode == NULL )
return( FALSE );
//read in the new node
FileRead( hFile, TempNode, sizeof( UNDERGROUND_SECTORINFO ), &uiNumBytesRead );
if( uiNumBytesRead != sizeof( UNDERGROUND_SECTORINFO ) )
{
return(FALSE);
}
//If its the first time in, assign the node to the list
if( cnt == 0 )
{
gpUndergroundSectorInfoHead = TempNode;
TempSpot = gpUndergroundSectorInfoHead;
TempSpot->next = NULL;
}
else
{
//assign the new node to the LL
TempSpot->next = TempNode;
//advance to the next node
TempSpot = TempSpot->next;
TempSpot->next = NULL;
gpUndergroundSectorInfoTail = TempSpot;
}
}
#ifdef JA2BETAVERSION
if( !uiNumOfRecords )
{
BuildUndergroundSectorInfoList();
gfClearCreatureQuest = TRUE;
}
#endif
return( TRUE );
}
UNDERGROUND_SECTORINFO* FindUnderGroundSector( INT16 sMapX, INT16 sMapY, UINT8 bMapZ )
{
UNDERGROUND_SECTORINFO *pUnderground;
pUnderground = gpUndergroundSectorInfoHead;
//Loop through all the underground sectors looking for specified sector
while( pUnderground )
{
//If the sector is the right one
if( pUnderground->ubSectorX == sMapX &&
pUnderground->ubSectorY == sMapY &&
pUnderground->ubSectorZ == bMapZ )
{
return( pUnderground );
}
pUnderground = pUnderground->next;
}
return( NULL );
}
void BeginCaptureSquence( )
{
if( !( gStrategicStatus.uiFlags & STRATEGIC_PLAYER_CAPTURED_FOR_RESCUE ) || !( gStrategicStatus.uiFlags & STRATEGIC_PLAYER_CAPTURED_FOR_ESCAPE ) )
{
gStrategicStatus.ubNumCapturedForRescue = 0;
}
}
void EndCaptureSequence( )
{
// Set flag...
if( !( gStrategicStatus.uiFlags & STRATEGIC_PLAYER_CAPTURED_FOR_RESCUE ) || !(gStrategicStatus.uiFlags & STRATEGIC_PLAYER_CAPTURED_FOR_ESCAPE) )
{
// CJC Dec 1 2002: fixing multiple captures:
//gStrategicStatus.uiFlags |= STRATEGIC_PLAYER_CAPTURED_FOR_RESCUE;
if ( gubQuest[ QUEST_HELD_IN_ALMA ] == QUESTNOTSTARTED )
{
// CJC Dec 1 2002: fixing multiple captures:
gStrategicStatus.uiFlags |= STRATEGIC_PLAYER_CAPTURED_FOR_RESCUE;
StartQuest( QUEST_HELD_IN_ALMA, gWorldSectorX, gWorldSectorY );
}
// CJC Dec 1 2002: fixing multiple captures:
//else if ( gubQuest[ QUEST_HELD_IN_ALMA ] == QUESTDONE )
else if ( gubQuest[ QUEST_HELD_IN_ALMA ] == QUESTDONE && gubQuest[ QUEST_INTERROGATION ] == QUESTNOTSTARTED )
{
StartQuest( QUEST_INTERROGATION, gWorldSectorX, gWorldSectorY );
// CJC Dec 1 2002: fixing multiple captures:
gStrategicStatus.uiFlags |= STRATEGIC_PLAYER_CAPTURED_FOR_ESCAPE;
// OK! - Schedule Meanwhile now!
{
MEANWHILE_DEFINITION MeanwhileDef;
MeanwhileDef.sSectorX = 7;
MeanwhileDef.sSectorY = 14;
MeanwhileDef.ubNPCNumber = QUEEN;
MeanwhileDef.usTriggerEvent = 0;
MeanwhileDef.ubMeanwhileID = INTERROGATION;
ScheduleMeanwhileEvent( &MeanwhileDef, 10 );
}
}
// CJC Dec 1 2002: fixing multiple captures
else
{
// !?!? set both flags
gStrategicStatus.uiFlags |= STRATEGIC_PLAYER_CAPTURED_FOR_RESCUE;
gStrategicStatus.uiFlags |= STRATEGIC_PLAYER_CAPTURED_FOR_ESCAPE;
}
}
}
void EnemyCapturesPlayerSoldier( SOLDIERTYPE *pSoldier )
{
INT32 i;
WORLDITEM WorldItem;
BOOLEAN fMadeCorpse;
INT32 iNumEnemiesInSector;
static INT16 sAlmaCaptureGridNos[] = { 9208, 9688, 9215 };
static INT16 sAlmaCaptureItemsGridNo[] = { 12246, 12406, 13046 };
static INT16 sInterrogationItemGridNo[] = { 12089, 12089, 12089 };
// ATE: Check first if ! in player captured sequence already
// CJC Dec 1 2002: fixing multiple captures
if ( ( gStrategicStatus.uiFlags & STRATEGIC_PLAYER_CAPTURED_FOR_RESCUE ) && (gStrategicStatus.uiFlags & STRATEGIC_PLAYER_CAPTURED_FOR_ESCAPE) )
{
return;
}
// ATE: If maximum prisoners captured, return!
if ( gStrategicStatus.ubNumCapturedForRescue > 3 )
{
return;
}
// If this is an EPC , just kill them...
if ( AM_AN_EPC( pSoldier ) )
{
pSoldier->bLife = 0;
HandleSoldierDeath( pSoldier, &fMadeCorpse );
return;
}
if ( pSoldier->uiStatusFlags & SOLDIER_VEHICLE )
{
return;
}
// ATE: Patch fix If in a vehicle, remove from vehicle...
TakeSoldierOutOfVehicle( pSoldier );
// Are there anemies in ALMA? ( I13 )
iNumEnemiesInSector = NumEnemiesInSector( 13, 9 );
// IF there are no enemies, and we need to do alma, skip!
if ( gubQuest[ QUEST_HELD_IN_ALMA ] == QUESTNOTSTARTED && iNumEnemiesInSector == 0 )
{
InternalStartQuest( QUEST_HELD_IN_ALMA, gWorldSectorX, gWorldSectorY, FALSE );
InternalEndQuest( QUEST_HELD_IN_ALMA, gWorldSectorX, gWorldSectorY, FALSE );
}
HandleMoraleEvent( pSoldier, MORALE_MERC_CAPTURED, pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ );
// Change to POW....
//-add him to a POW assignment/group
if( ( pSoldier->bAssignment != ASSIGNMENT_POW ) )
{
SetTimeOfAssignmentChangeForMerc( pSoldier );
}
ChangeSoldiersAssignment( pSoldier, ASSIGNMENT_POW );
// ATE: Make them neutral!
if ( gubQuest[ QUEST_HELD_IN_ALMA ] == QUESTNOTSTARTED )
{
pSoldier->bNeutral = TRUE;
}
RemoveCharacterFromSquads( pSoldier );
// Is this the first one..?
if ( gubQuest[ QUEST_HELD_IN_ALMA ] == QUESTNOTSTARTED )
{
//-teleport him to NE Alma sector (not Tixa as originally planned)
pSoldier->sSectorX = 13;
pSoldier->sSectorY = 9;
pSoldier->bSectorZ = 0;
// put him on the floor!!
pSoldier->bLevel = 0;
// OK, drop all items!
for ( i = 0; i < NUM_INV_SLOTS; i++ )
{
if( pSoldier->inv[ i ].usItem != 0 )
{
WorldItem.fExists = TRUE;
WorldItem.sGridNo = sAlmaCaptureItemsGridNo[ gStrategicStatus.ubNumCapturedForRescue ];
WorldItem.ubLevel = 0;
WorldItem.usFlags = 0;
WorldItem.bVisible = FALSE;
WorldItem.bRenderZHeightAboveLevel = 0;
memcpy( &(WorldItem.o), &pSoldier->inv[i], sizeof( OBJECTTYPE ) );
AddWorldItemsToUnLoadedSector( 13, 9, 0, sAlmaCaptureItemsGridNo[ gStrategicStatus.ubNumCapturedForRescue ], 1, &WorldItem, FALSE );
DeleteObj( &( pSoldier->inv[ i ] ) );
}
}
pSoldier->ubStrategicInsertionCode = INSERTION_CODE_GRIDNO;
pSoldier->usStrategicInsertionData = sAlmaCaptureGridNos[ gStrategicStatus.ubNumCapturedForRescue ];
gStrategicStatus.ubNumCapturedForRescue++;
}
else if ( gubQuest[ QUEST_HELD_IN_ALMA ] == QUESTDONE )
{
//-teleport him to N7
pSoldier->sSectorX = 7;
pSoldier->sSectorY = 14;
pSoldier->bSectorZ = 0;
// put him on the floor!!
pSoldier->bLevel = 0;
// OK, drop all items!
for ( i = 0; i < NUM_INV_SLOTS; i++ )
{
if( pSoldier->inv[ i ].usItem != 0 )
{
WorldItem.fExists = TRUE;
WorldItem.sGridNo = sInterrogationItemGridNo[ gStrategicStatus.ubNumCapturedForRescue ];
WorldItem.ubLevel = 0;
WorldItem.usFlags = 0;
WorldItem.bVisible = FALSE;
WorldItem.bRenderZHeightAboveLevel = 0;
memcpy( &(WorldItem.o), &pSoldier->inv[i], sizeof( OBJECTTYPE ) );
AddWorldItemsToUnLoadedSector( 7, 14, 0, sInterrogationItemGridNo[ gStrategicStatus.ubNumCapturedForRescue ], 1, &WorldItem, FALSE );
DeleteObj( &( pSoldier->inv[ i ] ) );
}
}
pSoldier->ubStrategicInsertionCode = INSERTION_CODE_GRIDNO;
pSoldier->usStrategicInsertionData = gsInterrogationGridNo[ gStrategicStatus.ubNumCapturedForRescue ];
gStrategicStatus.ubNumCapturedForRescue++;
}
//Bandaging him would prevent him from dying (due to low HP)
pSoldier->bBleeding = 0;
// wake him up
if ( pSoldier->fMercAsleep )
{
PutMercInAwakeState( pSoldier );
pSoldier->fForcedToStayAwake = FALSE;
}
//Set his life to 50% + or - 10 HP.
pSoldier->bLife = pSoldier->bLifeMax / 2;
if ( pSoldier->bLife <= 35 )
{
pSoldier->bLife = 35;
}
else if ( pSoldier->bLife >= 45 )
{
pSoldier->bLife += (INT8)(10 - Random( 21 ) );
}
// make him quite exhausted when found
pSoldier->bBreath = pSoldier->bBreathMax = 50;
pSoldier->sBreathRed = 0;
pSoldier->fMercCollapsedFlag = FALSE;
}
void HandleEnemyStatusInCurrentMapBeforeLoadingNewMap()
{
INT32 i;
BOOLEAN fMadeCorpse;
INT8 bKilledEnemies = 0, bKilledCreatures = 0, bKilledRebels = 0, bKilledCivilians = 0;
return;
//If any of the soldiers are dying, kill them now.
for( i = gTacticalStatus.Team[ ENEMY_TEAM ].bFirstID; i <= gTacticalStatus.Team[ ENEMY_TEAM ].bLastID; i++ )
{
if( MercPtrs[ i ]->bActive && MercPtrs[ i ]->bLife < OKLIFE && MercPtrs[ i ]->bLife )
{
MercPtrs[ i ]->bLife = 0;
HandleSoldierDeath( MercPtrs[ i ], &fMadeCorpse );
bKilledEnemies++;
}
}
//Do the same for the creatures.
for( i = gTacticalStatus.Team[ CREATURE_TEAM ].bFirstID; i <= gTacticalStatus.Team[ CREATURE_TEAM ].bLastID; i++ )
{
if( MercPtrs[ i ]->bActive && MercPtrs[ i ]->bLife < OKLIFE && MercPtrs[ i ]->bLife )
{
MercPtrs[ i ]->bLife = 0;
HandleSoldierDeath( MercPtrs[ i ], &fMadeCorpse );
bKilledCreatures++;
}
}
//Militia
for( i = gTacticalStatus.Team[ MILITIA_TEAM ].bFirstID; i <= gTacticalStatus.Team[ MILITIA_TEAM ].bLastID; i++ )
{
if( MercPtrs[ i ]->bActive && MercPtrs[ i ]->bLife < OKLIFE && MercPtrs[ i ]->bLife )
{
MercPtrs[ i ]->bLife = 0;
HandleSoldierDeath( MercPtrs[ i ], &fMadeCorpse );
bKilledRebels++;
}
}
//Civilians
for( i = gTacticalStatus.Team[ CIV_TEAM ].bFirstID; i <= gTacticalStatus.Team[ CIV_TEAM ].bLastID; i++ )
{
if( MercPtrs[ i ]->bActive && MercPtrs[ i ]->bLife < OKLIFE && MercPtrs[ i ]->bLife )
{
MercPtrs[ i ]->bLife = 0;
HandleSoldierDeath( MercPtrs[ i ], &fMadeCorpse );
bKilledCivilians++;
}
}
// TEST MESSAGES ONLY!
if( bKilledCivilians )
ScreenMsg( FONT_BLUE, MSG_TESTVERSION, L"%d civilians died after you left the sector.", bKilledCivilians );
if( bKilledRebels )
ScreenMsg( FONT_BLUE, MSG_TESTVERSION, L"%d militia died after you left the sector.", bKilledRebels );
if( bKilledEnemies )
ScreenMsg( FONT_BLUE, MSG_TESTVERSION, L"%d enemies died after you left the sector.", bKilledEnemies );
if( bKilledCreatures )
ScreenMsg( FONT_BLUE, MSG_TESTVERSION, L"%d creatures died after you left the sector.", bKilledCreatures );
if( !gbWorldSectorZ )
{
SECTORINFO *pSector;
pSector = &SectorInfo[ SECTOR(gWorldSectorX, gWorldSectorY) ];
pSector->ubAdminsInBattle = 0;
pSector->ubTroopsInBattle = 0;
pSector->ubElitesInBattle = 0;
pSector->ubCreaturesInBattle = 0;
//RecalculateSectorWeight(
}
else if( gbWorldSectorZ > 0 )
{
UNDERGROUND_SECTORINFO *pSector;
pSector = FindUnderGroundSector( gWorldSectorX, gWorldSectorY, gbWorldSectorZ );
if( !pSector )
return;
pSector->ubAdminsInBattle = 0;
pSector->ubTroopsInBattle = 0;
pSector->ubElitesInBattle = 0;
pSector->ubCreaturesInBattle = 0;
}
}
BOOLEAN PlayerSectorDefended( UINT8 ubSectorID )
{
SECTORINFO *pSector;
pSector = &SectorInfo[ ubSectorID ];
if( pSector->ubNumberOfCivsAtLevel[ GREEN_MILITIA ] +
pSector->ubNumberOfCivsAtLevel[ REGULAR_MILITIA ] +
pSector->ubNumberOfCivsAtLevel[ ELITE_MILITIA ] )
{ //militia in sector
return TRUE;
}
if( FindMovementGroupInSector( (UINT8)SECTORX( ubSectorID ), (UINT8)SECTORY( ubSectorID ), TRUE ) )
{ //player in sector
return TRUE;
}
return FALSE;
}
//Assumes gTacticalStatus.fEnemyInSector
BOOLEAN OnlyHostileCivsInSector()
{
SOLDIERTYPE *pSoldier;
INT32 i;
BOOLEAN fHostileCivs = FALSE;
//Look for any hostile civs.
for( i = gTacticalStatus.Team[ CIV_TEAM ].bFirstID; i <= gTacticalStatus.Team[ CIV_TEAM ].bLastID; i++ )
{
pSoldier = MercPtrs[ i ];
if( pSoldier->bActive && pSoldier->bInSector && pSoldier->bLife )
{
if( !pSoldier->bNeutral )
{
fHostileCivs = TRUE;
break;
}
}
}
if( !fHostileCivs )
{ //No hostile civs, so return FALSE
return FALSE;
}
//Look for anybody else hostile. If found, return FALSE immediately.
for( i = gTacticalStatus.Team[ ENEMY_TEAM ].bFirstID; i <= gTacticalStatus.Team[ ENEMY_TEAM ].bLastID; i++ )
{
pSoldier = MercPtrs[ i ];
if( pSoldier->bActive && pSoldier->bInSector && pSoldier->bLife )
{
if( !pSoldier->bNeutral )
{
return FALSE;
}
}
}
for( i = gTacticalStatus.Team[ CREATURE_TEAM ].bFirstID; i <= gTacticalStatus.Team[ CREATURE_TEAM ].bLastID; i++ )
{
pSoldier = MercPtrs[ i ];
if( pSoldier->bActive && pSoldier->bInSector && pSoldier->bLife )
{
if( !pSoldier->bNeutral )
{
return FALSE;
}
}
}
for( i = gTacticalStatus.Team[ MILITIA_TEAM ].bFirstID; i <= gTacticalStatus.Team[ MILITIA_TEAM ].bLastID; i++ )
{
pSoldier = MercPtrs[ i ];
if( pSoldier->bActive && pSoldier->bInSector && pSoldier->bLife )
{
if( !pSoldier->bNeutral )
{
return FALSE;
}
}
}
//We only have hostile civilians, don't allow time compression.
return TRUE;
}