Added config system to adjust raid hostility settings

Removed `enemyTypes` from pmcconfig
This commit is contained in:
Dev 2024-09-18 11:36:45 +01:00
parent f52283f3b3
commit 3952b34e29
3 changed files with 124 additions and 40 deletions

View File

@ -773,43 +773,44 @@
"max": 0 "max": 0
} }
}, },
"enemyTypes": [ "hostilitySettings": {
"assault", "pmcbear": {
"marksman", "additionalEnemyTypes": [
"pmcBot", "bossPartizan"
"bossBully", ],
"bossKilla", "ChancedEnemies": [{
"bossKojaniy", "EnemyChance": 100,
"bossGluhar", "Role": "assault"
"bossSanitar", }, {
"bossTagilla", "EnemyChance": 100,
"bossKnight", "Role": "marksman"
"bossZryachiy", }, {
"bossBoar", "EnemyChance": 85,
"bossBoarSniper", "Role": "pmcUSEC"
"bossKolontay", }
"bossPartisan", ],
"followerBully", "BearEnemyChance": 85,
"followerKojaniy", "UsecEnemyChance": 100
"followerGluharAssault", },
"followerGluharSecurity", "pmcbear": {
"followerGluharScout", "additionalEnemyTypes": [
"followerGluharSnipe", "bossPartizan"
"followerSanitar", ],
"followerBirdEye", "ChancedEnemies": [{
"followerBigPipe", "EnemyChance": 100,
"followerZryachiy", "Role": "assault"
"followerBoar", }, {
"followerBoarClose1", "EnemyChance": 100,
"followerBoarClose2", "Role": "marksman"
"followerKolontayAssault", }, {
"followerKolontaySecurity", "EnemyChance": 85,
"arenaFighter", "Role": "pmcBEAR"
"arenaFighterEvent", }
"crazyAssaultEvent", ],
"sectantWarrior", "BearEnemyChance": 85,
"sectantPriest" "UsecEnemyChance": 100
], }
},
"forceHealingItemsIntoSecure": true, "forceHealingItemsIntoSecure": true,
"addPrefixToSameNamePMCAsPlayerChance": 40, "addPrefixToSameNamePMCAsPlayerChance": 40,
"allPMCsHavePlayerNameWithRandomPrefixChance": 1, "allPMCsHavePlayerNameWithRandomPrefixChance": 1,

View File

@ -1,4 +1,5 @@
import { MinMax } from "@spt/models/common/MinMax"; import { MinMax } from "@spt/models/common/MinMax";
import { IChancedEnemy } from "@spt/models/eft/common/ILocationBase";
import { MemberCategory } from "@spt/models/enums/MemberCategory"; import { MemberCategory } from "@spt/models/enums/MemberCategory";
import { IBaseConfig } from "@spt/models/spt/config/IBaseConfig"; import { IBaseConfig } from "@spt/models/spt/config/IBaseConfig";
@ -37,20 +38,30 @@ export interface IPmcConfig extends IBaseConfig {
maxVestLootTotalRub: number; 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 */ /** 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<string, MinMax>; convertIntoPmcChance: Record<string, MinMax>;
/** WildSpawnType bots PMCs should see as hostile */
enemyTypes: string[];
/** How many levels above player level can a PMC be */ /** How many levels above player level can a PMC be */
botRelativeLevelDeltaMax: number; botRelativeLevelDeltaMax: number;
/** How many levels below player level can a PMC be */ /** How many levels below player level can a PMC be */
botRelativeLevelDeltaMin: number; botRelativeLevelDeltaMin: number;
/** Force a number of healing items into PMCs secure container to ensure they can heal */ /** Force a number of healing items into PMCs secure container to ensure they can heal */
forceHealingItemsIntoSecure: boolean; forceHealingItemsIntoSecure: boolean;
hostilitySettings: Record<string, IHostilitySettings>;
allPMCsHavePlayerNameWithRandomPrefixChance: number; allPMCsHavePlayerNameWithRandomPrefixChance: number;
locationSpecificPmcLevelOverride: Record<string, MinMax>; locationSpecificPmcLevelOverride: Record<string, MinMax>;
/** Should secure container loot from usec.json/bear.json be added to pmc bots secure */ /** Should secure container loot from usec.json/bear.json be added to pmc bots secure */
addSecureContainerLootFromBotConfig: boolean; 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 { export interface PmcTypes {
usec: string; usec: string;
bear: string; bear: string;

View File

@ -21,6 +21,7 @@ import { Traders } from "@spt/models/enums/Traders";
import { IHideoutConfig } from "@spt/models/spt/config/IHideoutConfig"; import { IHideoutConfig } from "@spt/models/spt/config/IHideoutConfig";
import { IInRaidConfig } from "@spt/models/spt/config/IInRaidConfig"; import { IInRaidConfig } from "@spt/models/spt/config/IInRaidConfig";
import { ILocationConfig } from "@spt/models/spt/config/ILocationConfig"; 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 { IRagfairConfig } from "@spt/models/spt/config/IRagfairConfig";
import { ITraderConfig } from "@spt/models/spt/config/ITraderConfig"; import { ITraderConfig } from "@spt/models/spt/config/ITraderConfig";
import { IRaidChanges } from "@spt/models/spt/location/IRaidChanges"; import { IRaidChanges } from "@spt/models/spt/location/IRaidChanges";
@ -50,6 +51,7 @@ export class LocationLifecycleService {
protected ragfairConfig: IRagfairConfig; protected ragfairConfig: IRagfairConfig;
protected hideoutConfig: IHideoutConfig; protected hideoutConfig: IHideoutConfig;
protected locationConfig: ILocationConfig; protected locationConfig: ILocationConfig;
protected pmcConfig: IPmcConfig;
constructor( constructor(
@inject("PrimaryLogger") protected logger: ILogger, @inject("PrimaryLogger") protected logger: ILogger,
@ -83,6 +85,7 @@ export class LocationLifecycleService {
this.ragfairConfig = this.configServer.getConfig(ConfigTypes.RAGFAIR); this.ragfairConfig = this.configServer.getConfig(ConfigTypes.RAGFAIR);
this.hideoutConfig = this.configServer.getConfig(ConfigTypes.HIDEOUT); this.hideoutConfig = this.configServer.getConfig(ConfigTypes.HIDEOUT);
this.locationConfig = this.configServer.getConfig(ConfigTypes.LOCATION); this.locationConfig = this.configServer.getConfig(ConfigTypes.LOCATION);
this.pmcConfig = this.configServer.getConfig(ConfigTypes.PMC);
} }
/** Handle client/match/local/start */ /** Handle client/match/local/start */
@ -96,6 +99,9 @@ export class LocationLifecycleService {
locationLoot: this.generateLocationAndLoot(request.location), 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 // Clear bot cache ready for a fresh raid
this.botGenerationCacheService.clearStoredBots(); this.botGenerationCacheService.clearStoredBots();
this.botNameService.clearNameCache(); 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 * @param name Map name
* @returns ILocationBase * @returns ILocationBase
*/ */