Files
source/Strategic/Queen Command.cpp
T
2018-08-15 14:37:15 +00:00

3031 lines
102 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"
#include "CampaignStats.h" // added by Flugente
#include "ASD.h" // added by Flugente
#endif
#ifdef JA2BETAVERSION
extern BOOLEAN gfClearCreatureQuest;
#endif
#include "connect.h"
#include "Reinforcement.h"
#include "MilitiaSquads.h"
#ifdef JA2UB
#include "Explosion Control.h"
#include "Ja25_Tactical.h"
#include "Ja25 Strategic Ai.h"
#include "MapScreen Quotes.h"
#include "email.h"
#include "interface Dialogue.h"
#include "Arms Dealer Init.h"
#endif
#include "GameInitOptionsScreen.h"
#include <vector>
//The sector information required for the strategic AI. Contains the number of enemy troops,
//as well as intentions, etc.
//SECTORINFO SectorInfo[256];
std::vector<SECTORINFO> SectorInfo (256);
UNDERGROUND_SECTORINFO *gpUndergroundSectorInfoHead = NULL;
extern UNDERGROUND_SECTORINFO* gpUndergroundSectorInfoTail;
BOOLEAN gfPendingNonPlayerTeam[PLAYER_PLAN] = {FALSE, FALSE, FALSE, FALSE, FALSE};
UINT32 guiTurnCnt = 0, guiReinforceTurn = 0, guiArrived = 0;//dnl ch68 080913
extern void BuildUndergroundSectorInfoList();
extern void EndCreatureQuest();
extern GARRISON_GROUP *gGarrisonGroup;
extern INT32 giGarrisonArraySize;
#ifdef JA2TESTVERSION
extern BOOLEAN gfOverrideSector;
#endif
//Buggler: Externalized to gModSettings.iMeanwhileInterrogatePOWGridNo
//INT32 gsInterrogationGridNo[3] = { 7756, 7757, 7758 };
#ifdef JA2UB
INT32 gsGridNoForMapEdgePointInfo=-1;
#endif
#ifdef JA2UB
void HandleBloodCatDeaths( SECTORINFO *pSector );
#endif
extern void Ensure_RepairedGarrisonGroup( GARRISON_GROUP **ppGarrison, INT32 *pGarraySize );
void ValidateEnemiesHaveWeapons()
{
#ifdef JA2BETAVERSION
SGPRect CenteringRect= {0 + xResOffset, 0, SCREEN_WIDTH - xResOffset, SCREEN_HEIGHT };
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;
}
// Flugente: zombies are fine with having no weapons...
if ( pSoldier->IsZombie() )
continue;
if( !pSoldier->inv[ HANDPOS ].usItem )
{
++iNumInvalid;
}
// WDS DEBUG
// Uncommenting the following two lines will cause all the PLACED soldiers to instantly drop dead,
// which is useful for debugging some things
//pSoldier->bBleeding = 10;
//pSoldier->stats.bLife = 1;
}
// 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;
AssertGE( sSectorX, MINIMUM_VALID_X_COORDINATE);
AssertLE( sSectorX, MAXIMUM_VALID_X_COORDINATE );
AssertGE( sSectorY, MINIMUM_VALID_Y_COORDINATE);
AssertLE( sSectorY, MAXIMUM_VALID_Y_COORDINATE );
AssertGE( sSectorZ, MINIMUM_VALID_Z_COORDINATE );
AssertLE( sSectorZ, MAXIMUM_VALID_Z_COORDINATE );
if( sSectorZ )
{
UNDERGROUND_SECTORINFO *pSector;
pSector = FindUnderGroundSector( sSectorX, sSectorY, (UINT8)sSectorZ );
if( pSector )
{
ubNumHostiles = (UINT8)(pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumCreatures + pSector->ubNumJeeps + pSector->ubNumTanks);
}
}
else
{
SECTORINFO *pSector;
GROUP *pGroup;
//Count stationary hostiles
pSector = &SectorInfo[ SECTOR( sSectorX, sSectorY ) ];
ubNumHostiles = (UINT8)(pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumCreatures + pSector->ubNumJeeps + pSector->ubNumTanks);
//Count mobile enemies
pGroup = gpGroupList;
while( pGroup )
{
if ( pGroup->usGroupTeam != OUR_TEAM && pGroup->usGroupTeam != MILITIA_TEAM && !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;
AssertGE( sSectorX, MINIMUM_VALID_X_COORDINATE);
AssertLE( sSectorX, MAXIMUM_VALID_X_COORDINATE );
AssertGE( sSectorY, MINIMUM_VALID_Y_COORDINATE);
AssertLE( sSectorY, MAXIMUM_VALID_Y_COORDINATE );
AssertGE( sSectorZ, MINIMUM_VALID_Z_COORDINATE );
AssertLE( sSectorZ, MAXIMUM_VALID_Z_COORDINATE );
if( sSectorZ )
{
UNDERGROUND_SECTORINFO *pSector;
pSector = FindUnderGroundSector( sSectorX, sSectorY, (UINT8)sSectorZ );
if( pSector )
{
ubNumEnemies = (UINT8)(pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumJeeps + pSector->ubNumTanks);
}
}
else
{
SECTORINFO *pSector;
GROUP *pGroup;
//Count stationary enemies
pSector = &SectorInfo[ SECTOR( sSectorX, sSectorY ) ];
ubNumEnemies = (UINT8)(pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumJeeps + pSector->ubNumTanks);
//Count mobile enemies
pGroup = gpGroupList;
while( pGroup )
{
if ( pGroup->usGroupTeam != OUR_TEAM && pGroup->usGroupTeam != MILITIA_TEAM && !pGroup->fVehicle && pGroup->ubSectorX == sSectorX && pGroup->ubSectorY == sSectorY )
{
ubNumEnemies += pGroup->ubGroupSize;
}
pGroup = pGroup->next;
}
}
return ubNumEnemies;
}
// returns how many members of a team are in a sector - not intended for OUR_TEAM!
UINT8 NumNonPlayerTeamMembersInSector( INT16 sSectorX, INT16 sSectorY, UINT8 ubTeam )
{
SECTORINFO *pSector;
GROUP *pGroup;
UINT8 ubNumTroops;
// HEADROCK: This is a TEMPORARY fix to avoid the assertion error. Not sure this is the best solution,
// probably isn't. But I need this bit to work.
if (sSectorX < MINIMUM_VALID_X_COORDINATE ||
sSectorX > MAXIMUM_VALID_X_COORDINATE ||
sSectorY < MINIMUM_VALID_Y_COORDINATE ||
sSectorY > MAXIMUM_VALID_Y_COORDINATE)
{
return (0);
}
AssertGE( sSectorX, MINIMUM_VALID_X_COORDINATE);
AssertLE( sSectorX, MAXIMUM_VALID_X_COORDINATE );
AssertGE( sSectorY, MINIMUM_VALID_Y_COORDINATE);
AssertLE( sSectorY, MAXIMUM_VALID_Y_COORDINATE );
pSector = &SectorInfo[ SECTOR( sSectorX, sSectorY ) ];
if ( ubTeam == ENEMY_TEAM )
{
ubNumTroops = (UINT8)(pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumJeeps + pSector->ubNumTanks);
if ( is_networked )
ubNumTroops += numenemyLAN((UINT8)sSectorX,(UINT8)sSectorY ); //hayden
}
else if ( ubTeam == MILITIA_TEAM )
{
ubNumTroops = (UINT8)(pSector->ubNumberOfCivsAtLevel[0] + pSector->ubNumberOfCivsAtLevel[1] + pSector->ubNumberOfCivsAtLevel[2]);
}
else if ( ubTeam == CREATURE_TEAM )
{
ubNumTroops = pSector->ubNumCreatures;
}
pGroup = gpGroupList;
while( pGroup )
{
if ( pGroup->usGroupTeam == ubTeam && !pGroup->fVehicle && pGroup->ubSectorX == sSectorX && pGroup->ubSectorY == sSectorY )
{
ubNumTroops += pGroup->ubGroupSize;
}
pGroup = pGroup->next;
}
return ubNumTroops;
}
// returns how many members of a team are in a sector - only intended for OUR_TEAM! POWs not included
UINT16 NumPlayerTeamMembersInSector( INT16 sSectorX, INT16 sSectorY, INT8 sSectorZ )
{
UINT16 teammemberspresent = 0;
SOLDIERTYPE* pTeamSoldier = NULL;
UINT16 bMercID = gTacticalStatus.Team[gbPlayerNum].bFirstID;
UINT16 bLastTeamID = gTacticalStatus.Team[gbPlayerNum].bLastID;
for ( pTeamSoldier = MercPtrs[bMercID]; bMercID <= bLastTeamID; ++bMercID, pTeamSoldier++ )
{
// we test several conditions before we allow adding an opinion
// other merc must be active, have a profile, be someone else and not be in transit or dead
if ( pTeamSoldier->bActive && !pTeamSoldier->flags.fBetweenSectors && pTeamSoldier->stats.bLife > 0 && !(pTeamSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE) &&
!(pTeamSoldier->bAssignment == IN_TRANSIT || pTeamSoldier->bAssignment == ASSIGNMENT_DEAD || pTeamSoldier->bAssignment == ASSIGNMENT_POW) &&
(pTeamSoldier->sSectorX == sSectorX && pTeamSoldier->sSectorY == sSectorY && pTeamSoldier->bSectorZ == sSectorZ) )
{
++teammemberspresent;
}
}
return teammemberspresent;
}
UINT16 NumEnemyArmedVehiclesInSector( INT16 sSectorX, INT16 sSectorY, UINT8 usTeam )
{
SECTORINFO *pSector;
GROUP *pGroup;
UINT16 ubNum;
// HEADROCK: This is a TEMPORARY fix to avoid the assertion error. Not sure this is the best solution,
// probably isn't. But I need this bit to work.
if ( sSectorX < MINIMUM_VALID_X_COORDINATE ||
sSectorX > MAXIMUM_VALID_X_COORDINATE ||
sSectorY < MINIMUM_VALID_Y_COORDINATE ||
sSectorY > MAXIMUM_VALID_Y_COORDINATE )
{
return (0);
}
AssertGE( sSectorX, MINIMUM_VALID_X_COORDINATE );
AssertLE( sSectorX, MAXIMUM_VALID_X_COORDINATE );
AssertGE( sSectorY, MINIMUM_VALID_Y_COORDINATE );
AssertLE( sSectorY, MAXIMUM_VALID_Y_COORDINATE );
pSector = &SectorInfo[SECTOR( sSectorX, sSectorY )];
if ( usTeam == ENEMY_TEAM )
ubNum = (UINT16)(pSector->ubNumTanks + pSector->ubNumJeeps);
pGroup = gpGroupList;
while ( pGroup )
{
if ( pGroup->usGroupTeam == usTeam && !pGroup->fVehicle && pGroup->ubSectorX == sSectorX && pGroup->ubSectorY == sSectorY )
{
ubNum += pGroup->pEnemyGroup->ubNumTanks + pGroup->pEnemyGroup->ubNumJeeps;
}
pGroup = pGroup->next;
}
return ubNum;
}
UINT8 NumStationaryEnemiesInSector( INT16 sSectorX, INT16 sSectorY )
{
SECTORINFO *pSector;
AssertGE( sSectorX, MINIMUM_VALID_X_COORDINATE);
AssertLE( sSectorX, MAXIMUM_VALID_X_COORDINATE );
AssertGE( sSectorY, MINIMUM_VALID_Y_COORDINATE);
AssertLE( sSectorY, MAXIMUM_VALID_Y_COORDINATE );
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 + pSector->ubNumTanks);
}
UINT8 NumMobileEnemiesInSector( INT16 sSectorX, INT16 sSectorY )
{
GROUP *pGroup;
SECTORINFO *pSector;
UINT8 ubNumTroops;
AssertGE( sSectorX, MINIMUM_VALID_X_COORDINATE);
AssertLE( sSectorX, MAXIMUM_VALID_X_COORDINATE );
AssertGE( sSectorY, MINIMUM_VALID_Y_COORDINATE);
AssertLE( sSectorY, MAXIMUM_VALID_Y_COORDINATE );
ubNumTroops = 0;
pGroup = gpGroupList;
while( pGroup )
{
if ( pGroup->usGroupTeam != OUR_TEAM && pGroup->usGroupTeam != MILITIA_TEAM && !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 + pSector->ubNumJeeps + pSector->ubNumTanks);
}
return ubNumTroops;
}
void GetNumberOfMobileEnemiesInSector( INT16 sSectorX, INT16 sSectorY, UINT8 *pubNumAdmins, UINT8 *pubNumTroops, UINT8 *pubNumElites, UINT8 *pubNumTanks, UINT8 *pubNumJeeps )
{
GROUP *pGroup;
SECTORINFO *pSector;
AssertGE( sSectorX, MINIMUM_VALID_X_COORDINATE);
AssertLE( sSectorX, MAXIMUM_VALID_X_COORDINATE );
AssertGE( sSectorY, MINIMUM_VALID_Y_COORDINATE);
AssertLE( sSectorY, MAXIMUM_VALID_Y_COORDINATE );
//Now count the number of mobile groups in the sector.
*pubNumTroops = *pubNumElites = *pubNumAdmins = *pubNumTanks = *pubNumJeeps =0;
pGroup = gpGroupList;
while( pGroup )
{
if ( pGroup->usGroupTeam != OUR_TEAM && pGroup->usGroupTeam != MILITIA_TEAM && !pGroup->fVehicle && pGroup->ubSectorX == sSectorX && pGroup->ubSectorY == sSectorY )
{
*pubNumTroops += pGroup->pEnemyGroup->ubNumTroops;
*pubNumElites += pGroup->pEnemyGroup->ubNumElites;
*pubNumAdmins += pGroup->pEnemyGroup->ubNumAdmins;
*pubNumTanks += pGroup->pEnemyGroup->ubNumTanks;
*pubNumJeeps += pGroup->pEnemyGroup->ubNumJeeps;
}
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;
*pubNumTanks += pSector->ubNumTanks;
*pubNumJeeps += pSector->ubNumJeeps;
}
}
void GetNumberOfMobileEnemiesInSectorWithoutRoadBlock( INT16 sSectorX, INT16 sSectorY, UINT8 usTeam, UINT8 *pubNumAdmins, UINT8 *pubNumTroops, UINT8 *pubNumElites, UINT8 *pubNumTanks, UINT8 *pubNumJeeps )
{
GROUP *pGroup;
AssertGE( sSectorX, MINIMUM_VALID_X_COORDINATE);
AssertLE( sSectorX, MAXIMUM_VALID_X_COORDINATE );
AssertGE( sSectorY, MINIMUM_VALID_Y_COORDINATE);
AssertLE( sSectorY, MAXIMUM_VALID_Y_COORDINATE );
//Now count the number of mobile groups in the sector.
*pubNumTroops = *pubNumElites = *pubNumAdmins = *pubNumTanks = *pubNumJeeps = 0;
pGroup = gpGroupList;
while( pGroup )
{
if ( pGroup->usGroupTeam == usTeam && !pGroup->fVehicle && pGroup->ubSectorX == sSectorX && pGroup->ubSectorY == sSectorY )
{
*pubNumTroops += pGroup->pEnemyGroup->ubNumTroops;
*pubNumElites += pGroup->pEnemyGroup->ubNumElites;
*pubNumAdmins += pGroup->pEnemyGroup->ubNumAdmins;
*pubNumTanks += pGroup->pEnemyGroup->ubNumTanks;
*pubNumJeeps += pGroup->pEnemyGroup->ubNumJeeps;
}
pGroup = pGroup->next;
}
}
void GetNumberOfStationaryEnemiesInSector( INT16 sSectorX, INT16 sSectorY, UINT8 *pubNumAdmins, UINT8 *pubNumTroops, UINT8 *pubNumElites, UINT8 *pubNumTanks, UINT8 *pubNumJeeps )
{
SECTORINFO *pSector;
AssertGE( sSectorX, MINIMUM_VALID_X_COORDINATE);
AssertLE( sSectorX, MAXIMUM_VALID_X_COORDINATE );
AssertGE( sSectorY, MINIMUM_VALID_Y_COORDINATE);
AssertLE( sSectorY, MAXIMUM_VALID_Y_COORDINATE );
pSector = &SectorInfo[ SECTOR( sSectorX, sSectorY ) ];
//grab the number of each type in the stationary sector
*pubNumAdmins = pSector->ubNumAdmins;
*pubNumTroops = pSector->ubNumTroops;
*pubNumElites = pSector->ubNumElites;
*pubNumTanks = pSector->ubNumTanks;
*pubNumJeeps = pSector->ubNumJeeps;
}
void GetNumberOfEnemiesInSector( INT16 sSectorX, INT16 sSectorY, UINT8 *pubNumAdmins, UINT8 *pubNumTroops, UINT8 *pubNumElites, UINT8 *pubNumTanks, UINT8 *pubNumJeeps )
{
UINT8 ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks, ubNumJeeps;
GetNumberOfStationaryEnemiesInSector( sSectorX, sSectorY, pubNumAdmins, pubNumTroops, pubNumElites, pubNumTanks, pubNumJeeps );
GetNumberOfMobileEnemiesInSector( sSectorX, sSectorY, &ubNumAdmins, &ubNumTroops, &ubNumElites, &ubNumTanks, &ubNumJeeps );
*pubNumAdmins += ubNumAdmins;
*pubNumTroops += ubNumTroops;
*pubNumElites += ubNumElites;
*pubNumTanks += ubNumTanks;
*pubNumJeeps += ubNumJeeps;
}
void EndTacticalBattleForEnemy()
{
GROUP *pGroup;
INT32 i;
//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;
pSector->ubTanksInBattle = 0;
pSector->ubJeepsInBattle = 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->ubTanksInBattle = 0;
pSector->ubJeepsInBattle = 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->usGroupTeam == ENEMY_TEAM && !pGroup->fVehicle && pGroup->ubSectorX == gWorldSectorX && pGroup->ubSectorY == gWorldSectorY )
{
pGroup->pEnemyGroup->ubTroopsInBattle = 0;
pGroup->pEnemyGroup->ubElitesInBattle = 0;
pGroup->pEnemyGroup->ubAdminsInBattle = 0;
pGroup->pEnemyGroup->ubTanksInBattle = 0;
pGroup->pEnemyGroup->ubJeepsInBattle = 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 ]->stats.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 ]->stats.bLife >= OKLIFE )
{ //confirmed at least one enemy here, so do the loyalty penalty.
HandleGlobalLoyaltyEvent( GLOBAL_LOYALTY_ABANDON_MILITIA, gWorldSectorX, gWorldSectorY, 0 );
break;
}
}
break;
}
}
}
UINT8 NumFreeSlots( UINT8 ubTeam )
{
UINT8 ubNumFreeSlots = 0;
//Count the number of free enemy slots. It is possible to have multiple groups exceed the maximum.
for ( INT32 i = gTacticalStatus.Team[ubTeam].bFirstID; i <= gTacticalStatus.Team[ubTeam].bLastID; ++i )
{
if ( !Menptr[i].bActive )
++ubNumFreeSlots;
}
// the militia team size can be restricted by the ini
if ( ubTeam == MILITIA_TEAM )
{
ubNumFreeSlots = (UINT8)max( 0, (INT8)ubNumFreeSlots - (INT8)(gGameExternalOptions.ubGameMaximumNumberOfRebels - gGameExternalOptions.iMaxMilitiaPerSector) );
}
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;
unsigned ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks, ubNumJeeps;
unsigned ubTotalAdmins, ubTotalElites, ubTotalTroops, ubTotalTanks, ubTotalJeeps = 0;
unsigned totalCountOfStationaryEnemies = 0;
unsigned totalCountOfMobileEnemies = 0;
int sNumSlots;
gfPendingNonPlayerTeam[ENEMY_TEAM] = FALSE;
if( gbWorldSectorZ > 0 )
return PrepareEnemyForUndergroundBattle();
// Add the invading group
if ( gpBattleGroup && gpBattleGroup->usGroupTeam == ENEMY_TEAM )
{
//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 );
// Reinforcement groups? Bring it on!
// only if not Omerta on a non-insane difficulty level
if( gGameExternalOptions.gfAllowReinforcements &&
!( ( GetTownIdForSector( gWorldSectorX, gWorldSectorY ) == OMERTA) && (gGameOptions.ubDifficultyLevel != DIF_LEVEL_INSANE) ) )
{
UINT16 pusMoveDir[4][3];
UINT8 ubDirNumber = 0;
GROUP *pGroup;
SECTORINFO *pThisSector;
// They arrived in multiple groups, so here they come
pThisSector = &SectorInfo[ SECTOR( gWorldSectorX, gWorldSectorY ) ];
GenerateDirectionInfos( gWorldSectorX, gWorldSectorY, &ubDirNumber, pusMoveDir, FALSE, TRUE );
for( unsigned ubIndex = 0; ubIndex < ubDirNumber; ++ubIndex )
{
while ( NumMobileEnemiesInSector( SECTORX( pusMoveDir[ubIndex][0] ), SECTORY( pusMoveDir[ubIndex][0] ) ) && GetNonPlayerGroupInSector( SECTORX( pusMoveDir[ubIndex][0] ), SECTORY( pusMoveDir[ubIndex][0] ), ENEMY_TEAM ) )
{
pGroup = GetNonPlayerGroupInSector( SECTORX( pusMoveDir[ubIndex][0] ), SECTORY( pusMoveDir[ubIndex][0] ), ENEMY_TEAM );
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->usGroupTeam != OUR_TEAM && !pGroup->fVehicle &&
pGroup->ubSectorX == gpBattleGroup->ubSectorX &&
pGroup->ubSectorY == gpBattleGroup->ubSectorY &&
!pGroup->pEnemyGroup->ubAdminsInBattle &&
!pGroup->pEnemyGroup->ubTroopsInBattle &&
!pGroup->pEnemyGroup->ubElitesInBattle &&
!pGroup->pEnemyGroup->ubTanksInBattle &&
!pGroup->pEnemyGroup->ubJeepsInBattle )
{
HandleArrivalOfReinforcements( pGroup );
}
pGroup = pGroup->next;
}
}
ValidateEnemiesHaveWeapons();
UnPauseGame();
return ( ( BOOLEAN) ( gpBattleGroup->ubGroupSize > 0 ) );
}
// WDS Count the number of placements. This will limit the maximum number of enemies we can place on the map
SOLDIERINITNODE *curr = gSoldierInitHead;
unsigned mapMaximumNumberOfEnemies = 0;
while( curr )
{
if( curr->pBasicPlacement->bTeam == ENEMY_TEAM )
{
++mapMaximumNumberOfEnemies;
}
curr = curr->next;
}
AssertGE (mapMaximumNumberOfEnemies, 0);
if (mapMaximumNumberOfEnemies > gGameExternalOptions.ubGameMaximumNumberOfEnemies)
mapMaximumNumberOfEnemies = gGameExternalOptions.ubGameMaximumNumberOfEnemies;
//is there more enemies in the sector then we can actually place on map?
//are there more enemies in the sector then we can actually place on map?
gfPendingNonPlayerTeam[ENEMY_TEAM] = (NumNonPlayerTeamMembersInSector( gWorldSectorX, gWorldSectorY, ENEMY_TEAM ) > mapMaximumNumberOfEnemies);
pSector = &SectorInfo[ SECTOR( gWorldSectorX, gWorldSectorY ) ];
// OJW - 20090403 - override max ai in co-op
if (is_networked && is_server && gMaxEnemiesEnabled == 1)
{
float totalEnemies = (float)(pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumTanks + pSector->ubNumJeeps);
ubTotalAdmins = (unsigned int)(((float)pSector->ubNumAdmins / totalEnemies) * mapMaximumNumberOfEnemies);
ubTotalTroops = (unsigned int)(((float)pSector->ubNumTroops / totalEnemies) * mapMaximumNumberOfEnemies);
ubTotalElites = (unsigned int)(((float)pSector->ubNumElites / totalEnemies) * mapMaximumNumberOfEnemies);
ubTotalTanks = (unsigned int)(((float)pSector->ubNumTanks / totalEnemies) * mapMaximumNumberOfEnemies);
ubTotalJeeps = (unsigned int)(((float)pSector->ubNumJeeps / totalEnemies) * mapMaximumNumberOfEnemies);
totalEnemies = (float)(ubTotalAdmins + ubTotalTroops + ubTotalElites + ubTotalTanks + ubTotalJeeps);
// take care of any rounding losses
while (totalEnemies < mapMaximumNumberOfEnemies)
{
// just fill out with standard troops
++ubTotalTroops;
++totalEnemies;
}
pSector->ubNumAdmins = ubTotalAdmins;
pSector->ubNumTroops = ubTotalTroops;
pSector->ubNumElites = ubTotalElites;
pSector->ubNumTanks = ubTotalTanks;
pSector->ubNumJeeps = ubTotalJeeps;
pSector->ubAdminsInBattle = 0;
pSector->ubTroopsInBattle = 0;
pSector->ubElitesInBattle = 0;
pSector->ubTanksInBattle = 0;
pSector->ubJeepsInBattle = 0;
}
else
{
if( pSector->uiFlags & SF_USE_MAP_SETTINGS )
{
//count the number of enemy placements in a map and use those
SOLDIERINITNODE *curr = gSoldierInitHead;
ubTotalAdmins = ubTotalTroops = ubTotalElites = ubTotalTanks = 0;
while( curr )
{
if( curr->pBasicPlacement->bTeam == ENEMY_TEAM )
{
switch( curr->pBasicPlacement->ubSoldierClass )
{
case SOLDIER_CLASS_ADMINISTRATOR:
case SOLDIER_CLASS_BANDIT: ubTotalAdmins++; break;
case SOLDIER_CLASS_ARMY: ubTotalTroops++; break;
case SOLDIER_CLASS_ELITE: ubTotalElites++; break;
case SOLDIER_CLASS_TANK: ubTotalTanks++; break;
case SOLDIER_CLASS_JEEP: ubTotalJeeps++; break;
}
}
curr = curr->next;
}
pSector->ubNumAdmins = ubTotalAdmins;
pSector->ubNumTroops = ubTotalTroops;
pSector->ubNumElites = ubTotalElites;
pSector->ubNumTanks = ubTotalTanks;
pSector->ubNumJeeps = ubTotalJeeps;
pSector->ubAdminsInBattle = 0;
pSector->ubTroopsInBattle = 0;
pSector->ubElitesInBattle = 0;
pSector->ubTanksInBattle = 0;
pSector->ubJeepsInBattle = 0;
}
else
{
ubTotalAdmins = pSector->ubNumAdmins - pSector->ubAdminsInBattle;
ubTotalTroops = pSector->ubNumTroops - pSector->ubTroopsInBattle;
ubTotalElites = pSector->ubNumElites - pSector->ubElitesInBattle;
ubTotalTanks = pSector->ubNumTanks - pSector->ubTanksInBattle;
ubTotalJeeps = pSector->ubNumJeeps - pSector->ubJeepsInBattle;
}
}
totalCountOfStationaryEnemies = ubTotalAdmins + ubTotalTroops + ubTotalElites + ubTotalTanks + ubTotalJeeps;
if( totalCountOfStationaryEnemies > mapMaximumNumberOfEnemies )
{
/*
#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, mapMaximumNumberOfEnemies );
#endif
*/
ubTotalAdmins = min( mapMaximumNumberOfEnemies, ubTotalAdmins );
ubTotalTroops = min( mapMaximumNumberOfEnemies-ubTotalAdmins, ubTotalTroops );
ubTotalElites = min( mapMaximumNumberOfEnemies-ubTotalAdmins-ubTotalTroops, ubTotalElites );
ubTotalTanks = min( mapMaximumNumberOfEnemies-ubTotalAdmins-ubTotalTroops-ubTotalElites, ubTotalTanks );
ubTotalJeeps = min( mapMaximumNumberOfEnemies - ubTotalAdmins - ubTotalTroops - ubTotalElites - ubTotalTanks, ubTotalJeeps );
}
pSector->ubAdminsInBattle += ubTotalAdmins;
pSector->ubTroopsInBattle += ubTotalTroops;
pSector->ubElitesInBattle += ubTotalElites;
pSector->ubTanksInBattle += ubTotalTanks;
pSector->ubJeepsInBattle += ubTotalJeeps;
#ifdef JA2TESTVERSION
if( gfOverrideSector )
{
//if there are no troops in the current groups, then we're done.
if ( !ubTotalAdmins && !ubTotalTroops && !ubTotalElites && !ubTotalTanks && !ubTotalJeeps )
return FALSE;
AddSoldierInitListEnemyDefenceSoldiers( ubTotalAdmins, ubTotalTroops, ubTotalElites, ubTotalTanks, ubTotalJeeps );
ValidateEnemiesHaveWeapons();
UnPauseGame();
return TRUE;
}
#endif
//Search for movement groups that happen to be in the sector.
sNumSlots = NumFreeSlots( ENEMY_TEAM );
if (sNumSlots > (int)mapMaximumNumberOfEnemies)
sNumSlots = mapMaximumNumberOfEnemies;
/*
* WDS - this test no longer valid with the above change
//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 + ubTotalTanks + ubTotalJeeps;
//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->usGroupTeam == ENEMY_TEAM && !pGroup->fVehicle &&
pGroup->ubSectorX == gWorldSectorX && pGroup->ubSectorY == gWorldSectorY && !gbWorldSectorZ )
{ //Process enemy group in sector.
if( sNumSlots > 0 )
{
AssertGE(pGroup->pEnemyGroup->ubNumAdmins, pGroup->pEnemyGroup->ubAdminsInBattle);
ubNumAdmins = pGroup->pEnemyGroup->ubNumAdmins - pGroup->pEnemyGroup->ubAdminsInBattle;
sNumSlots -= ubNumAdmins;
if( sNumSlots < 0 )
{ //adjust the value to zero
ubNumAdmins += sNumSlots;
sNumSlots = 0;
gfPendingNonPlayerTeam[ENEMY_TEAM] = TRUE;
}
pGroup->pEnemyGroup->ubAdminsInBattle += ubNumAdmins;
ubTotalAdmins += ubNumAdmins;
}
if( sNumSlots > 0 )
{ //Add regular army forces.
AssertGE(pGroup->pEnemyGroup->ubNumTroops, pGroup->pEnemyGroup->ubTroopsInBattle);
ubNumTroops = pGroup->pEnemyGroup->ubNumTroops - pGroup->pEnemyGroup->ubTroopsInBattle;
sNumSlots -= ubNumTroops;
if( sNumSlots < 0 )
{ //adjust the value to zero
ubNumTroops += sNumSlots;
sNumSlots = 0;
gfPendingNonPlayerTeam[ENEMY_TEAM] = TRUE;
}
pGroup->pEnemyGroup->ubTroopsInBattle += ubNumTroops;
ubTotalTroops += ubNumTroops;
}
if( sNumSlots > 0 )
{ //Add elite troops
AssertGE(pGroup->pEnemyGroup->ubNumElites, pGroup->pEnemyGroup->ubElitesInBattle);
ubNumElites = pGroup->pEnemyGroup->ubNumElites - pGroup->pEnemyGroup->ubElitesInBattle;
sNumSlots -= ubNumElites;
if( sNumSlots < 0 )
{ //adjust the value to zero
ubNumElites += sNumSlots;
sNumSlots = 0;
gfPendingNonPlayerTeam[ENEMY_TEAM] = TRUE;
}
pGroup->pEnemyGroup->ubElitesInBattle += ubNumElites;
ubTotalElites += ubNumElites;
}
if( sNumSlots > 0 )
{ //Add tanks
AssertGE(pGroup->pEnemyGroup->ubNumTanks, pGroup->pEnemyGroup->ubTanksInBattle);
ubNumTanks = pGroup->pEnemyGroup->ubNumTanks - pGroup->pEnemyGroup->ubTanksInBattle;
sNumSlots -= ubNumTanks;
if( sNumSlots < 0 )
{ //adjust the value to zero
ubNumTanks += sNumSlots;
sNumSlots = 0;
gfPendingNonPlayerTeam[ENEMY_TEAM] = TRUE;
}
pGroup->pEnemyGroup->ubTanksInBattle += ubNumTanks;
ubTotalTanks += ubNumTanks;
}
if ( sNumSlots > 0 )
{
//Add jeeps
AssertGE( pGroup->pEnemyGroup->ubNumJeeps, pGroup->pEnemyGroup->ubJeepsInBattle );
ubNumJeeps = pGroup->pEnemyGroup->ubNumJeeps - pGroup->pEnemyGroup->ubJeepsInBattle;
sNumSlots -= ubNumJeeps;
if ( sNumSlots < 0 )
{ //adjust the value to zero
ubNumJeeps += sNumSlots;
sNumSlots = 0;
gfPendingNonPlayerTeam[ENEMY_TEAM] = TRUE;
}
pGroup->pEnemyGroup->ubJeepsInBattle += ubNumJeeps;
ubTotalJeeps += ubNumJeeps;
}
//NOTE:
//no provisions for profile troop leader or retreat groups yet.
}
if ( pGroup->usGroupTeam == OUR_TEAM && !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 && !ubTotalTanks && !ubTotalJeeps )
{
return FALSE;
}
AddSoldierInitListEnemyDefenceSoldiers( ubTotalAdmins, ubTotalTroops, ubTotalElites, ubTotalTanks, ubTotalJeeps );
//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 = mapMaximumNumberOfEnemies - totalCountOfStationaryEnemies;
// Flugente: at this point, soldiers have already been placed, thus enough slots for them exist
sNumSlots = min( mapMaximumNumberOfEnemies, NumNonPlayerTeamMembersInSector( gWorldSectorX, gWorldSectorY, ENEMY_TEAM ) );
pGroup = gpGroupList;
while( pGroup && sNumSlots > 0 )
{
if ( pGroup->usGroupTeam != OUR_TEAM && !pGroup->fVehicle &&
pGroup->ubSectorX == gWorldSectorX && pGroup->ubSectorY == gWorldSectorY && !gbWorldSectorZ )
{
ubNumAdmins = pGroup->pEnemyGroup->ubAdminsInBattle;
ubNumTroops = pGroup->pEnemyGroup->ubTroopsInBattle;
ubNumElites = pGroup->pEnemyGroup->ubElitesInBattle;
ubNumTanks = pGroup->pEnemyGroup->ubTanksInBattle;
ubNumJeeps = pGroup->pEnemyGroup->ubJeepsInBattle;
unsigned num = ubNumAdmins + ubNumTroops + ubNumElites + ubNumTanks + ubNumJeeps;
unsigned firstSlot = gTacticalStatus.Team[ ENEMY_TEAM ].bFirstID;
unsigned lastSlot = gTacticalStatus.Team[ ENEMY_TEAM ].bLastID;
unsigned slotsAvailable = lastSlot-firstSlot+1;
AssertGE((int)slotsAvailable, sNumSlots);
for (unsigned slot = firstSlot;
(slot <= lastSlot) && num && sNumSlots;
++slot)
{
pSoldier = &Menptr[ slot ];
// Skip inactive and already grouped soldiers
if (!pSoldier->bActive || pSoldier->ubGroupID)
{
// if this guy already has an ID, reduce the number of people who still need one
--num;
--sNumSlots;
continue;
}
// At this point we should not have added more soldiers than are in slots
AssertGT( sNumSlots, 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;
// silversurfer: bugfix for Jaggzilla bug #623
// Mike or Iggy can be part of the enemy team and they are created from an Elite but they don't have SOLDIER_CLASS_ELITE.
// Therefore once this for loop was done ubNumElites was still 1 which caused an assertion error.
case SOLDIER_CLASS_NONE:
if( ubNumElites )
{
if ( pSoldier->ubProfile == MIKE || pSoldier->ubProfile == IGGY )
{
num--;
sNumSlots--;
ubNumElites--;
pSoldier->ubGroupID = pGroup->ubGroupID;
}
}
break;
case SOLDIER_CLASS_TANK:
if( ubNumTanks )
{
num--;
sNumSlots--;
ubNumTanks--;
pSoldier->ubGroupID = pGroup->ubGroupID;
}
break;
case SOLDIER_CLASS_JEEP:
if ( ubNumJeeps )
{
num--;
sNumSlots--;
ubNumJeeps--;
pSoldier->ubGroupID = pGroup->ubGroupID;
}
break;
}
}
// Flugente: instead of just crashing the game without any explanation to the user, ignore this issue if it still exists.
// The worst that should happen is a warning that a soldier has no group id.
/*AssertEQ( ubNumElites , 0);
AssertEQ( ubNumTroops , 0);
AssertEQ( ubNumAdmins , 0);
AssertEQ( ubNumTanks , 0);
AssertEQ( ubNumJeeps , 0);
AssertEQ( num , 0);*/
}
pGroup = pGroup->next;
}
ValidateEnemiesHaveWeapons();
UnPauseGame();
return TRUE;
}
BOOLEAN PrepareEnemyForUndergroundBattle()
{
UNDERGROUND_SECTORINFO *pUnderground;
unsigned ubTotalAdmins, ubTotalTroops, ubTotalElites, ubTotalTanks, ubTotalJeeps;
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);
ubTotalTanks = (UINT8)(pUnderground->ubNumTanks - pUnderground->ubTanksInBattle);
ubTotalJeeps = (UINT8)(pUnderground->ubNumJeeps - pUnderground->ubJeepsInBattle);
pUnderground->ubAdminsInBattle += ubTotalAdmins;
pUnderground->ubTroopsInBattle += ubTotalTroops;
pUnderground->ubElitesInBattle += ubTotalElites;
pUnderground->ubTanksInBattle += ubTotalTanks;
pUnderground->ubJeepsInBattle += ubTotalJeeps;
AddSoldierInitListEnemyDefenceSoldiers( pUnderground->ubNumAdmins, pUnderground->ubNumTroops, pUnderground->ubNumElites, pUnderground->ubNumTanks, pUnderground->ubNumJeeps );
ValidateEnemiesHaveWeapons();
UnPauseGame();
}
return ((BOOLEAN)(pUnderground->ubNumAdmins + pUnderground->ubNumTroops + pUnderground->ubNumElites + pUnderground->ubNumTanks + pUnderground->ubNumJeeps > 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;
INT32 iMaxEnemyGroupSize = gGameExternalOptions.iMaxEnemyGroupSize;
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"QueenCommand");
AssertNotNIL (pSoldier);
EvaluateDeathEffectsToSoldierInitList( pSoldier );
switch( pSoldier->ubProfile )
{
#ifdef JA2UB
case 75://MORRIS:
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;
#endif
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;
case TANK_CAR:
if( !pSoldier->bSectorZ )
{
pSector = &SectorInfo[ SECTOR( pSoldier->sSectorX, pSoldier->sSectorY ) ];
if( pSector->ubNumTanks )
{
pSector->ubNumTanks--;
}
if( pSector->ubTanksInBattle )
{
pSector->ubTanksInBattle--;
}
}
else
{
UNDERGROUND_SECTORINFO *pUnderground;
pUnderground = FindUnderGroundSector( (UINT8)pSoldier->sSectorX, (UINT8)pSoldier->sSectorY, (UINT8)pSoldier->bSectorZ );
Assert( pUnderground );
if( pUnderground->ubNumTanks)
{
pUnderground->ubNumTanks--;
}
if( pUnderground->ubTanksInBattle )
{
pUnderground->ubTanksInBattle--;
}
}
break;
case COMBAT_JEEP_CAR:
if ( !pSoldier->bSectorZ )
{
pSector = &SectorInfo[SECTOR( pSoldier->sSectorX, pSoldier->sSectorY )];
if ( pSector->ubNumJeeps )
{
pSector->ubNumJeeps--;
}
if ( pSector->ubJeepsInBattle )
{
pSector->ubJeepsInBattle--;
}
}
else
{
UNDERGROUND_SECTORINFO *pUnderground;
pUnderground = FindUnderGroundSector( (UINT8)pSoldier->sSectorX, (UINT8)pSoldier->sSectorY, (UINT8)pSoldier->bSectorZ );
Assert( pUnderground );
if ( pUnderground->ubNumJeeps )
{
pUnderground->ubNumJeeps--;
}
if ( pUnderground->ubJeepsInBattle )
{
pUnderground->ubJeepsInBattle--;
}
}
break;
}
if( pSoldier->aiData.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->usGroupTeam == OUR_TEAM )
{
#ifdef JA2BETAVERSION
CHAR16 str[256];
swprintf( str, L"Attempting to process player group %d thinking it's an enemy group in ProcessQueenCmdImplicationsOfDeath()", pSoldier->ubGroupID );
DoScreenIndependantMessageBox( str, MSG_BOX_FLAG_OK, NULL );
#endif
return;
}
else if ( pGroup->usGroupTeam == MILITIA_TEAM )
{
#ifdef JA2BETAVERSION
CHAR16 str[256];
swprintf( str, L"Attempting to process militia group %d 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 && !gfPendingNonPlayerTeam[ENEMY_TEAM] ||
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 && !gfPendingNonPlayerTeam[ENEMY_TEAM] ||
pGroup->ubGroupSize > iMaxEnemyGroupSize /*|| pGroup->pEnemyGroup->ubNumTroops > 50 || pGroup->pEnemyGroup->ubTroopsInBattle > 50*/ )
{
// haydent
if (!is_client)
{
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 && !gfPendingNonPlayerTeam[ENEMY_TEAM] ||
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 + pSector->ubNumTanks + pSector->ubNumJeeps;
#endif
switch( pSoldier->ubSoldierClass )
{
case SOLDIER_CLASS_ADMINISTRATOR:
#ifdef JA2BETAVERSION
if( guiCurrentScreen == GAME_SCREEN )
{
if( ubTotalEnemies <= gGameExternalOptions.ubGameMaximumNumberOfEnemies && pSector->ubNumAdmins != pSector->ubAdminsInBattle ||
!pSector->ubNumAdmins || !pSector->ubAdminsInBattle ||
pSector->ubNumAdmins > gGameExternalOptions.ubGameMaximumNumberOfEnemies || pSector->ubAdminsInBattle > gGameExternalOptions.ubGameMaximumNumberOfEnemies )
{
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 <= gGameExternalOptions.ubGameMaximumNumberOfEnemies && pSector->ubNumTroops != pSector->ubTroopsInBattle ||
!pSector->ubNumTroops || !pSector->ubTroopsInBattle ||
pSector->ubNumTroops > gGameExternalOptions.ubGameMaximumNumberOfEnemies || pSector->ubTroopsInBattle > gGameExternalOptions.ubGameMaximumNumberOfEnemies )
{
if(!is_client)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 );
//disabled: hayden.
}
}
#endif
if( pSector->ubNumTroops )
{
pSector->ubNumTroops--;
}
if( pSector->ubTroopsInBattle )
{
pSector->ubTroopsInBattle--;
}
break;
case SOLDIER_CLASS_ELITE:
#ifdef JA2BETAVERSION
if( guiCurrentScreen == GAME_SCREEN )
{
if( ubTotalEnemies <= gGameExternalOptions.ubGameMaximumNumberOfEnemies && pSector->ubNumElites != pSector->ubElitesInBattle ||
!pSector->ubNumElites || !pSector->ubElitesInBattle ||
pSector->ubNumElites > gGameExternalOptions.ubGameMaximumNumberOfEnemies || pSector->ubElitesInBattle > gGameExternalOptions.ubGameMaximumNumberOfEnemies )
{
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:
case SOLDIER_CLASS_BANDIT:
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--;
}
#ifdef JA2UB
//JA25 UB
//handle anything important when bloodcats die
HandleBloodCatDeaths( pSector );
#endif
}
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 + pSector->ubNumTanks + pSector->ubNumJeeps;
#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:
case SOLDIER_CLASS_BANDIT:
if (pSoldier->ubBodyType == BLOODCAT)
{
if( pSector->ubNumBloodcats > 0 )
pSector->ubNumBloodcats--;
}
else
{
#ifdef JA2BETAVERSION
if( ubTotalEnemies <= (UINT32)iMaxEnemyGroupSize && pSector->ubNumCreatures != pSector->ubCreaturesInBattle ||
!pSector->ubNumCreatures ||
!pSector->ubCreaturesInBattle ||
pSector->ubNumCreatures > gGameExternalOptions.ubGameMaximumNumberOfCreatures ||
pSector->ubCreaturesInBattle > gGameExternalOptions.ubGameMaximumNumberOfCreatures )
{
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 ( pSoldier->ubSoldierClass == SOLDIER_CLASS_CREATURE )
{
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 = NumNonPlayerTeamMembersInSector( pSoldier->sSectorX, pSoldier->sSectorY, ENEMY_TEAM );
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 gGameExternalOptions.ubGameMaximumNumberOfEnemies 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()
{
// Check if no world is loaded, and is not underground level
if(!(gWorldSectorX > 0 && gWorldSectorY > 0 && gbWorldSectorZ == 0))//dnl ch57 161009
return;
#ifdef JA2UB
BOOLEAN fMagicallyAppeared=FALSE;
#endif
UINT8 ubSlots, ubNumAvailable;
UINT8 ubNumElites, ubNumTroops, ubNumAdmins, ubNumTanks, ubNumJeeps;
UINT8 ubNumGroupsInSector;
UINT8 ubGroupIndex;
GROUP *pGroup;
SECTORINFO *pSector = &SectorInfo[ SECTOR( gWorldSectorX, gWorldSectorY ) ];
GROUP **pGroupInSectorList;
static UINT8 ubPredefinedInsertionCode = 255;
// haydent
if (is_networked)
{
if ((is_client && !is_server) || gEnemyEnabled == 0)
{
return;
}
}
if ( (!PlayerMercsInSector( (UINT8)gWorldSectorX, (UINT8)gWorldSectorY, 0 ) && !NumNonPlayerTeamMembersInSector( gWorldSectorX, gWorldSectorY, MILITIA_TEAM ))
|| !NumNonPlayerTeamMembersInSector( gWorldSectorX, gWorldSectorY, ENEMY_TEAM ) )
return;
// Flugente: if there is an enemy helicopter here, it can add reinforcements
if ( gTacticalStatus.Team[ENEMY_TEAM].bAwareOfOpposition )
{
EnemyHeliTroopDrop( SECTOR( gWorldSectorX, gWorldSectorY ) );
}
ubSlots = NumFreeSlots( ENEMY_TEAM );
// silversurfer: Only if there are enemy troops in the sector already we can talk about "reinforcements". If no troops are there we will spawn the incoming troops without delay.
if( gGameExternalOptions.sMinDelayEnemyReinforcements && gTacticalStatus.Team[ENEMY_TEAM].bTeamActive )//dnl ch68 080913
{
if(gTacticalStatus.Team[ENEMY_TEAM].bAwareOfOpposition == TRUE)
{
if(guiReinforceTurn == 0)
{
guiReinforceTurn = guiTurnCnt + gGameExternalOptions.sMinDelayEnemyReinforcements + Random(gGameExternalOptions.sRndDelayEnemyReinforcements+1);// first possible reinforcement
ubSlots = 0;
}
else if(guiTurnCnt >= guiReinforceTurn)
{
guiReinforceTurn = guiTurnCnt + gGameExternalOptions.sMinDelayEnemyReinforcements/3 + Random(gGameExternalOptions.sRndDelayEnemyReinforcements+1);// any other reinforcement should appear more frequently
ubNumAvailable = gGameExternalOptions.sMinEnterEnemyReinforcements + Random(gGameExternalOptions.sRndEnterEnemyReinforcements+1);// total allowed units to enter per reinforce turn
//SendFmtMsg("Enemy reinforcements: ubSlots=%d ubNumAvailable=%d", ubSlots, ubNumAvailable);
if(ubSlots > ubNumAvailable)
ubSlots = ubNumAvailable;
guiArrived += (ubNumAvailable - ubSlots);
}
else
{
if(guiArrived > 0)
{
if(ubSlots > guiArrived)
ubSlots = guiArrived;
guiArrived -= ubSlots;
}
else
ubSlots = 0;
}
}
else
guiReinforceTurn = guiArrived = 0;
//SendFmtMsg("Enemy reinforcements: guiTurnCnt=%d guiReinforceTurn=%d guiArrived=%d", guiTurnCnt, guiReinforceTurn, guiArrived);
}
if( !ubSlots )
{
//no available slots to add enemies to. Try again later...
return;
}
if ( !gfPendingNonPlayerTeam[ENEMY_TEAM] )
{
//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 = DoReinforcementAsPendingNonPlayer( gWorldSectorX, gWorldSectorY, ENEMY_TEAM );
if (ubInsertionCode == 255)
{
break;
}
// Assume we added one since there are supposedly more available and room for them
ubSlots--;
}
// It's probable that the "pending enemies" flag isn't working right. So we'll go ahead and continue into
// the group insertion code from here.
//return;
}
if ( pSector->ubNumElites + pSector->ubNumTroops + pSector->ubNumAdmins + pSector->ubNumTanks + pSector->ubNumJeeps )
{
ubNumElites = ubNumTroops = ubNumAdmins = ubNumTanks = ubNumJeeps = 0;
ubNumAvailable = pSector->ubNumElites + pSector->ubNumTroops + pSector->ubNumAdmins + pSector->ubNumTanks + pSector->ubNumJeeps
- pSector->ubElitesInBattle - pSector->ubTroopsInBattle - pSector->ubAdminsInBattle - pSector->ubTanksInBattle - pSector->ubJeepsInBattle;
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 if( pSector->ubTanksInBattle < pSector->ubNumTanks )
{ //Add a tank
pSector->ubTanksInBattle++;
ubNumAvailable--;
ubSlots--;
ubNumTanks++;
}
else if ( pSector->ubJeepsInBattle < pSector->ubNumJeeps )
{
//Add a jeep
pSector->ubJeepsInBattle++;
ubNumAvailable--;
ubSlots--;
ubNumJeeps++;
}
else
{
AssertMsg( 0, "AddPossiblePendingEnemiesToBattle(): Logic Error -- by Kris" );
}
}
if ( ubNumAdmins || ubNumTroops || ubNumElites || ubNumTanks || ubNumJeeps )
{ //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 ( NumNonPlayerTeamMembersInSector( gWorldSectorX + 1, gWorldSectorY, ENEMY_TEAM ) )
ubStrategicInsertionCode = INSERTION_CODE_EAST;
else if ( NumNonPlayerTeamMembersInSector( gWorldSectorX - 1, gWorldSectorY, ENEMY_TEAM ) )
ubStrategicInsertionCode = INSERTION_CODE_WEST;
else if ( NumNonPlayerTeamMembersInSector( gWorldSectorX, gWorldSectorY + 1, ENEMY_TEAM ) )
ubStrategicInsertionCode = INSERTION_CODE_SOUTH;
else if ( NumNonPlayerTeamMembersInSector( gWorldSectorX, gWorldSectorY - 1, ENEMY_TEAM ) )
ubStrategicInsertionCode = INSERTION_CODE_NORTH;
#ifdef JA2UB
else if( gsGridNoForMapEdgePointInfo != -1 )
{
//Ja25: it doesnt matter the entry point at this point, it will become GRIDNO at a later point
ubStrategicInsertionCode = INSERTION_CODE_NORTH;
fMagicallyAppeared = FALSE;
}
#endif
}
if( ubStrategicInsertionCode == 255 )
{
if ( !NumNonPlayerTeamMembersInSector( gWorldSectorX + 1, gWorldSectorY, MILITIA_TEAM ) )
ubStrategicInsertionCode = INSERTION_CODE_EAST;
else if ( !NumNonPlayerTeamMembersInSector( gWorldSectorX - 1, gWorldSectorY, MILITIA_TEAM ) )
ubStrategicInsertionCode = INSERTION_CODE_WEST;
else if ( !NumNonPlayerTeamMembersInSector( gWorldSectorX, gWorldSectorY + 1, MILITIA_TEAM ) )
ubStrategicInsertionCode = INSERTION_CODE_SOUTH;
else if ( !NumNonPlayerTeamMembersInSector( gWorldSectorX, gWorldSectorY - 1, MILITIA_TEAM ) )
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, ubNumTanks, ubNumJeeps, FALSE );
gfPendingNonPlayerTeam[ENEMY_TEAM] = 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->usGroupTeam == ENEMY_TEAM && !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->usGroupTeam == ENEMY_TEAM && !pGroup->fVehicle && pGroup->ubSectorX == gWorldSectorX && pGroup->ubSectorY == gWorldSectorY && !gbWorldSectorZ )
{
pGroupInSectorList[ ubNumGroupsInSector++] = pGroup;
}
}
while( ubSlots && ubNumGroupsInSector )
{
UINT8 ubInsertionCode = 255;
ubGroupIndex = Random( ubNumGroupsInSector);
pGroup = pGroupInSectorList[ ubGroupIndex];
// Flugente fix: check for underflow...
UINT8 currentgroupsize = pGroup->pEnemyGroup->ubElitesInBattle + pGroup->pEnemyGroup->ubTroopsInBattle + pGroup->pEnemyGroup->ubAdminsInBattle
+ pGroup->pEnemyGroup->ubTanksInBattle + pGroup->pEnemyGroup->ubJeepsInBattle;
if ( currentgroupsize > pGroup->ubGroupSize )
ubNumAvailable = 0;
else
ubNumAvailable = pGroup->ubGroupSize - currentgroupsize;
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
{
// WANNE: Hack: If no valid insertion is found, get random insertion instead of Assert() error
UINT32 rndInsertionCode = GetRndNum(3);
ubInsertionCode = rndInsertionCode;
//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
{
// WANNE: Hack: If no valid insertion is found, get random insertion instead of Assert() error
UINT32 rndInsertionCode = GetRndNum(3);
ubInsertionCode = rndInsertionCode;
//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, 0, 0, FALSE );
}
else if( pGroup->pEnemyGroup->ubTroopsInBattle < pGroup->pEnemyGroup->ubNumTroops )
{ //Add a regular troop.
pGroup->pEnemyGroup->ubTroopsInBattle++;
ubSlots--;
AddEnemiesToBattle( pGroup, ubInsertionCode, 0, 1, 0, 0, 0, FALSE );
}
else if( pGroup->pEnemyGroup->ubAdminsInBattle < pGroup->pEnemyGroup->ubNumAdmins )
{ //Add an admin troop
pGroup->pEnemyGroup->ubAdminsInBattle++;
ubSlots--;
AddEnemiesToBattle( pGroup, ubInsertionCode, 1, 0, 0, 0, 0, FALSE );
}
else if( pGroup->pEnemyGroup->ubTanksInBattle < pGroup->pEnemyGroup->ubNumTanks )
{ //Add a tank
pGroup->pEnemyGroup->ubTanksInBattle++;
ubSlots--;
AddEnemiesToBattle( pGroup, ubInsertionCode, 0, 0, 0, 1, 0, FALSE );
}
else if ( pGroup->pEnemyGroup->ubJeepsInBattle < pGroup->pEnemyGroup->ubNumJeeps )
{
//Add a jeep
pGroup->pEnemyGroup->ubJeepsInBattle++;
ubSlots--;
AddEnemiesToBattle( pGroup, ubInsertionCode, 0, 0, 0, 0, 1, FALSE );
}
else
{
// WANNE: Instead of asserting, just add a regular troop
//AssertMsg( 0, "AddPossiblePendingEnemiesToBattle(): Logic Error -- by Kris" );
pGroup->pEnemyGroup->ubTroopsInBattle++;
ubSlots--;
AddEnemiesToBattle( pGroup, ubInsertionCode, 0, 1, 0, 0, 0, FALSE );
}
}
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.
gfPendingNonPlayerTeam[ENEMY_TEAM] = 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->stats.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->stats.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->stats.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, UINT8 ubNumTanks, UINT8 ubNumJeeps, 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;
pSector->ubNumTanks += ubNumTanks;
pSector->ubTanksInBattle += ubNumTanks;
pSector->ubNumJeeps += ubNumJeeps;
pSector->ubJeepsInBattle += ubNumJeeps;
}
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;
pSector->ubNumTanks += ubNumTanks;
pSector->ubTanksInBattle += ubNumTanks;
pSector->ubNumJeeps += ubNumJeeps;
pSector->ubJeepsInBattle += ubNumJeeps;
}
}
//Because the enemies magically appeared, have one of our soldiers say something...
NotifyPlayersOfNewEnemies();
}
ubTotalSoldiers = ubNumAdmins + ubNumTroops + ubNumElites + ubNumTanks + ubNumJeeps;
#ifdef JA2UB
if( gsGridNoForMapEdgePointInfo != -1 )
{
ubStrategicInsertionCode = INSERTION_CODE_GRIDNO;
}
if( ubStrategicInsertionCode == INSERTION_CODE_GRIDNO )
{
if( gsGridNoForMapEdgePointInfo == -1 )
{
Assert( 0 );
gsGridNoForMapEdgePointInfo=0;
}
for( UINT8 ubCnt=0; ubCnt<32; ++ubCnt)
{
MapEdgepointInfo.sGridNo[ ubCnt ] = gsGridNoForMapEdgePointInfo;
}
MapEdgepointInfo.ubNumPoints = 32;
MapEdgepointInfo.ubStrategicInsertionCode = INSERTION_CODE_GRIDNO;
}
else
{
ChooseMapEdgepoints( &MapEdgepointInfo, ubStrategicInsertionCode, ubTotalSoldiers );
}
#else
ChooseMapEdgepoints( &MapEdgepointInfo, ubStrategicInsertionCode, ubTotalSoldiers );
#endif
extern INT16 gsStrategicDiseaseOriginSector;
// Flugente: we need to set the sector of origin to determine from which sector to take the disease ratio that affects health
gsStrategicDiseaseOriginSector = -1;
if ( !gbWorldSectorZ )
{
switch ( ubStrategicInsertionCode )
{
case INSERTION_CODE_NORTH: gsStrategicDiseaseOriginSector = SECTOR( gWorldSectorX, gWorldSectorY - 1 ); break;
case INSERTION_CODE_EAST: gsStrategicDiseaseOriginSector = SECTOR( gWorldSectorX + 1, gWorldSectorY ); break;
case INSERTION_CODE_SOUTH: gsStrategicDiseaseOriginSector = SECTOR( gWorldSectorX, gWorldSectorY + 1 ); break;
case INSERTION_CODE_WEST: gsStrategicDiseaseOriginSector = SECTOR( gWorldSectorX - 1, gWorldSectorY ); break;
default:
break;
}
}
ubCurrSlot = 0;
while( ubTotalSoldiers )
{
if( ubNumElites && Random( ubTotalSoldiers ) < ubNumElites )
{
ubNumElites--;
ubTotalSoldiers--;
Assert(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--;
Assert(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--;
Assert(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 );
}
else if( ubNumTanks && (UINT8)Random( ubTotalSoldiers ) < (UINT8)(ubNumElites + ubNumTroops + ubNumAdmins + ubNumTanks) && ubNumberOfVehicles < 9 )
{
ubNumTanks--;
ubTotalSoldiers--;
Assert(pSoldier = TacticalCreateEnemyTank());
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 ( ubNumJeeps && (UINT8)Random( ubTotalSoldiers ) < (UINT8)(ubNumElites + ubNumTroops + ubNumAdmins + ubNumTanks + ubNumJeeps) && ubNumberOfVehicles < 9 )
{
ubNumJeeps--;
ubTotalSoldiers--;
Assert( pSoldier = TacticalCreateEnemyJeep( ) );
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 );
}
// HEADROCK HAM 3.2: enemy reinforcements arrive with 0 APs.
if (gGameExternalOptions.ubReinforcementsFirstTurnFreeze == 1 || gGameExternalOptions.ubReinforcementsFirstTurnFreeze == 2)
{
pSoldier->bActionPoints = 0;
// Flugente: due to a fix, also note here that the reinforcements get no APs.
pSoldier->usSoldierFlagMask |= SOLDIER_NO_AP;
// Flugente: campaign stats
if ( IsOurSoldier(pSoldier) )
gCurrentIncident.usIncidentFlags |= INCIDENT_REINFORCEMENTS_PLAYERSIDE;
else
gCurrentIncident.usIncidentFlags |= INCIDENT_REINFORCEMENTS_ENEMY;
}
}
// set this back so it doesn't affect others
gsStrategicDiseaseOriginSector = -1;
#ifdef JA2UB
gsGridNoForMapEdgePointInfo = -1;
#endif
}
void AddMilitiaToBattle( GROUP *pGroup, UINT8 ubStrategicInsertionCode, UINT8 ubNumGreens, UINT8 ubNumRegulars, 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"Militia reinforcements have arrived! (%d greens, %d regulars, %d elite)", ubNumGreens, ubNumRegulars, ubNumElites );
#endif
if ( fMagicallyAppeared )
{
//update the strategic counters
if ( !gbWorldSectorZ )
{
SECTORINFO *pSector = &SectorInfo[SECTOR( gWorldSectorX, gWorldSectorY )];
pSector->ubNumberOfCivsAtLevel[GREEN_MILITIA] += ubNumGreens;
pSector->ubNumberOfCivsAtLevel[REGULAR_MILITIA] += ubNumRegulars;
pSector->ubNumberOfCivsAtLevel[ELITE_MILITIA] += ubNumElites;
}
else
{
// there are no underground militia... error if this ever happens
AssertMsg( 0, "Tried to add militia to an underground sector" );
}
}
ubTotalSoldiers = ubNumGreens + ubNumRegulars + ubNumElites;
#ifdef JA2UB
if ( gsGridNoForMapEdgePointInfo != -1 )
{
ubStrategicInsertionCode = INSERTION_CODE_GRIDNO;
}
if ( ubStrategicInsertionCode == INSERTION_CODE_GRIDNO )
{
if ( gsGridNoForMapEdgePointInfo == -1 )
{
Assert( 0 );
gsGridNoForMapEdgePointInfo = 0;
}
for ( UINT8 ubCnt = 0; ubCnt<32; ++ubCnt )
{
MapEdgepointInfo.sGridNo[ubCnt] = gsGridNoForMapEdgePointInfo;
}
MapEdgepointInfo.ubNumPoints = 32;
MapEdgepointInfo.ubStrategicInsertionCode = INSERTION_CODE_GRIDNO;
}
else
{
ChooseMapEdgepoints( &MapEdgepointInfo, ubStrategicInsertionCode, ubTotalSoldiers );
}
#else
ChooseMapEdgepoints( &MapEdgepointInfo, ubStrategicInsertionCode, (ubTotalSoldiers) );
#endif
ubCurrSlot = 0;
while ( ubTotalSoldiers )
{
if ( ubNumElites && Random( ubTotalSoldiers ) < ubNumElites )
{
ubNumElites--;
ubTotalSoldiers--;
Assert( pSoldier = TacticalCreateMilitia( SOLDIER_CLASS_ELITE_MILITIA, gWorldSectorX, gWorldSectorY ) );
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 ( ubNumRegulars && (UINT8)Random( ubTotalSoldiers ) < (UINT8)(ubNumElites + ubNumRegulars) )
{
ubNumRegulars--;
ubTotalSoldiers--;
Assert( pSoldier = TacticalCreateMilitia( SOLDIER_CLASS_REG_MILITIA, gWorldSectorX, gWorldSectorY ) );
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 ( ubNumGreens && (UINT8)Random( ubTotalSoldiers ) < (UINT8)(ubNumElites + ubNumRegulars + ubNumGreens) )
{
ubNumGreens--;
ubTotalSoldiers--;
Assert( pSoldier = TacticalCreateMilitia( SOLDIER_CLASS_GREEN_MILITIA, gWorldSectorX, gWorldSectorY ) );
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 );
}
// HEADROCK HAM 3.2: enemy reinforcements arrive with 0 APs.
if ( gGameExternalOptions.ubReinforcementsFirstTurnFreeze == 1 || gGameExternalOptions.ubReinforcementsFirstTurnFreeze == 2 )
{
pSoldier->bActionPoints = 0;
// Flugente: due to a fix, also note here that the reinforcements get no APs.
pSoldier->usSoldierFlagMask |= SOLDIER_NO_AP;
// Flugente: campaign stats
if ( IsOurSoldier( pSoldier ) )
gCurrentIncident.usIncidentFlags |= INCIDENT_REINFORCEMENTS_PLAYERSIDE;
else
gCurrentIncident.usIncidentFlags |= INCIDENT_REINFORCEMENTS_ENEMY;
}
}
#ifdef JA2UB
gsGridNoForMapEdgePointInfo = -1;
#endif
}
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( )
{
#ifdef JA2UB
// no UB
#else
// 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!
HandleInterrogationMeanwhileScene();
}
// 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;
}
}
#endif
}
void EnemyCapturesPlayerSoldier( SOLDIERTYPE *pSoldier )
{
UINT32 i;
BOOLEAN fMadeCorpse;
INT32 iNumEnemiesInSector;
// Buggler: Externalized Hardcoded grid number
//static INT32 sAlmaCaptureGridNos[] = { 9208, 9688, 9215 }; //dnl!!!
//static INT32 sAlmaCaptureItemsGridNo[] = { 12246, 12406, 12086 }; //dnl!!!
//static INT32 sInterrogationItemGridNo[] = { 12089, 12089, 12089 }; //dnl!!!
AssertNotNIL(pSoldier);
// 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->stats.bLife = 0;
pSoldier->iHealableInjury = 0; // added by SANDRO
HandleSoldierDeath( pSoldier, &fMadeCorpse );
return;
}
if ( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE )
{
return;
}
// ATE: Patch fix If in a vehicle, remove from vehicle...
TakeSoldierOutOfVehicle( pSoldier );
// Are there enemies in ALMA? ( I13 )
iNumEnemiesInSector = NumNonPlayerTeamMembersInSector( gModSettings.ubInitialPOWSectorX, gModSettings.ubInitialPOWSectorY, ENEMY_TEAM ); //(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->aiData.bNeutral = TRUE;
}
RemoveCharacterFromSquads( pSoldier );
WORLDITEM WorldItem;
std::vector<WORLDITEM> pWorldItem;
if ( gubQuest[QUEST_HELD_IN_ALMA] == QUESTNOTSTARTED || gubQuest[QUEST_HELD_IN_ALMA] == QUESTDONE )
{
INT32 itemdropoffgridno = -1;
// 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 = gModSettings.ubInitialPOWSectorX; //13
pSoldier->sSectorY = gModSettings.ubInitialPOWSectorY; //9
pSoldier->bSectorZ = 0;
pSoldier->usStrategicInsertionData = gModSettings.iInitialPOWGridNo[gStrategicStatus.ubNumCapturedForRescue];
itemdropoffgridno = gModSettings.iInitialPOWItemGridNo[gStrategicStatus.ubNumCapturedForRescue];
}
else //if ( gubQuest[QUEST_HELD_IN_ALMA] == QUESTDONE )
{
//-teleport him to N7
pSoldier->sSectorX = gModSettings.ubMeanwhileInterrogatePOWSectorX; //7
pSoldier->sSectorY = gModSettings.ubMeanwhileInterrogatePOWSectorY; //14
pSoldier->bSectorZ = 0;
pSoldier->usStrategicInsertionData = gModSettings.iMeanwhileInterrogatePOWGridNo[gStrategicStatus.ubNumCapturedForRescue];
itemdropoffgridno = gModSettings.iMeanwhileInterrogatePOWItemGridNo[gStrategicStatus.ubNumCapturedForRescue];;
}
// OK, drop all items!
UINT32 invsize = pSoldier->inv.size();
for ( i = 0; i < invsize; ++i )
{
if ( pSoldier->inv[i].exists() )
{
WorldItem.fExists = TRUE;
WorldItem.sGridNo = itemdropoffgridno;
WorldItem.ubLevel = 0;
WorldItem.usFlags = 0;
WorldItem.bVisible = FALSE;
WorldItem.bRenderZHeightAboveLevel = 0;
pSoldier->inv[i].MoveThisObjectTo( WorldItem.object );
pWorldItem.push_back( WorldItem );
}
}
AddWorldItemsToUnLoadedSector( pSoldier->sSectorX, pSoldier->sSectorY, 0, itemdropoffgridno, pWorldItem.size(), pWorldItem, FALSE );
// put him on the floor!!
pSoldier->pathing.bLevel = 0;
pSoldier->ubStrategicInsertionCode = INSERTION_CODE_GRIDNO;
gStrategicStatus.ubNumCapturedForRescue++;
}
//Bandaging him would prevent him from dying (due to low HP)
pSoldier->bBleeding = 0;
// wake him up
if ( pSoldier->flags.fMercAsleep )
{
PutMercInAwakeState( pSoldier );
pSoldier->flags.fForcedToStayAwake = FALSE;
}
//Set his life to 50% + or - 10 HP.
INT8 oldlife = pSoldier->stats.bLife;
pSoldier->stats.bLife = max(35, pSoldier->stats.bLifeMax / 2);
if ( pSoldier->stats.bLife >= 45 )
{
pSoldier->stats.bLife += (INT8)(10 - Random( 21 ) );
}
// SANDRO - make the lost life insta-healable
pSoldier->iHealableInjury = ((pSoldier->stats.bLifeMax - pSoldier->stats.bLife) * 100);
// make him quite exhausted when found
pSoldier->bBreath = pSoldier->bBreathMax = 50;
pSoldier->sBreathRed = 0;
pSoldier->flags.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 ]->stats.bLife < OKLIFE && MercPtrs[ i ]->stats.bLife )
{
MercPtrs[ i ]->stats.bLife = 0;
MercPtrs[ i ]->iHealableInjury = 0; // added just for sure - SANDRO
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 ]->stats.bLife < OKLIFE && MercPtrs[ i ]->stats.bLife )
{
MercPtrs[ i ]->stats.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 ]->stats.bLife < OKLIFE && MercPtrs[ i ]->stats.bLife )
{
MercPtrs[ i ]->stats.bLife = 0;
MercPtrs[ i ]->iHealableInjury = 0; // added just for sure - SANDRO
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 ]->stats.bLife < OKLIFE && MercPtrs[ i ]->stats.bLife )
{
MercPtrs[ i ]->stats.bLife = 0;
MercPtrs[ i ]->iHealableInjury = 0; // added just for sure - SANDRO
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 )
{
if ( NumNonPlayerTeamMembersInSector( SECTORX( ubSectorID ), SECTORY( ubSectorID ), MILITIA_TEAM ) )
{
//militia in sector
return TRUE;
}
if ( FindMovementGroupInSector( SECTORX( ubSectorID ), SECTORY( ubSectorID ), OUR_TEAM ) )
{
// player/militia 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->stats.bLife )
{
if( !pSoldier->aiData.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->stats.bLife )
{
if( !pSoldier->aiData.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->stats.bLife )
{
if( !pSoldier->aiData.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->stats.bLife )
{
if( !pSoldier->aiData.bNeutral )
{
return FALSE;
}
}
}
//We only have hostile civilians, don't allow time compression.
return TRUE;
}
// Flugente check whether a team has nearby members that can be added to the current battle
// Note that this requires separate counts of teammembers in the sector and those that are actually fighting
// This currently does not exist for MILITIA_TEAM, making such a check relatively useless
BOOLEAN CheckPendingNonPlayerTeam( UINT8 usTeam )
{
if( gbWorldSectorZ )
return FALSE;
SECTORINFO *pSector = &SectorInfo[SECTOR( gWorldSectorX, gWorldSectorY )];
if ( usTeam == ENEMY_TEAM )
{
if ( (pSector->ubNumElites + pSector->ubNumTroops + pSector->ubNumAdmins + pSector->ubNumTanks + pSector->ubNumJeeps) >
(pSector->ubElitesInBattle + pSector->ubTroopsInBattle + pSector->ubAdminsInBattle + pSector->ubTanksInBattle + pSector->ubJeepsInBattle) )
return TRUE;
}
for (GROUP *pGroup = gpGroupList; pGroup; pGroup = pGroup->next)
{
if ( pGroup->usGroupTeam == usTeam
&& !pGroup->fVehicle
&& pGroup->ubSectorX == gWorldSectorX
&& pGroup->ubSectorY == gWorldSectorY )
{
if ( usTeam == ENEMY_TEAM )
{
if ( pGroup->ubGroupSize > pGroup->pEnemyGroup->ubElitesInBattle + pGroup->pEnemyGroup->ubTroopsInBattle + pGroup->pEnemyGroup->ubAdminsInBattle
+ pGroup->pEnemyGroup->ubTanksInBattle + pGroup->pEnemyGroup->ubJeepsInBattle )
return TRUE;
}
else if ( usTeam == MILITIA_TEAM )
{
if ( pGroup->ubGroupSize > pSector->ubNumberOfCivsAtLevel[GREEN_MILITIA] + pSector->ubNumberOfCivsAtLevel[REGULAR_MILITIA] + pSector->ubNumberOfCivsAtLevel[ELITE_MILITIA] )
return TRUE;
}
}
}
return FALSE;
}
#ifdef JA2UB
void HandleBloodCatDeaths( SECTORINFO *pSector )
{
//if the current sector is the first part of the town
if( gWorldSectorX == 10 && gWorldSectorY == 9 && gbWorldSectorZ == 0 )
{
//if ALL the bloodcats are killed
if( pSector->bBloodCats == 0 )
{
UINT8 bId1=-1;
UINT8 bId2=-1;
UINT8 bNum=0;
SetFactTrue( FACT_PLAYER_KILLED_ALL_BETTYS_BLOODCATS );
//Instantly have betties missing items show up
//DailyCheckOnItemQuantities( TRUE );
// Now have a merc say the killed bloodcat quote
bNum = Get3RandomQualifiedMercs( &bId1, &bId2, NULL );
//if there are some qualified mercs
if( bNum != 0 )
{
//must make sure TEX doesnt say the quote
if( bId1 != NOBODY && Menptr[ bId1 ].ubProfile != TEX_UB )
{
TacticalCharacterDialogue( &Menptr[ bId1 ], QUOTE_RENEW_REFUSAL_DUE_TO_LACK_OF_FUNDS );
}
else if( bId2 != NOBODY && Menptr[ bId2 ].ubProfile != TEX_UB )
{
TacticalCharacterDialogue( &Menptr[ bId2 ], QUOTE_RENEW_REFUSAL_DUE_TO_LACK_OF_FUNDS );
}
}
}
}
}
#endif