From a358e3b4f1cb75c67b256f52c01c65d50ce102e8 Mon Sep 17 00:00:00 2001 From: Chomp Date: Sun, 16 Feb 2025 18:01:22 +0000 Subject: [PATCH] First pass at custom pmc wave service - basic waves for factory day only --- project/assets/configs/pmc.json | 73 ++++++++++++++++++- project/src/di/Container.ts | 4 + project/src/generators/BotGenerator.ts | 4 +- project/src/generators/PmcWaveGenerator.ts | 66 +++++++++++++++++ .../src/services/LocationLifecycleService.ts | 9 ++- 5 files changed, 151 insertions(+), 5 deletions(-) create mode 100644 project/src/generators/PmcWaveGenerator.ts diff --git a/project/assets/configs/pmc.json b/project/assets/configs/pmc.json index 39c6ee968..d6f34f6b7 100644 --- a/project/assets/configs/pmc.json +++ b/project/assets/configs/pmc.json @@ -865,5 +865,76 @@ } }, "addSecureContainerLootFromBotConfig": false, - "removeExistingPmcWaves": true + "removeExistingPmcWaves": true, + "customPmcWaves": { + "factory4_day": [ + { + "BossChance": 100, + "BossDifficult": "normal", + "BossEscortAmount": "0,0,0,0,2,2,2,1,1,1,1,1,0,2,3", + "BossEscortDifficult": "normal", + "BossEscortType": "pmcUSEC", + "BossName": "pmcUSEC", + "BossPlayer": false, + "BossZone": "", + "IgnoreMaxBots": true, + "RandomTimeSpawn": false, + "SpawnMode": ["pve"], + "Supports": null, + "Time": -1.0, + "TriggerId": "", + "TriggerName": "" + }, + { + "BossChance": 100, + "BossDifficult": "normal", + "BossEscortAmount": "0,0,0,0,2,2,2,1,1,1,1,1,0,2,3", + "BossEscortDifficult": "normal", + "BossEscortType": "pmcBEAR", + "BossName": "pmcBEAR", + "BossPlayer": false, + "BossZone": "", + "IgnoreMaxBots": true, + "RandomTimeSpawn": false, + "SpawnMode": ["pve"], + "Supports": null, + "Time": -1.0, + "TriggerId": "", + "TriggerName": "" + }, + { + "BossChance": 50.0, + "BossDifficult": "normal", + "BossEscortAmount": "0,0,0,0,2,2,2,1,1,1,1,1,0,2,3", + "BossEscortDifficult": "normal", + "BossEscortType": "pmcUSEC", + "BossName": "pmcUSEC", + "BossPlayer": false, + "BossZone": "", + "IgnoreMaxBots": true, + "RandomTimeSpawn": false, + "SpawnMode": ["pve"], + "Supports": null, + "Time": 250, + "TriggerId": "", + "TriggerName": "" + }, { + "BossChance": 50.0, + "BossDifficult": "normal", + "BossEscortAmount": "0,0,0,0,2,2,2,1,1,1,1,1,0,2,3", + "BossEscortDifficult": "normal", + "BossEscortType": "pmcBEAR", + "BossName": "pmcBEAR", + "BossPlayer": false, + "BossZone": "", + "IgnoreMaxBots": true, + "RandomTimeSpawn": false, + "SpawnMode": ["pve"], + "Supports": null, + "Time": 250, + "TriggerId": "", + "TriggerName": "" + } + ] + } } diff --git a/project/src/di/Container.ts b/project/src/di/Container.ts index f8f743624..ea94e74e4 100644 --- a/project/src/di/Container.ts +++ b/project/src/di/Container.ts @@ -73,6 +73,7 @@ import { LocationLootGenerator } from "@spt/generators/LocationLootGenerator"; import { LootGenerator } from "@spt/generators/LootGenerator"; import { PMCLootGenerator } from "@spt/generators/PMCLootGenerator"; import { PlayerScavGenerator } from "@spt/generators/PlayerScavGenerator"; +import { PmcWaveGenerator } from "@spt/generators/PmcWaveGenerator"; import { RagfairAssortGenerator } from "@spt/generators/RagfairAssortGenerator"; import { RagfairOfferGenerator } from "@spt/generators/RagfairOfferGenerator"; import { RepeatableQuestGenerator } from "@spt/generators/RepeatableQuestGenerator"; @@ -575,6 +576,9 @@ export class Container { depContainer.register("RepeatableQuestRewardGenerator", { useClass: RepeatableQuestRewardGenerator, }); + depContainer.register("PmcWaveGenerator", { + useClass: PmcWaveGenerator, + }); depContainer.register("BarrelInventoryMagGen", { useClass: BarrelInventoryMagGen }); depContainer.register("ExternalInventoryMagGen", { diff --git a/project/src/generators/BotGenerator.ts b/project/src/generators/BotGenerator.ts index 381ec5283..cc96fce68 100644 --- a/project/src/generators/BotGenerator.ts +++ b/project/src/generators/BotGenerator.ts @@ -131,8 +131,8 @@ export class BotGenerator { } // The client expects the Side for PMCs to be Savage - if (botRole === "Bear" || botRole === "Usec") - { + if (botRole === "Bear" || botRole === "Usec") { + // TODO: cleanup later preparedBotBase.Info.Side = "Savage"; } diff --git a/project/src/generators/PmcWaveGenerator.ts b/project/src/generators/PmcWaveGenerator.ts new file mode 100644 index 000000000..2e439d44b --- /dev/null +++ b/project/src/generators/PmcWaveGenerator.ts @@ -0,0 +1,66 @@ +import { IBossLocationSpawn, ILocationBase, IWave } from "@spt/models/eft/common/ILocationBase"; +import { ConfigTypes } from "@spt/models/enums/ConfigTypes"; +import { ILocationConfig } from "@spt/models/spt/config/ILocationConfig"; +import { IPmcConfig } from "@spt/models/spt/config/IPmcConfig"; +import type { ILogger } from "@spt/models/spt/utils/ILogger"; +import { ConfigServer } from "@spt/servers/ConfigServer"; +import { DatabaseService } from "@spt/services/DatabaseService"; +import { RandomUtil } from "@spt/utils/RandomUtil"; +import { inject, injectable } from "tsyringe"; + +@injectable() +export class PmcWaveGenerator { + protected pmcConfig: IPmcConfig; + + constructor( + @inject("PrimaryLogger") protected logger: ILogger, + @inject("RandomUtil") protected randomUtil: RandomUtil, + @inject("DatabaseService") protected databaseService: DatabaseService, + @inject("ConfigServer") protected configServer: ConfigServer, + ) { + this.pmcConfig = this.configServer.getConfig(ConfigTypes.PMC); + } + + /** + * Add a pmc wave to a map + * @param locationId e.g. factory4_day, bigmap + * @param waveToAdd Boss wave to add to map + */ + public AddPmcWaveToLocation(locationId: string, waveToAdd: IBossLocationSpawn): void { + this.pmcConfig.customPmcWaves[locationId].push(waveToAdd); + } + + /** + * Add custom boss and normal waves to maps found in config/location.json to db + */ + public applyWaveChangesToAllMaps(): void { + for (const location of Object.keys(this.pmcConfig.customPmcWaves)) { + const data = this.pmcConfig.customPmcWaves[location]; + + this.applyWaveChangesToMapByName(location); + } + } + + public applyWaveChangesToMapByName(name: string): void { + const pmcWavesToAdd = this.pmcConfig.customPmcWaves[name]; + if (!pmcWavesToAdd) { + return; + } + + const location = this.databaseService.getLocation(name); + if (!location) { + return; + } + + location.base.BossLocationSpawn.push(...pmcWavesToAdd); + } + + public applyWaveChangesToMap(location: ILocationBase): void { + const pmcWavesToAdd = this.pmcConfig.customPmcWaves[location.Id.toLowerCase()]; + if (!pmcWavesToAdd) { + return; + } + + location.BossLocationSpawn.push(...pmcWavesToAdd); + } +} diff --git a/project/src/services/LocationLifecycleService.ts b/project/src/services/LocationLifecycleService.ts index 3965e3ea3..579acbdb3 100644 --- a/project/src/services/LocationLifecycleService.ts +++ b/project/src/services/LocationLifecycleService.ts @@ -3,10 +3,12 @@ import { ContextVariableType } from "@spt/context/ContextVariableType"; import { LocationLootGenerator } from "@spt/generators/LocationLootGenerator"; import { LootGenerator } from "@spt/generators/LootGenerator"; import { PlayerScavGenerator } from "@spt/generators/PlayerScavGenerator"; +import { PmcWaveGenerator } from "@spt/generators/PmcWaveGenerator"; import { HealthHelper } from "@spt/helpers/HealthHelper"; import { InRaidHelper } from "@spt/helpers/InRaidHelper"; import { ProfileHelper } from "@spt/helpers/ProfileHelper"; import { QuestHelper } from "@spt/helpers/QuestHelper"; +import { RewardHelper } from "@spt/helpers/RewardHelper"; import { TraderHelper } from "@spt/helpers/TraderHelper"; import { ILocationBase } from "@spt/models/eft/common/ILocationBase"; import { IPmcData } from "@spt/models/eft/common/IPmcData"; @@ -26,6 +28,7 @@ import { ExitStatus } from "@spt/models/enums/ExitStatis"; import { MessageType } from "@spt/models/enums/MessageType"; import { QuestStatus } from "@spt/models/enums/QuestStatus"; import { Traders } from "@spt/models/enums/Traders"; +import { TransitionType } from "@spt/models/enums/TransitionType"; import { IHideoutConfig } from "@spt/models/spt/config/IHideoutConfig"; import { IInRaidConfig } from "@spt/models/spt/config/IInRaidConfig"; import { ILocationConfig } from "@spt/models/spt/config/ILocationConfig"; @@ -51,8 +54,6 @@ import { RandomUtil } from "@spt/utils/RandomUtil"; import { TimeUtil } from "@spt/utils/TimeUtil"; import type { ICloner } from "@spt/utils/cloners/ICloner"; import { inject, injectable } from "tsyringe"; -import { TransitionType } from "@spt/models/enums/TransitionType"; -import { RewardHelper } from "@spt/helpers/RewardHelper"; @injectable() export class LocationLifecycleService { @@ -90,6 +91,7 @@ export class LocationLifecycleService { @inject("LootGenerator") protected lootGenerator: LootGenerator, @inject("ApplicationContext") protected applicationContext: ApplicationContext, @inject("LocationLootGenerator") protected locationLootGenerator: LocationLootGenerator, + @inject("PmcWaveGenerator") protected pmcWaveGenerator: PmcWaveGenerator, @inject("PrimaryCloner") protected cloner: ICloner, ) { this.inRaidConfig = this.configServer.getConfig(ConfigTypes.IN_RAID); @@ -287,6 +289,9 @@ export class LocationLifecycleService { return locationBaseClone; } + // Add cusom pmcs to map every time its run + this.pmcWaveGenerator.applyWaveChangesToMap(locationBaseClone); + // Check for a loot multipler adjustment in app context and apply if one is found let locationConfigClone: ILocationConfig; const raidAdjustments = this.applicationContext