using System;
using System.Collections.Generic;
using System.Linq;
using ACE.Common;
using ACE.Database;
using ACE.Database.Models.World;
using ACE.Entity;
using ACE.Entity.Enum;
using ACE.Entity.Enum.Properties;
using ACE.Entity.Models;
using ACE.Server.Entity;
using ACE.Server.Entity.Actions;
using ACE.Server.Factories;
using ACE.Server.Managers;
using ACE.Server.Network.GameMessages.Messages;
namespace ACE.Server.WorldObjects
{
partial class Creature
{
public bool EquippedObjectsLoaded { get; private set; }
///
/// Use EquipObject() and DequipObject() to manipulate this dictionary..
/// Do not manipulate this dictionary directly.
///
public Dictionary EquippedObjects { get; } = new Dictionary();
///
/// The only time this should be used is to populate EquippedObjects from the ctor.
///
protected void AddBiotasToEquippedObjects(IEnumerable wieldedItems)
{
foreach (var biota in wieldedItems)
{
var worldObject = WorldObjectFactory.CreateWorldObject(biota);
EquippedObjects[worldObject.Guid] = worldObject;
AddItemToEquippedItemsRatingCache(worldObject);
EncumbranceVal += (worldObject.EncumbranceVal ?? 0);
}
EquippedObjectsLoaded = true;
SetChildren();
}
public bool WieldedLocationIsAvailable(WorldObject item, EquipMask wieldedLocation)
{
// filtering to just armor here, or else trinkets and dual wielding breaks
// update: cannot repro the break anymore?
//var existing = this is Player ? GetEquippedClothingArmor(item.ClothingPriority ?? 0) : GetEquippedItems(item, wieldedLocation);
var existing = GetEquippedItems(item, wieldedLocation);
// TODO: handle overlap from MeleeWeapon / MissileWeapon / Held
return existing.Count == 0;
}
public bool HasEquippedItem(ObjectGuid objectGuid)
{
return EquippedObjects.ContainsKey(objectGuid);
}
///
/// Get Wielded Item. Returns null if not found.
///
public WorldObject GetEquippedItem(uint objectGuid)
{
return EquippedObjects.TryGetValue(new ObjectGuid(objectGuid), out var item) ? item : null; // todo fix this so it doesn't instantiate a new ObjectGuid
}
///
/// Get Wielded Item. Returns null if not found.
///
public WorldObject GetEquippedItem(ObjectGuid objectGuid)
{
return EquippedObjects.TryGetValue(objectGuid, out var item) ? item : null;
}
///
/// Returns a list of equipped clothing/armor with any coverage overlap
///
public List GetEquippedClothingArmor(CoverageMask coverageMask)
{
return EquippedObjects.Values.Where(i => i.ClothingPriority != null && (i.ClothingPriority & coverageMask) != 0).ToList();
}
///
/// Returns a list of equipped items with any overlap with input locations
///
public List GetEquippedItems(WorldObject item, EquipMask wieldedLocation)
{
if (IsWeaponSlot(wieldedLocation))
{
// TODO: change to coalesced CurrentWieldedLocation
GetPlacementLocation(item, wieldedLocation, out var placement, out var parentLocation);
return EquippedObjects.Values.Where(i => i.ParentLocation != null && i.ParentLocation == parentLocation && i.CurrentWieldedLocation != EquipMask.MissileAmmo).ToList();
}
if (item is Clothing)
return GetEquippedClothingArmor(item.ClothingPriority ?? 0);
else
return EquippedObjects.Values.Where(i => i.CurrentWieldedLocation != null && (i.CurrentWieldedLocation & wieldedLocation) != 0).ToList();
}
///
/// Returns the currently equipped primary weapon
///
public WorldObject GetEquippedWeapon(bool forceMainHand = false)
{
var meleeWeapon = GetEquippedMeleeWeapon(forceMainHand);
return meleeWeapon ?? GetEquippedMissileWeapon();
}
///
/// Returns the current equipped active melee weapon
/// This will normally be the primary melee weapon, but if dual wielding, this will be the weapon for the next attack
///
public WorldObject GetEquippedMeleeWeapon(bool forceMainHand = false)
{
if (!IsDualWieldAttack || DualWieldAlternate || forceMainHand)
return EquippedObjects.Values.FirstOrDefault(e => e.ParentLocation == ACE.Entity.Enum.ParentLocation.RightHand && (e.CurrentWieldedLocation == EquipMask.MeleeWeapon || e.CurrentWieldedLocation == EquipMask.TwoHanded));
return GetDualWieldWeapon();
}
///
/// Returns the currently equipped secondary weapon
///
public WorldObject GetDualWieldWeapon()
{
return EquippedObjects.Values.FirstOrDefault(e => !e.IsShield && e.CurrentWieldedLocation == EquipMask.Shield);
}
///
/// Returns the currently equipped wand
///
public WorldObject GetEquippedWand()
{
return EquippedObjects.Values.FirstOrDefault(e => e.CurrentWieldedLocation == EquipMask.Held);
}
///
/// Returns the currently equipped missile weapon
/// This can be either a missile launcher (bow, crossbow, atlatl) or stackable thrown weapons directly in the main hand slot
///
public WorldObject GetEquippedMissileWeapon()
{
return EquippedObjects.Values.FirstOrDefault(e => e.CurrentWieldedLocation == EquipMask.MissileWeapon);
}
///
/// Returns the currently equipped missile launcher
///
public WorldObject GetEquippedMissileLauncher()
{
return EquippedObjects.Values.FirstOrDefault(e => e.CurrentWieldedLocation == EquipMask.MissileWeapon && e is MissileLauncher);
}
///
/// Returns the current equipped weapon in main hand
///
public WorldObject GetEquippedMainHand()
{
return GetEquippedMeleeWeapon(true) ?? GetEquippedMissileWeapon() ?? GetEquippedWand();
}
///
/// Returns either a shield, an off-hand weapon, or null
///
public WorldObject GetEquippedOffHand()
{
return EquippedObjects.Values.FirstOrDefault(e => e.CurrentWieldedLocation == EquipMask.Shield);
}
///
/// Returns the currently equipped shield
///
public WorldObject GetEquippedShield()
{
return EquippedObjects.Values.FirstOrDefault(e => e.IsShield && e.CurrentWieldedLocation == EquipMask.Shield);
}
///
/// Returns the currently equipped missile ammo
///
///
public WorldObject GetEquippedAmmo()
{
return EquippedObjects.Values.FirstOrDefault(e => e.CurrentWieldedLocation == EquipMask.MissileAmmo);
}
///
/// Returns the ammo slot item for bows / atlatls,
/// or the missile weapon for thrown weapons
///
public WorldObject GetMissileAmmo()
{
var weapon = GetEquippedMissileWeapon();
if (weapon != null && weapon.IsAmmoLauncher)
return GetEquippedAmmo();
return weapon;
}
///
/// This is initialized the first time an item is equipped that has a rating. If it is null, there are no equipped items with ratings.
///
private Dictionary equippedItemsRatingCache;
private void AddItemToEquippedItemsRatingCache(WorldObject wo)
{
if ((wo.GearDamage ?? 0) == 0 && (wo.GearDamageResist ?? 0) == 0 && (wo.GearCrit ?? 0) == 0 && (wo.GearCritResist ?? 0) == 0 && (wo.GearCritDamage ?? 0) == 0 && (wo.GearCritDamageResist ?? 0) == 0 && (wo.GearHealingBoost ?? 0) == 0 && (wo.GearMaxHealth ?? 0) == 0 && (wo.GearPKDamageRating ?? 0) == 0 && (wo.GearPKDamageResistRating ?? 0) == 0)
return;
if (equippedItemsRatingCache == null)
{
equippedItemsRatingCache = new Dictionary
{
{ PropertyInt.GearDamage, 0 },
{ PropertyInt.GearDamageResist, 0 },
{ PropertyInt.GearCrit, 0 },
{ PropertyInt.GearCritResist, 0 },
{ PropertyInt.GearCritDamage, 0 },
{ PropertyInt.GearCritDamageResist, 0 },
{ PropertyInt.GearHealingBoost, 0 },
{ PropertyInt.GearMaxHealth, 0 },
{ PropertyInt.GearPKDamageRating, 0 },
{ PropertyInt.GearPKDamageResistRating, 0 },
};
}
equippedItemsRatingCache[PropertyInt.GearDamage] += (wo.GearDamage ?? 0);
equippedItemsRatingCache[PropertyInt.GearDamageResist] += (wo.GearDamageResist ?? 0);
equippedItemsRatingCache[PropertyInt.GearCrit] += (wo.GearCrit ?? 0);
equippedItemsRatingCache[PropertyInt.GearCritResist] += (wo.GearCritResist ?? 0);
equippedItemsRatingCache[PropertyInt.GearCritDamage] += (wo.GearCritDamage ?? 0);
equippedItemsRatingCache[PropertyInt.GearCritDamageResist] += (wo.GearCritDamageResist ?? 0);
equippedItemsRatingCache[PropertyInt.GearHealingBoost] += (wo.GearHealingBoost ?? 0);
equippedItemsRatingCache[PropertyInt.GearMaxHealth] += (wo.GearMaxHealth ?? 0);
equippedItemsRatingCache[PropertyInt.GearPKDamageRating] += (wo.GearPKDamageRating ?? 0);
equippedItemsRatingCache[PropertyInt.GearPKDamageResistRating] += (wo.GearPKDamageResistRating ?? 0);
}
private void RemoveItemFromEquippedItemsRatingCache(WorldObject wo)
{
if (equippedItemsRatingCache == null)
return;
equippedItemsRatingCache[PropertyInt.GearDamage] -= (wo.GearDamage ?? 0);
equippedItemsRatingCache[PropertyInt.GearDamageResist] -= (wo.GearDamageResist ?? 0);
equippedItemsRatingCache[PropertyInt.GearCrit] -= (wo.GearCrit ?? 0);
equippedItemsRatingCache[PropertyInt.GearCritResist] -= (wo.GearCritResist ?? 0);
equippedItemsRatingCache[PropertyInt.GearCritDamage] -= (wo.GearCritDamage ?? 0);
equippedItemsRatingCache[PropertyInt.GearCritDamageResist] -= (wo.GearCritDamageResist ?? 0);
equippedItemsRatingCache[PropertyInt.GearHealingBoost] -= (wo.GearHealingBoost ?? 0);
equippedItemsRatingCache[PropertyInt.GearMaxHealth] -= (wo.GearMaxHealth ?? 0);
equippedItemsRatingCache[PropertyInt.GearPKDamageRating] -= (wo.GearPKDamageRating ?? 0);
equippedItemsRatingCache[PropertyInt.GearPKDamageResistRating] -= (wo.GearPKDamageResistRating ?? 0);
}
public int GetEquippedItemsRatingSum(PropertyInt rating)
{
if (equippedItemsRatingCache == null)
return 0;
if (equippedItemsRatingCache.TryGetValue(rating, out var value))
return value;
log.Error($"Creature_Equipment.GetEquippedItemsRatingsSum() does not support {rating}");
return 0;
}
///
/// Try to wield an object for non-player creatures
///
///
public bool TryWieldObject(WorldObject worldObject, EquipMask wieldedLocation)
{
// check wield requirements?
if (!TryEquipObject(worldObject, wieldedLocation))
return false;
// enqueue to ensure parent object has spawned,
// and spell fx are visible
var actionChain = new ActionChain();
actionChain.AddDelaySeconds(0.1);
actionChain.AddAction(this, () => TryActivateItemSpells(worldObject));
actionChain.EnqueueChain();
return true;
}
///
/// Tries to activate item spells for a non-player creature
///
private void TryActivateItemSpells(WorldObject item)
{
if (!Attackable)
return;
// check activation requirements?
foreach (var spell in item.Biota.GetKnownSpellsIds(BiotaDatabaseLock))
CreateItemSpell(item, (uint)spell);
}
///
/// This will set the CurrentWieldedLocation property to wieldedLocation and the Wielder property to this guid and will add it to the EquippedObjects dictionary.
/// It will also increase the EncumbranceVal and Value.
///
public bool TryEquipObject(WorldObject worldObject, EquipMask wieldedLocation)
{
// todo: verify wielded location is valid location
if (!WieldedLocationIsAvailable(worldObject, wieldedLocation))
return false;
worldObject.CurrentWieldedLocation = wieldedLocation;
worldObject.WielderId = Biota.Id;
worldObject.Wielder = this;
EquippedObjects[worldObject.Guid] = worldObject;
AddItemToEquippedItemsRatingCache(worldObject);
EncumbranceVal += (worldObject.EncumbranceVal ?? 0);
Value += (worldObject.Value ?? 0);
TrySetChild(worldObject);
worldObject.OnWield(this);
return true;
}
protected bool TryWieldObjectWithBroadcasting(WorldObject worldObject, EquipMask wieldedLocation)
{
// check wield requirements?
if (!TryEquipObjectWithBroadcasting(worldObject, wieldedLocation))
return false;
TryActivateItemSpells(worldObject);
return true;
}
///
/// This will set the CurrentWieldedLocation property to wieldedLocation and the Wielder property to this guid and will add it to the EquippedObjects dictionary.
/// It will also increase the EncumbranceVal and Value.
///
protected bool TryEquipObjectWithBroadcasting(WorldObject worldObject, EquipMask wieldedLocation)
{
if (!TryEquipObject(worldObject, wieldedLocation))
return false;
if (IsInChildLocation(worldObject)) // Is this equipped item visible to others?
EnqueueBroadcast(false, new GameMessageSound(Guid, Sound.WieldObject));
if (worldObject.ParentLocation != null)
EnqueueBroadcast(new GameMessageParentEvent(this, worldObject));
EnqueueBroadcast(new GameMessageObjDescEvent(this));
// Notify viewers in the area that we've equipped the item
EnqueueActionBroadcast(p => p.TrackEquippedObject(this, worldObject));
return true;
}
///
/// This will remove the Wielder and CurrentWieldedLocation properties on the item and will remove it from the EquippedObjects dictionary.
/// It does not add it to inventory as you could be unwielding to the ground or a chest.
/// It will also decrease the EncumbranceVal and Value.
///
public bool TryDequipObject(ObjectGuid objectGuid, out WorldObject worldObject, out EquipMask wieldedLocation)
{
if (!EquippedObjects.Remove(objectGuid, out worldObject))
{
wieldedLocation = 0;
return false;
}
RemoveItemFromEquippedItemsRatingCache(worldObject);
wieldedLocation = worldObject.CurrentWieldedLocation ?? EquipMask.None;
worldObject.RemoveProperty(PropertyInt.CurrentWieldedLocation);
worldObject.RemoveProperty(PropertyInstanceId.Wielder);
worldObject.Wielder = null;
worldObject.OnSpellsDeactivated();
EncumbranceVal -= (worldObject.EncumbranceVal ?? 0);
Value -= (worldObject.Value ?? 0);
ClearChild(worldObject);
var wo = worldObject;
Children.Remove(Children.Find(s => s.Guid == wo.Guid.Full));
worldObject.OnUnWield(this);
return true;
}
///
/// Called by non-player creatures to unwield an item,
/// removing any spells casted by the item
///
public bool TryUnwieldObjectWithBroadcasting(ObjectGuid objectGuid, out WorldObject worldObject, out EquipMask wieldedLocation, bool droppingToLandscape = false)
{
if (!TryDequipObjectWithBroadcasting(objectGuid, out worldObject, out wieldedLocation, droppingToLandscape))
return false;
// remove item spells
foreach (var spell in worldObject.Biota.GetKnownSpellsIds(BiotaDatabaseLock))
RemoveItemSpell(worldObject, (uint)spell, true);
return true;
}
///
/// This will remove the Wielder and CurrentWieldedLocation properties on the item and will remove it from the EquippedObjects dictionary.
/// It does not add it to inventory as you could be unwielding to the ground or a chest.
/// It will also decrease the EncumbranceVal and Value.
///
protected bool TryDequipObjectWithBroadcasting(ObjectGuid objectGuid, out WorldObject worldObject, out EquipMask wieldedLocation, bool droppingToLandscape = false)
{
if (!TryDequipObject(objectGuid, out worldObject, out wieldedLocation))
return false;
if ((wieldedLocation & EquipMask.Selectable) != 0) // Is this equipped item visible to others?
EnqueueBroadcast(false, new GameMessageSound(Guid, Sound.UnwieldObject));
EnqueueBroadcast(new GameMessageObjDescEvent(this));
// If item has any spells, remove them from the registry on unequip
if (worldObject.Biota.PropertiesSpellBook != null)
{
foreach (var spell in worldObject.Biota.PropertiesSpellBook)
{
if (worldObject.HasProcSpell((uint)spell.Key))
continue;
RemoveItemSpell(worldObject, (uint)spell.Key, true);
}
}
if (!droppingToLandscape)
{
// This should only be called if the object is going to the private storage, not when dropped on the landscape
var wo = worldObject;
EnqueueActionBroadcast(p => p.RemoveTrackedEquippedObject(this, wo));
}
return true;
}
protected bool IsInChildLocation(WorldObject item)
{
if (item.CurrentWieldedLocation == null)
return false;
if (((EquipMask)item.CurrentWieldedLocation & EquipMask.Selectable) != 0)
return true;
if (((EquipMask)item.CurrentWieldedLocation & EquipMask.MissileAmmo) != 0)
{
var wielder = item.Wielder;
if (wielder != null && wielder is Creature creature)
{
var weapon = creature.GetEquippedMissileWeapon();
if (weapon == null)
return false;
if (creature.CombatMode == CombatMode.Missile && weapon.WeenieType == WeenieType.MissileLauncher)
return true;
}
}
return false;
}
///
/// This method sets properties needed for items that will be child items.
/// Items here are only items equipped in the hands.
/// This deals with the orientation and positioning for visual appearance of the child items held by the parent.
/// If the item isn't in a valid child state (CurrentWieldedLocation), the child properties will be cleared. (Placement, ParentLocation, Location).
///
private bool TrySetChild(WorldObject item)
{
if (!IsInChildLocation(item))
{
ClearChild(item);
return false;
}
GetPlacementLocation(item, item.CurrentWieldedLocation ?? 0, out var placement, out var parentLocation);
Children.Add(new HeldItem(item.Guid.Full, (int)parentLocation, (EquipMask)item.CurrentWieldedLocation));
item.Placement = placement;
item.ParentLocation = parentLocation;
item.Location = Location;
return true;
}
private static void GetPlacementLocation(WorldObject item, EquipMask wieldedLocation, out Placement placement, out ParentLocation parentLocation)
{
switch (wieldedLocation)
{
case EquipMask.MeleeWeapon:
case EquipMask.Held:
case EquipMask.TwoHanded:
placement = ACE.Entity.Enum.Placement.RightHandCombat;
parentLocation = ACE.Entity.Enum.ParentLocation.RightHand;
break;
case EquipMask.Shield:
if (item.ItemType == ItemType.Armor)
{
placement = ACE.Entity.Enum.Placement.Shield;
parentLocation = ACE.Entity.Enum.ParentLocation.Shield;
}
else
{
placement = ACE.Entity.Enum.Placement.RightHandNonCombat;
parentLocation = ACE.Entity.Enum.ParentLocation.LeftWeapon;
}
break;
case EquipMask.MissileWeapon:
if (item.DefaultCombatStyle == CombatStyle.Bow || item.DefaultCombatStyle == CombatStyle.Crossbow)
{
placement = ACE.Entity.Enum.Placement.LeftHand;
parentLocation = ACE.Entity.Enum.ParentLocation.LeftHand;
}
else
{
placement = ACE.Entity.Enum.Placement.RightHandCombat;
parentLocation = ACE.Entity.Enum.ParentLocation.RightHand;
}
break;
default:
placement = ACE.Entity.Enum.Placement.Default;
parentLocation = ACE.Entity.Enum.ParentLocation.None;
break;
}
}
private static bool IsWeaponSlot(EquipMask equipMask)
{
switch (equipMask)
{
case EquipMask.MeleeWeapon:
case EquipMask.Held:
case EquipMask.TwoHanded:
case EquipMask.Shield:
case EquipMask.MissileWeapon:
return true;
default:
return false;
}
}
///
/// This clears the child properties:
/// Placement = ACE.Entity.Enum.Placement.Resting
/// ParentLocation = null
/// Location = null
///
protected void ClearChild(WorldObject item)
{
item.Placement = ACE.Entity.Enum.Placement.Resting;
item.ParentLocation = null;
item.Location = null;
}
///
/// Removes an existing object from Children if exists,
/// and resets to new Child position
///
public void ResetChild(WorldObject item)
{
Children.Remove(Children.Find(s => s.Guid == item.Guid.Full));
TrySetChild(item);
}
///
/// This is called prior to SendSelf to load up the child list for wielded items that are held in a hand.
///
private void SetChildren()
{
Children.Clear();
foreach (var item in EquippedObjects.Values)
{
if (item.CurrentWieldedLocation != null)
TrySetChild(item);
}
}
public void GenerateWieldList()
{
if (Biota.PropertiesCreateList == null)
return;
var wielded = Biota.PropertiesCreateList.Where(i => (i.DestinationType & DestinationType.Wield) != 0).ToList();
var items = CreateListSelect(wielded);
foreach (var item in items)
{
var wo = WorldObjectFactory.CreateNewWorldObject(item);
if (wo == null) continue;
//if (wo.ValidLocations == null || (ItemCapacity ?? 0) > 0)
{
if (!TryAddToInventory(wo))
wo.Destroy();
}
//else
//TryWieldObject(wo, (EquipMask)wo.ValidLocations);
}
}
public static List CreateListSelect(List createList)
{
var trophy_drop_rate = PropertyManager.GetDouble("trophy_drop_rate").Item;
if (trophy_drop_rate != 1.0)
return CreateListSelect(createList, (float)trophy_drop_rate);
var rng = ThreadSafeRandom.Next(0.0f, 1.0f);
var totalProbability = 0.0f;
var rngSelected = false;
var results = new List();
foreach (var item in createList)
{
var destinationType = (DestinationType)item.DestinationType;
var useRNG = destinationType.HasFlag(DestinationType.Treasure) && item.Shade != 0;
var shadeOrProbability = item.Shade;
if (useRNG)
{
// handle sets in 0-1 chunks
if (totalProbability >= 1.0f)
{
totalProbability = 0.0f;
rng = ThreadSafeRandom.Next(0.0f, 1.0f);
rngSelected = false;
}
var probability = shadeOrProbability;
totalProbability += probability;
if (rngSelected || rng >= totalProbability)
continue;
rngSelected = true;
}
results.Add(item);
}
return results;
}
public static List CreateListSelect(List _createList, float dropRateMod)
{
var createList = new CreateList(_createList);
CreateListSetModifier modifier = null;
var rng = ThreadSafeRandom.Next(0.0f, 1.0f);
var totalProbability = 0.0f;
var rngSelected = false;
var results = new List();
for (var i = 0; i < _createList.Count; i++)
{
var item = _createList[i];
var destinationType = (DestinationType)item.DestinationType;
var useRNG = destinationType.HasFlag(DestinationType.Treasure) && item.Shade != 0;
var shadeOrProbability = item.Shade;
if (useRNG)
{
// handle sets in 0-1 chunks
if (totalProbability == 0.0f || totalProbability >= 1.0f)
{
totalProbability = 0.0f;
rng = ThreadSafeRandom.Next(0.0f, 1.0f);
rngSelected = false;
modifier = createList.GetSetModifier(i, dropRateMod);
}
var probability = shadeOrProbability * (item.WeenieClassId != 0 ? modifier.TrophyMod : modifier.NoneMod);
totalProbability += probability;
if (rngSelected || rng >= totalProbability)
continue;
rngSelected = true;
}
results.Add(item);
}
return results;
}
public uint? WieldedTreasureType
{
get => GetProperty(PropertyDataId.WieldedTreasureType);
set { if (!value.HasValue) RemoveProperty(PropertyDataId.WieldedTreasureType); else SetProperty(PropertyDataId.WieldedTreasureType, value.Value); }
}
public List WieldedTreasure
{
get
{
if (WieldedTreasureType.HasValue)
return DatabaseManager.World.GetCachedWieldedTreasure(WieldedTreasureType.Value);
return null;
}
}
public void GenerateWieldedTreasure()
{
if (WieldedTreasure == null) return;
//var table = new TreasureWieldedTable(WieldedTreasure);
var wieldedTreasure = GenerateWieldedTreasureSets(WieldedTreasure);
if (wieldedTreasure == null)
return;
foreach (var item in wieldedTreasure)
{
//if (item.ValidLocations == null || (ItemCapacity ?? 0) > 0)
{
if (!TryAddToInventory(item))
item.Destroy();
}
//else
//TryWieldObject(item, (EquipMask)item.ValidLocations);
}
}
public uint? InventoryTreasureType
{
get => GetProperty(PropertyDataId.InventoryTreasureType);
set { if (!value.HasValue) RemoveProperty(PropertyDataId.InventoryTreasureType); else SetProperty(PropertyDataId.InventoryTreasureType, value.Value); }
}
public void GenerateInventoryTreasure()
{
if (InventoryTreasureType == null || InventoryTreasureType.Value <= 0) return;
// based on property name found in older data, this property was only found 5 weenies (entirely contained in Focusing Stone quest)
// guessing that the value might have possibly allowed for either Death or Wielded treasure, but technically it might have only been the former.
// so for now, coded for checking both types.
// Although the property's name seemingly was removed, either it's value was still used in code OR its value was moved into DeathTreasureType/CreateList
// because pcaps for these 5 objects do show similar, if not exact, results on corpses.
var treasureDeath = DatabaseManager.World.GetCachedDeathTreasure(InventoryTreasureType.Value);
var treasureWielded = DatabaseManager.World.GetCachedWieldedTreasure(InventoryTreasureType.Value);
var treasure = new List();
if (treasureDeath != null)
{
treasure = LootGenerationFactory.CreateRandomLootObjects(treasureDeath);
}
else if (treasureWielded != null)
{
treasure = GenerateWieldedTreasureSets(treasureWielded);
}
foreach (var item in treasure)
{
item.DestinationType = DestinationType.Treasure;
// add this flag so item can move over to corpse upon death
// (ACE logic: it is likely all inventory of a creature was moved over without reservation (bonded rules enforced), but ACE is slightly different in how it handles it for net same result)
if (!TryAddToInventory(item))
item.Destroy();
}
}
}
}