diff --git a/GameSettings.cpp b/GameSettings.cpp index 4dc0df52..b2885d52 100644 --- a/GameSettings.cpp +++ b/GameSettings.cpp @@ -1386,6 +1386,14 @@ void LoadGameExternalOptions() gGameExternalOptions.ubAPSharedAmongPassengersAndVehicleMode = iniReader.ReadInteger("Tactical Gameplay Settings","AP_SHARED_AMONG_PASSENGERS_AND_VEHICLE_MODE", 3, 0, 3); gGameExternalOptions.ubAPSharedAmongPassengersAndVehicleScale = iniReader.ReadInteger("Tactical Gameplay Settings","AP_SHARED_AMONG_PASSENGERS_AND_VEHICLE_SCALE", 100, 0, 200); + gGameExternalOptions.fEnemyTanksCanMoveInTactical = iniReader.ReadBoolean("Tactical Gameplay Settings","ENEMY_TANKS_CAN_MOVE_IN_TACTICAL", FALSE); + gGameExternalOptions.fEnemyTanksDontSpareShells = iniReader.ReadBoolean("Tactical Gameplay Settings","ENEMY_TANKS_DONT_SPARE_SHELLS", TRUE); + gGameExternalOptions.fEnemyTanksBlowObstaclesUp = iniReader.ReadBoolean("Tactical Gameplay Settings","ENEMY_TANKS_BLOW_OBSTACLES_UP", TRUE); + gGameExternalOptions.fEnemyTanksAnyPartVisible = iniReader.ReadBoolean("Tactical Gameplay Settings","ENEMY_TANKS_ANY_PART_VISIBLE", FALSE); + + gGameExternalOptions.fEnemiesDontSpareLaunchables = iniReader.ReadBoolean("Tactical Gameplay Settings","ENEMIES_DONT_SPARE_LAUNCHABLES", TRUE); + gGameExternalOptions.fEnemiesBlowObstaclesUp = iniReader.ReadBoolean("Tactical Gameplay Settings","ENEMIES_BLOW_OBSTACLES_UP", FALSE); + // SANDRO - Improved camo applying and camo can be removed gGameExternalOptions.fCamoRemoving = iniReader.ReadBoolean("Tactical Gameplay Settings", "CAMO_REMOVING", TRUE); gGameExternalOptions.bCamoKitArea = iniReader.ReadInteger("Tactical Gameplay Settings", "CAMO_KIT_USABLE_AREA", 5, 0, 100); @@ -2234,6 +2242,9 @@ void LoadGameExternalOptions() //dnl ch68 090913 Don't allow permanent items removal from sector gGameExternalOptions.fNoRemoveRandomSectorItems = iniReader.ReadBoolean("Strategic GamePlay Settings", "NO_REMOVE_RANDOM_SECTOR_ITEMS", true, false); + gGameExternalOptions.fArmyUsesTanksInAttacks = iniReader.ReadBoolean("Strategic Gameplay Settings","ARMY_USES_TANKS_IN_ATTACKS", FALSE); + gGameExternalOptions.fArmyUsesTanksInPatrols = iniReader.ReadBoolean("Strategic Gameplay Settings","ARMY_USES_TANKS_IN_PATROLS", FALSE); + // WANNE: This is just a debug setting. Only in debug version we set that property to TRUE. // In Release version this should always be set to FALSE // dnl ch51 081009 JA2 Debug Settings diff --git a/GameSettings.h b/GameSettings.h index 697bbf58..ff5cca57 100644 --- a/GameSettings.h +++ b/GameSettings.h @@ -837,6 +837,18 @@ typedef struct BOOLEAN fAddPassengerToAnySquad; BOOLEAN fPassengerLeavingSwitchToNewSquad; + // anv: tanks can move! + BOOLEAN fEnemyTanksCanMoveInTactical; + BOOLEAN fEnemyTanksDontSpareShells; + BOOLEAN fEnemyTanksBlowObstaclesUp; + BOOLEAN fEnemyTanksAnyPartVisible; + + BOOLEAN fEnemiesDontSpareLaunchables; + BOOLEAN fEnemiesBlowObstaclesUp; + + BOOLEAN fArmyUsesTanksInAttacks; + BOOLEAN fArmyUsesTanksInPatrols; + // WANNE: Always use "prof.dat". BOOLEAN fUseDifficultyBasedProfDat; diff --git a/SaveLoadGame.cpp b/SaveLoadGame.cpp index 40fe92b4..c09e2410 100644 --- a/SaveLoadGame.cpp +++ b/SaveLoadGame.cpp @@ -9259,7 +9259,7 @@ void ValidateStrategicGroups() for( i = SEC_A1; i < SEC_P16; i++ ) { pSector = &SectorInfo[ i ]; - if( pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites > gGameExternalOptions.iMaxEnemyGroupSize ) + if( pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumTanks > gGameExternalOptions.iMaxEnemyGroupSize ) { } //militia diff --git a/Strategic/AI Viewer.cpp b/Strategic/AI Viewer.cpp index 56818c13..1edf9509 100644 --- a/Strategic/AI Viewer.cpp +++ b/Strategic/AI Viewer.cpp @@ -161,7 +161,7 @@ void ViewCreaturesCallback( GUI_BUTTON *btn, INT32 reason ); void ExtractAndUpdatePopulations(); void PrintEnemyPopTable(); void PrintEnemiesKilledTable(); -UINT8 ChooseEnemyIconColor( UINT8 ubAdmins, UINT8 ubTroops, UINT8 ubElites ); +UINT8 ChooseEnemyIconColor( UINT8 ubAdmins, UINT8 ubTroops, UINT8 ubElites, UINT8 ubTanks ); void BlitGroupIcon( UINT8 ubIconType, UINT8 ubIconColor, UINT32 uiX, UINT32 uiY, HVOBJECT hVObject ); void PrintDetailedEnemiesInSectorInfo( INT32 iScreenX, INT32 iScreenY, UINT8 ubSectorX, UINT8 ubSectorY ); @@ -188,6 +188,7 @@ UINT16 gusDkBlue; INT16 gsAINumAdmins = -1; INT16 gsAINumTroops = -1; INT16 gsAINumElites = -1; +INT16 gsAINumTanks = -1; INT16 gsAINumCreatures = -1; BOOLEAN gfOverrideSector = FALSE; @@ -488,11 +489,11 @@ void RenderStationaryGroups() ubGroupSize = pSector->ubNumberOfCivsAtLevel[0] + pSector->ubNumberOfCivsAtLevel[1] + pSector->ubNumberOfCivsAtLevel[2]; } else - if( pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites ) + if( pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumTanks ) { // show enemies - ubIconColor = ChooseEnemyIconColor( pSector->ubNumAdmins, pSector->ubNumTroops, pSector->ubNumElites ); - ubGroupSize = pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites; + ubIconColor = ChooseEnemyIconColor( pSector->ubNumAdmins, pSector->ubNumTroops, pSector->ubNumElites, pSector->ubNumTanks ); + ubGroupSize = pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumTanks; if( pSector->ubGarrisonID != NO_GARRISON ) { if( gGarrisonGroup[ pSector->ubGarrisonID ].ubPendingGroupID ) @@ -536,7 +537,7 @@ void RenderMovingGroupsAndMercs() GROUP *pGroup; HVOBJECT hVObject; INT32 x, y; - UINT8 ubNumTroops, ubNumAdmins, ubNumElites; + UINT8 ubNumTroops, ubNumAdmins, ubNumElites, ubNumTanks; float ratio; INT32 minX, maxX, minY, maxY; UINT8 ubIconType; @@ -591,12 +592,13 @@ void RenderMovingGroupsAndMercs() ubNumAdmins = pGroup->pEnemyGroup->ubNumAdmins;//+ pGroup->pEnemyGroup->ubAdminsInBattle; ubNumTroops = pGroup->pEnemyGroup->ubNumTroops;//+ pGroup->pEnemyGroup->ubTroopsInBattle; ubNumElites = pGroup->pEnemyGroup->ubNumElites;// + pGroup->pEnemyGroup->ubElitesInBattle; + ubNumTanks = pGroup->pEnemyGroup->ubNumTanks; // must have one of the three, already checked groupsize! - Assert( ubNumAdmins || ubNumTroops || ubNumElites ); + Assert( ubNumAdmins || ubNumTroops || ubNumElites || ubNumTanks ); //determine icon color - ubIconColor = ChooseEnemyIconColor( ubNumAdmins, ubNumTroops, ubNumElites ); + ubIconColor = ChooseEnemyIconColor( ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks ); // must have a valid intention Assert( pGroup->pEnemyGroup->ubIntention < NUM_ENEMY_INTENTIONS ); @@ -721,7 +723,7 @@ void RenderInfoInSector() { SECTORINFO *pSector; GROUP *pGroup; - UINT8 ubNumAdmins=0, ubNumTroops=0, ubNumElites=0, ubAdminsInBattle=0, ubTroopsInBattle=0, ubElitesInBattle=0, ubNumGroups=0; + UINT8 ubNumAdmins=0, ubNumTroops=0, ubNumElites=0, ubNumTanks=0, ubAdminsInBattle=0, ubTroopsInBattle=0, ubElitesInBattle=0, ubTanksInBattle=0, ubNumGroups=0; pSector = &SectorInfo[ SECTOR( ubSectorX, ubSectorY ) ]; @@ -734,9 +736,11 @@ void RenderInfoInSector() ubNumTroops += pGroup->pEnemyGroup->ubNumTroops; ubNumElites += pGroup->pEnemyGroup->ubNumElites; ubNumAdmins += pGroup->pEnemyGroup->ubNumAdmins; + ubNumTanks += pGroup->pEnemyGroup->ubNumTanks; ubTroopsInBattle += pGroup->pEnemyGroup->ubTroopsInBattle; ubElitesInBattle += pGroup->pEnemyGroup->ubElitesInBattle; ubAdminsInBattle += pGroup->pEnemyGroup->ubAdminsInBattle; + ubTanksInBattle += pGroup->pEnemyGroup->ubTanksInBattle; ubNumGroups++; } pGroup = pGroup->next; @@ -753,15 +757,17 @@ void RenderInfoInSector() pSector->ubNumberOfCivsAtLevel[0], pSector->ubNumberOfCivsAtLevel[1], pSector->ubNumberOfCivsAtLevel[2] ); yp += 10; SetFontForeground( FONT_ORANGE ); - mprintf( 280, yp, L"Garrison: (%d:%d Admins, %d:%d Troops, %d:%d Elites)", + mprintf( 280, yp, L"Garrison: (%d:%d Admins, %d:%d Troops, %d:%d Elites, %d:%d Tanks)", pSector->ubAdminsInBattle, pSector->ubNumAdmins, pSector->ubTroopsInBattle, pSector->ubNumTroops, - pSector->ubElitesInBattle, pSector->ubNumElites ); + pSector->ubElitesInBattle, pSector->ubNumElites, + pSector->ubTanksInBattle, pSector->ubNumTanks ); yp += 10; - mprintf( 280, yp, L"%d Groups: (%d:%d Admins, %d:%d Troops, %d:%d Elites)", ubNumGroups, + mprintf( 280, yp, L"%d Groups: (%d:%d Admins, %d:%d Troops, %d:%d Elites, %d:%d Tanks)", ubNumGroups, ubAdminsInBattle, ubNumAdmins, ubTroopsInBattle, ubNumTroops, - ubElitesInBattle, ubNumElites ); + ubElitesInBattle, ubNumElites, + ubTanksInBattle, ubNumTanks ); yp += 10; SetFontForeground( FONT_WHITE ); @@ -1266,7 +1272,7 @@ void TestIncoming4SidesCallback( GUI_BUTTON *btn, INT32 reason ) gfRenderViewer = TRUE; if( gsSelSectorY > 1 ) { - pGroup = CreateNewEnemyGroupDepartingFromSector( ubSector-16, 0, 11, 5 ); + pGroup = CreateNewEnemyGroupDepartingFromSector( ubSector-16, 0, 11, 5, 0 ); pGroup->ubNextX = (UINT8)gsSelSectorX; pGroup->ubNextY = (UINT8)gsSelSectorY; pGroup->uiTraverseTime = 10; @@ -1278,7 +1284,7 @@ void TestIncoming4SidesCallback( GUI_BUTTON *btn, INT32 reason ) } if( gsSelSectorY < 16 ) { - pGroup = CreateNewEnemyGroupDepartingFromSector( ubSector+16, 0, 8, 8 ); + pGroup = CreateNewEnemyGroupDepartingFromSector( ubSector+16, 0, 8, 8, 0 ); pGroup->ubNextX = (UINT8)gsSelSectorX; pGroup->ubNextY = (UINT8)gsSelSectorY; pGroup->uiTraverseTime = 12; @@ -1290,7 +1296,7 @@ void TestIncoming4SidesCallback( GUI_BUTTON *btn, INT32 reason ) } if( gsSelSectorX > 1 ) { - pGroup = CreateNewEnemyGroupDepartingFromSector( ubSector-1, 0, 11, 5 ); + pGroup = CreateNewEnemyGroupDepartingFromSector( ubSector-1, 0, 11, 5, 0 ); pGroup->ubNextX = (UINT8)gsSelSectorX; pGroup->ubNextY = (UINT8)gsSelSectorY; pGroup->uiTraverseTime = 11; @@ -1302,7 +1308,7 @@ void TestIncoming4SidesCallback( GUI_BUTTON *btn, INT32 reason ) } if( gsSelSectorX < 16 ) { - pGroup = CreateNewEnemyGroupDepartingFromSector( ubSector+1, 0, 14, 0 ); + pGroup = CreateNewEnemyGroupDepartingFromSector( ubSector+1, 0, 14, 0, 0 ); pGroup->ubNextX = (UINT8)gsSelSectorX; pGroup->ubNextY = (UINT8)gsSelSectorY; pGroup->uiTraverseTime = 13; @@ -1557,6 +1563,7 @@ void PrintEnemyPopTable() usEnemyPopTable[ ENEMY_RANK_ADMIN ][ ENEMY_TYPE_GARRISON ] += pSector->ubNumAdmins; usEnemyPopTable[ ENEMY_RANK_TROOP ][ ENEMY_TYPE_GARRISON ] += pSector->ubNumTroops; usEnemyPopTable[ ENEMY_RANK_ELITE ][ ENEMY_TYPE_GARRISON ] += pSector->ubNumElites; + //usEnemyPopTable[ ENEMY_RANK_TANK ][ ENEMY_TYPE_GARRISON ] += pSector->ubNumTanks; } // count moving enemies @@ -1583,6 +1590,7 @@ void PrintEnemyPopTable() usEnemyPopTable[ ENEMY_RANK_ADMIN ][ ubEnemyType ] += pGroup->pEnemyGroup->ubNumAdmins; usEnemyPopTable[ ENEMY_RANK_TROOP ][ ubEnemyType ] += pGroup->pEnemyGroup->ubNumTroops; usEnemyPopTable[ ENEMY_RANK_ELITE ][ ubEnemyType ] += pGroup->pEnemyGroup->ubNumElites; + //usEnemyPopTable[ ENEMY_RANK_TANK ][ ubEnemyType ] += pGroup->pEnemyGroup->ubNumTanks; } pGroup = pGroup->next; @@ -1823,7 +1831,7 @@ void PrintEnemiesKilledTable() -UINT8 ChooseEnemyIconColor( UINT8 ubAdmins, UINT8 ubTroops, UINT8 ubElites ) +UINT8 ChooseEnemyIconColor( UINT8 ubAdmins, UINT8 ubTroops, UINT8 ubElites, UINT8 ubTanks ) { UINT8 ubIconColor; @@ -1834,7 +1842,7 @@ UINT8 ChooseEnemyIconColor( UINT8 ubAdmins, UINT8 ubTroops, UINT8 ubElites ) // Orange Mixed, no elites (Admins + Troops) // Burgundy Mixed, with elites (Elites + (Admins OR Troops)) - Assert( ubAdmins || ubTroops || ubElites ); + Assert( ubAdmins || ubTroops || ubElites ||ubTanks ); if ( ubElites ) { @@ -1895,8 +1903,8 @@ void PrintDetailedEnemiesInSectorInfo( INT32 iScreenX, INT32 iScreenY, UINT8 ubS // handle garrisoned enemies if( pSector->ubGarrisonID != NO_GARRISON ) { - iDesired = gArmyComp[ gGarrisonGroup[ pSector->ubGarrisonID ].ubComposition ].bDesiredPopulation; - iSurplus = pSector->ubNumTroops + pSector->ubNumAdmins + pSector->ubNumElites - iDesired; + iDesired = gArmyComp[ gGarrisonGroup[ pSector->ubGarrisonID ].ubComposition ].bDesiredPopulation; + iSurplus = pSector->ubNumTroops + pSector->ubNumAdmins + pSector->ubNumElites + pSector->ubNumTanks - iDesired; SetFontForeground( FONT_WHITE ); swprintf( wString, L"Garrison #%d: %d desired, ", pSector->ubGarrisonID, iDesired ); diff --git a/Strategic/Assignments.cpp b/Strategic/Assignments.cpp index 4b25eb28..cce70988 100644 --- a/Strategic/Assignments.cpp +++ b/Strategic/Assignments.cpp @@ -6839,6 +6839,7 @@ void HandlePrison( INT16 sMapX, INT16 sMapY, INT8 bZ ) pSectorInfo->ubNumTroops = min(255, pSectorInfo->ubNumTroops + prisonersregular); pSectorInfo->ubNumElites = min(255, pSectorInfo->ubNumElites + prisonerselite + prisonersofficer); pSectorInfo->ubNumAdmins = min(255, pSectorInfo->ubNumAdmins + prisonersadmin); + pSectorInfo->ubNumTanks = min(255, pSectorInfo->ubNumTanks ); // all prisoners are free, reduce count! DeleteAllPrisoners(pSectorInfo); @@ -6892,6 +6893,7 @@ void HandlePrison( INT16 sMapX, INT16 sMapY, INT8 bZ ) pSectorInfo->ubNumTroops = min( 512, pSectorInfo->ubNumTroops + escapedregulars ); pSectorInfo->ubNumElites = min( 512, pSectorInfo->ubNumElites + escapedelites + escapedofficers ); pSectorInfo->ubNumAdmins = min( 512, pSectorInfo->ubNumAdmins + escapedadmins ); + pSectorInfo->ubNumTanks = min( 512, pSectorInfo->ubNumTanks ); // reduce prisoner count! ChangeNumberOfPrisoners( pSectorInfo, -escapedofficers, -escapedelites, -escapedregulars, -escapedadmins, sMapX, sMapY ); diff --git a/Strategic/Auto Resolve.cpp b/Strategic/Auto Resolve.cpp index 678b9d70..ebdaae2c 100644 --- a/Strategic/Auto Resolve.cpp +++ b/Strategic/Auto Resolve.cpp @@ -166,7 +166,7 @@ typedef struct AUTORESOLVE_STRUCT UINT8 ubEnemyLeadership; UINT8 ubPlayerLeadership; UINT8 ubMercs, ubCivs, ubEnemies; - UINT8 ubAdmins, ubTroops, ubElites; + UINT8 ubAdmins, ubTroops, ubElites, ubTanks; UINT8 ubYMCreatures, ubYFCreatures, ubAMCreatures, ubAFCreatures; UINT8 ubAliveMercs, ubAliveCivs, ubAliveEnemies; UINT8 ubMercCols, ubMercRows; @@ -226,10 +226,11 @@ typedef struct AUTORESOLVE_STRUCT #define CELL_ASSIGNED 0x00080000 #define CELL_EPC 0x00100000 #define CELL_ROBOT 0x00200000 +#define CELL_TANK 0x00400000 //Combined flags #define CELL_PLAYER ( CELL_MERC | CELL_MILITIA ) -#define CELL_ENEMY ( CELL_ELITE | CELL_TROOP | CELL_ADMIN ) +#define CELL_ENEMY ( CELL_ELITE | CELL_TROOP | CELL_ADMIN | CELL_TANK ) #define CELL_CREATURE ( CELL_AF_CREATURE | CELL_AM_CREATURE | CELL_YF_CREATURE | CELL_YM_CREATURE ) #define CELL_FEMALECREATURE ( CELL_AF_CREATURE | CELL_YF_CREATURE ) #define CELL_MALECREATURE ( CELL_AM_CREATURE | CELL_YM_CREATURE ) @@ -441,7 +442,7 @@ void EliminateAllEnemies( UINT8 ubSectorX, UINT8 ubSectorY ) // we must process the enemies killed right here & give out loyalty bonuses as if the battle had been fought & won if( !gpAR ) { - GetNumberOfEnemiesInSector( ubSectorX, ubSectorY, &ubNumEnemies[ 0 ], &ubNumEnemies[ 1 ], &ubNumEnemies[ 2 ] ); + GetNumberOfEnemiesInSector( ubSectorX, ubSectorY, &ubNumEnemies[ 0 ], &ubNumEnemies[ 1 ], &ubNumEnemies[ 2 ], &ubNumEnemies[ 3 ] ); for ( ubRankIndex = 0; ubRankIndex < NUM_ENEMY_RANKS; ubRankIndex++ ) { @@ -461,6 +462,7 @@ void EliminateAllEnemies( UINT8 ubSectorX, UINT8 ubSectorY ) pSector->ubNumTroops = 0; pSector->ubNumElites = 0; pSector->ubNumAdmins = 0; + pSector->ubNumTanks = 0; pSector->ubNumCreatures = 0; pSector->bLastKnownEnemies = 0; //Remove the mobile forces here, but only if battle is over. @@ -749,9 +751,9 @@ void AssociateEnemiesWithStrategicGroups() { SECTORINFO *pSector; GROUP *pGroup; - UINT8 ubNumAdmins, ubNumTroops, ubNumElites; - UINT8 ubISNumAdmins, ubISNumTroops, ubISNumElites; - UINT8 ubNumElitesInGroup, ubNumTroopsInGroup, ubNumAdminsInGroup; + UINT8 ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks; + UINT8 ubISNumAdmins, ubISNumTroops, ubISNumElites, ubISNumTanks; + UINT8 ubNumElitesInGroup, ubNumTroopsInGroup, ubNumAdminsInGroup, ubNumTanksInGroup; INT32 i; UINT8 pSectors[4]; UINT8 ubDirAmount; @@ -766,6 +768,7 @@ void AssociateEnemiesWithStrategicGroups() ubNumAdmins = pSector->ubNumAdmins; ubNumTroops = pSector->ubNumTroops; ubNumElites = pSector->ubNumElites; + ubNumTanks = pSector->ubNumTanks; //Now go through our enemies in the autoresolve array, and assign the ubGroupID to the soldier //Stationary groups have a group ID of 0 @@ -789,13 +792,20 @@ void AssociateEnemiesWithStrategicGroups() gpEnemies[ i ].uiFlags |= CELL_ASSIGNED; ubNumAdmins--; } + else if( gpEnemies[ i ].uiFlags & CELL_TANK && ubNumTanks ) + { + gpEnemies[ i ].pSoldier->ubGroupID = 0; + gpEnemies[ i ].uiFlags |= CELL_ASSIGNED; + ubNumTanks--; + } } ubNumAdmins = gpAR->ubAdmins - pSector->ubNumAdmins; ubNumTroops = gpAR->ubTroops - pSector->ubNumTroops; ubNumElites = gpAR->ubElites - pSector->ubNumElites; + ubNumTanks = gpAR->ubTanks - pSector->ubNumTanks; - if( !ubNumElites && !ubNumTroops && !ubNumAdmins ) + if( !ubNumElites && !ubNumTroops && !ubNumAdmins && !ubNumTanks ) { //All troops accounted for. return; } @@ -809,6 +819,7 @@ void AssociateEnemiesWithStrategicGroups() ubNumElitesInGroup = pGroup->pEnemyGroup->ubNumElites; ubNumTroopsInGroup = pGroup->pEnemyGroup->ubNumTroops; ubNumAdminsInGroup = pGroup->pEnemyGroup->ubNumAdmins; + ubNumTanksInGroup = pGroup->pEnemyGroup->ubNumTanks; for( i = 0; i < gpAR->ubEnemies; i++ ) { if( !(gpEnemies[ i ].uiFlags & CELL_ASSIGNED) ) @@ -834,6 +845,13 @@ void AssociateEnemiesWithStrategicGroups() ubNumAdmins--; ubNumAdminsInGroup--; } + else if( ubNumTanks && ubNumTanksInGroup ) + { + gpEnemies[ i ].pSoldier->ubGroupID = pGroup->ubGroupID; + gpEnemies[ i ].uiFlags |= CELL_ASSIGNED; + ubNumTanks--; + ubNumTanksInGroup--; + } } } } @@ -850,6 +868,7 @@ void AssociateEnemiesWithStrategicGroups() ubNumElitesInGroup = pGroup->pEnemyGroup->ubNumElites; ubNumTroopsInGroup = pGroup->pEnemyGroup->ubNumTroops; ubNumAdminsInGroup = pGroup->pEnemyGroup->ubNumAdmins; + ubNumTanksInGroup = pGroup->pEnemyGroup->ubNumTanks; for( i = 0; i < gpAR->ubEnemies; i++ ) { if( !(gpEnemies[ i ].uiFlags & CELL_ASSIGNED) ) @@ -875,6 +894,13 @@ void AssociateEnemiesWithStrategicGroups() ubNumAdmins--; ubNumAdminsInGroup--; } + else if( ubNumTanks && ubNumTanksInGroup ) + { + gpEnemies[ i ].pSoldier->ubGroupID = pGroup->ubGroupID; + gpEnemies[ i ].uiFlags |= CELL_ASSIGNED; + ubNumTanks--; + ubNumTanksInGroup--; + } } } } @@ -892,10 +918,11 @@ void AssociateEnemiesWithStrategicGroups() ubISNumAdmins = pSector->ubNumAdmins; ubISNumTroops = pSector->ubNumTroops; ubISNumElites = pSector->ubNumElites; + ubISNumTanks = pSector->ubNumTanks; for( i = 0; i < gpAR->ubEnemies; i++ ) { - if( ubISNumAdmins + ubISNumTroops + ubISNumElites <= gubReinforcementMinEnemyStaticGroupSize ) break; + if( ubISNumAdmins + ubISNumTroops + ubISNumElites + ubISNumTanks <= gubReinforcementMinEnemyStaticGroupSize ) break; if( !(gpEnemies[ i ].uiFlags & CELL_ASSIGNED) ) { @@ -926,6 +953,15 @@ void AssociateEnemiesWithStrategicGroups() ubISNumAdmins--; ubNumAdmins--; } + else if( gpEnemies[ i ].uiFlags & CELL_TANK && ubISNumTanks && ubNumTanks ) + { + gpEnemies[ i ].pSoldier->ubGroupID = 0; + gpEnemies[ i ].uiFlags |= CELL_ASSIGNED; + gpEnemies[ i ].pSoldier->sSectorX = SECTORX( pSectors[ ubCurrSI ] ); + gpEnemies[ i ].pSoldier->sSectorY = SECTORY( pSectors[ ubCurrSI ] ); + ubISNumTanks--; + ubNumTanks--; + } } } } @@ -2480,6 +2516,15 @@ void CreateAutoResolveInterface() gpEnemies[index].pSoldier->sSectorY = gpAR->ubSectorY; swprintf( gpEnemies[index].pSoldier->name, gpStrategicString[ STR_AR_ADMINISTRATOR_NAME ] ); } + for( i = 0; i < gpAR->ubTanks; i++, index++ ) + { + gpEnemies[index].pSoldier = TacticalCreateEnemyTank(); + gpEnemies[index].uiVObjectID = gpAR->iFaces; + gpEnemies[index].usIndex = ELITE_FACE; + gpEnemies[index].pSoldier->sSectorX = gpAR->ubSectorX; + gpEnemies[index].pSoldier->sSectorY = gpAR->ubSectorY; + //swprintf( gpEnemies[index].pSoldier->name, gpStrategicString[ STR_AR_ADMINISTRATOR_NAME ] ); + } AssociateEnemiesWithStrategicGroups(); } else @@ -3141,7 +3186,7 @@ void CalculateAutoResolveInfo() { // GetNumberOfEnemiesInSector( gpAR->ubSectorX, gpAR->ubSectorY, GetNumberOfEnemiesInFiveSectors( gpAR->ubSectorX, gpAR->ubSectorY, - &gpAR->ubAdmins, &gpAR->ubTroops, &gpAR->ubElites ); + &gpAR->ubAdmins, &gpAR->ubTroops, &gpAR->ubElites, &gpAR->ubTanks ); gpAR->ubEnemies = (UINT8)min( gpAR->ubAdmins + gpAR->ubTroops + gpAR->ubElites, MAX_AR_TEAM_SIZE ); } else diff --git a/Strategic/Campaign Init.cpp b/Strategic/Campaign Init.cpp index 21e65de7..1bb66f35 100644 --- a/Strategic/Campaign Init.cpp +++ b/Strategic/Campaign Init.cpp @@ -337,25 +337,25 @@ void GeneratePatrolGroups() GROUP *pGroup; UINT8 ubNumTroops; ubNumTroops = (UINT8)(3 + gGameOptions.ubDifficultyLevel + Random( 3 )); - pGroup = CreateNewEnemyGroupDepartingFromSector( SEC_C7, 0, ubNumTroops, 0 ); + pGroup = CreateNewEnemyGroupDepartingFromSector( SEC_C7, 0, ubNumTroops, 0, 0 ); pGroup->ubTransportationMask = CAR; AddWaypointToPGroup( pGroup, 8, 3 ); //C8 AddWaypointToPGroup( pGroup, 7, 3 ); //C7 ubNumTroops = (UINT8)(3 + gGameOptions.ubDifficultyLevel + Random( 3 )); - pGroup = CreateNewEnemyGroupDepartingFromSector( SEC_D9, 0, ubNumTroops, 0 ); + pGroup = CreateNewEnemyGroupDepartingFromSector( SEC_D9, 0, ubNumTroops, 0, 0 ); AddWaypointToPGroup( pGroup, 9, 5 ); //E9 AddWaypointToPGroup( pGroup, 9, 4 ); //D9 pGroup->ubTransportationMask = TRUCK; ubNumTroops = (UINT8)(3 + gGameOptions.ubDifficultyLevel + Random( 3 )); - pGroup = CreateNewEnemyGroupDepartingFromSector( SEC_B9, 0, ubNumTroops, 0 ); + pGroup = CreateNewEnemyGroupDepartingFromSector( SEC_B9, 0, ubNumTroops, 0, 0 ); AddWaypointToPGroup( pGroup, 12, 2 ); //B12 AddWaypointToPGroup( pGroup, 9, 2 ); //B9 pGroup->ubTransportationMask = FOOT; ubNumTroops = (UINT8)(3 + gGameOptions.ubDifficultyLevel + Random( 3 )); - pGroup = CreateNewEnemyGroupDepartingFromSector( SEC_A14, 0, ubNumTroops, 0 ); + pGroup = CreateNewEnemyGroupDepartingFromSector( SEC_A14, 0, ubNumTroops, 0, 0 ); pGroup->ubMoveType = ENDTOEND_FORWARDS; AddWaypointToPGroup( pGroup, 13, 1 ); //A13 AddWaypointToPGroup( pGroup, 15, 1 ); //A15 @@ -366,13 +366,13 @@ void GeneratePatrolGroups() pGroup->ubTransportationMask = TRACKED; ubNumTroops = (UINT8)(5 + gGameOptions.ubDifficultyLevel * 2 + Random( 4 )); - pGroup = CreateNewEnemyGroupDepartingFromSector( SEC_N6, 0, ubNumTroops, 0 ); + pGroup = CreateNewEnemyGroupDepartingFromSector( SEC_N6, 0, ubNumTroops, 0, 0 ); AddWaypointToPGroup( pGroup, 9, 14 ); //N9 AddWaypointToPGroup( pGroup, 6, 14 ); //N6 pGroup->ubTransportationMask = CAR; ubNumTroops = (UINT8)(5 + gGameOptions.ubDifficultyLevel * 2 + Random( 4 )); - pGroup = CreateNewEnemyGroupDepartingFromSector( SEC_N10, 0, ubNumTroops, 0 ); + pGroup = CreateNewEnemyGroupDepartingFromSector( SEC_N10, 0, ubNumTroops, 0, 0 ); AddWaypointToPGroup( pGroup, 10, 11 ); //K10 AddWaypointToPGroup( pGroup, 10, 14 ); //N10 pGroup->ubTransportationMask = CAR; diff --git a/Strategic/Campaign Types.h b/Strategic/Campaign Types.h index 67fdc3f7..83de0b2a 100644 --- a/Strategic/Campaign Types.h +++ b/Strategic/Campaign Types.h @@ -500,7 +500,10 @@ typedef struct SECTORINFO UINT32 uiTimeAIArtillerywasOrdered; // Flugente: updated every time an artillery strike is ordered from the militia - INT8 bPadding[ 29 ]; + UINT8 ubNumTanks; + UINT8 ubTanksInBattle; + + INT8 bPadding[ 27 ]; }SECTORINFO; @@ -539,7 +542,10 @@ typedef struct UNDERGROUND_SECTORINFO UINT8 uiNumberOfPrisonersOfWar[PRISONER_MAX]; - INT8 bPadding[32]; + UINT8 ubNumTanks; + UINT8 ubTanksInBattle; + + INT8 bPadding[30]; //no padding left! }UNDERGROUND_SECTORINFO; diff --git a/Strategic/Ja25 Strategic Ai.cpp b/Strategic/Ja25 Strategic Ai.cpp index 6b9b0443..303fb3da 100644 --- a/Strategic/Ja25 Strategic Ai.cpp +++ b/Strategic/Ja25 Strategic Ai.cpp @@ -123,16 +123,16 @@ JA25_SECTOR_AI_MANAGER gJa25StrategicAi; BOOLEAN AddEnemiesToInitialSectorH7(); -UINT32 GetNumberOfJA25EnemiesInSector( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ, UINT8 *pNumAdmins, UINT8 *pNumTroops, UINT8 *pNumElites ); -void SetNumberJa25EnemiesInSurfaceSector( INT32 iSectorID, UINT8 ubNumAdmins, UINT8 ubNumTroops, UINT8 ubNumElites ); +UINT32 GetNumberOfJA25EnemiesInSector( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ, UINT8 *pNumAdmins, UINT8 *pNumTroops, UINT8 *pNumElites, UINT8 *pubNumTanks ); +void SetNumberJa25EnemiesInSurfaceSector( INT32 iSectorID, UINT8 ubNumAdmins, UINT8 ubNumTroops, UINT8 ubNumElites, UINT8 ubNumTanks ); -void SetNumberJa25EnemiesInSector( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ, UINT8 ubNumAdmins, UINT8 ubNumTroops, UINT8 ubNumElites ); +void SetNumberJa25EnemiesInSector( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ, UINT8 ubNumAdmins, UINT8 ubNumTroops, UINT8 ubNumElites, UINT8 ubNumTanks ); void InitJa25InitialEnemiesInSector(); void InitJa25UnderGroundSectors(); void InitNumberOfEnemiesInAboveGroundSectors( ); void InitNumberOfEnemiesInUnderGroundSectors( ); void SetNumberOfJa25BloodCatsInSector( INT32 iSectorID, INT8 bNumBloodCats, INT8 bBloodCatPlacements ); -void SetNumberJa25EnemiesInUnderGroundSector( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ, UINT8 ubNumAdmins, UINT8 ubNumTroops, UINT8 ubNumElites ); +void SetNumberJa25EnemiesInUnderGroundSector( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ, UINT8 ubNumAdmins, UINT8 ubNumTroops, UINT8 ubNumElites, UINT8 ubNumTanks ); void ResetJa25SectorProbabilities(); BOOLEAN InitJa25StrategicSectorAI( BOOLEAN fReset ); @@ -152,8 +152,8 @@ void FixEnemyCounterInSectorBug(); void AddEnemiesToFirstTunnelSector(); void AddEnemiesToSecondTunnelSector(); -UINT8 NumEnemiesToAttackFirstTunnelSector( UINT8 *pAdmins, UINT8 *pTroops, UINT8 *pElites ); -UINT8 NumEnemiesToAttackSecondTunnelSector( UINT8 *pAdmins, UINT8 *pTroops, UINT8 *pElites ); +UINT8 NumEnemiesToAttackFirstTunnelSector( UINT8 *pAdmins, UINT8 *pTroops, UINT8 *pElites, UINT8 *pTanks ); +UINT8 NumEnemiesToAttackSecondTunnelSector( UINT8 *pAdmins, UINT8 *pTroops, UINT8 *pElites, UINT8 *pTanks ); void RemoveAllEnemySoldierInitListLinks(); INT16 GetGridNoEnemyWillSeekWhenAttacking( INT8 bSaiSector ); void SetH11NumEnemiesInSector(); @@ -175,7 +175,7 @@ BOOLEAN Ja25BetaDateToInvalidateExe(); -UINT32 GetNumberOfJA25EnemiesInSector( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ, UINT8 *pNumAdmins, UINT8 *pNumTroops, UINT8 *pNumElites ) +UINT32 GetNumberOfJA25EnemiesInSector( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ, UINT8 *pNumAdmins, UINT8 *pNumTroops, UINT8 *pNumElites, UINT8 *pNumTanks ) { SECTORINFO *pSector; @@ -187,6 +187,7 @@ UINT32 GetNumberOfJA25EnemiesInSector( INT16 sSectorX, INT16 sSectorY, INT8 bSec *pNumAdmins = pSector->ubNumAdmins; *pNumTroops = pSector->ubNumTroops; *pNumElites = pSector->ubNumElites; + *pNumTanks = pSector->ubNumTanks; } else { @@ -198,6 +199,7 @@ UINT32 GetNumberOfJA25EnemiesInSector( INT16 sSectorX, INT16 sSectorY, INT8 bSec *pNumAdmins = pSector->ubNumAdmins; *pNumTroops = pSector->ubNumTroops; *pNumElites = pSector->ubNumElites; + *pNumTanks = pSector->ubNumTanks; } } @@ -278,15 +280,17 @@ BOOLEAN AddEnemiesToInitialSectorH7() UINT8 ubNumAdmins; UINT8 ubNumTroops; UINT8 ubNumElites; + UINT8 ubNumTanks; UINT8 ubNumRemovedAdmins=0; UINT8 ubNumRemovedTroops=0; UINT8 ubNumRemovedElites=0; + UINT8 ubNumRemovedTanks=0; ubSector = SECTOR( JA2_5_START_SECTOR_X, JA2_5_START_SECTOR_Y ); //Get the number of enemies in the guard post sector - GetNumberOfJA25EnemiesInSector( 8, MAP_ROW_H, 0, &ubNumAdmins, &ubNumTroops, &ubNumElites ); + GetNumberOfJA25EnemiesInSector( 8, MAP_ROW_H, 0, &ubNumAdmins, &ubNumTroops, &ubNumElites, &ubNumTanks ); //determine the #of enemies to travel to the initial heli sector @@ -299,13 +303,16 @@ BOOLEAN AddEnemiesToInitialSectorH7() if( ubNumElites > 1 ) ubNumRemovedElites = ubNumElites / 3 + + Random( 3 ); + if( ubNumTanks > 1 ) + ubNumRemovedTanks = ubNumTanks / 3 + + Random( 3 ); + //deduct the # that are moving from the # in the guard post sector // SetNumberJa25EnemiesInSurfaceSector( SEC_H8, (UINT8)(ubNumAdmins-ubNumRemovedAdmins), (UINT8)(ubNumTroops-ubNumRemovedTroops), (UINT8)(ubNumElites-ubNumRemovedElites) ); - SetNumberJa25EnemiesInSector( 8, MAP_ROW_H, 0, (UINT8)(ubNumAdmins-ubNumRemovedAdmins), (UINT8)(ubNumTroops-ubNumRemovedTroops), (UINT8)(ubNumElites-ubNumRemovedElites) ); + SetNumberJa25EnemiesInSector( 8, MAP_ROW_H, 0, (UINT8)(ubNumAdmins-ubNumRemovedAdmins), (UINT8)(ubNumTroops-ubNumRemovedTroops), (UINT8)(ubNumElites-ubNumRemovedElites), (UINT8)(ubNumTanks-ubNumRemovedTanks) ); uiWorldMin = GetWorldTotalMin(); - pGroup = CreateNewEnemyGroupDepartingFromSector( ubSector+1, ubNumRemovedAdmins, ubNumRemovedTroops, ubNumRemovedElites ); + pGroup = CreateNewEnemyGroupDepartingFromSector( ubSector+1, ubNumRemovedAdmins, ubNumRemovedTroops, ubNumRemovedElites, ubNumRemovedTanks ); if( pGroup == NULL ) { @@ -396,24 +403,24 @@ void InitJa25UnderGroundSectors() */ } -void SetNumberJa25EnemiesInSector( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ, UINT8 ubNumAdmins, UINT8 ubNumTroops, UINT8 ubNumElites ) +void SetNumberJa25EnemiesInSector( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ, UINT8 ubNumAdmins, UINT8 ubNumTroops, UINT8 ubNumElites, UINT8 ubNumTanks ) { //if its a ground level if( bSectorZ == 0 ) { - SetNumberJa25EnemiesInSurfaceSector( SECTOR( sSectorX, sSectorY ), ubNumAdmins, ubNumTroops, ubNumElites ); + SetNumberJa25EnemiesInSurfaceSector( SECTOR( sSectorX, sSectorY ), ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks ); } //its an underground level else { - SetNumberJa25EnemiesInUnderGroundSector( sSectorX, sSectorY, bSectorZ, ubNumAdmins, ubNumTroops, ubNumElites ); + SetNumberJa25EnemiesInUnderGroundSector( sSectorX, sSectorY, bSectorZ, ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks ); } } -void SetNumberJa25EnemiesInSurfaceSector( INT32 iSectorID, UINT8 ubNumAdmins, UINT8 ubNumTroops, UINT8 ubNumElites ) +void SetNumberJa25EnemiesInSurfaceSector( INT32 iSectorID, UINT8 ubNumAdmins, UINT8 ubNumTroops, UINT8 ubNumElites, UINT8 ubNumTanks ) { SECTORINFO *pSector; @@ -421,6 +428,7 @@ void SetNumberJa25EnemiesInSurfaceSector( INT32 iSectorID, UINT8 ubNumAdmins, UI pSector->ubNumAdmins = ubNumAdmins; pSector->ubNumTroops = ubNumTroops; pSector->ubNumElites = ubNumElites; + pSector->ubNumTanks = ubNumTanks; } void SetNumberOfJa25BloodCatsInSector( INT32 iSectorID, INT8 bNumBloodCats, INT8 bBloodCatPlacements ) @@ -433,7 +441,7 @@ void SetNumberOfJa25BloodCatsInSector( INT32 iSectorID, INT8 bNumBloodCats, INT8 pSector->bBloodCatPlacements = bBloodCatPlacements; } -void SetNumberJa25EnemiesInUnderGroundSector( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ, UINT8 ubNumAdmins, UINT8 ubNumTroops, UINT8 ubNumElites ) +void SetNumberJa25EnemiesInUnderGroundSector( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ, UINT8 ubNumAdmins, UINT8 ubNumTroops, UINT8 ubNumElites, UINT8 ubNumTanks ) { UNDERGROUND_SECTORINFO *pSector=NULL; @@ -444,6 +452,7 @@ void SetNumberJa25EnemiesInUnderGroundSector( INT16 sSectorX, INT16 sSectorY, IN pSector->ubNumAdmins = ubNumAdmins; pSector->ubNumTroops = ubNumTroops; pSector->ubNumElites = ubNumElites; + pSector->ubNumTanks = ubNumTanks; } void InitNumberOfEnemiesInAboveGroundSectors( ) @@ -451,6 +460,7 @@ void InitNumberOfEnemiesInAboveGroundSectors( ) UINT8 ubNumAdmins=0; UINT8 ubNumTroops=0; UINT8 ubNumElites=0; + UINT8 ubNumTanks=0; //H7 { @@ -477,7 +487,7 @@ void InitNumberOfEnemiesInAboveGroundSectors( ) ubNumElites = 0 + Random( 0 ); break; } - SetNumberJa25EnemiesInSurfaceSector( SEC_H7, ubNumAdmins, ubNumTroops, ubNumElites ); + SetNumberJa25EnemiesInSurfaceSector( SEC_H7, ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks ); } @@ -508,7 +518,7 @@ void InitNumberOfEnemiesInAboveGroundSectors( ) break; } - SetNumberJa25EnemiesInSurfaceSector( SEC_H8, ubNumAdmins, ubNumTroops, ubNumElites ); + SetNumberJa25EnemiesInSurfaceSector( SEC_H8, ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks ); } //Guard Post @@ -538,7 +548,7 @@ void InitNumberOfEnemiesInAboveGroundSectors( ) break; } - SetNumberJa25EnemiesInSurfaceSector( SEC_H9, ubNumAdmins, ubNumTroops, ubNumElites ); + SetNumberJa25EnemiesInSurfaceSector( SEC_H9, ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks ); } // SEC_H10: @@ -567,7 +577,7 @@ void InitNumberOfEnemiesInAboveGroundSectors( ) break; } - SetNumberJa25EnemiesInSurfaceSector( SEC_H10, ubNumAdmins, ubNumTroops, ubNumElites ); + SetNumberJa25EnemiesInSurfaceSector( SEC_H10, ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks ); } //SEC_H11 @@ -600,7 +610,7 @@ void InitNumberOfEnemiesInAboveGroundSectors( ) break; } - SetNumberJa25EnemiesInSurfaceSector( SEC_I9, ubNumAdmins, ubNumTroops, ubNumElites ); + SetNumberJa25EnemiesInSurfaceSector( SEC_I9, ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks ); } //First part of town @@ -630,7 +640,7 @@ void InitNumberOfEnemiesInAboveGroundSectors( ) break; } - SetNumberJa25EnemiesInSurfaceSector( SEC_I10, ubNumAdmins, ubNumTroops, ubNumElites ); + SetNumberJa25EnemiesInSurfaceSector( SEC_I10, ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks ); } //Second part of town @@ -660,7 +670,7 @@ void InitNumberOfEnemiesInAboveGroundSectors( ) break; } - SetNumberJa25EnemiesInSurfaceSector( SEC_I11, ubNumAdmins, ubNumTroops, ubNumElites ); + SetNumberJa25EnemiesInSurfaceSector( SEC_I11, ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks ); } //SEC_I12: @@ -689,7 +699,7 @@ void InitNumberOfEnemiesInAboveGroundSectors( ) break; } - SetNumberJa25EnemiesInSurfaceSector( SEC_I12, ubNumAdmins, ubNumTroops, ubNumElites ); + SetNumberJa25EnemiesInSurfaceSector( SEC_I12, ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks ); } //Abandoned mine @@ -719,7 +729,7 @@ void InitNumberOfEnemiesInAboveGroundSectors( ) break; } - SetNumberJa25EnemiesInSurfaceSector( SEC_I13, ubNumAdmins, ubNumTroops, ubNumElites ); + SetNumberJa25EnemiesInSurfaceSector( SEC_I13, ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks ); } // SEC_J11: @@ -748,7 +758,7 @@ void InitNumberOfEnemiesInAboveGroundSectors( ) break; } - SetNumberJa25EnemiesInSurfaceSector( SEC_J11, ubNumAdmins, ubNumTroops, ubNumElites ); + SetNumberJa25EnemiesInSurfaceSector( SEC_J11, ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks ); } // SEC_J12: @@ -777,7 +787,7 @@ void InitNumberOfEnemiesInAboveGroundSectors( ) break; } - SetNumberJa25EnemiesInSurfaceSector( SEC_J12, ubNumAdmins, ubNumTroops, ubNumElites ); + SetNumberJa25EnemiesInSurfaceSector( SEC_J12, ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks ); } //Power Generator, Ground Level @@ -807,7 +817,7 @@ void InitNumberOfEnemiesInAboveGroundSectors( ) break; } - SetNumberJa25EnemiesInSurfaceSector( SEC_J13, ubNumAdmins, ubNumTroops, ubNumElites ); + SetNumberJa25EnemiesInSurfaceSector( SEC_J13, ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks ); } //Complex, Ground Level @@ -837,7 +847,7 @@ void InitNumberOfEnemiesInAboveGroundSectors( ) break; } - SetNumberJa25EnemiesInSurfaceSector( SEC_K15, ubNumAdmins, ubNumTroops, ubNumElites ); + SetNumberJa25EnemiesInSurfaceSector( SEC_K15, ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks ); } } @@ -846,6 +856,7 @@ void InitNumberOfEnemiesInUnderGroundSectors( ) UINT8 ubNumAdmins=0; UINT8 ubNumTroops=0; UINT8 ubNumElites=0; + UINT8 ubNumTanks; //Mine Sector Level 1 switch( gGameOptions.ubDifficultyLevel ) @@ -866,7 +877,7 @@ void InitNumberOfEnemiesInUnderGroundSectors( ) ubNumElites = 0 + Random( 0 ); break; } - SetNumberJa25EnemiesInSector( 13, 9, 1, ubNumAdmins, ubNumTroops, ubNumElites ); + SetNumberJa25EnemiesInSector( 13, 9, 1, ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks ); //Power Generator Level 1 @@ -888,7 +899,7 @@ void InitNumberOfEnemiesInUnderGroundSectors( ) ubNumElites = 0 + Random( 0 ); break; } - SetNumberJa25EnemiesInSector( 13, 10, 1, ubNumAdmins, ubNumTroops, ubNumElites ); + SetNumberJa25EnemiesInSector( 13, 10, 1, ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks ); //Tunnel First Part, Level 1 @@ -910,7 +921,7 @@ void InitNumberOfEnemiesInUnderGroundSectors( ) ubNumElites = 0 + Random( 0 ); break; } - SetNumberJa25EnemiesInSector( 14, 10, 1, ubNumAdmins, ubNumTroops, ubNumElites ); + SetNumberJa25EnemiesInSector( 14, 10, 1, ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks ); //Tunnel Second Part, Level 1 @@ -932,7 +943,7 @@ void InitNumberOfEnemiesInUnderGroundSectors( ) ubNumElites = 0 + Random( 0 ); break; } - SetNumberJa25EnemiesInSector( 14, 11, 1, ubNumAdmins, ubNumTroops, ubNumElites ); + SetNumberJa25EnemiesInSector( 14, 11, 1, ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks ); @@ -955,7 +966,7 @@ void InitNumberOfEnemiesInUnderGroundSectors( ) ubNumElites = 6 + Random( 4 ); break; } - SetNumberJa25EnemiesInSector( 15, 11, 1, ubNumAdmins, ubNumTroops, ubNumElites ); + SetNumberJa25EnemiesInSector( 15, 11, 1, ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks ); //Complex, Level 2, K15 @@ -977,7 +988,7 @@ void InitNumberOfEnemiesInUnderGroundSectors( ) ubNumElites = 10 + Random( 2 ); break; } - SetNumberJa25EnemiesInSector( 15, 11, 2, ubNumAdmins, ubNumTroops, ubNumElites ); + SetNumberJa25EnemiesInSector( 15, 11, 2, ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks ); //Complex, Level 2, L15 @@ -999,7 +1010,7 @@ void InitNumberOfEnemiesInUnderGroundSectors( ) ubNumElites = 14 + Random( 2 ); break; } - SetNumberJa25EnemiesInSector( 15, 12, 2, ubNumAdmins, ubNumTroops, ubNumElites ); + SetNumberJa25EnemiesInSector( 15, 12, 2, ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks ); //Complex, Level 3, L15 @@ -1021,7 +1032,7 @@ void InitNumberOfEnemiesInUnderGroundSectors( ) ubNumElites = 15 + Random( 0 ); break; } - SetNumberJa25EnemiesInSector( 15, 12, 3, ubNumAdmins, ubNumTroops, ubNumElites ); + SetNumberJa25EnemiesInSector( 15, 12, 3, ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks ); } void InitJa25SaveStruct() @@ -1270,7 +1281,7 @@ void HandleAddingEnemiesToTunnelMaps() else if( AreAnyPlayerMercsStillInSector( 14, 10, 1 ) && !AreAnyPlayerMercsStillInSector( 14, 11, 1 ) ) { - ubNumEnemies = NumEnemiesToAttackFirstTunnelSector( NULL, NULL, NULL ); + ubNumEnemies = NumEnemiesToAttackFirstTunnelSector( NULL, NULL, NULL, NULL ); //Add enemies to the first sector HandleAddEnemiesToSectorPlayerIsntIn( JA25_J14_1, ubNumEnemies ); @@ -1284,7 +1295,7 @@ void HandleAddingEnemiesToTunnelMaps() //else if the player is in the second sector else if( AreAnyPlayerMercsStillInSector( 14, 11, 1 ) ) { - ubNumEnemies = NumEnemiesToAttackSecondTunnelSector( NULL, NULL, NULL ); + ubNumEnemies = NumEnemiesToAttackSecondTunnelSector( NULL, NULL, NULL, NULL ); //Add enemies to the first sector HandleAddEnemiesToSectorPlayerIsntIn( JA25_K14_1, ubNumEnemies ); @@ -1313,10 +1324,11 @@ void AddEnemiesToFirstTunnelSector() UINT8 ubNumAdmins=0; UINT8 ubNumTroops=0; UINT8 ubNumElites=0; + UINT8 ubNumTanks=0; - NumEnemiesToAttackFirstTunnelSector( &ubNumAdmins, &ubNumTroops, &ubNumElites ); + NumEnemiesToAttackFirstTunnelSector( &ubNumAdmins, &ubNumTroops, &ubNumElites, &ubNumTanks ); - SetNumberJa25EnemiesInSector( 14, 10, 1, ubNumAdmins, ubNumTroops, ubNumElites ); + SetNumberJa25EnemiesInSector( 14, 10, 1, ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks ); } void AddEnemiesToSecondTunnelSector() @@ -1324,16 +1336,18 @@ void AddEnemiesToSecondTunnelSector() UINT8 ubNumAdmins=0; UINT8 ubNumTroops=0; UINT8 ubNumElites=0; + UINT8 ubNumTanks=0; - NumEnemiesToAttackSecondTunnelSector( &ubNumAdmins, &ubNumTroops, &ubNumElites ); - SetNumberJa25EnemiesInSector( 14, 11, 1, ubNumAdmins, ubNumTroops, ubNumElites ); + NumEnemiesToAttackSecondTunnelSector( &ubNumAdmins, &ubNumTroops, &ubNumElites, &ubNumTanks ); + SetNumberJa25EnemiesInSector( 14, 11, 1, ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks ); } -UINT8 NumEnemiesToAttackFirstTunnelSector( UINT8 *pAdmins, UINT8 *pTroops, UINT8 *pElites ) +UINT8 NumEnemiesToAttackFirstTunnelSector( UINT8 *pAdmins, UINT8 *pTroops, UINT8 *pElites, UINT8 *pTanks ) { UINT8 ubNumAdmins=0; UINT8 ubNumTroops=0; UINT8 ubNumElites=0; + UINT8 ubNumTanks=0; //if the player blew up the fan, add a ton of enemies to the sector //1st Tunnel Sector @@ -1365,14 +1379,18 @@ UINT8 NumEnemiesToAttackFirstTunnelSector( UINT8 *pAdmins, UINT8 *pTroops, UINT8 if( pElites ) *pElites = ubNumElites; - return( ubNumAdmins + ubNumTroops + ubNumElites ); + if( pTanks ) + *pTanks = ubNumTanks; + + return( ubNumAdmins + ubNumTroops + ubNumElites + ubNumTanks ); } -UINT8 NumEnemiesToAttackSecondTunnelSector( UINT8 *pAdmins, UINT8 *pTroops, UINT8 *pElites ) +UINT8 NumEnemiesToAttackSecondTunnelSector( UINT8 *pAdmins, UINT8 *pTroops, UINT8 *pElites, UINT8 *pTanks ) { UINT8 ubNumAdmins=0; UINT8 ubNumTroops=0; UINT8 ubNumElites=0; + UINT8 ubNumTanks=0; //if the player blew up the fan, add a ton of enemies to the sector //1st Tunnel Sector @@ -1402,8 +1420,10 @@ UINT8 NumEnemiesToAttackSecondTunnelSector( UINT8 *pAdmins, UINT8 *pTroops, UINT *pTroops = ubNumTroops; if( pElites ) *pElites = ubNumElites; + if( pTanks ) + *pTanks = ubNumTanks; - return( ubNumAdmins + ubNumTroops + ubNumElites ); + return( ubNumAdmins + ubNumTroops + ubNumElites + ubNumTanks ); } @@ -2166,7 +2186,7 @@ BOOLEAN HandleAddEnemiesToSectorPlayerIsntIn( INT16 sSaiSector, UINT8 ubNumEnemi gubEnemyEncounterCode = ENEMY_INVASION_CODE; } - SetNumberJa25EnemiesInSector( sSectorX, sSectorY, bSectorZ, 0, ubNumEnemies, 0 ); + SetNumberJa25EnemiesInSector( sSectorX, sSectorY, bSectorZ, 0, ubNumEnemies, 0, 0 ); SetThisSectorAsEnemyControlled( sSectorX, sSectorY, bSectorZ, FALSE ); @@ -2211,7 +2231,7 @@ if ( gGameUBOptions.pJA2UB == TRUE ) if( gJa25AiSectorStruct[ sSaiSector ].bSectorZ == 0 ) { - pGroup = CreateNewEnemyGroupDepartingFromSector( sSector, 0, ubNumEnemies, 0 ); + pGroup = CreateNewEnemyGroupDepartingFromSector( sSector, 0, ubNumEnemies, 0, 0 ); if( sGridNo != -1 ) { @@ -2241,7 +2261,7 @@ if ( gGameUBOptions.pJA2UB == TRUE ) Ja25SAI_DetermineWhichLevelToAttackFrom( sSaiSector, &sSector, &bLevel ); //underground, we have to specify - pGroup = CreateNewEnemyGroupDepartingFromSectorUsingZLevel( sSector, bLevel, 0, ubNumEnemies, 0 );//was sSector + pGroup = CreateNewEnemyGroupDepartingFromSectorUsingZLevel( sSector, bLevel, 0, ubNumEnemies, 0, 0 );//was sSector // pGroup->pEnemyGroup->ubTroopsInBattle = ubNumEnemies; } @@ -2802,6 +2822,7 @@ void SetH11NumEnemiesInSector() UINT8 ubNumAdmins=0; UINT8 ubNumTroops=0; UINT8 ubNumElites=0; + UINT8 ubNumTanks=0; // SEC_H11: { @@ -2829,7 +2850,7 @@ void SetH11NumEnemiesInSector() break; } - SetNumberJa25EnemiesInSurfaceSector( SEC_H11, ubNumAdmins, ubNumTroops, ubNumElites ); + SetNumberJa25EnemiesInSurfaceSector( SEC_H11, ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks ); } } diff --git a/Strategic/Ja25 Strategic Ai.h b/Strategic/Ja25 Strategic Ai.h index 193f7d32..5e6b397f 100644 --- a/Strategic/Ja25 Strategic Ai.h +++ b/Strategic/Ja25 Strategic Ai.h @@ -188,12 +188,12 @@ BOOLEAN ShouldEnemiesBeAddedToInitialSector(); void InitJa25StrategicAi(); -extern void SetNumberJa25EnemiesInSector( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ, UINT8 ubNumAdmins, UINT8 ubNumTroops, UINT8 ubNumElites ); +extern void SetNumberJa25EnemiesInSector( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ, UINT8 ubNumAdmins, UINT8 ubNumTroops, UINT8 ubNumElites, UINT8 ubNumTanks ); void InitJa25SaveStruct(); void InitJa25StrategicAiBloodcats( ); -extern void SetNumberJa25EnemiesInSurfaceSector( INT32 iSectorID, UINT8 ubNumAdmins, UINT8 ubNumTroops, UINT8 ubNumElites ); +extern void SetNumberJa25EnemiesInSurfaceSector( INT32 iSectorID, UINT8 ubNumAdmins, UINT8 ubNumTroops, UINT8 ubNumElites, UINT8 ubNumTanks ); BOOLEAN SaveJa25SaveInfoToSaveGame( HWFILE hFile ); BOOLEAN LoadJa25SaveInfoFromSavedGame( HWFILE hFile ); @@ -305,7 +305,7 @@ enum extern BOOLEAN gfEnemyShouldImmediatelySeekThePlayer; //extern INT32 giNumJA25Sectors; -extern void SetNumberJa25EnemiesInSector( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ, UINT8 ubNumAdmins, UINT8 ubNumTroops, UINT8 ubNumElites ); +extern void SetNumberJa25EnemiesInSector( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ, UINT8 ubNumAdmins, UINT8 ubNumTroops, UINT8 ubNumElites, UINT8 ubNumTanks ); void SetJa25SectorOwnedStatus( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ, BOOLEAN fPlayerOwned ); INT8 GetTheFurthestSectorPlayerOwns(); void Ja25_UpdateTimeOfEndOfLastBattle( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ ); @@ -317,7 +317,7 @@ void JA25_HandleUpdateOfStrategicAi(); void SetEnemiesToFindThePlayerMercs(); void HandleSayingDontStayToLongWarningInSectorH8(); -extern void SetNumberJa25EnemiesInSector( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ, UINT8 ubNumAdmins, UINT8 ubNumTroops, UINT8 ubNumElites ); +extern void SetNumberJa25EnemiesInSector( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ, UINT8 ubNumAdmins, UINT8 ubNumTroops, UINT8 ubNumElites, UINT8 ubNumTanks ); #ifdef JA2BETAVERSION BOOLEAN InitJa25StrategicAiDecisions( BOOLEAN fLoadedGame ); diff --git a/Strategic/LuaInitNPCs.cpp b/Strategic/LuaInitNPCs.cpp index 6667c141..e3b07e32 100644 --- a/Strategic/LuaInitNPCs.cpp +++ b/Strategic/LuaInitNPCs.cpp @@ -1996,6 +1996,7 @@ static int l_AddEnemyToUnderGroundSector(lua_State *L) UINT8 ubNumAdmins = lua_tointeger(L,4); UINT8 ubNumTroops = lua_tointeger(L,5); UINT8 ubNumElites = lua_tointeger(L,6); + UINT8 ubNumTanks = lua_tointeger(L,7); UNDERGROUND_SECTORINFO *pSector = FindUnderGroundSector( sSectorX, sSectorY, bLevel ); @@ -2004,6 +2005,7 @@ static int l_AddEnemyToUnderGroundSector(lua_State *L) pSector->ubNumAdmins = ubNumAdmins; pSector->ubNumTroops = ubNumTroops; pSector->ubNumElites = ubNumElites; + pSector->ubNumTanks = ubNumTanks; } } @@ -2191,6 +2193,7 @@ int i; UINT8 ubNumAdmins=0; UINT8 ubNumTroops=0; UINT8 ubNumElites=0; + UINT8 ubNumTanks=0; INT16 sSectorX; INT16 sSectorY; @@ -2202,8 +2205,9 @@ INT16 sSectorY; if (i == 3 ) ubNumAdmins = lua_tointeger(L,i); if (i == 4 ) ubNumTroops = lua_tointeger(L,i); if (i == 5 ) ubNumElites = lua_tointeger(L,i); + if (i == 6 ) ubNumTanks = lua_tointeger(L,i); } - SetNumberJa25EnemiesInSurfaceSector( SECTOR( sSectorX, sSectorY ), ubNumAdmins, ubNumTroops, ubNumElites ); + SetNumberJa25EnemiesInSurfaceSector( SECTOR( sSectorX, sSectorY ), ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks ); return 0; } @@ -4360,7 +4364,8 @@ UINT16 y = -1; UINT16 z = -1; UINT8 TROOPS_ILOSC = 0; UINT8 ELITA_ILOSC = 0; -UINT CREATURE_ILOSC = 0; +UINT8 CREATURE_ILOSC = 0; +UINT8 TANKS_ILOSC = 0; if ( ( x >= 1 || x <= 16 ) && ( y >= 1 || y <= 16 ) ) { @@ -4370,12 +4375,14 @@ UINT CREATURE_ILOSC = 0; TROOPS_ILOSC = lh_getIntegerFromTable(L, "Troops"); ELITA_ILOSC = lh_getIntegerFromTable(L, "Elite"); CREATURE_ILOSC = lh_getIntegerFromTable(L, "Creature"); + TANKS_ILOSC = lh_getIntegerFromTable(L, "Tanks"); //z = lh_getIntegerFromTable(L, "SectorZ"); SectorInfo[ (UINT8)SECTOR( x, y ) ].ubNumTroops = TROOPS_ILOSC; SectorInfo[ (UINT8)SECTOR( x, y ) ].ubNumElites = ELITA_ILOSC; SectorInfo[ (UINT8)SECTOR( x, y ) ].ubNumCreatures = CREATURE_ILOSC; + SectorInfo[ (UINT8)SECTOR( x, y ) ].ubNumTanks = TANKS_ILOSC; } return 0; diff --git a/Strategic/MilitiaSquads.cpp b/Strategic/MilitiaSquads.cpp index 0c58f359..4f1f1dac 100644 --- a/Strategic/MilitiaSquads.cpp +++ b/Strategic/MilitiaSquads.cpp @@ -2689,39 +2689,39 @@ void MobileMilitiaDeserters(INT16 sMapX, INT16 sMapY, BOOLEAN fDeleteEquip, BOOL /////////////////////// // check enemy presence to decide if mobiles are threatened and some will desert. // Note: cant use NumEnemiesInFiveSectors() as it does not work for omerta or when reinforcements are deactivated, also it uses generateDirectionInfo(), which is used for militia movement. - UINT8 eAdmins = 0, eTroops = 0, eElites = 0; + UINT8 eAdmins = 0, eTroops = 0, eElites = 0, eTanks = 0; //enemies in current sector - GetNumberOfEnemiesInSector( sMapX, sMapY, &eAdmins, &eTroops, &eElites ); + GetNumberOfEnemiesInSector( sMapX, sMapY, &eAdmins, &eTroops, &eElites, &eTanks ); if ( (eAdmins > 0) || (eTroops > 0) ||(eElites > 0) ) enemiesNear = TRUE; if ( ( sMapX > MINIMUM_VALID_X_COORDINATE ) && !enemiesNear ) { //left side - GetNumberOfEnemiesInSector( sMapX - 1, sMapY, &eAdmins, &eTroops, &eElites ); - if ( (eAdmins > 0) || (eTroops > 0) ||(eElites > 0) ) + GetNumberOfEnemiesInSector( sMapX - 1, sMapY, &eAdmins, &eTroops, &eElites, &eTanks ); + if ( (eAdmins > 0) || (eTroops > 0) ||(eElites > 0) || (eTanks > 0) ) enemiesNear = TRUE; } if ( ( sMapX < MAXIMUM_VALID_X_COORDINATE ) && !enemiesNear) { //right side - GetNumberOfEnemiesInSector( sMapX + 1, sMapY, &eAdmins, &eTroops, &eElites ); - if ( (eAdmins > 0) || (eTroops > 0) ||(eElites > 0) ) + GetNumberOfEnemiesInSector( sMapX + 1, sMapY, &eAdmins, &eTroops, &eElites, &eTanks ); + if ( (eAdmins > 0) || (eTroops > 0) ||(eElites > 0) || (eTanks > 0) ) enemiesNear = TRUE; } if ( ( sMapY > MINIMUM_VALID_Y_COORDINATE ) && !enemiesNear ) { //top side - GetNumberOfEnemiesInSector( sMapX, sMapY - 1, &eAdmins, &eTroops, &eElites ); - if ( (eAdmins > 0) || (eTroops > 0) ||(eElites > 0) ) + GetNumberOfEnemiesInSector( sMapX, sMapY - 1, &eAdmins, &eTroops, &eElites, &eTanks ); + if ( (eAdmins > 0) || (eTroops > 0) ||(eElites > 0) || (eTanks > 0) ) enemiesNear = TRUE; } if ( ( sMapY < MAXIMUM_VALID_Y_COORDINATE ) && !enemiesNear) { //bottom side - GetNumberOfEnemiesInSector( sMapX, sMapY + 1, &eAdmins, &eTroops, &eElites ); - if ( (eAdmins > 0) || (eTroops > 0) ||(eElites > 0) ) + GetNumberOfEnemiesInSector( sMapX, sMapY + 1, &eAdmins, &eTroops, &eElites, &eTanks ); + if ( (eAdmins > 0) || (eTroops > 0) ||(eElites > 0) || (eTanks > 0) ) enemiesNear = TRUE; } diff --git a/Strategic/PreBattle Interface.cpp b/Strategic/PreBattle Interface.cpp index 621549c8..0c92d105 100644 --- a/Strategic/PreBattle Interface.cpp +++ b/Strategic/PreBattle Interface.cpp @@ -221,12 +221,13 @@ void ValidateAndCorrectInBattleCounters( GROUP *pLocGroup ) { if( pGroup->ubSectorX == pLocGroup->ubSectorX && pGroup->ubSectorY == pLocGroup->ubSectorY ) { - if( pGroup->pEnemyGroup->ubAdminsInBattle || pGroup->pEnemyGroup->ubTroopsInBattle || pGroup->pEnemyGroup->ubElitesInBattle ) + if( pGroup->pEnemyGroup->ubAdminsInBattle || pGroup->pEnemyGroup->ubTroopsInBattle || pGroup->pEnemyGroup->ubElitesInBattle || pGroup->pEnemyGroup->ubTanksInBattle ) { ubInvalidGroups++; pGroup->pEnemyGroup->ubAdminsInBattle = 0; pGroup->pEnemyGroup->ubTroopsInBattle = 0; pGroup->pEnemyGroup->ubElitesInBattle = 0; + pGroup->pEnemyGroup->ubTanksInBattle = 0; } } } @@ -244,17 +245,19 @@ void ValidateAndCorrectInBattleCounters( GROUP *pLocGroup ) L"If you can provide information on how a previous battle was resolved here or nearby patrol " L"(auto resolve, tactical battle, cheat keys, or retreat)," L"please forward that info (no data files necessary) as well as the following code (very important): " - L"G(%02d:%c%d_b%d) A(%02d:%02d) T(%02d:%02d) E(%02d:%02d) C(%02d:%02d)", + L"G(%02d:%c%d_b%d) A(%02d:%02d) T(%02d:%02d) E(%02d:%02d) C(%02d:%02d) Ta(%02d:%02d)", ubInvalidGroups, pLocGroup->ubSectorY + 'A' - 1, pLocGroup->ubSectorX, pLocGroup->ubSectorZ, pSector->ubNumAdmins, pSector->ubAdminsInBattle, pSector->ubNumTroops, pSector->ubTroopsInBattle, pSector->ubNumElites, pSector->ubElitesInBattle, - pSector->ubNumCreatures, pSector->ubCreaturesInBattle ); + pSector->ubNumCreatures, pSector->ubCreaturesInBattle, + pSector->ubNumTanks, pSector->ubTanksInBattle ); DoScreenIndependantMessageBox( str, MSG_BOX_FLAG_OK, NULL ); pSector->ubAdminsInBattle = 0; pSector->ubTroopsInBattle = 0; pSector->ubElitesInBattle = 0; pSector->ubCreaturesInBattle = 0; + pSector->ubTanksInBattle = 0; } } #endif diff --git a/Strategic/Queen Command.cpp b/Strategic/Queen Command.cpp index d49a8d74..e7d61455 100644 --- a/Strategic/Queen Command.cpp +++ b/Strategic/Queen Command.cpp @@ -161,7 +161,7 @@ UINT8 NumHostilesInSector( INT16 sSectorX, INT16 sSectorY, INT16 sSectorZ ) pSector = FindUnderGroundSector( sSectorX, sSectorY, (UINT8)sSectorZ ); if( pSector ) { - ubNumHostiles = (UINT8)(pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumCreatures); + ubNumHostiles = (UINT8)(pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumCreatures + pSector->ubNumTanks); } } else @@ -171,7 +171,7 @@ UINT8 NumHostilesInSector( INT16 sSectorX, INT16 sSectorY, INT16 sSectorZ ) //Count stationary hostiles pSector = &SectorInfo[ SECTOR( sSectorX, sSectorY ) ]; - ubNumHostiles = (UINT8)(pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumCreatures); + ubNumHostiles = (UINT8)(pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumCreatures + pSector->ubNumTanks); //Count mobile enemies pGroup = gpGroupList; @@ -205,7 +205,7 @@ UINT8 NumEnemiesInAnySector( INT16 sSectorX, INT16 sSectorY, INT16 sSectorZ ) pSector = FindUnderGroundSector( sSectorX, sSectorY, (UINT8)sSectorZ ); if( pSector ) { - ubNumEnemies = (UINT8)(pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites); + ubNumEnemies = (UINT8)(pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumTanks); } } else @@ -215,7 +215,7 @@ UINT8 NumEnemiesInAnySector( INT16 sSectorX, INT16 sSectorY, INT16 sSectorZ ) //Count stationary enemies pSector = &SectorInfo[ SECTOR( sSectorX, sSectorY ) ]; - ubNumEnemies = (UINT8)(pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites); + ubNumEnemies = (UINT8)(pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumTanks); //Count mobile enemies pGroup = gpGroupList; @@ -254,7 +254,7 @@ UINT8 NumEnemiesInSector( INT16 sSectorX, INT16 sSectorY ) AssertLE( sSectorY, MAXIMUM_VALID_Y_COORDINATE ); pSector = &SectorInfo[ SECTOR( sSectorX, sSectorY ) ]; - ubNumTroops = (UINT8)(pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites); + ubNumTroops = (UINT8)(pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumTanks); if (is_networked) ubNumTroops += numenemyLAN((UINT8)sSectorX,(UINT8)sSectorY ); //hayden @@ -295,7 +295,7 @@ UINT8 NumStationaryEnemiesInSector( INT16 sSectorX, INT16 sSectorY ) return( 0 ); } - return (UINT8)(pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites); + return (UINT8)(pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumTanks); } UINT8 NumMobileEnemiesInSector( INT16 sSectorX, INT16 sSectorY ) @@ -322,13 +322,13 @@ UINT8 NumMobileEnemiesInSector( INT16 sSectorX, INT16 sSectorY ) 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); + ubNumTroops += (UINT8)(pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumTanks); } return ubNumTroops; } -void GetNumberOfMobileEnemiesInSector( INT16 sSectorX, INT16 sSectorY, UINT8 *pubNumAdmins, UINT8 *pubNumTroops, UINT8 *pubNumElites ) +void GetNumberOfMobileEnemiesInSector( INT16 sSectorX, INT16 sSectorY, UINT8 *pubNumAdmins, UINT8 *pubNumTroops, UINT8 *pubNumElites, UINT8 *pubNumTanks ) { GROUP *pGroup; SECTORINFO *pSector; @@ -338,7 +338,7 @@ void GetNumberOfMobileEnemiesInSector( INT16 sSectorX, INT16 sSectorY, UINT8 *pu AssertLE( sSectorY, MAXIMUM_VALID_Y_COORDINATE ); //Now count the number of mobile groups in the sector. - *pubNumTroops = *pubNumElites = *pubNumAdmins = 0; + *pubNumTroops = *pubNumElites = *pubNumAdmins = *pubNumTanks = 0; pGroup = gpGroupList; while( pGroup ) { @@ -347,6 +347,7 @@ void GetNumberOfMobileEnemiesInSector( INT16 sSectorX, INT16 sSectorY, UINT8 *pu *pubNumTroops += pGroup->pEnemyGroup->ubNumTroops; *pubNumElites += pGroup->pEnemyGroup->ubNumElites; *pubNumAdmins += pGroup->pEnemyGroup->ubNumAdmins; + *pubNumTanks += pGroup->pEnemyGroup->ubNumTanks; } pGroup = pGroup->next; } @@ -357,11 +358,12 @@ void GetNumberOfMobileEnemiesInSector( INT16 sSectorX, INT16 sSectorY, UINT8 *pu *pubNumAdmins += pSector->ubNumAdmins; *pubNumTroops += pSector->ubNumTroops; *pubNumElites += pSector->ubNumElites; + *pubNumTanks += pSector->ubNumTanks; } } -void GetNumberOfMobileEnemiesInSectorWithoutRoadBlock( INT16 sSectorX, INT16 sSectorY, UINT8 *pubNumAdmins, UINT8 *pubNumTroops, UINT8 *pubNumElites ) +void GetNumberOfMobileEnemiesInSectorWithoutRoadBlock( INT16 sSectorX, INT16 sSectorY, UINT8 *pubNumAdmins, UINT8 *pubNumTroops, UINT8 *pubNumElites, UINT8 *pubNumTanks ) { GROUP *pGroup; AssertGE( sSectorX, MINIMUM_VALID_X_COORDINATE); @@ -370,7 +372,7 @@ void GetNumberOfMobileEnemiesInSectorWithoutRoadBlock( INT16 sSectorX, INT16 sSe AssertLE( sSectorY, MAXIMUM_VALID_Y_COORDINATE ); //Now count the number of mobile groups in the sector. - *pubNumTroops = *pubNumElites = *pubNumAdmins = 0; + *pubNumTroops = *pubNumElites = *pubNumAdmins = *pubNumTanks = 0; pGroup = gpGroupList; while( pGroup ) { @@ -379,13 +381,14 @@ void GetNumberOfMobileEnemiesInSectorWithoutRoadBlock( INT16 sSectorX, INT16 sSe *pubNumTroops += pGroup->pEnemyGroup->ubNumTroops; *pubNumElites += pGroup->pEnemyGroup->ubNumElites; *pubNumAdmins += pGroup->pEnemyGroup->ubNumAdmins; + *pubNumTanks += pGroup->pEnemyGroup->ubNumTanks; } pGroup = pGroup->next; } } -void GetNumberOfStationaryEnemiesInSector( INT16 sSectorX, INT16 sSectorY, UINT8 *pubNumAdmins, UINT8 *pubNumTroops, UINT8 *pubNumElites ) +void GetNumberOfStationaryEnemiesInSector( INT16 sSectorX, INT16 sSectorY, UINT8 *pubNumAdmins, UINT8 *pubNumTroops, UINT8 *pubNumElites, UINT8 *pubNumTanks ) { SECTORINFO *pSector; AssertGE( sSectorX, MINIMUM_VALID_X_COORDINATE); @@ -398,19 +401,21 @@ void GetNumberOfStationaryEnemiesInSector( INT16 sSectorX, INT16 sSectorY, UINT8 *pubNumAdmins = pSector->ubNumAdmins; *pubNumTroops = pSector->ubNumTroops; *pubNumElites = pSector->ubNumElites; + *pubNumTanks = pSector->ubNumTanks; } -void GetNumberOfEnemiesInSector( INT16 sSectorX, INT16 sSectorY, UINT8 *pubNumAdmins, UINT8 *pubNumTroops, UINT8 *pubNumElites ) +void GetNumberOfEnemiesInSector( INT16 sSectorX, INT16 sSectorY, UINT8 *pubNumAdmins, UINT8 *pubNumTroops, UINT8 *pubNumElites, UINT8 *pubNumTanks ) { - UINT8 ubNumAdmins, ubNumTroops, ubNumElites; + UINT8 ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks; - GetNumberOfStationaryEnemiesInSector( sSectorX, sSectorY, pubNumAdmins, pubNumTroops, pubNumElites ); + GetNumberOfStationaryEnemiesInSector( sSectorX, sSectorY, pubNumAdmins, pubNumTroops, pubNumElites, pubNumTanks ); - GetNumberOfMobileEnemiesInSector( sSectorX, sSectorY, &ubNumAdmins, &ubNumTroops, &ubNumElites ); + GetNumberOfMobileEnemiesInSector( sSectorX, sSectorY, &ubNumAdmins, &ubNumTroops, &ubNumElites, &ubNumTanks ); *pubNumAdmins += ubNumAdmins; *pubNumTroops += ubNumTroops; *pubNumElites += ubNumElites; + *pubNumTanks += ubNumTanks; } void EndTacticalBattleForEnemy() @@ -426,6 +431,7 @@ void EndTacticalBattleForEnemy() pSector->ubAdminsInBattle = 0; pSector->ubTroopsInBattle = 0; pSector->ubElitesInBattle = 0; + pSector->ubTanksInBattle = 0; } else if( !gbWorldSectorZ ) { @@ -435,6 +441,7 @@ void EndTacticalBattleForEnemy() pSector->ubAdminsInBattle = 0; pSector->ubTroopsInBattle = 0; pSector->ubElitesInBattle = 0; + pSector->ubTanksInBattle = 0; pSector->ubNumCreatures = 0; pSector->ubCreaturesInBattle = 0; } @@ -453,6 +460,7 @@ void EndTacticalBattleForEnemy() pGroup->pEnemyGroup->ubTroopsInBattle = 0; pGroup->pEnemyGroup->ubElitesInBattle = 0; pGroup->pEnemyGroup->ubAdminsInBattle = 0; + pGroup->pEnemyGroup->ubTanksInBattle = 0; } pGroup = pGroup->next; } @@ -502,8 +510,8 @@ BOOLEAN PrepareEnemyForSectorBattle() SECTORINFO *pSector; GROUP *pGroup; SOLDIERTYPE *pSoldier; - unsigned ubNumAdmins, ubNumTroops, ubNumElites; - unsigned ubTotalAdmins, ubTotalElites, ubTotalTroops; + unsigned ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks; + unsigned ubTotalAdmins, ubTotalElites, ubTotalTroops, ubTotalTanks; unsigned totalCountOfStationaryEnemies = 0; unsigned totalCountOfMobileEnemies = 0; int sNumSlots; @@ -557,7 +565,8 @@ BOOLEAN PrepareEnemyForSectorBattle() pGroup->ubSectorY == gpBattleGroup->ubSectorY && !pGroup->pEnemyGroup->ubAdminsInBattle && !pGroup->pEnemyGroup->ubTroopsInBattle && - !pGroup->pEnemyGroup->ubElitesInBattle ) + !pGroup->pEnemyGroup->ubElitesInBattle && + !pGroup->pEnemyGroup->ubTanksInBattle) { HandleArrivalOfReinforcements( pGroup ); } @@ -592,11 +601,12 @@ BOOLEAN PrepareEnemyForSectorBattle() // OJW - 20090403 - override max ai in co-op if (is_networked && is_server && gMaxEnemiesEnabled == 1) { - float totalEnemies = (float)(pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites); + float totalEnemies = (float)(pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumTanks); ubTotalAdmins = (unsigned int)(((float)pSector->ubNumAdmins / totalEnemies) * mapMaximumNumberOfEnemies); ubTotalTroops = (unsigned int)(((float)pSector->ubNumTroops / totalEnemies) * mapMaximumNumberOfEnemies); ubTotalElites = (unsigned int)(((float)pSector->ubNumElites / totalEnemies) * mapMaximumNumberOfEnemies); - totalEnemies = (float)(ubTotalAdmins + ubTotalTroops + ubTotalElites); + ubTotalTanks = (unsigned int)(((float)pSector->ubNumTanks / totalEnemies) * mapMaximumNumberOfEnemies); + totalEnemies = (float)(ubTotalAdmins + ubTotalTroops + ubTotalElites + ubTotalTanks); // take care of any rounding losses while (totalEnemies < mapMaximumNumberOfEnemies) @@ -609,9 +619,11 @@ BOOLEAN PrepareEnemyForSectorBattle() pSector->ubNumAdmins = ubTotalAdmins; pSector->ubNumTroops = ubTotalTroops; pSector->ubNumElites = ubTotalElites; + pSector->ubNumTanks = ubTotalTanks; pSector->ubAdminsInBattle = 0; pSector->ubTroopsInBattle = 0; pSector->ubElitesInBattle = 0; + pSector->ubTanksInBattle = 0; } else { @@ -636,19 +648,22 @@ BOOLEAN PrepareEnemyForSectorBattle() pSector->ubNumAdmins = ubTotalAdmins; pSector->ubNumTroops = ubTotalTroops; pSector->ubNumElites = ubTotalElites; + pSector->ubNumTanks = ubTotalTanks; pSector->ubAdminsInBattle = 0; pSector->ubTroopsInBattle = 0; pSector->ubElitesInBattle = 0; + pSector->ubTanksInBattle = 0; } else { ubTotalAdmins = pSector->ubNumAdmins - pSector->ubAdminsInBattle; ubTotalTroops = pSector->ubNumTroops - pSector->ubTroopsInBattle; ubTotalElites = pSector->ubNumElites - pSector->ubElitesInBattle; + ubTotalTanks = pSector->ubNumTanks - pSector->ubTanksInBattle; } } - totalCountOfStationaryEnemies = ubTotalAdmins + ubTotalTroops + ubTotalElites; + totalCountOfStationaryEnemies = ubTotalAdmins + ubTotalTroops + ubTotalElites + ubTotalTanks; if( totalCountOfStationaryEnemies > mapMaximumNumberOfEnemies ) { @@ -662,19 +677,21 @@ BOOLEAN PrepareEnemyForSectorBattle() ubTotalAdmins = min( mapMaximumNumberOfEnemies, ubTotalAdmins ); ubTotalTroops = min( mapMaximumNumberOfEnemies-ubTotalAdmins, ubTotalTroops ); ubTotalElites = min( mapMaximumNumberOfEnemies-ubTotalAdmins-ubTotalTroops, ubTotalElites ); + ubTotalTanks = min( mapMaximumNumberOfEnemies-ubTotalAdmins-ubTotalTroops-ubTotalElites, ubTotalTanks ); } pSector->ubAdminsInBattle += ubTotalAdmins; pSector->ubTroopsInBattle += ubTotalTroops; pSector->ubElitesInBattle += ubTotalElites; + pSector->ubTanksInBattle += ubTotalTanks; #ifdef JA2TESTVERSION if( gfOverrideSector ) { //if there are no troops in the current groups, then we're done. - if( !ubTotalAdmins && !ubTotalTroops && !ubTotalElites ) + if( !ubTotalAdmins && !ubTotalTroops && !ubTotalElites && !ubTotalTanks ) return FALSE; - AddSoldierInitListEnemyDefenceSoldiers( ubTotalAdmins, ubTotalTroops, ubTotalElites ); + AddSoldierInitListEnemyDefenceSoldiers( ubTotalAdmins, ubTotalTroops, ubTotalElites, ubTotalTanks ); ValidateEnemiesHaveWeapons(); return TRUE; } @@ -701,7 +718,7 @@ BOOLEAN PrepareEnemyForSectorBattle() //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; + sNumSlots -= ubTotalAdmins + ubTotalTroops + ubTotalElites + ubTotalTanks; //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 @@ -756,6 +773,20 @@ BOOLEAN PrepareEnemyForSectorBattle() 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; + gfPendingEnemies = TRUE; + } + pGroup->pEnemyGroup->ubTanksInBattle += ubNumTanks; + ubTotalTanks += ubNumTanks; + } //NOTE: //no provisions for profile troop leader or retreat groups yet. } @@ -777,12 +808,12 @@ BOOLEAN PrepareEnemyForSectorBattle() } //if there are no troops in the current groups, then we're done. - if( !ubTotalAdmins && !ubTotalTroops && !ubTotalElites ) + if( !ubTotalAdmins && !ubTotalTroops && !ubTotalElites && !ubTotalTanks ) { return FALSE; } - AddSoldierInitListEnemyDefenceSoldiers( ubTotalAdmins, ubTotalTroops, ubTotalElites ); + AddSoldierInitListEnemyDefenceSoldiers( ubTotalAdmins, ubTotalTroops, ubTotalElites, ubTotalTanks ); //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 @@ -797,7 +828,8 @@ BOOLEAN PrepareEnemyForSectorBattle() ubNumAdmins = pGroup->pEnemyGroup->ubAdminsInBattle; ubNumTroops = pGroup->pEnemyGroup->ubTroopsInBattle; ubNumElites = pGroup->pEnemyGroup->ubElitesInBattle; - unsigned num = ubNumAdmins + ubNumTroops + ubNumElites; + ubNumTanks = pGroup->pEnemyGroup->ubTanksInBattle; + unsigned num = ubNumAdmins + ubNumTroops + ubNumElites + ubNumTanks; unsigned firstSlot = gTacticalStatus.Team[ ENEMY_TEAM ].bFirstID; unsigned lastSlot = gTacticalStatus.Team[ ENEMY_TEAM ].bLastID; @@ -863,12 +895,22 @@ BOOLEAN PrepareEnemyForSectorBattle() } } break; + case SOLDIER_CLASS_TANK: + if( ubNumTanks ) + { + num--; + sNumSlots--; + ubNumTanks--; + pSoldier->ubGroupID = pGroup->ubGroupID; + } + break; } } AssertEQ( ubNumElites , 0); AssertEQ( ubNumTroops , 0); AssertEQ( ubNumAdmins , 0); + AssertEQ( ubNumTanks , 0); AssertEQ( num , 0); } pGroup = pGroup->next; @@ -882,7 +924,7 @@ BOOLEAN PrepareEnemyForSectorBattle() BOOLEAN PrepareEnemyForUndergroundBattle() { UNDERGROUND_SECTORINFO *pUnderground; - unsigned ubTotalAdmins, ubTotalTroops, ubTotalElites; + unsigned ubTotalAdmins, ubTotalTroops, ubTotalElites, ubTotalTanks; pUnderground = gpUndergroundSectorInfoHead; while( pUnderground ) @@ -896,13 +938,15 @@ BOOLEAN PrepareEnemyForUndergroundBattle() ubTotalAdmins = (UINT8)(pUnderground->ubNumAdmins - pUnderground->ubAdminsInBattle); ubTotalTroops = (UINT8)(pUnderground->ubNumTroops - pUnderground->ubTroopsInBattle); ubTotalElites = (UINT8)(pUnderground->ubNumElites - pUnderground->ubElitesInBattle); + ubTotalTanks = (UINT8)(pUnderground->ubNumTanks - pUnderground->ubTanksInBattle); pUnderground->ubAdminsInBattle += ubTotalAdmins; pUnderground->ubTroopsInBattle += ubTotalTroops; pUnderground->ubElitesInBattle += ubTotalElites; - AddSoldierInitListEnemyDefenceSoldiers( pUnderground->ubNumAdmins, pUnderground->ubNumTroops, pUnderground->ubNumElites ); + pUnderground->ubTanksInBattle += ubTotalTanks; + AddSoldierInitListEnemyDefenceSoldiers( pUnderground->ubNumAdmins, pUnderground->ubNumTroops, pUnderground->ubNumElites, pUnderground->ubNumTanks ); ValidateEnemiesHaveWeapons(); } - return ( ( BOOLEAN) ( pUnderground->ubNumAdmins + pUnderground->ubNumTroops + pUnderground->ubNumElites > 0 ) ); + return ( ( BOOLEAN) ( pUnderground->ubNumAdmins + pUnderground->ubNumTroops + pUnderground->ubNumElites + pUnderground->ubNumTanks > 0 ) ); } pUnderground = pUnderground->next; } @@ -990,6 +1034,34 @@ void ProcessQueenCmdImplicationsOfDeath( SOLDIERTYPE *pSoldier ) } } 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; } if( pSoldier->aiData.bNeutral || pSoldier->bTeam != ENEMY_TEAM && pSoldier->bTeam != CREATURE_TEAM ) @@ -1130,7 +1202,7 @@ void ProcessQueenCmdImplicationsOfDeath( SOLDIERTYPE *pSoldier ) // } #ifdef JA2BETAVERSION - ubTotalEnemies = pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites; + ubTotalEnemies = pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumTanks; #endif switch( pSoldier->ubSoldierClass ) @@ -1243,7 +1315,7 @@ void ProcessQueenCmdImplicationsOfDeath( SOLDIERTYPE *pSoldier ) { //basement level (UNDERGROUND_SECTORINFO) UNDERGROUND_SECTORINFO *pSector = FindUnderGroundSector( gWorldSectorX, gWorldSectorY, gbWorldSectorZ ); #ifdef JA2BETAVERSION - UINT32 ubTotalEnemies = pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites; + UINT32 ubTotalEnemies = pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumTanks; #endif if( pSector ) { @@ -1387,7 +1459,7 @@ void AddPossiblePendingEnemiesToBattle() #endif UINT8 ubSlots, ubNumAvailable; - UINT8 ubNumElites, ubNumTroops, ubNumAdmins; + UINT8 ubNumElites, ubNumTroops, ubNumAdmins, ubNumTanks; UINT8 ubNumGroupsInSector; UINT8 ubGroupIndex; GROUP *pGroup; @@ -1473,11 +1545,11 @@ void AddPossiblePendingEnemiesToBattle() //return; } - if( pSector->ubNumElites + pSector->ubNumTroops + pSector->ubNumAdmins ) + if( pSector->ubNumElites + pSector->ubNumTroops + pSector->ubNumAdmins + pSector->ubNumTanks ) { - ubNumElites = ubNumTroops = ubNumAdmins = 0; + ubNumElites = ubNumTroops = ubNumAdmins = ubNumTanks = 0; - ubNumAvailable = pSector->ubNumElites + pSector->ubNumTroops + pSector->ubNumAdmins - pSector->ubElitesInBattle - pSector->ubTroopsInBattle - pSector->ubAdminsInBattle; + ubNumAvailable = pSector->ubNumElites + pSector->ubNumTroops + pSector->ubNumAdmins + pSector->ubNumTanks - pSector->ubElitesInBattle - pSector->ubTroopsInBattle - pSector->ubAdminsInBattle - pSector->ubTanksInBattle; while( ubNumAvailable && ubSlots ) { // So they just magically appear out of nowhere from the edge? @@ -1504,6 +1576,13 @@ void AddPossiblePendingEnemiesToBattle() ubSlots--; ubNumAdmins++; } + else if( pSector->ubTanksInBattle < pSector->ubNumTanks ) + { //Add a tank + pSector->ubTanksInBattle++; + ubNumAvailable--; + ubSlots--; + ubNumTanks++; + } else { AssertMsg( 0, "AddPossiblePendingEnemiesToBattle(): Logic Error -- by Kris" ); @@ -1511,7 +1590,7 @@ void AddPossiblePendingEnemiesToBattle() } - if( ubNumAdmins || ubNumTroops || ubNumElites ) + if( ubNumAdmins || ubNumTroops || ubNumElites || ubNumTanks ) { //This group has contributed forces, then add them now, because different //groups appear on different sides of the map. UINT8 ubStrategicInsertionCode = ubPredefinedInsertionCode; @@ -1552,7 +1631,7 @@ void AddPossiblePendingEnemiesToBattle() if( ubStrategicInsertionCode < INSERTION_CODE_NORTH ||ubStrategicInsertionCode > INSERTION_CODE_WEST ) ubStrategicInsertionCode = INSERTION_CODE_NORTH + Random( 4 ); - AddEnemiesToBattle( 0, ubStrategicInsertionCode, ubNumAdmins, ubNumTroops, ubNumElites, FALSE ); + AddEnemiesToBattle( 0, ubStrategicInsertionCode, ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks, FALSE ); gfPendingEnemies = TRUE; } } @@ -1582,7 +1661,7 @@ void AddPossiblePendingEnemiesToBattle() pGroup = pGroupInSectorList[ ubGroupIndex]; // Flugente fix: check for underflow... - UINT8 currentgroupsize = pGroup->pEnemyGroup->ubElitesInBattle + pGroup->pEnemyGroup->ubTroopsInBattle + pGroup->pEnemyGroup->ubAdminsInBattle; + UINT8 currentgroupsize = pGroup->pEnemyGroup->ubElitesInBattle + pGroup->pEnemyGroup->ubTroopsInBattle + pGroup->pEnemyGroup->ubAdminsInBattle + pGroup->pEnemyGroup->ubTanksInBattle; if ( currentgroupsize > pGroup->ubGroupSize ) ubNumAvailable = 0; else @@ -1643,19 +1722,25 @@ void AddPossiblePendingEnemiesToBattle() { //Add an elite troop pGroup->pEnemyGroup->ubElitesInBattle++; ubSlots--; - AddEnemiesToBattle( pGroup, ubInsertionCode, 0, 0, 1, FALSE ); + AddEnemiesToBattle( pGroup, ubInsertionCode, 0, 0, 1, 0, FALSE ); } else if( pGroup->pEnemyGroup->ubTroopsInBattle < pGroup->pEnemyGroup->ubNumTroops ) { //Add a regular troop. pGroup->pEnemyGroup->ubTroopsInBattle++; ubSlots--; - AddEnemiesToBattle( pGroup, ubInsertionCode, 0, 1, 0, FALSE ); + AddEnemiesToBattle( pGroup, ubInsertionCode, 0, 1, 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, FALSE ); + AddEnemiesToBattle( pGroup, ubInsertionCode, 1, 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, FALSE ); } else { @@ -1664,7 +1749,7 @@ void AddPossiblePendingEnemiesToBattle() pGroup->pEnemyGroup->ubTroopsInBattle++; ubSlots--; - AddEnemiesToBattle( pGroup, ubInsertionCode, 0, 1, 0, FALSE ); + AddEnemiesToBattle( pGroup, ubInsertionCode, 0, 1, 0, 0, FALSE ); } } @@ -1733,7 +1818,7 @@ void NotifyPlayersOfNewEnemies() } } -void AddEnemiesToBattle( GROUP *pGroup, UINT8 ubStrategicInsertionCode, UINT8 ubNumAdmins, UINT8 ubNumTroops, UINT8 ubNumElites, BOOLEAN fMagicallyAppeared ) +void AddEnemiesToBattle( GROUP *pGroup, UINT8 ubStrategicInsertionCode, UINT8 ubNumAdmins, UINT8 ubNumTroops, UINT8 ubNumElites, UINT8 ubNumTanks, BOOLEAN fMagicallyAppeared ) { SOLDIERTYPE *pSoldier; MAPEDGEPOINTINFO MapEdgepointInfo; @@ -1768,6 +1853,8 @@ void AddEnemiesToBattle( GROUP *pGroup, UINT8 ubStrategicInsertionCode, UINT8 ub pSector->ubTroopsInBattle += ubNumTroops; pSector->ubNumElites += ubNumElites; pSector->ubElitesInBattle += ubNumElites; + pSector->ubNumTanks += ubNumTanks; + pSector->ubTanksInBattle += ubNumTanks; } else { @@ -1780,13 +1867,15 @@ void AddEnemiesToBattle( GROUP *pGroup, UINT8 ubStrategicInsertionCode, UINT8 ub pSector->ubTroopsInBattle += ubNumTroops; pSector->ubNumElites += ubNumElites; pSector->ubElitesInBattle += ubNumElites; + pSector->ubNumTanks += ubNumTanks; + pSector->ubTanksInBattle += ubNumTanks; } } //Because the enemies magically appeared, have one of our soldiers say something... NotifyPlayersOfNewEnemies(); } - ubTotalSoldiers = ubNumAdmins + ubNumTroops + ubNumElites; + ubTotalSoldiers = ubNumAdmins + ubNumTroops + ubNumElites + ubNumTanks; #ifdef JA2UB if( gsGridNoForMapEdgePointInfo != -1 ) @@ -1814,10 +1903,10 @@ void AddEnemiesToBattle( GROUP *pGroup, UINT8 ubStrategicInsertionCode, UINT8 ub } else { - ChooseMapEdgepoints( &MapEdgepointInfo, ubStrategicInsertionCode, (UINT8)(ubNumAdmins+ubNumElites+ubNumTroops) ); + ChooseMapEdgepoints( &MapEdgepointInfo, ubStrategicInsertionCode, (UINT8)(ubNumAdmins+ubNumElites+ubNumTroops+ubNumTanks) ); } #else - ChooseMapEdgepoints( &MapEdgepointInfo, ubStrategicInsertionCode, (UINT8)(ubNumAdmins+ubNumElites+ubNumTroops) ); + ChooseMapEdgepoints( &MapEdgepointInfo, ubStrategicInsertionCode, (UINT8)(ubNumAdmins+ubNumElites+ubNumTroops+ubNumTanks) ); #endif @@ -1893,6 +1982,29 @@ void AddEnemiesToBattle( GROUP *pGroup, UINT8 ubStrategicInsertionCode, UINT8 ub } 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 ); + } // HEADROCK HAM 3.2: enemy reinforcements arrive with 0 APs. if (gGameExternalOptions.ubReinforcementsFirstTurnFreeze == 1 || gGameExternalOptions.ubReinforcementsFirstTurnFreeze == 2) { @@ -2454,7 +2566,7 @@ BOOLEAN CheckPendingEnemies() { if( gbWorldSectorZ ) return FALSE; SECTORINFO *pSector = &SectorInfo[ SECTOR( gWorldSectorX, gWorldSectorY ) ]; - if( (pSector->ubNumElites + pSector->ubNumTroops + pSector->ubNumAdmins) > ( pSector->ubElitesInBattle + pSector->ubTroopsInBattle + pSector->ubAdminsInBattle) ) + if( (pSector->ubNumElites + pSector->ubNumTroops + pSector->ubNumAdmins + pSector->ubNumTanks) > ( pSector->ubElitesInBattle + pSector->ubTroopsInBattle + pSector->ubAdminsInBattle + pSector->ubTanksInBattle) ) return TRUE; for (GROUP *pGroup = gpGroupList; pGroup; pGroup = pGroup->next) { @@ -2462,7 +2574,7 @@ BOOLEAN CheckPendingEnemies() && !pGroup->fVehicle && pGroup->ubSectorX == gWorldSectorX && pGroup->ubSectorY == gWorldSectorY - && pGroup->ubGroupSize > pGroup->pEnemyGroup->ubElitesInBattle + pGroup->pEnemyGroup->ubTroopsInBattle + pGroup->pEnemyGroup->ubAdminsInBattle) + && pGroup->ubGroupSize > pGroup->pEnemyGroup->ubElitesInBattle + pGroup->pEnemyGroup->ubTroopsInBattle + pGroup->pEnemyGroup->ubAdminsInBattle + pGroup->pEnemyGroup->ubTanksInBattle) return TRUE; } return FALSE; diff --git a/Strategic/Queen Command.h b/Strategic/Queen Command.h index f0383a07..1ac35eec 100644 --- a/Strategic/Queen Command.h +++ b/Strategic/Queen Command.h @@ -22,10 +22,10 @@ UINT8 NumEnemiesInAnySector( INT16 sSectorX, INT16 sSectorY, INT16 sSectorZ ); UINT8 NumEnemiesInSector( INT16 sSectorX, INT16 sSectorY ); UINT8 NumStationaryEnemiesInSector( INT16 sSectorX, INT16 sSectorY ); UINT8 NumMobileEnemiesInSector( INT16 sSectorX, INT16 sSectorY ); -void GetNumberOfMobileEnemiesInSector( INT16 sSectorX, INT16 sSectorY, UINT8 *pubNumAdmins, UINT8 *pubNumTroops, UINT8 *pubNumElites ); -void GetNumberOfMobileEnemiesInSectorWithoutRoadBlock( INT16 sSectorX, INT16 sSectorY, UINT8 *pubNumAdmins, UINT8 *pubNumTroops, UINT8 *pubNumElites ); -void GetNumberOfStationaryEnemiesInSector( INT16 sSectorX, INT16 sSectorY, UINT8 *pubNumAdmins, UINT8 *pubNumTroops, UINT8 *pubNumElites ); -void GetNumberOfEnemiesInSector( INT16 sSectorX, INT16 sSectorY, UINT8 *pubNumAdmins, UINT8 *pubNumTroops, UINT8 *pubNumElites ); +void GetNumberOfMobileEnemiesInSector( INT16 sSectorX, INT16 sSectorY, UINT8 *pubNumAdmins, UINT8 *pubNumTroops, UINT8 *pubNumElites, UINT8 *pubNumTanks ); +void GetNumberOfMobileEnemiesInSectorWithoutRoadBlock( INT16 sSectorX, INT16 sSectorY, UINT8 *pubNumAdmins, UINT8 *pubNumTroops, UINT8 *pubNumElites, UINT8 *pubNumTanks ); +void GetNumberOfStationaryEnemiesInSector( INT16 sSectorX, INT16 sSectorY, UINT8 *pubNumAdmins, UINT8 *pubNumTroops, UINT8 *pubNumElites, UINT8 *pubNumTanks ); +void GetNumberOfEnemiesInSector( INT16 sSectorX, INT16 sSectorY, UINT8 *pubNumAdmins, UINT8 *pubNumTroops, UINT8 *pubNumElites, UINT8 *pubNumTanks ); //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 @@ -33,7 +33,7 @@ void GetNumberOfEnemiesInSector( INT16 sSectorX, INT16 sSectorY, UINT8 *pubNumAd BOOLEAN PrepareEnemyForSectorBattle(); BOOLEAN PrepareEnemyForUndergroundBattle(); -void AddEnemiesToBattle( GROUP *pGroup, UINT8 ubStrategicInsertionCode, UINT8 ubNumAdmins, UINT8 ubNumTroops, UINT8 ubNumElites, BOOLEAN fMagicallyAppeared ); +void AddEnemiesToBattle( GROUP *pGroup, UINT8 ubStrategicInsertionCode, UINT8 ubNumAdmins, UINT8 ubNumTroops, UINT8 ubNumElites, UINT8 ubNumTanks, BOOLEAN fMagicallyAppeared ); void AddPossiblePendingEnemiesToBattle(); void EndTacticalBattleForEnemy(); diff --git a/Strategic/Reinforcement.cpp b/Strategic/Reinforcement.cpp index c8640378..c4389a83 100644 --- a/Strategic/Reinforcement.cpp +++ b/Strategic/Reinforcement.cpp @@ -31,19 +31,20 @@ UINT8 gubReinforcementMinEnemyStaticGroupSize = 12; UINT32 guiMilitiaReinforceTurn = 0, guiMilitiaArrived = 0;//dnl ch68 090913 -void GetNumberOfEnemiesInFiveSectors( INT16 sSectorX, INT16 sSectorY, UINT8 *pubNumAdmins, UINT8 *pubNumTroops, UINT8 *pubNumElites ) +void GetNumberOfEnemiesInFiveSectors( INT16 sSectorX, INT16 sSectorY, UINT8 *pubNumAdmins, UINT8 *pubNumTroops, UINT8 *pubNumElites, UINT8 *pubNumTanks ) { - UINT8 ubNumAdmins, ubNumTroops, ubNumElites; + UINT8 ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks; UINT16 pusMoveDir[4][3]; UINT8 ubDirNumber, ubIndex; - GetNumberOfStationaryEnemiesInSector( sSectorX, sSectorY, pubNumAdmins, pubNumTroops, pubNumElites ); + GetNumberOfStationaryEnemiesInSector( sSectorX, sSectorY, pubNumAdmins, pubNumTroops, pubNumElites, pubNumTanks ); - GetNumberOfMobileEnemiesInSectorWithoutRoadBlock( sSectorX, sSectorY, &ubNumAdmins, &ubNumTroops, &ubNumElites ); + GetNumberOfMobileEnemiesInSectorWithoutRoadBlock( sSectorX, sSectorY, &ubNumAdmins, &ubNumTroops, &ubNumElites, &ubNumTanks ); *pubNumAdmins += ubNumAdmins; *pubNumTroops += ubNumTroops; *pubNumElites += ubNumElites; + *pubNumTanks += ubNumTanks; if( !gGameExternalOptions.gfAllowReinforcements ) return; @@ -55,9 +56,9 @@ void GetNumberOfEnemiesInFiveSectors( INT16 sSectorX, INT16 sSectorY, UINT8 *pub for( ubIndex = 0; ubIndex < ubDirNumber; ubIndex++ ) { - GetNumberOfStationaryEnemiesInSector( SECTORX( pusMoveDir[ ubIndex ][ 0 ] ), SECTORY( pusMoveDir[ ubIndex ][ 0 ] ), &ubNumAdmins, &ubNumTroops, &ubNumElites ); + GetNumberOfStationaryEnemiesInSector( SECTORX( pusMoveDir[ ubIndex ][ 0 ] ), SECTORY( pusMoveDir[ ubIndex ][ 0 ] ), &ubNumAdmins, &ubNumTroops, &ubNumElites, &ubNumTanks ); - while( ubNumElites + ubNumTroops + ubNumAdmins > gubReinforcementMinEnemyStaticGroupSize) + while( ubNumElites + ubNumTroops + ubNumAdmins + ubNumTanks > gubReinforcementMinEnemyStaticGroupSize) { if( ubNumElites ) { @@ -72,23 +73,29 @@ void GetNumberOfEnemiesInFiveSectors( INT16 sSectorX, INT16 sSectorY, UINT8 *pub *pubNumAdmins += 1; ubNumAdmins--; } + else if( ubNumTanks ) + { + *pubNumTanks += 1; + ubNumTanks--; + } } - GetNumberOfMobileEnemiesInSectorWithoutRoadBlock( SECTORX( pusMoveDir[ ubIndex ][ 0 ] ), SECTORY( pusMoveDir[ ubIndex ][ 0 ] ), &ubNumAdmins, &ubNumTroops, &ubNumElites ); + GetNumberOfMobileEnemiesInSectorWithoutRoadBlock( SECTORX( pusMoveDir[ ubIndex ][ 0 ] ), SECTORY( pusMoveDir[ ubIndex ][ 0 ] ), &ubNumAdmins, &ubNumTroops, &ubNumElites, &ubNumTanks ); *pubNumAdmins += ubNumAdmins; *pubNumTroops += ubNumTroops; *pubNumElites += ubNumElites; + *pubNumTanks += ubNumTanks; } } UINT8 NumEnemiesInFiveSectors( INT16 sMapX, INT16 sMapY ) { - UINT8 ubNumAdmins, ubNumTroops, ubNumElites; + UINT8 ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks; - GetNumberOfEnemiesInFiveSectors( sMapX, sMapY, &ubNumAdmins, &ubNumTroops, &ubNumElites ); + GetNumberOfEnemiesInFiveSectors( sMapX, sMapY, &ubNumAdmins, &ubNumTroops, &ubNumElites, &ubNumTanks ); - return ubNumAdmins + ubNumTroops + ubNumElites; + return ubNumAdmins + ubNumTroops + ubNumElites + ubNumTanks; } BOOLEAN IsGroupInARightSectorToReinforce( GROUP *pGroup, INT16 sSectorX, INT16 sSectorY ) @@ -279,19 +286,25 @@ UINT8 DoReinforcementAsPendingEnemy( INT16 sMapX, INT16 sMapY ) (pThisSector->ubNumElites)++; (pSector->ubNumElites)--; (pThisSector->ubElitesInBattle)++; - AddEnemiesToBattle( NULL, (UINT8)pusMoveDir[ ubIndex ][ 2 ], 0, 0, 1, FALSE ); + AddEnemiesToBattle( NULL, (UINT8)pusMoveDir[ ubIndex ][ 2 ], 0, 0, 1, 0, FALSE ); }else if( pSector->ubNumTroops ) { (pThisSector->ubNumTroops)++; (pSector->ubNumTroops)--; (pThisSector->ubTroopsInBattle)++; - AddEnemiesToBattle( NULL, (UINT8)pusMoveDir[ ubIndex ][ 2 ], 0, 1, 0, FALSE ); + AddEnemiesToBattle( NULL, (UINT8)pusMoveDir[ ubIndex ][ 2 ], 0, 1, 0, 0, FALSE ); }else if( pSector->ubNumAdmins ) { (pThisSector->ubNumAdmins)++; (pSector->ubNumAdmins)--; (pThisSector->ubAdminsInBattle)++; - AddEnemiesToBattle( NULL, (UINT8)pusMoveDir[ ubIndex ][ 2 ], 1, 0, 0, FALSE ); + AddEnemiesToBattle( NULL, (UINT8)pusMoveDir[ ubIndex ][ 2 ], 1, 0, 0, 0, FALSE ); + }else if( pSector->ubNumTanks ) + { + (pThisSector->ubNumTanks)++; + (pSector->ubNumTanks)--; + (pThisSector->ubTanksInBattle)++; + AddEnemiesToBattle( NULL, (UINT8)pusMoveDir[ ubIndex ][ 2 ], 0, 0, 0, 1, FALSE ); } return (UINT8)pusMoveDir[ ubIndex ][ 2 ]; diff --git a/Strategic/Reinforcement.h b/Strategic/Reinforcement.h index 18fb0119..14b8c6c4 100644 --- a/Strategic/Reinforcement.h +++ b/Strategic/Reinforcement.h @@ -6,7 +6,7 @@ //For Autoresolve (mostly) -void GetNumberOfEnemiesInFiveSectors( INT16 sSectorX, INT16 sSectorY, UINT8 *pubNumAdmins, UINT8 *pubNumTroops, UINT8 *pubNumElites ); +void GetNumberOfEnemiesInFiveSectors( INT16 sSectorX, INT16 sSectorY, UINT8 *pubNumAdmins, UINT8 *pubNumTroops, UINT8 *pubNumElites, UINT8 *pubNumTanks ); BOOLEAN IsGroupInARightSectorToReinforce( GROUP *pGroup, INT16 sSectorX, INT16 sSectorY ); UINT8 GetAdjacentSectors( UINT8 pSectors[4], INT16 sSectorX, INT16 sSectorY ); UINT8 CountAllMilitiaInFiveSectors(INT16 sMapX, INT16 sMapY); diff --git a/Strategic/Strategic AI.cpp b/Strategic/Strategic AI.cpp index f14b3d03..5f759010 100644 --- a/Strategic/Strategic AI.cpp +++ b/Strategic/Strategic AI.cpp @@ -462,7 +462,7 @@ void SendReinforcementsForPatrol( INT32 iPatrolID, GROUP **pOptionalGroup ); void ClearPreviousAIGroupAssignment( GROUP *pGroup ); -void CalcNumTroopsBasedOnComposition( UINT8 *pubNumTroops, UINT8 *pubNumElites, UINT8 ubTotal, INT32 iCompositionID ); +void CalcNumTroopsBasedOnComposition( UINT8 *pubNumTroops, UINT8 *pubNumElites, UINT8 *pubNumTanks, UINT8 ubTotal, INT32 iCompositionID ); void ConvertGroupTroopsToComposition( GROUP *pGroup, INT32 iCompositionID ); void RemoveSoldiersFromGarrisonBasedOnComposition( INT32 iGarrisonID, UINT8 ubSize ); @@ -556,7 +556,7 @@ INT32 GarrisonReinforcementsRequested( INT32 iGarrisonID, UINT8 *pubExtraReinfor Ensure_RepairedGarrisonGroup( &gGarrisonGroup, &giGarrisonArraySize ); /* added NULL fix, 2007-03-03, Sgt. Kolja */ pSector = &SectorInfo[ gGarrisonGroup[ iGarrisonID ].ubSectorID ]; - iExistingForces = pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites; + iExistingForces = pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumTanks; iReinforcementsRequested = gArmyComp[ gGarrisonGroup[ iGarrisonID ].ubComposition ].bDesiredPopulation - iExistingForces; //Record how many of the reinforcements are additionally provided due to being denied in the past. This will grow @@ -592,7 +592,7 @@ INT32 ReinforcementsAvailable( INT32 iGarrisonID ) Ensure_RepairedGarrisonGroup( &gGarrisonGroup, &giGarrisonArraySize ); /* added NULL fix, 2007-03-03, Sgt. Kolja */ pSector = &SectorInfo[ gGarrisonGroup[ iGarrisonID ].ubSectorID ]; - iReinforcementsAvailable = pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumAdmins; + iReinforcementsAvailable = pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumAdmins + pSector->ubNumTanks; iReinforcementsAvailable -= gArmyComp[ gGarrisonGroup[ iGarrisonID ].ubComposition ].bDesiredPopulation; switch( gGarrisonGroup[ iGarrisonID ].ubComposition ) @@ -673,7 +673,7 @@ BOOLEAN AdjacentSectorIsImportantAndUndefended( UINT8 ubSectorID ) pSector = &SectorInfo[ ubSectorID ]; - if( pSector->ubNumTroops || pSector->ubNumElites || pSector->ubNumAdmins ) + if( pSector->ubNumTroops || pSector->ubNumElites || pSector->ubNumAdmins || pSector->ubNumTanks ) { return FALSE; } @@ -815,7 +815,7 @@ DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"Strategic2"); } } #ifdef JA2BETAVERSION - if( pGroup->pEnemyGroup->ubNumAdmins + pGroup->pEnemyGroup->ubNumTroops + pGroup->pEnemyGroup->ubNumElites != pGroup->ubGroupSize || + if( pGroup->pEnemyGroup->ubNumAdmins + pGroup->pEnemyGroup->ubNumTroops + pGroup->pEnemyGroup->ubNumElites + pGroup->pEnemyGroup->ubNumTanks != pGroup->ubGroupSize || pGroup->ubGroupSize > iMaxEnemyGroupSize ) { SAIReportError( L"Strategic AI: Internal error (bad group populations). Please send PRIOR save file and Strategic Decisions.txt." ); @@ -1120,6 +1120,7 @@ void InitStrategicAI() SECTORINFO *pSector = NULL; GROUP *pGroup; UINT8 ubNumTroops; + UINT8 ubNumTanks; INT32 iPercentElitesBonus; INT32 iMaxEnemyGroupSize = gGameExternalOptions.iMaxEnemyGroupSize; DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"Strategic3"); @@ -1432,9 +1433,9 @@ void InitStrategicAI() } // fill up deficit with admins if total enemies less than min enemy group size - if( pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites < gubMinEnemyGroupSize ) + if( pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumTanks < gubMinEnemyGroupSize ) { - pSector->ubNumAdmins = gubMinEnemyGroupSize - pSector->ubNumTroops - pSector->ubNumElites; + pSector->ubNumAdmins = gubMinEnemyGroupSize - pSector->ubNumTroops - pSector->ubNumElites - pSector->ubNumTanks; } //Calculate weight (range is -20 to +20 before multiplier). @@ -1472,11 +1473,22 @@ void InitStrategicAI() { //Add this patrol group now. ubNumTroops = (UINT8)(gPatrolGroup[ i ].bSize + Random( 3 ) - 1); ubNumTroops = (UINT8)max( gubMinEnemyGroupSize, min( iMaxEnemyGroupSize, ubNumTroops ) ); + ubNumTanks = 0; + + if( ubNumTroops && gGameExternalOptions.fArmyUsesTanksInPatrols ) + { + if( Random( 10 ) < gGameOptions.ubDifficultyLevel && i != 3 && i != 4) + { + ubNumTroops--; + ubNumTanks++; + } + } + //ubNumTroops = (UINT8)max( gubMinEnemyGroupSize, min( MAX_STRATEGIC_TEAM_SIZE, gPatrolGroup[ i ].bSize + Random( 3 ) - 1 ) ); //Note on adding patrol groups... //The patrol group can't actually start on the first waypoint, so we set it to the second way //point for initialization, and then add the waypoints from 0 up - pGroup = CreateNewEnemyGroupDepartingFromSector( gPatrolGroup[ i ].ubSectorID[ 1 ], 0, ubNumTroops, 0 ); + pGroup = CreateNewEnemyGroupDepartingFromSector( gPatrolGroup[ i ].ubSectorID[ 1 ], 0, ubNumTroops, 0, ubNumTanks ); Assert( pGroup ); if( i == 3 || i == 4 ) @@ -1788,7 +1800,8 @@ BOOLEAN HandlePlayerGroupNoticedByPatrolGroup( GROUP *pPlayerGroup, GROUP *pEnem ubSectorID = (BOOLEAN)SECTOR( pPlayerGroup->ubSectorX, pPlayerGroup->ubSectorY ); usOffensePoints = pEnemyGroup->pEnemyGroup->ubNumAdmins * 2 + pEnemyGroup->pEnemyGroup->ubNumTroops * 4 + - pEnemyGroup->pEnemyGroup->ubNumElites * 6; + pEnemyGroup->pEnemyGroup->ubNumElites * 6 + + pEnemyGroup->pEnemyGroup->ubNumTanks * 20; if( PlayerForceTooStrong( ubSectorID, usOffensePoints, &usDefencePoints ) ) { RequestAttackOnSector( ubSectorID, usDefencePoints ); @@ -1838,7 +1851,8 @@ void HandlePlayerGroupNoticedByGarrison( GROUP *pPlayerGroup, UINT8 ubSectorID ) } usOffensePoints = pSector->ubNumAdmins * 2 + pSector->ubNumTroops * 4 + - pSector->ubNumElites * 6; + pSector->ubNumElites * 6 + + pSector->ubNumTanks * 20; if( PlayerForceTooStrong( ubSectorID, usOffensePoints, &usDefencePoints ) ) { RequestAttackOnSector( ubSectorID, usDefencePoints ); @@ -1850,7 +1864,7 @@ void HandlePlayerGroupNoticedByGarrison( GROUP *pPlayerGroup, UINT8 ubSectorID ) if( pSector->ubGarrisonID != NO_GARRISON ) { //Decide whether or not they will attack them with some of the troops. - ubEnemies = (UINT8)(pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites); + ubEnemies = (UINT8)(pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumTanks); if ( gGameOptions.ubDifficultyLevel == DIF_LEVEL_INSANE ) iReinforcementsApproved = (ubEnemies - gArmyComp[ gGarrisonGroup[ pSector->ubGarrisonID ].ubComposition ].bDesiredPopulation ); else @@ -1858,7 +1872,7 @@ void HandlePlayerGroupNoticedByGarrison( GROUP *pPlayerGroup, UINT8 ubSectorID ) if( iReinforcementsApproved*2 > pPlayerGroup->ubGroupSize*3 && iReinforcementsApproved > gubMinEnemyGroupSize ) { //Then enemy's available outnumber the player by at least 3:2, so attack them. - pGroup = CreateNewEnemyGroupDepartingFromSector( ubSectorID, 0, (UINT8)iReinforcementsApproved, 0 ); + pGroup = CreateNewEnemyGroupDepartingFromSector( ubSectorID, 0, (UINT8)iReinforcementsApproved, 0, 0 ); ConvertGroupTroopsToComposition( pGroup, gGarrisonGroup[ pSector->ubGarrisonID ].ubComposition ); @@ -1866,12 +1880,12 @@ void HandlePlayerGroupNoticedByGarrison( GROUP *pPlayerGroup, UINT8 ubSectorID ) RemoveSoldiersFromGarrisonBasedOnComposition( pSector->ubGarrisonID, pGroup->ubGroupSize ); - if( pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumAdmins > iMaxEnemyGroupSize ) + if( pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumAdmins + pSector->ubNumTanks > iMaxEnemyGroupSize ) { #ifdef JA2BETAVERSION LogStrategicEvent( "ERROR: Sector %c%d now has %d enemies (max %d).", gGarrisonGroup[ pSector->ubGarrisonID ].ubSectorID / 16 + 'A' , gGarrisonGroup[ pSector->ubGarrisonID ].ubSectorID % 16, - pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumAdmins, iMaxEnemyGroupSize ); + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumAdmins + pSector->ubNumTanks, iMaxEnemyGroupSize ); #endif } @@ -1893,7 +1907,8 @@ BOOLEAN HandleMilitiaNoticedByPatrolGroup( UINT8 ubSectorID, GROUP *pEnemyGroup UINT8 ubSectorY = (UINT8)(ubSectorID / 16) + 1; usOffensePoints = pEnemyGroup->pEnemyGroup->ubNumAdmins * 2 + pEnemyGroup->pEnemyGroup->ubNumTroops * 4 + - pEnemyGroup->pEnemyGroup->ubNumElites * 6; + pEnemyGroup->pEnemyGroup->ubNumElites * 6 + + pEnemyGroup->pEnemyGroup->ubNumTanks * 20; if( PlayerForceTooStrong( ubSectorID, usOffensePoints, &usDefencePoints ) ) { RequestAttackOnSector( ubSectorID, usDefencePoints ); @@ -2043,11 +2058,11 @@ void HandleEmptySectorNoticedByGarrison( UINT8 ubGarrisonSectorID, UINT8 ubEmpty //An opportunity has arisen, where the enemy has noticed an important sector that is undefended. pSector = &SectorInfo[ ubGarrisonSectorID ]; - ubAvailableTroops = pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumAdmins; + ubAvailableTroops = pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumAdmins + pSector->ubNumTanks; if( ubAvailableTroops >= gubMinEnemyGroupSize * 2 ) { //split group into two groups, and move one of the groups to the next sector. - pGroup = CreateNewEnemyGroupDepartingFromSector( ubGarrisonSectorID, 0, (UINT8)(ubAvailableTroops / 2), 0 ); + pGroup = CreateNewEnemyGroupDepartingFromSector( ubGarrisonSectorID, 0, (UINT8)(ubAvailableTroops / 2), 0, 0 ); ConvertGroupTroopsToComposition( pGroup, gGarrisonGroup[ ubDstGarrisonID ].ubComposition ); RemoveSoldiersFromGarrisonBasedOnComposition( ubSrcGarrisonID, pGroup->ubGroupSize ); gGarrisonGroup[ ubDstGarrisonID ].ubPendingGroupID = pGroup->ubGroupID; @@ -2145,11 +2160,12 @@ DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"Strategic5"); pSector->ubNumAdmins = (UINT8)(pSector->ubNumAdmins + pGroup->pEnemyGroup->ubNumAdmins); pSector->ubNumTroops = (UINT8)(pSector->ubNumTroops + pGroup->pEnemyGroup->ubNumTroops); pSector->ubNumElites = (UINT8)(pSector->ubNumElites + pGroup->pEnemyGroup->ubNumElites); + pSector->ubNumTanks = (UINT8)(pSector->ubNumTanks + pGroup->pEnemyGroup->ubNumTanks); #ifdef JA2BETAVERSION LogStrategicEvent( "%d reinforcements have arrived to garrison sector %c%d", pGroup->pEnemyGroup->ubNumAdmins + pGroup->pEnemyGroup->ubNumTroops + - pGroup->pEnemyGroup->ubNumElites, pGroup->ubSectorY + 'A' - 1, pGroup->ubSectorX ); + pGroup->pEnemyGroup->ubNumElites + pGroup->pEnemyGroup->ubNumTanks, pGroup->ubSectorY + 'A' - 1, pGroup->ubSectorX ); #endif if( IsThisSectorASAMSector( pGroup->ubSectorX, pGroup->ubSectorY, 0 ) ) { @@ -2218,10 +2234,11 @@ DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"Strategic5"); pPatrolGroup->pEnemyGroup->ubNumTroops += pGroup->pEnemyGroup->ubNumTroops; pPatrolGroup->pEnemyGroup->ubNumElites += pGroup->pEnemyGroup->ubNumElites; pPatrolGroup->pEnemyGroup->ubNumAdmins += pGroup->pEnemyGroup->ubNumAdmins; - pPatrolGroup->ubGroupSize += (UINT8)(pGroup->pEnemyGroup->ubNumTroops + pGroup->pEnemyGroup->ubNumElites + pGroup->pEnemyGroup->ubNumAdmins ); + pPatrolGroup->pEnemyGroup->ubNumTanks += pGroup->pEnemyGroup->ubNumTanks; + pPatrolGroup->ubGroupSize += (UINT8)(pGroup->pEnemyGroup->ubNumTroops + pGroup->pEnemyGroup->ubNumElites + pGroup->pEnemyGroup->ubNumAdmins + pGroup->pEnemyGroup->ubNumTanks); #ifdef JA2BETAVERSION LogStrategicEvent( "%d reinforcements have joined patrol group at sector %c%d (new size: %d)", - pGroup->pEnemyGroup->ubNumTroops + pGroup->pEnemyGroup->ubNumElites + pGroup->pEnemyGroup->ubNumAdmins, + pGroup->pEnemyGroup->ubNumTroops + pGroup->pEnemyGroup->ubNumElites + pGroup->pEnemyGroup->ubNumAdmins + pGroup->pEnemyGroup->ubNumTanks, pPatrolGroup->ubSectorY + 'A' - 1, pPatrolGroup->ubSectorX, pPatrolGroup->ubGroupSize ); #endif if( pPatrolGroup->ubGroupSize > iMaxEnemyGroupSize ) @@ -2255,11 +2272,17 @@ DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"Strategic5"); pGroup->pEnemyGroup->ubNumElites--; pPatrolGroup->pEnemyGroup->ubNumElites--; } + else if( pGroup->pEnemyGroup->ubNumTanks ) + { + pGroup->pEnemyGroup->ubNumTanks--; + pPatrolGroup->pEnemyGroup->ubNumTanks--; + } } pPatrolGroup->ubGroupSize = iMaxEnemyGroupSize; Assert( pPatrolGroup->pEnemyGroup->ubNumAdmins + pPatrolGroup->pEnemyGroup->ubNumTroops + - pPatrolGroup->pEnemyGroup->ubNumElites == iMaxEnemyGroupSize ); + pPatrolGroup->pEnemyGroup->ubNumElites + + pPatrolGroup->pEnemyGroup->ubNumTanks == iMaxEnemyGroupSize ); } RemovePGroup( pGroup ); RecalculatePatrolWeight( i ); @@ -2285,7 +2308,7 @@ DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"Strategic5"); #ifdef JA2BETAVERSION LogStrategicEvent( "%d soldiers have arrived to patrol area near sector %c%d", - pGroup->pEnemyGroup->ubNumTroops + pGroup->pEnemyGroup->ubNumElites + pGroup->pEnemyGroup->ubNumAdmins, + pGroup->pEnemyGroup->ubNumTroops + pGroup->pEnemyGroup->ubNumElites + pGroup->pEnemyGroup->ubNumAdmins + pGroup->pEnemyGroup->ubNumTanks, pGroup->ubSectorY + 'A' - 1, pGroup->ubSectorX ); #endif RecalculatePatrolWeight( i ); @@ -2451,7 +2474,7 @@ BOOLEAN StrategicAILookForAdjacentGroups( GROUP *pGroup ) return FALSE; } pSector = &SectorInfo[ SECTOR( pPlayerGroup->ubSectorX, pPlayerGroup->ubSectorY-1 ) ]; - ubNumEnemies = pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites; + ubNumEnemies = pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumTanks; if( ubNumEnemies && pSector->ubGarrisonID != NO_GARRISON && AttemptToNoticeAdjacentGroupSucceeds() ) { HandlePlayerGroupNoticedByGarrison( pPlayerGroup, (UINT8)SECTOR( pPlayerGroup->ubSectorX, pPlayerGroup->ubSectorY-1 ) ); @@ -2483,7 +2506,7 @@ BOOLEAN StrategicAILookForAdjacentGroups( GROUP *pGroup ) return FALSE; } pSector = &SectorInfo[ SECTOR( pPlayerGroup->ubSectorX, pPlayerGroup->ubSectorY+1 ) ]; - ubNumEnemies = pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites; + ubNumEnemies = pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumTanks; if( ubNumEnemies && pSector->ubGarrisonID != NO_GARRISON && AttemptToNoticeAdjacentGroupSucceeds() ) { HandlePlayerGroupNoticedByGarrison( pPlayerGroup, (UINT8)SECTOR( pPlayerGroup->ubSectorX, pPlayerGroup->ubSectorY+1 ) ); @@ -2499,7 +2522,7 @@ BOOLEAN StrategicAILookForAdjacentGroups( GROUP *pGroup ) return FALSE; } pSector = &SectorInfo[ SECTOR( pPlayerGroup->ubSectorX-1, pPlayerGroup->ubSectorY ) ]; - ubNumEnemies = pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites; + ubNumEnemies = pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumTanks; if( ubNumEnemies && pSector->ubGarrisonID != NO_GARRISON && AttemptToNoticeAdjacentGroupSucceeds() ) { HandlePlayerGroupNoticedByGarrison( pPlayerGroup, (UINT8)SECTOR( pPlayerGroup->ubSectorX-1, pPlayerGroup->ubSectorY ) ); @@ -2563,7 +2586,7 @@ void CheckEnemyControlledSector( UINT8 ubSectorID ) } } } - if( pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites ) + if( pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumTanks ) { //The sector is still controlled, so look around to see if there are any players nearby. @@ -2718,7 +2741,7 @@ void RecalculateGarrisonWeight( INT32 iGarrisonID ) pSector = &SectorInfo[ gGarrisonGroup[ iGarrisonID ].ubSectorID ]; iDesiredPop = gArmyComp[ gGarrisonGroup[ iGarrisonID ].ubComposition ].bDesiredPopulation; - iCurrentPop = pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites; + iCurrentPop = pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumTanks; iPriority = gArmyComp[ gGarrisonGroup[ iGarrisonID ].ubComposition ].bPriority; //First, remove the previous weight from the applicable field. @@ -2954,7 +2977,7 @@ void SendReinforcementsForGarrison( INT32 iDstGarrisonID, UINT16 usDefencePoints #ifdef JA2BETAVERSION LogStrategicEvent( "%d troops have been reassigned from %c%d to garrison sector %c%d", - pGroup->pEnemyGroup->ubNumTroops + pGroup->pEnemyGroup->ubNumElites + pGroup->pEnemyGroup->ubNumAdmins, + pGroup->pEnemyGroup->ubNumTroops + pGroup->pEnemyGroup->ubNumElites + pGroup->pEnemyGroup->ubNumAdmins + pGroup->pEnemyGroup->ubNumTanks, pGroup->ubSectorY + 'A' - 1, pGroup->ubSectorX, ubDstSectorY + 'A' - 1, ubDstSectorX ); #endif @@ -3013,7 +3036,7 @@ void SendReinforcementsForGarrison( INT32 iDstGarrisonID, UINT16 usDefencePoints } - pGroup = CreateNewEnemyGroupDepartingFromSector( SECTOR( gModSettings.ubSAISpawnSectorX, gModSettings.ubSAISpawnSectorY ), 0, (UINT8)iReinforcementsApproved, 0 ); + pGroup = CreateNewEnemyGroupDepartingFromSector( SECTOR( gModSettings.ubSAISpawnSectorX, gModSettings.ubSAISpawnSectorY ), 0, (UINT8)iReinforcementsApproved, 0, 0 ); ConvertGroupTroopsToComposition( pGroup, gGarrisonGroup[ iDstGarrisonID ].ubComposition ); pGroup->ubOriginalSector = (UINT8)SECTOR( ubDstSectorX, ubDstSectorY ); //Madd: unlimited reinforcements? @@ -3023,7 +3046,7 @@ void SendReinforcementsForGarrison( INT32 iDstGarrisonID, UINT16 usDefencePoints pGroup->ubMoveType = ONE_WAY; gGarrisonGroup[ iDstGarrisonID ].ubPendingGroupID = pGroup->ubGroupID; - ubGroupSize = (UINT8)(pGroup->pEnemyGroup->ubNumTroops + pGroup->pEnemyGroup->ubNumElites + pGroup->pEnemyGroup->ubNumAdmins); + ubGroupSize = (UINT8)(pGroup->pEnemyGroup->ubNumTroops + pGroup->pEnemyGroup->ubNumElites + pGroup->pEnemyGroup->ubNumAdmins + pGroup->pEnemyGroup->ubNumTanks); if( ubNumExtraReinforcements ) { @@ -3099,13 +3122,13 @@ void SendReinforcementsForGarrison( INT32 iDstGarrisonID, UINT16 usDefencePoints } } - pGroup = CreateNewEnemyGroupDepartingFromSector( gGarrisonGroup[ iSrcGarrisonID ].ubSectorID, 0, (UINT8)iReinforcementsApproved, 0 ); + pGroup = CreateNewEnemyGroupDepartingFromSector( gGarrisonGroup[ iSrcGarrisonID ].ubSectorID, 0, (UINT8)iReinforcementsApproved, 0, 0 ); ConvertGroupTroopsToComposition( pGroup, gGarrisonGroup[ iDstGarrisonID ].ubComposition ); RemoveSoldiersFromGarrisonBasedOnComposition( iSrcGarrisonID, pGroup->ubGroupSize ); pGroup->ubOriginalSector = (UINT8)SECTOR( ubDstSectorX, ubDstSectorY ); pGroup->ubMoveType = ONE_WAY; gGarrisonGroup[ iDstGarrisonID ].ubPendingGroupID = pGroup->ubGroupID; - ubGroupSize = (UINT8)( pGroup->pEnemyGroup->ubNumTroops + pGroup->pEnemyGroup->ubNumElites + pGroup->pEnemyGroup->ubNumAdmins ); + ubGroupSize = (UINT8)( pGroup->pEnemyGroup->ubNumTroops + pGroup->pEnemyGroup->ubNumElites + pGroup->pEnemyGroup->ubNumAdmins + pGroup->pEnemyGroup->ubNumTanks ); if( ubNumExtraReinforcements ) { @@ -3167,7 +3190,7 @@ void SendReinforcementsForPatrol( INT32 iPatrolID, GROUP **pOptionalGroup ) #ifdef JA2BETAVERSION LogStrategicEvent( "%d troops have been reassigned from %c%d to reinforce patrol group covering sector %c%d", - pGroup->pEnemyGroup->ubNumTroops + pGroup->pEnemyGroup->ubNumElites + pGroup->pEnemyGroup->ubNumAdmins, + pGroup->pEnemyGroup->ubNumTroops + pGroup->pEnemyGroup->ubNumElites + pGroup->pEnemyGroup->ubNumAdmins + pGroup->pEnemyGroup->ubNumTanks, pGroup->ubSectorY + 'A' - 1, pGroup->ubSectorX, ubDstSectorY + 'A' - 1, ubDstSectorX ); #endif @@ -3181,7 +3204,7 @@ void SendReinforcementsForPatrol( INT32 iPatrolID, GROUP **pOptionalGroup ) if( iRandom < giReinforcementPool ) { //use the pool and send the requested amount from SECTOR P3 (queen's palace) iReinforcementsApproved = min( iReinforcementsRequested, giReinforcementPool ); - pGroup = CreateNewEnemyGroupDepartingFromSector( SECTOR( gModSettings.ubSAISpawnSectorX, gModSettings.ubSAISpawnSectorY ), 0, (UINT8)iReinforcementsApproved, 0 ); + pGroup = CreateNewEnemyGroupDepartingFromSector( SECTOR( gModSettings.ubSAISpawnSectorX, gModSettings.ubSAISpawnSectorY ), 0, (UINT8)iReinforcementsApproved, 0, 0 ); pGroup->ubOriginalSector = (UINT8)SECTOR( ubDstSectorX, ubDstSectorY ); //Madd: unlimited reinforcements? @@ -3192,7 +3215,7 @@ void SendReinforcementsForPatrol( INT32 iPatrolID, GROUP **pOptionalGroup ) #ifdef JA2BETAVERSION LogStrategicEvent( "%d troops have been sent from palace to patrol area near sector %c%d", - pGroup->pEnemyGroup->ubNumTroops + pGroup->pEnemyGroup->ubNumElites + pGroup->pEnemyGroup->ubNumAdmins, + pGroup->pEnemyGroup->ubNumTroops + pGroup->pEnemyGroup->ubNumElites + pGroup->pEnemyGroup->ubNumAdmins + pGroup->pEnemyGroup->ubNumTanks, ubDstSectorY + 'A' - 1, ubDstSectorX ); #endif @@ -3219,7 +3242,7 @@ void SendReinforcementsForPatrol( INT32 iPatrolID, GROUP **pOptionalGroup ) iReinforcementsAvailable = ReinforcementsAvailable( iSrcGarrisonID ); //Send the lowest of the two: number requested or number available iReinforcementsApproved = min( iReinforcementsRequested, iReinforcementsAvailable ); - pGroup = CreateNewEnemyGroupDepartingFromSector( gGarrisonGroup[ iSrcGarrisonID ].ubSectorID, 0, (UINT8)iReinforcementsApproved, 0 ); + pGroup = CreateNewEnemyGroupDepartingFromSector( gGarrisonGroup[ iSrcGarrisonID ].ubSectorID, 0, (UINT8)iReinforcementsApproved, 0, 0 ); pGroup->ubOriginalSector = (UINT8)SECTOR( ubDstSectorX, ubDstSectorY ); gPatrolGroup[ iPatrolID ].ubPendingGroupID = pGroup->ubGroupID; @@ -3227,7 +3250,7 @@ void SendReinforcementsForPatrol( INT32 iPatrolID, GROUP **pOptionalGroup ) #ifdef JA2BETAVERSION LogStrategicEvent( "%d troops have been sent from garrison sector %c%d to patrol area near sector %c%d", - pGroup->pEnemyGroup->ubNumTroops + pGroup->pEnemyGroup->ubNumElites + pGroup->pEnemyGroup->ubNumAdmins, + pGroup->pEnemyGroup->ubNumTroops + pGroup->pEnemyGroup->ubNumElites + pGroup->pEnemyGroup->ubNumAdmins + pGroup->pEnemyGroup->ubNumTanks, ubSrcSectorY + 'A' - 1, ubSrcSectorX, ubDstSectorY + 'A' - 1, ubDstSectorX ); #endif @@ -4284,6 +4307,10 @@ void ExecuteStrategicAIAction( UINT16 usActionCode, INT16 sSectorX, INT16 sSecto UINT8 stagesector0, stagesector1, stagesector2, stagesector3; UINT8 assaultsector0, assaultsector1, assaultsector2, assaultsector3; unsigned ubNumSoldiers; + UINT8 ubNumTanks = 0; + UINT32 grouptroops[4] = {0,0,0,0}; + UINT32 groupelites[4] = {0,0,0,0}; + UINT32 grouptanks[4] = {0,0,0,0}; switch( usActionCode ) { @@ -4366,11 +4393,25 @@ void ExecuteStrategicAIAction( UINT16 usActionCode, INT16 sSectorX, INT16 sSecto ubNumSoldiers = (UINT8)( gubMinEnemyGroupSize + gGameOptions.ubDifficultyLevel * 3); - pGroup0 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, 0, ubNumSoldiers, ubNumSoldiers - ubNumSoldiers / gGameOptions.ubDifficultyLevel ); - pGroup1 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, 0, ubNumSoldiers, ubNumSoldiers - ubNumSoldiers / gGameOptions.ubDifficultyLevel ); - pGroup2 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, 0, ubNumSoldiers, ubNumSoldiers - ubNumSoldiers / gGameOptions.ubDifficultyLevel ); - pGroup3 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, 0, ubNumSoldiers, ubNumSoldiers - ubNumSoldiers / gGameOptions.ubDifficultyLevel ); + // anv: replace one of soldiers with tank + for( UINT8 ubCounter = 0; ubCounter < 4; ubCounter++ ) + { + grouptroops[ubCounter] = ubNumSoldiers; + grouptanks[ubCounter] = 0; + if( ubNumSoldiers && gGameExternalOptions.fArmyUsesTanksInAttacks ) + { + if( Random(10) < gGameOptions.ubDifficultyLevel ) + { + grouptroops[ubCounter]--; + grouptanks[ubCounter]++; + } + } + } + pGroup0 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, 0, grouptroops[0], grouptroops[0] - grouptroops[0] / gGameOptions.ubDifficultyLevel, grouptanks[0] ); + pGroup1 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, 0, grouptroops[1], grouptroops[1] - grouptroops[1] / gGameOptions.ubDifficultyLevel, grouptanks[1] ); + pGroup2 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, 0, grouptroops[2], grouptroops[2] - grouptroops[2] / gGameOptions.ubDifficultyLevel, grouptanks[2] ); + pGroup3 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, 0, grouptroops[3], grouptroops[3] - grouptroops[3] / gGameOptions.ubDifficultyLevel, grouptanks[3] ); if( !gGarrisonGroup[ SectorInfo[ ubTargetSectorID ].ubGarrisonID ].ubPendingGroupID ) { @@ -4416,13 +4457,27 @@ void ExecuteStrategicAIAction( UINT16 usActionCode, INT16 sSectorX, INT16 sSecto } ubNumSoldiers = (UINT8)( gubMinEnemyGroupSize + gGameOptions.ubDifficultyLevel * 3); - - UINT32 grouptroops = ubNumSoldiers; - UINT32 groupelites = 0; - if ( gGameOptions.ubDifficultyLevel > 0 ) - groupelites = ubNumSoldiers - ubNumSoldiers / gGameOptions.ubDifficultyLevel; - UINT32 totalusedsoldiers = 4 * min(grouptroops + groupelites, (UINT32)gGameExternalOptions.iMaxEnemyGroupSize); + // anv: replace one of soldiers with tank + for( UINT8 ubCounter = 0; ubCounter < 4; ubCounter++ ) + { + grouptroops[ubCounter] = ubNumSoldiers; + grouptanks[ubCounter] = 0; + if( ubNumSoldiers && gGameExternalOptions.fArmyUsesTanksInAttacks ) + { + if( Random(10) < gGameOptions.ubDifficultyLevel ) + { + grouptroops[ubCounter]--; + grouptanks[ubCounter]++; + } + } + groupelites[ubCounter] = 0; + if ( gGameOptions.ubDifficultyLevel > 0 ) + groupelites[ubCounter] = grouptroops[ubCounter] - grouptroops[ubCounter] / gGameOptions.ubDifficultyLevel; + } + + //UINT32 totalusedsoldiers = 4 * min(grouptroops + groupelites + ubNumTanks, (UINT32)gGameExternalOptions.iMaxEnemyGroupSize); + UINT32 totalusedsoldiers = 4 * min(grouptroops[0] + groupelites[0] + grouptanks[0], (UINT32)gGameExternalOptions.iMaxEnemyGroupSize); switch( usActionCode ) { @@ -4542,10 +4597,10 @@ void ExecuteStrategicAIAction( UINT16 usActionCode, INT16 sSectorX, INT16 sSecto break; } - pGroup0 = CreateNewEnemyGroupDepartingFromSector( stagesector0, 0, grouptroops, groupelites ); - pGroup1 = CreateNewEnemyGroupDepartingFromSector( stagesector1, 0, grouptroops, groupelites ); - pGroup2 = CreateNewEnemyGroupDepartingFromSector( stagesector2, 0, grouptroops, groupelites ); - pGroup3 = CreateNewEnemyGroupDepartingFromSector( stagesector3, 0, grouptroops, groupelites ); + pGroup0 = CreateNewEnemyGroupDepartingFromSector( stagesector0, 0, grouptroops[0], groupelites[0], grouptanks[0] ); + pGroup1 = CreateNewEnemyGroupDepartingFromSector( stagesector1, 0, grouptroops[1], groupelites[1], grouptanks[1] ); + pGroup2 = CreateNewEnemyGroupDepartingFromSector( stagesector2, 0, grouptroops[2], groupelites[2], grouptanks[2] ); + pGroup3 = CreateNewEnemyGroupDepartingFromSector( stagesector3, 0, grouptroops[3], groupelites[3], grouptanks[3] ); if( !gGarrisonGroup[ SectorInfo[ ubTargetSectorID ].ubGarrisonID ].ubPendingGroupID ) { @@ -4599,6 +4654,13 @@ void ExecuteStrategicAIAction( UINT16 usActionCode, INT16 sSectorX, INT16 sSecto ubNumSoldiers = (UINT8)( gubMinEnemyGroupSize + gGameOptions.ubDifficultyLevel * 3); + // anv: replace one of soldiers with tank + if( ubNumSoldiers && gGameExternalOptions.fArmyUsesTanksInAttacks ) + { + ubNumSoldiers--; + ubNumTanks++; + } + UINT32 grouptroops = ubNumSoldiers; UINT32 groupelites = 0; if ( gGameOptions.ubDifficultyLevel > 0 ) @@ -4614,12 +4676,12 @@ void ExecuteStrategicAIAction( UINT16 usActionCode, INT16 sSectorX, INT16 sSecto if ( !(SectorInfo[ ubSourceSectorID ].ubNumTroops > 0) ) ubSourceSectorID = SECTOR( gModSettings.ubSAISpawnSectorX, gModSettings.ubSAISpawnSectorY ); - pGroup0 = CreateNewEnemyGroupDepartingFromSector( SECTOR( gModSettings.ubSAISpawnSectorX, gModSettings.ubSAISpawnSectorY ), 0, grouptroops, groupelites ); - pGroup1 = CreateNewEnemyGroupDepartingFromSector( SECTOR( gModSettings.ubSAISpawnSectorX, gModSettings.ubSAISpawnSectorY ), 0, grouptroops, groupelites ); - pGroup2 = CreateNewEnemyGroupDepartingFromSector( SECTOR( gModSettings.ubSAISpawnSectorX, gModSettings.ubSAISpawnSectorY ), 0, grouptroops, groupelites ); - pGroup3 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, 0, grouptroops, groupelites ); + pGroup0 = CreateNewEnemyGroupDepartingFromSector( SECTOR( gModSettings.ubSAISpawnSectorX, gModSettings.ubSAISpawnSectorY ), 0, grouptroops, groupelites, ubNumTanks ); + pGroup1 = CreateNewEnemyGroupDepartingFromSector( SECTOR( gModSettings.ubSAISpawnSectorX, gModSettings.ubSAISpawnSectorY ), 0, grouptroops, groupelites, ubNumTanks ); + pGroup2 = CreateNewEnemyGroupDepartingFromSector( SECTOR( gModSettings.ubSAISpawnSectorX, gModSettings.ubSAISpawnSectorY ), 0, grouptroops, groupelites, ubNumTanks ); + pGroup3 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, 0, grouptroops, groupelites, 0 ); - totalusedsoldiers += min(grouptroops + groupelites, (UINT32)gGameExternalOptions.iMaxEnemyGroupSize); + totalusedsoldiers += min(grouptroops + groupelites + ubNumTanks, (UINT32)gGameExternalOptions.iMaxEnemyGroupSize); if( !gGarrisonGroup[ SectorInfo[ ubTargetSectorID ].ubGarrisonID ].ubPendingGroupID ) { @@ -4671,12 +4733,12 @@ void ExecuteStrategicAIAction( UINT16 usActionCode, INT16 sSectorX, INT16 sSecto assaultsector3 = SEC_H9; } - pGroup0 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, 0, grouptroops, groupelites ); - pGroup1 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, 0, grouptroops, groupelites ); - pGroup2 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, 0, grouptroops, groupelites ); - pGroup3 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, 0, grouptroops, groupelites ); + pGroup0 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, 0, grouptroops, groupelites, ubNumTanks ); + pGroup1 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, 0, grouptroops, groupelites, ubNumTanks ); + pGroup2 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, 0, grouptroops, groupelites, ubNumTanks ); + pGroup3 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, 0, grouptroops, groupelites, 0 ); - totalusedsoldiers += min(grouptroops + groupelites, (UINT32)gGameExternalOptions.iMaxEnemyGroupSize); + totalusedsoldiers += min(grouptroops + groupelites + ubNumTanks, (UINT32)gGameExternalOptions.iMaxEnemyGroupSize); if( !gGarrisonGroup[ SectorInfo[ ubTargetSectorID ].ubGarrisonID ].ubPendingGroupID ) { @@ -4711,12 +4773,12 @@ void ExecuteStrategicAIAction( UINT16 usActionCode, INT16 sSectorX, INT16 sSecto if ( !(SectorInfo[ ubSourceSectorID ].ubNumTroops > 0) ) ubSourceSectorID = SECTOR( gModSettings.ubSAISpawnSectorX, gModSettings.ubSAISpawnSectorY ); - pGroup0 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, 0, grouptroops, groupelites ); - pGroup1 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, 0, grouptroops, groupelites ); - pGroup2 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, 0, grouptroops, groupelites ); - pGroup3 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, 0, grouptroops, groupelites ); + pGroup0 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, 0, grouptroops, groupelites, ubNumTanks ); + pGroup1 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, 0, grouptroops, groupelites, ubNumTanks ); + pGroup2 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, 0, grouptroops, groupelites, ubNumTanks ); + pGroup3 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, 0, grouptroops, groupelites, ubNumTanks ); - totalusedsoldiers += min(grouptroops + groupelites, (UINT32)gGameExternalOptions.iMaxEnemyGroupSize); + totalusedsoldiers += min(grouptroops + groupelites + ubNumTanks, (UINT32)gGameExternalOptions.iMaxEnemyGroupSize); if( !gGarrisonGroup[ SectorInfo[ ubTargetSectorID ].ubGarrisonID ].ubPendingGroupID ) { @@ -4751,10 +4813,10 @@ void ExecuteStrategicAIAction( UINT16 usActionCode, INT16 sSectorX, INT16 sSecto if ( !(SectorInfo[ ubSourceSectorID ].ubNumTroops > 0) ) ubSourceSectorID = SECTOR( gModSettings.ubSAISpawnSectorX, gModSettings.ubSAISpawnSectorY ); - pGroup0 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, 0, grouptroops, groupelites ); - pGroup1 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, 0, grouptroops, groupelites ); - pGroup2 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, 0, grouptroops, groupelites ); - pGroup3 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, 0, grouptroops, groupelites ); + pGroup0 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, 0, grouptroops, groupelites, ubNumTanks ); + pGroup1 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, 0, grouptroops, groupelites, ubNumTanks ); + pGroup2 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, 0, grouptroops, groupelites, ubNumTanks ); + pGroup3 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, 0, grouptroops, groupelites, ubNumTanks ); totalusedsoldiers += min(grouptroops + groupelites, (UINT32)gGameExternalOptions.iMaxEnemyGroupSize); @@ -4792,10 +4854,10 @@ void ExecuteStrategicAIAction( UINT16 usActionCode, INT16 sSectorX, INT16 sSecto // If we were to use our usual staging points in Meduna, the Chitzena and Grumm attacks would very likely combine in Grumm Mine. 2 double attacks in the same sector are a 'bit' too much if ( (SectorInfo[ ubSourceSectorID ].ubNumTroops > 0) ) { - pGroup0 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, 0, grouptroops, groupelites ); - pGroup1 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, 0, grouptroops, groupelites ); - pGroup2 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, 0, grouptroops, groupelites ); - pGroup3 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, 0, grouptroops, groupelites ); + pGroup0 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, 0, grouptroops, groupelites, ubNumTanks ); + pGroup1 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, 0, grouptroops, groupelites, ubNumTanks ); + pGroup2 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, 0, grouptroops, groupelites, ubNumTanks ); + pGroup3 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, 0, grouptroops, groupelites, ubNumTanks ); totalusedsoldiers += min(grouptroops + groupelites, (UINT32)gGameExternalOptions.iMaxEnemyGroupSize); @@ -4839,11 +4901,22 @@ void ExecuteStrategicAIAction( UINT16 usActionCode, INT16 sSectorX, INT16 sSecto ubSectorID = (UINT8)STRATEGIC_INDEX_TO_SECTOR_INFO( sWorldSectorLocationOfFirstBattle ); pSector = &SectorInfo[ ubSectorID ]; ubNumSoldiers = (UINT8)( gubMinEnemyGroupSize + gGameOptions.ubDifficultyLevel * 4); - pGroup = CreateNewEnemyGroupDepartingFromSector( SECTOR( gModSettings.ubSAISpawnSectorX, gModSettings.ubSAISpawnSectorY ), 0, ubNumSoldiers, 0 ); + + // anv: replace one of soldiers with tank + if( ubNumSoldiers && gGameExternalOptions.fArmyUsesTanksInAttacks ) + { + if( Random( 10 ) < gGameOptions.ubDifficultyLevel ) + { + ubNumSoldiers--; + ubNumTanks++; + } + } + + pGroup = CreateNewEnemyGroupDepartingFromSector( SECTOR( gModSettings.ubSAISpawnSectorX, gModSettings.ubSAISpawnSectorY ), 0, ubNumSoldiers, 0, ubNumTanks ); //Madd: unlimited reinforcements? if ( !gfUnlimitedTroops ) - giReinforcementPool -= ubNumSoldiers; + giReinforcementPool -= ( ubNumSoldiers + ubNumTanks ); giReinforcementPool = max( giReinforcementPool, 0 ); @@ -4915,6 +4988,7 @@ void ExecuteStrategicAIAction( UINT16 usActionCode, INT16 sSectorX, INT16 sSecto unsigned adminsThisSquad = 0; unsigned troopsThisSquad = 0; unsigned elitesThisSquad = 0; + unsigned tanksThisSquad = 0; if (direness < 25) { adminsThisSquad = soldiersThisSquad * (40 + Random(20)) / 100; // 40-60% of total troopsThisSquad = soldiersThisSquad - adminsThisSquad; // The rest @@ -4932,7 +5006,16 @@ void ExecuteStrategicAIAction( UINT16 usActionCode, INT16 sSectorX, INT16 sSecto elitesThisSquad = soldiersThisSquad - troopsThisSquad - adminsThisSquad; // The rest } Assert(adminsThisSquad + troopsThisSquad + elitesThisSquad == soldiersThisSquad); - pGroup0 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, adminsThisSquad, soldiersThisSquad, elitesThisSquad ); + // anv: replace one of soldiers with tank + if( ubNumSoldiers && gGameExternalOptions.fArmyUsesTanksInAttacks ) + { + if( Random( 10 * 100 ) < gGameOptions.ubDifficultyLevel * direness ) + { + elitesThisSquad--; + tanksThisSquad++; + } + } + pGroup0 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, adminsThisSquad, soldiersThisSquad, elitesThisSquad, tanksThisSquad ); if( !gGarrisonGroup[ SectorInfo[ ubTargetSectorID ].ubGarrisonID ].ubPendingGroupID ) { pGroup0->pEnemyGroup->ubIntention = STAGE; if (groupCnt > 2) { @@ -5001,7 +5084,7 @@ void ExecuteStrategicAIAction( UINT16 usActionCode, INT16 sSectorX, INT16 sSecto unsigned elitesThisSquad = soldiersThisSquad - troopsThisSquad - adminsThisSquad; // The rest Assert(adminsThisSquad + troopsThisSquad + elitesThisSquad == soldiersThisSquad); - pGroup0 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, adminsThisSquad, soldiersThisSquad, elitesThisSquad ); + pGroup0 = CreateNewEnemyGroupDepartingFromSector( ubSourceSectorID, adminsThisSquad, soldiersThisSquad, elitesThisSquad, 0 ); if( !gGarrisonGroup[ SectorInfo[ ubTargetSectorID ].ubGarrisonID ].ubPendingGroupID ) { pGroup0->pEnemyGroup->ubIntention = STAGE; if (groupCnt > 2) { @@ -5018,7 +5101,7 @@ void ExecuteStrategicAIAction( UINT16 usActionCode, INT16 sSectorX, INT16 sSecto case NPC_ACTION_SEND_SOLDIERS_TO_OMERTA: ubNumSoldiers = (UINT8)( gubMinEnemyGroupSize + gGameOptions.ubDifficultyLevel * 6); //6, 12, or 18 based on difficulty. - pGroup = CreateNewEnemyGroupDepartingFromSector( SECTOR( gModSettings.ubSAISpawnSectorX, gModSettings.ubSAISpawnSectorY ), 0, ubNumSoldiers, (UINT8)(ubNumSoldiers/7) ); //add 1 elite to normal, and 2 for hard + pGroup = CreateNewEnemyGroupDepartingFromSector( SECTOR( gModSettings.ubSAISpawnSectorX, gModSettings.ubSAISpawnSectorY ), 0, ubNumSoldiers, (UINT8)(ubNumSoldiers/7), 0 ); //add 1 elite to normal, and 2 for hard ubNumSoldiers = (UINT8)(ubNumSoldiers + ubNumSoldiers / 7); //Madd: unlimited reinforcements @@ -5048,8 +5131,18 @@ void ExecuteStrategicAIAction( UINT16 usActionCode, INT16 sSectorX, INT16 sSecto if ( !gfUnlimitedTroops ) giReinforcementPool -= ubNumSoldiers; + // anv: replace one of soldiers with tank + if( ubNumSoldiers && gGameExternalOptions.fArmyUsesTanksInAttacks ) + { + if( Random( 10 * 100 ) < gGameOptions.ubDifficultyLevel * HighestPlayerProgressPercentage() ) + { + ubNumSoldiers--; + ubNumTanks++; + } + } + giReinforcementPool = max( giReinforcementPool, 0 ); - pGroup = CreateNewEnemyGroupDepartingFromSector( SECTOR( gModSettings.ubSAISpawnSectorX, gModSettings.ubSAISpawnSectorY ), 0, 0, ubNumSoldiers ); + pGroup = CreateNewEnemyGroupDepartingFromSector( SECTOR( gModSettings.ubSAISpawnSectorX, gModSettings.ubSAISpawnSectorY ), 0, 0, ubNumSoldiers, ubNumTanks ); MoveSAIGroupToSector( &pGroup, ubSectorID, STAGE, REINFORCEMENTS ); // WANNE: This should fix the assertion in UC in the cutscene! @@ -5313,16 +5406,16 @@ void InvestigateSector( UINT8 ubSectorID ) switch( i ) { case 0: //NORTH - AddEnemiesToBattle( NULL, INSERTION_CODE_NORTH, ubAdmins[i], ubTroops[i], ubElites[i], TRUE ); + AddEnemiesToBattle( NULL, INSERTION_CODE_NORTH, ubAdmins[i], ubTroops[i], ubElites[i], 0, TRUE ); break; case 1: //EAST - AddEnemiesToBattle( NULL, INSERTION_CODE_EAST, ubAdmins[i], ubTroops[i], ubElites[i], TRUE ); + AddEnemiesToBattle( NULL, INSERTION_CODE_EAST, ubAdmins[i], ubTroops[i], ubElites[i], 0, TRUE ); break; case 2: //SOUTH - AddEnemiesToBattle( NULL, INSERTION_CODE_SOUTH, ubAdmins[i], ubTroops[i], ubElites[i], TRUE ); + AddEnemiesToBattle( NULL, INSERTION_CODE_SOUTH, ubAdmins[i], ubTroops[i], ubElites[i], 0, TRUE ); break; case 3: //WEST - AddEnemiesToBattle( NULL, INSERTION_CODE_WEST, ubAdmins[i], ubTroops[i], ubElites[i], TRUE ); + AddEnemiesToBattle( NULL, INSERTION_CODE_WEST, ubAdmins[i], ubTroops[i], ubElites[i], 0, TRUE ); break; } } @@ -5561,7 +5654,7 @@ void RequestHighPriorityGarrisonReinforcements( INT32 iGarrisonID, UINT8 ubSoldi if( pGroup->ubGroupSize > ubSoldiersRequested && pGroup->ubGroupSize - ubSoldiersRequested >= gubMinEnemyGroupSize ) { //Split the group, and send to location GROUP *pNewGroup; - pNewGroup = CreateNewEnemyGroupDepartingFromSector( (UINT8)SECTOR( pGroup->ubSectorX, pGroup->ubSectorY ), 0, 0, 0 ); + pNewGroup = CreateNewEnemyGroupDepartingFromSector( (UINT8)SECTOR( pGroup->ubSectorX, pGroup->ubSectorY ), 0, 0, 0, 0 ); //Transfer the troops from group to new group if( pGroup->pEnemyGroup->ubNumTroops >= ubSoldiersRequested ) { //All of them are troops, so do it in one shot. @@ -5604,6 +5697,16 @@ void RequestHighPriorityGarrisonReinforcements( INT32 iGarrisonID, UINT8 ubSoldi ValidateLargeGroup( pGroup ); ValidateLargeGroup( pNewGroup ); } + else if( pGroup->pEnemyGroup->ubNumTanks ) + { + pGroup->pEnemyGroup->ubNumTanks--; + pGroup->ubGroupSize--; + pNewGroup->pEnemyGroup->ubNumTanks++; + pNewGroup->ubGroupSize++; + ubSoldiersRequested--; + ValidateLargeGroup( pGroup ); + ValidateLargeGroup( pNewGroup ); + } else { AssertMsg( 0, "Strategic AI group transfer error. KM : 0" ); @@ -5632,7 +5735,7 @@ void RequestHighPriorityGarrisonReinforcements( INT32 iGarrisonID, UINT8 ubSoldi } else { //There are no groups that have enough troops. Send a new force from the palace instead. - pGroup = CreateNewEnemyGroupDepartingFromSector( SECTOR( gModSettings.ubSAISpawnSectorX, gModSettings.ubSAISpawnSectorY ), 0, ubSoldiersRequested, 0 ); + pGroup = CreateNewEnemyGroupDepartingFromSector( SECTOR( gModSettings.ubSAISpawnSectorX, gModSettings.ubSAISpawnSectorY ), 0, ubSoldiersRequested, 0, 0 ); pGroup->ubMoveType = ONE_WAY; pGroup->pEnemyGroup->ubIntention = REINFORCEMENTS; gGarrisonGroup[ iGarrisonID ].ubPendingGroupID = pGroup->ubGroupID; @@ -5669,7 +5772,7 @@ void MassFortifyTowns() for( i = 0; i < giGarrisonArraySize; i++ ) { pSector = &SectorInfo[ gGarrisonGroup[ i ].ubSectorID ]; - ubNumTroops = pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites; + ubNumTroops = pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumTanks; ubDesiredTroops = (UINT8)gArmyComp[ gGarrisonGroup[ i ].ubComposition ].bDesiredPopulation; if( ubNumTroops < ubDesiredTroops ) @@ -5708,7 +5811,7 @@ void RenderAIViewerGarrisonInfo( INT32 x, INT32 y, SECTORINFO *pSector ) { INT32 iDesired, iSurplus; iDesired = gArmyComp[ gGarrisonGroup[ pSector->ubGarrisonID ].ubComposition ].bDesiredPopulation; - iSurplus = pSector->ubNumTroops + pSector->ubNumAdmins + pSector->ubNumElites - iDesired; + iSurplus = pSector->ubNumTroops + pSector->ubNumAdmins + pSector->ubNumElites + pSector->ubNumTanks- iDesired; SetFontForeground( FONT_WHITE ); if( iSurplus >= 0 ) { @@ -5779,7 +5882,7 @@ BOOLEAN GarrisonCanProvideMinimumReinforcements( INT32 iGarrisonID ) pSector = &SectorInfo[ gGarrisonGroup[ iGarrisonID ].ubSectorID ]; - iAvailable = pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites; + iAvailable = pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumTanks; iDesired = gArmyComp[ gGarrisonGroup[ iGarrisonID ].ubComposition ].bDesiredPopulation; if( iAvailable - iDesired >= gubMinEnemyGroupSize ) @@ -5811,7 +5914,7 @@ BOOLEAN GarrisonRequestingMinimumReinforcements( INT32 iGarrisonID ) } pSector = &SectorInfo[ gGarrisonGroup[ iGarrisonID ].ubSectorID ]; - iAvailable = pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites; + iAvailable = pSector->ubNumAdmins + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumTanks; iDesired = gArmyComp[ gGarrisonGroup[ iGarrisonID ].ubComposition ].bDesiredPopulation; if( iDesired - iAvailable >= gubMinEnemyGroupSize ) @@ -5857,8 +5960,8 @@ void EliminateSurplusTroopsForGarrison( GROUP *pGroup, SECTORINFO *pSector ) INT32 iMaxEnemyGroupSize = gGameExternalOptions.iMaxEnemyGroupSize; DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"Strategic8"); - iTotal = pGroup->pEnemyGroup->ubNumTroops + pGroup->pEnemyGroup->ubNumElites + pGroup->pEnemyGroup->ubNumAdmins + - pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumAdmins; +iTotal = pGroup->pEnemyGroup->ubNumTroops + pGroup->pEnemyGroup->ubNumElites + pGroup->pEnemyGroup->ubNumAdmins + pGroup->pEnemyGroup->ubNumTanks + + pSector->ubNumTroops + pSector->ubNumElites + pSector->ubNumAdmins + pSector->ubNumTanks; if( iTotal <= iMaxEnemyGroupSize ) { return; @@ -5944,6 +6047,32 @@ DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"Strategic8"); iTotal = 0; } } + else if( pGroup->pEnemyGroup->ubNumTanks ) + { + if( pGroup->pEnemyGroup->ubNumTanks < iTotal ) + { + iTotal -= pGroup->pEnemyGroup->ubNumTanks; + pGroup->pEnemyGroup->ubNumTanks = 0; + } + else + { + pGroup->pEnemyGroup->ubNumTanks -= (UINT8)iTotal; + iTotal = 0; + } + } + else if( pSector->ubNumTanks ) + { + if( pSector->ubNumTanks < iTotal ) + { + iTotal -= pSector->ubNumTanks; + pSector->ubNumTanks = 0; + } + else + { + pSector->ubNumTanks -= (UINT8)iTotal; + iTotal = 0; + } + } } } diff --git a/Strategic/Strategic Movement.cpp b/Strategic/Strategic Movement.cpp index e58d99bd..dfbb623f 100644 --- a/Strategic/Strategic Movement.cpp +++ b/Strategic/Strategic Movement.cpp @@ -695,7 +695,7 @@ BOOLEAN AddWaypointStrategicIDToPGroup( GROUP *pGroup, UINT32 uiSectorID ) //Enemy grouping functions -- private use by the strategic AI. //............................................................ -GROUP* CreateNewEnemyGroupDepartingFromSector( UINT32 uiSector, UINT8 ubNumAdmins, UINT8 ubNumTroops, UINT8 ubNumElites ) +GROUP* CreateNewEnemyGroupDepartingFromSector( UINT32 uiSector, UINT8 ubNumAdmins, UINT8 ubNumTroops, UINT8 ubNumElites, UINT8 ubNumTanks ) { GROUP *pNew; AssertMsg( uiSector >= 0 && uiSector <= 255, String( "CreateNewEnemyGroup with out of range value of %d", uiSector ) ); @@ -706,7 +706,7 @@ GROUP* CreateNewEnemyGroupDepartingFromSector( UINT32 uiSector, UINT8 ubNumAdmin AssertMsg( pNew->pEnemyGroup, "MemAlloc failure during enemy group creation." ); memset( pNew->pEnemyGroup, 0, sizeof( ENEMYGROUP ) ); // Make sure group is not bigger than allowed! - while (ubNumAdmins + ubNumTroops + ubNumElites > gGameExternalOptions.iMaxEnemyGroupSize) + while (ubNumAdmins + ubNumTroops + ubNumElites + ubNumTanks > gGameExternalOptions.iMaxEnemyGroupSize) { if (ubNumTroops) { @@ -716,10 +716,14 @@ GROUP* CreateNewEnemyGroupDepartingFromSector( UINT32 uiSector, UINT8 ubNumAdmin { ubNumAdmins--; } - else + else if (ubNumElites) { ubNumElites--; } + else if (ubNumTanks) + { + ubNumTanks--; + } } pNew->pWaypoints = NULL; pNew->ubSectorX = (UINT8)SECTORX( uiSector ); @@ -733,7 +737,8 @@ GROUP* CreateNewEnemyGroupDepartingFromSector( UINT32 uiSector, UINT8 ubNumAdmin pNew->pEnemyGroup->ubNumAdmins = ubNumAdmins; pNew->pEnemyGroup->ubNumTroops = ubNumTroops; pNew->pEnemyGroup->ubNumElites = ubNumElites; - pNew->ubGroupSize = (UINT8)(ubNumAdmins + ubNumTroops + ubNumElites); + pNew->pEnemyGroup->ubNumTanks = ubNumTanks; + pNew->ubGroupSize = (UINT8)(ubNumAdmins + ubNumTroops + ubNumElites + ubNumTanks); pNew->ubTransportationMask = FOOT; pNew->fVehicle = FALSE; pNew->ubCreatedSectorID = pNew->ubOriginalSector; @@ -5554,7 +5559,7 @@ BOOLEAN ScoutIsPresentInSquad( INT16 ubSectorNumX, INT16 ubSectorNumY ) } #ifdef JA2UB -GROUP* CreateNewEnemyGroupDepartingFromSectorUsingZLevel( UINT32 uiSector, UINT8 ubSectorZ, UINT8 ubNumAdmins, UINT8 ubNumTroops, UINT8 ubNumElites ) +GROUP* CreateNewEnemyGroupDepartingFromSectorUsingZLevel( UINT32 uiSector, UINT8 ubSectorZ, UINT8 ubNumAdmins, UINT8 ubNumTroops, UINT8 ubNumElites, UINT8 ubNumTanks ) { GROUP *pNew; AssertMsg( uiSector >= 0 && uiSector <= 255, String( "CreateNewEnemyGroup with out of range value of %d", uiSector ) ); diff --git a/Strategic/Strategic Movement.h b/Strategic/Strategic Movement.h index 7fd20759..98c9cecc 100644 --- a/Strategic/Strategic Movement.h +++ b/Strategic/Strategic Movement.h @@ -71,8 +71,9 @@ typedef struct ENEMYGROUP UINT8 ubTroopsInBattle; //number of soldiers currently in battle. UINT8 ubElitesInBattle; //number of elite soldiers currently in battle. // WDS - New AI - UINT8 numTanks; - INT8 bPadding[19]; + UINT8 ubNumTanks; + UINT8 ubTanksInBattle; + INT8 bPadding[18]; }ENEMYGROUP; //NOTE: ALL FLAGS ARE CLEARED WHENEVER A GROUP ARRIVES IN A SECTOR, OR ITS WAYPOINTS ARE @@ -180,9 +181,9 @@ BOOLEAN SetGroupPatrolParameters( UINT8 ubGroupID, UINT8 ubRestAtFL, UINT8 ubRes //Enemy grouping functions -- private use by the strategic AI. //............................................................ -GROUP* CreateNewEnemyGroupDepartingFromSector( UINT32 uiSector, UINT8 ubNumAdmins, UINT8 ubNumTroops, UINT8 ubNumElites ); +GROUP* CreateNewEnemyGroupDepartingFromSector( UINT32 uiSector, UINT8 ubNumAdmins, UINT8 ubNumTroops, UINT8 ubNumElites, UINT8 ubNumTanks ); #ifdef JA2UB -GROUP* CreateNewEnemyGroupDepartingFromSectorUsingZLevel( UINT32 uiSector, UINT8 ubSectorZ, UINT8 ubNumAdmins, UINT8 ubNumTroops, UINT8 ubNumElites ); +GROUP* CreateNewEnemyGroupDepartingFromSectorUsingZLevel( UINT32 uiSector, UINT8 ubSectorZ, UINT8 ubNumAdmins, UINT8 ubNumTroops, UINT8 ubNumElites, UINT8 ubNumTanks ); #endif //ARRIVALCALLBACK -- None of these functions should be called directly. diff --git a/Strategic/Strategic Status.h b/Strategic/Strategic Status.h index a63f6d7d..096d004a 100644 --- a/Strategic/Strategic Status.h +++ b/Strategic/Strategic Status.h @@ -86,6 +86,7 @@ enum ENEMY_RANK_ADMIN, ENEMY_RANK_TROOP, ENEMY_RANK_ELITE, + //ENEMY_RANK_TANK, NUM_ENEMY_RANKS }; diff --git a/Strategic/UndergroundInit.cpp b/Strategic/UndergroundInit.cpp index 85cc53c1..7a83a8b3 100644 --- a/Strategic/UndergroundInit.cpp +++ b/Strategic/UndergroundInit.cpp @@ -88,6 +88,7 @@ BOOLEAN LuaUnderground::InitializeSectorList() sectorData.getValue("numAdmins", s->ubNumAdmins); sectorData.getValue("numTroops", s->ubNumTroops); sectorData.getValue("numElites", s->ubNumElites); + sectorData.getValue("numTanks", s->ubNumTanks); sectorData.getValue("numBloodcats", s->ubNumBloodcats); sectorData.getValue("numCreatures", s->ubNumCreatures); @@ -104,6 +105,7 @@ BOOLEAN LuaUnderground::InitializeSectorList() m_log << "\t\tAdmins: " << static_cast(s->ubNumAdmins) << LF; m_log << "\t\tTroops: " << static_cast(s->ubNumTroops) << LF; m_log << "\t\tElites: " << static_cast(s->ubNumElites) << LF; + m_log << "\t\tTanks: " << static_cast(s->ubNumTanks) << LF; m_log << "\t- Creature population" << LF; m_log << "\t\tBloodcats: " << static_cast(s->ubNumBloodcats) << LF; m_log << "\t\tCrepitus: " << static_cast(s->ubNumCreatures) << LF; diff --git a/Strategic/strategicmap.cpp b/Strategic/strategicmap.cpp index b6974037..0b52d12e 100644 --- a/Strategic/strategicmap.cpp +++ b/Strategic/strategicmap.cpp @@ -391,6 +391,7 @@ void CrippledVersionFailureToLoadMapCheck(); extern INT16 gsAINumAdmins; extern INT16 gsAINumTroops; extern INT16 gsAINumElites; + extern INT16 gsAINumTanks; extern INT16 gsAINumCreatures; //The wrapper time for EnterSector BOOLEAN fStartNewFile = TRUE; @@ -2550,6 +2551,7 @@ void PrepareLoadedSector() pSector->ubNumAdmins = (UINT8)( gsAINumAdmins > 0 ? gsAINumAdmins : 0 ); pSector->ubNumTroops = (UINT8)( gsAINumTroops > 0 ? gsAINumTroops : 0 ); pSector->ubNumElites = (UINT8)( gsAINumElites > 0 ? gsAINumElites : 0 ); + pSector->ubNumTanks = (UINT8)( gsAINumTanks > 0 ? gsAINumTanks : 0 ); pSector->ubNumCreatures = (UINT8)( gsAINumCreatures > 0 ? gsAINumCreatures : 0 ); } else if( !gbWorldSectorZ ) @@ -2559,6 +2561,7 @@ void PrepareLoadedSector() pSector->ubNumAdmins = (UINT8)( gsAINumAdmins > 0 ? gsAINumAdmins : 0 ); pSector->ubNumTroops = (UINT8)( gsAINumTroops > 0 ? gsAINumTroops : 0 ); pSector->ubNumElites = (UINT8)( gsAINumElites > 0 ? gsAINumElites : 0 ); + pSector->ubNumTanks = (UINT8)( gsAINumTanks > 0 ? gsAINumTanks : 0 ); pSector->ubNumCreatures = (UINT8)( gsAINumCreatures > 0 ? gsAINumCreatures : 0 ); } } diff --git a/Tactical/End Game.cpp b/Tactical/End Game.cpp index ce947cc2..3afaeabe 100644 --- a/Tactical/End Game.cpp +++ b/Tactical/End Game.cpp @@ -316,9 +316,11 @@ void DoneFadeOutKilledQueen( void ) SectorInfo[ SECTOR( VICTORY_X, VICTORY_Y ) ].ubNumAdmins = 0; SectorInfo[ SECTOR( VICTORY_X, VICTORY_Y ) ].ubNumTroops = 0; SectorInfo[ SECTOR( VICTORY_X, VICTORY_Y ) ].ubNumElites = 0; + SectorInfo[ SECTOR( VICTORY_X, VICTORY_Y ) ].ubNumTanks = 0; SectorInfo[ SECTOR( VICTORY_X, VICTORY_Y ) ].ubAdminsInBattle = 0; SectorInfo[ SECTOR( VICTORY_X, VICTORY_Y ) ].ubTroopsInBattle = 0; SectorInfo[ SECTOR( VICTORY_X, VICTORY_Y ) ].ubElitesInBattle = 0; + SectorInfo[ SECTOR( VICTORY_X, VICTORY_Y ) ].ubTanksInBattle = 0; // ATE: banish elliot... dead or alive gMercProfiles[ ELLIOT ].sSectorX = 0; diff --git a/Tactical/Enemy Soldier Save.cpp b/Tactical/Enemy Soldier Save.cpp index fc076a1e..1adf96fe 100644 --- a/Tactical/Enemy Soldier Save.cpp +++ b/Tactical/Enemy Soldier Save.cpp @@ -43,7 +43,7 @@ int gCivPreservedTempFileVersion[256]; BOOLEAN AddPlacementToWorld( SOLDIERINITNODE *pNode, GROUP *pGroup = NULL ); -BOOLEAN CountNumberOfElitesRegularsAdminsAndCreaturesFromEnemySoldiersTempFile( UINT8 *pubNumElites, UINT8 *pubNumRegulars, UINT8 *pubNumAdmins, UINT8 *pubNumCreatures ); +BOOLEAN CountNumberOfElitesRegularsAdminsAndCreaturesFromEnemySoldiersTempFile( UINT8 *pubNumElites, UINT8 *pubNumRegulars, UINT8 *pubNumAdmins, UINT8 *pubNumCreatures, UINT8 *pubNumTanks ); BOOLEAN gfRestoringEnemySoldiersFromTempFile = FALSE; BOOLEAN gfRestoringCiviliansFromTempFile = FALSE; @@ -104,8 +104,8 @@ BOOLEAN LoadEnemySoldiersFromTempFile() #endif INT8 bSectorZ; UINT8 ubSectorID; - UINT8 ubNumElites = 0, ubNumTroops = 0, ubNumAdmins = 0, ubNumCreatures = 0; - UINT8 ubStrategicElites, ubStrategicTroops, ubStrategicAdmins, ubStrategicCreatures; + UINT8 ubNumElites = 0, ubNumTroops = 0, ubNumAdmins = 0, ubNumCreatures = 0, ubNumTanks = 0; + UINT8 ubStrategicElites, ubStrategicTroops, ubStrategicAdmins, ubStrategicCreatures, ubStrategicTanks; gfRestoringEnemySoldiersFromTempFile = TRUE; @@ -253,6 +253,7 @@ BOOLEAN LoadEnemySoldiersFromTempFile() ubStrategicElites = pSector->ubNumElites; ubStrategicTroops = pSector->ubNumTroops; ubStrategicAdmins = pSector->ubNumAdmins; + ubStrategicTanks = pSector->ubNumTanks; ubStrategicCreatures = pSector->ubNumCreatures; } else @@ -260,7 +261,7 @@ BOOLEAN LoadEnemySoldiersFromTempFile() SECTORINFO *pSector; pSector = &SectorInfo[ SECTOR( sSectorX, sSectorY ) ]; ubStrategicCreatures = pSector->ubNumCreatures; - GetNumberOfEnemiesInSector( sSectorX, sSectorY, &ubStrategicAdmins, &ubStrategicTroops, &ubStrategicElites ); + GetNumberOfEnemiesInSector( sSectorX, sSectorY, &ubStrategicAdmins, &ubStrategicTroops, &ubStrategicElites, &ubStrategicTanks ); } for( i = 0; i < slots; i++ ) @@ -347,6 +348,16 @@ BOOLEAN LoadEnemySoldiersFromTempFile() AddPlacementToWorld( curr ); } break; + case SOLDIER_CLASS_TANK: + if( curr->pBasicPlacement->bBodyType == TANK_NE || curr->pBasicPlacement->bBodyType == TANK_NW ) + { + ubNumTanks++; + if( ubNumTanks < ubStrategicTanks ) + { + AddPlacementToWorld( curr ); + } + } + break; } break; } @@ -374,12 +385,13 @@ BOOLEAN LoadEnemySoldiersFromTempFile() } //now add any extra enemies that have arrived since the temp file was made. - if( ubStrategicTroops > ubNumTroops || ubStrategicElites > ubNumElites || ubStrategicAdmins > ubNumAdmins ) + if( ubStrategicTroops > ubNumTroops || ubStrategicElites > ubNumElites || ubStrategicAdmins > ubNumAdmins || ubStrategicTanks > ubNumTanks ) { ubStrategicTroops = ( ubStrategicTroops > ubNumTroops ) ? ubStrategicTroops - ubNumTroops : 0; ubStrategicElites = ( ubStrategicElites > ubNumElites ) ? ubStrategicElites - ubNumElites : 0; ubStrategicAdmins = ( ubStrategicAdmins > ubNumAdmins ) ? ubStrategicAdmins - ubNumAdmins : 0; - AddSoldierInitListEnemyDefenceSoldiers( ubStrategicAdmins, ubStrategicTroops, ubStrategicElites ); + ubStrategicTanks = ( ubStrategicTanks > ubNumTanks ) ? ubStrategicTanks - ubNumTanks : 0; + AddSoldierInitListEnemyDefenceSoldiers( ubStrategicAdmins, ubStrategicTroops, ubStrategicElites, ubStrategicTanks ); } if( ubStrategicCreatures > ubNumCreatures ) { @@ -662,8 +674,8 @@ BOOLEAN NewWayOfLoadingEnemySoldiersFromTempFile() #endif INT8 bSectorZ; UINT8 ubSectorID; - UINT8 ubNumElites = 0, ubNumTroops = 0, ubNumAdmins = 0, ubNumCreatures = 0; - UINT8 ubStrategicElites, ubStrategicTroops, ubStrategicAdmins, ubStrategicCreatures; + UINT8 ubNumElites = 0, ubNumTroops = 0, ubNumAdmins = 0, ubNumCreatures = 0, ubNumTanks = 0; + UINT8 ubStrategicElites, ubStrategicTroops, ubStrategicAdmins, ubStrategicCreatures, ubStrategicTanks; gfRestoringEnemySoldiersFromTempFile = TRUE; @@ -702,16 +714,17 @@ BOOLEAN NewWayOfLoadingEnemySoldiersFromTempFile() ubNumElites = pSector->ubNumElites; ubNumTroops = pSector->ubNumTroops; ubNumAdmins = pSector->ubNumAdmins; + ubNumTanks = pSector->ubNumTanks; ubNumCreatures = pSector->ubNumCreatures; } if( !( gTacticalStatus.uiFlags & LOADING_SAVED_GAME ) ) { // Get the number of enemies form the temp file - CountNumberOfElitesRegularsAdminsAndCreaturesFromEnemySoldiersTempFile( &ubStrategicElites, &ubStrategicTroops, &ubStrategicAdmins, &ubStrategicCreatures ); + CountNumberOfElitesRegularsAdminsAndCreaturesFromEnemySoldiersTempFile( &ubStrategicElites, &ubStrategicTroops, &ubStrategicAdmins, &ubStrategicCreatures, &ubStrategicTanks ); //If any of the counts differ from what is in memory - if( ubStrategicElites != ubNumElites || ubStrategicTroops != ubNumTroops || ubStrategicAdmins != ubNumAdmins || ubStrategicCreatures != ubNumCreatures ) + if( ubStrategicElites != ubNumElites || ubStrategicTroops != ubNumTroops || ubStrategicAdmins != ubNumAdmins || ubStrategicCreatures != ubNumCreatures || ubStrategicTanks != ubNumTanks ) { //remove the file RemoveEnemySoldierTempFile( gWorldSectorX, gWorldSectorY, gbWorldSectorZ ); @@ -720,7 +733,7 @@ BOOLEAN NewWayOfLoadingEnemySoldiersFromTempFile() } //reset - ubNumElites = ubNumTroops = ubNumAdmins = ubNumCreatures = 0; + ubNumElites = ubNumTroops = ubNumAdmins = ubNumCreatures = ubNumTanks = 0; //Open the file for reading @@ -860,6 +873,7 @@ BOOLEAN NewWayOfLoadingEnemySoldiersFromTempFile() ubStrategicElites = pSector->ubNumElites; ubStrategicTroops = pSector->ubNumTroops; ubStrategicAdmins = pSector->ubNumAdmins; + ubStrategicTanks = pSector->ubNumTanks; ubStrategicCreatures = pSector->ubNumCreatures; } else @@ -867,7 +881,7 @@ BOOLEAN NewWayOfLoadingEnemySoldiersFromTempFile() SECTORINFO *pSector; pSector = &SectorInfo[ SECTOR( sSectorX, sSectorY ) ]; ubStrategicCreatures = pSector->ubNumCreatures; - GetNumberOfEnemiesInSector( sSectorX, sSectorY, &ubStrategicAdmins, &ubStrategicTroops, &ubStrategicElites ); + GetNumberOfEnemiesInSector( sSectorX, sSectorY, &ubStrategicAdmins, &ubStrategicTroops, &ubStrategicElites, &ubStrategicTanks ); } for( i = 0; i < slots; i++ ) @@ -944,6 +958,16 @@ BOOLEAN NewWayOfLoadingEnemySoldiersFromTempFile() //def: AddPlacementToWorld( curr ); } break; + case SOLDIER_CLASS_TANK: + if( curr->pBasicPlacement->bBodyType == TANK_NE || curr->pBasicPlacement->bBodyType == TANK_NW ) + { + ubNumTanks++; + if( ubNumTanks <= ubStrategicTanks ) + { +//def: AddPlacementToWorld( curr ); + } + } + break; } break; } @@ -969,12 +993,13 @@ BOOLEAN NewWayOfLoadingEnemySoldiersFromTempFile() } //now add any extra enemies that have arrived since the temp file was made. - if( ubStrategicTroops > ubNumTroops || ubStrategicElites > ubNumElites || ubStrategicAdmins > ubNumAdmins ) + if( ubStrategicTroops > ubNumTroops || ubStrategicElites > ubNumElites || ubStrategicAdmins > ubNumAdmins || ubStrategicTanks > ubNumTanks ) { ubStrategicTroops = ( ubStrategicTroops > ubNumTroops ) ? ubStrategicTroops - ubNumTroops : 0; ubStrategicElites = ( ubStrategicElites > ubNumElites ) ? ubStrategicElites - ubNumElites : 0; ubStrategicAdmins = ( ubStrategicAdmins > ubNumAdmins ) ? ubStrategicAdmins - ubNumAdmins : 0; - AddSoldierInitListEnemyDefenceSoldiers( ubStrategicAdmins, ubStrategicTroops, ubStrategicElites ); + ubStrategicTanks = ( ubStrategicTanks > ubNumTanks ) ? ubStrategicTanks - ubNumTanks : 0; + AddSoldierInitListEnemyDefenceSoldiers( ubStrategicAdmins, ubStrategicTroops, ubStrategicElites, ubStrategicTanks ); } if( ubStrategicCreatures > ubNumCreatures ) { @@ -1567,7 +1592,7 @@ BOOLEAN NewWayOfSavingEnemyAndCivliansToTempFile( INT16 sSectorX, INT16 sSectorY -BOOLEAN CountNumberOfElitesRegularsAdminsAndCreaturesFromEnemySoldiersTempFile( UINT8 *pubNumElites, UINT8 *pubNumRegulars, UINT8 *pubNumAdmins, UINT8 *pubNumCreatures ) +BOOLEAN CountNumberOfElitesRegularsAdminsAndCreaturesFromEnemySoldiersTempFile( UINT8 *pubNumElites, UINT8 *pubNumRegulars, UINT8 *pubNumAdmins, UINT8 *pubNumCreatures, UINT8 *pubNumTanks ) { // SOLDIERINITNODE *curr; SOLDIERCREATE_STRUCT tempDetailedPlacement; @@ -1592,6 +1617,7 @@ BOOLEAN CountNumberOfElitesRegularsAdminsAndCreaturesFromEnemySoldiersTempFile( *pubNumElites = 0; *pubNumRegulars = 0; *pubNumAdmins = 0; + *pubNumTanks = 0; *pubNumCreatures = 0; @@ -1758,6 +1784,12 @@ BOOLEAN CountNumberOfElitesRegularsAdminsAndCreaturesFromEnemySoldiersTempFile( case SOLDIER_CLASS_CREATURE: (*pubNumCreatures)++; break; + case SOLDIER_CLASS_TANK: + if( tempDetailedPlacement.bBodyType == TANK_NE || tempDetailedPlacement.bBodyType == TANK_NW ) + { + (*pubNumTanks)++; + } + break; } /* while( curr ) diff --git a/Tactical/Inventory Choosing.cpp b/Tactical/Inventory Choosing.cpp index ee0351d1..3ce9c537 100644 --- a/Tactical/Inventory Choosing.cpp +++ b/Tactical/Inventory Choosing.cpp @@ -259,7 +259,7 @@ void GenerateRandomEquipment( SOLDIERCREATE_STRUCT *pp, INT8 bSoldierClass, INT8 } - Assert( ( bSoldierClass >= SOLDIER_CLASS_NONE ) && ( bSoldierClass <= SOLDIER_CLASS_ELITE_MILITIA ) ); + Assert( ( bSoldierClass >= SOLDIER_CLASS_NONE ) && ( bSoldierClass <= SOLDIER_CLASS_ELITE_MILITIA ) || bSoldierClass == SOLDIER_CLASS_TANK ); Assert( ( bEquipmentRating >= 0 ) && ( bEquipmentRating <= 4 ) ); diff --git a/Tactical/LOS.cpp b/Tactical/LOS.cpp index bc70ebc2..f7833a5d 100644 --- a/Tactical/LOS.cpp +++ b/Tactical/LOS.cpp @@ -2329,7 +2329,7 @@ INT32 SoldierToSoldierLineOfSightTest( SOLDIERTYPE * pStartSoldier, SOLDIERTYPE // anv: special check for vehicles - since they're no longer transparent, we need to check for visibility // of all substructures, also vehicle will be noticed even if just part of it is sticking around the corner - if( pEndSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE && !TANK( pEndSoldier ) ) + if( pEndSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE && ( !TANK( pEndSoldier ) || gGameExternalOptions.fEnemyTanksAnyPartVisible ) ) { STRUCTURE *pBase = pEndSoldier->pLevelNode->pStructureData; if( pBase == NULL ) diff --git a/Tactical/Overhead.cpp b/Tactical/Overhead.cpp index f17ce5b2..823f5ab6 100644 --- a/Tactical/Overhead.cpp +++ b/Tactical/Overhead.cpp @@ -6950,16 +6950,16 @@ void RemoveStaticEnemiesFromSectorInfo( INT16 sMapX, INT16 sMapY, INT8 bMapZ ) { SECTORINFO *pSectorInfo = &(SectorInfo[SECTOR( sMapX, sMapY )]); - pSectorInfo->ubNumAdmins = pSectorInfo->ubNumTroops = pSectorInfo->ubNumElites = 0; - pSectorInfo->ubAdminsInBattle = pSectorInfo->ubTroopsInBattle = pSectorInfo->ubElitesInBattle = 0; + pSectorInfo->ubNumAdmins = pSectorInfo->ubNumTroops = pSectorInfo->ubNumElites = pSectorInfo->ubNumTanks = 0; + pSectorInfo->ubAdminsInBattle = pSectorInfo->ubTroopsInBattle = pSectorInfo->ubElitesInBattle = pSectorInfo->ubTanksInBattle = 0; } else { UNDERGROUND_SECTORINFO *pSectorInfo; pSectorInfo = FindUnderGroundSector( sMapX, sMapY, bMapZ ); - pSectorInfo->ubNumAdmins = pSectorInfo->ubNumTroops = pSectorInfo->ubNumElites = 0; - pSectorInfo->ubAdminsInBattle = pSectorInfo->ubTroopsInBattle = pSectorInfo->ubElitesInBattle = 0; + pSectorInfo->ubNumAdmins = pSectorInfo->ubNumTroops = pSectorInfo->ubNumElites = pSectorInfo->ubNumTanks = 0; + pSectorInfo->ubAdminsInBattle = pSectorInfo->ubTroopsInBattle = pSectorInfo->ubElitesInBattle = pSectorInfo->ubTanksInBattle = 0; } } diff --git a/Tactical/Points.cpp b/Tactical/Points.cpp index 2594a2d3..673ad462 100644 --- a/Tactical/Points.cpp +++ b/Tactical/Points.cpp @@ -2610,7 +2610,7 @@ INT16 MinPtsToMove(SOLDIERTYPE *pSoldier) INT16 sCost; INT32 sGridNo; - if ( TANK( pSoldier ) ) + if ( TANK( pSoldier ) && !gGameExternalOptions.fEnemyTanksCanMoveInTactical ) { return(sLowest);//dnl ch64 290813 100AP made INT8 return obsolete } diff --git a/Tactical/Soldier Control.cpp b/Tactical/Soldier Control.cpp index a354dc12..ddf5ff44 100644 --- a/Tactical/Soldier Control.cpp +++ b/Tactical/Soldier Control.cpp @@ -14228,6 +14228,15 @@ BOOLEAN SOLDIERTYPE::IsWeaponMounted( void ) if ( TileIsOutOfBounds(this->sGridNo) ) return( FALSE ); + // anv: passengers who can shoot can rest their guns + if ( this->flags.uiStatusFlags & ( SOLDIER_DRIVER | SOLDIER_PASSENGER ) ) + { + if( !gNewVehicle[pVehicleList[this->iVehicleId].ubVehicleType].VehicleSeats[GetSeatIndexFromSoldier(this)].fBlockedShots ) + return( TRUE ); + else + return( FALSE ); + } + // we determine the height of the next tile in our direction. Because of the way structures are handled, we sometimes have to take the very tile we're occupying right now INT32 nextGridNoinSight = this->sGridNo; if ( this->ubDirection == NORTH || this->ubDirection == SOUTHWEST || this->ubDirection == WEST || this->ubDirection == NORTHWEST ) @@ -14258,8 +14267,13 @@ BOOLEAN SOLDIERTYPE::IsWeaponMounted( void ) { SOLDIERTYPE* pSoldier = MercPtrs[ usPersonID ]; + // anv: vehicles don't mind + if( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) + { + applybipod = TRUE; + } // if the other person is an ally and prone - if ( this->bSide == pSoldier->bSide && gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE ) + else if ( this->bSide == pSoldier->bSide && gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE ) { // if we are facing the other guy in a 90 degree angle, we can mount our gun on his back // Once merc's relationship allows angering mercs through actions of others, add a penalty here @@ -14324,8 +14338,13 @@ BOOLEAN SOLDIERTYPE::IsWeaponMounted( void ) { SOLDIERTYPE* pSoldier = MercPtrs[usPersonID]; + // anv: vehicles don't mind + if( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) + { + applybipod = TRUE; + } // if the other person is an ally and prone - if ( this->bSide == pSoldier->bSide && gAnimControl[pSoldier->usAnimState].ubEndHeight == ANIM_CROUCH ) + else if ( this->bSide == pSoldier->bSide && gAnimControl[pSoldier->usAnimState].ubEndHeight == ANIM_CROUCH ) { applybipod = TRUE; diff --git a/Tactical/Soldier Control.h b/Tactical/Soldier Control.h index 2f1f4aaf..e845b563 100644 --- a/Tactical/Soldier Control.h +++ b/Tactical/Soldier Control.h @@ -329,6 +329,7 @@ enum SOLDIER_CLASS_CREATURE, SOLDIER_CLASS_MINER, SOLDIER_CLASS_ZOMBIE, + SOLDIER_CLASS_TANK, SOLDIER_CLASS_MAX, }; diff --git a/Tactical/Soldier Create.cpp b/Tactical/Soldier Create.cpp index 24577a61..248e394e 100644 --- a/Tactical/Soldier Create.cpp +++ b/Tactical/Soldier Create.cpp @@ -2430,6 +2430,10 @@ void CreateDetailedPlacementGivenBasicPlacementInfo( SOLDIERCREATE_STRUCT *pp, B } break; + case SOLDIER_CLASS_TANK: + pp->bExpLevel = bp->bRelativeAttributeLevel; + break; + default: pp->bExpLevel = bp->bRelativeAttributeLevel; //avg 2 (1-4) ubSoldierClass = SOLDIER_CLASS_NONE; @@ -3033,6 +3037,86 @@ SOLDIERTYPE* TacticalCreateEliteEnemy() return( pSoldier ); } +//USED BY STRATEGIC AI and AUTORESOLVE +SOLDIERTYPE* TacticalCreateEnemyTank() +{ + BASIC_SOLDIERCREATE_STRUCT bp; + SOLDIERCREATE_STRUCT pp; + UINT8 ubID; + SOLDIERTYPE * pSoldier; + + if( guiCurrentScreen == AUTORESOLVE_SCREEN && !gfPersistantPBI ) + { + pSoldier = ReserveTacticalSoldierForAutoresolve( SOLDIER_CLASS_ELITE ); + if( pSoldier ) return pSoldier; + } + + memset( &bp, 0, sizeof( BASIC_SOLDIERCREATE_STRUCT ) ); + RandomizeRelativeLevel( &( bp.bRelativeAttributeLevel ), SOLDIER_CLASS_ELITE ); + RandomizeRelativeLevel( &( bp.bRelativeEquipmentLevel ), SOLDIER_CLASS_ELITE ); + bp.bTeam = ENEMY_TEAM; + bp.bOrders = SEEKENEMY; + bp.bAttitude = (INT8) Random( MAXATTITUDES ); + bp.bBodyType = TANK_NW; + bp.ubSoldierClass = SOLDIER_CLASS_TANK; + CreateDetailedPlacementGivenBasicPlacementInfo( &pp, &bp ); + + //SPECIAL! Certain events in the game can cause profiled NPCs to become enemies. The two cases are + //adding Mike and Iggy. We will only add one NPC in any given combat and the conditions for setting + //the associated facts are done elsewhere. There is also another place where NPCs can get added, which + //is in AddPlacementToWorld() used for inserting defensive enemies. + //NOTE: We don't want to add Mike or Iggy if this is being called from autoresolve! + OkayToUpgradeEliteToSpecialProfiledEnemy( &pp ); + + pSoldier = TacticalCreateSoldier( &pp, &ubID ); + if ( pSoldier ) + { + // send soldier to centre of map, roughly + pSoldier->aiData.sNoiseGridno = (CENTRAL_GRIDNO + ( Random( CENTRAL_RADIUS * 2 + 1 ) - CENTRAL_RADIUS ) + ( Random( CENTRAL_RADIUS * 2 + 1 ) - CENTRAL_RADIUS ) * WORLD_COLS); + pSoldier->aiData.ubNoiseVolume = MAX_MISC_NOISE_DURATION; + } + + return( pSoldier ); +} + +//USED BY STRATEGIC AI and AUTORESOLVE +// should to be succeeded by TacticalCreateArmyTroop/EliteEnemy and AddSoldierToVehicle +SOLDIERTYPE* TacticalCreateJeep() +{ + BASIC_SOLDIERCREATE_STRUCT bp; + SOLDIERCREATE_STRUCT pp; + UINT8 ubID; + SOLDIERTYPE * pSoldier; + SOLDIERTYPE * pDriver; + + if( guiCurrentScreen == AUTORESOLVE_SCREEN && !gfPersistantPBI ) + { + pSoldier = ReserveTacticalSoldierForAutoresolve( SOLDIER_CLASS_ELITE ); + if( pSoldier ) return pSoldier; + } + + memset( &bp, 0, sizeof( BASIC_SOLDIERCREATE_STRUCT ) ); + RandomizeRelativeLevel( &( bp.bRelativeAttributeLevel ), SOLDIER_CLASS_ELITE ); + RandomizeRelativeLevel( &( bp.bRelativeEquipmentLevel ), SOLDIER_CLASS_ELITE ); + bp.bTeam = CIV_TEAM; + bp.bOrders = STATIONARY; + bp.bAttitude = (INT8) Random( MAXATTITUDES ); + bp.bBodyType = JEEP; + bp.ubSoldierClass = SOLDIER_CLASS_NONE; + CreateDetailedPlacementGivenBasicPlacementInfo( &pp, &bp ); + pp.ubProfile = 199; + + pSoldier = TacticalCreateSoldier( &pp, &ubID ); + if ( pSoldier ) + { + // send soldier to centre of map, roughly + pSoldier->aiData.sNoiseGridno = (CENTRAL_GRIDNO + ( Random( CENTRAL_RADIUS * 2 + 1 ) - CENTRAL_RADIUS ) + ( Random( CENTRAL_RADIUS * 2 + 1 ) - CENTRAL_RADIUS ) * WORLD_COLS); + pSoldier->aiData.ubNoiseVolume = MAX_MISC_NOISE_DURATION; + } + + return( pSoldier ); +} + #ifdef ENABLE_ZOMBIES //USED BY STRATEGIC AI and AUTORESOLVE SOLDIERTYPE* TacticalCreateZombie() diff --git a/Tactical/Soldier Create.h b/Tactical/Soldier Create.h index 96a6d393..aa2a9ebc 100644 --- a/Tactical/Soldier Create.h +++ b/Tactical/Soldier Create.h @@ -425,6 +425,8 @@ SOLDIERTYPE* TacticalCreateArmyTroop(); #endif SOLDIERTYPE* TacticalCreateMilitia( UINT8 ubMilitiaClass, INT16 sX, INT16 sY ); // Flugente: added sector coordinates SOLDIERTYPE* TacticalCreateCreature( INT8 bCreatureBodyType ); +SOLDIERTYPE* TacticalCreateEnemyTank(); +SOLDIERTYPE* TacticalCreateJeep(); // Flugente: assassins are elite soldiers of the civ team that go hostile on a certain event, otherwise they just blend in SOLDIERTYPE* TacticalCreateEnemyAssassin(UINT8 disguisetype); diff --git a/Tactical/Soldier Init List.cpp b/Tactical/Soldier Init List.cpp index 35f630f4..cd96517a 100644 --- a/Tactical/Soldier Init List.cpp +++ b/Tactical/Soldier Init List.cpp @@ -976,7 +976,7 @@ UINT8 AddSoldierInitListTeamToWorld( INT8 bTeam, UINT8 ubMaxNum ) return ubNumAdded; } -void AddSoldierInitListEnemyDefenceSoldiers( UINT8 ubTotalAdmin, UINT8 ubTotalTroops, UINT8 ubTotalElite ) +void AddSoldierInitListEnemyDefenceSoldiers( UINT8 ubTotalAdmin, UINT8 ubTotalTroops, UINT8 ubTotalElite, UINT8 ubTotalTanks ) { SOLDIERINITNODE *mark; SOLDIERINITNODE *curr; @@ -985,6 +985,7 @@ void AddSoldierInitListEnemyDefenceSoldiers( UINT8 ubTotalAdmin, UINT8 ubTotalTr UINT8 ubElitePDSlots = 0, ubEliteDSlots = 0, ubElitePSlots = 0, ubEliteBSlots = 0; UINT8 ubTroopPDSlots = 0, ubTroopDSlots = 0, ubTroopPSlots = 0, ubTroopBSlots = 0; UINT8 ubAdminPDSlots = 0, ubAdminDSlots = 0, ubAdminPSlots = 0, ubAdminBSlots = 0; + UINT8 ubTankPDSlots = 0, ubTankDSlots = 0, ubTankPSlots = 0, ubTankBSlots = 0; UINT8 ubFreeSlots; UINT8 *pCurrSlots=NULL; UINT8 *pCurrTotal=NULL; @@ -1002,7 +1003,7 @@ void AddSoldierInitListEnemyDefenceSoldiers( UINT8 ubTotalAdmin, UINT8 ubTotalTr //of each type of enemy may not be the same. Elites will choose the best placements, then army, then //administrators. - ubMaxNum = ubTotalAdmin + ubTotalTroops + ubTotalElite; + ubMaxNum = ubTotalAdmin + ubTotalTroops + ubTotalElite + ubTotalTanks; AssertLE (ubMaxNum, gGameExternalOptions.ubGameMaximumNumberOfEnemies); @@ -1052,6 +1053,19 @@ void AddSoldierInitListEnemyDefenceSoldiers( UINT8 ubTotalAdmin, UINT8 ubTotalTr else ubTroopBSlots++; break; + case SOLDIER_CLASS_TANK: + if( curr->pDetailedPlacement->bBodyType == TANK_NW ||curr->pDetailedPlacement->bBodyType == TANK_NE ) + { + if( curr->pBasicPlacement->fPriorityExistance && curr->pDetailedPlacement ) + ubTankPDSlots++; + else if( curr->pBasicPlacement->fPriorityExistance ) + ubTankPSlots++; + else if( curr->pDetailedPlacement ) + ubTankDSlots++; + else + ubTankBSlots++; + } + break; } } curr = curr->next; @@ -1060,7 +1074,7 @@ void AddSoldierInitListEnemyDefenceSoldiers( UINT8 ubTotalAdmin, UINT8 ubTotalTr //ADD PLACEMENTS WITH PRIORITY EXISTANCE WITH DETAILED PLACEMENT INFORMATION FIRST //we now have the numbers of available slots for each soldier class, so loop through three times //and randomly choose some (or all) of the matching slots to fill. This is done randomly. - for( ubCurrClass = SOLDIER_CLASS_ADMINISTRATOR; ubCurrClass <= SOLDIER_CLASS_ARMY; ubCurrClass++ ) + for( ubCurrClass = SOLDIER_CLASS_ADMINISTRATOR; ubCurrClass <= SOLDIER_CLASS_ARMY + 1; ubCurrClass++ ) { //First, prepare the counters. switch( ubCurrClass ) @@ -1077,6 +1091,11 @@ void AddSoldierInitListEnemyDefenceSoldiers( UINT8 ubTotalAdmin, UINT8 ubTotalTr pCurrSlots = &ubTroopPDSlots; pCurrTotal = &ubTotalTroops; break; + case SOLDIER_CLASS_ARMY + 1:// SOLDIER_CLASS_TANK + ubCurrClass = SOLDIER_CLASS_TANK; + pCurrSlots = &ubTankPDSlots; + pCurrTotal = &ubTotalTanks; + break; } //Now, loop through the priority existance and detailed placement section of the list. curr = gSoldierInitHead; @@ -1253,6 +1272,12 @@ void AddSoldierInitListEnemyDefenceSoldiers( UINT8 ubTotalAdmin, UINT8 ubTotalTr curr->pBasicPlacement->ubSoldierClass = SOLDIER_CLASS_ADMINISTRATOR; ubTotalAdmin--; } + else if( iRandom < ubTotalElite + ubTotalTroops + ubTotalAdmin + ubTotalTanks ) + { + curr->pBasicPlacement->ubSoldierClass = SOLDIER_CLASS_TANK; + curr->pBasicPlacement->bBodyType = TANK_NW; + ubTotalTanks--; + } else Assert(0); if( AddPlacementToWorld( curr ) ) @@ -1334,6 +1359,26 @@ void AddSoldierInitListEnemyDefenceSoldiers( UINT8 ubTotalAdmin, UINT8 ubTotalTr curr = curr->next; } + // anv: try to place tanks outdoors + curr = gSoldierInitHead; + while( curr && ubFreeSlots && ubMaxNum ) + { + if( !curr->pSoldier && curr->pBasicPlacement->bTeam == ENEMY_TEAM && ubTotalTanks && !GridNoIndoors( curr->pBasicPlacement->usStartingGridNo )) + { + curr->pBasicPlacement->ubSoldierClass = SOLDIER_CLASS_TANK; + curr->pBasicPlacement->bBodyType = TANK_NW; + ubTotalTanks--; + if( AddPlacementToWorld( curr ) ) + { + ubMaxNum--; + } + else + return; + ubFreeSlots--; + } + curr = curr->next; + } + //Now, loop through the entire list again, but for the last time. All enemies will be inserted now ignoring //detailed placements and classes. curr = gSoldierInitHead; @@ -1362,6 +1407,12 @@ void AddSoldierInitListEnemyDefenceSoldiers( UINT8 ubTotalAdmin, UINT8 ubTotalTr curr->pBasicPlacement->ubSoldierClass = SOLDIER_CLASS_ADMINISTRATOR; ubTotalAdmin--; } + else if( iRandom < ubTotalElite + ubTotalTroops + ubTotalAdmin + ubTotalTanks ) + { + curr->pBasicPlacement->ubSoldierClass = SOLDIER_CLASS_TANK; + curr->pBasicPlacement->bBodyType = TANK_NW; + ubTotalTanks--; + } else Assert(0); /* DISABLE THE OVERRIDE FOR NOW... diff --git a/Tactical/Soldier Init List.h b/Tactical/Soldier Init List.h index ff8cb507..17a3abbe 100644 --- a/Tactical/Soldier Init List.h +++ b/Tactical/Soldier Init List.h @@ -40,7 +40,7 @@ void RemoveSoldierNodeFromInitList( SOLDIERINITNODE *pNode ); SOLDIERINITNODE* FindSoldierInitNodeWithID( UINT16 usID ); UINT8 AddSoldierInitListTeamToWorld( INT8 bTeam, UINT8 ubMaxNum ); -void AddSoldierInitListEnemyDefenceSoldiers( UINT8 ubTotalAdmin, UINT8 ubTotalTroops, UINT8 ubTotalElite ); +void AddSoldierInitListEnemyDefenceSoldiers( UINT8 ubTotalAdmin, UINT8 ubTotalTroops, UINT8 ubTotalElite, UINT8 ubTotalTanks ); void AddSoldierInitListCreatures( BOOLEAN fQueen, UINT8 ubNumLarvae, UINT8 ubNumInfants, UINT8 ubNumYoungMales, UINT8 ubNumYoungFemales, UINT8 ubNumAdultMales, UINT8 ubNumAdultFemales ); diff --git a/Tactical/Vehicles.cpp b/Tactical/Vehicles.cpp index 6b07c5c3..00fb22e6 100644 --- a/Tactical/Vehicles.cpp +++ b/Tactical/Vehicles.cpp @@ -510,24 +510,24 @@ BOOLEAN AddSoldierToVehicle( SOLDIERTYPE *pSoldier, INT32 iId, UINT8 ubSeatIndex if( pVehicleSoldier ) { - if ( pVehicleSoldier->bTeam != gbPlayerNum ) + if ( pVehicleSoldier->bTeam != pSoldier->bTeam ) { // Can we add a new vehicle - if( vCount >= gGameExternalOptions.ubGameMaximumNumberOfPlayerVehicles ) + if( vCount >= gGameExternalOptions.ubGameMaximumNumberOfPlayerVehicles && pSoldier->bTeam == gbPlayerNum ) { ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, TacticalStr[VEHICLE_CAN_NOT_BE_ADDED] ); return( FALSE ); } // Change sides... - pVehicleSoldier = ChangeSoldierTeam( pVehicleSoldier, gbPlayerNum ); + pVehicleSoldier = ChangeSoldierTeam( pVehicleSoldier, pSoldier->bTeam ); // add it to mapscreen list fReBuildCharacterList = TRUE; } } // If vehicle is empty, add to unique squad now that it has somebody in it! - if ( GetNumberInVehicle( iId ) == 0 && pVehicleSoldier ) + if ( GetNumberInVehicle( iId ) == 0 && pVehicleSoldier && pSoldier->bTeam == gbPlayerNum ) { // 2 ) Add to unique squad... AddCharacterToUniqueSquad( pVehicleSoldier ); @@ -536,17 +536,17 @@ BOOLEAN AddSoldierToVehicle( SOLDIERTYPE *pSoldier, INT32 iId, UINT8 ubSeatIndex // We have now a guy on a squad group, remove him! RemovePlayerFromGroup( SquadMovementGroups[ pVehicleSoldier->bAssignment ], pVehicleSoldier ); - // I really have vehicles.\ - // ONLY add to vehicle group once! - if ( !DoesPlayerExistInPGroup( pVehicleList[ iId ].ubMovementGroup, pVehicleSoldier ) ) - { - //NOW.. add guy to vehicle group.... - AddPlayerToGroup( pVehicleList[ iId ].ubMovementGroup, pVehicleSoldier ); - } - else - { - pVehicleSoldier->ubGroupID = pVehicleList[ iId ].ubMovementGroup; - } + // I really have vehicles.\ + // ONLY add to vehicle group once! + if ( !DoesPlayerExistInPGroup( pVehicleList[ iId ].ubMovementGroup, pVehicleSoldier ) ) + { + //NOW.. add guy to vehicle group.... + AddPlayerToGroup( pVehicleList[ iId ].ubMovementGroup, pVehicleSoldier ); + } + else + { + pVehicleSoldier->ubGroupID = pVehicleList[ iId ].ubMovementGroup; + } } // check if the grunt is already here @@ -565,7 +565,7 @@ BOOLEAN AddSoldierToVehicle( SOLDIERTYPE *pSoldier, INT32 iId, UINT8 ubSeatIndex UnSetUIBusy( pSoldier->ubID ); // can't call SelectSoldier in mapscreen, that will initialize interface panels!!! - if ( guiCurrentScreen == GAME_SCREEN ) + if ( guiCurrentScreen == GAME_SCREEN && pSoldier->bTeam == gbPlayerNum ) { SelectSoldier( pVehicleSoldier->ubID, FALSE, TRUE ); } @@ -611,11 +611,11 @@ BOOLEAN AddSoldierToVehicle( SOLDIERTYPE *pSoldier, INT32 iId, UINT8 ubSeatIndex } // if in a squad, remove from squad, if not, check if in vehicle, if so remove, if not, then check if in mvt group..if so, move and destroy group - if( pSoldier->bAssignment < ON_DUTY ) + if( pSoldier->bTeam == gbPlayerNum && pSoldier->bAssignment < ON_DUTY ) { RemoveCharacterFromSquads( pSoldier ); } - else if( pSoldier->ubGroupID != 0 ) + else if( pSoldier->bTeam == gbPlayerNum && pSoldier->ubGroupID != 0 ) { // Flugente 2012-08-15: had very weird behaviour here. The outcommented code below failed, because the group size wasn't 0, which then threw an Assert()-error. // This happened in r5468 when assinging a merc on repair duty to the truck, switching back and forth between the two @@ -628,22 +628,26 @@ BOOLEAN AddSoldierToVehicle( SOLDIERTYPE *pSoldier, INT32 iId, UINT8 ubSeatIndex //pSoldier->ubGroupID = 0; } - if( ( pSoldier->bAssignment != VEHICLE ) || ( pSoldier->iVehicleId != iId ) ) - { - SetTimeOfAssignmentChangeForMerc( pSoldier ); - } - - // set thier assignment - ChangeSoldiersAssignment( pSoldier, VEHICLE ); - // set vehicle id pSoldier->iVehicleId = iId; - // if vehicle is part of mvt group, then add character to mvt group - if( pVehicleList[ iId ].ubMovementGroup != 0 ) + if( pSoldier->bTeam == gbPlayerNum ) { - // add character - AddPlayerToGroup( pVehicleList[ iId ].ubMovementGroup, pSoldier ); + + if( ( pSoldier->bAssignment != VEHICLE ) || ( pSoldier->iVehicleId != iId ) ) + { + SetTimeOfAssignmentChangeForMerc( pSoldier ); + } + + // set thier assignment + ChangeSoldiersAssignment( pSoldier, VEHICLE ); + + // if vehicle is part of mvt group, then add character to mvt group + if( pVehicleList[ iId ].ubMovementGroup != 0 ) + { + // add character + AddPlayerToGroup( pVehicleList[ iId ].ubMovementGroup, pSoldier ); + } } @@ -692,7 +696,7 @@ BOOLEAN AddSoldierToVehicle( SOLDIERTYPE *pSoldier, INT32 iId, UINT8 ubSeatIndex pSoldier->EVENT_StopMerc( pSoldier->sGridNo, pSoldier->ubDirection ); // can't call SetCurrentSquad OR SelectSoldier in mapscreen, that will initialize interface panels!!! - if ( guiCurrentScreen == GAME_SCREEN ) + if ( pSoldier->bTeam == gbPlayerNum && guiCurrentScreen == GAME_SCREEN ) { SetCurrentSquad( pVehicleSoldier->bAssignment, TRUE ); } @@ -1592,7 +1596,7 @@ SOLDIERTYPE *GetDriver( INT32 iID ) void SetDriver( INT32 iID, UINT8 ubID ) { // anv: first make sure previous driver won't be driver anymore - if( pVehicleList[ iID ].ubDriver != NOBODY ) + if( pVehicleList[ iID ].ubDriver != NOBODY && MercPtrs[ pVehicleList[ iID ].ubDriver ]->iVehicleId == iID ) { if( MercPtrs[ pVehicleList[ iID ].ubDriver ] ) { diff --git a/TacticalAI/AIMain.cpp b/TacticalAI/AIMain.cpp index a7e06a04..e074613d 100644 --- a/TacticalAI/AIMain.cpp +++ b/TacticalAI/AIMain.cpp @@ -346,7 +346,7 @@ void HandleSoldierAI( SOLDIERTYPE *pSoldier ) // FIXME - this function is named return; } - if ( ( (pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE) && !TANK( pSoldier ) ) || AM_A_ROBOT( pSoldier ) ) + if ( ( !gGameExternalOptions.fEnemyTanksCanMoveInTactical && ( (pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE) && !TANK( pSoldier ) ) ) || AM_A_ROBOT( pSoldier ) ) { // bail out! #ifdef TESTAICONTROL @@ -1235,7 +1235,7 @@ void CancelAIAction(SOLDIERTYPE *pSoldier, UINT8 ubForce) #endif // re-enable cover checking, something is new or something strange happened - if(!TANK(pSoldier))//dnl ch64 290813 + if( gGameExternalOptions.fEnemyTanksCanMoveInTactical || !TANK(pSoldier))//dnl ch64 290813 SkipCoverCheck = FALSE; // turn off new situation flag to stop this from repeating all the time! @@ -1506,7 +1506,7 @@ void RefreshAI(SOLDIERTYPE *pSoldier) if (pSoldier->aiData.bAlertStatus == STATUS_YELLOW) SkipCoverCheck = FALSE; - if(TANK(pSoldier))//dnl ch64 290813 tanks don't have move animations + if( !gGameExternalOptions.fEnemyTanksCanMoveInTactical && TANK(pSoldier) )//dnl ch64 290813 tanks don't have move animations SkipCoverCheck = TRUE; // if he's in battle or knows opponents are here @@ -1597,7 +1597,7 @@ INT8 ExecuteAction(SOLDIERTYPE *pSoldier) // in most cases, merc will change location, or may cause damage to opponents, // so a new cover check will be necessary. Exceptions handled individually. - if(!TANK(pSoldier))//dnl ch64 290813 + if( gGameExternalOptions.fEnemyTanksCanMoveInTactical || !TANK(pSoldier) )//dnl ch64 290813 SkipCoverCheck = FALSE; // reset this field, too @@ -2612,6 +2612,11 @@ void HandleAITacticalTraversal( SOLDIERTYPE * pSoldier ) ++pSectorInfo->ubNumAdmins; break; + case SOLDIER_CLASS_TANK: + if( TANK(pSoldier) ) + ++pSectorInfo->ubNumTanks; + break; + } ProcessQueenCmdImplicationsOfDeath( pSoldier ); diff --git a/TacticalAI/AIUtils.cpp b/TacticalAI/AIUtils.cpp index 72c2f124..0413599c 100644 --- a/TacticalAI/AIUtils.cpp +++ b/TacticalAI/AIUtils.cpp @@ -2480,7 +2480,8 @@ INT16 RoamingRange(SOLDIERTYPE *pSoldier, INT32 * pusFromGridNo) switch (pSoldier->aiData.bOrders) { // JA2 GOLD: give non-NPCs a 5 tile roam range for cover in combat when being shot at - case STATIONARY: if (pSoldier->ubProfile != NO_PROFILE || (pSoldier->aiData.bAlertStatus < STATUS_BLACK && !(pSoldier->aiData.bUnderFire))) + // anv: and tanks who are technically NPCs + case STATIONARY: if ( ( pSoldier->ubProfile != NO_PROFILE && !TANK(pSoldier) ) || (pSoldier->aiData.bAlertStatus < STATUS_BLACK && !(pSoldier->aiData.bUnderFire))) { return( 0 ); } diff --git a/TacticalAI/Attacks.cpp b/TacticalAI/Attacks.cpp index c19375ac..617c5c16 100644 --- a/TacticalAI/Attacks.cpp +++ b/TacticalAI/Attacks.cpp @@ -985,7 +985,7 @@ void CalcBestThrow(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestThrow) bPersOL = pSoldier->aiData.bOppList[pOpponent->ubID]; - if ((Item[usInHand].mortar ) || (Item[usInHand].grenadelauncher ) ) + if ((Item[usInHand].mortar ) || (Item[usInHand].grenadelauncher ) || (Item[usInHand].cannon ) ) { bPublOL = gbPublicOpplist[pSoldier->bTeam][pOpponent->ubID]; // allow long range firing, where target doesn't PERSONALLY see opponent @@ -1100,19 +1100,21 @@ void CalcBestThrow(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestThrow) case 0: case 1: // they won't use them until they have 2+ opponents as long as half life left - if ((ubOpponentCnt < 2) && (pSoldier->stats.bLife > (pSoldier->stats.bLifeMax / 2))) + // anv: tanks don't care + if ( ( ubOpponentCnt < 2 ) && ( pSoldier->stats.bLife > pSoldier->stats.bLifeMax / 2 ) && + ( !gGameExternalOptions.fEnemyTanksDontSpareShells || !TANK(pSoldier) ) && !gGameExternalOptions.fEnemiesDontSpareLaunchables ) { return; } break; case 2: // they won't use them until they have 2+ opponents as long as 3/4 life left - if ((ubOpponentCnt < 2) && (pSoldier->stats.bLife > (pSoldier->stats.bLifeMax / 4) * 3 )) + if ( (ubOpponentCnt < 2) && ( pSoldier->stats.bLife > (pSoldier->stats.bLifeMax / 4) * 3 ) && + ( !gGameExternalOptions.fEnemyTanksDontSpareShells || !TANK(pSoldier) ) && !gGameExternalOptions.fEnemiesDontSpareLaunchables ) { return; } break; - break; default: break; } @@ -1346,7 +1348,13 @@ void CalcBestThrow(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestThrow) if ( EXPLOSIVE_GUN( usInHand ) ) { ubChanceToGetThrough = AISoldierToLocationChanceToGetThrough( pSoldier, sGridNo, bOpponentLevel[ubLoop], 0 ); - if ( ubChanceToGetThrough == 0) + // anv: tanks shouldn't care about chance to get through - can't hit? At least we'll destroy their cover. + // also AISoldierToLocationChanceToGetThrough used to return 0 for tanks, but that's a different story + if( ( gGameExternalOptions.fEnemyTanksBlowObstaclesUp && TANK(pSoldier) ) || gGameExternalOptions.fEnemiesBlowObstaclesUp ) + { + ubChanceToGetThrough = 100; + } + if ( ubChanceToGetThrough == 0 ) { continue; // next gridno } @@ -1387,7 +1395,7 @@ void CalcBestThrow(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestThrow) // this is try to minimize enemies wasting their (few) mortar shells or LAWs // they won't use them on less than 2 targets as long as half life left if ((Item[usInHand].mortar || Item[usInHand].rocketlauncher ) && (ubOppsInRange < 2) && - (pSoldier->stats.bLife > (pSoldier->stats.bLifeMax / 2))) + (pSoldier->stats.bLife > (pSoldier->stats.bLifeMax / 2)) && ( !gGameExternalOptions.fEnemyTanksDontSpareShells || !TANK(pSoldier) ) && !gGameExternalOptions.fEnemiesDontSpareLaunchables ) { continue; // next gridno } diff --git a/TacticalAI/DecideAction.cpp b/TacticalAI/DecideAction.cpp index b2d750d9..e1b26f04 100644 --- a/TacticalAI/DecideAction.cpp +++ b/TacticalAI/DecideAction.cpp @@ -794,7 +794,7 @@ INT8 DecideActionGreen(SOLDIERTYPE *pSoldier) } } - if ( TANK( pSoldier ) ) + if ( !gGameExternalOptions.fEnemyTanksCanMoveInTactical && TANK( pSoldier ) ) { return( AI_ACTION_NONE ); } @@ -1889,7 +1889,7 @@ INT8 DecideActionYellow(SOLDIERTYPE *pSoldier) } } - if ( TANK( pSoldier ) ) + if ( !gGameExternalOptions.fEnemyTanksCanMoveInTactical && TANK( pSoldier ) ) { return( AI_ACTION_NONE ); } @@ -2521,7 +2521,7 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK) } } - if ( fCivilian && !( pSoldier->ubBodyType == COW || pSoldier->ubBodyType == CRIPPLECIV ) && + if ( fCivilian && !( pSoldier->ubBodyType == COW || pSoldier->ubBodyType == CRIPPLECIV || pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) && gTacticalStatus.bBoxingState == NOT_BOXING) { if ( FindAIUsableObjClass( pSoldier, IC_WEAPON ) == ITEM_NOT_FOUND ) @@ -2589,7 +2589,7 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK) } - if ( fCivilian && !( pSoldier->ubBodyType == COW || pSoldier->ubBodyType == CRIPPLECIV ) ) + if ( fCivilian && !( pSoldier->ubBodyType == COW || pSoldier->ubBodyType == CRIPPLECIV || pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) ) { if ( FindAIUsableObjClass( pSoldier, IC_WEAPON ) == ITEM_NOT_FOUND ) { @@ -3330,7 +3330,8 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK) } } - if ( !TANK( pSoldier ) ) + //if ( !TANK( pSoldier ) ) + if( ( gGameExternalOptions.fEnemyTanksCanMoveInTactical || !TANK( pSoldier ) ) && !( pSoldier->flags.uiStatusFlags & ( SOLDIER_DRIVER | SOLDIER_PASSENGER ) ) ) { DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"decideactionred: main red ai"); @@ -4385,6 +4386,11 @@ INT16 ubMinAPCost; // can this guy move to any of the neighbouring squares ? (sets TRUE/FALSE) ubCanMove = (pSoldier->bActionPoints >= MinPtsToMove(pSoldier)); + if( pSoldier->flags.uiStatusFlags & ( SOLDIER_DRIVER | SOLDIER_PASSENGER ) ) + { + ubCanMove = 0; + } + if ( (pSoldier->bTeam == ENEMY_TEAM || pSoldier->ubProfile == WARDEN) && (gTacticalStatus.fPanicFlags & PANIC_TRIGGERS_HERE) && (gTacticalStatus.ubTheChosenOne == NOBODY) ) { INT8 bPanicTrigger; @@ -4560,7 +4566,7 @@ INT16 ubMinAPCost; // offer surrender? #ifdef JA2UB #else - if ( pSoldier->bTeam == ENEMY_TEAM && pSoldier->bVisible == TRUE && !( gTacticalStatus.fEnemyFlags & ENEMY_OFFERED_SURRENDER ) && pSoldier->stats.bLife >= pSoldier->stats.bLifeMax / 2 ) + if ( pSoldier->bTeam == ENEMY_TEAM && pSoldier->bVisible == TRUE && !( gTacticalStatus.fEnemyFlags & ENEMY_OFFERED_SURRENDER ) && pSoldier->stats.bLife >= pSoldier->stats.bLifeMax / 2 && !TANK(pSoldier) ) { if ( gTacticalStatus.Team[ MILITIA_TEAM ].bMenInSector == 0 && gTacticalStatus.Team[ CREATURE_TEAM ].bMenInSector == 0 && NumPCsInSector() < 4 && gTacticalStatus.Team[ ENEMY_TEAM ].bMenInSector >= NumPCsInSector() * 3 ) { @@ -4601,7 +4607,7 @@ INT16 ubMinAPCost; { if (fCivilian) { - if ( ( bCanAttack == NOSHOOT_NOWEAPON) && !(pSoldier->flags.uiStatusFlags & SOLDIER_BOXER) && pSoldier->ubBodyType != COW && pSoldier->ubBodyType != CRIPPLECIV ) + if ( ( bCanAttack == NOSHOOT_NOWEAPON) && !(pSoldier->flags.uiStatusFlags & SOLDIER_BOXER) && pSoldier->ubBodyType != COW && pSoldier->ubBodyType != CRIPPLECIV && !(pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE) ) { // cower in fear!! if ( pSoldier->flags.uiStatusFlags & SOLDIER_COWERING ) @@ -4841,6 +4847,7 @@ INT16 ubMinAPCost; if(BestShot.ubFriendlyFireChance)//dnl ch61 180813 { + iChance = 0; if(BestShot.ubFriendlyFireChance == 100) { if(pSoldier->aiData.bAttitude == AGGRESSIVE) @@ -4973,7 +4980,7 @@ INT16 ubMinAPCost; // if the soldier does have a usable knife somewhere // 0verhaul: And is not a tank! - if (bWeaponIn != NO_SLOT && !TANK( pSoldier)) + if (bWeaponIn != NO_SLOT && !TANK( pSoldier) && !( pSoldier->flags.uiStatusFlags & ( SOLDIER_DRIVER | SOLDIER_PASSENGER ) ) ) { DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"try to stab"); BestStab.bWeaponIn = bWeaponIn; @@ -5041,7 +5048,7 @@ INT16 ubMinAPCost; } ///////////////////////////////////////////////////////////////////////////////////////////////////// // SANDRO - even if we don't have any blade, calculate how much damage we could do unarmed - else if ( !TANK( pSoldier) ) + else if ( !TANK( pSoldier) && !( pSoldier->flags.uiStatusFlags & ( SOLDIER_DRIVER | SOLDIER_PASSENGER ) ) ) { bWeaponIn = FindAIUsableObjClass( pSoldier, IC_PUNCH ); if (bWeaponIn == NO_SLOT) // if no punch-type weapon found, just calculate it with empty hands @@ -5497,7 +5504,7 @@ INT16 ubMinAPCost; } } #else - if(!TANK(pSoldier)) + if( gGameExternalOptions.fEnemyTanksCanMoveInTactical || !TANK(pSoldier) ) { // first get the direction, as we will need to pass that in to ShootingStanceChange bDirection = atan8(CenterX(pSoldier->sGridNo),CenterY(pSoldier->sGridNo),CenterX(BestAttack.sTarget),CenterY(BestAttack.sTarget)); @@ -5967,7 +5974,7 @@ L_NEWAIM: } // end of tank AI - if ( TANK( pSoldier ) ) + if( !gGameExternalOptions.fEnemyTanksCanMoveInTactical && TANK( pSoldier ) ) { return( AI_ACTION_NONE ); } @@ -6598,7 +6605,7 @@ void DecideAlertStatus( SOLDIERTYPE *pSoldier ) gubNPCPathCount = 0; - if ( TANK( pSoldier ) ) + if( !gGameExternalOptions.fEnemyTanksCanMoveInTactical && TANK( pSoldier ) ) { return( AI_ACTION_NONE ); } @@ -7110,7 +7117,7 @@ void DecideAlertStatus( SOLDIERTYPE *pSoldier ) } } - if ( TANK( pSoldier ) ) + if( !gGameExternalOptions.fEnemyTanksCanMoveInTactical && TANK( pSoldier ) ) { return( AI_ACTION_NONE ); } @@ -7269,7 +7276,7 @@ void DecideAlertStatus( SOLDIERTYPE *pSoldier ) // RADIO RED ALERT: determine %chance to call others and report contact //////////////////////////////////////////////////////////////////////////// - if ( !TANK( pSoldier ) ) + if( gGameExternalOptions.fEnemyTanksCanMoveInTactical || !TANK( pSoldier ) ) { DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"decideactionred: main red ai"); @@ -8450,7 +8457,7 @@ void DecideAlertStatus( SOLDIERTYPE *pSoldier ) } // end of tank AI - if ( TANK( pSoldier ) ) + if( gGameExternalOptions.fEnemyTanksCanMoveInTactical || TANK( pSoldier ) ) { return( AI_ACTION_NONE ); } diff --git a/lua/lua_strategic.cpp b/lua/lua_strategic.cpp index aa3c05d6..719a7a8b 100644 --- a/lua/lua_strategic.cpp +++ b/lua/lua_strategic.cpp @@ -157,8 +157,9 @@ static int LuaGroupCreate( lua_State *L ) UINT8 NumAdmins = (UINT8) luaL_checkinteger( L, 2); UINT8 NumTroops = (UINT8) luaL_checkinteger( L, 3); UINT8 NumElites = (UINT8) luaL_checkinteger( L, 4); + UINT8 NumTanks = (UINT8) luaL_checkinteger( L, 5); - GROUP *pGroup = CreateNewEnemyGroupDepartingFromSector( Sector, NumAdmins, NumTroops, NumElites ); + GROUP *pGroup = CreateNewEnemyGroupDepartingFromSector( Sector, NumAdmins, NumTroops, NumElites, NumTanks ); if (pGroup) { diff --git a/ub_config.cpp b/ub_config.cpp index 33f0d751..64d64187 100644 --- a/ub_config.cpp +++ b/ub_config.cpp @@ -103,6 +103,7 @@ UNDERGROUND_SECTORINFO *pSector; UINT8 ubNumAdmins = 0; UINT8 ubNumTroops = 0; UINT8 ubNumElites = 0; +UINT8 ubNumTanks = 0; if ( Level != 0 ) { @@ -117,25 +118,25 @@ UINT8 ubNumElites = 0; ubNumAdmins = Random( 0 ); ubNumTroops = 10 + Random( 5 ); ubNumElites = Random( 4 ); - SetNumberJa25EnemiesInSector( SectorX, SectorY, Level, ubNumAdmins, ubNumTroops, ubNumElites ); + SetNumberJa25EnemiesInSector( SectorX, SectorY, Level, ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks ); break; case DIF_LEVEL_MEDIUM: ubNumAdmins = Random( 0 ); ubNumTroops = 15 + Random( 8 ); ubNumElites = 1 + Random( 2 ); - SetNumberJa25EnemiesInSector( SectorX, SectorY, Level, ubNumAdmins, ubNumTroops, ubNumElites ); + SetNumberJa25EnemiesInSector( SectorX, SectorY, Level, ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks ); break; case DIF_LEVEL_HARD: ubNumAdmins = Random( 0 ); ubNumTroops = 20 + Random( 7 ); ubNumElites = 2 + Random( 2 ); - SetNumberJa25EnemiesInSector( SectorX, SectorY, Level, ubNumAdmins, ubNumTroops, ubNumElites ); + SetNumberJa25EnemiesInSector( SectorX, SectorY, Level, ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks ); break; case DIF_LEVEL_INSANE: ubNumAdmins = Random( 0 ); ubNumTroops = 20 + Random( 3 ); ubNumElites = 6 + Random( 3 ); - SetNumberJa25EnemiesInSector( SectorX, SectorY, Level, ubNumAdmins, ubNumTroops, ubNumElites ); + SetNumberJa25EnemiesInSector( SectorX, SectorY, Level, ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks ); break; } } @@ -151,25 +152,25 @@ UINT8 ubNumElites = 0; ubNumAdmins = Random( 0 ); ubNumTroops = 10 + Random( 5 ); ubNumElites = Random( 4 ); - SetNumberJa25EnemiesInSector( SectorX, SectorY, Level, ubNumAdmins, ubNumTroops, ubNumElites ); + SetNumberJa25EnemiesInSector( SectorX, SectorY, Level, ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks ); break; case DIF_LEVEL_MEDIUM: ubNumAdmins = Random( 0 ); ubNumTroops = 15 + Random( 8 ); ubNumElites = 1 + Random( 2 ); - SetNumberJa25EnemiesInSector( SectorX, SectorY, Level, ubNumAdmins, ubNumTroops, ubNumElites ); + SetNumberJa25EnemiesInSector( SectorX, SectorY, Level, ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks ); break; case DIF_LEVEL_HARD: ubNumAdmins = Random( 0 ); ubNumTroops = 23 + Random( 7); ubNumElites = 2 + Random( 2 ); - SetNumberJa25EnemiesInSector( SectorX, SectorY, Level, ubNumAdmins, ubNumTroops, ubNumElites ); + SetNumberJa25EnemiesInSector( SectorX, SectorY, Level, ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks ); break; case DIF_LEVEL_INSANE: ubNumAdmins = Random( 0 ); ubNumTroops = 20 + Random( 3 ); ubNumElites = 6 + Random( 3 ); - SetNumberJa25EnemiesInSector( SectorX, SectorY, Level, ubNumAdmins, ubNumTroops, ubNumElites ); + SetNumberJa25EnemiesInSector( SectorX, SectorY, Level, ubNumAdmins, ubNumTroops, ubNumElites, ubNumTanks ); break; } }