From 3952b34e29108ad0aa45692019f5d3e8407a0b83 Mon Sep 17 00:00:00 2001 From: Dev Date: Wed, 18 Sep 2024 11:36:45 +0100 Subject: [PATCH] Added config system to adjust raid hostility settings Removed `enemyTypes` from pmcconfig --- project/assets/configs/pmc.json | 75 ++++++++++--------- project/src/models/spt/config/IPmcConfig.ts | 15 +++- .../src/services/LocationLifecycleService.ts | 74 +++++++++++++++++- 3 files changed, 124 insertions(+), 40 deletions(-) diff --git a/project/assets/configs/pmc.json b/project/assets/configs/pmc.json index 343a5140..75d073d9 100644 --- a/project/assets/configs/pmc.json +++ b/project/assets/configs/pmc.json @@ -773,43 +773,44 @@ "max": 0 } }, - "enemyTypes": [ - "assault", - "marksman", - "pmcBot", - "bossBully", - "bossKilla", - "bossKojaniy", - "bossGluhar", - "bossSanitar", - "bossTagilla", - "bossKnight", - "bossZryachiy", - "bossBoar", - "bossBoarSniper", - "bossKolontay", - "bossPartisan", - "followerBully", - "followerKojaniy", - "followerGluharAssault", - "followerGluharSecurity", - "followerGluharScout", - "followerGluharSnipe", - "followerSanitar", - "followerBirdEye", - "followerBigPipe", - "followerZryachiy", - "followerBoar", - "followerBoarClose1", - "followerBoarClose2", - "followerKolontayAssault", - "followerKolontaySecurity", - "arenaFighter", - "arenaFighterEvent", - "crazyAssaultEvent", - "sectantWarrior", - "sectantPriest" - ], + "hostilitySettings": { + "pmcbear": { + "additionalEnemyTypes": [ + "bossPartizan" + ], + "ChancedEnemies": [{ + "EnemyChance": 100, + "Role": "assault" + }, { + "EnemyChance": 100, + "Role": "marksman" + }, { + "EnemyChance": 85, + "Role": "pmcUSEC" + } + ], + "BearEnemyChance": 85, + "UsecEnemyChance": 100 + }, + "pmcbear": { + "additionalEnemyTypes": [ + "bossPartizan" + ], + "ChancedEnemies": [{ + "EnemyChance": 100, + "Role": "assault" + }, { + "EnemyChance": 100, + "Role": "marksman" + }, { + "EnemyChance": 85, + "Role": "pmcBEAR" + } + ], + "BearEnemyChance": 85, + "UsecEnemyChance": 100 + } + }, "forceHealingItemsIntoSecure": true, "addPrefixToSameNamePMCAsPlayerChance": 40, "allPMCsHavePlayerNameWithRandomPrefixChance": 1, diff --git a/project/src/models/spt/config/IPmcConfig.ts b/project/src/models/spt/config/IPmcConfig.ts index 15db98a7..2129c666 100644 --- a/project/src/models/spt/config/IPmcConfig.ts +++ b/project/src/models/spt/config/IPmcConfig.ts @@ -1,4 +1,5 @@ import { MinMax } from "@spt/models/common/MinMax"; +import { IChancedEnemy } from "@spt/models/eft/common/ILocationBase"; import { MemberCategory } from "@spt/models/enums/MemberCategory"; import { IBaseConfig } from "@spt/models/spt/config/IBaseConfig"; @@ -37,20 +38,30 @@ export interface IPmcConfig extends IBaseConfig { maxVestLootTotalRub: number; /** Percentage chance a bot from a wave is converted into a PMC, key = bot wildspawn tpye (assault/exusec), value: min+max chance to be converted */ convertIntoPmcChance: Record; - /** WildSpawnType bots PMCs should see as hostile */ - enemyTypes: string[]; /** How many levels above player level can a PMC be */ botRelativeLevelDeltaMax: number; /** How many levels below player level can a PMC be */ botRelativeLevelDeltaMin: number; /** Force a number of healing items into PMCs secure container to ensure they can heal */ forceHealingItemsIntoSecure: boolean; + hostilitySettings: Record; allPMCsHavePlayerNameWithRandomPrefixChance: number; locationSpecificPmcLevelOverride: Record; /** Should secure container loot from usec.json/bear.json be added to pmc bots secure */ addSecureContainerLootFromBotConfig: boolean; } +export interface IHostilitySettings { + /** Bot roles that are 100% an enemy */ + additionalEnemyTypes?: string[]; + /** Objects that determine the % chance another bot type is an enemy */ + ChancedEnemies?: IChancedEnemy[]; + BearEnemyChance?: number; + UsecEnemyChance?: number; + /** Bot roles that are 100% an friendly */ + additionalFriendlyTypes?: string[]; +} + export interface PmcTypes { usec: string; bear: string; diff --git a/project/src/services/LocationLifecycleService.ts b/project/src/services/LocationLifecycleService.ts index 5128c497..23a637c8 100644 --- a/project/src/services/LocationLifecycleService.ts +++ b/project/src/services/LocationLifecycleService.ts @@ -21,6 +21,7 @@ import { Traders } from "@spt/models/enums/Traders"; import { IHideoutConfig } from "@spt/models/spt/config/IHideoutConfig"; import { IInRaidConfig } from "@spt/models/spt/config/IInRaidConfig"; import { ILocationConfig } from "@spt/models/spt/config/ILocationConfig"; +import { IPmcConfig } from "@spt/models/spt/config/IPmcConfig"; import { IRagfairConfig } from "@spt/models/spt/config/IRagfairConfig"; import { ITraderConfig } from "@spt/models/spt/config/ITraderConfig"; import { IRaidChanges } from "@spt/models/spt/location/IRaidChanges"; @@ -50,6 +51,7 @@ export class LocationLifecycleService { protected ragfairConfig: IRagfairConfig; protected hideoutConfig: IHideoutConfig; protected locationConfig: ILocationConfig; + protected pmcConfig: IPmcConfig; constructor( @inject("PrimaryLogger") protected logger: ILogger, @@ -83,6 +85,7 @@ export class LocationLifecycleService { this.ragfairConfig = this.configServer.getConfig(ConfigTypes.RAGFAIR); this.hideoutConfig = this.configServer.getConfig(ConfigTypes.HIDEOUT); this.locationConfig = this.configServer.getConfig(ConfigTypes.LOCATION); + this.pmcConfig = this.configServer.getConfig(ConfigTypes.PMC); } /** Handle client/match/local/start */ @@ -96,6 +99,9 @@ export class LocationLifecycleService { locationLoot: this.generateLocationAndLoot(request.location), }; + // Apply changes from pmcConfig to bot hostility values + this.adjustBotHostilitySettings(result.locationLoot); + // Clear bot cache ready for a fresh raid this.botGenerationCacheService.clearStoredBots(); this.botNameService.clearNameCache(); @@ -104,7 +110,73 @@ export class LocationLifecycleService { } /** - * Generate a maps base location and loot + * Adjust the bot hostility values prior to entering a raid + * @param location map to adjust values of + */ + protected adjustBotHostilitySettings(location: ILocationBase): void { + for (const botId in this.pmcConfig.hostilitySettings) { + const configHostilityChanges = this.pmcConfig.hostilitySettings[botId]; + const locationBotHostilityDetails = location.BotLocationModifier.AdditionalHostilitySettings.find( + (botSettings) => botSettings.BotRole.toLowerCase() === botId, + ); + + // No matching bot in config, skip + if (!locationBotHostilityDetails) { + this.logger.warning( + `No bot: ${botId} hostility values found on: ${location.Id}, can only edit existing. Skipping`, + ); + + continue; + } + + // Add new permanent enemies if they don't already exist + if (configHostilityChanges.additionalEnemyTypes) { + for (const enemyTypeToAdd of configHostilityChanges.additionalEnemyTypes) { + if (!locationBotHostilityDetails.AlwaysEnemies.includes(enemyTypeToAdd)) { + locationBotHostilityDetails.AlwaysEnemies.push(enemyTypeToAdd); + } + } + } + + // Add/edit chance settings + if (configHostilityChanges.ChancedEnemies) { + for (const chanceDetailsToApply of configHostilityChanges.ChancedEnemies) { + const locationBotDetails = locationBotHostilityDetails.ChancedEnemies.find( + (botChance) => botChance.Role === chanceDetailsToApply.Role, + ); + if (locationBotDetails) { + // Existing + locationBotDetails.EnemyChance = chanceDetailsToApply.EnemyChance; + } else { + // Add new + locationBotHostilityDetails.ChancedEnemies.push(chanceDetailsToApply); + } + } + } + + // Add new permanent friends if they don't already exist + if (configHostilityChanges.additionalFriendlyTypes) { + for (const friendlyTypeToAdd of configHostilityChanges.additionalFriendlyTypes) { + if (!locationBotHostilityDetails.AlwaysFriends.includes(friendlyTypeToAdd)) { + locationBotHostilityDetails.AlwaysFriends.push(friendlyTypeToAdd); + } + } + } + + // Adjust bear hostility chance + if (typeof configHostilityChanges.BearEnemyChance !== "undefined") { + locationBotHostilityDetails.BearEnemyChance = configHostilityChanges.BearEnemyChance; + } + + // Adjust usec hostility chance + if (typeof configHostilityChanges.UsecEnemyChance !== "undefined") { + locationBotHostilityDetails.UsecEnemyChance = configHostilityChanges.UsecEnemyChance; + } + } + } + + /** + * Generate a maps base location (cloned) and loot * @param name Map name * @returns ILocationBase */