public ActionChain GetCreateCorpseChain() { ActionChain createCorpseChain = new ActionChain(this, () => { // Create Corspe and set a location on the ground // TODO: set text of killer in description and find a better computation for the location, some corpse could end up in the ground var corpse = CorpseObjectFactory.CreateCorpse(this, this.Location); // FIXME(ddevec): We don't have a real corpse yet, so these come in null -- this hack just stops them from crashing the game corpse.Location.PositionY -= (corpse.ObjScale ?? 0); corpse.Location.PositionZ -= (corpse.ObjScale ?? 0) / 2; // Corpses stay on the ground for 5 * player level but minimum 1 hour // corpse.DespawnTime = Math.Max((int)session.Player.PropertiesInt[Enum.Properties.PropertyInt.Level] * 5, 360) + WorldManager.PortalYearTicks; // as in live // corpse.DespawnTime = 20 + WorldManager.PortalYearTicks; // only for testing float despawnTime = GetCorpseSpawnTime(); // Create corpse CurrentLandblock.AddWorldObject(corpse); // Create corpse decay ActionChain despawnChain = new ActionChain(); despawnChain.AddDelaySeconds(despawnTime); despawnChain.AddAction(CurrentLandblock, () => corpse.CurrentLandblock.RemoveWorldObject(corpse.Guid, false)); despawnChain.EnqueueChain(); }); return(createCorpseChain); }
public void ActivateLinks(List <LandblockInstance> sourceObjects, List <Biota> biotas) { if (LinkedInstances.Count == 0) { return; } if (IsGenerator) { AddGeneratorLinks(); return; } foreach (var link in LinkedInstances) { WorldObject wo = null; var biota = biotas.FirstOrDefault(b => b.Id == link.Guid); if (biota == null) { wo = WorldObjectFactory.CreateWorldObject(DatabaseManager.World.GetCachedWeenie(link.WeenieClassId), new ObjectGuid(link.Guid)); } else { wo = WorldObjectFactory.CreateWorldObject(biota); //Console.WriteLine("Loaded child biota " + wo.Name); } if (wo == null) { continue; } wo.Location = new Position(link.ObjCellId, link.OriginX, link.OriginY, link.OriginZ, link.AnglesX, link.AnglesY, link.AnglesZ, link.AnglesW); SetLinkProperties(wo); CurrentLandblock?.AddWorldObject(wo); wo.ParentLink = this; ChildLinks.Add(wo); // process nested links recursively foreach (var subLink in link.LandblockInstanceLink) { var linkInstance = sourceObjects.FirstOrDefault(x => x.Guid == subLink.ChildGuid); if (linkInstance != null) { wo.LinkedInstances.Add(linkInstance); } } if (wo.LinkedInstances.Count > 0) { wo.ActivateLinks(sourceObjects, biotas); } } }
public virtual void ActivateLinks(List <LandblockInstance> sourceObjects) { if (LinkedInstances.Count == 0) { return; } if (IsGenerator) { AddGeneratorLinks(); return; } foreach (var link in LinkedInstances) { var wo = WorldObjectFactory.CreateWorldObject(DatabaseManager.World.GetCachedWeenie(link.WeenieClassId), new ObjectGuid(link.Guid)); if (wo == null) { continue; } wo.Location = new Position(link.ObjCellId, link.OriginX, link.OriginY, link.OriginZ, link.AnglesX, link.AnglesY, link.AnglesZ, link.AnglesW); wo.ActivationTarget = Guid.Full; CurrentLandblock?.AddWorldObject(wo); // process nested links recursively foreach (var subLink in link.LandblockInstanceLink) { var linkInstance = sourceObjects.FirstOrDefault(x => x.Guid == subLink.ChildGuid); if (linkInstance != null) { wo.LinkedInstances.Add(linkInstance); } } if (wo.LinkedInstances.Count > 0) { wo.ActivateLinks(sourceObjects); } } }
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.Debug($"[CORPSE] {Name} (0x{Guid.ToString()}).Decay: TimeToRot had no value, set to {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.Debug($"[CORPSE] {corpse.Name} (0x{corpse.Guid.ToString()}).Decay({elapsed.ToString()}): InventoryLoaded = {corpse.InventoryLoaded} | Inventory.Count = {corpse.Inventory.Count} | previous TimeToRot: {previousTTR} | current TimeToRot: {TimeToRot}"); } return; } } if (TimeToRot > 0) { TimeToRot -= elapsed.TotalSeconds; if (this is Corpse && Level.HasValue && PropertyManager.GetBool("corpse_decay_tick_logging").Item) { log.Debug($"[CORPSE] {corpse.Name} (0x{corpse.Guid.ToString()}).Decay({elapsed.ToString()}): previous TimeToRot: {previousTTR} | current TimeToRot: {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.Debug($"[CORPSE] {corpse.Name} (0x{corpse.Guid.ToString()}).Decay({elapsed.ToString()}): previous TimeToRot: {previousTTR} | current TimeToRot: {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.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.Debug($"[CORPSE] {corpse.Name} (0x{corpse.Guid.ToString()}) 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 Decay(TimeSpan elapsed) { // http://asheron.wikia.com/wiki/Item_Decay if (decayCompleted) { return; } if (!TimeToRot.HasValue) { TimeToRot = DefaultTimeToRot.TotalSeconds; return; } var corpse = this as Corpse; if (corpse != null && corpse.Inventory.Count == 0 && TimeToRot.Value > Corpse.EmptyDecayTime) { TimeToRot = Corpse.EmptyDecayTime; return; } if (TimeToRot > 0) { TimeToRot -= elapsed.TotalSeconds; // 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 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(); foreach (var guid in inventoryGUIDs) { if (corpse.TryRemoveFromInventory(guid, out var item)) { item.Location = new Position(corpse.Location); item.Placement = ACE.Entity.Enum.Placement.Resting; // This is needed to make items lay flat on the ground. CurrentLandblock.AddWorldObject(item); } } } Destroy(); }
public void HandleActionDropItem(ObjectGuid itemGuid) { // Goody Goody -- lets build drop chain // First start drop animation new ActionChain(this, () => { // check packs of item. WorldObject item; if (!TryRemoveFromInventory(itemGuid, out item)) { // check to see if this item is wielded if (TryDequipObject(itemGuid, out item)) { Session.Network.EnqueueSend( new GameMessageSound(Guid, Sound.WieldObject, 1.0f), new GameMessageObjDescEvent(this), new GameMessageUpdateInstanceId(Guid, new ObjectGuid(0), PropertyInstanceId.Wielder)); } } item.SetPropertiesForWorld(this); UniversalMotion motion = new UniversalMotion(MotionStance.Standing); motion.MovementData.ForwardCommand = (uint)MotionCommand.Pickup; Session.Network.EnqueueSend(new GameMessageUpdateInstanceId(itemGuid, new ObjectGuid(0), PropertyInstanceId.Container)); // Set drop motion CurrentLandblock.EnqueueBroadcastMotion(this, motion); // Now wait for Drop Motion to finish -- use ActionChain ActionChain chain = new ActionChain(); // Wait for drop animation var motionTable = DatManager.PortalDat.ReadFromDat <MotionTable>(MotionTableId); var pickupAnimationLength = motionTable.GetAnimationLength(MotionCommand.Pickup); chain.AddDelaySeconds(pickupAnimationLength); // Play drop sound // Put item on landblock chain.AddAction(this, () => { motion = new UniversalMotion(MotionStance.Standing); CurrentLandblock.EnqueueBroadcastMotion(this, motion); Session.Network.EnqueueSend( new GameMessageSound(Guid, Sound.DropItem, (float)1.0), new GameMessagePutObjectIn3d(Session, this, itemGuid), new GameMessageUpdateInstanceId(itemGuid, new ObjectGuid(0), PropertyInstanceId.Container)); // This is the sequence magic - adds back into 3d space seem to be treated like teleport. Debug.Assert(item != null, "item != null"); item.Sequences.GetNextSequence(SequenceType.ObjectTeleport); item.Sequences.GetNextSequence(SequenceType.ObjectVector); CurrentLandblock.AddWorldObject(item); Session.Network.EnqueueSend(new GameMessageUpdateObject(item)); }); chain.EnqueueChain(); // Removed SaveSession - this was causing items that were dropped to not be removed from inventory. // If this causes a problem with vendor, we need to fix vendor. Og II }).EnqueueChain(); }
/// <summary> /// This is raised when we drop an item. It can be a wielded item, or an item in our inventory. /// </summary> public void HandleActionDropItem(ObjectGuid itemGuid) { // Goody Goody -- lets build drop chain // First start drop animation new ActionChain(this, () => { // check packs of item. WorldObject item; if (!TryRemoveFromInventory(itemGuid, out item)) { // check to see if this item is wielded if (TryDequipObject(itemGuid, out item)) { Children.Remove(Children.Find(s => s.Guid == item.Guid.Full)); Session.Network.EnqueueSend( new GameMessageSound(Guid, Sound.WieldObject, 1.0f), new GameMessageObjDescEvent(this), new GameMessageUpdateInstanceId(Guid, new ObjectGuid(0), PropertyInstanceId.Wielder)); } } if (item == null) { log.Error("Player_Inventory HandleActionDropItem item is null"); return; } item.SetPropertiesForWorld(this); // It's important that we save an item after it's been removed from inventory. // We want to avoid the scenario where the server crashes and a player has too many items. item.SaveBiotaToDatabase(); var motion = new UniversalMotion(MotionStance.Standing); motion.MovementData.ForwardCommand = (uint)MotionCommand.Pickup; Session.Network.EnqueueSend(new GameMessageUpdateInstanceId(itemGuid, new ObjectGuid(0), PropertyInstanceId.Container)); // Set drop motion CurrentLandblock.EnqueueBroadcastMotion(this, motion); // Now wait for Drop Motion to finish -- use ActionChain var chain = new ActionChain(); // Wait for drop animation var motionTable = DatManager.PortalDat.ReadFromDat <MotionTable>(MotionTableId); var pickupAnimationLength = motionTable.GetAnimationLength(MotionCommand.Pickup); chain.AddDelaySeconds(pickupAnimationLength); // Play drop sound // Put item on landblock chain.AddAction(this, () => { motion = new UniversalMotion(MotionStance.Standing); CurrentLandblock.EnqueueBroadcastMotion(this, motion); Session.Network.EnqueueSend( new GameMessageSound(Guid, Sound.DropItem, (float)1.0), new GameMessagePutObjectIn3d(Session, this, itemGuid), new GameMessageUpdateInstanceId(itemGuid, new ObjectGuid(0), PropertyInstanceId.Container), new GameMessagePrivateUpdatePropertyInt(Sequences, PropertyInt.EncumbranceVal, EncumbranceVal ?? 0)); // This is the sequence magic - adds back into 3d space seem to be treated like teleport. item.Sequences.GetNextSequence(SequenceType.ObjectTeleport); item.Sequences.GetNextSequence(SequenceType.ObjectVector); CurrentLandblock.AddWorldObject(item); Session.Network.EnqueueSend(new GameMessageUpdateObject(item)); }); chain.EnqueueChain(); }).EnqueueChain(); }