mirror of
https://github.com/ACEmulator/ACE
synced 2026-08-17 12:26:06 -04:00
* Update ShardDatabaseOfflineTools.cs * Update Corpse.cs * Update Creature_Death.cs * Update Player_Death.cs * Update Player_Inventory.cs * Update WorldObject_Decay.cs * Update HouseManager.cs * Update Player_House.cs * Update RecipeManager.cs * Update Player_Allegiance.cs * Update AuthenticationDatabase.cs * Update ShardDatabase.cs * Update WorldDatabase.cs * Update Player_Magic.cs * Update Player_Skills.cs * Update Player_Attributes.cs * Update Player_Combat.cs * Update PhysicsObj.cs * Update Player_Vitals.cs * Update Player_Missile.cs * Update Player_Melee.cs * Update Monster_Melee.cs * Update Session.cs
169 lines
6.8 KiB
C#
169 lines
6.8 KiB
C#
using System;
|
|
using System.Linq;
|
|
|
|
using ACE.Entity;
|
|
using ACE.Entity.Enum;
|
|
using ACE.Server.Entity.Actions;
|
|
using ACE.Server.Managers;
|
|
using ACE.Server.Network.GameMessages.Messages;
|
|
|
|
namespace ACE.Server.WorldObjects
|
|
{
|
|
partial class WorldObject
|
|
{
|
|
/// <summary>
|
|
/// The default number of seconds for a object on a landblock to disappear<para />
|
|
/// Current default is 5 minutes
|
|
/// </summary>
|
|
protected TimeSpan DefaultTimeToRot { get; set; } = TimeSpan.FromMinutes(5);
|
|
|
|
/// <summary>
|
|
/// A decayable object is one that, when it exists on a landblock, would decay (rot) over time.<para />
|
|
/// When it rots, it would be destroyed, and removed from the landblock.<para />
|
|
/// In most cases, these should be player dropped items or corpses. It can also be a missile or spell projectile.<para />
|
|
/// Items that have a TimeToRot value of -1 will return false.<para />
|
|
/// Generators and items still linked to a generator will return false.
|
|
/// </summary>
|
|
public bool IsDecayable()
|
|
{
|
|
if (!Guid.IsDynamic())
|
|
return false;
|
|
|
|
// Don't rot generators, and items that were generated by a generator
|
|
// If the item was generated by a generator and then picked up by a player, the wo.Generator property would be set to null.
|
|
if (IsGenerator || Generator != null)
|
|
return false;
|
|
|
|
// Don't rot items with lifespan, they'll handle their own version of decay.
|
|
if (Lifespan.HasValue)
|
|
return false;
|
|
|
|
if (TimeToRot.HasValue)
|
|
return TimeToRot != -1; // -1 = Never Rot
|
|
|
|
return true;
|
|
}
|
|
|
|
private bool decayCompleted;
|
|
|
|
public void Decay(TimeSpan elapsed)
|
|
{
|
|
// http://asheron.wikia.com/wiki/Item_Decay
|
|
|
|
if (decayCompleted)
|
|
return;
|
|
|
|
var previousTTR = TimeToRot;
|
|
|
|
if (!TimeToRot.HasValue)
|
|
{
|
|
TimeToRot = DefaultTimeToRot.TotalSeconds;
|
|
|
|
if (this is Corpse && Level.HasValue)
|
|
log.InfoFormat("[CORPSE] {0} (0x{1}).Decay: TimeToRot had no value, set to {2}", Name, Guid, TimeToRot);
|
|
|
|
return;
|
|
}
|
|
|
|
var corpse = this as Corpse;
|
|
|
|
if (corpse != null)
|
|
{
|
|
if (!corpse.InventoryLoaded)
|
|
return;
|
|
|
|
if (corpse.Inventory.Count == 0 && TimeToRot.Value > Corpse.EmptyDecayTime)
|
|
{
|
|
TimeToRot = Corpse.EmptyDecayTime;
|
|
if (Level.HasValue && PropertyManager.GetBool("corpse_decay_tick_logging").Item)
|
|
log.InfoFormat("[CORPSE] {0} (0x{1}).Decay({2}): InventoryLoaded = {3} | Inventory.Count = {4} | previous TimeToRot: {5} | current TimeToRot: {6}", corpse.Name, corpse.Guid, elapsed, corpse.InventoryLoaded, corpse.Inventory.Count, previousTTR, TimeToRot);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (TimeToRot > 0)
|
|
{
|
|
TimeToRot -= elapsed.TotalSeconds;
|
|
|
|
if (this is Corpse && Level.HasValue && PropertyManager.GetBool("corpse_decay_tick_logging").Item)
|
|
log.InfoFormat("[CORPSE] {0} (0x{1}).Decay({2}): previous TimeToRot: {3} | current TimeToRot: {4}", corpse.Name, corpse.Guid, elapsed, previousTTR, TimeToRot);
|
|
|
|
// Is there still time left?
|
|
if (TimeToRot > 0)
|
|
return;
|
|
|
|
TimeToRot = -2; // We force it to -2 to make sure it doesn't end up at 0 or -1. 0 indicates instant rot. -1 indicates no rot. 0 and -1 can be found in weenie defaults
|
|
|
|
if (this is Corpse && Level.HasValue && PropertyManager.GetBool("corpse_decay_tick_logging").Item)
|
|
log.InfoFormat("[CORPSE] {0} (0x{1}).Decay({2}): previous TimeToRot: {3} | current TimeToRot: {4}", corpse.Name, corpse.Guid, elapsed, previousTTR, TimeToRot);
|
|
}
|
|
|
|
if (this is Container container && container.IsOpen)
|
|
{
|
|
// If you wanted to add a grace period to the container to give Player B more time to open it after Player A closes it, it would go here.
|
|
|
|
return;
|
|
}
|
|
|
|
// Time to rot has elapsed, time to disappear...
|
|
decayCompleted = true;
|
|
|
|
// If this is a player corpse, puke out the corpses contents onto the landblock
|
|
if (corpse != null && !corpse.IsMonster)
|
|
{
|
|
var inventoryGUIDs = corpse.Inventory.Keys.ToList();
|
|
|
|
var pukedItems = "";
|
|
|
|
foreach (var guid in inventoryGUIDs)
|
|
{
|
|
if (corpse.TryRemoveFromInventory(guid, out var item))
|
|
{
|
|
item.Location = new Position(corpse.Location);
|
|
item.Location.PositionZ += 0.05f * (item.ObjScale ?? 1.0f);
|
|
item.Placement = ACE.Entity.Enum.Placement.Resting; // This is needed to make items lay flat on the ground.
|
|
CurrentLandblock.AddWorldObject(item);
|
|
item.SaveBiotaToDatabase();
|
|
pukedItems += $"{item.Name} (0x{item.Guid.Full.ToString("X8")}), ";
|
|
}
|
|
}
|
|
|
|
if (pukedItems.EndsWith(", "))
|
|
pukedItems = pukedItems.Substring(0, pukedItems.Length - 2);
|
|
|
|
log.Info($"[CORPSE] {corpse.Name} (0x{corpse.Guid}) at {corpse.Location.ToLOCString()} has decayed{((pukedItems == "") ? "" : $" and placed the following items on the landblock: {pukedItems}")}.");
|
|
}
|
|
|
|
if (corpse != null)
|
|
{
|
|
EnqueueBroadcast(new GameMessageScript(Guid, PlayScript.Destroy));
|
|
|
|
var actionChain = new ActionChain();
|
|
actionChain.AddDelaySeconds(1.0f);
|
|
actionChain.AddAction(this, () => Destroy());
|
|
actionChain.EnqueueChain();
|
|
}
|
|
else
|
|
Destroy();
|
|
}
|
|
|
|
public void DeleteObject(Container rootOwner = null)
|
|
{
|
|
if (Wielder != null)
|
|
{
|
|
if (Wielder is Player player)
|
|
player.TryDequipObjectWithNetworking(Guid, out _, Player.DequipObjectAction.ConsumeItem);
|
|
else if (Wielder is Creature creature)
|
|
creature.TryUnwieldObjectWithBroadcasting(Guid, out _, out _);
|
|
}
|
|
else if (rootOwner != null)
|
|
{
|
|
if (rootOwner is Player player)
|
|
player.TryRemoveFromInventoryWithNetworking(Guid, out _, Player.RemoveFromInventoryAction.ConsumeItem);
|
|
else
|
|
rootOwner.TryRemoveFromInventory(Guid);
|
|
}
|
|
Destroy();
|
|
}
|
|
}
|
|
}
|