Handle changes to airdrop endpoint
Reworked airdrop loot generation to incorporate 'radar' drops Added `forced loot` system to LootGenerator service, can now explicitly define what items it contains Fixed airdrop system sending incorrect icon to client
This commit is contained in:
parent
3bbe167450
commit
80762d6a00
@ -3,10 +3,12 @@
|
|||||||
"mixed": 5,
|
"mixed": 5,
|
||||||
"weaponArmor": 2,
|
"weaponArmor": 2,
|
||||||
"foodMedical": 1,
|
"foodMedical": 1,
|
||||||
"barter": 1
|
"barter": 1,
|
||||||
|
"radar": 0
|
||||||
},
|
},
|
||||||
"loot": {
|
"loot": {
|
||||||
"mixed": {
|
"mixed": {
|
||||||
|
"icon": "Common",
|
||||||
"weaponPresetCount": {
|
"weaponPresetCount": {
|
||||||
"min": 3,
|
"min": 3,
|
||||||
"max": 5
|
"max": 5
|
||||||
@ -108,6 +110,7 @@
|
|||||||
"allowBossItems": false
|
"allowBossItems": false
|
||||||
},
|
},
|
||||||
"weaponArmor": {
|
"weaponArmor": {
|
||||||
|
"icon": "Weapon",
|
||||||
"weaponPresetCount": {
|
"weaponPresetCount": {
|
||||||
"min": 6,
|
"min": 6,
|
||||||
"max": 8
|
"max": 8
|
||||||
@ -180,6 +183,7 @@
|
|||||||
"allowBossItems": false
|
"allowBossItems": false
|
||||||
},
|
},
|
||||||
"foodMedical": {
|
"foodMedical": {
|
||||||
|
"icon": "Medical",
|
||||||
"weaponPresetCount": {
|
"weaponPresetCount": {
|
||||||
"min": 0,
|
"min": 0,
|
||||||
"max": 0
|
"max": 0
|
||||||
@ -260,6 +264,7 @@
|
|||||||
"allowBossItems": false
|
"allowBossItems": false
|
||||||
},
|
},
|
||||||
"barter": {
|
"barter": {
|
||||||
|
"icon": "Supply",
|
||||||
"weaponPresetCount": {
|
"weaponPresetCount": {
|
||||||
"min": 0,
|
"min": 0,
|
||||||
"max": 0
|
"max": 0
|
||||||
@ -339,6 +344,39 @@
|
|||||||
},
|
},
|
||||||
"armorLevelWhitelist": [0],
|
"armorLevelWhitelist": [0],
|
||||||
"allowBossItems": false
|
"allowBossItems": false
|
||||||
}
|
},
|
||||||
}
|
"radar": {
|
||||||
|
"icon": "Supply",
|
||||||
|
"weaponPresetCount": {
|
||||||
|
"min": 0,
|
||||||
|
"max": 0
|
||||||
|
},
|
||||||
|
"armorPresetCount": {
|
||||||
|
"min": 0,
|
||||||
|
"max": 0
|
||||||
|
},
|
||||||
|
"itemCount": {
|
||||||
|
"min": 0,
|
||||||
|
"max": 0
|
||||||
|
},
|
||||||
|
"weaponCrateCount": {
|
||||||
|
"min": 0,
|
||||||
|
"max": 0
|
||||||
|
},
|
||||||
|
"itemBlacklist": [],
|
||||||
|
"itemTypeWhitelist": [],
|
||||||
|
"itemLimits": {},
|
||||||
|
"itemStackLimits": {},
|
||||||
|
"armorLevelWhitelist": [],
|
||||||
|
"allowBossItems": false,
|
||||||
|
"useForcedLoot": true,
|
||||||
|
"forcedLoot": {
|
||||||
|
"66d9f7256916142b3b02276e": {"min": 2, "max": 4 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"customAirdropMapping": {
|
||||||
|
"66da1b49099cf6adcc07a36b": "radar",
|
||||||
|
"66da1b546916142b3b022777": "radar"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ import { LocationController } from "@spt/controllers/LocationController";
|
|||||||
import { IEmptyRequestData } from "@spt/models/eft/common/IEmptyRequestData";
|
import { IEmptyRequestData } from "@spt/models/eft/common/IEmptyRequestData";
|
||||||
import { ILocationsGenerateAllResponse } from "@spt/models/eft/common/ILocationsSourceDestinationBase";
|
import { ILocationsGenerateAllResponse } from "@spt/models/eft/common/ILocationsSourceDestinationBase";
|
||||||
import { IGetBodyResponseData } from "@spt/models/eft/httpResponse/IGetBodyResponseData";
|
import { IGetBodyResponseData } from "@spt/models/eft/httpResponse/IGetBodyResponseData";
|
||||||
|
import { IGetAirdropLootRequest } from "@spt/models/eft/location/IGetAirdropLootRequest";
|
||||||
import { IGetAirdropLootResponse } from "@spt/models/eft/location/IGetAirdropLootResponse";
|
import { IGetAirdropLootResponse } from "@spt/models/eft/location/IGetAirdropLootResponse";
|
||||||
import { HttpResponseUtil } from "@spt/utils/HttpResponseUtil";
|
import { HttpResponseUtil } from "@spt/utils/HttpResponseUtil";
|
||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
@ -25,9 +26,9 @@ export class LocationCallbacks {
|
|||||||
/** Handle client/airdrop/loot */
|
/** Handle client/airdrop/loot */
|
||||||
public getAirdropLoot(
|
public getAirdropLoot(
|
||||||
url: string,
|
url: string,
|
||||||
info: IEmptyRequestData,
|
info: IGetAirdropLootRequest,
|
||||||
sessionID: string,
|
sessionID: string,
|
||||||
): IGetBodyResponseData<IGetAirdropLootResponse> {
|
): IGetBodyResponseData<IGetAirdropLootResponse> {
|
||||||
return this.httpResponse.getBody(this.locationController.getAirdropLoot());
|
return this.httpResponse.getBody(this.locationController.getAirdropLoot(info));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { ILocationsGenerateAllResponse } from "@spt/models/eft/common/ILocationsSourceDestinationBase";
|
import { ILocationsGenerateAllResponse } from "@spt/models/eft/common/ILocationsSourceDestinationBase";
|
||||||
|
import { IGetAirdropLootRequest } from "@spt/models/eft/location/IGetAirdropLootRequest";
|
||||||
import { IGetAirdropLootResponse } from "@spt/models/eft/location/IGetAirdropLootResponse";
|
import { IGetAirdropLootResponse } from "@spt/models/eft/location/IGetAirdropLootResponse";
|
||||||
import { ConfigTypes } from "@spt/models/enums/ConfigTypes";
|
import { ConfigTypes } from "@spt/models/enums/ConfigTypes";
|
||||||
import { ILocationConfig } from "@spt/models/spt/config/ILocationConfig";
|
import { ILocationConfig } from "@spt/models/spt/config/ILocationConfig";
|
||||||
@ -50,7 +51,11 @@ export class LocationController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Handle client/airdrop/loot */
|
/** Handle client/airdrop/loot */
|
||||||
public getAirdropLoot(): IGetAirdropLootResponse {
|
public getAirdropLoot(request: IGetAirdropLootRequest): IGetAirdropLootResponse {
|
||||||
|
if (request.containerId) {
|
||||||
|
return this.airdropService.generateCustomAirdropLoot(request);
|
||||||
|
}
|
||||||
|
|
||||||
return this.airdropService.generateAirdropLoot();
|
return this.airdropService.generateAirdropLoot();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -153,6 +153,32 @@ export class LootGenerator {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public createForcedLoot(airdropConfig: LootRequest) {
|
||||||
|
const result: IItem[] = [];
|
||||||
|
|
||||||
|
const forcedItems = Object.keys(airdropConfig.forcedLoot);
|
||||||
|
|
||||||
|
for (const tpl of forcedItems) {
|
||||||
|
const details = airdropConfig.forcedLoot[tpl];
|
||||||
|
const randomisedItemCount = this.randomUtil.getInt(details.min, details.max);
|
||||||
|
|
||||||
|
// Add forced loot item to result
|
||||||
|
const newLootItem: IItem = {
|
||||||
|
_id: this.hashUtil.generate(),
|
||||||
|
_tpl: tpl,
|
||||||
|
upd: {
|
||||||
|
StackObjectsCount: randomisedItemCount,
|
||||||
|
SpawnedInSession: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const splitResults = this.itemHelper.splitStack(newLootItem);
|
||||||
|
result.push(...splitResults);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
protected getItemRewardPool(
|
protected getItemRewardPool(
|
||||||
itemTplBlacklist: string[],
|
itemTplBlacklist: string[],
|
||||||
itemTypeWhitelist: string[],
|
itemTypeWhitelist: string[],
|
||||||
|
@ -3,4 +3,5 @@ export enum AirdropTypeEnum {
|
|||||||
SUPPLY = "barter",
|
SUPPLY = "barter",
|
||||||
FOOD_MEDICAL = "foodMedical",
|
FOOD_MEDICAL = "foodMedical",
|
||||||
WEAPON_ARMOR = "weaponArmor",
|
WEAPON_ARMOR = "weaponArmor",
|
||||||
|
RADAR = "radar",
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ export interface IAirdropConfig extends IBaseConfig {
|
|||||||
airdropTypeWeightings: Record<AirdropTypeEnum, number>;
|
airdropTypeWeightings: Record<AirdropTypeEnum, number>;
|
||||||
/** What rewards will the loot crate contain, keyed by drop type e.g. mixed/weaponArmor/foodMedical/barter */
|
/** What rewards will the loot crate contain, keyed by drop type e.g. mixed/weaponArmor/foodMedical/barter */
|
||||||
loot: Record<string, IAirdropLoot>;
|
loot: Record<string, IAirdropLoot>;
|
||||||
|
customAirdropMapping: Record<string, AirdropTypeEnum>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Chance map will have an airdrop occur out of 100 - locations not included count as 0% */
|
/** Chance map will have an airdrop occur out of 100 - locations not included count as 0% */
|
||||||
@ -23,6 +24,7 @@ export interface IAirdropChancePercent {
|
|||||||
|
|
||||||
/** Loot inside crate */
|
/** Loot inside crate */
|
||||||
export interface IAirdropLoot {
|
export interface IAirdropLoot {
|
||||||
|
icon: AirdropTypeEnum;
|
||||||
/** Min/max of weapons inside crate */
|
/** Min/max of weapons inside crate */
|
||||||
weaponPresetCount?: MinMax;
|
weaponPresetCount?: MinMax;
|
||||||
/** Min/max of armors (head/chest/rig) inside crate */
|
/** Min/max of armors (head/chest/rig) inside crate */
|
||||||
@ -43,4 +45,6 @@ export interface IAirdropLoot {
|
|||||||
armorLevelWhitelist?: number[];
|
armorLevelWhitelist?: number[];
|
||||||
/** Should boss items be added to airdrop crate */
|
/** Should boss items be added to airdrop crate */
|
||||||
allowBossItems: boolean;
|
allowBossItems: boolean;
|
||||||
|
useForcedLoot?: boolean;
|
||||||
|
forcedLoot?: Record<string, MinMax>;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { MinMax } from "@spt/models/common/MinMax";
|
import { MinMax } from "@spt/models/common/MinMax";
|
||||||
|
import { AirdropTypeEnum } from "@spt/models/enums/AirdropType";
|
||||||
|
|
||||||
export interface LootRequest {
|
export interface LootRequest {
|
||||||
weaponPresetCount: MinMax;
|
weaponPresetCount: MinMax;
|
||||||
@ -13,4 +14,10 @@ export interface LootRequest {
|
|||||||
armorLevelWhitelist: number[];
|
armorLevelWhitelist: number[];
|
||||||
allowBossItems: boolean;
|
allowBossItems: boolean;
|
||||||
useRewarditemBlacklist?: boolean;
|
useRewarditemBlacklist?: boolean;
|
||||||
|
useForcedLoot?: boolean;
|
||||||
|
forcedLoot?: Record<string, MinMax>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IAirdropLootRequest extends LootRequest {
|
||||||
|
icon?: AirdropTypeEnum;
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,13 @@ import { LootGenerator } from "@spt/generators/LootGenerator";
|
|||||||
import { ItemHelper } from "@spt/helpers/ItemHelper";
|
import { ItemHelper } from "@spt/helpers/ItemHelper";
|
||||||
import { WeightedRandomHelper } from "@spt/helpers/WeightedRandomHelper";
|
import { WeightedRandomHelper } from "@spt/helpers/WeightedRandomHelper";
|
||||||
import { IItem } from "@spt/models/eft/common/tables/IItem";
|
import { IItem } from "@spt/models/eft/common/tables/IItem";
|
||||||
|
import { IGetAirdropLootRequest } from "@spt/models/eft/location/IGetAirdropLootRequest";
|
||||||
import { IGetAirdropLootResponse } from "@spt/models/eft/location/IGetAirdropLootResponse";
|
import { IGetAirdropLootResponse } from "@spt/models/eft/location/IGetAirdropLootResponse";
|
||||||
import { AirdropTypeEnum } from "@spt/models/enums/AirdropType";
|
import { AirdropTypeEnum } from "@spt/models/enums/AirdropType";
|
||||||
import { ConfigTypes } from "@spt/models/enums/ConfigTypes";
|
import { ConfigTypes } from "@spt/models/enums/ConfigTypes";
|
||||||
import { ItemTpl } from "@spt/models/enums/ItemTpl";
|
import { ItemTpl } from "@spt/models/enums/ItemTpl";
|
||||||
import { IAirdropConfig, IAirdropLoot } from "@spt/models/spt/config/IAirdropConfig";
|
import { IAirdropConfig, IAirdropLoot } from "@spt/models/spt/config/IAirdropConfig";
|
||||||
import { LootRequest } from "@spt/models/spt/services/LootRequest";
|
import { IAirdropLootRequest, LootRequest } from "@spt/models/spt/services/LootRequest";
|
||||||
import { ILogger } from "@spt/models/spt/utils/ILogger";
|
import { ILogger } from "@spt/models/spt/utils/ILogger";
|
||||||
import { ConfigServer } from "@spt/servers/ConfigServer";
|
import { ConfigServer } from "@spt/servers/ConfigServer";
|
||||||
import { DatabaseService } from "@spt/services/DatabaseService";
|
import { DatabaseService } from "@spt/services/DatabaseService";
|
||||||
@ -36,21 +37,36 @@ export class AirdropService {
|
|||||||
this.airdropConfig = this.configServer.getConfig(ConfigTypes.AIRDROP);
|
this.airdropConfig = this.configServer.getConfig(ConfigTypes.AIRDROP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public generateCustomAirdropLoot(request: IGetAirdropLootRequest): IGetAirdropLootResponse {
|
||||||
|
const customAirdropInformation = this.airdropConfig.customAirdropMapping[request.containerId];
|
||||||
|
if (!customAirdropInformation) {
|
||||||
|
this.logger.warning(
|
||||||
|
`Unable to find data for custom airdrop ${request.containerId}, returning random airdrop instead`,
|
||||||
|
);
|
||||||
|
|
||||||
|
return this.generateAirdropLoot();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.generateAirdropLoot(customAirdropInformation);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle client/location/getAirdropLoot
|
* Handle client/location/getAirdropLoot
|
||||||
* Get loot for an airdrop container
|
* Get loot for an airdrop container
|
||||||
* Generates it randomly based on config/airdrop.json values
|
* Generates it randomly based on config/airdrop.json values
|
||||||
* @returns Array of LootItem objects
|
* @returns Array of LootItem objects
|
||||||
*/
|
*/
|
||||||
public generateAirdropLoot(): IGetAirdropLootResponse {
|
public generateAirdropLoot(forcedAirdropType = null): IGetAirdropLootResponse {
|
||||||
const airdropType = this.chooseAirdropType();
|
const airdropType = forcedAirdropType ? forcedAirdropType : this.chooseAirdropType();
|
||||||
this.logger.debug(`Chose ${airdropType} for airdrop loot`);
|
this.logger.debug(`Chose ${airdropType} for airdrop loot`);
|
||||||
|
|
||||||
// Common/weapon/etc
|
// Common/weapon/etc
|
||||||
const airdropConfig = this.getAirdropLootConfigByType(airdropType);
|
const airdropConfig = this.getAirdropLootConfigByType(airdropType);
|
||||||
|
|
||||||
// generate loot to put into airdrop crate
|
// generate loot to put into airdrop crate
|
||||||
const crateLoot = this.lootGenerator.createRandomLoot(airdropConfig);
|
const crateLoot = airdropConfig.useForcedLoot
|
||||||
|
? this.lootGenerator.createForcedLoot(airdropConfig)
|
||||||
|
: this.lootGenerator.createRandomLoot(airdropConfig);
|
||||||
|
|
||||||
// Create airdrop crate and add to result in first spot
|
// Create airdrop crate and add to result in first spot
|
||||||
const airdropCrateItem = this.getAirdropCrateItem(airdropType);
|
const airdropCrateItem = this.getAirdropCrateItem(airdropType);
|
||||||
@ -58,7 +74,7 @@ export class AirdropService {
|
|||||||
// Add crate to front of array
|
// Add crate to front of array
|
||||||
crateLoot.unshift(airdropCrateItem);
|
crateLoot.unshift(airdropCrateItem);
|
||||||
|
|
||||||
// Reparent loot items to create we added above
|
// Reparent loot items to crate we added above
|
||||||
for (const item of crateLoot) {
|
for (const item of crateLoot) {
|
||||||
if (item._id === airdropCrateItem._id) {
|
if (item._id === airdropCrateItem._id) {
|
||||||
// Crate itself, don't alter
|
// Crate itself, don't alter
|
||||||
@ -72,7 +88,7 @@ export class AirdropService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return { icon: airdropType, container: crateLoot };
|
return { icon: airdropConfig.icon, container: crateLoot };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -103,6 +119,9 @@ export class AirdropService {
|
|||||||
case AirdropTypeEnum.COMMON:
|
case AirdropTypeEnum.COMMON:
|
||||||
airdropContainer._tpl = ItemTpl.LOOTCONTAINER_AIRDROP_COMMON_SUPPLY_CRATE;
|
airdropContainer._tpl = ItemTpl.LOOTCONTAINER_AIRDROP_COMMON_SUPPLY_CRATE;
|
||||||
break;
|
break;
|
||||||
|
case AirdropTypeEnum.RADAR:
|
||||||
|
airdropContainer._tpl = ItemTpl.LOOTCONTAINER_AIRDROP_TECHNICAL_SUPPLY_CRATE_EVENT_1;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
airdropContainer._tpl = ItemTpl.LOOTCONTAINER_AIRDROP_COMMON_SUPPLY_CRATE;
|
airdropContainer._tpl = ItemTpl.LOOTCONTAINER_AIRDROP_COMMON_SUPPLY_CRATE;
|
||||||
break;
|
break;
|
||||||
@ -126,7 +145,7 @@ export class AirdropService {
|
|||||||
* @param airdropType Type of airdrop to get settings for
|
* @param airdropType Type of airdrop to get settings for
|
||||||
* @returns LootRequest
|
* @returns LootRequest
|
||||||
*/
|
*/
|
||||||
protected getAirdropLootConfigByType(airdropType: AirdropTypeEnum): LootRequest {
|
protected getAirdropLootConfigByType(airdropType: AirdropTypeEnum): IAirdropLootRequest {
|
||||||
let lootSettingsByType: IAirdropLoot = this.airdropConfig.loot[airdropType];
|
let lootSettingsByType: IAirdropLoot = this.airdropConfig.loot[airdropType];
|
||||||
if (!lootSettingsByType) {
|
if (!lootSettingsByType) {
|
||||||
this.logger.error(
|
this.logger.error(
|
||||||
@ -136,6 +155,7 @@ export class AirdropService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
icon: lootSettingsByType.icon,
|
||||||
weaponPresetCount: lootSettingsByType.weaponPresetCount,
|
weaponPresetCount: lootSettingsByType.weaponPresetCount,
|
||||||
armorPresetCount: lootSettingsByType.armorPresetCount,
|
armorPresetCount: lootSettingsByType.armorPresetCount,
|
||||||
itemCount: lootSettingsByType.itemCount,
|
itemCount: lootSettingsByType.itemCount,
|
||||||
@ -150,6 +170,8 @@ export class AirdropService {
|
|||||||
itemStackLimits: lootSettingsByType.itemStackLimits,
|
itemStackLimits: lootSettingsByType.itemStackLimits,
|
||||||
armorLevelWhitelist: lootSettingsByType.armorLevelWhitelist,
|
armorLevelWhitelist: lootSettingsByType.armorLevelWhitelist,
|
||||||
allowBossItems: lootSettingsByType.allowBossItems,
|
allowBossItems: lootSettingsByType.allowBossItems,
|
||||||
|
useForcedLoot: lootSettingsByType.useForcedLoot,
|
||||||
|
forcedLoot: lootSettingsByType.forcedLoot,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user