From 0e0d329b95997ea26463fe209e482e924db9b153 Mon Sep 17 00:00:00 2001 From: Sevenfm Date: Sun, 21 Feb 2021 13:18:04 +0000 Subject: [PATCH] New option DEFEAT_MODE: - 0: default, any lost battle is considered defeat - 1: if enemy team was alerted - 2: if at least one of retreating mercs is not covert - 3: if at least one merc was killed in battle - 4: if all mercs were killed in battle MORALE_RAN_AWAY: - apply penalty when retreating from sector only if enemy team was alerted - improved check for mercs in sector - no MORALE_HEARD_BATTLE_LOST penalty - no reputation loss when retreating from battle CheckForEndOfBattle: - only apply morale and loyalty penalty if player was defeated - only play death music if player is defeated - log defeat only when player was defeated - clear aware status for enemy team, clear enemy kill counter git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@8945 3b4a5df2-a311-0410-b5c6-a8a6f20db521 --- GameSettings.cpp | 2 +- GameSettings.h | 2 + Strategic/Strategic Town Loyalty.cpp | 12 ++- Tactical/Morale.cpp | 11 ++- Tactical/Overhead.cpp | 123 ++++++++++++++++++++------- 5 files changed, 111 insertions(+), 39 deletions(-) diff --git a/GameSettings.cpp b/GameSettings.cpp index 4370f876..89b83f75 100644 --- a/GameSettings.cpp +++ b/GameSettings.cpp @@ -1493,7 +1493,6 @@ void LoadGameExternalOptions() // Flugente/sevenfm: player-controlled mercs won't die instantly from most damage, instead they fall into a coma gGameExternalOptions.fReducedInstantDeath = iniReader.ReadBoolean("Tactical Gameplay Settings", "REDUCED_INSTANT_DEATH", FALSE); - // enable schedules and decision making for any named npc regardless of their team gGameExternalOptions.fAllNamedNpcsDecideAction = iniReader.ReadBoolean("Tactical Gameplay Settings", "ALL_NAMED_NPCS_DECIDE_ACTION", FALSE); @@ -1502,6 +1501,7 @@ void LoadGameExternalOptions() gGameExternalOptions.fEnemyJams = iniReader.ReadBoolean("Tactical Gameplay Settings", "ENEMY_JAMS", true, false); gGameExternalOptions.fNewRandom = iniReader.ReadBoolean("Tactical Gameplay Settings", "NEW_RANDOM", true, false); + gGameExternalOptions.ubDefeatMode = iniReader.ReadInteger("Tactical Gameplay Settings", "DEFEAT_MODE", 0, 0, 4); //################# Tactical Enemy Role Settings ################## // Flugente: enemy roles diff --git a/GameSettings.h b/GameSettings.h index d6fc519d..b98929e2 100644 --- a/GameSettings.h +++ b/GameSettings.h @@ -556,6 +556,8 @@ typedef struct BOOLEAN fEnemyJams; // use new code for random BOOLEAN fNewRandom; + // determine if battle was defeat + UINT8 ubDefeatMode; // WDS - Improve Tony's and Devin's inventory like BR's // silversurfer: not used anymore, see "Tactical\XML_Merchants.cpp" for "useBRSetting" diff --git a/Strategic/Strategic Town Loyalty.cpp b/Strategic/Strategic Town Loyalty.cpp index 9ff88927..6ff7bf81 100644 --- a/Strategic/Strategic Town Loyalty.cpp +++ b/Strategic/Strategic Town Loyalty.cpp @@ -2148,7 +2148,8 @@ UINT32 EnemyStrength( void ) void HandleLoyaltyImplicationsOfMercRetreat( INT8 bRetreatCode, INT16 sSectorX, INT16 sSectorY, INT16 sSectorZ ) { if ( NumNonPlayerTeamMembersInSector( sSectorX, sSectorY, MILITIA_TEAM ) ) - { //Big morale penalty! + { + //Big morale penalty! HandleGlobalLoyaltyEvent( GLOBAL_LOYALTY_ABANDON_MILITIA, sSectorX, sSectorY, (INT8)sSectorZ ); } @@ -2161,10 +2162,13 @@ void HandleLoyaltyImplicationsOfMercRetreat( INT8 bRetreatCode, INT16 sSectorX, UINT8 DiffLevel = gGameOptions.ubDifficultyLevel; if ( DiffLevel > DIF_LEVEL_INSANE ) DiffLevel = 1; - - if ( gTacticalStatus.fEnemyInSector && ( (PlayerStrength() * (2 + DiffLevel)) >= EnemyStrength() ) ) + + // sevenfm: if enemy was alerted + if (gTacticalStatus.fEnemyInSector && + gTacticalStatus.Team[ENEMY_TEAM].bAwareOfOpposition && + ((PlayerStrength() * (2 + DiffLevel)) >= EnemyStrength())) { - HandleMoraleEvent( NULL, MORALE_RAN_AWAY, sSectorX, sSectorY, (INT8)sSectorZ ); + HandleMoraleEvent(NULL, MORALE_RAN_AWAY, sSectorX, sSectorY, (INT8)sSectorZ); } } else diff --git a/Tactical/Morale.cpp b/Tactical/Morale.cpp index 3cee7bf0..c03dcf2e 100644 --- a/Tactical/Morale.cpp +++ b/Tactical/Morale.cpp @@ -791,8 +791,10 @@ void HandleMoraleEvent( SOLDIERTYPE *pSoldier, INT8 bMoraleEvent, INT16 sMapX, I { // CJC: adding to SOLDIER_IN_SECTOR check special stuff because the old sector values might // be appropriate (because in transit going out of that sector!) - - if ( SOLDIER_IN_SECTOR( pTeamSoldier, sMapX, sMapY, bMapZ ) || (pTeamSoldier->flags.fBetweenSectors && SECTORX( pTeamSoldier->ubPrevSectorID ) == sMapX && SECTORY( pTeamSoldier->ubPrevSectorID ) == sMapY && (pTeamSoldier->bSectorZ == bMapZ)) ) + // sevenfm: improved check + //if ( SOLDIER_IN_SECTOR( pTeamSoldier, sMapX, sMapY, bMapZ ) || (pTeamSoldier->flags.fBetweenSectors && SECTORX( pTeamSoldier->ubPrevSectorID ) == sMapX && SECTORY( pTeamSoldier->ubPrevSectorID ) == sMapY && (pTeamSoldier->bSectorZ == bMapZ)) ) + if (pTeamSoldier->bInSector || + pTeamSoldier->flags.fBetweenSectors && pTeamSoldier->sSectorX == gWorldSectorX && pTeamSoldier->sSectorY == gWorldSectorY && pTeamSoldier->bSectorZ == gbWorldSectorZ) { if ( gGameOptions.fNewTraitSystem ) { @@ -834,7 +836,8 @@ void HandleMoraleEvent( SOLDIERTYPE *pSoldier, INT8 bMoraleEvent, INT16 sMapX, I // SANDRO - Assertive people don't care about actions of others else if ( !gGameOptions.fNewTraitSystem || !DoesMercHavePersonality( pTeamSoldier, CHAR_TRAIT_ASSERTIVE ) ) { - HandleMoraleEventForSoldier( pTeamSoldier, MORALE_HEARD_BATTLE_LOST ); + // sevenfm: no MORALE_HEARD_BATTLE_LOST penalty fpr running from battle + //HandleMoraleEventForSoldier( pTeamSoldier, MORALE_HEARD_BATTLE_LOST ); } } } @@ -1079,6 +1082,8 @@ void HandleMoraleEvent( SOLDIERTYPE *pSoldier, INT8 bMoraleEvent, INT16 sMapX, I ModifyPlayerReputation(REPUTATION_BATTLE_WON); break; case MORALE_RAN_AWAY: + // sevenfm: no reputation loss when retreating from battle + break; case MORALE_HEARD_BATTLE_LOST: ModifyPlayerReputation(REPUTATION_BATTLE_LOST); break; diff --git a/Tactical/Overhead.cpp b/Tactical/Overhead.cpp index f16f1dbc..6fa470ee 100644 --- a/Tactical/Overhead.cpp +++ b/Tactical/Overhead.cpp @@ -7278,17 +7278,17 @@ void RemoveStaticEnemiesFromSectorInfo( INT16 sMapX, INT16 sMapY, INT8 bMapZ ) } } - //!!!! //IMPORTANT NEW NOTE: //Whenever returning TRUE, make sure you clear gfBlitBattleSectorLocator; BOOLEAN CheckForEndOfBattle( BOOLEAN fAnEnemyRetreated ) { SOLDIERTYPE *pTeamSoldier; - BOOLEAN fBattleWon = TRUE; - BOOLEAN fBattleLost = FALSE; - INT32 cnt = 0; - UINT16 usAnimState; + BOOLEAN fBattleWon = TRUE; + BOOLEAN fBattleLost = FALSE; + INT32 cnt = 0; + UINT16 usAnimState; + UINT16 usMapSector = gWorldSectorX + (gWorldSectorY * MAP_WORLD_X); if ( gTacticalStatus.bBoxingState == BOXING ) { @@ -7299,7 +7299,7 @@ BOOLEAN CheckForEndOfBattle( BOOLEAN fAnEnemyRetreated ) // OJW - 090212 - Fix end conditions for multiplayer - TeamDM if(is_server) { - // check the server's conditions for continueing the game, if the server wants to continue the game it returns true + // check the server's conditions for continuing the game, if the server wants to continue the game it returns true // hence we return false that the battle has ended. If not, when this function returns below we will force the game to end. if ( check_status() ) return(FALSE); @@ -7372,29 +7372,72 @@ BOOLEAN CheckForEndOfBattle( BOOLEAN fAnEnemyRetreated ) // We should NEVER have a battle lost and won at the same time... - if ( fBattleLost ) - { - // CJC: End AI's turn here.... first... so that UnSetUIBusy will succeed if militia win - // battle for us - EndAllAITurns( ); + if (fBattleLost) + { + // sevenfm: count alive/dead/not covert mercs in sector/retreating from sector + UINT8 ubLoop = gTacticalStatus.Team[gbPlayerNum].bFirstID; + BOOLEAN fFoundNotCovertMerc = FALSE; + BOOLEAN fFoundAliveMerc = FALSE; + BOOLEAN fFoundDeadMerc = FALSE; + for (pTeamSoldier = MercPtrs[ubLoop]; ubLoop <= gTacticalStatus.Team[gbPlayerNum].bLastID; ubLoop++, pTeamSoldier++) + { + if (pTeamSoldier->bActive) + { + if (pTeamSoldier->bInSector || + //pTeamSoldier->flags.fBetweenSectors && SECTORX(pTeamSoldier->ubPrevSectorID) == gWorldSectorX && SECTORY(pTeamSoldier->ubPrevSectorID) == gWorldSectorY && (pTeamSoldier->bSectorZ == gbWorldSectorZ) || + pTeamSoldier->flags.fBetweenSectors && pTeamSoldier->sSectorX == gWorldSectorX && pTeamSoldier->sSectorY == gWorldSectorY && pTeamSoldier->bSectorZ == gbWorldSectorZ) + { + if (pTeamSoldier->stats.bLife >= OKLIFE) + { + fFoundAliveMerc = TRUE; + if (!gGameOptions.fNewTraitSystem || !(pTeamSoldier->usSoldierFlagMask & (SOLDIER_COVERT_SOLDIER | SOLDIER_COVERT_CIV))) + { + fFoundNotCovertMerc = TRUE; + } + } + else + { + fFoundDeadMerc = TRUE; + } + } + } + } - // Set enemy presence to false - // This is safe 'cause we're about to unload the friggen sector anyway.... - gTacticalStatus.fEnemyInSector = FALSE; - // SANDRO - reset number of enemies here - memset( &(gTacticalStatus.bNumFoughtInBattle), 0, MAXTEAMS ); + BOOLEAN fDefeat = FALSE; - // If here, the battle has been lost! - UnSetUIBusy( (UINT8)gusSelectedSoldier ); + // sevenfm: determine if we should consider this as defeat + if (gGameExternalOptions.ubDefeatMode == 0 || + gGameExternalOptions.ubDefeatMode == 1 && gTacticalStatus.Team[ENEMY_TEAM].bAwareOfOpposition || + gGameExternalOptions.ubDefeatMode == 2 && fFoundNotCovertMerc || + gGameExternalOptions.ubDefeatMode == 3 && fFoundDeadMerc || + gGameExternalOptions.ubDefeatMode == 4 && !fFoundAliveMerc) + fDefeat = TRUE; - if ( gTacticalStatus.uiFlags & INCOMBAT ) - { - // Exit mode! - ExitCombatMode(); - } + // CJC: End AI's turn here.... first... so that UnSetUIBusy will succeed if militia win + // battle for us + EndAllAITurns(); - HandleMoraleEvent( NULL, MORALE_HEARD_BATTLE_LOST, gWorldSectorX, gWorldSectorY, gbWorldSectorZ ); - HandleGlobalLoyaltyEvent( GLOBAL_LOYALTY_BATTLE_LOST, gWorldSectorX, gWorldSectorY, gbWorldSectorZ ); + // Set enemy presence to false + // This is safe 'cause we're about to unload the friggen sector anyway.... + gTacticalStatus.fEnemyInSector = FALSE; + // SANDRO - reset number of enemies here + memset(&(gTacticalStatus.bNumFoughtInBattle), 0, MAXTEAMS); + + // If here, the battle has been lost! + UnSetUIBusy((UINT8)gusSelectedSoldier); + + if (gTacticalStatus.uiFlags & INCOMBAT) + { + // Exit mode! + ExitCombatMode(); + } + + // sevenfm: only apply morale and loyalty penalty if player was defeated + if (fDefeat) + { + HandleMoraleEvent(NULL, MORALE_HEARD_BATTLE_LOST, gWorldSectorX, gWorldSectorY, gbWorldSectorZ); + HandleGlobalLoyaltyEvent(GLOBAL_LOYALTY_BATTLE_LOST, gWorldSectorX, gWorldSectorY, gbWorldSectorZ); + } // SANDRO - end quest if cleared the sector after interrogation (sector N7 by Meduna) if ( gWorldSectorX == gModSettings.ubMeanwhileInterrogatePOWSectorX && gWorldSectorY == gModSettings.ubMeanwhileInterrogatePOWSectorY && @@ -7411,7 +7454,12 @@ BOOLEAN CheckForEndOfBattle( BOOLEAN fAnEnemyRetreated ) SetMusicModeID( MUSIC_TACTICAL_DEATH, MusicSoundValues[ SECTOR( gWorldSectorX, gWorldSectorY ) ].SoundTacticalDeath[gbWorldSectorZ] ); else #endif - SetMusicMode( MUSIC_TACTICAL_DEATH ); + + // sevenfm: only play death music if player is defeated + if (fDefeat) + SetMusicMode(MUSIC_TACTICAL_DEATH); + else + SetMusicMode(MUSIC_TACTICAL_NOTHING); SetCustomizableTimerCallbackAndDelay( 10000, DeathNoMessageTimerCallback, FALSE ); @@ -7436,11 +7484,14 @@ BOOLEAN CheckForEndOfBattle( BOOLEAN fAnEnemyRetreated ) SetThisSectorAsEnemyControlled( gWorldSectorX, gWorldSectorY, gbWorldSectorZ, TRUE ); } - // ATE: Important! THis is delayed until music ends so we can have proper effect! + // ATE: Important! This is delayed until music ends so we can have proper effect! // CheckAndHandleUnloadingOfCurrentWorld(); + // sevenfm: log defeat only when player was defeated + if (fDefeat) + LogBattleResults(LOG_DEFEAT); + //Whenever returning TRUE, make sure you clear gfBlitBattleSectorLocator; - LogBattleResults( LOG_DEFEAT ); gfBlitBattleSectorLocator = FALSE; // Flugente: in any case, reset creature attack variables @@ -7500,8 +7551,7 @@ BOOLEAN CheckForEndOfBattle( BOOLEAN fAnEnemyRetreated ) if ( gTacticalStatus.bBoxingState == NOT_BOXING ) // if boxing don't do any of this stuff { - - // Only do some stuff if we actually faught a battle + // Only do some stuff if we actually fought a battle if ( gTacticalStatus.bNumFoughtInBattle[ ENEMY_TEAM ] + gTacticalStatus.bNumFoughtInBattle[ CREATURE_TEAM ] + gTacticalStatus.bNumFoughtInBattle[ CIV_TEAM ] > 0 ) //if ( gTacticalStatus.bNumEnemiesFoughtInBattle > 0 ) { @@ -7540,7 +7590,8 @@ BOOLEAN CheckForEndOfBattle( BOOLEAN fAnEnemyRetreated ) pTeamSoldier->bStealthMode = FALSE; fInterfacePanelDirty = DIRTYLEVEL2; //DBrot: Stance change - if (gGameExternalOptions.fStandUpAfterBattle){ + if (gGameExternalOptions.fStandUpAfterBattle) + { if ( gAnimControl[ pTeamSoldier->usAnimState ].ubHeight != ANIM_STAND ) { pTeamSoldier->ChangeSoldierStance( ANIM_STAND ); @@ -7667,6 +7718,10 @@ BOOLEAN CheckForEndOfBattle( BOOLEAN fAnEnemyRetreated ) } } gTacticalStatus.Team[ MILITIA_TEAM ].bAwareOfOpposition = FALSE; + // sevenfm: clear aware status for enemy team + gTacticalStatus.Team[ENEMY_TEAM].bAwareOfOpposition = FALSE; + // sevenfm: also clear enemy kill counter + gTacticalStatus.ubArmyGuysKilled = 0; // Loop through all civs and restore them to peaceful status cnt = gTacticalStatus.Team[ CIV_TEAM ].bFirstID; @@ -7723,13 +7778,18 @@ BOOLEAN CheckForEndOfBattle( BOOLEAN fAnEnemyRetreated ) // Flugente: in any case, reset creature attack variables ResetCreatureAttackVariables(); + + // sevenfm: switch off radio + //SwitchOffAllRadio(); // If we are the server, we escape this function at the top if we think the game should still be running // hence if we get here the game is over for all clients and we should report it if (is_networked && is_server) game_over(); + return( TRUE ); } + // If we are the server, we escape this function at the top if we think the game should still be running // hence if we get here the game is over for all clients and we should report it if (is_networked && is_server) @@ -11785,3 +11845,4 @@ BOOLEAN IsFreeSlotAvailable( int aTeam ) return FALSE; } +