diff --git a/GameSettings.cpp b/GameSettings.cpp index a9da1e405..701807bee 100644 --- a/GameSettings.cpp +++ b/GameSettings.cpp @@ -2834,6 +2834,7 @@ void LoadSkillTraitsExternalSettings() gSkillTraitValues.fCOTurncoats = iniReader.ReadBoolean( "Covert Ops", "COVERT_TURNCOATS", TRUE ); gSkillTraitValues.fCOTurncoats_SectorActivationRequiresRadioOperator = iniReader.ReadBoolean( "Covert Ops", "COVERT_TURNCOATS_SECTOR_ACTIVATION_REQUIRES_RADIOOPERATOR", FALSE ); gSkillTraitValues.sCOTurncoats_PlayerConvinctionBonus = iniReader.ReadInteger( "Covert Ops", "COVERT_TURNCOATS_PLAYER_CONVINCTION_BONUS", 0, -100, 100 ); + gSkillTraitValues.fCOTurncoatsActivateInAutoResolve = iniReader.ReadBoolean( "Covert Ops", "COVERT_TURNCOATS_ACTIVATE_IN_AUTORESOLVE", FALSE ); // Flugente: RADIO OPERATOR gSkillTraitValues.fROAllowArtillery = iniReader.ReadBoolean("Radio Operator","RADIO_OPERATOR_ARTILLERY", TRUE); diff --git a/GameSettings.h b/GameSettings.h index 23a2dfb0e..f1c5cc20b 100644 --- a/GameSettings.h +++ b/GameSettings.h @@ -2103,6 +2103,7 @@ typedef struct BOOLEAN fCOTurncoats; // can we create enemy turncoats that can be ordered to betray their comrades? BOOLEAN fCOTurncoats_SectorActivationRequiresRadioOperator; // activating turncoats sector-wide requires a radio operator INT32 sCOTurncoats_PlayerConvinctionBonus; + BOOLEAN fCOTurncoatsActivateInAutoResolve; // RADIO OPERATOR BOOLEAN fROAllowArtillery; // artillery can be forbidden for all teams with this setting diff --git a/Strategic/Auto Resolve.cpp b/Strategic/Auto Resolve.cpp index e848d4d39..0d13b4bf0 100644 --- a/Strategic/Auto Resolve.cpp +++ b/Strategic/Auto Resolve.cpp @@ -3107,6 +3107,8 @@ void CalculateAutoResolveInfo() } else { + ActivateTurncoatsForAutoResolve( gpAR->ubSectorX, gpAR->ubSectorY ); + GetNumberOfEnemiesInFiveSectors( gpAR->ubSectorX, gpAR->ubSectorY, &gpAR->ubAdmins, &gpAR->ubTroops, &gpAR->ubElites, &gpAR->ubRobots, &gpAR->ubTanks, &gpAR->ubJeeps ); diff --git a/Strategic/Queen Command.cpp b/Strategic/Queen Command.cpp index e1aa32621..be29421ff 100644 --- a/Strategic/Queen Command.cpp +++ b/Strategic/Queen Command.cpp @@ -3245,7 +3245,7 @@ BOOLEAN TurncoatsInSector( INT16 sSectorX, INT16 sSectorY ) return FALSE; } -bool RemoveOneTurncoat( INT16 sSectorX, INT16 sSectorY, UINT8 aSoldierClass ) +bool RemoveOneTurncoat( INT16 sSectorX, INT16 sSectorY, UINT8 aSoldierClass, BOOLEAN alsoRemoveFromGroup ) { // HEADROCK: This is a TEMPORARY fix to avoid the assertion error. Not sure this is the best solution, // probably isn't. But I need this bit to work. @@ -3315,14 +3315,20 @@ bool RemoveOneTurncoat( INT16 sSectorX, INT16 sSectorY, UINT8 aSoldierClass ) { case SOLDIER_CLASS_ADMINISTRATOR: pSector->ubNumAdmins_Turncoat--; + if (alsoRemoveFromGroup) + pSector->ubNumAdmins--; return true; break; case SOLDIER_CLASS_ARMY: pSector->ubNumTroops_Turncoat--; + if (alsoRemoveFromGroup) + pSector->ubNumTroops--; return true; break; case SOLDIER_CLASS_ELITE: pSector->ubNumElites_Turncoat--; + if (alsoRemoveFromGroup) + pSector->ubNumElites--; return true; break; default: @@ -3342,8 +3348,11 @@ bool RemoveOneTurncoat( INT16 sSectorX, INT16 sSectorY, UINT8 aSoldierClass ) if ( pGroup->pEnemyGroup->ubNumAdmins_Turncoat && pGroup->ubGroupSize && pGroup->pEnemyGroup->ubNumAdmins ) { pGroup->pEnemyGroup->ubNumAdmins_Turncoat--; - pGroup->pEnemyGroup->ubNumAdmins--; - pGroup->ubGroupSize--; + if (alsoRemoveFromGroup) + { + pGroup->pEnemyGroup->ubNumAdmins--; + pGroup->ubGroupSize--; + } return true; } break; @@ -3351,8 +3360,11 @@ bool RemoveOneTurncoat( INT16 sSectorX, INT16 sSectorY, UINT8 aSoldierClass ) if ( pGroup->pEnemyGroup->ubNumTroops_Turncoat && pGroup->ubGroupSize && pGroup->pEnemyGroup->ubNumTroops ) { pGroup->pEnemyGroup->ubNumTroops_Turncoat--; - pGroup->pEnemyGroup->ubNumTroops--; - pGroup->ubGroupSize--; + if (alsoRemoveFromGroup) + { + pGroup->pEnemyGroup->ubNumTroops--; + pGroup->ubGroupSize--; + } return true; } break; @@ -3360,8 +3372,11 @@ bool RemoveOneTurncoat( INT16 sSectorX, INT16 sSectorY, UINT8 aSoldierClass ) if ( pGroup->pEnemyGroup->ubNumElites_Turncoat && pGroup->ubGroupSize && pGroup->pEnemyGroup->ubNumElites ) { pGroup->pEnemyGroup->ubNumElites_Turncoat--; - pGroup->pEnemyGroup->ubNumElites--; - pGroup->ubGroupSize--; + if (alsoRemoveFromGroup) + { + pGroup->pEnemyGroup->ubNumElites--; + pGroup->ubGroupSize--; + } return true; } break; diff --git a/Strategic/Queen Command.h b/Strategic/Queen Command.h index 8b5dcea0f..541206d04 100644 --- a/Strategic/Queen Command.h +++ b/Strategic/Queen Command.h @@ -76,7 +76,7 @@ BOOLEAN CheckPendingNonPlayerTeam(UINT8 usTeam); // Flugente: turncoats UINT16 NumTurncoatsOfClassInSector( INT16 sSectorX, INT16 sSectorY, UINT8 aSoldierClass ); BOOLEAN TurncoatsInSector( INT16 sSectorX, INT16 sSectorY ); -bool RemoveOneTurncoat( INT16 sSectorX, INT16 sSectorY, UINT8 aSoldierClass ); +bool RemoveOneTurncoat( INT16 sSectorX, INT16 sSectorY, UINT8 aSoldierClass, BOOLEAN alsoRemoveFromGroup ); bool AddOneTurncoat( INT16 sSectorX, INT16 sSectorY, UINT8 aSoldierClass ); void CorrectTurncoatCount( INT16 sSectorX, INT16 sSectorY ); diff --git a/Strategic/Reinforcement.cpp b/Strategic/Reinforcement.cpp index e74d8b2aa..99bf11238 100644 --- a/Strategic/Reinforcement.cpp +++ b/Strategic/Reinforcement.cpp @@ -107,6 +107,59 @@ void GetNumberOfEnemiesInFiveSectors( INT16 sSectorX, INT16 sSectorY, UINT8 *pub } } +void ActivateTurncoatsForAutoResolve( INT16 sSectorX, INT16 sSectorY ) +{ + if (!gSkillTraitValues.fCOTurncoatsActivateInAutoResolve) + return; + + if (!gGameExternalOptions.gfAllowReinforcements) + return; + + if ( ( GetTownIdForSector( sSectorX, sSectorY ) == OMERTA )&& ( !zDiffSetting[gGameOptions.ubDifficultyLevel].bAllowReinforcementsOmerta ) ) //Madd: skip Omerta //Lal: but not on insane ;-) + return; + + UINT16 ubAdminTurncoats = NumTurncoatsOfClassInSector(sSectorX, sSectorY, SOLDIER_CLASS_ADMINISTRATOR); + UINT16 ubTroopTurncoats = NumTurncoatsOfClassInSector(sSectorX, sSectorY, SOLDIER_CLASS_ARMY); + UINT16 ubEliteTurncoats = NumTurncoatsOfClassInSector(sSectorX, sSectorY, SOLDIER_CLASS_ELITE); + + for (int i = 0; i < ubAdminTurncoats; ++i) RemoveOneTurncoat(sSectorX, sSectorY, SOLDIER_CLASS_ADMINISTRATOR, TRUE); + for (int i = 0; i < ubTroopTurncoats; ++i) RemoveOneTurncoat(sSectorX, sSectorY, SOLDIER_CLASS_ARMY, TRUE); + for (int i = 0; i < ubEliteTurncoats; ++i) RemoveOneTurncoat(sSectorX, sSectorY, SOLDIER_CLASS_ELITE, TRUE); + + StrategicAddMilitiaToSector(sSectorX, sSectorY, GREEN_MILITIA, ubAdminTurncoats); + StrategicAddMilitiaToSector(sSectorX, sSectorY, REGULAR_MILITIA, ubTroopTurncoats); + StrategicAddMilitiaToSector(sSectorX, sSectorY, ELITE_MILITIA, ubEliteTurncoats); + + UINT16 pusMoveDir[4][3]; //first column in this matrix is number of sector, except for 4th row + UINT8 ubDirNumber; + GenerateDirectionInfos( sSectorX, sSectorY, &ubDirNumber, pusMoveDir, FALSE, TRUE ); + + for (UINT8 i = 0; i < ubDirNumber; ++i) + { + GROUP* pGroup = gpGroupList; + while ( pGroup ) + { + if ( pGroup->usGroupTeam == ENEMY_TEAM && !pGroup->fVehicle && pGroup->ubSectorX == SECTORX(pusMoveDir[i][0]) && pGroup->ubSectorY == SECTORY(pusMoveDir[i][0]) ) + { + ubAdminTurncoats = pGroup->pEnemyGroup->ubNumAdmins_Turncoat; + ubTroopTurncoats = pGroup->pEnemyGroup->ubNumTroops_Turncoat; + ubEliteTurncoats = pGroup->pEnemyGroup->ubNumElites_Turncoat; + + for (int j = 0; j < ubAdminTurncoats; ++j) RemoveOneTurncoat(SECTORX(pusMoveDir[i][0]), SECTORY(pusMoveDir[i][0]), SOLDIER_CLASS_ADMINISTRATOR, TRUE); + for (int j = 0; j < ubTroopTurncoats; ++j) RemoveOneTurncoat(SECTORX(pusMoveDir[i][0]), SECTORY(pusMoveDir[i][0]), SOLDIER_CLASS_ARMY, TRUE); + for (int j = 0; j < ubEliteTurncoats; ++j) RemoveOneTurncoat(SECTORX(pusMoveDir[i][0]), SECTORY(pusMoveDir[i][0]), SOLDIER_CLASS_ELITE, TRUE); + + // since we're going directly to autoresolve, add miliita directly to sector after removing from a reinforcement group + StrategicAddMilitiaToSector(sSectorX, sSectorY, GREEN_MILITIA, ubAdminTurncoats); + StrategicAddMilitiaToSector(sSectorX, sSectorY, REGULAR_MILITIA, ubTroopTurncoats); + StrategicAddMilitiaToSector(sSectorX, sSectorY, ELITE_MILITIA, ubEliteTurncoats); + } + + pGroup = pGroup->next; + } + } +} + UINT8 NumEnemiesInFiveSectors( INT16 sMapX, INT16 sMapY ) { UINT8 ubNumAdmins, ubNumTroops, ubNumElites, ubNumRobots, ubNumTanks, ubNumJeeps; diff --git a/Strategic/Reinforcement.h b/Strategic/Reinforcement.h index 235f10673..87f3e645e 100644 --- a/Strategic/Reinforcement.h +++ b/Strategic/Reinforcement.h @@ -3,6 +3,7 @@ //For Autoresolve (mostly) void GetNumberOfEnemiesInFiveSectors( INT16 sSectorX, INT16 sSectorY, UINT8 *pubNumAdmins, UINT8 *pubNumTroops, UINT8 *pubNumElites, UINT8 *pubNumRobots, UINT8 *pubNumTanks, UINT8 *pubNumJeeps ); +void ActivateTurncoatsForAutoResolve( INT16 sSectorX, INT16 sSectorY ); 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/Tactical/Overhead.cpp b/Tactical/Overhead.cpp index 58fd266b9..8d45e49db 100644 --- a/Tactical/Overhead.cpp +++ b/Tactical/Overhead.cpp @@ -7281,7 +7281,7 @@ void RemoveCapturedEnemiesFromSectorInfo( INT16 sMapX, INT16 sMapY, INT8 bMapZ ) // Flugente: turncoats if ( pTeamSoldier->usSoldierFlagMask2 & SOLDIER_TURNCOAT ) - RemoveOneTurncoat( sMapX, sMapY, pTeamSoldier->ubSoldierClass ); + RemoveOneTurncoat( sMapX, sMapY, pTeamSoldier->ubSoldierClass, FALSE ); // Flugente: campaign stats gCurrentIncident.AddStat( pTeamSoldier, CAMPAIGNHISTORY_TYPE_PRISONER ); diff --git a/Tactical/Soldier Ani.cpp b/Tactical/Soldier Ani.cpp index fac4ca8f8..5c5e7387b 100644 --- a/Tactical/Soldier Ani.cpp +++ b/Tactical/Soldier Ani.cpp @@ -114,7 +114,7 @@ extern UINT8 gubInterruptProvoker; extern UINT16 PickSoldierReadyAnimation( SOLDIERTYPE *pSoldier, BOOLEAN fEndReady, BOOLEAN fHipStance ); -extern bool RemoveOneTurncoat( INT16 sSectorX, INT16 sSectorY, UINT8 aSoldierClass ); +extern bool RemoveOneTurncoat( INT16 sSectorX, INT16 sSectorY, UINT8 aSoldierClass, BOOLEAN alsoRemoveFromGroup ); extern void PlaySplashSound(INT32 sGridNo); // Animation code explanations! @@ -4212,7 +4212,7 @@ BOOLEAN HandleSoldierDeath( SOLDIERTYPE *pSoldier , BOOLEAN *pfMadeCorpse ) // Flugente: turncoats if ( pSoldier->usSoldierFlagMask2 & SOLDIER_TURNCOAT ) - RemoveOneTurncoat( pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->ubSoldierClass ); + RemoveOneTurncoat( pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->ubSoldierClass, FALSE ); // Flugente: additional dialogue if ( pSoldier->ubProfile != NO_PROFILE ) diff --git a/Tactical/Soldier Control.cpp b/Tactical/Soldier Control.cpp index 9adc7f0f4..fff1c7014 100644 --- a/Tactical/Soldier Control.cpp +++ b/Tactical/Soldier Control.cpp @@ -10286,7 +10286,7 @@ UINT8 SOLDIERTYPE::SoldierTakeDamage( INT8 bHeight, INT16 sLifeDeduct, INT16 sBr { this->usSoldierFlagMask2 &= ~SOLDIER_TURNCOAT; - RemoveOneTurncoat( this->sSectorX, this->sSectorY, this->ubSoldierClass ); + RemoveOneTurncoat( this->sSectorX, this->sSectorY, this->ubSoldierClass, FALSE ); } } @@ -21804,7 +21804,7 @@ BOOLEAN SOLDIERTYPE::OrderTurnCoatToSwitchSides( UINT16 usID ) { // remove turncoat property pSoldier->usSoldierFlagMask2 &= ~SOLDIER_TURNCOAT; - RemoveOneTurncoat( pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->ubSoldierClass ); + RemoveOneTurncoat( pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->ubSoldierClass, TRUE ); MakeCivHostile( pSoldier ); @@ -21834,7 +21834,7 @@ void SOLDIERTYPE::OrderAllTurnCoatToSwitchSides() { // remove turncoat property pSoldier->usSoldierFlagMask2 &= ~SOLDIER_TURNCOAT; - RemoveOneTurncoat( pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->ubSoldierClass ); + RemoveOneTurncoat( pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->ubSoldierClass, TRUE ); MakeCivHostile( pSoldier ); }