From 4b7258f8b3f386e0ca77597bc5bb37a2f539e6f8 Mon Sep 17 00:00:00 2001 From: Wanne Date: Thu, 28 Nov 2013 08:23:03 +0000 Subject: [PATCH] Updated Enemy Taunts (by anv) - fixed crash due to same enemy taunting several times in a row (e.g. after being hit by a burst) - prevent enemy from taunting again, before his previous taunt is finished - taunt .xmls should be kept in subdirectory TableData\EnemyTaunts\ to avoid mess in TableData\ - added , if TAUNT_CENSORED_MODE set to TRUE and defined, it will be displayed instead of git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@6659 3b4a5df2-a311-0410-b5c6-a8a6f20db521 --- GameSettings.cpp | 1 + GameSettings.h | 1 + Tactical/Civ Quotes.cpp | 108 ++++++++++++++++++++++++++-------------- Tactical/Interface.h | 1 + Tactical/XML.h | 2 +- Tactical/XML_Taunts.cpp | 10 ++++ 6 files changed, 85 insertions(+), 38 deletions(-) diff --git a/GameSettings.cpp b/GameSettings.cpp index 4667eedc..20bfd0e6 100644 --- a/GameSettings.cpp +++ b/GameSettings.cpp @@ -3206,6 +3206,7 @@ void LoadCTHConstants() void LoadTauntsSettings() { CIniReader iniReader(TAUNTS_SETTINGS_FILE); + gTauntsSettings.fTauntCensoredMode = iniReader.ReadBoolean("Taunts Settings","TAUNT_CENSORED_MODE", FALSE ); gTauntsSettings.fTauntShowPopupBox = iniReader.ReadBoolean("Taunts Settings","TAUNT_SHOW_POPUP_BOX", TRUE ); gTauntsSettings.fTauntShowInLog = iniReader.ReadBoolean("Taunts Settings","TAUNT_SHOW_IN_LOG", TRUE ); gTauntsSettings.fTauntMakeNoise = iniReader.ReadBoolean("Taunts Settings","TAUNT_MAKE_NOISE", TRUE ); diff --git a/GameSettings.h b/GameSettings.h index 4e903d9d..b109b680 100644 --- a/GameSettings.h +++ b/GameSettings.h @@ -1330,6 +1330,7 @@ typedef struct typedef struct { + BOOLEAN fTauntCensoredMode; BOOLEAN fTauntShowPopupBox; BOOLEAN fTauntShowInLog; BOOLEAN fTauntMakeNoise; diff --git a/Tactical/Civ Quotes.cpp b/Tactical/Civ Quotes.cpp index 77f6b41c..1855b7fc 100644 --- a/Tactical/Civ Quotes.cpp +++ b/Tactical/Civ Quotes.cpp @@ -45,6 +45,8 @@ #define HIGH_TOWN_LOYALTY 80 #define CIV_QUOTE_HINT 99 +#define MAX_APPLICABLE_TAUNTS 512 + extern void CaptureTimerCallback( void ); BOOLEAN gfSurrendered = FALSE; @@ -137,6 +139,11 @@ CHAR16 gzCivQuote[ 320 ]; UINT16 gusCivQuoteBoxWidth; UINT16 gusCivQuoteBoxHeight; +// anv: store times, when enemy taunt will be finished (so they won't taunt 50 times / second) +UINT32 uiTauntFinishTimes[ TOTAL_SOLDIERS ]; + +TAUNT_VALUES zApplicableTaunts[NUM_TAUNT]; + //-------------------------------------------------------------- void CopyNumEntriesIntoQuoteStruct( ) // Not used { @@ -1029,11 +1036,15 @@ BOOLEAN SaveCivQuotesToSaveGameFile( HWFILE hFile ) return( TRUE ); } +// anv: used now //is allowed remove. Not used and remove from SaveLoadGame.cpp. BOOLEAN LoadCivQuotesFromLoadGameFile( HWFILE hFile ) { UINT32 uiNumBytesRead; + // anv: reset uiTauntFinishTimes after game is loaded (so enemies can taunt after guiBaseJA2Clock is decreased) + memset( &uiTauntFinishTimes, 0, sizeof( uiTauntFinishTimes ) ); + FileRead( hFile, &gCivQuotes, sizeof( gCivQuotes ), &uiNumBytesRead ); if( uiNumBytesRead != sizeof( gCivQuotes ) ) { @@ -1062,6 +1073,12 @@ void PossiblyStartEnemyTaunt( SOLDIERTYPE *pCiv, TAUNTTYPE iTauntType, SOLDIERTY { return; } + // is enemy blocked from taunting at the moment? + if( uiTauntFinishTimes[pCiv->ubID] > GetJA2Clock() ) + { + + return; + } // check if generated person if ( !(IS_MERC_BODY_TYPE( pCiv )) || !(pCiv->ubProfile == NO_PROFILE) ) { @@ -1079,7 +1096,7 @@ void PossiblyStartEnemyTaunt( SOLDIERTYPE *pCiv, TAUNTTYPE iTauntType, SOLDIERTY return; } // only enemies that are able to speak at the moment can taunt - if ( pCiv->stats.bLife < OKLIFE || pCiv->bCollapsed ) + if ( pCiv->stats.bLife < OKLIFE || pCiv->bBreathCollapsed ) { return; } @@ -1248,13 +1265,9 @@ void PossiblyStartEnemyTaunt( SOLDIERTYPE *pCiv, TAUNTTYPE iTauntType, SOLDIERTY // SANDRO - soldier taunts void StartEnemyTaunt( SOLDIERTYPE *pCiv, TAUNTTYPE iTauntType, SOLDIERTYPE *pTarget ) { - UINT16 iTauntNumber; - CHAR16 sTauntText[320]; + CHAR16 sTauntText[ 320 ]; CHAR16 gzTauntQuote[ 320 ]; - TAUNT_VALUES zApplicableTaunts[1024]; UINT16 iApplicableTaunts = 0; - BOOLEAN fApplicableAttitude[6]; - #ifdef ENABLE_ZOMBIES // Flugente: zombies don't talk @@ -1262,11 +1275,12 @@ void StartEnemyTaunt( SOLDIERTYPE *pCiv, TAUNTTYPE iTauntType, SOLDIERTYPE *pTar return; #endif + // gCivQuoteData.bActive is checked in ShowTauntPopupBox() instead, taunt can be shown in log though! // if we have a different quote on, return, this one is not important - if ( gCivQuoteData.bActive ) - { - return; - } + //if ( gCivQuoteData.bActive ) + //{ + // return; + //} // anv: check all taunts, and remember those applicable for(UINT16 i=0; i= MAX_APPLICABLE_TAUNTS) + continue; } // are there any applicable taunts? if( iApplicableTaunts > 0 ) { // use random one - swprintf( sTauntText, zApplicableTaunts[ Random(iApplicableTaunts) ].szText ); + // use censored version if setting is set + UINT16 iChosenTaunt = Random(iApplicableTaunts); + if( gTauntsSettings.fTauntCensoredMode == TRUE && zApplicableTaunts[ iChosenTaunt ].szCensoredText[0] != 0 ) + { + swprintf( sTauntText, zApplicableTaunts[ iChosenTaunt ].szCensoredText ); + } + else + { + swprintf( sTauntText, zApplicableTaunts[ iChosenTaunt ].szText ); + } +#ifdef TAIWANESE + swprintf( gzTauntQuote, L"%s", sTauntText ); +#else + swprintf( gzTauntQuote, L"\"%s\"", sTauntText ); +#endif + + // block this enemy from taunting for a time being + uiTauntFinishTimes[pCiv->ubID] = GetJA2Clock() + min( gTauntsSettings.sMaxDelay , max( gTauntsSettings.sMinDelay, FindDelayForString( gzTauntQuote ) + gTauntsSettings.sModDelay ) ); + + if( gTauntsSettings.fTauntMakeNoise == TRUE ) + MakeNoise( pCiv->ubID, pCiv->sGridNo, pCiv->pathing.bLevel, pCiv->bOverTerrainType, gTauntsSettings.sVolume, NOISE_VOICE, gzTauntQuote ); + else + { + if(gTauntsSettings.fTauntShowPopupBox == TRUE) + { + if( gbPublicOpplist[gbPlayerNum][pCiv->ubID] == SEEN_CURRENTLY || gTauntsSettings.fTauntAlwaysShowPopupBox == TRUE ) + { + ShowTauntPopupBox( pCiv, gzTauntQuote ); + } + } + if(gTauntsSettings.fTauntShowInLog == TRUE) + { + if( gbPublicOpplist[gbPlayerNum][pCiv->ubID] == SEEN_CURRENTLY || gTauntsSettings.fTauntAlwaysShowInLog == TRUE ) + { + ScreenMsg( FONT_GRAY2, MSG_INTERFACE, L"%s: %s", pCiv->GetName(), gzTauntQuote ); + } + } + } } else { return; } -#ifdef TAIWANESE - swprintf( gzTauntQuote, L"%s", sTauntText ); -#else - swprintf( gzTauntQuote, L"\"%s\"", sTauntText ); -#endif - - if( gTauntsSettings.fTauntMakeNoise == TRUE ) - MakeNoise( pCiv->ubID, pCiv->sGridNo, pCiv->pathing.bLevel, pCiv->bOverTerrainType, gTauntsSettings.sVolume, NOISE_VOICE, gzTauntQuote ); - else - { - if(gTauntsSettings.fTauntShowPopupBox == TRUE) - { - if( gbPublicOpplist[gbPlayerNum][pCiv->ubID] == SEEN_CURRENTLY || gTauntsSettings.fTauntAlwaysShowPopupBox == TRUE ) - { - ShowTauntPopupBox( pCiv, gzTauntQuote ); - } - } - if(gTauntsSettings.fTauntShowInLog == TRUE) - { - if( gbPublicOpplist[gbPlayerNum][pCiv->ubID] == SEEN_CURRENTLY || gTauntsSettings.fTauntAlwaysShowInLog == TRUE ) - { - ScreenMsg( FONT_GRAY2, MSG_INTERFACE, L"%s: %s", pCiv->GetName(), gzTauntQuote ); - } - } - } } void ShowTauntPopupBox( SOLDIERTYPE *pCiv, STR16 gzTauntQuote ) @@ -1922,6 +1950,12 @@ void ShowTauntPopupBox( SOLDIERTYPE *pCiv, STR16 gzTauntQuote ) INT16 sScreenX, sScreenY; VIDEO_OVERLAY_DESC VideoOverlayDesc; + // stop if other civ quote is already being shown + if( gCivQuoteData.bActive == TRUE ) + { + return; + } + // Determine location... // Get location of civ on screen..... GetSoldierScreenPos( pCiv, &sScreenX, &sScreenY ); diff --git a/Tactical/Interface.h b/Tactical/Interface.h index 046f557c..a021d610 100644 --- a/Tactical/Interface.h +++ b/Tactical/Interface.h @@ -267,6 +267,7 @@ typedef struct { UINT16 uiIndex; CHAR16 szText[320]; + CHAR16 szCensoredText[320]; UINT64 uiFlags; UINT64 uiFlags2; INT16 value[TAUNT_MAX]; diff --git a/Tactical/XML.h b/Tactical/XML.h index b0e7a55b..46513251 100644 --- a/Tactical/XML.h +++ b/Tactical/XML.h @@ -238,7 +238,7 @@ typedef PARSE_STAGE; #define SQUADNAMEFILENAME "SquadNames.xml" #define BACKGROUNDSFILENAME "Backgrounds.xml" #define TAUNTSFILENAME "EnemyTaunts.xml" -#define TAUNTSFILENAMEBEGINNING "EnemyTaunts" +#define TAUNTSFILENAMEBEGINNING "EnemyTaunts\\EnemyTaunts" #define TAUNTSFILENAMEENDING ".xml" #define ENEMY_ADMIN_PROFILE_FILENAME "Profiles\\SoldierProfileEnemyAdmin.xml" diff --git a/Tactical/XML_Taunts.cpp b/Tactical/XML_Taunts.cpp index 964c3ba5..3c1dcdf0 100644 --- a/Tactical/XML_Taunts.cpp +++ b/Tactical/XML_Taunts.cpp @@ -55,6 +55,7 @@ tauntStartElementHandle(void *userData, const XML_Char *name, const XML_Char **a else if(pData->curElement == ELEMENT && (strcmp(name, "uiIndex") == 0 || strcmp(name, "szText") == 0 || + strcmp(name, "szCensoredText") == 0 || strcmp(name, "aggressive") == 0 || strcmp(name, "defensive") == 0 || @@ -233,6 +234,8 @@ tauntEndElementHandle(void *userData, const XML_Char *name) { MultiByteToWideChar( CP_UTF8, 0, pData->szCharData, -1, pData->curArray[pData->curTaunt.uiIndex].szText, sizeof(pData->curTaunt.szText)/sizeof(pData->curTaunt.szText[0]) ); pData->curArray[pData->curTaunt.uiIndex].szText[sizeof(pData->curTaunt.szText)/sizeof(pData->curTaunt.szText[0]) - 1] = '\0'; + MultiByteToWideChar( CP_UTF8, 0, pData->szCharData, -1, pData->curArray[pData->curTaunt.uiIndex].szCensoredText, sizeof(pData->curTaunt.szCensoredText)/sizeof(pData->curTaunt.szCensoredText[0]) ); + pData->curArray[pData->curTaunt.uiIndex].szCensoredText[sizeof(pData->curTaunt.szCensoredText)/sizeof(pData->curTaunt.szCensoredText[0]) - 1] = '\0'; } else { @@ -297,6 +300,13 @@ tauntEndElementHandle(void *userData, const XML_Char *name) MultiByteToWideChar( CP_UTF8, 0, pData->szCharData, -1, pData->curTaunt.szText, sizeof(pData->curTaunt.szText)/sizeof(pData->curTaunt.szText[0]) ); pData->curTaunt.szText[sizeof(pData->curTaunt.szText)/sizeof(pData->curTaunt.szText[0]) - 1] = '\0'; } + else if(strcmp(name, "szCensoredText") == 0 ) + { + pData->curElement = ELEMENT; + + MultiByteToWideChar( CP_UTF8, 0, pData->szCharData, -1, pData->curTaunt.szCensoredText, sizeof(pData->curTaunt.szCensoredText)/sizeof(pData->curTaunt.szCensoredText[0]) ); + pData->curTaunt.szCensoredText[sizeof(pData->curTaunt.szCensoredText)/sizeof(pData->curTaunt.szCensoredText[0]) - 1] = '\0'; + } else if(strcmp(name, "aggressive") == 0) { pData->curElement = ELEMENT;