Cleanup of generateContainerLoot()
to improve readability
This commit is contained in:
parent
63ac0d6fe2
commit
d6fed1aa0f
@ -77,22 +77,22 @@ export class LocationController
|
|||||||
|
|
||||||
output.Loot = [];
|
output.Loot = [];
|
||||||
|
|
||||||
// mounted weapons
|
// Mounted weapons
|
||||||
for (const mi of staticWeapons)
|
for (const mi of staticWeapons)
|
||||||
{
|
{
|
||||||
output.Loot.push(mi);
|
output.Loot.push(mi);
|
||||||
}
|
}
|
||||||
|
|
||||||
let count = 0;
|
let staticContainerCount = 0;
|
||||||
// static loot
|
// static loot
|
||||||
for (const ci of staticContainers)
|
for (const staticContainer of staticContainers)
|
||||||
{
|
{
|
||||||
const container = this.locationGenerator.generateContainerLoot(ci, staticForced, staticLootDist, staticAmmoDist, name);
|
const container = this.locationGenerator.generateContainerLoot(staticContainer, staticForced, staticLootDist, staticAmmoDist, name);
|
||||||
output.Loot.push(container);
|
output.Loot.push(container);
|
||||||
count++;
|
staticContainerCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger.success(this.localisationService.getText("location-containers_generated_success", count));
|
this.logger.success(this.localisationService.getText("location-containers_generated_success", staticContainerCount));
|
||||||
|
|
||||||
// dyanmic loot
|
// dyanmic loot
|
||||||
const dynamicLootDist: ILooseLoot = this.jsonUtil.clone(location.looseLoot);
|
const dynamicLootDist: ILooseLoot = this.jsonUtil.clone(location.looseLoot);
|
||||||
|
@ -5,7 +5,7 @@ import { ItemHelper } from "../helpers/ItemHelper";
|
|||||||
import { PresetHelper } from "../helpers/PresetHelper";
|
import { PresetHelper } from "../helpers/PresetHelper";
|
||||||
import { RagfairServerHelper } from "../helpers/RagfairServerHelper";
|
import { RagfairServerHelper } from "../helpers/RagfairServerHelper";
|
||||||
import {
|
import {
|
||||||
ILooseLoot, Spawnpoint, SpawnpointsForced, SpawnpointTemplate
|
ILooseLoot, Spawnpoint, SpawnpointTemplate, SpawnpointsForced
|
||||||
} from "../models/eft/common/ILooseLoot";
|
} from "../models/eft/common/ILooseLoot";
|
||||||
import { Item } from "../models/eft/common/tables/IItem";
|
import { Item } from "../models/eft/common/tables/IItem";
|
||||||
import {
|
import {
|
||||||
@ -55,43 +55,142 @@ export class LocationGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Choose loot to put into a static container
|
* Choose loot to put into a static container based on weighting
|
||||||
* @param containerIn
|
* Handle forced items + seasonal item removal when not in season
|
||||||
* @param staticForced
|
* @param staticContainer The container itself we will add loot to
|
||||||
* @param staticLootDist
|
* @param staticForced Loot we need to force into the container
|
||||||
* @param staticAmmoDist
|
* @param staticLootDist staticLoot.json
|
||||||
|
* @param staticAmmoDist staticAmmo.json
|
||||||
* @param locationName Name of the map to generate static loot for
|
* @param locationName Name of the map to generate static loot for
|
||||||
* @returns IStaticContainerProps
|
* @returns IStaticContainerProps
|
||||||
*/
|
*/
|
||||||
public generateContainerLoot(
|
public generateContainerLoot(
|
||||||
containerIn: IStaticContainerProps,
|
staticContainer: IStaticContainerProps,
|
||||||
staticForced: IStaticForcedProps[],
|
staticForced: IStaticForcedProps[],
|
||||||
staticLootDist: Record<string, IStaticLootDetails>,
|
staticLootDist: Record<string, IStaticLootDetails>,
|
||||||
staticAmmoDist: Record<string, IStaticAmmoDetails[]>,
|
staticAmmoDist: Record<string, IStaticAmmoDetails[]>,
|
||||||
locationName: string): IStaticContainerProps
|
locationName: string): IStaticContainerProps
|
||||||
{
|
{
|
||||||
const container = this.jsonUtil.clone(containerIn);
|
const container = this.jsonUtil.clone(staticContainer);
|
||||||
const containerTypeId = container.Items[0]._tpl;
|
const containerTpl = container.Items[0]._tpl;
|
||||||
|
|
||||||
|
// Create new unique parent id to prevent any collisions
|
||||||
const parentId = this.objectId.generate();
|
const parentId = this.objectId.generate();
|
||||||
container.Root = parentId;
|
container.Root = parentId;
|
||||||
container.Items[0]._id = parentId;
|
container.Items[0]._id = parentId;
|
||||||
|
|
||||||
const containerTemplate = this.itemHelper.getItem(containerTypeId)[1];
|
let containerMap = this.getContainerMapping(containerTpl);
|
||||||
|
|
||||||
|
// Choose count of items to add to container
|
||||||
|
const itemCountToAdd = this.getWeightedCountOfContainerItems(containerTpl, staticLootDist, locationName);
|
||||||
|
|
||||||
|
// Get all possible loot items for container
|
||||||
|
const containerLootPool = this.getPossibleLootItemsForContainer(containerTpl, staticLootDist);
|
||||||
|
|
||||||
|
// Some containers need to have items forced into it (quest keys etc)
|
||||||
|
const tplsForced = staticForced.filter(x => x.containerId === container.Id).map(x => x.itemTpl);
|
||||||
|
|
||||||
|
// Draw random loot
|
||||||
|
// Money spawn more than once in container
|
||||||
|
let failedToFitCount = 0;
|
||||||
|
const locklist = [Money.ROUBLES, Money.DOLLARS, Money.EUROS];
|
||||||
|
|
||||||
|
// Choose items to add to container, factor in weighting + lock money down
|
||||||
|
const chosenTpls = containerLootPool.draw(itemCountToAdd, false, locklist);
|
||||||
|
|
||||||
|
// Add forced loot to chosen item pool
|
||||||
|
const tplsToAddToContainer = tplsForced.concat(chosenTpls);
|
||||||
|
for (const tplToAdd of tplsToAddToContainer)
|
||||||
|
{
|
||||||
|
const chosenItemWithChildren = this.createStaticLootItem(tplToAdd, staticAmmoDist, parentId);
|
||||||
|
const items = chosenItemWithChildren.items;
|
||||||
|
const width = chosenItemWithChildren.width;
|
||||||
|
const height = chosenItemWithChildren.height;
|
||||||
|
|
||||||
|
// look for open slot to put chosen item into
|
||||||
|
const result = this.containerHelper.findSlotForItem(containerMap, width, height);
|
||||||
|
if (!result.success)
|
||||||
|
{
|
||||||
|
// 2 attempts to fit an item, container is probably full, stop trying to add more
|
||||||
|
if (failedToFitCount >= this.locationConfig.fitLootIntoContainerAttempts)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Can't fit item, skip
|
||||||
|
failedToFitCount++;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
containerMap = this.containerHelper.fillContainerMapWithItem(containerMap, result.x, result.y, width, height, result.rotation);
|
||||||
|
const rotation = result.rotation ? 1 : 0;
|
||||||
|
|
||||||
|
items[0].slotId = "main";
|
||||||
|
items[0].location = { "x": result.x, "y": result.y, "r": rotation };
|
||||||
|
|
||||||
|
// Add loot to container before returning
|
||||||
|
for (const item of items)
|
||||||
|
{
|
||||||
|
container.Items.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a 2d grid of a containers item slots
|
||||||
|
* @param containerTpl Tpl id of the container
|
||||||
|
* @returns number[][]
|
||||||
|
*/
|
||||||
|
protected getContainerMapping(containerTpl: string): number[][]
|
||||||
|
{
|
||||||
|
// Get template from db
|
||||||
|
const containerTemplate = this.itemHelper.getItem(containerTpl)[1];
|
||||||
|
|
||||||
|
// Get height/width
|
||||||
const height = containerTemplate._props.Grids[0]._props.cellsV;
|
const height = containerTemplate._props.Grids[0]._props.cellsV;
|
||||||
const width = containerTemplate._props.Grids[0]._props.cellsH;
|
const width = containerTemplate._props.Grids[0]._props.cellsH;
|
||||||
let container2D: number[][] = Array(height).fill(0).map(() => Array(width).fill(0));
|
|
||||||
|
|
||||||
|
// Calcualte 2d array and return
|
||||||
|
return Array(height).fill(0).map(() => Array(width).fill(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Look up a containers itemcountDistribution data and choose an item count based on the found weights
|
||||||
|
* @param containerTypeId Container to get item count for
|
||||||
|
* @param staticLootDist staticLoot.json
|
||||||
|
* @param locationName Map name (to get per-map multiplier for from config)
|
||||||
|
* @returns item count
|
||||||
|
*/
|
||||||
|
protected getWeightedCountOfContainerItems(containerTypeId: string, staticLootDist: Record<string, IStaticLootDetails>, locationName: string): number
|
||||||
|
{
|
||||||
|
// Create probability array to calcualte the total count of lootable items inside container
|
||||||
const itemCountArray = new ProbabilityObjectArray<number>(this.mathUtil);
|
const itemCountArray = new ProbabilityObjectArray<number>(this.mathUtil);
|
||||||
for (const icd of staticLootDist[containerTypeId].itemcountDistribution)
|
for (const itemCountDistribution of staticLootDist[containerTypeId].itemcountDistribution)
|
||||||
{
|
{
|
||||||
|
// Add each count of items into array
|
||||||
itemCountArray.push(
|
itemCountArray.push(
|
||||||
new ProbabilityObject(icd.count, icd.relativeProbability)
|
new ProbabilityObject(itemCountDistribution.count, itemCountDistribution.relativeProbability)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const numberItems = Math.round(this.getStaticLootMultiplerForLocation(locationName) * itemCountArray.draw()[0]);
|
|
||||||
|
|
||||||
|
return Math.round(this.getStaticLootMultiplerForLocation(locationName) * itemCountArray.draw()[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all possible loot items that can be placed into a container
|
||||||
|
* Do not add seasonal items if found + current date is inside seasonal event
|
||||||
|
* @param containerTypeId Contianer to get possible loot for
|
||||||
|
* @param staticLootDist staticLoot.json
|
||||||
|
* @returns ProbabilityObjectArray of item tpls + probabilty
|
||||||
|
*/
|
||||||
|
protected getPossibleLootItemsForContainer(containerTypeId: string, staticLootDist: Record<string, IStaticLootDetails>): ProbabilityObjectArray<string, number>
|
||||||
|
{
|
||||||
const seasonalEventActive = this.seasonalEventService.seasonalEventEnabled();
|
const seasonalEventActive = this.seasonalEventService.seasonalEventEnabled();
|
||||||
const seasonalItemTplBlacklist = this.seasonalEventService.getSeasonalEventItemsToBlock();
|
const seasonalItemTplBlacklist = this.seasonalEventService.getSeasonalEventItemsToBlock();
|
||||||
|
|
||||||
const itemDistribution = new ProbabilityObjectArray<string>(this.mathUtil);
|
const itemDistribution = new ProbabilityObjectArray<string>(this.mathUtil);
|
||||||
for (const icd of staticLootDist[containerTypeId].itemDistribution)
|
for (const icd of staticLootDist[containerTypeId].itemDistribution)
|
||||||
{
|
{
|
||||||
@ -106,52 +205,7 @@ export class LocationGenerator
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get forced container loot tpls
|
return itemDistribution;
|
||||||
const tplsForced = staticForced.filter(x => x.containerId === container.Id).map(x => x.itemTpl);
|
|
||||||
|
|
||||||
// Draw random loot
|
|
||||||
// money spawn more than once in container
|
|
||||||
let failedToFitCount = 0;
|
|
||||||
const locklist = [Money.ROUBLES, Money.DOLLARS, Money.EUROS];
|
|
||||||
const tplsDraw = itemDistribution.draw(numberItems, false, locklist);
|
|
||||||
const tpls = tplsForced.concat(tplsDraw);
|
|
||||||
for (const tpl of tpls)
|
|
||||||
{
|
|
||||||
const chosenItemWithChildren = this.createStaticLootItem(tpl, staticAmmoDist, parentId);
|
|
||||||
const items = chosenItemWithChildren.items;
|
|
||||||
const width = chosenItemWithChildren.width;
|
|
||||||
const height = chosenItemWithChildren.height;
|
|
||||||
|
|
||||||
// look for open slot to put chosen item into
|
|
||||||
const result = this.containerHelper.findSlotForItem(container2D, width, height);
|
|
||||||
if (!result.success)
|
|
||||||
{
|
|
||||||
// 2 attempts to fit an item, container is probably full, stop trying to add more
|
|
||||||
if (failedToFitCount >= this.locationConfig.fitLootIntoContainerAttempts)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Can't fit item, skip
|
|
||||||
failedToFitCount++;
|
|
||||||
continue;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
container2D = this.containerHelper.fillContainerMapWithItem(container2D, result.x, result.y, width, height, result.rotation);
|
|
||||||
const rot = result.rotation ? 1 : 0;
|
|
||||||
|
|
||||||
items[0].slotId = "main";
|
|
||||||
items[0].location = { "x": result.x, "y": result.y, "r": rot };
|
|
||||||
|
|
||||||
|
|
||||||
for (const item of items)
|
|
||||||
{
|
|
||||||
container.Items.push(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return container;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected getLooseLootMultiplerForLocation(location: string): number
|
protected getLooseLootMultiplerForLocation(location: string): number
|
||||||
|
@ -98,7 +98,7 @@ export class ContainerHelper
|
|||||||
return new FindSlotResult();
|
return new FindSlotResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
public fillContainerMapWithItem(container2D: number[][], x: number, y: number, itemW: number, itemH: number, rotate: boolean): any
|
public fillContainerMapWithItem(container2D: number[][], x: number, y: number, itemW: number, itemH: number, rotate: boolean): number[][]
|
||||||
{
|
{
|
||||||
const itemWidth = rotate ? itemH : itemW;
|
const itemWidth = rotate ? itemH : itemW;
|
||||||
const itemHeight = rotate ? itemW : itemH;
|
const itemHeight = rotate ? itemW : itemH;
|
||||||
|
Loading…
Reference in New Issue
Block a user