LocationLootGen done
This commit is contained in:
@@ -422,7 +422,8 @@ public class LocationLootGenerator(
|
||||
|
||||
// Add forced loot to chosen item pool
|
||||
var tplsToAddToContainer = tplsForced.Concat(chosenTpls);
|
||||
foreach (var tplToAdd in tplsToAddToContainer) {
|
||||
foreach (var tplToAdd in tplsToAddToContainer)
|
||||
{
|
||||
var chosenItemWithChildren = CreateStaticLootItem(tplToAdd, staticAmmoDist, parentId);
|
||||
if (chosenItemWithChildren is null)
|
||||
{
|
||||
@@ -457,7 +458,8 @@ public class LocationLootGenerator(
|
||||
result.Y.Value,
|
||||
(int)width,
|
||||
(int)height,
|
||||
result.Rotation.GetValueOrDefault(false));
|
||||
result.Rotation.GetValueOrDefault(false)
|
||||
);
|
||||
|
||||
var rotation = result.Rotation.GetValueOrDefault(false) ? 1 : 0;
|
||||
|
||||
@@ -465,7 +467,8 @@ public class LocationLootGenerator(
|
||||
items[0].Location = new { X = result.X, Y = result.Y, R = rotation };
|
||||
|
||||
// Add loot to container before returning
|
||||
foreach (var item in items) {
|
||||
foreach (var item in items)
|
||||
{
|
||||
containerClone.Template.Items.Add(item);
|
||||
}
|
||||
}
|
||||
@@ -596,7 +599,189 @@ public class LocationLootGenerator(
|
||||
Dictionary<string, List<StaticAmmoDetails>> staticAmmoDist,
|
||||
string locationName)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
List<SpawnpointTemplate> loot = [];
|
||||
List<Spawnpoint> dynamicForcedSpawnPoints = [];
|
||||
|
||||
// Remove christmas items from loot data
|
||||
if (!_seasonalEventService.ChristmasEventEnabled())
|
||||
{
|
||||
dynamicLootDist.Spawnpoints = dynamicLootDist.Spawnpoints.Where(
|
||||
(point) => !point.Template.Id.StartsWith("christmas")
|
||||
)
|
||||
.ToList();
|
||||
dynamicLootDist.SpawnpointsForced = dynamicLootDist.SpawnpointsForced.Where(
|
||||
(point) => !point.Template.Id.StartsWith("christmas")
|
||||
)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
// Build the list of forced loot from both `spawnpointsForced` and any point marked `IsAlwaysSpawn`
|
||||
dynamicForcedSpawnPoints.AddRange(dynamicLootDist.SpawnpointsForced);
|
||||
dynamicForcedSpawnPoints.AddRange(dynamicLootDist.Spawnpoints.Where((point) => point.Template.IsAlwaysSpawn ?? false));
|
||||
|
||||
// Add forced loot
|
||||
AddForcedLoot(loot, dynamicForcedSpawnPoints, locationName, staticAmmoDist);
|
||||
|
||||
var allDynamicSpawnpoints = dynamicLootDist.Spawnpoints;
|
||||
|
||||
// Draw from random distribution
|
||||
var desiredSpawnpointCount = Math.Round(
|
||||
GetLooseLootMultiplerForLocation(locationName) *
|
||||
_randomUtil.GetNormallyDistributedRandomNumber(
|
||||
(double)dynamicLootDist.SpawnpointCount.Mean,
|
||||
(double)dynamicLootDist.SpawnpointCount.Std
|
||||
)
|
||||
);
|
||||
|
||||
// Positions not in forced but have 100% chance to spawn
|
||||
List<Spawnpoint> guaranteedLoosePoints = [];
|
||||
|
||||
var blacklistedSpawnpoints = _locationConfig.LooseLootBlacklist[locationName];
|
||||
var spawnpointArray = new ProbabilityObjectArray<ProbabilityObject<string, Spawnpoint>, string, Spawnpoint>(_mathUtil, _cloner, []);
|
||||
|
||||
foreach (var spawnpoint in allDynamicSpawnpoints)
|
||||
{
|
||||
// Point is blacklsited, skip
|
||||
if (blacklistedSpawnpoints?.Contains(spawnpoint.Template.Id) ?? false)
|
||||
{
|
||||
_logger.Debug($"Ignoring loose loot location: {spawnpoint.Template.Id}");
|
||||
continue;
|
||||
}
|
||||
|
||||
// We've handled IsAlwaysSpawn above, so skip them
|
||||
if (spawnpoint.Template.IsAlwaysSpawn ?? false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// 100%, add it to guaranteed
|
||||
if (spawnpoint.Probability == 1)
|
||||
{
|
||||
guaranteedLoosePoints.Add(spawnpoint);
|
||||
continue;
|
||||
}
|
||||
|
||||
spawnpointArray.Add(new ProbabilityObject<string, Spawnpoint>(spawnpoint.Template.Id, spawnpoint.Probability ?? 0, spawnpoint));
|
||||
}
|
||||
|
||||
// Select a number of spawn points to add loot to
|
||||
// Add ALL loose loot with 100% chance to pool
|
||||
List<Spawnpoint> chosenSpawnpoints = [];
|
||||
chosenSpawnpoints.AddRange(guaranteedLoosePoints);
|
||||
|
||||
var randomSpawnpointCount = desiredSpawnpointCount - chosenSpawnpoints.Count;
|
||||
// Only draw random spawn points if needed
|
||||
if (randomSpawnpointCount > 0 && spawnpointArray.Count > 0)
|
||||
{
|
||||
// Add randomly chosen spawn points
|
||||
foreach (var si in spawnpointArray.Draw((int)randomSpawnpointCount, false))
|
||||
{
|
||||
chosenSpawnpoints.Add(spawnpointArray.Data(si));
|
||||
}
|
||||
}
|
||||
|
||||
// Filter out duplicate locationIds // prob can be done better
|
||||
chosenSpawnpoints = chosenSpawnpoints.GroupBy(spawnpoint => spawnpoint.LocationId).Select(group => group.First()).ToList();
|
||||
|
||||
// Do we have enough items in pool to fulfill requirement
|
||||
var tooManySpawnPointsRequested = desiredSpawnpointCount - chosenSpawnpoints.Count > 0;
|
||||
if (tooManySpawnPointsRequested)
|
||||
{
|
||||
_logger.Debug(
|
||||
_localisationService.GetText(
|
||||
"location-spawn_point_count_requested_vs_found",
|
||||
new
|
||||
{
|
||||
requested = desiredSpawnpointCount + guaranteedLoosePoints.Count,
|
||||
found = chosenSpawnpoints.Count,
|
||||
mapName = locationName,
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Iterate over spawnpoints
|
||||
var seasonalEventActive = _seasonalEventService.SeasonalEventEnabled();
|
||||
var seasonalItemTplBlacklist = _seasonalEventService.GetInactiveSeasonalEventItems();
|
||||
foreach (var spawnPoint in chosenSpawnpoints)
|
||||
{
|
||||
// Spawnpoint is invalid, skip it
|
||||
if (spawnPoint.Template is null)
|
||||
{
|
||||
_logger.Warning(
|
||||
_localisationService.GetText("location-missing_dynamic_template", spawnPoint.LocationId)
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Ensure no blacklisted lootable items are in pool
|
||||
spawnPoint.Template.Items = spawnPoint.Template.Items.Where(
|
||||
(item) => !_itemFilterService.IsLootableItemBlacklisted(item.Template)
|
||||
)
|
||||
.ToList();
|
||||
|
||||
// Ensure no seasonal items are in pool if not in-season
|
||||
if (!seasonalEventActive)
|
||||
{
|
||||
spawnPoint.Template.Items = spawnPoint.Template.Items.Where(
|
||||
(item) => !seasonalItemTplBlacklist.Contains(item.Template)
|
||||
)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
// Spawn point has no items after filtering, skip
|
||||
if (spawnPoint.Template.Items is null || spawnPoint.Template.Items.Count == 0)
|
||||
{
|
||||
_logger.Warning(
|
||||
_localisationService.GetText("location-spawnpoint_missing_items", spawnPoint.Template.Id)
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get an array of allowed IDs after above filtering has occured
|
||||
var validItemIds = spawnPoint.Template.Items.Select((item) => item.Id).ToList();
|
||||
|
||||
// Construct container to hold above filtered items, letting us pick an item for the spot
|
||||
var itemArray = new ProbabilityObjectArray<ProbabilityObject<string, double?>, string, double?>(_mathUtil, _cloner, []);
|
||||
foreach (var itemDist in spawnPoint.ItemDistribution)
|
||||
{
|
||||
if (!validItemIds.Contains(itemDist.ComposedKey.Key))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
itemArray.Add(new ProbabilityObject<string, double?>(itemDist.ComposedKey.Key, itemDist.RelativeProbability ?? 0, null));
|
||||
}
|
||||
|
||||
if (itemArray.Count == 0)
|
||||
{
|
||||
_logger.Warning(
|
||||
_localisationService.GetText("location-loot_pool_is_empty_skipping", spawnPoint.Template.Id)
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Draw a random item from spawn points possible items
|
||||
var chosenComposedKey = itemArray.Draw(1).FirstOrDefault();
|
||||
var createItemResult = CreateDynamicLootItem(
|
||||
chosenComposedKey,
|
||||
spawnPoint.Template.Items,
|
||||
staticAmmoDist
|
||||
);
|
||||
|
||||
// Root id can change when generating a weapon, ensure ids match
|
||||
spawnPoint.Template.Root = createItemResult.Items.FirstOrDefault().Id;
|
||||
|
||||
// Overwrite entire pool with chosen item
|
||||
spawnPoint.Template.Items = createItemResult.Items;
|
||||
|
||||
loot.Add(spawnPoint.Template);
|
||||
}
|
||||
|
||||
return loot;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -606,12 +791,186 @@ public class LocationLootGenerator(
|
||||
/// <param name="forcedSpawnPoints">Forced loot locations that must be added</param>
|
||||
/// <param name="locationName">Name of map currently having force loot created for</param>
|
||||
protected void AddForcedLoot(List<SpawnpointTemplate> lootLocationTemplates,
|
||||
List<SpawnpointsForced> forcedSpawnPoints, string locationName,
|
||||
List<Spawnpoint> forcedSpawnPoints, string locationName,
|
||||
Dictionary<string, List<StaticAmmoDetails>> staticAmmoDist)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var lootToForceSingleAmountOnMap = _locationConfig.ForcedLootSingleSpawnById[locationName];
|
||||
if (lootToForceSingleAmountOnMap is not null)
|
||||
{
|
||||
// Process loot items defined as requiring only 1 spawn position as they appear in multiple positions on the map
|
||||
foreach (var itemTpl in lootToForceSingleAmountOnMap)
|
||||
{
|
||||
// Get all spawn positions for item tpl in forced loot array
|
||||
var items = forcedSpawnPoints.Where(
|
||||
(forcedSpawnPoint) => forcedSpawnPoint.Template.Items[0].Template == itemTpl
|
||||
);
|
||||
if (items is null || !items.Any())
|
||||
{
|
||||
_logger.Debug($"Unable to adjust loot item {itemTpl} as it does not exist inside {locationName} forced loot.");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create probability array of all spawn positions for this spawn id
|
||||
var spawnpointArray = new ProbabilityObjectArray<ProbabilityObject<string, Spawnpoint>, string, Spawnpoint>(_mathUtil, _cloner, []);
|
||||
foreach (var si in items)
|
||||
{
|
||||
// use locationId as template.Id is the same across all items
|
||||
spawnpointArray.Add(new ProbabilityObject<string, Spawnpoint>(si.LocationId, si.Probability ?? 0, si));
|
||||
}
|
||||
|
||||
// Choose 1 out of all found spawn positions for spawn id and add to loot array
|
||||
foreach (var spawnPointLocationId in spawnpointArray.Draw(1, false))
|
||||
{
|
||||
var itemToAdd = items.FirstOrDefault((item) => item.LocationId == spawnPointLocationId);
|
||||
var lootItem = itemToAdd?.Template;
|
||||
if (lootItem is null)
|
||||
{
|
||||
_logger.Warning($"Item with spawn point id {spawnPointLocationId} could not be found, skipping");
|
||||
continue;
|
||||
}
|
||||
|
||||
var createItemResult = CreateDynamicLootItem(
|
||||
lootItem.Items.FirstOrDefault().Id,
|
||||
lootItem.Items,
|
||||
staticAmmoDist
|
||||
);
|
||||
|
||||
// Update root ID with the dynamically generated ID
|
||||
lootItem.Root = createItemResult.Items.FirstOrDefault().Id;
|
||||
lootItem.Items = createItemResult.Items;
|
||||
lootLocationTemplates.Add(lootItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var seasonalEventActive = _seasonalEventService.SeasonalEventEnabled();
|
||||
var seasonalItemTplBlacklist = _seasonalEventService.GetInactiveSeasonalEventItems();
|
||||
|
||||
// Add remaining forced loot to array
|
||||
foreach (var forcedLootLocation in forcedSpawnPoints)
|
||||
{
|
||||
var firstLootItemTpl = forcedLootLocation.Template.Items.FirstOrDefault().Template;
|
||||
|
||||
// Skip spawn positions processed already
|
||||
if (lootToForceSingleAmountOnMap?.Contains(firstLootItemTpl) ?? false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip adding seasonal items when seasonal event is not active
|
||||
if (!seasonalEventActive && seasonalItemTplBlacklist.Contains(firstLootItemTpl))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var locationTemplateToAdd = forcedLootLocation.Template;
|
||||
var createItemResult = CreateDynamicLootItem(
|
||||
locationTemplateToAdd.Items.FirstOrDefault().Id,
|
||||
forcedLootLocation.Template.Items,
|
||||
staticAmmoDist
|
||||
);
|
||||
|
||||
// Update root ID with the dynamically generated ID
|
||||
forcedLootLocation.Template.Root = createItemResult.Items.FirstOrDefault().Id;
|
||||
forcedLootLocation.Template.Items = createItemResult.Items;
|
||||
|
||||
// Push forced location into array as long as it doesnt exist already
|
||||
var existingLocation = lootLocationTemplates.Any(
|
||||
(spawnPoint) => spawnPoint.Id == locationTemplateToAdd.Id
|
||||
);
|
||||
if (!existingLocation)
|
||||
{
|
||||
lootLocationTemplates.Add(locationTemplateToAdd);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Debug(
|
||||
$"Attempted to add a forced loot location with Id: {locationTemplateToAdd.Id} to map {locationName} that already has that id in use, skipping"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ContainerItem CreateDynamicLootItem(string? chosenComposedKey, List<Item> items, Dictionary<string, List<StaticAmmoDetails>> staticAmmoDist)
|
||||
{
|
||||
var chosenItem = items.FirstOrDefault((item) => item.Id == chosenComposedKey);
|
||||
var chosenTpl = chosenItem?.Template;
|
||||
if (chosenTpl is null) {
|
||||
throw new Exception($"Item for tpl {chosenComposedKey} was not found in the spawn point");
|
||||
}
|
||||
var itemTemplate = _itemHelper.GetItem(chosenTpl).Value;
|
||||
if (itemTemplate is null) {
|
||||
_logger.Error($"Item tpl: {chosenTpl} cannot be found in database");
|
||||
}
|
||||
|
||||
// Item array to return
|
||||
List<Item> itemWithMods = [];
|
||||
|
||||
// Money/Ammo - don't rely on items in spawnPoint.template.Items so we can randomise it ourselves
|
||||
if (_itemHelper.IsOfBaseclasses(chosenTpl, [BaseClasses.MONEY, BaseClasses.AMMO])) {
|
||||
var stackCount =
|
||||
itemTemplate.Properties.StackMaxSize == 1
|
||||
? 1
|
||||
: _randomUtil.GetInt((int)itemTemplate.Properties.StackMinRandom, (int)itemTemplate.Properties.StackMaxRandom);
|
||||
|
||||
itemWithMods.Add(new Item {
|
||||
Id = _hashUtil.Generate(),
|
||||
Template = chosenTpl,
|
||||
Upd = new Upd { StackObjectsCount = stackCount }
|
||||
});
|
||||
} else if (_itemHelper.IsOfBaseclass(chosenTpl, BaseClasses.AMMO_BOX)) {
|
||||
// Fill with cartridges
|
||||
List<Item> ammoBoxItem = [ new Item { Id = _hashUtil.Generate(), Template = chosenTpl }];
|
||||
_itemHelper.AddCartridgesToAmmoBox(ammoBoxItem, itemTemplate);
|
||||
itemWithMods.AddRange(ammoBoxItem);
|
||||
} else if (_itemHelper.IsOfBaseclass(chosenTpl, BaseClasses.MAGAZINE)) {
|
||||
// Create array with just magazine
|
||||
List<Item> magazineItem = [new Item { Id = _hashUtil.Generate(), Template = chosenTpl }];
|
||||
|
||||
if (_randomUtil.GetChance100(_locationConfig.StaticMagazineLootHasAmmoChancePercent)) {
|
||||
// Add randomised amount of cartridges
|
||||
_itemHelper.FillMagazineWithRandomCartridge(
|
||||
magazineItem,
|
||||
itemTemplate, // Magazine template
|
||||
staticAmmoDist,
|
||||
null,
|
||||
_locationConfig.MinFillLooseMagazinePercent / 100
|
||||
);
|
||||
}
|
||||
|
||||
itemWithMods.AddRange(magazineItem);
|
||||
} else {
|
||||
// Also used by armors to get child mods
|
||||
// Get item + children and add into array we return
|
||||
var itemWithChildren = _itemHelper.FindAndReturnChildrenAsItems(items, chosenItem.Id);
|
||||
|
||||
// Ensure all IDs are unique
|
||||
itemWithChildren = _itemHelper.ReplaceIDs(itemWithChildren);
|
||||
|
||||
if (_locationConfig.TplsToStripChildItemsFrom.Contains(chosenItem.Template)) {
|
||||
// Strip children from parent before adding
|
||||
itemWithChildren = [itemWithChildren[0]];
|
||||
}
|
||||
|
||||
itemWithMods.AddRange(itemWithChildren);
|
||||
}
|
||||
|
||||
// Get inventory size of item
|
||||
var size = _itemHelper.GetItemSize(itemWithMods, itemWithMods[0].Id);
|
||||
|
||||
return new ContainerItem { Items = itemWithMods, Width = size.Width, Height = size.Height };
|
||||
}
|
||||
|
||||
private double GetLooseLootMultiplerForLocation(string location)
|
||||
{
|
||||
return _locationConfig.LooseLootMultiplier[location];
|
||||
}
|
||||
|
||||
protected double getStaticLootMultiplerForLocation(string location) {
|
||||
return _locationConfig.StaticLootMultiplier[location];
|
||||
}
|
||||
|
||||
|
||||
// TODO: rewrite, BIG yikes
|
||||
protected ContainerItem? CreateStaticLootItem(
|
||||
string chosenTpl,
|
||||
@@ -619,81 +978,109 @@ public class LocationLootGenerator(
|
||||
string? parentId = null)
|
||||
{
|
||||
var itemTemplate = _itemHelper.GetItem(chosenTpl).Value;
|
||||
if (itemTemplate.Properties is null) {
|
||||
if (itemTemplate.Properties is null)
|
||||
{
|
||||
_logger.Error($"Unable to process item: ${{chosenTpl}}. it lacks _props");
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
var width = itemTemplate.Properties.Width;
|
||||
var height = itemTemplate.Properties.Height;
|
||||
List<Item> items = [ new Item { Id = _hashUtil.Generate(), Template = chosenTpl }];
|
||||
List<Item> items = [new Item { Id = _hashUtil.Generate(), Template = chosenTpl }];
|
||||
var rootItem = items.FirstOrDefault();
|
||||
|
||||
// Use passed in parentId as override for new item
|
||||
if (!string.IsNullOrEmpty(parentId)) {
|
||||
if (!string.IsNullOrEmpty(parentId))
|
||||
{
|
||||
rootItem.ParentId = parentId;
|
||||
}
|
||||
|
||||
if (
|
||||
_itemHelper.IsOfBaseclass(chosenTpl, BaseClasses.MONEY) ||
|
||||
_itemHelper.IsOfBaseclass(chosenTpl, BaseClasses.AMMO)
|
||||
) {
|
||||
)
|
||||
{
|
||||
// Edge case - some ammos e.g. flares or M406 grenades shouldn't be stacked
|
||||
var stackCount = itemTemplate.Properties.StackMaxSize == 1
|
||||
? 1
|
||||
: _randomUtil.GetInt((int)(itemTemplate.Properties.StackMinRandom), (int)(itemTemplate.Properties.StackMaxRandom));
|
||||
? 1
|
||||
: _randomUtil.GetInt((int)(itemTemplate.Properties.StackMinRandom), (int)(itemTemplate.Properties.StackMaxRandom));
|
||||
|
||||
rootItem.Upd = new Upd { StackObjectsCount = stackCount };
|
||||
}
|
||||
// No spawn point, use default template
|
||||
else if (_itemHelper.IsOfBaseclass(chosenTpl, BaseClasses.WEAPON)) {
|
||||
else if (_itemHelper.IsOfBaseclass(chosenTpl, BaseClasses.WEAPON))
|
||||
{
|
||||
List<Item> children = [];
|
||||
var defaultPreset = _cloner.Clone(_presetHelper.GetDefaultPreset(chosenTpl));
|
||||
if (defaultPreset?.Items is not null) {
|
||||
try {
|
||||
if (defaultPreset?.Items is not null)
|
||||
{
|
||||
try
|
||||
{
|
||||
children = _itemHelper.ReparentItemAndChildren(defaultPreset.Items[0], defaultPreset.Items);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// this item already broke it once without being reproducible tpl = "5839a40f24597726f856b511"; AKS-74UB Default
|
||||
// 5ea03f7400685063ec28bfa8 // ppsh default
|
||||
// 5ba26383d4351e00334c93d9 //mp7_devgru
|
||||
_logger.Error(
|
||||
_localisationService.GetText("location-preset_not_found", new {
|
||||
tpl = chosenTpl,
|
||||
defaultId = defaultPreset.Id,
|
||||
defaultName = defaultPreset.Name,
|
||||
parentId,
|
||||
})
|
||||
_localisationService.GetText(
|
||||
"location-preset_not_found",
|
||||
new
|
||||
{
|
||||
tpl = chosenTpl,
|
||||
defaultId = defaultPreset.Id,
|
||||
defaultName = defaultPreset.Name,
|
||||
parentId,
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
throw;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// RSP30 (62178be9d0050232da3485d9/624c0b3340357b5f566e8766/6217726288ed9f0845317459) doesnt have any default presets and kills this code below as it has no chidren to reparent
|
||||
_logger.Debug($"createStaticLootItem() No preset found for weapon: {chosenTpl}");
|
||||
}
|
||||
|
||||
rootItem = items[0];
|
||||
if (rootItem is null) {
|
||||
if (rootItem is null)
|
||||
{
|
||||
_logger.Error(
|
||||
_localisationService.GetText("location-missing_root_item", new {
|
||||
tpl = chosenTpl,
|
||||
parentId,
|
||||
})
|
||||
_localisationService.GetText(
|
||||
"location-missing_root_item",
|
||||
new
|
||||
{
|
||||
tpl = chosenTpl,
|
||||
parentId,
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
throw new Exception(_localisationService.GetText("location-critical_error_see_log"));
|
||||
}
|
||||
|
||||
try {
|
||||
if (children?.Count > 0) {
|
||||
try
|
||||
{
|
||||
if (children?.Count > 0)
|
||||
{
|
||||
items = _itemHelper.ReparentItemAndChildren(rootItem, children);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Error(
|
||||
_localisationService.GetText("location-unable_to_reparent_item", new {
|
||||
tpl = chosenTpl,
|
||||
parentId = parentId,
|
||||
})
|
||||
_localisationService.GetText(
|
||||
"location-unable_to_reparent_item",
|
||||
new
|
||||
{
|
||||
tpl = chosenTpl,
|
||||
parentId = parentId,
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
throw;
|
||||
@@ -705,7 +1092,8 @@ public class LocationLootGenerator(
|
||||
// BotGenerator
|
||||
var magazine = items.FirstOrDefault(item => item.SlotId == "mod_magazine");
|
||||
// some weapon presets come without magazine; only fill the mag if it exists
|
||||
if (magazine is not null) {
|
||||
if (magazine is not null)
|
||||
{
|
||||
var magTemplate = _itemHelper.GetItem(magazine.Template).Value;
|
||||
var weaponTemplate = _itemHelper.GetItem(chosenTpl).Value;
|
||||
|
||||
@@ -732,10 +1120,14 @@ public class LocationLootGenerator(
|
||||
height = size.Height;
|
||||
}
|
||||
// No spawnpoint to fall back on, generate manually
|
||||
else if (_itemHelper.IsOfBaseclass(chosenTpl, BaseClasses.AMMO_BOX)) {
|
||||
else if (_itemHelper.IsOfBaseclass(chosenTpl, BaseClasses.AMMO_BOX))
|
||||
{
|
||||
_itemHelper.AddCartridgesToAmmoBox(items, itemTemplate);
|
||||
} else if (_itemHelper.IsOfBaseclass(chosenTpl, BaseClasses.MAGAZINE)) {
|
||||
if (_randomUtil.GetChance100(_locationConfig.MagazineLootHasAmmoChancePercent)) {
|
||||
}
|
||||
else if (_itemHelper.IsOfBaseclass(chosenTpl, BaseClasses.MAGAZINE))
|
||||
{
|
||||
if (_randomUtil.GetChance100(_locationConfig.MagazineLootHasAmmoChancePercent))
|
||||
{
|
||||
// Create array with just magazine
|
||||
List<Item> magazineWithCartridges = [rootItem];
|
||||
_itemHelper.FillMagazineWithRandomCartridge(
|
||||
@@ -750,18 +1142,24 @@ public class LocationLootGenerator(
|
||||
items.Remove(rootItem);
|
||||
items.AddRange(magazineWithCartridges);
|
||||
}
|
||||
} else if (_itemHelper.ArmorItemCanHoldMods(chosenTpl)) {
|
||||
}
|
||||
else if (_itemHelper.ArmorItemCanHoldMods(chosenTpl))
|
||||
{
|
||||
var defaultPreset = _presetHelper.GetDefaultPreset(chosenTpl);
|
||||
if (defaultPreset is not null) {
|
||||
if (defaultPreset is not null)
|
||||
{
|
||||
List<Item> presetAndMods = _itemHelper.ReplaceIDs(defaultPreset.Items);
|
||||
_itemHelper.RemapRootItemId(presetAndMods);
|
||||
|
||||
// Use original items parentId otherwise item doesnt get added to container correctly
|
||||
presetAndMods[0].ParentId = rootItem.ParentId;
|
||||
items = presetAndMods;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// We make base item above, at start of function, no need to do it here
|
||||
if ((itemTemplate.Properties.Slots?.Count ?? 0) > 0) {
|
||||
if ((itemTemplate.Properties.Slots?.Count ?? 0) > 0)
|
||||
{
|
||||
items = _itemHelper.AddChildSlotItems(
|
||||
items,
|
||||
itemTemplate,
|
||||
|
||||
@@ -9,7 +9,7 @@ public record LooseLoot
|
||||
public SpawnpointCount? SpawnpointCount { get; set; }
|
||||
|
||||
[JsonPropertyName("spawnpointsForced")]
|
||||
public List<SpawnpointsForced>? SpawnpointsForced { get; set; }
|
||||
public List<Spawnpoint>? SpawnpointsForced { get; set; }
|
||||
|
||||
[JsonPropertyName("spawnpoints")]
|
||||
public List<Spawnpoint>? Spawnpoints { get; set; }
|
||||
@@ -24,18 +24,6 @@ public record SpawnpointCount
|
||||
public double? Std { get; set; }
|
||||
}
|
||||
|
||||
public record SpawnpointsForced
|
||||
{
|
||||
[JsonPropertyName("locationId")]
|
||||
public string? LocationId { get; set; }
|
||||
|
||||
[JsonPropertyName("probability")]
|
||||
public double? Probability { get; set; }
|
||||
|
||||
[JsonPropertyName("template")]
|
||||
public SpawnpointTemplate? Template { get; set; }
|
||||
}
|
||||
|
||||
public record SpawnpointTemplate
|
||||
{
|
||||
[JsonPropertyName("Id")]
|
||||
|
||||
@@ -83,7 +83,7 @@ public class App
|
||||
|
||||
_logger.Success(GetRandomisedStartMessage());
|
||||
_logger.Success(".oooO Oooo.");
|
||||
_logger.Success("( ( ) ( ) )");
|
||||
_logger.Success("( ( ) ( ) )"); // TODO: Remove later
|
||||
_logger.Success(" \\ ( ) /");
|
||||
_logger.Success(" \\_) (_/");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user