From 899d0f15a0ecda8283d86479ecc2549f572fb104 Mon Sep 17 00:00:00 2001 From: Wanne Date: Sun, 10 Nov 2013 08:26:05 +0000 Subject: [PATCH] New Feature: Externalized Enemy taunts (by anv) - Taunts will be shown in the tactica log, once enabled (TAUNT_SHOW_IN_LOG = TRUE) - Enemies will randomly choose their taunt from an pool of applicable ones - All taunts can be stored in TableData/EnemyTaunts.xml - see: http://www.bears-pit.com/board/ubbthreads.php/topics/327830/Externalised_taunts.html#Post327830 git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@6575 3b4a5df2-a311-0410-b5c6-a8a6f20db521 --- GameSettings.cpp | 26 + GameSettings.h | 25 + Init.cpp | 6 + MainMenuScreen.cpp | 2 + Tactical/Civ Quotes.cpp | 554 +++++++++++++++++-- Tactical/Civ Quotes.h | 7 +- Tactical/Interface.cpp | 2 + Tactical/Interface.h | 70 +++ Tactical/Soldier Control.cpp | 2 + Tactical/Soldier Control.h | 50 ++ Tactical/Tactical_VS2005.vcproj | 8 +- Tactical/Tactical_VS2008.vcproj | 4 + Tactical/Tactical_VS2010.vcxproj | 1 + Tactical/Tactical_VS2010.vcxproj.filters | 3 + Tactical/Weapons.cpp | 20 +- Tactical/XML.h | 5 + Tactical/XML_Taunts.cpp | 660 +++++++++++++++++++++++ Tactical/opplist.cpp | 5 +- TacticalAI/AIMain.cpp | 72 ++- Utils/Encrypted File.cpp | 38 ++ Utils/Encrypted File.h | 1 + gameloop.cpp | 2 + 22 files changed, 1485 insertions(+), 78 deletions(-) create mode 100644 Tactical/XML_Taunts.cpp diff --git a/GameSettings.cpp b/GameSettings.cpp index 3509c195..a09b352a 100644 --- a/GameSettings.cpp +++ b/GameSettings.cpp @@ -67,6 +67,9 @@ // silversurfer: Modifiers for item properties ( thresholds, range, damage, armor etc.) #define ITEM_SETTINGS_FILE "Item_Settings.ini" +// anv: externalised taunt settings +#define TAUNTS_SETTINGS_FILE "Taunts_Settings.ini" + #define CD_ROOT_DIR "DATA\\" GAME_SETTINGS gGameSettings; @@ -74,6 +77,7 @@ GAME_OPTIONS gGameOptions; // Snap: Options read from an INI file in the default of custom Data directory GAME_EXTERNAL_OPTIONS gGameExternalOptions; SKILL_TRAIT_VALUES gSkillTraitValues; // SANDRO - added this one +TAUNTS_SETTINGS gTauntsSettings; CTH_CONSTANTS gGameCTHConstants; // HEADROCK HAM 4: CTH constants MOD_SETTINGS gModSettings; //DBrot: mod specific settings @@ -3155,6 +3159,28 @@ void LoadCTHConstants() gGameCTHConstants.MAX_EFFECTIVE_USE_GRADIENT = iniReader.ReadBoolean("Shooting Mechanism","MAX_EFFECTIVE_USE_GRADIENT", FALSE ); } +void LoadTauntsSettings() +{ + CIniReader iniReader(TAUNTS_SETTINGS_FILE); + gTauntsSettings.fTauntShowInLog = iniReader.ReadBoolean("Taunts Settings","TAUNT_SHOW_IN_LOG", TRUE ); + gTauntsSettings.sModDelay = iniReader.ReadInteger("Taunts Settings","TAUNT_MIN_DELAY",100, -32767, 32767 ); + gTauntsSettings.sMinDelay = iniReader.ReadInteger("Taunts Settings","TAUNT_MIN_DELAY",500, 0, 65535 ); + gTauntsSettings.sMaxDelay = iniReader.ReadInteger("Taunts Settings","TAUNT_MAX_DELAY",5000, 0, 65535 ); + gTauntsSettings.ubTauntFireGunChance = iniReader.ReadInteger("Taunts Settings","TAUNT_FIRE_GUN_CHANCE",12, 0, 100); + gTauntsSettings.ubTauntFireLauncherChance = iniReader.ReadInteger("Taunts Settings","TAUNT_FIRE_LAUNCHER_CHANCE",25, 0, 100); + gTauntsSettings.ubTauntThrowKnifeChance = iniReader.ReadInteger("Taunts Settings","TAUNT_THROW_KNIFE_CHANCE",33, 0, 100); + gTauntsSettings.ubTauntThrowGrenadeChance = iniReader.ReadInteger("Taunts Settings","TAUNT_THROW_GRENADE_CHANCE",33, 0, 100); + gTauntsSettings.ubTauntChargeKnifeChance = iniReader.ReadInteger("Taunts Settings","TAUNT_CHARGE_KNIFE_CHANCE",25, 0, 100); + gTauntsSettings.ubTauntChargeFistsChance = iniReader.ReadInteger("Taunts Settings","TAUNT_CHARGE_FISTS_CHANCE",25, 0, 100); + gTauntsSettings.ubTauntStealChance = iniReader.ReadInteger("Taunts Settings","TAUNT_STEAL_CHANCE",25, 0, 100); + gTauntsSettings.ubTauntRunAwayChance = iniReader.ReadInteger("Taunts Settings","TAUNT_RUN_AWAY_CHANCE",20, 0, 100); + gTauntsSettings.ubTauntSeekNoiseChance = iniReader.ReadInteger("Taunts Settings","TAUNT_SEEK_NOISE_CHANCE",33, 0, 100); + gTauntsSettings.ubTauntAlertChance = iniReader.ReadInteger("Taunts Settings","TAUNT_ALERT_CHANCE",33, 0, 100); + gTauntsSettings.ubTauntGotHitChance = iniReader.ReadInteger("Taunts Settings","TAUNT_GOT_HIT_CHANCE",25, 0, 100); + gTauntsSettings.ubTauntGotMissedChance = iniReader.ReadInteger("Taunts Settings","TAUNT_GOT_MISSED_CHANCE",12, 0, 100); + gTauntsSettings.ubTauntNoticedUnseenChance = iniReader.ReadInteger("Taunts Settings","TAUNT_NOTICED_UNSEEN_MERC_CHANCE",10, 0, 100); + +} void FreeGameExternalOptions() { if (gGameExternalOptions.iaIMPSlots != NULL) // OJW - 20081129 - Fix memory leak when calling LoadGameExternalOptions twice diff --git a/GameSettings.h b/GameSettings.h index 23074963..93e3a583 100644 --- a/GameSettings.h +++ b/GameSettings.h @@ -1320,6 +1320,28 @@ typedef struct } GAME_EXTERNAL_OPTIONS; +typedef struct +{ + BOOLEAN fTauntShowInLog; + INT16 sModDelay; + UINT16 sMinDelay; + UINT16 sMaxDelay; + UINT8 ubTauntFireGunChance; + UINT8 ubTauntFireLauncherChance; + UINT8 ubTauntThrowKnifeChance; + UINT8 ubTauntThrowGrenadeChance; + UINT8 ubTauntChargeKnifeChance; + UINT8 ubTauntChargeFistsChance; + UINT8 ubTauntStealChance; + UINT8 ubTauntRunAwayChance; + UINT8 ubTauntSeekNoiseChance; + UINT8 ubTauntAlertChance; + UINT8 ubTauntGotHitChance; + UINT8 ubTauntGotMissedChance; + UINT8 ubTauntNoticedUnseenChance; + +} TAUNTS_SETTINGS; + typedef struct { UINT8 ubMaxNumberOfTraits; @@ -1998,6 +2020,8 @@ extern GAME_EXTERNAL_OPTIONS gGameExternalOptions; extern SKILL_TRAIT_VALUES gSkillTraitValues; // SANDRO - added this one +extern TAUNTS_SETTINGS gTauntsSettings; + // HEADROCK HAM 4: CTH constants read from a separate INI file extern CTH_CONSTANTS gGameCTHConstants; @@ -2014,6 +2038,7 @@ void LoadItemSettings(); // silversurfer: reads item property modifiers void LoadGameAPBPConstants(); // HEADROCK HAM 4: Read CTH/Shooting coefficients from file void LoadCTHConstants(); +void LoadTauntsSettings(); void FreeGameExternalOptions(); void InitGameOptions(); diff --git a/Init.cpp b/Init.cpp index 2c6e73ad..97948593 100644 --- a/Init.cpp +++ b/Init.cpp @@ -1003,6 +1003,12 @@ BOOLEAN LoadExternalGameplayData(STR directoryName) DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); SGP_THROW_IFFALSE(ReadInBackgrounds(fileName,FALSE), BACKGROUNDSFILENAME); + // Externalised taunts + strcpy(fileName, directoryName); + strcat(fileName, TAUNTSFILENAME); + DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("LoadExternalGameplayData, fileName = %s", fileName)); + SGP_THROW_IFFALSE(ReadInTaunts(fileName,FALSE), TAUNTSFILENAME); + //Madd: Simple localization // The idea here is that we can have a separate xml file that's named differently // but only contains the relevant tags that need to be localized diff --git a/MainMenuScreen.cpp b/MainMenuScreen.cpp index 6933a115..88a9cf6f 100644 --- a/MainMenuScreen.cpp +++ b/MainMenuScreen.cpp @@ -383,6 +383,8 @@ void InitDependingGameStyleOptions() LoadSkillTraitsExternalSettings(); // HEADROCK HAM 4: CTH constants LoadCTHConstants(); + // Load externalised taunts settings + LoadTauntsSettings(); #ifdef JA2UB LoadGameUBOptions(); // JA25 UB diff --git a/Tactical/Civ Quotes.cpp b/Tactical/Civ Quotes.cpp index c2db386f..a1ab1dfc 100644 --- a/Tactical/Civ Quotes.cpp +++ b/Tactical/Civ Quotes.cpp @@ -35,6 +35,10 @@ #endif #include "connect.h" +// for enemy taunts +#include "Soldier Profile.h" +#include "Campaign.h" + #define DIALOGUE_DEFAULT_WIDTH 200 #define EXTREAMLY_LOW_TOWN_LOYALTY 20 #define HIGH_TOWN_LOYALTY 80 @@ -1041,16 +1045,84 @@ BOOLEAN LoadCivQuotesFromLoadGameFile( HWFILE hFile ) } //-------------------------------------------------------------- +// anv: start enemy taunt with probabilty depending on taunt settings +void PossiblyStartEnemyTaunt( SOLDIERTYPE *pCiv, INT8 iTauntType, SOLDIERTYPE *pTarget ) +{ + switch(iTauntType) + { + case TAUNT_FIRE_GUN: + if( Random(100) > gTauntsSettings.ubTauntFireGunChance ) + return; + break; + case TAUNT_FIRE_LAUNCHER: + if( Random(100) > gTauntsSettings.ubTauntFireLauncherChance ) + return; + break; + case TAUNT_THROW: + if( Random(100) > gTauntsSettings.ubTauntThrowKnifeChance ) + return; + break; + case TAUNT_CHARGE_KNIFE: + if( Random(100) > gTauntsSettings.ubTauntChargeKnifeChance ) + return; + break; + case TAUNT_CHARGE_FISTS: + if( Random(100) > gTauntsSettings.ubTauntChargeFistsChance ) + return; + break; + case TAUNT_STEAL: + if( Random(100) > gTauntsSettings.ubTauntStealChance ) + return; + break; + case TAUNT_RUN_AWAY: + if( Random(100) > gTauntsSettings.ubTauntRunAwayChance) + return; + break; + case TAUNT_SEEK_NOISE: + if( Random(100) > gTauntsSettings.ubTauntSeekNoiseChance ) + return; + break; + case TAUNT_ALERT: + if( Random(100) > gTauntsSettings.ubTauntAlertChance ) + return; + break; + case TAUNT_GOT_HIT: + if( Random(100) > gTauntsSettings.ubTauntGotHitChance ) + return; + break; + case TAUNT_NOTICED_UNSEEN_MERC: + if( Random(100) > gTauntsSettings.ubTauntNoticedUnseenChance ) + return; + break; + case TAUNT_THROW_GRENADE: + if( Random(100) > gTauntsSettings.ubTauntThrowGrenadeChance ) + return; + break; + case TAUNT_GOT_MISSED: + if( Random(100) > gTauntsSettings.ubTauntGotMissedChance ) + return; + break; + default: + break; + } + StartEnemyTaunt( pCiv, iTauntType, pTarget ); +} + // SANDRO - soldier taunts -void StartEnemyTaunt( SOLDIERTYPE *pCiv, INT8 iTauntType ) +void StartEnemyTaunt( SOLDIERTYPE *pCiv, INT8 iTauntType, SOLDIERTYPE *pTarget ) { INT16 sX, sY; UINT8 ubEntryID = 0; INT16 sScreenX, sScreenY; UINT16 iTauntNumber; - STR16 sTauntText; + CHAR16 sTauntText[320]; VIDEO_OVERLAY_DESC VideoOverlayDesc; CHAR16 gzTauntQuote[ 320 ]; + CHAR pFileName[320] = "NPCData\\TauntsEdt\\"; + TAUNT_VALUES zApplicableTaunts[1024]; + UINT16 iApplicableTaunts = 0; + BOOLEAN fApplicableAttitude[6]; + #ifdef ENABLE_ZOMBIES // Flugente: zombies don't talk @@ -1064,47 +1136,435 @@ void StartEnemyTaunt( SOLDIERTYPE *pCiv, INT8 iTauntType ) return; } - switch(iTauntType) + // anv: check all taunts, and remember those applicable + for(UINT16 i=1; iaiData.bAttitude ) + { + case CUNNINGAID: + if( !(zTaunt[ i ].uiFlags & TAUNT_A_CUNNING_AID) ) + continue; + break; + case CUNNINGSOLO: + if( !(zTaunt[ i ].uiFlags & TAUNT_A_CUNNING_SOLO) ) + continue; + break; + case BRAVEAID: + if( !(zTaunt[ i ].uiFlags & TAUNT_A_BRAVE_AID) ) + continue; + case BRAVESOLO: + if( !(zTaunt[ i ].uiFlags & TAUNT_A_BRAVE_SOLO) ) + continue; + break; + case DEFENSIVE: + if( !(zTaunt[ i ].uiFlags & TAUNT_A_DEFENSIVE) ) + continue; + break; + case AGGRESSIVE: + if( !(zTaunt[ i ].uiFlags & TAUNT_A_AGGRESSIVE) ) + continue; + break; + default: + break; + } + // check if situation is ok + switch(iTauntType) + { + case TAUNT_FIRE_GUN: + if( !(zTaunt[ i ].uiFlags & TAUNT_S_FIRE_GUN) ) + continue; + break; + case TAUNT_FIRE_LAUNCHER: + if( !(zTaunt[ i ].uiFlags & TAUNT_S_FIRE_LAUNCHER) ) + continue; + break; + case TAUNT_THROW: + if( !(zTaunt[ i ].uiFlags & TAUNT_S_THROW_KNIFE) ) + continue; + break; + case TAUNT_CHARGE_KNIFE: + if( !(zTaunt[ i ].uiFlags & TAUNT_S_CHARGE_KNIFE) ) + continue; + break; + case TAUNT_CHARGE_FISTS: + if( !(zTaunt[ i ].uiFlags & TAUNT_S_CHARGE_FISTS) ) + continue; + break; + case TAUNT_STEAL: + if( !(zTaunt[ i ].uiFlags & TAUNT_S_STEAL) ) + continue; + break; + case TAUNT_RUN_AWAY: + if( !(zTaunt[ i ].uiFlags & TAUNT_S_RUN_AWAY) ) + continue; + break; + case TAUNT_SEEK_NOISE: + if( !(zTaunt[ i ].uiFlags & TAUNT_S_SEEK_NOISE) ) + continue; + break; + case TAUNT_ALERT: + if( !(zTaunt[ i ].uiFlags & TAUNT_S_ALERT) ) + continue; + break; + case TAUNT_GOT_HIT: + if( !(zTaunt[ i ].uiFlags & TAUNT_S_GOT_HIT) ) + continue; + break; + case TAUNT_NOTICED_UNSEEN_MERC: + if( !(zTaunt[ i ].uiFlags & TAUNT_S_NOTICED_UNSEEN) ) + continue; + break; + case TAUNT_THROW_GRENADE: + if( !(zTaunt[ i ].uiFlags & TAUNT_S_THROW_GRENADE) ) + continue; + break; + case TAUNT_GOT_MISSED: + if( !(zTaunt[ i ].uiFlags & TAUNT_S_GOT_MISSED) ) + continue; + break; + default: + return; + break; + } + + // class and predefined profiles + switch( pCiv->ubSoldierClass ) + { + case SOLDIER_CLASS_ADMINISTRATOR: + if( !(zTaunt[ i ].uiFlags & TAUNT_C_ADMIN) ) + continue; + if( (zTaunt[ i ].value[TAUNT_PROFILE_ADMIN] != -1 ) && !(zTaunt[ i ].value[TAUNT_PROFILE_ADMIN] == pCiv->usSoldierProfile ) ) + continue; + break; + case SOLDIER_CLASS_ARMY: + if( !(zTaunt[ i ].uiFlags & TAUNT_C_ARMY) ) + continue; + if( (zTaunt[ i ].value[TAUNT_PROFILE_ARMY] != -1 ) && !(zTaunt[ i ].value[TAUNT_PROFILE_ARMY] == pCiv->usSoldierProfile ) ) + continue; + break; + case SOLDIER_CLASS_ELITE: + if( !(zTaunt[ i ].uiFlags & TAUNT_C_ELITE) ) + continue; + if( (zTaunt[ i ].value[TAUNT_PROFILE_ELITE] != -1 ) && !(zTaunt[ i ].value[TAUNT_PROFILE_ELITE] == pCiv->usSoldierProfile ) ) + continue; + break; + case SOLDIER_CLASS_GREEN_MILITIA: + if( !(zTaunt[ i ].uiFlags & TAUNT_C_GREEN) ) + continue; + if( (zTaunt[ i ].value[TAUNT_PROFILE_GREEN] != -1 ) && !( zTaunt[ i ].value[TAUNT_PROFILE_GREEN] == pCiv->usSoldierProfile ) ) + continue; + break; + case SOLDIER_CLASS_REG_MILITIA: + if( !(zTaunt[ i ].uiFlags & TAUNT_C_REGULAR) ) + continue; + if( (zTaunt[ i ].value[TAUNT_PROFILE_ARMY] != -1 ) && !(zTaunt[ i ].value[TAUNT_PROFILE_ARMY] == pCiv->usSoldierProfile ) ) + continue; + break; + case SOLDIER_CLASS_ELITE_MILITIA: + if( !(zTaunt[ i ].uiFlags & TAUNT_C_VETERAN) ) + continue; + if( (zTaunt[ i ].value[TAUNT_PROFILE_ARMY] != -1 ) && !(zTaunt[ i ].value[TAUNT_PROFILE_ARMY] == pCiv->usSoldierProfile ) ) + continue; + break; + default: + return; + break; + } + + // gender + switch( pCiv->ubBodyType ) + { + case REGMALE: + case BIGMALE: + case STOCKYMALE: + if( !(zTaunt[ i ].uiFlags & TAUNT_G_MALE) ) + continue; + break; + case REGFEMALE: + if( !(zTaunt[ i ].uiFlags & TAUNT_G_FEMALE) ) + continue; + break; + default: + return; + break; + } + + // energy, health + if( zTaunt[ i ].value[TAUNT_ENERGY_GT] != -1 ) + { + if( pCiv->bBreath <= zTaunt[ i ].value[TAUNT_ENERGY_GT] ) + continue; + } + if( zTaunt[ i ].value[TAUNT_ENERGY_LT] != -1 ) + { + if( pCiv->bBreath >= zTaunt[ i ].value[TAUNT_ENERGY_LT] ) + continue; + } + if( zTaunt[ i ].value[TAUNT_ENERGY_MAX_GT] != -1 ) + { + if( pCiv->bBreathMax <= zTaunt[ i ].value[TAUNT_ENERGY_MAX_GT] ) + continue; + } + if( zTaunt[ i ].value[TAUNT_ENERGY_MAX_LT] != -1 ) + { + if( pCiv->bBreathMax >= zTaunt[ i ].value[TAUNT_ENERGY_MAX_LT] ) + continue; + } + if( zTaunt[ i ].value[TAUNT_HEALTH_GT] != -1 ) + { + if( pCiv->stats.bLife <= zTaunt[ i ].value[TAUNT_HEALTH_GT] ) + continue; + } + if( zTaunt[ i ].value[TAUNT_HEALTH_GT] != -1 ) + { + if( pCiv->stats.bLife <= zTaunt[ i ].value[TAUNT_TARGET_HEALTH_GT] ) + continue; + } + if( zTaunt[ i ].value[TAUNT_HEALTH_LT] != -1 ) + { + if( pCiv->stats.bLife >= zTaunt[ i ].value[TAUNT_HEALTH_LT] ) + continue; + } + if( zTaunt[ i ].value[TAUNT_HEALTH_MAX_GT] != -1 ) + { + if( pCiv->stats.bLifeMax <= zTaunt[ i ].value[TAUNT_HEALTH_MAX_GT] ) + continue; + } + if( zTaunt[ i ].value[TAUNT_HEALTH_MAX_LT] != -1 ) + { + if( pCiv->stats.bLifeMax >= zTaunt[ i ].value[TAUNT_HEALTH_MAX_LT] ) + continue; + } + // morale + if( zTaunt[ i ].value[TAUNT_MORALE_GT] != -1 ) + { + if( pCiv->aiData.bMorale <= zTaunt[ i ].value[TAUNT_MORALE_GT] ) + continue; + } + if( zTaunt[ i ].value[TAUNT_MORALE_LT] != -1 ) + { + if( pCiv->aiData.bMorale >= zTaunt[ i ].value[TAUNT_MORALE_LT] ) + continue; + } + // experience + if( zTaunt[ i ].value[TAUNT_EXP_LEVEL_GT] != -1 ) + { + if( pCiv->stats.bExpLevel <= zTaunt[ i ].value[TAUNT_EXP_LEVEL_GT] ) + continue; + } + if( zTaunt[ i ].value[TAUNT_TARGET_EXP_LEVEL_LT] != -1 ) + { + if( pCiv->stats.bExpLevel >= zTaunt[ i ].value[TAUNT_TARGET_EXP_LEVEL_LT] ) + continue; + } + + // game progress + if( zTaunt[ i ].value[TAUNT_PROGRESS_GT] != -1 ) + { + if( zTaunt[ i ].value[TAUNT_PROGRESS_GT] >= CurrentPlayerProgressPercentage() ) + continue; + } + if( zTaunt[ i ].value[TAUNT_PROGRESS_LT] != -1 ) + { + if( zTaunt[ i ].value[TAUNT_PROGRESS_GT] <= CurrentPlayerProgressPercentage() ) + continue; + } + + // facts + if( zTaunt[ i ].value[TAUNT_FACT_TRUE] != -1 ) + { + if( gubFact[ zTaunt[ i ].value[TAUNT_FACT_TRUE] ] != TRUE ) + continue; + } + if( zTaunt[ i ].value[TAUNT_FACT_FALSE] != -1 ) + { + if( gubFact[ zTaunt[ i ].value[TAUNT_FACT_FALSE] ] != FALSE ) + continue; + } + + // target limitations + if( pTarget != NULL ) + { + // target merc profile + if( zTaunt[ i ].value[TAUNT_TARGET_MERC_PROFILE] != -1 ) + { + if( pTarget->ubProfile != zTaunt[ i ].value[TAUNT_TARGET_MERC_PROFILE] ) + continue; + } + // target type + if( zTaunt[ i ].value[TAUNT_TARGET_TYPE] != -1 ) + { + if( pTarget->ubProfile != zTaunt[ i ].value[TAUNT_TARGET_TYPE] ) + continue; + } + // target gender + switch( pTarget->ubBodyType ) + { + case REGMALE: + case BIGMALE: + case STOCKYMALE: + if( !(zTaunt[ i ].uiFlags & TAUNT_T_MALE) ) + continue; + break; + case REGFEMALE: + if( !(zTaunt[ i ].uiFlags & TAUNT_T_FEMALE) ) + continue; + break; + default: + return; + break; + } + // target appearance + if( zTaunt[ i ].value[TAUNT_TARGET_APPEARANCE] != -1 ) + { + // check if pTarget has his own predefined profile (ubProfile = 200 for generated characters) + if( pTarget->ubProfile != 200 ) + { + if( gMercProfiles[pTarget->ubProfile].bAppearance != zTaunt[ i ].value[TAUNT_TARGET_APPEARANCE] ) + continue; + } + else + continue; + } + + // target type + switch( zTaunt[ i ].value[TAUNT_TARGET_TYPE] ) + { + case 0: + if( pTarget->ubWhatKindOfMercAmI != MERC_TYPE__PLAYER_CHARACTER ) + continue; + break; + case 1: + if( pTarget->ubWhatKindOfMercAmI != MERC_TYPE__AIM_MERC ) + continue; + break; + case 2: + if( pTarget->ubWhatKindOfMercAmI != MERC_TYPE__MERC ) + continue; + break; + case 3: + if( pTarget->ubWhatKindOfMercAmI != MERC_TYPE__NPC ) + continue; + break; + case 4: + if( pTarget->ubWhatKindOfMercAmI != MERC_TYPE__EPC ) + continue; + break; + case 5: + if( pTarget->ubWhatKindOfMercAmI != MERC_TYPE__NPC_WITH_UNEXTENDABLE_CONTRACT ) + continue; + break; + case 6: + if( pTarget->ubWhatKindOfMercAmI != MERC_TYPE__VEHICLE ) + continue; + break; + default: + break; + } + + // target energy, health + if( zTaunt[ i ].value[TAUNT_TARGET_ENERGY_GT] != -1 ) + { + if( pTarget->bBreath <= zTaunt[ i ].value[TAUNT_TARGET_ENERGY_GT] ) + continue; + } + if( zTaunt[ i ].value[TAUNT_TARGET_ENERGY_LT] != -1 ) + { + if( pTarget->bBreath >= zTaunt[ i ].value[TAUNT_TARGET_ENERGY_LT] ) + continue; + } + if( zTaunt[ i ].value[TAUNT_TARGET_ENERGY_MAX_GT] != -1 ) + { + if( pTarget->bBreathMax <= zTaunt[ i ].value[TAUNT_TARGET_ENERGY_MAX_GT] ) + continue; + } + if( zTaunt[ i ].value[TAUNT_TARGET_ENERGY_MAX_LT] != -1 ) + { + if( pTarget->bBreathMax >= zTaunt[ i ].value[TAUNT_TARGET_ENERGY_MAX_LT] ) + continue; + } + if( zTaunt[ i ].value[TAUNT_TARGET_HEALTH_GT] != -1 ) + { + if( pTarget->stats.bLife <= zTaunt[ i ].value[TAUNT_TARGET_HEALTH_GT] ) + continue; + } + if( zTaunt[ i ].value[TAUNT_TARGET_HEALTH_GT] != -1 ) + { + if( pTarget->stats.bLife <= zTaunt[ i ].value[TAUNT_TARGET_HEALTH_GT] ) + continue; + } + if( zTaunt[ i ].value[TAUNT_TARGET_HEALTH_LT] != -1 ) + { + if( pTarget->stats.bLife >= zTaunt[ i ].value[TAUNT_TARGET_HEALTH_LT] ) + continue; + } + if( zTaunt[ i ].value[TAUNT_TARGET_HEALTH_MAX_GT] != -1 ) + { + if( pTarget->stats.bLifeMax <= zTaunt[ i ].value[TAUNT_TARGET_HEALTH_MAX_GT] ) + continue; + } + if( zTaunt[ i ].value[TAUNT_TARGET_HEALTH_MAX_LT] != -1 ) + { + if( pTarget->stats.bLifeMax >= zTaunt[ i ].value[TAUNT_TARGET_HEALTH_MAX_LT] ) + continue; + } + // morale + if( zTaunt[ i ].value[TAUNT_TARGET_MORALE_GT] != -1 ) + { + if( pTarget->aiData.bMorale <= zTaunt[ i ].value[TAUNT_TARGET_MORALE_GT] ) + continue; + } + if( zTaunt[ i ].value[TAUNT_TARGET_MORALE_LT] != -1 ) + { + if( pTarget->aiData.bMorale >= zTaunt[ i ].value[TAUNT_TARGET_MORALE_LT] ) + continue; + } + // experience + if( zTaunt[ i ].value[TAUNT_TARGET_EXP_LEVEL_GT] != -1 ) + { + if( pTarget->stats.bExpLevel <= zTaunt[ i ].value[TAUNT_TARGET_EXP_LEVEL_GT] ) + continue; + } + if( zTaunt[ i ].value[TAUNT_TARGET_EXP_LEVEL_LT] != -1 ) + { + if( pTarget->stats.bExpLevel >= zTaunt[ i ].value[TAUNT_TARGET_EXP_LEVEL_LT] ) + continue; + } + } + else // pTarget==NULL + { + if( ( zTaunt[ i ].value[TAUNT_TARGET_MERC_PROFILE] != -1 ) || + ( zTaunt[ i ].value[TAUNT_TARGET_APPEARANCE] != -1 ) || + ( zTaunt[ i ].value[TAUNT_TARGET_ENERGY_GT] != -1 ) || + ( zTaunt[ i ].value[TAUNT_TARGET_ENERGY_LT] != -1 ) || + ( zTaunt[ i ].value[TAUNT_TARGET_ENERGY_MAX_GT] != -1 ) || + ( zTaunt[ i ].value[TAUNT_TARGET_ENERGY_MAX_LT] != -1 ) || + ( zTaunt[ i ].value[TAUNT_TARGET_HEALTH_GT] != -1 ) || + ( zTaunt[ i ].value[TAUNT_TARGET_HEALTH_LT] != -1 ) || + ( zTaunt[ i ].value[TAUNT_TARGET_HEALTH_MAX_GT] != -1 ) || + ( zTaunt[ i ].value[TAUNT_TARGET_HEALTH_MAX_LT] != -1 ) || + ( zTaunt[ i ].value[TAUNT_TARGET_EXP_LEVEL_GT] != -1 ) || + ( zTaunt[ i ].value[TAUNT_TARGET_EXP_LEVEL_LT] != -1 ) || + ( zTaunt[ i ].value[TAUNT_TARGET_MORALE_GT] != -1 ) || + ( zTaunt[ i ].value[TAUNT_TARGET_MORALE_LT] != -1 ) || + ( zTaunt[ i ].value[TAUNT_TARGET_TYPE] != -1 ) ) + continue; + + } + // everything ok, current taunt is applicable, remember it + zApplicableTaunts[iApplicableTaunts] = zTaunt[i]; + iApplicableTaunts++; + } + // are there any applicable taunts? + if( iApplicableTaunts > 0 ) + { + // use random one + swprintf( sTauntText, zApplicableTaunts[ Random(iApplicableTaunts) ].szText ); + } + else + { + return; } // Determine location... @@ -1176,9 +1636,15 @@ void StartEnemyTaunt( SOLDIERTYPE *pCiv, INT8 iTauntType ) gCivQuoteData.bActive = TRUE; gCivQuoteData.uiTimeOfCreation = GetJA2Clock( ); - - gCivQuoteData.uiDelayTime = FindDelayForString( gzCivQuote ) + 1500; + + gCivQuoteData.uiDelayTime = min( gTauntsSettings.sMaxDelay , max( gTauntsSettings.sMinDelay, FindDelayForString( gzTauntQuote ) + gTauntsSettings.sModDelay ) ); gCivQuoteData.pCiv = pCiv; + if(gTauntsSettings.fTauntShowInLog == TRUE) + { + CHAR16 LogMsg[320]; + swprintf( LogMsg, L"%s: %s", pCiv->GetName(), gzTauntQuote ); + ScreenMsg( FONT_GRAY2, MSG_INTERFACE, LogMsg ); + } } \ No newline at end of file diff --git a/Tactical/Civ Quotes.h b/Tactical/Civ Quotes.h index 5eff520b..4cf92421 100644 --- a/Tactical/Civ Quotes.h +++ b/Tactical/Civ Quotes.h @@ -80,14 +80,19 @@ enum //enemy taunts - SANDRO TAUNT_FIRE_LAUNCHER, TAUNT_THROW, TAUNT_CHARGE_KNIFE, + TAUNT_CHARGE_FISTS, + TAUNT_STEAL, TAUNT_RUN_AWAY, TAUNT_SEEK_NOISE, TAUNT_ALERT, TAUNT_GOT_HIT, TAUNT_NOTICED_UNSEEN_MERC, + TAUNT_THROW_GRENADE, + TAUNT_GOT_MISSED, }; -void StartEnemyTaunt( SOLDIERTYPE *pCiv, INT8 iTauntType ); //enemy taunts - SANDRO +void PossiblyStartEnemyTaunt( SOLDIERTYPE *pCiv, INT8 iTauntType, SOLDIERTYPE *pTarget = NULL ); +void StartEnemyTaunt( SOLDIERTYPE *pCiv, INT8 iTauntType, SOLDIERTYPE *pTarget = NULL ); //enemy taunts - SANDRO // anv: added pTarget argument void InitCivQuoteSystem( ); diff --git a/Tactical/Interface.cpp b/Tactical/Interface.cpp index 320e9afc..000c3a73 100644 --- a/Tactical/Interface.cpp +++ b/Tactical/Interface.cpp @@ -110,6 +110,8 @@ UINT16 num_found_soldier_profiles[6]; // the correct number is set on reading th BACKGROUND_VALUES zBackground[NUM_BACKGROUND]; // Flugente: backgrounds +TAUNT_VALUES zTaunt[NUM_TAUNT]; // anv: externalised taunts + BOOLEAN gfInMovementMenu = FALSE; INT32 giMenuAnchorX, giMenuAnchorY; diff --git a/Tactical/Interface.h b/Tactical/Interface.h index 2d9f09e6..4a15919b 100644 --- a/Tactical/Interface.h +++ b/Tactical/Interface.h @@ -205,6 +205,76 @@ extern BACKGROUND_VALUES zBackground[NUM_BACKGROUND]; extern UINT16 num_found_background; // the correct number is set on reading the xml +// anv: enums for externalised taunts +enum { + + // progress + TAUNT_PROGRESS_LT, + TAUNT_PROGRESS_GT, + + // taunting person's stats + TAUNT_EXP_LEVEL_LT, + TAUNT_EXP_LEVEL_GT, + TAUNT_HEALTH_LT, + TAUNT_HEALTH_GT, + TAUNT_HEALTH_MAX_LT, + TAUNT_HEALTH_MAX_GT, + TAUNT_ENERGY_LT, + TAUNT_ENERGY_GT, + TAUNT_ENERGY_MAX_LT, + TAUNT_ENERGY_MAX_GT, + TAUNT_MORALE_LT, + TAUNT_MORALE_GT, + + // enemy/milita profiles + TAUNT_PROFILE_ADMIN, + TAUNT_PROFILE_ARMY, + TAUNT_PROFILE_ELITE, + TAUNT_PROFILE_GREEN, + TAUNT_PROFILE_REGULAR, + TAUNT_PROFILE_VETERAN, + + // facts + TAUNT_FACT_TRUE, + TAUNT_FACT_FALSE, + + // taunt target's stats + TAUNT_TARGET_TYPE, + TAUNT_TARGET_EXP_LEVEL_LT, + TAUNT_TARGET_EXP_LEVEL_GT, + TAUNT_TARGET_HEALTH_LT, + TAUNT_TARGET_HEALTH_GT, + TAUNT_TARGET_HEALTH_MAX_LT, + TAUNT_TARGET_HEALTH_MAX_GT, + TAUNT_TARGET_ENERGY_LT, + TAUNT_TARGET_ENERGY_GT, + TAUNT_TARGET_ENERGY_MAX_LT, + TAUNT_TARGET_ENERGY_MAX_GT, + TAUNT_TARGET_MORALE_LT, + TAUNT_TARGET_MORALE_GT, + TAUNT_TARGET_APPEARANCE, + + // taunt target's profile + TAUNT_TARGET_MERC_PROFILE, + + TAUNT_MAX, +}; + +typedef struct +{ + UINT16 uiIndex; + CHAR16 szText[320]; + UINT64 uiFlags; + INT16 value[TAUNT_MAX]; + +} TAUNT_VALUES; + +#define NUM_TAUNT 2048 + +extern TAUNT_VALUES zTaunt[NUM_TAUNT]; + +extern UINT16 num_found_taunt; // the correct number is set on reading the xml + extern int INTERFACE_WIDTH; // 640 extern int INTERFACE_HEIGHT; // 120 extern int INV_INTERFACE_HEIGHT; // 140 diff --git a/Tactical/Soldier Control.cpp b/Tactical/Soldier Control.cpp index 60fb8301..de49c391 100644 --- a/Tactical/Soldier Control.cpp +++ b/Tactical/Soldier Control.cpp @@ -6273,6 +6273,8 @@ void SOLDIERTYPE::EVENT_SoldierGotHit( UINT16 usWeaponIndex, INT16 sDamage, INT1 { SoldierGotHitPunch( this, usWeaponIndex, sDamage, bDirection, sRange, ubAttackerID, ubSpecial, ubHitLocation ); } + if( ( this->bTeam == ENEMY_TEAM ) || ( this->bTeam == MILITIA_TEAM ) ) + PossiblyStartEnemyTaunt( this, TAUNT_GOT_HIT, MercPtrs[ubAttackerID]); } diff --git a/Tactical/Soldier Control.h b/Tactical/Soldier Control.h index ce513d86..73669db2 100644 --- a/Tactical/Soldier Control.h +++ b/Tactical/Soldier Control.h @@ -413,6 +413,56 @@ enum // some properties are hidden (forbid background in MP creation) #define BACKGROUND_HIDDEN_FLAGS (BACKGROUND_NO_MALE|BACKGROUND_NO_FEMALE) +// anv: externalised taunts +// taunt properties +// attitudes +#define TAUNT_A_CUNNING_SOLO 0x0000000000000001 //1 +#define TAUNT_A_CUNNING_AID 0x0000000000000002 //2 +#define TAUNT_A_BRAVE_SOLO 0x0000000000000004 //4 +#define TAUNT_A_BRAVE_AID 0x0000000000000008 //8 + +#define TAUNT_A_AGGRESSIVE 0x0000000000000010 //16 +#define TAUNT_A_DEFENSIVE 0x0000000000000020 //32 + +// situations +#define TAUNT_S_FIRE_GUN 0x0000000000000040 //64 +#define TAUNT_S_FIRE_LAUNCHER 0x0000000000000080 //128 + +#define TAUNT_S_GOT_HIT 0x0000000000000100 //256 +#define TAUNT_S_GOT_MISSED 0x0000000000000200 //512 //10 + +#define TAUNT_S_THROW_KNIFE 0x0000000000000400 //1024 +#define TAUNT_S_THROW_GRENADE 0x0000000000000800 //2048 + +#define TAUNT_S_CHARGE_KNIFE 0x0000000000001000 //4096 +#define TAUNT_S_CHARGE_FISTS 0x0000000000002000 //8192 +#define TAUNT_S_STEAL 0x0000000000004000 //16384 +#define TAUNT_S_RUN_AWAY 0x0000000000008000 //32768 + +#define TAUNT_S_SEEK_NOISE 0x0000000000010000 //65536 +#define TAUNT_S_ALERT 0x0000000000020000 //131072 +#define TAUNT_S_NOTICED_UNSEEN 0x0000000000040000 //262144 + +// class +#define TAUNT_C_ADMIN 0x0000000000080000 //524288 +//20 +#define TAUNT_C_ARMY 0x0000000000100000 //1048576 +#define TAUNT_C_ELITE 0x0000000000200000 //2097152 +#define TAUNT_C_GREEN 0x0000000000400000 //4194304 +#define TAUNT_C_REGULAR 0x0000000000800000 //8388608 + +#define TAUNT_C_VETERAN 0x0000000001000000 //16777216 +#define TAUNT_G_MALE 0x0000000002000000 //33554432 +#define TAUNT_G_FEMALE 0x0000000004000000 //67108864 + +// target +#define TAUNT_T_MALE 0x0000000008000000 //134217728 + +#define TAUNT_T_FEMALE 0x0000000010000000 //268435456 + + +#define TAUNT_FLAG_MAX 29 + // Flugente: types of multi-turn actions enum { diff --git a/Tactical/Tactical_VS2005.vcproj b/Tactical/Tactical_VS2005.vcproj index 1670d318..ab03a80c 100644 --- a/Tactical/Tactical_VS2005.vcproj +++ b/Tactical/Tactical_VS2005.vcproj @@ -1133,11 +1133,11 @@ > + + diff --git a/Tactical/Tactical_VS2008.vcproj b/Tactical/Tactical_VS2008.vcproj index 6540d9fb..b33e0b55 100644 --- a/Tactical/Tactical_VS2008.vcproj +++ b/Tactical/Tactical_VS2008.vcproj @@ -1194,6 +1194,10 @@ RelativePath=".\XML_SpreadPatterns.cpp" > + + diff --git a/Tactical/Tactical_VS2010.vcxproj b/Tactical/Tactical_VS2010.vcxproj index 453e0707..309b6560 100644 --- a/Tactical/Tactical_VS2010.vcxproj +++ b/Tactical/Tactical_VS2010.vcxproj @@ -237,6 +237,7 @@ + diff --git a/Tactical/Tactical_VS2010.vcxproj.filters b/Tactical/Tactical_VS2010.vcxproj.filters index 239aca0c..b2e742b5 100644 --- a/Tactical/Tactical_VS2010.vcxproj.filters +++ b/Tactical/Tactical_VS2010.vcxproj.filters @@ -653,5 +653,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/Tactical/Weapons.cpp b/Tactical/Weapons.cpp index c5c268f5..06cbdd48 100644 --- a/Tactical/Weapons.cpp +++ b/Tactical/Weapons.cpp @@ -56,6 +56,9 @@ class OBJECTTYPE; class SOLDIERTYPE; #include "connect.h" +// anv: for taunts on miss +#include "Civ Quotes.h" + //rain //#define WEAPON_RELIABILITY_REDUCTION_PER_RAIN_INTENSITY 0 extern INT8 gbCurrentRainIntensity; @@ -4869,6 +4872,14 @@ void StructureHit( INT32 iBullet, UINT16 usWeaponIndex, INT16 bWeaponStatus, UIN } } } + // anv: make missed guy taunt his shooter + if (gGameSettings.fOptions[TOPTION_ALLOW_TAUNTS] == TRUE && + ( ( MercPtrs[pAttacker->ubOppNum]->bTeam == ENEMY_TEAM && SOLDIER_CLASS_ENEMY( MercPtrs[pAttacker->ubOppNum]->ubSoldierClass ) ) || + ( MercPtrs[pAttacker->ubOppNum]->bTeam == MILITIA_TEAM && SOLDIER_CLASS_MILITIA( MercPtrs[pAttacker->ubOppNum]->ubSoldierClass ) ) ) + && MercPtrs[pAttacker->ubOppNum]->bVisible != -1 ) + { + PossiblyStartEnemyTaunt(MercPtrs[pAttacker->ubOppNum], TAUNT_GOT_MISSED, pAttacker); + } } pBullet->usLastStructureHit = usStructureID; @@ -10212,7 +10223,14 @@ void ShotMiss( UINT8 ubAttackerID, INT32 iBullet ) LocateGridNo( pBullet->sGridNo ); } } - + //anv: make missed guy taunt his shooter + if (gGameSettings.fOptions[TOPTION_ALLOW_TAUNTS] == TRUE && + ( ( MercPtrs[pAttacker->ubOppNum]->bTeam == ENEMY_TEAM && SOLDIER_CLASS_ENEMY( MercPtrs[pAttacker->ubOppNum]->ubSoldierClass ) ) || + ( MercPtrs[pAttacker->ubOppNum]->bTeam == MILITIA_TEAM && SOLDIER_CLASS_MILITIA( MercPtrs[pAttacker->ubOppNum]->ubSoldierClass ) ) ) + && MercPtrs[pAttacker->ubOppNum]->bVisible != -1 ) + { + PossiblyStartEnemyTaunt(MercPtrs[pAttacker->ubOppNum], TAUNT_GOT_MISSED, pAttacker); + } } // DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("@@@@@@@ Freeing up attacker - bullet missed") ); diff --git a/Tactical/XML.h b/Tactical/XML.h index c1407d06..44ea4aa7 100644 --- a/Tactical/XML.h +++ b/Tactical/XML.h @@ -235,6 +235,7 @@ typedef PARSE_STAGE; #define VEHICLESFILENAME "Vehicles.xml" #define SQUADNAMEFILENAME "SquadNames.xml" #define BACKGROUNDSFILENAME "Backgrounds.xml" +#define TAUNTSFILENAME "EnemyTaunts.xml" #define ENEMY_ADMIN_PROFILE_FILENAME "Profiles\\SoldierProfileEnemyAdmin.xml" #define ENEMY_REGULAR_PROFILE_FILENAME "Profiles\\SoldierProfileEnemyRegular.xml" @@ -467,6 +468,10 @@ extern void LoadIMPPortraitsTEMP(); extern BOOLEAN ReadInBackgrounds(STR fileName, BOOLEAN localizedVersion ); extern BOOLEAN WriteBackgrounds( STR fileName); +// anv: externalised taunts +extern BOOLEAN ReadInTaunts(STR fileName, BOOLEAN localizedVersion ); +extern BOOLEAN WriteTaunts( STR fileName ); + //Enabled\Disabled profile sound by Jazz extern BOOLEAN ReadInSoundProfile( STR fileName ); extern BOOLEAN WriteSoundProfile( STR fileName ); diff --git a/Tactical/XML_Taunts.cpp b/Tactical/XML_Taunts.cpp new file mode 100644 index 00000000..e9f6aa63 --- /dev/null +++ b/Tactical/XML_Taunts.cpp @@ -0,0 +1,660 @@ +#ifdef PRECOMPILEDHEADERS + #include "Tactical All.h" +#else + #include "sgp.h" + #include "Debug Control.h" + #include "expat.h" + #include "XML.h" + #include "Interface.h" +#endif + +struct +{ + PARSE_STAGE curElement; + + CHAR8 szCharData[MAX_CHAR_DATA_LENGTH+1]; + TAUNT_VALUES curTaunt; + TAUNT_VALUES * curArray; + + UINT32 maxArraySize; + UINT32 curIndex; + UINT32 currentDepth; + UINT32 maxReadDepth; +} +typedef enemyRankParseData; + +UINT16 num_found_taunt = 0; // the correct number is set on reading the xml + +static void XMLCALL +tauntStartElementHandle(void *userData, const XML_Char *name, const XML_Char **atts) +{ + enemyRankParseData * pData = (enemyRankParseData *)userData; + + if(pData->currentDepth <= pData->maxReadDepth) //are we reading this element? + { + if(strcmp(name, "TAUNTS") == 0 && pData->curElement == ELEMENT_NONE) + { + pData->curElement = ELEMENT_LIST; + pData->maxReadDepth++; //we are not skipping this element + } + else if(strcmp(name, "TAUNT") == 0 && pData->curElement == ELEMENT_LIST) + { + pData->curElement = ELEMENT; + pData->maxReadDepth++; //we are not skipping this element + } + else if(pData->curElement == ELEMENT && + (strcmp(name, "szText") == 0 || + strcmp(name, "aggressive") == 0 || + strcmp(name, "defensive") == 0 || + strcmp(name, "cunning") == 0 || + strcmp(name, "cunning_aid") == 0 || + strcmp(name, "cunning_solo") == 0 || + strcmp(name, "brave") == 0 || + strcmp(name, "brave_aid") == 0 || + strcmp(name, "brave_solo") == 0 || + strcmp(name, "fire_gun") == 0 || + strcmp(name, "fire_launcher") == 0 || + strcmp(name, "charge_knife") == 0 || + strcmp(name, "charge_fists") == 0 || + strcmp(name, "steal") == 0 || + strcmp(name, "throw_knife") == 0 || + strcmp(name, "throw_grenade") == 0 || + strcmp(name, "alert") == 0 || + strcmp(name, "seek_noise") == 0 || + strcmp(name, "noticed_unseen") == 0 || + strcmp(name, "run_away") == 0 || + strcmp(name, "got_hit") == 0 || + strcmp(name, "got_missed") == 0 || + strcmp(name, "admin") == 0 || + strcmp(name, "army") == 0 || + strcmp(name, "elite") == 0 || + strcmp(name, "green") == 0 || + strcmp(name, "regular") == 0 || + strcmp(name, "veteran") == 0 || + strcmp(name, "admin_profile") == 0 || + strcmp(name, "army_profile") == 0 || + strcmp(name, "elite_profile") == 0 || + strcmp(name, "green_profile") == 0 || + strcmp(name, "regular_profile") == 0 || + strcmp(name, "veteran_profile") == 0 || + strcmp(name, "male") == 0 || + strcmp(name, "female") == 0 || + strcmp(name, "exp_level_gt") == 0 || + strcmp(name, "exp_level_lt") == 0 || + strcmp(name, "health_gt") == 0 || + strcmp(name, "health_lt") == 0 || + strcmp(name, "health_max_gt") == 0 || + strcmp(name, "health_max_lt") == 0 || + strcmp(name, "energy_gt") == 0 || + strcmp(name, "energy_lt") == 0 || + strcmp(name, "energy_max_gt") == 0 || + strcmp(name, "energy_max_lt") == 0 || + strcmp(name, "progress_gt") == 0 || + strcmp(name, "progress_lt") == 0 || + strcmp(name, "target_type") == 0 || + strcmp(name, "target_male") == 0 || + strcmp(name, "target_female") == 0 || + strcmp(name, "target_exp_level_gt") == 0 || + strcmp(name, "target_exp_level_lt") == 0 || + strcmp(name, "target_health_gt") == 0 || + strcmp(name, "target_health_lt") == 0 || + strcmp(name, "target_health_max_gt") == 0 || + strcmp(name, "target_health_max_lt") == 0 || + strcmp(name, "target_energy_gt") == 0 || + strcmp(name, "target_energy_lt") == 0 || + strcmp(name, "target_energy_max_gt") == 0 || + strcmp(name, "target_energy_max_lt") == 0 || + strcmp(name, "target_appearance") == 0 || + strcmp(name, "target_merc_profile") == 0 )) + { + pData->curElement = ELEMENT_PROPERTY; + + pData->maxReadDepth++; //we are not skipping this element + } + + pData->szCharData[0] = '\0'; + } + + pData->currentDepth++; +} + +static void XMLCALL +tauntCharacterDataHandle(void *userData, const XML_Char *str, int len) +{ + enemyRankParseData * pData = (enemyRankParseData *)userData; + + if( (pData->currentDepth <= pData->maxReadDepth) && + (strlen(pData->szCharData) < MAX_CHAR_DATA_LENGTH) + ){ + strncat(pData->szCharData,str,__min((unsigned int)len,MAX_CHAR_DATA_LENGTH-strlen(pData->szCharData))); + } +} + +static void XMLCALL +tauntEndElementHandle(void *userData, const XML_Char *name) +{ + enemyRankParseData * pData = (enemyRankParseData *)userData; + + if(pData->currentDepth <= pData->maxReadDepth) + { + if(strcmp(name, "TAUNTS") == 0) + { + pData->curElement = ELEMENT_NONE; + } + else if(strcmp(name, "TAUNT") == 0) + { + pData->curElement = ELEMENT_LIST; + + //if(pData->curTaunt.uiIndex < pData->maxArraySize) + if(num_found_taunt < pData->maxArraySize) + { + // no attitude specified -> set all + if( !(pData->curTaunt.uiFlags & TAUNT_A_AGGRESSIVE) && + !(pData->curTaunt.uiFlags & TAUNT_A_DEFENSIVE) && + !(pData->curTaunt.uiFlags & TAUNT_A_BRAVE_AID) && + !(pData->curTaunt.uiFlags & TAUNT_A_BRAVE_SOLO) && + !(pData->curTaunt.uiFlags & TAUNT_A_CUNNING_AID) && + !(pData->curTaunt.uiFlags & TAUNT_A_CUNNING_SOLO) ) + { + pData->curTaunt.uiFlags |= TAUNT_A_AGGRESSIVE; + pData->curTaunt.uiFlags |= TAUNT_A_DEFENSIVE; + pData->curTaunt.uiFlags |= TAUNT_A_BRAVE_AID; + pData->curTaunt.uiFlags |= TAUNT_A_BRAVE_SOLO; + pData->curTaunt.uiFlags |= TAUNT_A_CUNNING_AID; + pData->curTaunt.uiFlags |= TAUNT_A_CUNNING_SOLO; + } + // no gender specified -> set all + if( !(pData->curTaunt.uiFlags & TAUNT_G_FEMALE) && + !(pData->curTaunt.uiFlags & TAUNT_G_MALE) ) + { + pData->curTaunt.uiFlags |= TAUNT_G_FEMALE; + pData->curTaunt.uiFlags |= TAUNT_G_MALE; + } + if( !(pData->curTaunt.uiFlags & TAUNT_T_FEMALE) && + !(pData->curTaunt.uiFlags & TAUNT_T_MALE) ) + { + pData->curTaunt.uiFlags |= TAUNT_T_FEMALE; + pData->curTaunt.uiFlags |= TAUNT_T_MALE; + } + + // no class specified -> set all enemies + if( !(pData->curTaunt.uiFlags & TAUNT_C_ADMIN) && + !(pData->curTaunt.uiFlags & TAUNT_C_ARMY) && + !(pData->curTaunt.uiFlags & TAUNT_C_ELITE) && + !(pData->curTaunt.uiFlags & TAUNT_C_GREEN) && + !(pData->curTaunt.uiFlags & TAUNT_C_REGULAR) && + !(pData->curTaunt.uiFlags & TAUNT_C_VETERAN) ) + { + pData->curTaunt.uiFlags |= TAUNT_C_ADMIN; + pData->curTaunt.uiFlags |= TAUNT_C_ARMY; + pData->curTaunt.uiFlags |= TAUNT_C_ELITE; + pData->curTaunt.uiFlags |= TAUNT_C_GREEN; + pData->curTaunt.uiFlags |= TAUNT_C_REGULAR; + pData->curTaunt.uiFlags |= TAUNT_C_VETERAN; + } + //pData->curArray[pData->curTaunt.uiIndex] = pData->curTaunt; + pData->curArray[num_found_taunt-1] = pData->curTaunt; + pData->curTaunt.uiFlags = 0; + for(UINT16 i = 0; i < TAUNT_MAX; i++) + { + pData->curTaunt.value[i] = (-1); + } + } + + num_found_taunt++; + //num_found_taunt = pData->curTaunt.uiIndex; + } + else if(strcmp(name, "szText") == 0 ) + { + pData->curElement = ELEMENT; + + 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, "aggressive") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.uiFlags |= (UINT16) atol(pData->szCharData) ? TAUNT_A_AGGRESSIVE : 0; + } + else if(strcmp(name, "defensive") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.uiFlags |= (UINT16) atol(pData->szCharData) ? TAUNT_A_DEFENSIVE : 0; + } + else if(strcmp(name, "brave_aid") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.uiFlags |= (UINT16) atol(pData->szCharData) ? TAUNT_A_BRAVE_AID : 0; + } + else if(strcmp(name, "brave_solo") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.uiFlags |= (UINT16) atol(pData->szCharData) ? TAUNT_A_BRAVE_SOLO : 0; + } + else if(strcmp(name, "cunning_aid") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.uiFlags |= (UINT16) atol(pData->szCharData) ? TAUNT_A_CUNNING_AID : 0; + } + else if(strcmp(name, "cunning_solo") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.uiFlags |= (UINT16) atol(pData->szCharData) ? TAUNT_A_CUNNING_SOLO : 0; + } + else if(strcmp(name, "brave") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.uiFlags |= (UINT16) atol(pData->szCharData) ? TAUNT_A_BRAVE_AID : 0; + pData->curTaunt.uiFlags |= (UINT16) atol(pData->szCharData) ? TAUNT_A_BRAVE_SOLO : 0; + } + else if(strcmp(name, "cunning") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.uiFlags |= (UINT16) atol(pData->szCharData) ? TAUNT_A_CUNNING_AID : 0; + pData->curTaunt.uiFlags |= (UINT16) atol(pData->szCharData) ? TAUNT_A_CUNNING_SOLO : 0; + } + else if(strcmp(name, "fire_gun") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.uiFlags |= (UINT16) atol(pData->szCharData) ? TAUNT_S_FIRE_GUN : 0; + } + else if(strcmp(name, "fire_launcher") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.uiFlags |= (UINT16) atol(pData->szCharData) ? TAUNT_S_FIRE_LAUNCHER : 0; + } + else if(strcmp(name, "charge_knife") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.uiFlags |= (UINT16) atol(pData->szCharData) ? TAUNT_S_CHARGE_KNIFE : 0; + } + else if(strcmp(name, "charge_fists") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.uiFlags |= (UINT16) atol(pData->szCharData) ? TAUNT_S_CHARGE_FISTS : 0; + } + else if(strcmp(name, "steal") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.uiFlags |= (UINT16) atol(pData->szCharData) ? TAUNT_S_STEAL : 0; + } + else if(strcmp(name, "throw_knife") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.uiFlags |= (UINT16) atol(pData->szCharData) ? TAUNT_S_THROW_KNIFE : 0; + } + else if(strcmp(name, "throw_grenade") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.uiFlags |= (UINT16) atol(pData->szCharData) ? TAUNT_S_THROW_GRENADE: 0; + } + else if(strcmp(name, "alert") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.uiFlags |= (UINT16) atol(pData->szCharData) ? TAUNT_S_ALERT : 0; + } + else if(strcmp(name, "seek_noise") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.uiFlags |= (UINT16) atol(pData->szCharData) ? TAUNT_S_SEEK_NOISE : 0; + } + else if(strcmp(name, "noticed_unseen") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.uiFlags |= (UINT16) atol(pData->szCharData) ? TAUNT_S_NOTICED_UNSEEN : 0; + } + else if(strcmp(name, "run_away") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.uiFlags |= (UINT16) atol(pData->szCharData) ? TAUNT_S_RUN_AWAY : 0; + } + else if(strcmp(name, "got_hit") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.uiFlags |= (UINT16) atol(pData->szCharData) ? TAUNT_S_GOT_HIT: 0; + } + else if(strcmp(name, "got_missed") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.uiFlags |= (UINT16) atol(pData->szCharData) ? TAUNT_S_GOT_MISSED: 0; + } + else if(strcmp(name, "admin") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.uiFlags |= (UINT16) atol(pData->szCharData) ? TAUNT_C_ADMIN: 0; + } + else if(strcmp(name, "army") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.uiFlags |= (UINT16) atol(pData->szCharData) ? TAUNT_C_ARMY: 0; + } + else if(strcmp(name, "elite") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.uiFlags |= (UINT16) atol(pData->szCharData) ? TAUNT_C_ELITE: 0; + } + else if(strcmp(name, "green") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.uiFlags |= (UINT16) atol(pData->szCharData) ? TAUNT_C_GREEN: 0; + } + else if(strcmp(name, "regular") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.uiFlags |= (UINT16) atol(pData->szCharData) ? TAUNT_C_REGULAR: 0; + } + else if(strcmp(name, "veteran") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.uiFlags |= (UINT16) atol(pData->szCharData) ? TAUNT_C_VETERAN: 0; + } + else if(strcmp(name, "admin_profile") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.value[TAUNT_PROFILE_ADMIN] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "army_profile") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.value[TAUNT_PROFILE_ARMY] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "elite_profile") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.value[TAUNT_PROFILE_ELITE] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "green_profile") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.value[TAUNT_PROFILE_GREEN] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "regular_profile") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.value[TAUNT_PROFILE_REGULAR] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "veteran_profile") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.value[TAUNT_PROFILE_VETERAN] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "male") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.uiFlags |= (UINT16) atol(pData->szCharData) ? TAUNT_G_MALE: 0; + } + else if(strcmp(name, "female") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.uiFlags |= (UINT16) atol(pData->szCharData) ? TAUNT_G_FEMALE: 0; + } + else if(strcmp(name, "exp_level_gt") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.value[TAUNT_EXP_LEVEL_GT] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "exp_level_lt") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.value[TAUNT_EXP_LEVEL_LT] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "health_gt") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.value[TAUNT_HEALTH_GT] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "health_lt") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.value[TAUNT_HEALTH_LT] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "health_max_gt") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.value[TAUNT_HEALTH_MAX_GT] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "health_max_lt") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.value[TAUNT_HEALTH_MAX_LT] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "energy_gt") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.value[TAUNT_ENERGY_GT] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "energy_lt") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.value[TAUNT_ENERGY_LT] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "energy_max_gt") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.value[TAUNT_ENERGY_MAX_GT] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "energy_max_lt") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.value[TAUNT_ENERGY_MAX_LT] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "morale_gt") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.value[TAUNT_MORALE_GT] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "morale_lt") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.value[TAUNT_MORALE_LT] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "progress_gt") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.value[TAUNT_MORALE_GT] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "progress_lt") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.value[TAUNT_MORALE_LT] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "fact_true") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.value[TAUNT_FACT_TRUE] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "fact_false") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.value[TAUNT_FACT_FALSE] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "veteran_profile") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.value[TAUNT_PROFILE_VETERAN] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "veteran_profile") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.value[TAUNT_PROFILE_VETERAN] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "target_type") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.value[TAUNT_TARGET_TYPE] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "target_male") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.uiFlags |= (UINT16) atol(pData->szCharData) ? TAUNT_T_MALE: 0; + } + else if(strcmp(name, "target_female") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.uiFlags |= (UINT16) atol(pData->szCharData) ? TAUNT_T_FEMALE: 0; + } + else if(strcmp(name, "target_exp_level_gt") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.value[TAUNT_TARGET_EXP_LEVEL_GT] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "target_exp_level_lt") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.value[TAUNT_TARGET_EXP_LEVEL_LT] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "target_health_gt") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.value[TAUNT_TARGET_HEALTH_GT] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "target_health_lt") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.value[TAUNT_TARGET_HEALTH_LT] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "target_health_max_gt") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.value[TAUNT_TARGET_HEALTH_MAX_GT] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "target_health_max_lt") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.value[TAUNT_TARGET_HEALTH_MAX_LT] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "target_energy_gt") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.value[TAUNT_TARGET_ENERGY_GT] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "target_energy_lt") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.value[TAUNT_TARGET_ENERGY_LT] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "target_energy_max_gt") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.value[TAUNT_TARGET_ENERGY_MAX_GT] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "target_energy_max_lt") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.value[TAUNT_TARGET_ENERGY_MAX_LT] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "target_morale_gt") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.value[TAUNT_TARGET_MORALE_GT] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "target_morale_lt") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.value[TAUNT_TARGET_MORALE_LT] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "target_appearance") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.value[TAUNT_TARGET_APPEARANCE] = (INT16) atol(pData->szCharData); + } + else if(strcmp(name, "target_merc_profile") == 0) + { + pData->curElement = ELEMENT; + pData->curTaunt.value[TAUNT_TARGET_MERC_PROFILE] = (INT16) atol(pData->szCharData); + } + pData->maxReadDepth--; + } + pData->currentDepth--; +} + +BOOLEAN ReadInTaunts(STR fileName, BOOLEAN localizedVersion) +{ + HWFILE hFile; + UINT32 uiBytesRead; + UINT32 uiFSize; + CHAR8 * lpcBuffer; + XML_Parser parser = XML_ParserCreate(NULL); + + enemyRankParseData pData; + + DebugMsg(TOPIC_JA2, DBG_LEVEL_3, "Loading EnemyTaunts.xml" ); + + // Open file + hFile = FileOpen( fileName, FILE_ACCESS_READ, FALSE ); + if ( !hFile ) + return( FALSE ); + + uiFSize = FileGetSize(hFile); + lpcBuffer = (CHAR8 *) MemAlloc(uiFSize+1); + + //Read in block + if ( !FileRead( hFile, lpcBuffer, uiFSize, &uiBytesRead ) ) + { + MemFree(lpcBuffer); + return( FALSE ); + } + + lpcBuffer[uiFSize] = 0; //add a null terminator + + FileClose( hFile ); + + + XML_SetElementHandler(parser, tauntStartElementHandle, tauntEndElementHandle); + XML_SetCharacterDataHandler(parser, tauntCharacterDataHandle); + + + memset(&pData,0,sizeof(pData)); + pData.curArray = zTaunt; + pData.maxArraySize = NUM_TAUNT; + + XML_SetUserData(parser, &pData); + + if(!XML_Parse(parser, lpcBuffer, uiFSize, TRUE)) + { + CHAR8 errorBuf[511]; + + sprintf(errorBuf, "XML Parser Error in EnemyTaunts.xml: %s at line %d", XML_ErrorString(XML_GetErrorCode(parser)), XML_GetCurrentLineNumber(parser)); + LiveMessage(errorBuf); + + MemFree(lpcBuffer); + return FALSE; + } + + MemFree(lpcBuffer); + + + XML_ParserFree(parser); + + + return( TRUE ); +} + + +BOOLEAN WriteTaunts( STR fileName) +{ + HWFILE hFile; + + //Debug code; make sure that what we got from the file is the same as what's there + // Open a new file + hFile = FileOpen( fileName, FILE_ACCESS_WRITE | FILE_CREATE_ALWAYS, FALSE ); + if ( !hFile ) + return( FALSE ); + + { + UINT32 cnt; + + FilePrintf(hFile,"\r\n"); + for(cnt = 0; cnt < NUM_TAUNT; ++cnt) + { + FilePrintf(hFile,"\t\r\n"); + FilePrintf(hFile,"\t\t%d\r\n", cnt); + + FilePrintf(hFile,"\t\r\n"); + } + FilePrintf(hFile,"\r\n"); + } + FileClose( hFile ); + + return( TRUE ); +} diff --git a/Tactical/opplist.cpp b/Tactical/opplist.cpp index 495f392f..8749af67 100644 --- a/Tactical/opplist.cpp +++ b/Tactical/opplist.cpp @@ -2539,9 +2539,10 @@ void ManSeesMan(SOLDIERTYPE *pSoldier, SOLDIERTYPE *pOpponent, INT32 sOppGridNo, // SANDRO - if this is an enemy guy, who was unaware of us till now, and the combat didn't started yet, throw "taunt" and indicator we have been seen if ( IS_MERC_BODY_TYPE( pSoldier ) && pSoldier->bTeam != gbPlayerNum ) { - if ( pSoldier->aiData.bOppList[pOpponent->ubID] <= NOT_HEARD_OR_SEEN && pSoldier->aiData.bAlertStatus != STATUS_RED && pSoldier->aiData.bAlertStatus != STATUS_BLACK ) + //if ( pSoldier->aiData.bOppList[pOpponent->ubID] <= NOT_HEARD_OR_SEEN && pSoldier->aiData.bAlertStatus != STATUS_RED && pSoldier->aiData.bAlertStatus != STATUS_BLACK ) + if ( pSoldier->aiData.bOppList[pOpponent->ubID] <= NOT_HEARD_OR_SEEN ) { - StartEnemyTaunt( pSoldier, TAUNT_NOTICED_UNSEEN_MERC ); + PossiblyStartEnemyTaunt( pSoldier, TAUNT_NOTICED_UNSEEN_MERC, pOpponent ); } ShowRadioLocator( pSoldier->ubID, 1 ); } diff --git a/TacticalAI/AIMain.cpp b/TacticalAI/AIMain.cpp index 1551a974..11bb6496 100644 --- a/TacticalAI/AIMain.cpp +++ b/TacticalAI/AIMain.cpp @@ -1709,16 +1709,18 @@ INT8 ExecuteAction(SOLDIERTYPE *pSoldier) case AI_ACTION_SEEK_NOISE: // seek most important noise heard case AI_ACTION_RUN_AWAY: // run away from nearby opponent(s) // SANDRO - ENEMY TAUNTS - if (gGameSettings.fOptions[TOPTION_ALLOW_TAUNTS] == TRUE && pSoldier->bTeam == ENEMY_TEAM && SOLDIER_CLASS_ENEMY( pSoldier->ubSoldierClass ) && pSoldier->bVisible != -1 ) + if (gGameSettings.fOptions[TOPTION_ALLOW_TAUNTS] == TRUE && + ( ( pSoldier->bTeam == ENEMY_TEAM && SOLDIER_CLASS_ENEMY( pSoldier->ubSoldierClass ) && pSoldier->bVisible != -1 ) || + ( pSoldier->bTeam == MILITIA_TEAM && SOLDIER_CLASS_MILITIA( pSoldier->ubSoldierClass ) && pSoldier->bVisible != -1 ) ) ) { - if ( Random( 5 ) == 0 ) - { - if (pSoldier->aiData.bAction == AI_ACTION_SEEK_NOISE ) - StartEnemyTaunt( pSoldier, TAUNT_SEEK_NOISE ); - else if (pSoldier->aiData.bAction == AI_ACTION_RUN_AWAY ) - StartEnemyTaunt( pSoldier, TAUNT_RUN_AWAY ); + if (pSoldier->aiData.bAction == AI_ACTION_SEEK_NOISE ) + PossiblyStartEnemyTaunt( pSoldier, TAUNT_SEEK_NOISE ); + else if (pSoldier->aiData.bAction == AI_ACTION_RUN_AWAY ) + PossiblyStartEnemyTaunt( pSoldier, TAUNT_RUN_AWAY ); #ifdef ENABLE_ZOMBIES - else if ( pSoldier->IsZombie() ) // Madd: Zombies randomly moan... + if ( Random( 5 ) == 0 ) + { + if ( pSoldier->IsZombie() ) // Madd: Zombies randomly moan... pSoldier->DoMercBattleSound( (INT8)( BATTLE_SOUND_LAUGH1 ) ); #endif } @@ -1923,6 +1925,21 @@ INT8 ExecuteAction(SOLDIERTYPE *pSoldier) case AI_ACTION_TOSS_PROJECTILE: // throw grenade at/near opponent(s) LoadWeaponIfNeeded(pSoldier); // drop through here... + // randomly decide whether to say civ quote + if ( pSoldier->bVisible != -1 ) + { + // ATE: Make sure it's a person :) + if ( IS_MERC_BODY_TYPE( pSoldier ) && pSoldier->ubProfile == NO_PROFILE ) + { + // SANDRO - SOLDIER TAUNTS + if (gGameSettings.fOptions[TOPTION_ALLOW_TAUNTS] == TRUE && + ( ( pSoldier->bTeam == ENEMY_TEAM && SOLDIER_CLASS_ENEMY( pSoldier->ubSoldierClass ) ) || + ( pSoldier->bTeam == MILITIA_TEAM && SOLDIER_CLASS_MILITIA( pSoldier->ubSoldierClass ) ) ) ) + { + PossiblyStartEnemyTaunt( pSoldier, TAUNT_THROW_GRENADE ); + } + } + } case AI_ACTION_KNIFE_MOVE: // preparing to stab opponent if (pSoldier->aiData.bAction == AI_ACTION_KNIFE_MOVE) // if statement because toss falls through @@ -1934,29 +1951,28 @@ INT8 ExecuteAction(SOLDIERTYPE *pSoldier) case AI_ACTION_FIRE_GUN: // shoot at nearby opponent case AI_ACTION_THROW_KNIFE: // throw knife at nearby opponent // randomly decide whether to say civ quote - if ( pSoldier->bVisible != -1 && pSoldier->bTeam != MILITIA_TEAM ) + if ( pSoldier->bVisible != -1 )//&& pSoldier->bTeam != MILITIA_TEAM ) { // ATE: Make sure it's a person :) if ( IS_MERC_BODY_TYPE( pSoldier ) && pSoldier->ubProfile == NO_PROFILE ) { // SANDRO - SOLDIER TAUNTS - if (gGameSettings.fOptions[TOPTION_ALLOW_TAUNTS] == TRUE && pSoldier->bTeam == ENEMY_TEAM && SOLDIER_CLASS_ENEMY( pSoldier->ubSoldierClass ) ) + if (gGameSettings.fOptions[TOPTION_ALLOW_TAUNTS] == TRUE && + ( ( pSoldier->bTeam == ENEMY_TEAM && SOLDIER_CLASS_ENEMY( pSoldier->ubSoldierClass ) ) || + ( pSoldier->bTeam == MILITIA_TEAM && SOLDIER_CLASS_MILITIA( pSoldier->ubSoldierClass ) ) ) ) { - if ( Random( 8 ) == 0 ) + if (Item[pSoldier->inv[HANDPOS].usItem].usItemClass == IC_GUN ) + PossiblyStartEnemyTaunt( pSoldier, TAUNT_FIRE_GUN, MercPtrs[pSoldier->ubOppNum] ); + else if (Item[pSoldier->inv[HANDPOS].usItem].grenadelauncher || Item[pSoldier->inv[HANDPOS].usItem].mortar || Item[pSoldier->inv[HANDPOS].usItem].rocketlauncher ) + PossiblyStartEnemyTaunt( pSoldier, TAUNT_FIRE_LAUNCHER, MercPtrs[pSoldier->ubOppNum] ); + else if (pSoldier->aiData.bAction == AI_ACTION_TOSS_PROJECTILE && Item[pSoldier->inv[HANDPOS].usItem].usItemClass == IC_THROWN && !Item[pSoldier->inv[HANDPOS].usItem].flare ) + PossiblyStartEnemyTaunt( pSoldier, TAUNT_THROW, MercPtrs[pSoldier->ubOppNum] ); + else if (pSoldier->aiData.bAction == AI_ACTION_KNIFE_MOVE ) { - if (Item[pSoldier->inv[HANDPOS].usItem].usItemClass == IC_GUN ) - StartEnemyTaunt( pSoldier, TAUNT_FIRE_GUN ); - else if (Item[pSoldier->inv[HANDPOS].usItem].grenadelauncher || Item[pSoldier->inv[HANDPOS].usItem].mortar || Item[pSoldier->inv[HANDPOS].usItem].rocketlauncher ) - StartEnemyTaunt( pSoldier, TAUNT_FIRE_LAUNCHER ); - else if (pSoldier->aiData.bAction == AI_ACTION_TOSS_PROJECTILE && Item[pSoldier->inv[HANDPOS].usItem].usItemClass == IC_THROWN && !Item[pSoldier->inv[HANDPOS].usItem].flare ) - StartEnemyTaunt( pSoldier, TAUNT_THROW ); - else if (pSoldier->aiData.bAction == AI_ACTION_KNIFE_MOVE ) - { - if (Item[pSoldier->inv[HANDPOS].usItem].usItemClass == IC_BLADE ) - StartEnemyTaunt( pSoldier, TAUNT_CHARGE_KNIFE ); - //else if (Item[pSoldier->inv[HANDPOS].usItem].usItemClass == IC_PUNCH ) - // StartEnemyTaunt( pSoldier, TAUNT_CHARGE_HTH ); - } + if (Item[pSoldier->inv[HANDPOS].usItem].usItemClass == IC_BLADE ) + PossiblyStartEnemyTaunt( pSoldier, TAUNT_CHARGE_KNIFE ); + else if (Item[pSoldier->inv[HANDPOS].usItem].usItemClass == IC_PUNCH ) + StartEnemyTaunt( pSoldier, TAUNT_CHARGE_FISTS ); } } // CC, ATE here - I put in some TEMP randomness... @@ -2052,10 +2068,7 @@ INT8 ExecuteAction(SOLDIERTYPE *pSoldier) // SANDRO - ENEMY TAUNTS if (gGameSettings.fOptions[TOPTION_ALLOW_TAUNTS] == TRUE && pSoldier->bTeam == ENEMY_TEAM && SOLDIER_CLASS_ENEMY( pSoldier->ubSoldierClass ) && pSoldier->bVisible != -1 ) { - if ( Random( 4 ) == 0 ) - { - StartEnemyTaunt( pSoldier, TAUNT_ALERT ); - } + PossiblyStartEnemyTaunt( pSoldier, TAUNT_ALERT ); } //ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_BETAVERSION, L"Debug: AI radios your position!" ); // DROP THROUGH HERE! @@ -2258,7 +2271,10 @@ INT8 ExecuteAction(SOLDIERTYPE *pSoldier) pSoldier->usUIMovementMode = DetermineMovementMode( pSoldier, AI_ACTION_KNIFE_MOVE ); usSoldierIndex = WhoIsThere2( pSoldier->aiData.usActionData, pSoldier->bTargetLevel); if ( usSoldierIndex != NOBODY ) + { MercStealFromMerc( pSoldier, MercPtrs[usSoldierIndex] ); + PossiblyStartEnemyTaunt( pSoldier, TAUNT_STEAL, MercPtrs[usSoldierIndex] ); + } break; ///////////////////////////////////////////////////////////// diff --git a/Utils/Encrypted File.cpp b/Utils/Encrypted File.cpp index 2600cb8e..fcfd0612 100644 --- a/Utils/Encrypted File.cpp +++ b/Utils/Encrypted File.cpp @@ -7,6 +7,44 @@ #endif #include "Language Defines.h" +// anv: for selecting random line +#include "Random.h" + +// anv: loading random line from the file +BOOLEAN LoadEncryptedDataFromFileRandomLine(STR pFileName, STR16 pDestString, UINT32 uiSeekAmount) +{ + HWFILE hFile; + UINT32 uiBytesRead; + UINT32 uiSeekFrom; + + hFile = FileOpen(pFileName, FILE_ACCESS_READ, FALSE); + if ( !hFile ) + { + DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "LoadEncryptedDataFromFile: Failed to FileOpen"); + return( FALSE ); + } + + uiSeekFrom = Random( ( FileGetSize(hFile) / uiSeekAmount ) - 1 ); + + if ( FileSeek( hFile, uiSeekFrom * uiSeekAmount, FILE_SEEK_FROM_START ) == FALSE ) + { + FileClose(hFile); + DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "LoadEncryptedDataFromFile: Failed FileSeek"); + return( FALSE ); + } + + if( !FileRead( hFile, pDestString, uiSeekAmount, &uiBytesRead) ) + { + FileClose(hFile); + DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "LoadEncryptedDataFromFile: Failed FileRead"); + return( FALSE ); + } + + DecodeString(pDestString, uiSeekAmount); + + FileClose(hFile); + return(TRUE); +} BOOLEAN LoadEncryptedDataFromFile(STR pFileName, STR16 pDestString, UINT32 uiSeekFrom, UINT32 uiSeekAmount) { diff --git a/Utils/Encrypted File.h b/Utils/Encrypted File.h index 3964ad64..110b31d5 100644 --- a/Utils/Encrypted File.h +++ b/Utils/Encrypted File.h @@ -4,6 +4,7 @@ #include "types.h" BOOLEAN LoadEncryptedDataFromFile(STR pFileName, STR16 pDestString, UINT32 uiSeekFrom, UINT32 uiSeekAmount); +BOOLEAN LoadEncryptedDataFromFileRandomLine(STR pFileName, STR16 pDestString, UINT32 uiSeekAmount); void DecodeString(STR16 pDestString, UINT32 uiSeekAmount); #endif \ No newline at end of file diff --git a/gameloop.cpp b/gameloop.cpp index 492df2a4..213c4144 100644 --- a/gameloop.cpp +++ b/gameloop.cpp @@ -136,6 +136,8 @@ BOOLEAN InitializeGame(void) LoadModSettings(); // silversurfer: load item settings modifiers LoadItemSettings(); + // Load externalised taunts settings + LoadTauntsSettings(); #ifdef JA2UB LoadGameUBOptions(); // JA25 UB