diff --git a/GameSettings.cpp b/GameSettings.cpp index 49eb93c1..db9c76b3 100644 --- a/GameSettings.cpp +++ b/GameSettings.cpp @@ -1509,6 +1509,13 @@ void LoadGameExternalOptions() gGameExternalOptions.sEnemyOfficerSuppressionResistanceBonus = iniReader.ReadInteger("Tactical Enemy Role Settings", "ENEMY_OFFICERS_SUPPRESSION_RESISTANCE_BONUS", 10, 0, 50); gGameExternalOptions.dEnemyOfficerMoraleModifier = iniReader.ReadFloat ("Tactical Enemy Role Settings", "ENEMY_OFFICERS_MORALE_MODIFIER", 0.1f, 0.00f, 1.0f); gGameExternalOptions.dEnemyOfficerSurrenderStrengthBonus = iniReader.ReadFloat ("Tactical Enemy Role Settings", "ENEMY_OFFICERS_SURRENDERSTRENGTHBONUS", 0.1f, 0.00f, 1.0f); + + gGameExternalOptions.fEnemyGenerals = iniReader.ReadBoolean( "Tactical Enemy Role Settings", "ENEMY_GENERALS", TRUE ); + gGameExternalOptions.usEnemyGeneralsNumber = iniReader.ReadInteger( "Tactical Enemy Role Settings", "ENEMY_GENERALS_NUMBER", 5, 1, 10 ); + gGameExternalOptions.usEnemyGeneralsBodyGuardsNumber = iniReader.ReadInteger( "Tactical Enemy Role Settings", "ENEMY_GENERALS_BODYGUARDS_NUMBER", 4, 0, 10 ); + gGameExternalOptions.fEnemyGeneralStrategicDecisionSpeedBonus = iniReader.ReadFloat( "Tactical Enemy Role Settings", "ENEMY_GENERALS_STRATEGIC_DECISION_SPEEDBONUS", 0.05f, 0.00f, 0.1f ); + gGameExternalOptions.fEnemyGeneralStrategicMovementSpeedBonus = iniReader.ReadFloat( "Tactical Enemy Role Settings", "ENEMY_GENERALS_STRATEGIC_MOVEMENT_SPEEDBONUS", 0.03f, 0.00f, 0.1f ); + //################# Tactical Cover System Settings ################## @@ -1812,8 +1819,13 @@ void LoadGameExternalOptions() gGameExternalOptions.ubPrisonerInterrogationPoints[PRISONER_ADMIN] = iniReader.ReadInteger("Strategic Gameplay Settings","PRISONER_INTERROGATION_POINTS_ADMIN", 80, 30, 1000); gGameExternalOptions.ubPrisonerInterrogationPoints[PRISONER_REGULAR] = iniReader.ReadInteger("Strategic Gameplay Settings","PRISONER_INTERROGATION_POINTS_REGULAR", 100, gGameExternalOptions.ubPrisonerInterrogationPoints[PRISONER_ADMIN], 1000); gGameExternalOptions.ubPrisonerInterrogationPoints[PRISONER_ELITE] = iniReader.ReadInteger("Strategic Gameplay Settings","PRISONER_INTERROGATION_POINTS_ELITE", 100, gGameExternalOptions.ubPrisonerInterrogationPoints[PRISONER_REGULAR], 1000); - gGameExternalOptions.ubPrisonerInterrogationPoints[PRISONER_SPECIAL] = iniReader.ReadInteger("Strategic Gameplay Settings","PRISONER_INTERROGATION_POINTS_SPECIAL", 100, gGameExternalOptions.ubPrisonerInterrogationPoints[PRISONER_ELITE], 1000); - + gGameExternalOptions.ubPrisonerInterrogationPoints[PRISONER_OFFICER] = iniReader.ReadInteger( "Strategic Gameplay Settings", "PRISONER_INTERROGATION_POINTS_OFFICER", 100, gGameExternalOptions.ubPrisonerInterrogationPoints[PRISONER_ELITE], 1000 ); + + gGameExternalOptions.ubPrisonerInterrogationEnemyGeneralInfoChance[PRISONER_ADMIN] = iniReader.ReadInteger( "Strategic Gameplay Settings", "PRISONER_INTERROGATION_ENEMY_GENERAL_CHANCE_ADMIN", 0, 0, 100 ); + gGameExternalOptions.ubPrisonerInterrogationEnemyGeneralInfoChance[PRISONER_REGULAR] = iniReader.ReadInteger( "Strategic Gameplay Settings", "PRISONER_INTERROGATION_ENEMY_GENERAL_CHANCE_REGULAR", 1, gGameExternalOptions.ubPrisonerInterrogationEnemyGeneralInfoChance[PRISONER_ADMIN], 100 ); + gGameExternalOptions.ubPrisonerInterrogationEnemyGeneralInfoChance[PRISONER_ELITE] = iniReader.ReadInteger( "Strategic Gameplay Settings", "PRISONER_INTERROGATION_ENEMY_GENERAL_CHANCE_ELITE", 10, gGameExternalOptions.ubPrisonerInterrogationEnemyGeneralInfoChance[PRISONER_REGULAR], 100 ); + gGameExternalOptions.ubPrisonerInterrogationEnemyGeneralInfoChance[PRISONER_OFFICER] = iniReader.ReadInteger( "Strategic Gameplay Settings", "PRISONER_INTERROGATION_ENEMY_GENERAL_CHANCE_OFFICER", 60, gGameExternalOptions.ubPrisonerInterrogationEnemyGeneralInfoChance[PRISONER_ELITE], 100 ); + // CHRISL: Determine how Skyrider should handle landing in enemy occupied sectors gGameExternalOptions.ubSkyriderHotLZ = iniReader.ReadInteger("Strategic Gameplay Settings", "ALLOW_SKYRIDER_HOT_LZ", 0, 0, 3); @@ -2509,6 +2521,7 @@ void LoadSkillTraitsExternalSettings() gSkillTraitValues.sCOCloseDetectionRange = iniReader.ReadInteger("Covert Ops","COVERT_CLOSE_DETECTION_RANGE", 10, 0, 100); gSkillTraitValues.sCOCloseDetectionRangeSoldierCorpse = iniReader.ReadInteger("Covert Ops","COVERT_CLOSE_DETECTION_RANGE_SOLDIER_CORPSE", 5, 0, 100); gSkillTraitValues.fCOElitesDetectNextTile = iniReader.ReadBoolean("Covert Ops","COVERT_ELITES_DETECT_NEXTTILE", TRUE); + gSkillTraitValues.fCODetectIfBleeding = iniReader.ReadBoolean("Covert Ops","COVERT_DETECTEDIFBLEEDING", FALSE ); // Flugente: RADIO OPERATOR gSkillTraitValues.fROAllowArtillery = iniReader.ReadBoolean("Radio Operator","RADIO_OPERATOR_ARTILLERY", TRUE); diff --git a/GameSettings.h b/GameSettings.h index 0dfa65d3..2c9ac359 100644 --- a/GameSettings.h +++ b/GameSettings.h @@ -1358,6 +1358,7 @@ typedef struct UINT8 ubPrisonerProcessInfoDirectionChance; UINT8 ubPrisonerProcessRansomBaseChance; UINT16 ubPrisonerInterrogationPoints[4]; // points needed to interrogate a prisoner of a specific type + UINT8 ubPrisonerInterrogationEnemyGeneralInfoChance[4]; // chance that when getting info from interrogation, this prisoner will tell us about general we do not yet know about // Flugente: sexism/racism/etc. INT8 sMoraleModAppearance; @@ -1381,6 +1382,11 @@ typedef struct INT8 sEnemyOfficerSuppressionResistanceBonus; FLOAT dEnemyOfficerMoraleModifier; FLOAT dEnemyOfficerSurrenderStrengthBonus; + BOOLEAN fEnemyGenerals; + UINT16 usEnemyGeneralsNumber; + UINT16 usEnemyGeneralsBodyGuardsNumber; + FLOAT fEnemyGeneralStrategicDecisionSpeedBonus; + FLOAT fEnemyGeneralStrategicMovementSpeedBonus; // Sandro: Alternative weapon holding (rifles fired from hip / pistols fired one-handed) @@ -1838,6 +1844,7 @@ typedef struct INT16 sCOCloseDetectionRange; INT16 sCOCloseDetectionRangeSoldierCorpse; BOOLEAN fCOElitesDetectNextTile; + BOOLEAN fCODetectIfBleeding; // will we be discovered if we are bleeding? // RADIO OPERATOR BOOLEAN fROAllowArtillery; // artillery can be forbidden for all teams with this setting diff --git a/GameVersion.h b/GameVersion.h index 98bf09a4..39a1769a 100644 --- a/GameVersion.h +++ b/GameVersion.h @@ -21,6 +21,7 @@ extern CHAR16 zTrackingNumber[16]; // Keeps track of the saved game version. Increment the saved game version whenever // you will invalidate the saved game file +#define ENEMY_VIPS 154 // Flugente: enemy generals are placed randomly in the map #define MORE_LOCKS_AND_KEYS 153 // anv: externalized locks and keys to xml #define MILITIA_MOVEMENT 152 // Flugente: allow control of strategic militia movement #define SNITCH_TRAIT_EXTENDED 151 // anv: more soldier flags, remembering exposition of snitch @@ -72,7 +73,7 @@ extern CHAR16 zTrackingNumber[16]; #define AP100_SAVEGAME_DATATYPE_CHANGE 105 // Before this, we didn't have the 100AP structure changes #define NIV_SAVEGAME_DATATYPE_CHANGE 102 // Before this, we used the old structure system -#define SAVE_GAME_VERSION MORE_LOCKS_AND_KEYS +#define SAVE_GAME_VERSION ENEMY_VIPS //#define RUSSIANGOLD #ifdef __cplusplus diff --git a/Strategic/Assignments.cpp b/Strategic/Assignments.cpp index ad519c59..f2c42b2c 100644 --- a/Strategic/Assignments.cpp +++ b/Strategic/Assignments.cpp @@ -6581,7 +6581,7 @@ void HandlePrisonerProcessingInSector( INT16 sMapX, INT16 sMapY, INT8 bZ ) SECTORINFO *pSectorInfo = &( SectorInfo[ SECTOR( sMapX, sMapY ) ] ); UINT8 prisoners[PRISONER_MAX] = {0}; - UINT16 numprisoners = GetNumberOfPrisoners( pSectorInfo, &prisoners[PRISONER_SPECIAL], &prisoners[PRISONER_ELITE], &prisoners[PRISONER_REGULAR], &prisoners[PRISONER_ADMIN] ); + UINT16 numprisoners = GetNumberOfPrisoners( pSectorInfo, &prisoners[PRISONER_OFFICER], &prisoners[PRISONER_ELITE], &prisoners[PRISONER_REGULAR], &prisoners[PRISONER_ADMIN] ); // add interrogation progress from last hour and erase it in data UINT32 interrogationpoints = pSectorInfo->uiInterrogationHundredsLeft; @@ -6650,7 +6650,7 @@ void HandlePrisonerProcessingInSector( INT16 sMapX, INT16 sMapY, INT8 bZ ) } } - UINT16 prisonersinterrogated = interrogatedprisoners[PRISONER_ADMIN] + interrogatedprisoners[PRISONER_REGULAR] + interrogatedprisoners[PRISONER_ELITE] + interrogatedprisoners[PRISONER_SPECIAL]; + UINT16 prisonersinterrogated = interrogatedprisoners[PRISONER_ADMIN] + interrogatedprisoners[PRISONER_REGULAR] + interrogatedprisoners[PRISONER_ELITE] + interrogatedprisoners[PRISONER_OFFICER]; // the part that gets left behind is saved to the map (but not the part that gets lost due to there not being enough prisoners) UINT32 losthundreds = interrogationpoints / 100; @@ -6687,6 +6687,47 @@ void HandlePrisonerProcessingInSector( INT16 sMapX, INT16 sMapY, INT8 bZ ) // chance that prisoner will give us random info about enemy positions else if ( result < gGameExternalOptions.ubPrisonerProcessDefectChance + gGameExternalOptions.ubPrisonerProcessInfoBaseChance ) { + // if this guy is an elite or a special prisoner, there is a chance he might tell us about high-value targets! + BOOLEAN fGetInfoOnHiddenVIPs = FALSE; + if ( i < interrogatedprisoners[PRISONER_ADMIN] ) + { + if ( Chance( gGameExternalOptions.ubPrisonerInterrogationEnemyGeneralInfoChance[PRISONER_ADMIN] ) ) + fGetInfoOnHiddenVIPs = TRUE; + } + else if ( i < interrogatedprisoners[PRISONER_REGULAR] ) + { + if ( Chance( gGameExternalOptions.ubPrisonerInterrogationEnemyGeneralInfoChance[PRISONER_REGULAR] ) ) + fGetInfoOnHiddenVIPs = TRUE; + } + else if ( i < interrogatedprisoners[PRISONER_ELITE] ) + { + if ( Chance( gGameExternalOptions.ubPrisonerInterrogationEnemyGeneralInfoChance[PRISONER_ELITE] ) ) + fGetInfoOnHiddenVIPs = TRUE; + } + else if ( i < interrogatedprisoners[PRISONER_OFFICER] ) + { + if ( Chance( gGameExternalOptions.ubPrisonerInterrogationEnemyGeneralInfoChance[PRISONER_OFFICER] ) ) + fGetInfoOnHiddenVIPs = TRUE; + } + + if ( fGetInfoOnHiddenVIPs ) + { + UINT16 unknownvipector = 0; + if ( GetRandomUnknownVIPSector( unknownvipector ) ) + { + // make this guy known to the player + StrategicMap[unknownvipector].usFlags |= ENEMY_VIP_PRESENT_KNOWN; + + CHAR16 str[128]; + GetSectorIDString( SECTORX( unknownvipector ), SECTORY( unknownvipector ), 0, str, TRUE ); + + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szPrisonerTextStr[STR_PRISONER_DETECTION_VIP], str ); + + // enough info from this guy + continue; + } + } + BOOLEAN found = FALSE; UINT8 maxtries = 20; for(UINT8 infotry = 0; infotry < maxtries; ++infotry) @@ -6761,7 +6802,7 @@ void HandlePrisonerProcessingInSector( INT16 sMapX, INT16 sMapY, INT8 bZ ) } // remove interrogated prisoners... - ChangeNumberOfPrisoners( pSectorInfo, -interrogatedprisoners[PRISONER_SPECIAL], -interrogatedprisoners[PRISONER_ELITE], -interrogatedprisoners[PRISONER_REGULAR], -interrogatedprisoners[PRISONER_ADMIN], sMapX, sMapY ); + ChangeNumberOfPrisoners( pSectorInfo, -interrogatedprisoners[PRISONER_OFFICER], -interrogatedprisoners[PRISONER_ELITE], -interrogatedprisoners[PRISONER_REGULAR], -interrogatedprisoners[PRISONER_ADMIN], sMapX, sMapY ); // give experience rewards to the interrogators // total experience to share @@ -6824,13 +6865,13 @@ void HandlePrison( INT16 sMapX, INT16 sMapY, INT8 bZ ) // Are there any prisoners in this prison? SECTORINFO *pSectorInfo = &( SectorInfo[ SECTOR( sMapX, sMapY ) ] ); - UINT8 prisonersspecial = 0, prisonerselite = 0, prisonersregular = 0, prisonersadmin = 0; - UINT16 numprisoners = GetNumberOfPrisoners( pSectorInfo, &prisonersspecial, &prisonerselite, &prisonersregular, &prisonersadmin ); + UINT8 prisonersofficer = 0, prisonerselite = 0, prisonersregular = 0, prisonersadmin = 0; + UINT16 numprisoners = GetNumberOfPrisoners( pSectorInfo, &prisonersofficer, &prisonerselite, &prisonersregular, &prisonersadmin ); - // for now, simply count specials as elites - ChangeNumberOfPrisoners( pSectorInfo, -prisonersspecial, prisonersspecial, 0, 0 ); - prisonerselite += prisonersspecial; - prisonersspecial = 0; + // for now, simply count officers as elites + ChangeNumberOfPrisoners( pSectorInfo, -prisonersofficer, prisonersofficer, 0, 0 ); + prisonerselite += prisonersofficer; + prisonersofficer = 0; if ( !numprisoners ) return; @@ -6901,7 +6942,7 @@ void HandlePrison( INT16 sMapX, INT16 sMapY, INT8 bZ ) pSectorInfo->ubNumAdmins = min(255, pSectorInfo->ubNumAdmins + escapedadmins); // reduce prisoner count! - ChangeNumberOfPrisoners( pSectorInfo, -prisonersspecial, -escapedelites, -escapedregulars, -escapedadmins, sMapX, sMapY ); + ChangeNumberOfPrisoners( pSectorInfo, -prisonersofficer, -escapedelites, -escapedregulars, -escapedadmins, sMapX, sMapY ); ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szPrisonerTextStr[STR_PRISONER_RIOT], wSectorName ); } diff --git a/Strategic/Campaign Types.h b/Strategic/Campaign Types.h index c0018d4c..67fdc3f7 100644 --- a/Strategic/Campaign Types.h +++ b/Strategic/Campaign Types.h @@ -424,7 +424,7 @@ typedef enum PRISONER_ADMIN = 0, PRISONER_REGULAR, PRISONER_ELITE, - PRISONER_SPECIAL, + PRISONER_OFFICER, PRISONER_MAX, } PrisonerType; diff --git a/Strategic/Game Init.cpp b/Strategic/Game Init.cpp index 072141d7..a2aba33b 100644 --- a/Strategic/Game Init.cpp +++ b/Strategic/Game Init.cpp @@ -492,6 +492,10 @@ void InitStrategicLayer( void ) // re-set up leave list arrays for dismissed mercs InitLeaveList( ); + // Flugente: se up VIP locations + void InitVIPSectors( ); + + #ifdef JA2UB LuaInitStrategicLayer(0); //JA25 UB InitStrategicLayer.lua #endif @@ -1219,7 +1223,7 @@ void ReStartingGame() if ( InAirRaid( ) ) { EndAirRaid( ); - } +} #ifdef JA2TESTVERSION //Reset so we can use the 'cheat key' to start with mercs @@ -1248,3 +1252,58 @@ void ReStartingGame() gubCheatLevel = 0; } + +// Flugente: set up VIP locations +void InitVIPSectors() +{ + if ( !gGameExternalOptions.fEnemyGenerals ) + return; + + gStrategicStatus.usVIPsTotal = gGameExternalOptions.usEnemyGeneralsNumber; + gStrategicStatus.usVIPsLeft = 0; + + // first VIP is the general, if he is still alive + if ( gMercProfiles[GENERAL].bLife > 0 ) + { + UINT16 generalsector = SECTOR( gMercProfiles[GENERAL].sSectorX, gMercProfiles[GENERAL].sSectorY ); + + // place new VIP in sector + StrategicMap[generalsector].usFlags |= ENEMY_VIP_PRESENT; + + // no extra troops here. The player might have already taken the barracks but left the general alive + //SectorInfo[generalsector].ubNumElites += 5; + + ++gStrategicStatus.usVIPsLeft; + } + + for ( UINT8 i = gStrategicStatus.usVIPsLeft; i < gStrategicStatus.usVIPsTotal; ++i ) + { + UINT16 vipspawnsector = 0; + if ( GetPossibleVIPSector( vipspawnsector ) ) + { + // place new VIP in sector + StrategicMap[vipspawnsector].usFlags |= ENEMY_VIP_PRESENT; + + // increase troop count - VIP plus bodyguards + SectorInfo[vipspawnsector].ubNumElites += 5; + + // VIP placed + ++gStrategicStatus.usVIPsLeft; + } + // spawn the remaining generals in Meduna + else + { + if ( GetRandomEnemyTownSector( MEDUNA, vipspawnsector ) ) + { + // place new VIP in sector + StrategicMap[vipspawnsector].usFlags |= ENEMY_VIP_PRESENT; + + // increase troop count - VIP plus bodyguards + SectorInfo[vipspawnsector].ubNumElites += 5; + + // VIP placed + ++gStrategicStatus.usVIPsLeft; + } + } + } +} diff --git a/Strategic/Game Init.h b/Strategic/Game Init.h index 30200de5..77532945 100644 --- a/Strategic/Game Init.h +++ b/Strategic/Game Init.h @@ -14,5 +14,8 @@ void ReStartingGame(); void InitBloodCatSectors(); +// Flugente: se up VIP locations +void InitVIPSectors(); + #endif \ No newline at end of file diff --git a/Strategic/Map Screen Interface Map.cpp b/Strategic/Map Screen Interface Map.cpp index 06c86715..cfd24c81 100644 --- a/Strategic/Map Screen Interface Map.cpp +++ b/Strategic/Map Screen Interface Map.cpp @@ -1289,6 +1289,47 @@ void ShowUncertainNumberEnemiesInSector( INT16 sSectorX, INT16 sSectorY ) InvalidateRegion( sXPosition ,sYPosition, sXPosition + DMAP_GRID_X, sYPosition + DMAP_GRID_Y ); } +void ShowVIPSymbol( INT16 sSectorX, INT16 sSectorY ) +{ + INT16 sXPosition = 0, sYPosition = 0; + HVOBJECT hIconHandle; + + UINT8 iconOffsetX = 0; + UINT8 iconOffsetY = 0; + + if ( iResolution >= _640x480 && iResolution < _800x600 ) + { + iconOffsetX = 2; + iconOffsetY = 9; + } + else if ( iResolution < _1024x768 ) + { + iconOffsetX = 8; + iconOffsetY = 12; + } + else + { + iconOffsetX = 12; + iconOffsetY = 13; + } + + // grab the x and y postions + sXPosition = sSectorX; + sYPosition = sSectorY; + + // get the video object + GetVideoObject( &hIconHandle, guiCHARICONS ); + + // check if we are zoomed in...need to offset in case for scrolling purposes + sXPosition = (INT16)(iconOffsetX + (MAP_VIEW_START_X + (sSectorX * MAP_GRID_X + 1)) - 1); + sYPosition = (INT16)(((iconOffsetY + (sSectorY * MAP_GRID_Y) + 1))); + sYPosition -= 2; + + // small question mark + BltVideoObject( guiSAVEBUFFER, hIconHandle, 10, sXPosition, sYPosition, VO_BLT_SRCTRANSPARENCY, NULL ); + InvalidateRegion( sXPosition, sYPosition, sXPosition + DMAP_GRID_X, sYPosition + DMAP_GRID_Y ); +} + void ShowTeamAndVehicles(INT32 fShowFlags) { @@ -6493,6 +6534,10 @@ void HandleShowingOfEnemyForcesInSector( INT16 sSectorX, INT16 sSectorY, INT8 bS // get total number of badguys here sNumberOfEnemies = NumEnemiesInSector( sSectorX, sSectorY ); + // Flugente: note if we have detected a VIP here + if ( SectorHasVIP( sSectorX, sSectorY ) )//PlayerKnowsAboutVIP( sSectorX, sSectorY ) ) + ShowVIPSymbol( sSectorX, sSectorY ); + // Flugente: snitch reports can be false - we assume an enemy patrol where there is none. Unfortunately, that would always be the case if fNoEnemyDetectionWithoutReconis false - we detect something everywhere, // so every sector gets a red question mark. In that case, get out of here // anv: probability of false enemy reports! diff --git a/Strategic/Strategic AI.cpp b/Strategic/Strategic AI.cpp index 84bea5cb..f14b3d03 100644 --- a/Strategic/Strategic AI.cpp +++ b/Strategic/Strategic AI.cpp @@ -1155,6 +1155,14 @@ void InitStrategicAI() #ifdef JA2BETAVERSION ClearStrategicLog(); #endif + + // Flugente: enemy generals can speed up the AI decision process (justification: the generals are the ones planning the military operations, so if theay are around, the army is more efficient) + FLOAT dEnemyGeneralsSpeedupFactor = 1.0f; + if ( gGameExternalOptions.fEnemyRoles && gGameExternalOptions.fEnemyGenerals ) + { + dEnemyGeneralsSpeedupFactor = max( 0.5f, dEnemyGeneralsSpeedupFactor - gStrategicStatus.usVIPsLeft * gGameExternalOptions.fEnemyGeneralStrategicDecisionSpeedBonus ); + } + switch( gGameOptions.ubDifficultyLevel ) { case DIF_LEVEL_EASY: @@ -1167,7 +1175,7 @@ void InitStrategicAI() gfUnlimitedTroops = gGameExternalOptions.gfEasyUnlimitedTroops; gfAggressiveQueen = gGameExternalOptions.gfEasyAggressiveQueen; // 475 is 7:55am in minutes since midnight, the time the game starts on day 1 - AddStrategicEvent( EVENT_EVALUATE_QUEEN_SITUATION, 475 + gGameExternalOptions.ubEasyTimeEvaluateInMinutes + Random( gGameExternalOptions.ubEasyTimeEvaluateVariance ), 0 ); + AddStrategicEvent( EVENT_EVALUATE_QUEEN_SITUATION, 475 + dEnemyGeneralsSpeedupFactor * (gGameExternalOptions.ubEasyTimeEvaluateInMinutes + Random( gGameExternalOptions.ubEasyTimeEvaluateVariance )), 0 ); break; case DIF_LEVEL_MEDIUM: giReinforcementPool = gGameExternalOptions.iReinforcementPoolExperienced; @@ -1178,7 +1186,7 @@ void InitStrategicAI() gubHoursGracePeriod = gGameExternalOptions.ubNormalGracePeriodInHours; gfUnlimitedTroops = gGameExternalOptions.gfNormalUnlimitedTroops; gfAggressiveQueen = gGameExternalOptions.gfNormalAggressiveQueen; - AddStrategicEvent( EVENT_EVALUATE_QUEEN_SITUATION, 475 + gGameExternalOptions.ubNormalTimeEvaluateInMinutes + Random( gGameExternalOptions.ubNormalTimeEvaluateVariance ), 0 ); + AddStrategicEvent( EVENT_EVALUATE_QUEEN_SITUATION, 475 + dEnemyGeneralsSpeedupFactor * (gGameExternalOptions.ubNormalTimeEvaluateInMinutes + Random( gGameExternalOptions.ubNormalTimeEvaluateVariance )), 0); break; case DIF_LEVEL_HARD: giReinforcementPool = gGameExternalOptions.iReinforcementPoolExpert; @@ -1189,7 +1197,7 @@ void InitStrategicAI() gubHoursGracePeriod = gGameExternalOptions.ubHardGracePeriodInHours; gfUnlimitedTroops = gGameExternalOptions.gfHardUnlimitedTroops; gfAggressiveQueen = gGameExternalOptions.gfHardAggressiveQueen; - AddStrategicEvent( EVENT_EVALUATE_QUEEN_SITUATION, 475 + gGameExternalOptions.ubHardTimeEvaluateInMinutes + Random( gGameExternalOptions.ubHardTimeEvaluateVariance ), 0 ); + AddStrategicEvent( EVENT_EVALUATE_QUEEN_SITUATION, 475 + dEnemyGeneralsSpeedupFactor * (gGameExternalOptions.ubHardTimeEvaluateInMinutes + Random( gGameExternalOptions.ubHardTimeEvaluateVariance )), 0); break; case DIF_LEVEL_INSANE: giReinforcementPool = gGameExternalOptions.iReinforcementPoolInsane; @@ -1200,7 +1208,7 @@ void InitStrategicAI() gubHoursGracePeriod = gGameExternalOptions.ubInsaneGracePeriodInHours; gfUnlimitedTroops = gGameExternalOptions.gfInsaneUnlimitedTroops; gfAggressiveQueen = gGameExternalOptions.gfInsaneAggressiveQueen; - AddStrategicEvent( EVENT_EVALUATE_QUEEN_SITUATION, 475 + gGameExternalOptions.ubInsaneTimeEvaluateInMinutes + Random( gGameExternalOptions.ubInsaneTimeEvaluateVariance ), 0 ); + AddStrategicEvent( EVENT_EVALUATE_QUEEN_SITUATION, 475 + dEnemyGeneralsSpeedupFactor * (gGameExternalOptions.ubInsaneTimeEvaluateInMinutes + Random( gGameExternalOptions.ubInsaneTimeEvaluateVariance )), 0); break; } @@ -3257,19 +3265,27 @@ void EvaluateQueenSituation() // This can increase the decision intervals by up to 500 extra minutes (> 8 hrs) uiOffset = max( 100 - giRequestPoints, 0); uiOffset = uiOffset + Random( uiOffset * 4 ); + + // Flugente: enemy generals can speed up the AI decision process (justification: the generals are the ones planning the military operations, so if theay are around, the army is more efficient) + FLOAT dEnemyGeneralsSpeedupFactor = 1.0f; + if ( gGameExternalOptions.fEnemyRoles && gGameExternalOptions.fEnemyGenerals ) + { + dEnemyGeneralsSpeedupFactor = max( 0.5f, dEnemyGeneralsSpeedupFactor - gStrategicStatus.usVIPsLeft * gGameExternalOptions.fEnemyGeneralStrategicDecisionSpeedBonus ); + } + switch( gGameOptions.ubDifficultyLevel ) { case DIF_LEVEL_EASY: - uiOffset += gGameExternalOptions.ubEasyTimeEvaluateInMinutes + Random( gGameExternalOptions.ubEasyTimeEvaluateVariance ); + uiOffset += dEnemyGeneralsSpeedupFactor * (gGameExternalOptions.ubEasyTimeEvaluateInMinutes + Random( gGameExternalOptions.ubEasyTimeEvaluateVariance )); break; case DIF_LEVEL_MEDIUM: - uiOffset += gGameExternalOptions.ubNormalTimeEvaluateInMinutes + Random( gGameExternalOptions.ubNormalTimeEvaluateVariance ); + uiOffset += dEnemyGeneralsSpeedupFactor * (gGameExternalOptions.ubNormalTimeEvaluateInMinutes + Random( gGameExternalOptions.ubNormalTimeEvaluateVariance )); break; case DIF_LEVEL_HARD: - uiOffset += gGameExternalOptions.ubHardTimeEvaluateInMinutes + Random( gGameExternalOptions.ubHardTimeEvaluateVariance ); + uiOffset += dEnemyGeneralsSpeedupFactor * (gGameExternalOptions.ubHardTimeEvaluateInMinutes + Random( gGameExternalOptions.ubHardTimeEvaluateVariance )); break; case DIF_LEVEL_INSANE: - uiOffset += gGameExternalOptions.ubInsaneTimeEvaluateInMinutes + Random( gGameExternalOptions.ubInsaneTimeEvaluateVariance ); + uiOffset += dEnemyGeneralsSpeedupFactor * (gGameExternalOptions.ubInsaneTimeEvaluateInMinutes + Random( gGameExternalOptions.ubInsaneTimeEvaluateVariance )); break; } diff --git a/Strategic/Strategic Movement.cpp b/Strategic/Strategic Movement.cpp index 6a2eb87d..e58d99bd 100644 --- a/Strategic/Strategic Movement.cpp +++ b/Strategic/Strategic Movement.cpp @@ -3260,6 +3260,17 @@ INT32 GetSectorMvtTimeForGroup( UINT8 ubSector, UINT8 ubDirection, GROUP *pGroup } } } + else if ( !pGroup->fPlayer ) + { + // Flugente: enemy generals can speed up the AI decision process (justification: the generals are the ones planning the military operations, so if theay are around, the army is more efficient) + FLOAT dEnemyGeneralsSpeedupFactor = 1.0f; + if ( gGameExternalOptions.fEnemyRoles && gGameExternalOptions.fEnemyGenerals ) + { + dEnemyGeneralsSpeedupFactor = max( 0.75f, dEnemyGeneralsSpeedupFactor - gStrategicStatus.usVIPsLeft * gGameExternalOptions.fEnemyGeneralStrategicMovementSpeedBonus ); + } + + iBestTraverseTime = dEnemyGeneralsSpeedupFactor * iBestTraverseTime; + } /////////////////////////////////////////////////////////////////////////////// return iBestTraverseTime; @@ -5119,7 +5130,7 @@ void SetGroupArrivalTime( GROUP *pGroup, UINT32 uiArrivalTime ) // Also note that non-chopper groups can currently be delayed such that this assetion would fail - enemy groups by // DelayEnemyGroupsIfPathsCross(), and player groups via PrepareGroupsForSimultaneousArrival(). So we skip the assert. - + if ( IsGroupTheHelicopterGroup( pGroup ) ) { // make sure it's valid (NOTE: the correct traverse time must be set first!) diff --git a/Strategic/Strategic Status.cpp b/Strategic/Strategic Status.cpp index d5929955..880bfd13 100644 --- a/Strategic/Strategic Status.cpp +++ b/Strategic/Strategic Status.cpp @@ -13,6 +13,9 @@ #include "GameSettings.h" #include "history.h" #include "Strategic Town Loyalty.h" + #include "Game Init.h" // added by Flugente + #include "GameVersion.h" // added by Flugente + #include "SaveLoadGame.h" // added by Flugente #endif @@ -42,8 +45,6 @@ BOOLEAN SaveStrategicStatusToSaveGameFile( HWFILE hFile ) return( TRUE ); } - - BOOLEAN LoadStrategicStatusFromSaveGameFile( HWFILE hFile ) { UINT32 uiNumBytesRead; @@ -55,6 +56,13 @@ BOOLEAN LoadStrategicStatusFromSaveGameFile( HWFILE hFile ) return( FALSE ); } + // Flugente: enemy generals: if loading an old savegame that did not have this feature, or it was turned off and is now turned on, initialise generals + if ( guiCurrentSaveGameVersion < ENEMY_VIPS || !gStrategicStatus.usVIPsTotal ) + { + // Flugente: set up VIP locations + InitVIPSectors(); + } + return( TRUE ); } diff --git a/Strategic/Strategic Status.h b/Strategic/Strategic Status.h index 090ccd2e..a63f6d7d 100644 --- a/Strategic/Strategic Status.h +++ b/Strategic/Strategic Status.h @@ -127,7 +127,11 @@ typedef struct STRATEGIC_STATUS UINT8 ubNumNewSectorsVisitedToday; UINT8 ubNumberOfDaysOfInactivity; - INT8 bPadding[70]; + // Flugente: VIPs + UINT8 usVIPsTotal; + UINT8 usVIPsLeft; + + INT8 bPadding[68]; } STRATEGIC_STATUS; diff --git a/Strategic/strategic.h b/Strategic/strategic.h index ae3a9a2c..84d17e3d 100644 --- a/Strategic/strategic.h +++ b/Strategic/strategic.h @@ -43,6 +43,9 @@ enum #define MILITIA_MOVE_EAST 0x00000004 //4 #define MILITIA_MOVE_SOUTH 0x00000008 //8 +#define ENEMY_VIP_PRESENT 0x00000010 //16 // an enemy VIP is present in this sector +#define ENEMY_VIP_PRESENT_KNOWN 0x00000020 //16 // player thinks a VIP is here + #define MILITIA_MOVE_ALLDIRS 0x0000000F // 15 // ------------------------------------------------------- diff --git a/Tactical/Interface.cpp b/Tactical/Interface.cpp index 060583b5..4757aaa4 100644 --- a/Tactical/Interface.cpp +++ b/Tactical/Interface.cpp @@ -1848,7 +1848,7 @@ void DrawSelectedUIAboveGuy( UINT16 usSoldierID ) } } - if ( gDisplayEnemyRoles && pSoldier->bTeam == ENEMY_TEAM ) + if ( gDisplayEnemyRoles && pSoldier->bTeam == ENEMY_TEAM || pSoldier->bTeam == CIV_TEAM ) { ShowSoldierRoleSymbol(pSoldier); } @@ -6564,7 +6564,7 @@ void DrawEnemyHealthBar( SOLDIERTYPE* pSoldier, INT32 sX, INT32 sY, UINT8 ubLine BOOLEAN ShowSoldierRoleSymbol(SOLDIERTYPE* pSoldier) { // this only works on enemy soldiers - if ( pSoldier->bTeam != ENEMY_TEAM ) + if ( pSoldier->bTeam != ENEMY_TEAM && pSoldier->bTeam != CIV_TEAM ) return false; if ( pSoldier->usSkillCounter[SOLDIER_COUNTER_ROLE_OBSERVED] < gGameExternalOptions.usTurnsToUncover ) @@ -6580,8 +6580,26 @@ BOOLEAN ShowSoldierRoleSymbol(SOLDIERTYPE* pSoldier) sXPos += 50; sYPos += 25; - // is this guy an officer? - if ( pSoldier->usSoldierFlagMask & SOLDIER_ENEMY_OFFICER ) + // are we a VIP? show that only when the player knows a VIP is in this sector. otherwise, don't even show our officer property + if ( pSoldier->usSoldierFlagMask & SOLDIER_VIP && !pSoldier->bSectorZ ) + { + if ( SectorHasVIP( pSoldier->sSectorX, pSoldier->sSectorY ) )//PlayerKnowsAboutVIP( pSoldier->sSectorX, pSoldier->sSectorY ) ) + { + // Add bars + iBack = RegisterBackgroundRect( BGND_FLAG_SINGLE, NULL, sXPos, sYPos, (INT16)(sXPos + 20), (INT16)(sYPos + 20) ); + + if ( iBack != -1 ) + { + SetBackgroundRectFilled( iBack ); + } + + BltVideoObjectFromIndex( FRAME_BUFFER, guiENEMYROLES, 6, sXPos, sYPos, VO_BLT_TRANSSHADOW, NULL ); + + sYPos += 20; + } + } + // is this guy an (non-vip) officer? + else if ( pSoldier->usSoldierFlagMask & SOLDIER_ENEMY_OFFICER ) { // Add bars iBack = RegisterBackgroundRect( BGND_FLAG_SINGLE, NULL, sXPos, sYPos, (INT16)(sXPos + 20 ), (INT16)(sYPos + 20 ) ); @@ -6591,7 +6609,11 @@ BOOLEAN ShowSoldierRoleSymbol(SOLDIERTYPE* pSoldier) SetBackgroundRectFilled( iBack ); } - BltVideoObjectFromIndex( FRAME_BUFFER, guiENEMYROLES, 0, sXPos, sYPos, VO_BLT_TRANSSHADOW, NULL ); + // if we look at this guy long enough, we might even learn that he is an advanced officer + if ( pSoldier->usSkillCounter[SOLDIER_COUNTER_ROLE_OBSERVED] > 1.5 * gGameExternalOptions.usTurnsToUncover && NUM_SKILL_TRAITS( pSoldier, SQUADLEADER_NT ) > 1 ) + BltVideoObjectFromIndex( FRAME_BUFFER, guiENEMYROLES, 5, sXPos, sYPos, VO_BLT_TRANSSHADOW, NULL ); + else + BltVideoObjectFromIndex( FRAME_BUFFER, guiENEMYROLES, 0, sXPos, sYPos, VO_BLT_TRANSSHADOW, NULL ); sYPos += 20; } diff --git a/Tactical/Overhead.cpp b/Tactical/Overhead.cpp index 1eec5c19..3c8fb5f4 100644 --- a/Tactical/Overhead.cpp +++ b/Tactical/Overhead.cpp @@ -3859,6 +3859,11 @@ void HandleNPCTeamMemberDeath( SOLDIERTYPE *pSoldierOld ) #endif } + // Flugente: backgrounds + if ( pSoldierOld->HasBackgroundFlag( BACKGROUND_GLOBALOYALITYLOSSONDEATH ) ) + { + DecrementTownLoyaltyEverywhere( 20000 ); + } // killing crows/cows is not worth any experience! if ( ( pSoldierOld->ubBodyType != CROW ) && ( pSoldierOld->ubBodyType != COW ) ) //&& pSoldierOld->ubLastDamageReason != TAKE_DAMAGE_BLOODLOSS ) // SANDRO - why not give exp for bleeding out? @@ -6618,7 +6623,7 @@ BOOLEAN GetPlayerControlledPrisonList( std::vector& arSectorIDVector ) extern INT32 giReinforcementPool; // we cannot simply move all prisoners of a sector. It might be a prison we are already using, so we would move all inmates, not just the new ones -UINT16 gusPrisonersSpecial = 0; +UINT16 gusPrisonersOfficer = 0; UINT16 gusPrisonersElite = 0; UINT16 gusPrisonersRegular = 0; UINT16 gusPrisonersAdmin = 0; @@ -6652,7 +6657,7 @@ void PrisonerMessageBoxCallBack( UINT8 ubExitValue ) } BOOLEAN success = FALSE; - UINT16 prisonerstobemoved = gusPrisonersSpecial + gusPrisonersElite + gusPrisonersRegular + gusPrisonersAdmin; + UINT16 prisonerstobemoved = gusPrisonersOfficer + gusPrisonersElite + gusPrisonersRegular + gusPrisonersAdmin; if ( usSectorID > 0 ) { @@ -6662,7 +6667,7 @@ void PrisonerMessageBoxCallBack( UINT8 ubExitValue ) { success = TRUE; - ChangeNumberOfPrisoners( pPrisonSectorInfo, gusPrisonersSpecial, gusPrisonersElite, gusPrisonersRegular, gusPrisonersAdmin ); + ChangeNumberOfPrisoners( pPrisonSectorInfo, gusPrisonersOfficer, gusPrisonersElite, gusPrisonersRegular, gusPrisonersAdmin ); CHAR16 wString[64]; GetShortSectorString( SECTORX( usSectorID ), SECTORY( usSectorID ), wString ); @@ -6670,7 +6675,7 @@ void PrisonerMessageBoxCallBack( UINT8 ubExitValue ) } } - gusPrisonersSpecial = 0; + gusPrisonersOfficer = 0; gusPrisonersElite = 0; gusPrisonersRegular = 0; gusPrisonersAdmin = 0; @@ -6691,7 +6696,7 @@ void RemoveCapturedEnemiesFromSectorInfo( INT16 sMapX, INT16 sMapY, INT8 bMapZ ) UINT16 ubNumPrisonerAdmin = 0; UINT16 ubNumPrisonerTroop = 0; UINT16 ubNumPrisonerElite = 0; - UINT16 ubNumPrisonerSpecial = 0; + UINT16 ubNumPrisonerOfficer = 0; // Check if the battle is won! // Loop through all mercs and make go @@ -6706,15 +6711,29 @@ void RemoveCapturedEnemiesFromSectorInfo( INT16 sMapX, INT16 sMapY, INT8 bMapZ ) // if we arrive here and the guy has lifepoints < OKLIFE, something is very odd... better take him prisoner and remove him anyway //if ( pTeamSoldier->stats.bLife > OKLIFE && pTeamSoldier->stats.bLife != 0 ) { - switch ( pTeamSoldier->ubSoldierClass ) + // officers are 'special' prisoners... + if ( pTeamSoldier->usSoldierFlagMask & SOLDIER_ENEMY_OFFICER ) { - case SOLDIER_CLASS_ADMINISTRATOR: ++ubNumPrisonerAdmin; break; - case SOLDIER_CLASS_ARMY: ++ubNumPrisonerTroop; break; - case SOLDIER_CLASS_ELITE: ++ubNumPrisonerElite; break; - default: - // if none of the above classes, ignore this one - continue; - break; + ++ubNumPrisonerOfficer; + + // Flugente: VIPs + if ( pTeamSoldier->usSoldierFlagMask & SOLDIER_VIP ) + { + DeleteVIP( pTeamSoldier->sSectorX, pTeamSoldier->sSectorY ); + } + } + else + { + switch ( pTeamSoldier->ubSoldierClass ) + { + case SOLDIER_CLASS_ADMINISTRATOR: ++ubNumPrisonerAdmin; break; + case SOLDIER_CLASS_ARMY: ++ubNumPrisonerTroop; break; + case SOLDIER_CLASS_ELITE: ++ubNumPrisonerElite; break; + default: + // if none of the above classes, ignore this one + continue; + break; + } } // Flugente: campaign stats @@ -6822,15 +6841,13 @@ void RemoveCapturedEnemiesFromSectorInfo( INT16 sMapX, INT16 sMapY, INT8 bMapZ ) } // remember all prisoners... - gusPrisonersSpecial = ubNumPrisonerSpecial; + gusPrisonersOfficer = ubNumPrisonerOfficer; gusPrisonersElite = ubNumPrisonerElite; gusPrisonersRegular = ubNumPrisonerTroop; gusPrisonersAdmin = ubNumPrisonerAdmin; - DoMessageBox( MSG_BOX_BASIC_MEDIUM_BUTTONS, TacticalStr[PRISONER_DECIDE_STR], GAME_SCREEN, MSG_BOX_FLAG_GENERIC_EIGHT_BUTTONS, PrisonerMessageBoxCallBack, NULL ); + DoMessageBox( MSG_BOX_BASIC_MEDIUM_BUTTONS, TacticalStr[ PRISONER_DECIDE_STR ], GAME_SCREEN, MSG_BOX_FLAG_GENERIC_EIGHT_BUTTONS, PrisonerMessageBoxCallBack, NULL ); } - else - DoMessageBox( MSG_BOX_BASIC_STYLE, TacticalStr[PRISONER_NO_PRISONS_STR], GAME_SCREEN, (UINT8)MSG_BOX_FLAG_OK, NULL, NULL ); } } @@ -10550,38 +10567,38 @@ BOOLEAN IsProfileInUse(UINT8 usTeam, INT8 aType, UINT16 aNr) return FALSE; } -UINT16 GetNumberOfPrisoners( SECTORINFO *pSectorInfo, UINT8* apSpecial, UINT8* apElite, UINT8* apRegular, UINT8* apAdmin ) +UINT16 GetNumberOfPrisoners( SECTORINFO *pSectorInfo, UINT8* aOfficer, UINT8* apElite, UINT8* apRegular, UINT8* apAdmin ) { if ( !pSectorInfo ) return 0; - *apSpecial = pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_SPECIAL]; + *aOfficer = pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_OFFICER]; *apElite = pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_ELITE]; *apRegular = pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_REGULAR]; *apAdmin = pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_ADMIN]; - return (UINT16)(pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_SPECIAL] + pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_ELITE] + pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_REGULAR] + pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_ADMIN]); + return (UINT16)(pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_OFFICER] + pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_ELITE] + pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_REGULAR] + pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_ADMIN]); } -UINT16 GetNumberOfPrisoners( UNDERGROUND_SECTORINFO *pSectorInfo, UINT8* apSpecial, UINT8* apElite, UINT8* apRegular, UINT8* apAdmin ) +UINT16 GetNumberOfPrisoners( UNDERGROUND_SECTORINFO *pSectorInfo, UINT8* aOfficer, UINT8* apElite, UINT8* apRegular, UINT8* apAdmin ) { if ( !pSectorInfo ) return 0; - *apSpecial = pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_SPECIAL]; + *aOfficer = pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_OFFICER]; *apElite = pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_ELITE]; *apRegular = pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_REGULAR]; *apAdmin = pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_ADMIN]; - return (UINT16)(pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_SPECIAL] + pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_ELITE] + pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_REGULAR] + pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_ADMIN]); + return (UINT16)(pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_OFFICER] + pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_ELITE] + pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_REGULAR] + pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_ADMIN]); } -void ChangeNumberOfPrisoners( SECTORINFO *pSectorInfo, INT16 aSpecial, INT16 aElite, INT16 aRegular, INT16 aAdmin, INT16 sX, INT16 sY ) +void ChangeNumberOfPrisoners( SECTORINFO *pSectorInfo, INT16 aOfficer, INT16 aElite, INT16 aRegular, INT16 aAdmin, INT16 sX, INT16 sY ) { if ( !pSectorInfo ) return; - pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_SPECIAL] = max(0, min(255, pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_SPECIAL] + aSpecial) ); + pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_OFFICER] = max(0, min(255, pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_OFFICER] + aOfficer ) ); pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_ELITE] = max(0, min(255, pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_ELITE] + aElite) ); pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_REGULAR] = max(0, min(255, pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_REGULAR] + aRegular) ); pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_ADMIN] = max(0, min(255, pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_ADMIN] + aAdmin) ); @@ -10600,12 +10617,12 @@ void ChangeNumberOfPrisoners( SECTORINFO *pSectorInfo, INT16 aSpecial, INT16 aEl } -void ChangeNumberOfPrisoners( UNDERGROUND_SECTORINFO *pSectorInfo, INT16 aSpecial, INT16 aElite, INT16 aRegular, INT16 aAdmin ) +void ChangeNumberOfPrisoners( UNDERGROUND_SECTORINFO *pSectorInfo, INT16 aOfficer, INT16 aElite, INT16 aRegular, INT16 aAdmin ) { if ( !pSectorInfo ) return; - pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_SPECIAL] = max(0, min(255, pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_SPECIAL] + aSpecial) ); + pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_OFFICER] = max(0, min(255, pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_OFFICER] + aOfficer ) ); pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_ELITE] = max(0, min(255, pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_ELITE] + aElite) ); pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_REGULAR] = max(0, min(255, pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_REGULAR] + aRegular) ); pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_ADMIN] = max(0, min(255, pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_ADMIN] + aAdmin) ); @@ -10635,7 +10652,7 @@ void KillOnePrisoner( SECTORINFO *pSectorInfo ) if ( !pSectorInfo ) return; - for (int i = PRISONER_SPECIAL; i >= PRISONER_ADMIN; --i) + for ( int i = PRISONER_OFFICER; i >= PRISONER_ADMIN; --i ) { if ( pSectorInfo->uiNumberOfPrisonersOfWar[i] ) { @@ -10694,4 +10711,220 @@ UINT8 HighestEnemyOfficersInSector( BOOL& aType ) } return num; +} + +// count all soldiers in the current sector that have a specific flag set +UINT16 NumSoldiersWithFlagInSector( UINT8 aTeam, UINT32 aFlag ) +{ + SOLDIERTYPE* pSoldier; + INT32 cnt = 0; + UINT8 num = 0; + + for ( cnt = gTacticalStatus.Team[aTeam].bFirstID, pSoldier = MercPtrs[cnt]; cnt < gTacticalStatus.Team[aTeam].bLastID; pSoldier++, ++cnt ) + { + if ( pSoldier->bActive && pSoldier->bInSector && pSoldier->stats.bLife > 0 ) + { + if ( pSoldier->usSoldierFlagMask & aFlag ) + { + ++num; + } + } + } + + return num; +} + +INT32 GetClosestSoldierWithFlag( UINT8 aTeam, UINT32 aFlag ) +{ + INT32 sBestGridNo = NOWHERE; + + + + return sBestGridNo; +} + +// Flugente: VIP targets +// can a new VIP be created? +BOOLEAN VIPSlotFree() +{ + // TODO: somehow keep track of all VIPs so far, including the dead ones + + return TRUE; +} + +BOOLEAN SectorHasVIP( INT16 sMapX, INT16 sMapY ) +{ + return (StrategicMap[SECTOR(sMapX, sMapY)].usFlags & ENEMY_VIP_PRESENT); +} + +BOOLEAN PlayerKnowsAboutVIP( INT16 sMapX, INT16 sMapY ) +{ + return (StrategicMap[SECTOR( sMapX, sMapY )].usFlags & ENEMY_VIP_PRESENT_KNOWN); +} + +BOOLEAN TownHasVIP( INT8 bTownId ) +{ + for ( INT32 iCounterA = 1; iCounterA < (INT32)(MAP_WORLD_X - 1); ++iCounterA ) + { + for ( INT32 iCounterB = 1; iCounterB < (INT32)(MAP_WORLD_Y - 1); ++iCounterB ) + { + if ( StrategicMap[CALCULATE_STRATEGIC_INDEX( iCounterA, iCounterB )].bNameId == bTownId && SectorHasVIP( iCounterA, iCounterB ) ) + { + return TRUE; + } + } + } + + return FALSE; +} + +BOOLEAN GetRandomEnemyTownSector(INT8 bTownId, UINT16& aSector) +{ + UINT16 usSector = 0; + std::vector possiblesectors; + + for ( INT16 iCounterA = 1; iCounterA < (INT32)(MAP_WORLD_X - 1); ++iCounterA ) + { + for ( INT16 iCounterB = 1; iCounterB < (INT32)(MAP_WORLD_Y - 1); ++iCounterB ) + { + usSector = CALCULATE_STRATEGIC_INDEX( iCounterA, iCounterB ); + + if ( StrategicMap[usSector].bNameId == bTownId && NumEnemiesInSector( iCounterA, iCounterB ) > 0 && !SectorHasVIP( iCounterA, iCounterB ) ) + { + possiblesectors.push_back( usSector ); + } + } + } + + if ( !possiblesectors.empty( ) ) + { + // select a random town + UINT16 tmpSector = possiblesectors[Random( possiblesectors.size( ) )]; + + // as the game decides to be a dick, CALCULATE_STRATEGIC_INDEX(x, y) and SECTOR(x, y) are INCOMPATIBLE. Which is obscene, considering their liberate use throughout the code + aSector = STRATEGIC_INDEX_TO_SECTOR_INFO( tmpSector ); + + return TRUE; + } + + return false; +} + +// Get a possible sector for a VIP to spawn in. Note: we do not spawn new VIPs in Meduna - VIPs that escape move there instead +BOOLEAN GetPossibleVIPSector( UINT16& aSector) +{ + std::vector possibletowns; + + for ( INT8 town = FIRST_TOWN; town <= NUM_TOWNS; ++town ) + { + // VIPs don't spawn in Meduna on first try + if ( town == MEDUNA ) + continue; + + // San Mona is also out, as the army has no permanent presence there + if ( town == SAN_MONA ) + continue; + + // no tiny towns + if ( GetTownSectorSize( town ) < 2 ) + continue; + + // if this town already has a VIP, skip it + if ( TownHasVIP( town ) ) + continue; + + // VIPs only spawn in sectors that are completely under enemy control. This makes hunting them down much more challenging ;-) + if ( GetTownSectorsUnderControl( town ) == 0 ) + possibletowns.push_back(town); + } + + if ( !possibletowns.empty() ) + { + // select a random town + INT8 spawntown = possibletowns[Random( possibletowns.size() )]; + + if ( GetRandomEnemyTownSector( spawntown, aSector ) ) + return TRUE; + } + + return FALSE; +} + +// Get the location of a VIP we do not yet know about +BOOLEAN GetRandomUnknownVIPSector( UINT16& aSector ) +{ + UINT16 usSector = 0; + std::vector possiblesectors; + + for ( INT32 iCounterA = 1; iCounterA < (INT32)(MAP_WORLD_X - 1); ++iCounterA ) + { + for ( INT32 iCounterB = 1; iCounterB < (INT32)(MAP_WORLD_Y - 1); ++iCounterB ) + { + usSector = CALCULATE_STRATEGIC_INDEX( iCounterA, iCounterB ); + + if ( SectorHasVIP( iCounterA, iCounterB ) && !PlayerKnowsAboutVIP( iCounterA, iCounterB ) ) + { + usSector = CALCULATE_STRATEGIC_INDEX( iCounterA, iCounterB ); + + possiblesectors.push_back( usSector ); + } + } + } + + if ( !possiblesectors.empty( ) ) + { + // select a random sector + UINT16 tmpSector = possiblesectors[Random( possiblesectors.size( ) )]; + + // as the game decides to be a dick, CALCULATE_STRATEGIC_INDEX(x, y) and SECTOR(x, y) are INCOMPATIBLE. Which is obscene, considering their liberate use throughout the code + aSector = STRATEGIC_INDEX_TO_SECTOR_INFO( tmpSector ); + + return TRUE; + } + + return FALSE; +} + +void DeleteVIP( INT16 sMapX, INT16 sMapY ) +{ + if ( StrategicMap[SECTOR( sMapX, sMapY )].usFlags & ENEMY_VIP_PRESENT_KNOWN ) + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"An important enemy VIP has been removed!" ); + } + + // if no other VIPs are here, delete flags + if ( NumSoldiersWithFlagInSector( ENEMY_TEAM, SOLDIER_VIP ) + NumSoldiersWithFlagInSector( CIV_TEAM, SOLDIER_VIP ) < 2 ) + { + StrategicMap[SECTOR( sMapX, sMapY )].usFlags &= ~(ENEMY_VIP_PRESENT | ENEMY_VIP_PRESENT_KNOWN); + } + + gStrategicStatus.usVIPsLeft = max( 0, gStrategicStatus.usVIPsLeft - 1 ); +} + +void VIPFleesToMeduna() +{ + // not if we are already in Meduna + if ( StrategicMap[CALCULATE_STRATEGIC_INDEX( gWorldSectorX, gWorldSectorY )].bNameId != MEDUNA ) + { + if ( StrategicMap[SECTOR( gWorldSectorX, gWorldSectorY )].usFlags & ENEMY_VIP_PRESENT_KNOWN ) + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"An enemy VIP has evaded your forces. You have no clue about his whereabouts" ); + } + + // if no other VIPs are here, delete flags + if ( NumSoldiersWithFlagInSector( ENEMY_TEAM, SOLDIER_VIP ) + NumSoldiersWithFlagInSector( CIV_TEAM, SOLDIER_VIP ) == 1 ) + { + StrategicMap[SECTOR( gWorldSectorX, gWorldSectorY )].usFlags &= ~(ENEMY_VIP_PRESENT | ENEMY_VIP_PRESENT_KNOWN); + } + + UINT16 usSector = 0; + if ( GetRandomEnemyTownSector( MEDUNA, usSector ) ) + { + // place new VIP in sector + StrategicMap[usSector].usFlags |= ENEMY_VIP_PRESENT; + + // increase troop count - VIP plus bodyguards + SectorInfo[usSector].ubNumElites += 5; + } + } } \ No newline at end of file diff --git a/Tactical/Overhead.h b/Tactical/Overhead.h index 4ea4f269..a127df05 100644 --- a/Tactical/Overhead.h +++ b/Tactical/Overhead.h @@ -373,11 +373,11 @@ BOOLEAN AllowedToStealFromTeamMate( UINT8 aAccessorID, UINT8 aTargetID ); BOOLEAN IsProfileInUse(UINT8 usTeam, INT8 aType, UINT16 aNr); // Flugente: functions altering a sector's prisoners -UINT16 GetNumberOfPrisoners( SECTORINFO *pSectorInfo, UINT8* apSpecial, UINT8* apElite, UINT8* apRegular, UINT8* apAdmin ); -UINT16 GetNumberOfPrisoners( UNDERGROUND_SECTORINFO *pSectorInfo, UINT8* apSpecial, UINT8* apElite, UINT8* apRegular, UINT8* apAdmin ); +UINT16 GetNumberOfPrisoners( SECTORINFO *pSectorInfo, UINT8* aOfficer, UINT8* apElite, UINT8* apRegular, UINT8* apAdmin ); +UINT16 GetNumberOfPrisoners( UNDERGROUND_SECTORINFO *pSectorInfo, UINT8* aOfficer, UINT8* apElite, UINT8* apRegular, UINT8* apAdmin ); -void ChangeNumberOfPrisoners( SECTORINFO *pSectorInfo, INT16 aSpecial, INT16 aElite, INT16 aRegular, INT16 aAdmin, INT16 sX = 0, INT16 sY = 0 ); -void ChangeNumberOfPrisoners( UNDERGROUND_SECTORINFO *pSectorInfo, INT16 aSpecial, INT16 aElite, INT16 aRegular, INT16 aAdmin ); +void ChangeNumberOfPrisoners( SECTORINFO *pSectorInfo, INT16 aOfficer, INT16 aElite, INT16 aRegular, INT16 aAdmin, INT16 sX = 0, INT16 sY = 0 ); +void ChangeNumberOfPrisoners( UNDERGROUND_SECTORINFO *pSectorInfo, INT16 aOfficer, INT16 aElite, INT16 aRegular, INT16 aAdmin ); void DeleteAllPrisoners( SECTORINFO *pSectorInfo ); void DeleteAllPrisoners( UNDERGROUND_SECTORINFO *pSectorInfo ); @@ -400,5 +400,29 @@ enum { // Flugente: return number of enemy officers and highest rank found UINT8 HighestEnemyOfficersInSector(BOOL& aType); +// count all soldiers in the current sector that have a specific flag set +UINT16 NumSoldiersWithFlagInSector(UINT8 aTeam, UINT32 aFlag); +INT32 GetClosestSoldierWithFlag( UINT8 aTeam, UINT32 aFlag ); + +// Flugente: VIP targets +// can a new VIP be created? +BOOLEAN VIPSlotFree(); + +BOOLEAN SectorHasVIP( INT16 sMapX, INT16 sMapY ); +BOOLEAN PlayerKnowsAboutVIP( INT16 sMapX, INT16 sMapY ); + +BOOLEAN TownHasVIP( INT8 bTownId ); + +BOOLEAN GetRandomEnemyTownSector( INT8 bTownId, UINT16& aSector ); + +// Get a possible sector for a VIP to spawn in. Note: we do not spawn new VIPs in Meduna - VIPs that escape move there instead +BOOLEAN GetPossibleVIPSector( UINT16& aSector ); + +// Get the location of a VIP we do not yet know about +BOOLEAN GetRandomUnknownVIPSector( UINT16& aSector ); + +void DeleteVIP( INT16 sMapX, INT16 sMapY ); +void VIPFleesToMeduna(); + #endif diff --git a/Tactical/Soldier Ani.cpp b/Tactical/Soldier Ani.cpp index 266630b6..7dd96fbe 100644 --- a/Tactical/Soldier Ani.cpp +++ b/Tactical/Soldier Ani.cpp @@ -674,7 +674,6 @@ BOOLEAN AdjustToNextAnimationFrame( SOLDIERTYPE *pSoldier ) pSoldier->sZLevelOverride = -1; pSoldier->EVENT_SetSoldierDesiredDirection( pSoldier->ubDirection ); - if ( gTacticalStatus.bBoxingState == BOXING_WAITING_FOR_PLAYER || gTacticalStatus.bBoxingState == PRE_BOXING || gTacticalStatus.bBoxingState == BOXING ) { BoxingMovementCheck( pSoldier ); @@ -4005,6 +4004,12 @@ BOOLEAN HandleSoldierDeath( SOLDIERTYPE *pSoldier , BOOLEAN *pfMadeCorpse ) *pfMadeCorpse = TRUE; } + // Flugente: VIPs + if ( pSoldier->usSoldierFlagMask & SOLDIER_VIP ) + { + DeleteVIP( pSoldier->sSectorX, pSoldier->sSectorY ); + } + // Remove mad as target, one he has died! RemoveManAsTarget( pSoldier ); diff --git a/Tactical/Soldier Control.cpp b/Tactical/Soldier Control.cpp index 6b51c379..c13fd4f8 100644 --- a/Tactical/Soldier Control.cpp +++ b/Tactical/Soldier Control.cpp @@ -15430,7 +15430,7 @@ BOOLEAN SOLDIERTYPE::SeemsLegit( UINT8 ubObserverID ) // exceptions: we are discovered if we are close and bleeding, or if we are drunk while dressed as a soldier { // if we are openly bleeding: not covert - if ( this->bBleeding > 0 ) + if ( gSkillTraitValues.fCODetectIfBleeding && this->bBleeding > 0 ) { ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szCovertTextStr[STR_COVERT_BLEEDING], this->GetName() ); return FALSE; @@ -15448,7 +15448,7 @@ BOOLEAN SOLDIERTYPE::SeemsLegit( UINT8 ubObserverID ) // however, if we are dressed up as a civilian, we can get as close as we like, we won't be discovered { // if we are openly bleeding: not covert - if ( this->bBleeding > 0 ) + if ( gSkillTraitValues.fCODetectIfBleeding && this->bBleeding > 0 ) { ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szCovertTextStr[STR_COVERT_BLEEDING], this->GetName() ); return FALSE; diff --git a/Tactical/Soldier Control.h b/Tactical/Soldier Control.h index 72b77e00..cc731130 100644 --- a/Tactical/Soldier Control.h +++ b/Tactical/Soldier Control.h @@ -387,9 +387,9 @@ enum #define SOLDIER_ENEMY_OFFICER 0x04000000 //67108864 // soldier is an enemy officer #define SOLDIER_ENEMY_OBSERVEDTHISTURN 0x08000000 //134217728 // enemy soldier was seen by the player this turn -/*#define PLAYER_NET_1_LVL_4 0x10000000 //268435456 -#define PLAYER_NET_2_LVL_4 0x20000000 //536870912 -#define WH40K_SOLDIER_ILLUSION 0x40000000 //1073741824 // Soldier is an Illusion +#define SOLDIER_VIP 0x10000000 //268435456 // soldier is a VIP - the player will likely try to assassinate him +#define SOLDIER_BODYGUARD 0x20000000 //536870912 // soldier is a bodyguard for a VIP +/*#define WH40K_SOLDIER_ILLUSION 0x40000000 //1073741824 // Soldier is an Illusion #define WH40K_SOLDIER_KILLTHISTURN 0x80000000 //2147483648 // Soldier is on a kill streak*/ // ---------------------------------------------------------------- @@ -412,7 +412,9 @@ enum #define BACKGROUND_NO_MALE 0x0000000000000040 //64 // background cannot be selected by males (IMP creation) #define BACKGROUND_NO_FEMALE 0x0000000000000080 //128 // background cannot be selected by females (IMP creation) -#define BACKGROUND_FLAG_MAX 8 // number of flagged backgrounds - keep this updated, or properties will get lost! +#define BACKGROUND_GLOBALOYALITYLOSSONDEATH 0x0000000000000100 //256 // if character dies, huge loyalty loss in entire country + +#define BACKGROUND_FLAG_MAX 9 // number of flagged backgrounds - keep this updated, or properties will get lost! // some properties are hidden (forbid background in MP creation) // corruption property is not relevant in 1.13 diff --git a/Tactical/Soldier Create.cpp b/Tactical/Soldier Create.cpp index f08ade5b..75a73cf7 100644 --- a/Tactical/Soldier Create.cpp +++ b/Tactical/Soldier Create.cpp @@ -1261,6 +1261,12 @@ BOOLEAN TacticalCopySoldierFromProfile( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STR //} } + // Flugente: VIPs: The general is, well, a general + if ( pSoldier->ubProfile == GENERAL ) + { + pSoldier->usSoldierFlagMask |= (SOLDIER_ENEMY_OFFICER | SOLDIER_VIP); + } + // Flugente: if playing with the covert trait, the assassins come covert, so they are tougher to find if ( gGameExternalOptions.fAssassinsAreDisguised && gGameOptions.fNewTraitSystem && pSoldier->IsAssassin() ) { @@ -1721,6 +1727,48 @@ BOOLEAN TacticalCopySoldierFromCreateStruct( SOLDIERTYPE *pSoldier, SOLDIERCREAT pSoldier->usSoldierFlagMask |= SOLDIER_ENEMY_OFFICER; } } + + // Flugente: VIPs + if ( gGameExternalOptions.fEnemyRoles && gGameExternalOptions.fEnemyGenerals && !gbWorldSectorZ && SectorHasVIP( gWorldSectorX, gWorldSectorY ) ) + { + if ( pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE ) + { + // has the VIP already been placed? + // if we are in the Alam barracks,don't spawn a VIP here - the General is the VIP + if ( !NumSoldiersWithFlagInSector( ENEMY_TEAM, SOLDIER_VIP ) && !NumSoldiersWithFlagInSector( CIV_TEAM, SOLDIER_VIP ) && (gWorldSectorX != gMercProfiles[GENERAL].sSectorX || gWorldSectorY != gMercProfiles[GENERAL].sSectorY) ) + { + // nope, so this guy will become the VIP + // generals are also officers... + pSoldier->usSoldierFlagMask |= (SOLDIER_ENEMY_OFFICER | SOLDIER_VIP); + } + // a VIP has bodyguards + else if ( NumSoldiersWithFlagInSector( ENEMY_TEAM, SOLDIER_BODYGUARD ) < gGameExternalOptions.usEnemyGeneralsBodyGuardsNumber ) + { + pSoldier->usSoldierFlagMask |= SOLDIER_BODYGUARD; + pSoldier->aiData.bOrders = SEEKENEMY; // required, otherwise stationary orders forbid them from moving to the VIP + } + } + else if ( pSoldier->ubSoldierClass == SOLDIER_CLASS_ARMY ) + { + // check wether there are any elites at all + SECTORINFO *pSectorInfo = &(SectorInfo[SECTOR( gWorldSectorX, gWorldSectorY )]); + + // there is a chance that all elites have been removed from this sector, for example, they could have been sent as reinforcements to an adjacent sector + // in this case, we have to make a normal troop the general - otherwise no general will be created, thus there is no chance to remove him + // no need to to also replace the bodyguards - if the player was successful in luring them away, give him that advantage + if ( !pSectorInfo->ubNumElites ) + { + // has the VIP already been placed? + // if we are in the Alam barracks,don't spawn a VIP here - the General is the VIP + if ( !NumSoldiersWithFlagInSector( ENEMY_TEAM, SOLDIER_VIP ) && !NumSoldiersWithFlagInSector( CIV_TEAM, SOLDIER_VIP ) && (gWorldSectorX != gMercProfiles[GENERAL].sSectorX || gWorldSectorY != gMercProfiles[GENERAL].sSectorY) ) + { + // nope, so this guy will become the VIP + // generals are also officers... + pSoldier->usSoldierFlagMask |= (SOLDIER_ENEMY_OFFICER | SOLDIER_VIP); + } + } + } + } // SANDRO - If neither of these two options are activated, use the original code // however, "no traits" means no traits at all, so commented out @@ -3363,9 +3411,30 @@ void CreatePrisonerOfWar() // set correct civ group pSoldier->ubCivilianGroup = POW_PRISON_CIV_GROUP; - // set militia name to further irritate the player swprintf( pSoldier->name, TacticalStr[ POW_TEAM_MERC_NAME ] ); + // make him wear 'prisoner garb' (just what Shank and Dynamo are wearing) + UINT16 usPaletteAnimSurface = LoadSoldierAnimationSurface( pSoldier, pSoldier->usAnimState ); + + if ( usPaletteAnimSurface != INVALID_ANIMATION_SURFACE ) + { + SET_PALETTEREP_ID( pSoldier->VestPal, "greyVEST" ); + SET_PALETTEREP_ID( pSoldier->PantsPal, "BLACKPANTS" ); + + // Use palette from HVOBJECT, then use substitution for pants, etc + memcpy( pSoldier->p8BPPPalette, gAnimSurfaceDatabase[usPaletteAnimSurface].hVideoObject->pPaletteEntry, sizeof(pSoldier->p8BPPPalette) * 256 ); + + SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->HeadPal ); + SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->VestPal ); + SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->PantsPal ); + SetPaletteReplacement( pSoldier->p8BPPPalette, pSoldier->SkinPal ); + + pSoldier->CreateSoldierPalettes( ); + + // Dirty + fInterfacePanelDirty = DIRTYLEVEL2; + } + // So we can see them! AllTeamsLookForAll(NO_INTERRUPTS); @@ -4098,13 +4167,13 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre BOOLEAN BTraitAssigned = FALSE; BOOLEAN CTraitAssigned = FALSE; - ubProgress = HighestPlayerProgressPercentage(); + ubProgress = HighestPlayerProgressPercentage( ); ubSolClass = pSoldier->ubSoldierClass; // Flugente: soldier profiles - if any traits are in the xml, use them, but fill up empty slots afterwards if ( gGameOptions.fNewTraitSystem && pSoldier->usSoldierProfile ) { - INT8 type = pSoldier->GetSoldierProfileType(pCreateStruct->bTeam); + INT8 type = pSoldier->GetSoldierProfileType( pCreateStruct->bTeam ); if ( type > -1 ) { @@ -4123,7 +4192,7 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre if ( zSoldierProfile[type][pSoldier->usSoldierProfile].uiTrait[2] > 0 ) { // we have to make sure that not all 3 traits are major traits - if that happens, we ignore the third one - if ( TwoStagedTrait(pSoldier->stats.ubSkillTraits[0]) && TwoStagedTrait(pSoldier->stats.ubSkillTraits[1]) && TwoStagedTrait(zSoldierProfile[type][pSoldier->usSoldierProfile].uiTrait[2]) ) + if ( TwoStagedTrait( pSoldier->stats.ubSkillTraits[0] ) && TwoStagedTrait( pSoldier->stats.ubSkillTraits[1] ) && TwoStagedTrait( zSoldierProfile[type][pSoldier->usSoldierProfile].uiTrait[2] ) ) ; else { @@ -4133,16 +4202,16 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre } } } - + // First determine who will be the squadleader for this group (administrators do not get a squadleader - if ( gGameOptions.fNewTraitSystem && bNumSquadleadersInArmy < ((ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ARMY) ? gGameOptions.ubDifficultyLevel : 2 ) && - ( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA || - ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) ) + if ( gGameOptions.fNewTraitSystem && bNumSquadleadersInArmy < ((ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ARMY) ? gGameOptions.ubDifficultyLevel : 2) && + (ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA || + ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA) ) { // set the first in command if ( bNumSquadleadersInArmy == 0 ) { - if( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) + if ( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) { iChance = 100; } @@ -4150,16 +4219,16 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre { iChance = 50; } - if( gGameExternalOptions.bAssignedTraitsRarity < 0 ) + if ( gGameExternalOptions.bAssignedTraitsRarity < 0 ) { iChance += ((iChance * gGameExternalOptions.bAssignedTraitsRarity) / 100); } - if( Chance( iChance ) ) + if ( Chance( iChance ) ) { pSoldier->stats.ubSkillTraits[0] = SQUADLEADER_NT; // raise level and leadership for this guy - pSoldier->stats.bExpLevel = min( 10, (pSoldier->stats.bExpLevel + 1) ); - pSoldier->stats.bLeadership = min( 100, (pSoldier->stats.bLeadership + 20) ); + pSoldier->stats.bExpLevel = min( 10, (pSoldier->stats.bExpLevel + 1) ); + pSoldier->stats.bLeadership = min( 100, (pSoldier->stats.bLeadership + 20) ); ATraitAssigned = TRUE; bNumSquadleadersInArmy++; @@ -4167,31 +4236,31 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre } // second level can be given by a chance depending on soldier type - if( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) + if ( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) { // 60-100% - iChance = 60 + ubProgress * 2/5; + iChance = 60 + ubProgress * 2 / 5; } - else + else { // 30-70% - iChance = 30 + ubProgress * 2/5; + iChance = 30 + ubProgress * 2 / 5; } // modify the chance by preset ini setting - if( gGameExternalOptions.bAssignedTraitsRarity != 0 ) + if ( gGameExternalOptions.bAssignedTraitsRarity != 0 ) { iChance += ((iChance * gGameExternalOptions.bAssignedTraitsRarity) / 100); } - if( Chance( iChance ) ) + if ( Chance( iChance ) ) { if ( !ATraitAssigned ) { pSoldier->stats.ubSkillTraits[0] = SQUADLEADER_NT; // raise level and leadership for this guy - pSoldier->stats.bExpLevel = min( 10, (pSoldier->stats.bExpLevel + 1) ); - pSoldier->stats.bLeadership = min( 100, (pSoldier->stats.bLeadership + 20) ); + pSoldier->stats.bExpLevel = min( 10, (pSoldier->stats.bExpLevel + 1) ); + pSoldier->stats.bLeadership = min( 100, (pSoldier->stats.bLeadership + 20) ); ATraitAssigned = TRUE; bNumSquadleadersInArmy++; @@ -4200,8 +4269,8 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre { pSoldier->stats.ubSkillTraits[1] = SQUADLEADER_NT; // raise level and leadership for this guy - pSoldier->stats.bExpLevel = min( 10, (pSoldier->stats.bExpLevel + 1) ); - pSoldier->stats.bLeadership = min( 100, (pSoldier->stats.bLeadership + 20) ); + pSoldier->stats.bExpLevel = min( 10, (pSoldier->stats.bExpLevel + 1) ); + pSoldier->stats.bLeadership = min( 100, (pSoldier->stats.bLeadership + 20) ); BTraitAssigned = TRUE; bNumSquadleadersInArmy++; @@ -4209,39 +4278,39 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre } } - + // Now look what we have in hands and assign traits according to it // ASSAULT RIFLE OR LMG - CHANCE FOR AUTO WEAPONS TRAIT - if( Item[ pCreateStruct->Inv[ HANDPOS ].usItem ].usItemClass == IC_GUN && - ( Weapon[ pCreateStruct->Inv[ HANDPOS ].usItem ].ubWeaponType == GUN_AS_RIFLE || - Weapon[ pCreateStruct->Inv[ HANDPOS ].usItem ].ubWeaponType == GUN_LMG ) ) + if ( Item[pCreateStruct->Inv[HANDPOS].usItem].usItemClass == IC_GUN && + (Weapon[pCreateStruct->Inv[HANDPOS].usItem].ubWeaponType == GUN_AS_RIFLE || + Weapon[pCreateStruct->Inv[HANDPOS].usItem].ubWeaponType == GUN_LMG) ) { // setup the chances - if( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) + if ( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) { // 50-100% - iChance = 50 + ubProgress/2; + iChance = 50 + ubProgress / 2; } - else if( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) + else if ( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) { // 30-80% - iChance = 30 + ubProgress/2; + iChance = 30 + ubProgress / 2; } - else if( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) + else if ( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) { // 15-65% - iChance = 15 + ubProgress/2; + iChance = 15 + ubProgress / 2; } // modify the chance by preset ini setting - if( gGameExternalOptions.bAssignedTraitsRarity != 0 ) + if ( gGameExternalOptions.bAssignedTraitsRarity != 0 ) { iChance += ((iChance * gGameExternalOptions.bAssignedTraitsRarity) / 100); } // Now assign the trait - if( Chance( iChance ) ) + if ( Chance( iChance ) ) { if ( !ATraitAssigned ) { @@ -4253,7 +4322,7 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre ATraitAssigned = TRUE; // Half chance to assign expert level of the trait - if ( Chance( iChance/2 ) && !BTraitAssigned ) + if ( Chance( iChance / 2 ) && !BTraitAssigned ) { if ( gGameOptions.fNewTraitSystem ) pSoldier->stats.ubSkillTraits[1] = AUTO_WEAPONS_NT; @@ -4275,34 +4344,34 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre } } // SNIPER RIFLE - CHANCE FOR SNIPER TRAIT - else if( Item[ pCreateStruct->Inv[ HANDPOS ].usItem ].usItemClass == IC_GUN && - Weapon[ pCreateStruct->Inv[ HANDPOS ].usItem ].ubWeaponType == GUN_SN_RIFLE ) + else if ( Item[pCreateStruct->Inv[HANDPOS].usItem].usItemClass == IC_GUN && + Weapon[pCreateStruct->Inv[HANDPOS].usItem].ubWeaponType == GUN_SN_RIFLE ) { // setup the chances - if( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) + if ( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) { // 45-95% - iChance = 45 + ubProgress/2; + iChance = 45 + ubProgress / 2; } - else if( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) + else if ( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) { // 30-80% - iChance = 30 + ubProgress/2; + iChance = 30 + ubProgress / 2; } - else if( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) + else if ( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) { // 15-65% - iChance = 15 + ubProgress/2; + iChance = 15 + ubProgress / 2; } // modify the chance by preset ini setting - if( gGameExternalOptions.bAssignedTraitsRarity != 0 ) + if ( gGameExternalOptions.bAssignedTraitsRarity != 0 ) { iChance += ((iChance * gGameExternalOptions.bAssignedTraitsRarity) / 100); } // Now assign the trait - if( Chance( iChance ) ) + if ( Chance( iChance ) ) { if ( !ATraitAssigned ) { @@ -4314,7 +4383,7 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre ATraitAssigned = TRUE; // Lower chance to assign expert level of the trait - if ( Chance( iChance*2/5 ) && !BTraitAssigned ) + if ( Chance( iChance * 2 / 5 ) && !BTraitAssigned ) { if ( gGameOptions.fNewTraitSystem ) pSoldier->stats.ubSkillTraits[1] = SNIPER_NT; @@ -4336,37 +4405,37 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre } } // RIFLE OR SHOTGUN - CHANCE FOR RANGER TRAIT (new traits only) - else if( Item[ pCreateStruct->Inv[ HANDPOS ].usItem ].usItemClass == IC_GUN && - ( Weapon[ pCreateStruct->Inv[ HANDPOS ].usItem ].ubWeaponType == GUN_RIFLE || - Weapon[ pCreateStruct->Inv[ HANDPOS ].usItem ].ubWeaponType == GUN_SHOTGUN ) ) + else if ( Item[pCreateStruct->Inv[HANDPOS].usItem].usItemClass == IC_GUN && + (Weapon[pCreateStruct->Inv[HANDPOS].usItem].ubWeaponType == GUN_RIFLE || + Weapon[pCreateStruct->Inv[HANDPOS].usItem].ubWeaponType == GUN_SHOTGUN) ) { // setup the chances - if( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) + if ( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) { // 40-90% - iChance = 40 + ubProgress/2; + iChance = 40 + ubProgress / 2; } - else if( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) + else if ( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) { // 25-75% - iChance = 25 + ubProgress/2; + iChance = 25 + ubProgress / 2; } - else if( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) + else if ( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) { // 10-60% - iChance = 10 + ubProgress/2; + iChance = 10 + ubProgress / 2; } // modify the chance by preset ini setting - if( gGameExternalOptions.bAssignedTraitsRarity != 0 ) + if ( gGameExternalOptions.bAssignedTraitsRarity != 0 ) { iChance += ((iChance * gGameExternalOptions.bAssignedTraitsRarity) / 100); } // Now assign the trait - if( gGameOptions.fNewTraitSystem ) // for STOMP traits only + if ( gGameOptions.fNewTraitSystem ) // for STOMP traits only { - if( Chance( iChance ) ) + if ( Chance( iChance ) ) { if ( !ATraitAssigned ) { @@ -4374,7 +4443,7 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre ATraitAssigned = TRUE; // Lower chance to assign expert level of the trait - if ( Chance( iChance*2/5 ) && !BTraitAssigned ) + if ( Chance( iChance * 2 / 5 ) && !BTraitAssigned ) { pSoldier->stats.ubSkillTraits[1] = RANGER_NT; BTraitAssigned = TRUE; @@ -4390,7 +4459,7 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre else { // with old traits, we have some chance to gain sniper trait with rifle in hands - if( Chance( iChance*2/3 ) && (Weapon[ pCreateStruct->Inv[ HANDPOS ].usItem ].ubWeaponType == GUN_RIFLE) ) + if ( Chance( iChance * 2 / 3 ) && (Weapon[pCreateStruct->Inv[HANDPOS].usItem].ubWeaponType == GUN_RIFLE) ) { if ( !ATraitAssigned ) { @@ -4406,34 +4475,34 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre } } // SMG - CHANCE FOR AUTO WEAPONS TRAIT AND CHANCE FOR A SECOND WEAPON (+GUNSLINGER/AMBIDEXTROUS TRAIT) - else if( Item[ pCreateStruct->Inv[ HANDPOS ].usItem ].usItemClass == IC_GUN && - Weapon[ pCreateStruct->Inv[ HANDPOS ].usItem ].ubWeaponType == GUN_SMG ) + else if ( Item[pCreateStruct->Inv[HANDPOS].usItem].usItemClass == IC_GUN && + Weapon[pCreateStruct->Inv[HANDPOS].usItem].ubWeaponType == GUN_SMG ) { // setup the chances - if( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) + if ( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) { // 40-90% - iChance = 40 + ubProgress/2; + iChance = 40 + ubProgress / 2; } - else if( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) + else if ( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) { // 25-75% - iChance = 25 + ubProgress/2; + iChance = 25 + ubProgress / 2; } - else if( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) + else if ( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) { // 10-60% - iChance = 10 + ubProgress/2; + iChance = 10 + ubProgress / 2; } // modify the chance by preset ini setting - if( gGameExternalOptions.bAssignedTraitsRarity != 0 ) + if ( gGameExternalOptions.bAssignedTraitsRarity != 0 ) { iChance += ((iChance * gGameExternalOptions.bAssignedTraitsRarity) / 100); } // Now assign the trait - Auto weapons are superior here - if( Chance( iChance ) ) + if ( Chance( iChance ) ) { if ( !ATraitAssigned ) { @@ -4445,7 +4514,7 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre ATraitAssigned = TRUE; // Half chance to assign expert level of the trait - if ( Chance( iChance*2/5 ) && !BTraitAssigned ) + if ( Chance( iChance * 2 / 5 ) && !BTraitAssigned ) { if ( gGameOptions.fNewTraitSystem ) pSoldier->stats.ubSkillTraits[1] = AUTO_WEAPONS_NT; @@ -4466,12 +4535,12 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre } } // Chance to gain second weapon - if ( Chance( iChance/4 ) && !Item[ pCreateStruct->Inv[ HANDPOS ].usItem ].twohanded ) // 1/4 of chance + if ( Chance( iChance / 4 ) && !Item[pCreateStruct->Inv[HANDPOS].usItem].twohanded ) // 1/4 of chance { (pCreateStruct->Inv[SECONDHANDPOS]) = (pCreateStruct->Inv[HANDPOS]); // if traits not assigned, small chance to assign Gunslinger/Ambidextrous trait - if (!ATraitAssigned ) + if ( !ATraitAssigned ) { if ( gGameOptions.fNewTraitSystem ) { @@ -4485,7 +4554,7 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre } ATraitAssigned = TRUE; } - else if (!BTraitAssigned ) + else if ( !BTraitAssigned ) { if ( gGameOptions.fNewTraitSystem ) { @@ -4499,46 +4568,46 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre } BTraitAssigned = TRUE; } - else if (gGameOptions.fNewTraitSystem && (ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA) ) + else if ( gGameOptions.fNewTraitSystem && (ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA) ) { if ( pSoldier->stats.ubSkillTraits[0] != AMBIDEXTROUS_NT && pSoldier->stats.ubSkillTraits[1] != AMBIDEXTROUS_NT ) // paranoya check pSoldier->stats.ubSkillTraits[2] = AMBIDEXTROUS_NT; CTraitAssigned = TRUE; - return( TRUE ); // We no longer need to continue from here + return(TRUE); // We no longer need to continue from here } } } // PISTOL OR MACHINE PISTOL - CHANCE FOR GUNSLINGER/AMBIDEXTROUS TRAIT AND SECOND WEAPON - else if( Item[ pCreateStruct->Inv[ HANDPOS ].usItem ].usItemClass == IC_GUN && - ( Weapon[ pCreateStruct->Inv[ HANDPOS ].usItem ].ubWeaponType == GUN_PISTOL || - Weapon[ pCreateStruct->Inv[ HANDPOS ].usItem ].ubWeaponType == GUN_M_PISTOL ) ) + else if ( Item[pCreateStruct->Inv[HANDPOS].usItem].usItemClass == IC_GUN && + (Weapon[pCreateStruct->Inv[HANDPOS].usItem].ubWeaponType == GUN_PISTOL || + Weapon[pCreateStruct->Inv[HANDPOS].usItem].ubWeaponType == GUN_M_PISTOL) ) { // setup the chances - if( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) + if ( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) { // 40-90% - iChance = 40 + ubProgress/2; + iChance = 40 + ubProgress / 2; } - else if( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) + else if ( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) { // 25-75% - iChance = 25 + ubProgress/2; + iChance = 25 + ubProgress / 2; } - else if( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) + else if ( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) { // 10-60% - iChance = 10 + ubProgress/2; + iChance = 10 + ubProgress / 2; } // modify the chance by preset ini setting - if( gGameExternalOptions.bAssignedTraitsRarity != 0 ) + if ( gGameExternalOptions.bAssignedTraitsRarity != 0 ) { iChance += ((iChance * gGameExternalOptions.bAssignedTraitsRarity) / 100); } // Now assign the trait - if( Chance( iChance ) ) + if ( Chance( iChance ) ) { if ( gGameOptions.fNewTraitSystem ) { @@ -4548,23 +4617,23 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre ATraitAssigned = TRUE; // Lower chance to assign expert level of the trait - if ( Chance( iChance/2 ) && !BTraitAssigned ) + if ( Chance( iChance / 2 ) && !BTraitAssigned ) { pSoldier->stats.ubSkillTraits[1] = GUNSLINGER_NT; BTraitAssigned = TRUE; // elites can have third skill trait - if ( Chance( iChance/3 ) && !Item[ pCreateStruct->Inv[ HANDPOS ].usItem ].twohanded && - ( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) ) + if ( Chance( iChance / 3 ) && !Item[pCreateStruct->Inv[HANDPOS].usItem].twohanded && + (ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA) ) { pSoldier->stats.ubSkillTraits[2] = AMBIDEXTROUS_NT; CTraitAssigned = TRUE; - return( TRUE ); // We no longer need to continue from here + return(TRUE); // We no longer need to continue from here } } // Chance to gain second weapon and ambidextrous trait - else if ( Chance( iChance/2 ) && !Item[ pCreateStruct->Inv[ HANDPOS ].usItem ].twohanded && !BTraitAssigned ) // 1/2 of chance + else if ( Chance( iChance / 2 ) && !Item[pCreateStruct->Inv[HANDPOS].usItem].twohanded && !BTraitAssigned ) // 1/2 of chance { if ( pCreateStruct->bTeam == MILITIA_TEAM && gGameExternalOptions.fMilitiaUseSectorInventory && gGameExternalOptions.fMilitiaUseSectorInventory_Gun ) ; @@ -4582,12 +4651,12 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre BTraitAssigned = TRUE; // elites can have third skill trait - if ( Chance( iChance/3 ) && !Item[ pCreateStruct->Inv[ HANDPOS ].usItem ].twohanded && - ( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) ) + if ( Chance( iChance / 3 ) && !Item[pCreateStruct->Inv[HANDPOS].usItem].twohanded && + (ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA) ) { pSoldier->stats.ubSkillTraits[2] = AMBIDEXTROUS_NT; CTraitAssigned = TRUE; - return( TRUE ); // We no longer need to continue from here + return(TRUE); // We no longer need to continue from here } } } @@ -4598,7 +4667,7 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre pSoldier->stats.ubSkillTraits[0] = AMBIDEXT_OT; ATraitAssigned = TRUE; // Ambidextrous trait gives us second weapon automatically - if (!Item[ pCreateStruct->Inv[ HANDPOS ].usItem ].twohanded ) + if ( !Item[pCreateStruct->Inv[HANDPOS].usItem].twohanded ) { (pCreateStruct->Inv[SECONDHANDPOS]) = (pCreateStruct->Inv[HANDPOS]); } @@ -4608,7 +4677,7 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre pSoldier->stats.ubSkillTraits[1] = AMBIDEXT_OT; BTraitAssigned = TRUE; // Ambidextrous trait gives us second weapon automatically - if (!Item[ pCreateStruct->Inv[ HANDPOS ].usItem ].twohanded ) + if ( !Item[pCreateStruct->Inv[HANDPOS].usItem].twohanded ) { (pCreateStruct->Inv[SECONDHANDPOS]) = (pCreateStruct->Inv[HANDPOS]); } @@ -4622,7 +4691,7 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre } //NOW, IF SOME TRAITS HAVEN'T BEEN ASSIGNED, TRY TO ASSIGN DIFFERENT TRAITS - if (!ATraitAssigned || !BTraitAssigned || (!CTraitAssigned && ( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA )) ) + if ( !ATraitAssigned || !BTraitAssigned || (!CTraitAssigned && (ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA)) ) { INT8 bLoop; BOOLEAN foundMortar = FALSE; @@ -4638,29 +4707,29 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre BOOLEAN fMedKitFound = FALSE; // FIRST FIND OUT THE COMPOSITION OF OUR GEAR - INT8 invsize = (INT8)pSoldier->inv.size(); - for (bLoop = 0; bLoop < invsize; ++bLoop) + INT8 invsize = (INT8)pSoldier->inv.size( ); + for ( bLoop = 0; bLoop < invsize; ++bLoop ) { - if (pCreateStruct->Inv[bLoop].exists() == true) + if ( pCreateStruct->Inv[bLoop].exists( ) == true ) { - if (Item[pCreateStruct->Inv[bLoop].usItem].mortar ) + if ( Item[pCreateStruct->Inv[bLoop].usItem].mortar ) foundMortar = TRUE; - else if (Item[pCreateStruct->Inv[bLoop].usItem].rocketlauncher ) + else if ( Item[pCreateStruct->Inv[bLoop].usItem].rocketlauncher ) foundRocketlauncher = TRUE; - else if (Item[pCreateStruct->Inv[bLoop].usItem].grenadelauncher ) + else if ( Item[pCreateStruct->Inv[bLoop].usItem].grenadelauncher ) foundGrenadelauncher = TRUE; - else if (Item[pCreateStruct->Inv[bLoop].usItem].usItemClass == IC_BLADE ) + else if ( Item[pCreateStruct->Inv[bLoop].usItem].usItemClass == IC_BLADE ) foundKnife = TRUE; - else if (Item[pCreateStruct->Inv[bLoop].usItem].usItemClass == IC_THROWING_KNIFE ) + else if ( Item[pCreateStruct->Inv[bLoop].usItem].usItemClass == IC_THROWING_KNIFE ) foundThrowing = TRUE; - else if (Item[pCreateStruct->Inv[bLoop].usItem].usItemClass == IC_GRENADE ) + else if ( Item[pCreateStruct->Inv[bLoop].usItem].usItemClass == IC_GRENADE ) foundGrenades = TRUE; else if ( Item[pCreateStruct->Inv[bLoop].usItem].brassknuckles ) foundHtH = TRUE; - else if (Item[pCreateStruct->Inv[bLoop].usItem].usItemClass == 128 && // 128 is an identifier of blunt melee weapons - Item[pCreateStruct->Inv[bLoop].usItem].uiIndex != 0 ) + else if ( Item[pCreateStruct->Inv[bLoop].usItem].usItemClass == 128 && // 128 is an identifier of blunt melee weapons + Item[pCreateStruct->Inv[bLoop].usItem].uiIndex != 0 ) foundMelee = TRUE; - else if ( HasItemFlag(pCreateStruct->Inv[bLoop].usItem, RADIO_SET) ) + else if ( HasItemFlag( pCreateStruct->Inv[bLoop].usItem, RADIO_SET ) ) fRadioSetFound = TRUE; else if ( Item[pCreateStruct->Inv[bLoop].usItem].firstaidkit ) fFirstAidKitFound = TRUE; @@ -4675,17 +4744,18 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre // NOW BASED ON WHAT WE HAVE FOUND, ASSIGN UNASSIGNED TRAITS // Flugente: radio operator - if ( gGameOptions.fNewTraitSystem && (!ATraitAssigned || !BTraitAssigned || !CTraitAssigned ) ) + if ( gGameOptions.fNewTraitSystem && (!ATraitAssigned || !BTraitAssigned || !CTraitAssigned) ) { // if we have a radio set, give us the corresponding trait so we can use it... if ( fRadioSetFound ) { // this is a minor trait, so try to first fill the minor slot if possible + // reasoning: this trait has to be one of the first evaluated - getting a radio set is rare, so e want to make sure we become a radio guy if we're lucky if ( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) { pSoldier->stats.ubSkillTraits[2] = RADIO_OPERATOR_NT; CTraitAssigned = TRUE; - return( TRUE ); // We no longer need to continue from here + return(TRUE); // We no longer need to continue from here } else if ( !ATraitAssigned ) { @@ -4700,51 +4770,25 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre } } - // Flugente: enemy roles allow medics - if ( gGameExternalOptions.fEnemyRoles && gGameExternalOptions.fEnemyMedics && gGameOptions.fNewTraitSystem && (!ATraitAssigned || !BTraitAssigned ) ) - { - // if we have a radio set, give us the corresponding trait so we can use it... - if ( fFirstAidKitFound ) - { - if ( !ATraitAssigned ) - { - pSoldier->stats.ubSkillTraits[0] = DOCTOR_NT; - ATraitAssigned = TRUE; - - // if we found a medkit, chance to become a full doctor - if ( !BTraitAssigned && fMedKitFound && Chance(50) ) - { - pSoldier->stats.ubSkillTraits[1] = DOCTOR_NT; - BTraitAssigned = TRUE; - } - } - else if ( !BTraitAssigned ) - { - pSoldier->stats.ubSkillTraits[1] = DOCTOR_NT; - BTraitAssigned = TRUE; - } - } - } - // HEAVY WEAPONS TRAIT if ( foundMortar || foundRocketlauncher || foundGrenadelauncher ) { // setup basic chances based on soldier type - if( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) - iChance = 45 + ubProgress/2; // 45-95% chance - else if( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) - iChance = 30 + ubProgress/2; // 30-80% chance - else if( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) - iChance = 15 + ubProgress/2; // 15-65% chance + if ( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) + iChance = 45 + ubProgress / 2; // 45-95% chance + else if ( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) + iChance = 30 + ubProgress / 2; // 30-80% chance + else if ( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) + iChance = 15 + ubProgress / 2; // 15-65% chance // adust the chance by the type of heavy weapon - if (foundMortar) + if ( foundMortar ) iChance = 200; // instant chance if we are a mortar guy - else if (foundGrenadelauncher) + else if ( foundGrenadelauncher ) iChance -= 15; // -15% chance if we only have a grenade launcher // modify the chance by preset ini setting - if( gGameExternalOptions.bAssignedTraitsRarity != 0 ) + if ( gGameExternalOptions.bAssignedTraitsRarity != 0 ) { iChance += ((iChance * gGameExternalOptions.bAssignedTraitsRarity) / 100); } @@ -4760,16 +4804,16 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre pSoldier->stats.ubSkillTraits[0] = HEAVY_WEAPS_OT; ATraitAssigned = TRUE; - + // half the chance to be an expert - if ( Chance( iChance/2 ) && !BTraitAssigned ) + if ( Chance( iChance / 2 ) && !BTraitAssigned ) { if ( gGameOptions.fNewTraitSystem ) pSoldier->stats.ubSkillTraits[1] = HEAVY_WEAPONS_NT; else { pSoldier->stats.ubSkillTraits[1] = HEAVY_WEAPS_OT; - return( TRUE ); // We no longer need to continue from here + return(TRUE); // We no longer need to continue from here } BTraitAssigned = TRUE; } @@ -4781,7 +4825,7 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre else { pSoldier->stats.ubSkillTraits[1] = HEAVY_WEAPS_OT; - return( TRUE ); // We no longer need to continue from here + return(TRUE); // We no longer need to continue from here } BTraitAssigned = TRUE; } @@ -4789,25 +4833,25 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre } // MARTIAL ARTS - new traits - if (( !ATraitAssigned || !BTraitAssigned ) && gGameOptions.fNewTraitSystem ) + if ( (!ATraitAssigned || !BTraitAssigned) && gGameOptions.fNewTraitSystem ) { // setup basic chances based on soldier type - if( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) - iChance = 20 + ubProgress/4; // 20-45% chance - else if( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) - iChance = 10 + ubProgress/4; // 10-35% chance - else if( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) - iChance = ubProgress/4; // 0-25% chance + if ( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) + iChance = 20 + ubProgress / 4; // 20-45% chance + else if ( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) + iChance = 10 + ubProgress / 4; // 10-35% chance + else if ( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) + iChance = ubProgress / 4; // 0-25% chance #ifdef ENABLE_ZOMBIES - else if (ubSolClass == SOLDIER_CLASS_ZOMBIE ) + else if ( ubSolClass == SOLDIER_CLASS_ZOMBIE ) iChance = 100; // 100% chance #endif - if( foundHtH ) // if found brass knuckless, increase the chance (doesn't happen often) + if ( foundHtH ) // if found brass knuckless, increase the chance (doesn't happen often) iChance += 35; // modify the chance by preset ini setting - if( gGameExternalOptions.bAssignedTraitsRarity != 0 ) + if ( gGameExternalOptions.bAssignedTraitsRarity != 0 ) { iChance += ((iChance * gGameExternalOptions.bAssignedTraitsRarity) / 100); } @@ -4819,9 +4863,9 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre { pSoldier->stats.ubSkillTraits[0] = MARTIAL_ARTS_NT; ATraitAssigned = TRUE; - + // reduced chance to be an expert - if ( Chance( iChance/4 ) && !BTraitAssigned ) + if ( Chance( iChance / 4 ) && !BTraitAssigned ) { pSoldier->stats.ubSkillTraits[1] = MARTIAL_ARTS_NT; BTraitAssigned = TRUE; @@ -4836,22 +4880,22 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre } // NIGHT OPS TRAIT - if ( (DayTime() != TRUE) && (!ATraitAssigned || !BTraitAssigned || !CTraitAssigned) ) + if ( (DayTime( ) != TRUE) && (!ATraitAssigned || !BTraitAssigned || !CTraitAssigned) ) { // setup basic chances based on soldier type - if( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) - iChance = 40 + ubProgress*2/5; // 40-80% chance - else if( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) - iChance = 25 + ubProgress*2/5; // 25-65% chance - else if( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) - iChance = 10 + ubProgress*2/5; // 10-50% chance + if ( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) + iChance = 40 + ubProgress * 2 / 5; // 40-80% chance + else if ( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) + iChance = 25 + ubProgress * 2 / 5; // 25-65% chance + else if ( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) + iChance = 10 + ubProgress * 2 / 5; // 10-50% chance #ifdef ENABLE_ZOMBIES - else if (ubSolClass == SOLDIER_CLASS_ZOMBIE ) + else if ( ubSolClass == SOLDIER_CLASS_ZOMBIE ) iChance = 100; // 100% chance #endif // modify the chance by preset ini setting - if( gGameExternalOptions.bAssignedTraitsRarity != 0 ) + if ( gGameExternalOptions.bAssignedTraitsRarity != 0 ) { iChance += ((iChance * gGameExternalOptions.bAssignedTraitsRarity) / 100); } @@ -4861,7 +4905,7 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre { if ( !ATraitAssigned ) { - if (gGameOptions.fNewTraitSystem) + if ( gGameOptions.fNewTraitSystem ) { pSoldier->stats.ubSkillTraits[0] = NIGHT_OPS_NT; ATraitAssigned = TRUE; @@ -4872,31 +4916,31 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre ATraitAssigned = TRUE; // reduced chance to be an expert - if ( Chance( iChance*2/5 ) && !BTraitAssigned ) + if ( Chance( iChance * 2 / 5 ) && !BTraitAssigned ) { pSoldier->stats.ubSkillTraits[1] = NIGHTOPS_OT; BTraitAssigned = TRUE; - return( TRUE ); // We no longer need to continue from here + return(TRUE); // We no longer need to continue from here } } } else if ( !BTraitAssigned ) { - if (gGameOptions.fNewTraitSystem) + if ( gGameOptions.fNewTraitSystem ) pSoldier->stats.ubSkillTraits[1] = NIGHT_OPS_NT; else { pSoldier->stats.ubSkillTraits[1] = NIGHTOPS_OT; - return( TRUE ); // We no longer need to continue from here + return(TRUE); // We no longer need to continue from here } BTraitAssigned = TRUE; } // allow third only to elites - else if ( !CTraitAssigned && gGameOptions.fNewTraitSystem && ( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA )) + else if ( !CTraitAssigned && gGameOptions.fNewTraitSystem && (ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA) ) { pSoldier->stats.ubSkillTraits[2] = NIGHT_OPS_NT; CTraitAssigned = TRUE; - return( TRUE ); + return(TRUE); } } } @@ -4905,15 +4949,15 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre if ( (foundThrowing) && (!ATraitAssigned || !BTraitAssigned || !CTraitAssigned) ) { // setup basic chances based on soldier type - if( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) - iChance = 30 + ubProgress/3 + 30; // 60-92% chance - else if( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) - iChance = 15 + ubProgress/3 + 25; // 40-73% chance - else if( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) - iChance = ubProgress/3 + 20; // 20-53% chance + if ( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) + iChance = 30 + ubProgress / 3 + 30; // 60-92% chance + else if ( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) + iChance = 15 + ubProgress / 3 + 25; // 40-73% chance + else if ( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) + iChance = ubProgress / 3 + 20; // 20-53% chance // modify the chance by preset ini setting - if( gGameExternalOptions.bAssignedTraitsRarity != 0 ) + if ( gGameExternalOptions.bAssignedTraitsRarity != 0 ) { iChance += ((iChance * gGameExternalOptions.bAssignedTraitsRarity) / 100); } @@ -4923,7 +4967,7 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre { if ( !ATraitAssigned ) { - if (gGameOptions.fNewTraitSystem) + if ( gGameOptions.fNewTraitSystem ) { pSoldier->stats.ubSkillTraits[0] = THROWING_NT; ATraitAssigned = TRUE; @@ -4934,49 +4978,49 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre ATraitAssigned = TRUE; // reduced the chance to be an expert - if ( Chance( iChance*2/5 ) && !BTraitAssigned ) + if ( Chance( iChance * 2 / 5 ) && !BTraitAssigned ) { pSoldier->stats.ubSkillTraits[1] = THROWING_OT; BTraitAssigned = TRUE; - return( TRUE ); // We no longer need to continue from here + return(TRUE); // We no longer need to continue from here } } } else if ( !BTraitAssigned ) { - if (gGameOptions.fNewTraitSystem) + if ( gGameOptions.fNewTraitSystem ) pSoldier->stats.ubSkillTraits[1] = THROWING_NT; else { pSoldier->stats.ubSkillTraits[1] = THROWING_OT; - return( TRUE ); // We no longer need to continue from here + return(TRUE); // We no longer need to continue from here } BTraitAssigned = TRUE; } // allow third only to elites - else if ( !CTraitAssigned && gGameOptions.fNewTraitSystem && ( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA )) + else if ( !CTraitAssigned && gGameOptions.fNewTraitSystem && (ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA) ) { pSoldier->stats.ubSkillTraits[2] = THROWING_NT; CTraitAssigned = TRUE; - return( TRUE ); + return(TRUE); } } } // DEMOLITIONS TRAIT - if ( (foundGrenades) && (gGameOptions.fNewTraitSystem)&& (!ATraitAssigned || !BTraitAssigned || !CTraitAssigned) ) + if ( (foundGrenades) && (gGameOptions.fNewTraitSystem) && (!ATraitAssigned || !BTraitAssigned || !CTraitAssigned) ) { // setup basic chances based on soldier type - if( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) - iChance = 20 + ubProgress/3; // 20-53% chance - else if( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) - iChance = 10 + ubProgress/3; // 10-43% chance - else if( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) - iChance = ubProgress/3; // 0-33% chance + if ( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) + iChance = 20 + ubProgress / 3; // 20-53% chance + else if ( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) + iChance = 10 + ubProgress / 3; // 10-43% chance + else if ( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) + iChance = ubProgress / 3; // 0-33% chance // modify the chance by preset ini setting - if( gGameExternalOptions.bAssignedTraitsRarity != 0 ) + if ( gGameExternalOptions.bAssignedTraitsRarity != 0 ) { iChance += ((iChance * gGameExternalOptions.bAssignedTraitsRarity) / 100); } @@ -4995,28 +5039,28 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre BTraitAssigned = TRUE; } // allow third only to elites - else if ( !CTraitAssigned && gGameOptions.fNewTraitSystem && ( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA )) + else if ( !CTraitAssigned && gGameOptions.fNewTraitSystem && (ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA) ) { pSoldier->stats.ubSkillTraits[2] = DEMOLITIONS_NT; CTraitAssigned = TRUE; - return( TRUE ); + return(TRUE); } } } // MELEE / KNIFING TRAIT - if ( ( foundKnife || (foundMelee && gGameOptions.fNewTraitSystem)) && (!ATraitAssigned || !BTraitAssigned || !CTraitAssigned) ) + if ( (foundKnife || (foundMelee && gGameOptions.fNewTraitSystem)) && (!ATraitAssigned || !BTraitAssigned || !CTraitAssigned) ) { // setup basic chances based on soldier type - if( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) - iChance = 50 + ubProgress*2/5; // 50-90% chance - else if( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) - iChance = 35 + ubProgress*2/5; // 35-75% chance - else if( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) - iChance = 15 + ubProgress*2/5; // 15-55% chance + if ( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) + iChance = 50 + ubProgress * 2 / 5; // 50-90% chance + else if ( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) + iChance = 35 + ubProgress * 2 / 5; // 35-75% chance + else if ( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) + iChance = 15 + ubProgress * 2 / 5; // 15-55% chance // modify the chance by preset ini setting - if( gGameExternalOptions.bAssignedTraitsRarity != 0 ) + if ( gGameExternalOptions.bAssignedTraitsRarity != 0 ) { iChance += ((iChance * gGameExternalOptions.bAssignedTraitsRarity) / 100); } @@ -5027,7 +5071,7 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre if ( !ATraitAssigned ) { - if (gGameOptions.fNewTraitSystem) + if ( gGameOptions.fNewTraitSystem ) { pSoldier->stats.ubSkillTraits[0] = MELEE_NT; ATraitAssigned = TRUE; @@ -5038,48 +5082,48 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre ATraitAssigned = TRUE; // reduced the chance to be an expert - if ( Chance( iChance*2/5 ) && !BTraitAssigned ) + if ( Chance( iChance * 2 / 5 ) && !BTraitAssigned ) { pSoldier->stats.ubSkillTraits[1] = KNIFING_OT; BTraitAssigned = TRUE; - return( TRUE ); // We no longer need to continue from here + return(TRUE); // We no longer need to continue from here } } } else if ( !BTraitAssigned ) { - if (gGameOptions.fNewTraitSystem) + if ( gGameOptions.fNewTraitSystem ) pSoldier->stats.ubSkillTraits[1] = MELEE_NT; else { pSoldier->stats.ubSkillTraits[1] = KNIFING_OT; - return( TRUE ); // We no longer need to continue from here + return(TRUE); // We no longer need to continue from here } BTraitAssigned = TRUE; } // allow third only to elites - else if ( !CTraitAssigned && gGameOptions.fNewTraitSystem && ( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA )) + else if ( !CTraitAssigned && gGameOptions.fNewTraitSystem && (ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA) ) { pSoldier->stats.ubSkillTraits[2] = MELEE_NT; CTraitAssigned = TRUE; - return( TRUE ); // We no longer need to continue from here + return(TRUE); // We no longer need to continue from here } } } // HAND TO HAND TRAIT - old traits nly - if ( foundHtH && !gGameOptions.fNewTraitSystem && (!ATraitAssigned || !BTraitAssigned ) ) + if ( foundHtH && !gGameOptions.fNewTraitSystem && (!ATraitAssigned || !BTraitAssigned) ) { // setup basic chances based on soldier type - if( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) - iChance = 40 + ubProgress*2/5; // 40-80% chance - else if( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) - iChance = 25 + ubProgress*2/5; // 25-65% chance - else if( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) - iChance = 10 + ubProgress*2/5; // 10-50% chance + if ( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) + iChance = 40 + ubProgress * 2 / 5; // 40-80% chance + else if ( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) + iChance = 25 + ubProgress * 2 / 5; // 25-65% chance + else if ( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) + iChance = 10 + ubProgress * 2 / 5; // 10-50% chance // modify the chance by preset ini setting - if( gGameExternalOptions.bAssignedTraitsRarity != 0 ) + if ( gGameExternalOptions.bAssignedTraitsRarity != 0 ) { iChance += ((iChance * gGameExternalOptions.bAssignedTraitsRarity) / 100); } @@ -5091,37 +5135,37 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre { pSoldier->stats.ubSkillTraits[0] = HANDTOHAND_OT; ATraitAssigned = TRUE; - + // half the chance to be an expert - if ( Chance( iChance*2/5 ) && !BTraitAssigned ) + if ( Chance( iChance * 2 / 5 ) && !BTraitAssigned ) { pSoldier->stats.ubSkillTraits[1] = HANDTOHAND_OT; BTraitAssigned = TRUE; - return( TRUE ); // We no longer need to continue from here + return(TRUE); // We no longer need to continue from here } } else if ( !BTraitAssigned ) { pSoldier->stats.ubSkillTraits[1] = HANDTOHAND_OT; BTraitAssigned = TRUE; - return( TRUE ); // We no longer need to continue from here + return(TRUE); // We no longer need to continue from here } } } // MARTIAL ARTS - old traits - if (( !ATraitAssigned || !BTraitAssigned ) && !gGameOptions.fNewTraitSystem && (pCreateStruct->bBodyType == REGMALE)) + if ( (!ATraitAssigned || !BTraitAssigned) && !gGameOptions.fNewTraitSystem && (pCreateStruct->bBodyType == REGMALE) ) { // setup basic chances based on soldier type - if( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) - iChance = 10 + ubProgress/4; // 10-35% chance - else if( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) - iChance = ubProgress/5; // 0-20% chance - else if( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) + if ( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) + iChance = 10 + ubProgress / 4; // 10-35% chance + else if ( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) + iChance = ubProgress / 5; // 0-20% chance + else if ( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) iChance = 0; // 0% chance // modify the chance by preset ini setting - if( gGameExternalOptions.bAssignedTraitsRarity != 0 ) + if ( gGameExternalOptions.bAssignedTraitsRarity != 0 ) { iChance += ((iChance * gGameExternalOptions.bAssignedTraitsRarity) / 100); } @@ -5133,37 +5177,37 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre { pSoldier->stats.ubSkillTraits[0] = MARTIALARTS_OT; ATraitAssigned = TRUE; - + // reduced chance to be an expert - if ( Chance( iChance/2 ) && !BTraitAssigned ) + if ( Chance( iChance / 2 ) && !BTraitAssigned ) { pSoldier->stats.ubSkillTraits[1] = MARTIALARTS_OT; BTraitAssigned = TRUE; - return( TRUE ); // We no longer need to continue from here + return(TRUE); // We no longer need to continue from here } } else if ( !BTraitAssigned ) { pSoldier->stats.ubSkillTraits[1] = MARTIALARTS_OT; BTraitAssigned = TRUE; - return( TRUE ); // We no longer need to continue from here + return(TRUE); // We no longer need to continue from here } } } // BODYBUILDING/ATHLETICS TRAITS (only for new traits) - if ( gGameOptions.fNewTraitSystem && (!ATraitAssigned || !BTraitAssigned || !CTraitAssigned ) ) + if ( gGameOptions.fNewTraitSystem && (!ATraitAssigned || !BTraitAssigned || !CTraitAssigned) ) { // setup basic chances based on soldier type - if( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) - iChance = 30 + ubProgress/2; // 30-90% chance - else if( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) - iChance = 10 + ubProgress/2; // 10-60% chance - else if( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) - iChance = ubProgress/3; // 0-33% chance + if ( ubSolClass == SOLDIER_CLASS_ELITE || ubSolClass == SOLDIER_CLASS_ELITE_MILITIA ) + iChance = 30 + ubProgress / 2; // 30-90% chance + else if ( ubSolClass == SOLDIER_CLASS_ARMY || ubSolClass == SOLDIER_CLASS_REG_MILITIA ) + iChance = 10 + ubProgress / 2; // 10-60% chance + else if ( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA ) + iChance = ubProgress / 3; // 0-33% chance // modify the chance by preset ini setting - if( gGameExternalOptions.bAssignedTraitsRarity != 0 ) + if ( gGameExternalOptions.bAssignedTraitsRarity != 0 ) { iChance += ((iChance * gGameExternalOptions.bAssignedTraitsRarity) / 100); } @@ -5195,10 +5239,10 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre { pSoldier->stats.ubSkillTraits[2] = BODYBUILDING_NT; CTraitAssigned = TRUE; - return( TRUE ); // We no longer need to continue from here + return(TRUE); // We no longer need to continue from here } // give us also a small chance to get athletics on top - if ( Chance( iChance/3 ) && ( !ATraitAssigned || !BTraitAssigned || !CTraitAssigned )) + if ( Chance( iChance / 3 ) && (!ATraitAssigned || !BTraitAssigned || !CTraitAssigned) ) { if ( !ATraitAssigned ) { @@ -5214,7 +5258,7 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre { pSoldier->stats.ubSkillTraits[2] = ATHLETICS_NT; CTraitAssigned = TRUE; - return( TRUE ); // We no longer need to continue from here + return(TRUE); // We no longer need to continue from here } } } @@ -5234,10 +5278,10 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre { pSoldier->stats.ubSkillTraits[2] = ATHLETICS_NT; CTraitAssigned = TRUE; - return( TRUE ); // We no longer need to continue from here + return(TRUE); // We no longer need to continue from here } // give us also a small chance to get bodybuilding on top - if ( Chance( iChance/3 ) && ( !ATraitAssigned || !BTraitAssigned || !CTraitAssigned )) + if ( Chance( iChance / 3 ) && (!ATraitAssigned || !BTraitAssigned || !CTraitAssigned) ) { if ( !ATraitAssigned ) { @@ -5253,17 +5297,48 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre { pSoldier->stats.ubSkillTraits[2] = BODYBUILDING_NT; CTraitAssigned = TRUE; - return( TRUE ); // We no longer need to continue from here + return(TRUE); // We no longer need to continue from here } } } } } - } + // Flugente: enemy roles: allow medics + if ( gGameExternalOptions.fEnemyRoles && gGameExternalOptions.fEnemyMedics && gGameOptions.fNewTraitSystem && (!ATraitAssigned || !BTraitAssigned) ) + { + // if we have a radio set, give us the corresponding trait so we can use it... + if ( fFirstAidKitFound ) + { + if ( !ATraitAssigned ) + { + pSoldier->stats.ubSkillTraits[0] = DOCTOR_NT; + ATraitAssigned = TRUE; + + // if we found a medkit, chance to become a full doctor + if ( !BTraitAssigned && fMedKitFound && Chance( 50 ) ) + { + pSoldier->stats.ubSkillTraits[1] = DOCTOR_NT; + BTraitAssigned = TRUE; + } + + // make sure we ar reasonably skilled + pSoldier->stats.bMedical = max( pSoldier->stats.bMedical, 50 ); + } + else if ( !BTraitAssigned ) + { + pSoldier->stats.ubSkillTraits[1] = DOCTOR_NT; + BTraitAssigned = TRUE; + + // make sure we ar reasonably skilled + pSoldier->stats.bMedical = max( pSoldier->stats.bMedical, 50 ); + } + } + } + } // RETURN TRUE IF ALL TRAITS ASSIGNED OTHERWISE FALSE - if (( !gGameOptions.fNewTraitSystem && ATraitAssigned && BTraitAssigned ) || ( gGameOptions.fNewTraitSystem && ATraitAssigned && BTraitAssigned && CTraitAssigned ) ) - return( TRUE ); - - return( FALSE ); + if ( (!gGameOptions.fNewTraitSystem && ATraitAssigned && BTraitAssigned) || (gGameOptions.fNewTraitSystem && ATraitAssigned && BTraitAssigned && CTraitAssigned) ) + return(TRUE); + else + return(FALSE); } diff --git a/Tactical/XML_Background.cpp b/Tactical/XML_Background.cpp index a99f4d12..09ec68e8 100644 --- a/Tactical/XML_Background.cpp +++ b/Tactical/XML_Background.cpp @@ -132,7 +132,9 @@ backgroundStartElementHandle(void *userData, const XML_Char *name, const XML_Cha strcmp(name, "scrounging") == 0 || strcmp(name, "traplevel") == 0 || strcmp(name, "no_male") == 0 || - strcmp(name, "no_female") == 0 )) + strcmp(name, "no_female") == 0 || + strcmp( name, "loyalitylossondeath" ) == 0 )) + { pData->curElement = ELEMENT_PROPERTY; @@ -557,7 +559,12 @@ backgroundEndElementHandle(void *userData, const XML_Char *name) pData->curElement = ELEMENT; pData->curBackground.uiFlags |= (UINT16) atol(pData->szCharData) ? BACKGROUND_NO_FEMALE : 0; } - + else if ( strcmp( name, "loyalitylossondeath" ) == 0 ) + { + pData->curElement = ELEMENT; + pData->curBackground.uiFlags |= (UINT16)atol( pData->szCharData ) ? BACKGROUND_GLOBALOYALITYLOSSONDEATH : 0; + } + pData->maxReadDepth--; } pData->currentDepth--; diff --git a/TacticalAI/AIMain.cpp b/TacticalAI/AIMain.cpp index 7641fe53..3447830d 100644 --- a/TacticalAI/AIMain.cpp +++ b/TacticalAI/AIMain.cpp @@ -2562,6 +2562,12 @@ void HandleAITacticalTraversal( SOLDIERTYPE * pSoldier ) } #endif + // Flugente: VIPs: if a VIP flees, he flees to Meduna (in fact te sodleir doesn't, we simply move the flag to another sector) + if ( pSoldier->usSoldierFlagMask & SOLDIER_VIP ) + { + VIPFleesToMeduna(); + } + EndAIGuysTurn( pSoldier ); RemoveManAsTarget( pSoldier ); if (pSoldier->bTeam == CIV_TEAM && pSoldier->aiData.fAIFlags & AI_CHECK_SCHEDULE) diff --git a/TacticalAI/DecideAction.cpp b/TacticalAI/DecideAction.cpp index a3ac53d7..950f94f5 100644 --- a/TacticalAI/DecideAction.cpp +++ b/TacticalAI/DecideAction.cpp @@ -35,6 +35,7 @@ #endif #include "connect.h" #include "Text.h" +#include "Exit Grids.h" // added by Flugente ////////////////////////////////////////////////////////////////////////////// // SANDRO - In this file, all APBPConstants[AP_CROUCH] and APBPConstants[AP_PRONE] were changed to GetAPsCrouch() and GetAPsProne() @@ -1002,6 +1003,27 @@ INT8 DecideActionGreen(SOLDIERTYPE *pSoldier) } } } + + // are we a bodyguard? + if ( pSoldier->usSoldierFlagMask & SOLDIER_BODYGUARD ) + { + // is VIP still alive? + UINT16 ubPerson = GetClosestFlaggedSoldierID( pSoldier, 100, pSoldier->bTeam, SOLDIER_VIP, FALSE ); + + if ( ubPerson != NOBODY ) + { + // we want to stay close to him, but still be able to function properly... stay withing a 7-tile radius + if ( SpacesAway( pSoldier->sGridNo, MercPtrs[ubPerson]->sGridNo ) > 7 ) + { + pSoldier->aiData.usActionData = InternalGoAsFarAsPossibleTowards( pSoldier, MercPtrs[ubPerson]->sGridNo, 20, AI_ACTION_SEEK_FRIEND, 0 ); + + if ( !TileIsOutOfBounds( pSoldier->aiData.usActionData ) ) + { + return(AI_ACTION_SEEK_FRIEND); + } + } + } + } } //ddd} @@ -1716,6 +1738,27 @@ INT8 DecideActionYellow(SOLDIERTYPE *pSoldier) } } } + + // are we a bodyguard? + if ( pSoldier->usSoldierFlagMask & SOLDIER_BODYGUARD ) + { + // is VIP still alive? + UINT16 ubPerson = GetClosestFlaggedSoldierID( pSoldier, 100, pSoldier->bTeam, SOLDIER_VIP, FALSE ); + + if ( ubPerson != NOBODY ) + { + // we want to stay close to him, but still be able to function properly... stay withing a 7-tile radius + if ( SpacesAway( pSoldier->sGridNo, MercPtrs[ubPerson]->sGridNo ) > 7 ) + { + pSoldier->aiData.usActionData = InternalGoAsFarAsPossibleTowards( pSoldier, MercPtrs[ubPerson]->sGridNo, 20, AI_ACTION_SEEK_FRIEND, 0 ); + + if ( !TileIsOutOfBounds( pSoldier->aiData.usActionData ) ) + { + return(AI_ACTION_SEEK_FRIEND); + } + } + } + } } //////////////////////////////////////////////////////////////////////////// @@ -3071,6 +3114,46 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK) } } } + + // VIPs run away (but not the GENERAL) + if ( pSoldier->usSoldierFlagMask & SOLDIER_VIP && pSoldier->ubProfile != GENERAL ) + { + // this is in red AI state - a firefight is going on, we try to escape + pSoldier->aiData.usActionData = FindSpotMaxDistFromOpponents( pSoldier ); + + // if we don't know where our opponents are, we cannot run away from them... + if ( TileIsOutOfBounds( pSoldier->aiData.usActionData ) ) + { + // search for the closest map edge + pSoldier->aiData.usActionData = FindClosestExitGrid( pSoldier, pSoldier->sGridNo, 200 ); + } + + if ( !TileIsOutOfBounds( pSoldier->aiData.usActionData ) ) + { + return AI_ACTION_RUN_AWAY; + } + } + + // are we a bodyguard? + if ( pSoldier->usSoldierFlagMask & SOLDIER_BODYGUARD ) + { + // is VIP still alive? + UINT16 ubPerson = GetClosestFlaggedSoldierID( pSoldier, 100, pSoldier->bTeam, SOLDIER_VIP, FALSE ); + + if ( ubPerson != NOBODY ) + { + // we want to stay close to him, but still be able to function properly... stay withing a 7-tile radius + if ( SpacesAway( pSoldier->sGridNo, MercPtrs[ubPerson]->sGridNo ) > 7 ) + { + pSoldier->aiData.usActionData = InternalGoAsFarAsPossibleTowards( pSoldier, MercPtrs[ubPerson]->sGridNo, 20, AI_ACTION_SEEK_FRIEND, 0 ); + + if ( !TileIsOutOfBounds( pSoldier->aiData.usActionData ) ) + { + return(AI_ACTION_SEEK_FRIEND); + } + } + } + } } //////////////////////////////////////////////////////////////////////////// @@ -4345,7 +4428,6 @@ INT16 ubMinAPCost; } else if ( gTacticalStatus.bBoxingState == BOXING ) { - bInWater = FALSE; bInDeepWater = FALSE; bInGas = FALSE; @@ -4361,7 +4443,6 @@ INT16 ubMinAPCost; } else { - // determine if we happen to be in water (in which case we're in BIG trouble!) bInWater = Water( pSoldier->sGridNo ); bInDeepWater = WaterTooDeepForAttacks( pSoldier->sGridNo ); @@ -4679,6 +4760,25 @@ INT16 ubMinAPCost; } } + // VIPs run away (but not the GENERAL) + if ( pSoldier->usSoldierFlagMask & SOLDIER_VIP && pSoldier->ubProfile != GENERAL ) + { + // this is in red AI state - a firefight is going on, we try to escape + pSoldier->aiData.usActionData = FindSpotMaxDistFromOpponents( pSoldier ); + + // if we don't know where our opponents are, we cannot run away from them... + if ( TileIsOutOfBounds( pSoldier->aiData.usActionData ) ) + { + // search for the closest map edge + pSoldier->aiData.usActionData = FindClosestExitGrid( pSoldier, pSoldier->sGridNo, 200 ); + } + + if ( !TileIsOutOfBounds( pSoldier->aiData.usActionData ) ) + { + return AI_ACTION_RUN_AWAY; + } + } + BestShot.ubPossible = FALSE; // by default, assume Shooting isn't possible BestThrow.ubPossible = FALSE; // by default, assume Throwing isn't possible BestStab.ubPossible = FALSE; // by default, assume Stabbing isn't possible diff --git a/Utils/Text.h b/Utils/Text.h index 43d6bf75..a41ab43e 100644 --- a/Utils/Text.h +++ b/Utils/Text.h @@ -842,6 +842,7 @@ enum STR_PRISONER_REFUSE_TAKE_PRISONERS, SRT_PRISONER_INI_SETTING_OFF, STR_PRISONER_X_FREES_Y, + STR_PRISONER_DETECTION_VIP, TEXT_NUM_PRISONER_STR }; diff --git a/Utils/_ChineseText.cpp b/Utils/_ChineseText.cpp index 8202cb2c..65f8dfab 100644 --- a/Utils/_ChineseText.cpp +++ b/Utils/_ChineseText.cpp @@ -8060,6 +8060,7 @@ STR16 szPrisonerTextStr[]= L"敌人不肯拿你当囚犯 - 他们宁愿你死!", //L"The enemy refuses to take you as prisoners - they prefer you dead!", L"这些可以在 INI 设置关闭。", // L"This behaviour is set OFF in your ini settings.", L"%s释放了%s!", //L"%s has freed %s!", + L"A prisoner revealed the location of a high-ranking army officer in %s!", // TODO.Translate }; STR16 szMTATextStr[]= @@ -8093,6 +8094,8 @@ STR16 szBackgroundText_Flags[]= L" 会导致附近的佣兵腐败\n", //L" spreads corruption to nearby mercs\n", L" female only", // won't show up, text exists for compatibility reasons L" male only", // won't show up, text exists for compatibility reasons + + L" huge loyality penalty in all towns if we die\n", // TODO.Translate }; STR16 szBackgroundText_Value[]= diff --git a/Utils/_DutchText.cpp b/Utils/_DutchText.cpp index 391cda3b..c8c8e303 100644 --- a/Utils/_DutchText.cpp +++ b/Utils/_DutchText.cpp @@ -8072,6 +8072,7 @@ STR16 szPrisonerTextStr[]= L"The enemy refuses to take you as prisoners - they prefer you dead!", L"This behaviour is set OFF in your ini settings.", L"%s has freed %s!", + L"A prisoner revealed the location of a high-ranking army officer in %s!", // TODO.Translate }; STR16 szMTATextStr[]= // TODO.Translate @@ -8106,6 +8107,8 @@ STR16 szBackgroundText_Flags[]= L" spreads corruption to nearby mercs\n", L" female only", // won't show up, text exists for compatibility reasons L" male only", // won't show up, text exists for compatibility reasons + + L" huge loyality penalty in all towns if we die\n", // TODO.Translate }; // TODO.Translate diff --git a/Utils/_EnglishText.cpp b/Utils/_EnglishText.cpp index 8620ec3b..3012a19d 100644 --- a/Utils/_EnglishText.cpp +++ b/Utils/_EnglishText.cpp @@ -8057,6 +8057,7 @@ STR16 szPrisonerTextStr[]= L"The enemy refuses to take you as prisoners - they prefer you dead!", L"This behaviour is set OFF in your ini settings.", L"%s has freed %s!", + L"A prisoner revealed the location of a high-ranking army officer in %s!", }; STR16 szMTATextStr[]= @@ -8083,13 +8084,15 @@ STR16 szBackgroundText_Flags[]= { L" might consume drugs in inventory\n", L" disregard for other backgrounds\n", - L" +1 level in underground sectors\n", + L" +1 level in underground sectors\n", L" might steal items\n", L" +1 traplevel to planted bombs\n", L" spreads corruption to nearby mercs\n", L" female only", // won't show up, text exists for compatibility reasons L" male only", // won't show up, text exists for compatibility reasons + + L" huge loyality penalty in all towns if we die\n", }; STR16 szBackgroundText_Value[]= diff --git a/Utils/_FrenchText.cpp b/Utils/_FrenchText.cpp index 860f1052..55be0e7a 100644 --- a/Utils/_FrenchText.cpp +++ b/Utils/_FrenchText.cpp @@ -8058,6 +8058,7 @@ STR16 szPrisonerTextStr[]= L"L'ennemi refuse votre reddition... Ils veulent vos têtes !", L"Ce comportement est désactivé dans vos fichiers ini.", L"%s a libéré %s !", + L"A prisoner revealed the location of a high-ranking army officer in %s!", // TODO.Translate }; STR16 szMTATextStr[]= @@ -8092,6 +8093,8 @@ STR16 szBackgroundText_Flags[]= L" répand la corruption aux mercenaires proches\n", L" femme seulement", // won't show up, text exists for compatibility reasons L" homme seulement", // won't show up, text exists for compatibility reasons + + L" huge loyality penalty in all towns if we die\n", // TODO.Translate }; diff --git a/Utils/_GermanText.cpp b/Utils/_GermanText.cpp index dc2e7a8b..c2832140 100644 --- a/Utils/_GermanText.cpp +++ b/Utils/_GermanText.cpp @@ -7885,6 +7885,7 @@ STR16 szPrisonerTextStr[]= L"Der Feind weigert sich, Sie als Gefangenen zu nehmen - Er möchte Sie tod sehen!", L"Dieses Verhalten ist ausgeschaltet in der ja2_options.ini Datei.", L"%s hat %s befreit!", + L"A prisoner revealed the location of a high-ranking army officer in %s!", // TODO.Translate }; STR16 szMTATextStr[]= @@ -7919,6 +7920,8 @@ STR16 szBackgroundText_Flags[]= L" spreads corruption to nearby mercs\n", L" female only", // won't show up, text exists for compatibility reasons L" male only", // won't show up, text exists for compatibility reasons + + L" huge loyality penalty in all towns if we die\n", // TODO.Translate }; // TODO.Translate diff --git a/Utils/_ItalianText.cpp b/Utils/_ItalianText.cpp index 93ca3c97..8b904bcb 100644 --- a/Utils/_ItalianText.cpp +++ b/Utils/_ItalianText.cpp @@ -8063,6 +8063,7 @@ STR16 szPrisonerTextStr[]= L"The enemy refuses to take you as prisoners - they prefer you dead!", L"This behaviour is set OFF in your ini settings.", L"%s has freed %s!", + L"A prisoner revealed the location of a high-ranking army officer in %s!", // TODO.Translate }; STR16 szMTATextStr[]= // TODO.Translate @@ -8098,6 +8099,8 @@ STR16 szBackgroundText_Flags[]= L" spreads corruption to nearby mercs\n", L" female only", // won't show up, text exists for compatibility reasons L" male only", // won't show up, text exists for compatibility reasons + + L" huge loyality penalty in all towns if we die\n", // TODO.Translate }; // TODO.Translate diff --git a/Utils/_PolishText.cpp b/Utils/_PolishText.cpp index c58e58c4..0e50f4bb 100644 --- a/Utils/_PolishText.cpp +++ b/Utils/_PolishText.cpp @@ -8081,6 +8081,7 @@ STR16 szPrisonerTextStr[]= L"The enemy refuses to take you as prisoners - they prefer you dead!", L"This behaviour is set OFF in your ini settings.", L"%s has freed %s!", + L"A prisoner revealed the location of a high-ranking army officer in %s!", // TODO.Translate }; STR16 szMTATextStr[]= // TODO.Translate @@ -8115,6 +8116,8 @@ STR16 szBackgroundText_Flags[]= L" spreads corruption to nearby mercs\n", L" female only", // won't show up, text exists for compatibility reasons L" male only", // won't show up, text exists for compatibility reasons + + L" huge loyality penalty in all towns if we die\n", // TODO.Translate }; // TODO.Translate diff --git a/Utils/_RussianText.cpp b/Utils/_RussianText.cpp index e62f1d8d..af5b67d4 100644 --- a/Utils/_RussianText.cpp +++ b/Utils/_RussianText.cpp @@ -8061,6 +8061,7 @@ STR16 szPrisonerTextStr[]= L"The enemy refuses to take you as prisoners - they prefer you dead!", L"This behaviour is set OFF in your ini settings.", L"%s has freed %s!", + L"A prisoner revealed the location of a high-ranking army officer in %s!", // TODO.Translate }; STR16 szMTATextStr[]= // TODO.Translate @@ -8095,6 +8096,8 @@ STR16 szBackgroundText_Flags[]= L" spreads corruption to nearby mercs\n", L" female only", // won't show up, text exists for compatibility reasons L" male only", // won't show up, text exists for compatibility reasons + + L" huge loyality penalty in all towns if we die\n", // TODO.Translate }; // TODO.Translate diff --git a/Utils/_TaiwaneseText.cpp b/Utils/_TaiwaneseText.cpp index 8ec45cc9..5dafaf8c 100644 --- a/Utils/_TaiwaneseText.cpp +++ b/Utils/_TaiwaneseText.cpp @@ -8072,6 +8072,7 @@ STR16 szPrisonerTextStr[]= L"The enemy refuses to take you as prisoners - they prefer you dead!", L"This behaviour is set OFF in your ini settings.", L"%s has freed %s!", + L"A prisoner revealed the location of a high-ranking army officer in %s!", // TODO.Translate }; STR16 szMTATextStr[]= // TODO.Translate @@ -8106,6 +8107,8 @@ STR16 szBackgroundText_Flags[]= L" spreads corruption to nearby mercs\n", L" female only", // won't show up, text exists for compatibility reasons L" male only", // won't show up, text exists for compatibility reasons + + L" huge loyality penalty in all towns if we die\n", // TODO.Translate }; // TODO.Translate