public void Reset(double?resetTimestamp) { if (resetTimestamp != ResetTimestamp) { return; // already cleared by previous reset } // TODO: if 'ResetInterval' style, do we want to ensure a minimum amount of time for the last viewer? var player = CurrentLandblock.GetObject(Viewer) as Player; if (IsOpen) { Close(player, false); } if (DefaultLocked && !IsLocked) { IsLocked = true; EnqueueBroadcast(new GameMessagePublicUpdatePropertyBool(this, PropertyBool.Locked, IsLocked)); } if (IsGenerator) { ResetGenerator(); if (InitCreate > 0) { Generator_Regeneration(); } } ResetTimestamp = Time.GetUnixTime(); ResetMessagePending = false; }
public override void Reset() { // TODO: if 'ResetInterval' style, do we want to ensure a minimum amount of time for the last viewer? var player = CurrentLandblock.GetObject(Viewer) as Player; if (IsOpen) { Close(player, false); } if (DefaultLocked && !IsLocked) { IsLocked = true; EnqueueBroadcast(new GameMessagePublicUpdatePropertyBool(this, PropertyBool.Locked, IsLocked)); } if (IsGenerator) { ResetGenerator(); if (InitCreate > 0) { Generator_Regeneration(); } } ResetMessagePending = false; }
public override void Heartbeat(double currentUnixTime) { Inventory_Tick(); foreach (var subcontainer in Inventory.Values.Where(i => i is Container)) { (subcontainer as Container).Inventory_Tick(); } // for landblock containers if (IsOpen && CurrentLandblock != null) { var viewer = CurrentLandblock.GetObject(Viewer) as Player; if (viewer == null) { Close(null); return; } var withinUseRadius = CurrentLandblock.WithinUseRadius(viewer, Guid, out var targetValid); if (!withinUseRadius) { Close(viewer); return; } } base.Heartbeat(currentUnixTime); }
private void LogOut_Final(bool skipAnimations = false) { if (CurrentLandblock != null) { if (skipAnimations) { CurrentLandblock?.RemoveWorldObject(Guid, false); SetPropertiesAtLogOut(); SavePlayerToDatabase(); PlayerManager.SwitchPlayerFromOnlineToOffline(this); } else { var logout = new Motion(MotionStance.NonCombat, MotionCommand.LogOut); EnqueueBroadcastMotion(logout); EnqueueBroadcastPhysicsState(); var logoutChain = new ActionChain(); var motionTable = DatManager.PortalDat.ReadFromDat <MotionTable>((uint)MotionTableId); float logoutAnimationLength = motionTable.GetAnimationLength(MotionCommand.LogOut); logoutChain.AddDelaySeconds(logoutAnimationLength); // remove the player from landblock management -- after the animation has run logoutChain.AddAction(WorldManager.ActionQueue, () => { // If we're in the dying animation process, we cannot RemoveWorldObject and logout until that animation completes.. if (isInDeathProcess) { return; } CurrentLandblock?.RemoveWorldObject(Guid, false); SetPropertiesAtLogOut(); SavePlayerToDatabase(); PlayerManager.SwitchPlayerFromOnlineToOffline(this); }); // close any open landblock containers (chests / corpses) if (LastOpenedContainerId != ObjectGuid.Invalid) { var container = CurrentLandblock.GetObject(LastOpenedContainerId) as Container; if (container != null) { container.Close(this); } } logoutChain.EnqueueChain(); } } else { SetPropertiesAtLogOut(); SavePlayerToDatabase(); PlayerManager.SwitchPlayerFromOnlineToOffline(this); } }
/// <summary> /// Called when player clicks the 'Buy house' button, /// after adding the items required /// </summary> public void HandleActionBuyHouse(uint slumlord_id, List <uint> item_ids) { Console.WriteLine("\nHandleActionBuyHouse()"); var slumlord = (SlumLord)CurrentLandblock.GetObject(slumlord_id); if (slumlord == null) { Console.WriteLine("Couldn't find slumlord!"); return; } var verified = VerifyPurchase(slumlord, item_ids); if (!verified) { Console.WriteLine($"{Name} tried to purchase house {slumlord.Guid} without the required items!"); return; } Console.WriteLine("\nInventory check passed!"); // TODO: consume items for house purchase ConsumeItemsForPurchase(item_ids); SetHouseOwner(slumlord); }
public override void Heartbeat(double currentUnixTime) { // TODO: fix bug for landblock containers w/ no heartbeat Inventory_Tick(this); foreach (var subcontainer in Inventory.Values.OfType <Container>()) { subcontainer.Inventory_Tick(this); } // for landblock containers if (IsOpen && CurrentLandblock != null) { var viewer = CurrentLandblock.GetObject(Viewer) as Player; if (viewer == null) { Close(null); return; } var withinUseRadius = CurrentLandblock.WithinUseRadius(viewer, Guid, out var targetValid); if (!withinUseRadius) { Close(viewer); return; } } base.Heartbeat(currentUnixTime); }
/// <summary> /// Method used for handling creature untargeted spell casts /// </summary> public void CreateCreatureSpell(uint spellId) { Creature creature = CurrentLandblock.GetObject(Guid) as Creature; if (creature.IsBusy == true) { return; } else { creature.IsBusy = true; } SpellTable spellTable = DatManager.PortalDat.SpellTable; if (!spellTable.Spells.ContainsKey(spellId)) { creature.IsBusy = false; return; } SpellBase spell = spellTable.Spells[spellId]; float scale = SpellAttributes(null, spellId, out float castingDelay, out MotionCommand windUpMotion, out MotionCommand spellGesture); creature.IsBusy = false; return; }
public override void ActOnUse(ObjectGuid playerId) { Player player = CurrentLandblock.GetObject(playerId) as Player; if (player == null) { return; } ////if (playerDistanceTo >= 2500) ////{ //// var sendTooFarMsg = new GameEventDisplayStatusMessage(player.Session, StatusMessageType1.Enum_0037); //// player.Session.Network.EnqueueSend(sendTooFarMsg, sendUseDoneEvent); //// return; ////} if (!player.IsWithinUseRadiusOf(this)) { player.DoMoveTo(this); } else { if (AllowedActivator == null) { Activate(playerId); } var sendUseDoneEvent = new GameEventUseDone(player.Session); player.Session.Network.EnqueueSend(sendUseDoneEvent); } }
public override void Heartbeat(double currentUnixTime) { // added where clause foreach (var wo in Inventory.Values.Where(i => i.EnchantmentManager.HasEnchantments)) { // FIXME: wo.NextHeartbeatTime is double.MaxValue here //if (wo.NextHeartbeatTime <= currentUnixTime) //wo.Heartbeat(currentUnixTime); // just go by parent heartbeats, only for enchantments? wo.EnchantmentManager.HeartBeat(HeartbeatInterval); } // for landblock containers if (IsOpen && CurrentLandblock != null) { var viewer = CurrentLandblock.GetObject(Viewer) as Player; if (viewer == null) { Close(null); return; } var withinUseRadius = CurrentLandblock.WithinUseRadius(viewer, Guid, out var targetValid); if (!withinUseRadius) { Close(viewer); return; } } base.Heartbeat(currentUnixTime); }
// ========================================= // Game Action Handlers // ========================================= /// <summary> /// Fired from the client / client is sending us a Buy transaction to vendor /// </summary> /// <param name="vendorId"></param> /// <param name="items"></param> public void HandleActionBuyItem(ObjectGuid vendorId, List <ItemProfile> items) { var vendor = (CurrentLandblock.GetObject(vendorId) as Vendor); if (vendor != null) { vendor.BuyValidateTransaction(vendorId, items, this); } }
public override void ActOnUse(ObjectGuid playerId) { Player player = CurrentLandblock.GetObject(playerId) as Player; if (player == null) { return; } ////if (playerDistanceTo >= 2500) ////{ //// var sendTooFarMsg = new GameEventDisplayStatusMessage(player.Session, StatusMessageType1.Enum_0037); //// player.Session.Network.EnqueueSend(sendTooFarMsg, sendUseDoneEvent); //// return; ////} if (!player.IsWithinUseRadiusOf(this)) { player.DoMoveTo(this); } else { ActionChain checkDoorChain = new ActionChain(); checkDoorChain.AddAction(this, () => { if (!IsLocked ?? false) { if (!IsOpen ?? false) { Open(playerId); } else { Close(playerId); } // Create Door auto close timer ActionChain autoCloseTimer = new ActionChain(); autoCloseTimer.AddDelaySeconds(ResetInterval); autoCloseTimer.AddAction(this, () => Reset()); autoCloseTimer.EnqueueChain(); } else { CurrentLandblock.EnqueueBroadcastSound(this, Sound.OpenFailDueToLock); } var sendUseDoneEvent = new GameEventUseDone(player.Session); player.Session.Network.EnqueueSend(sendUseDoneEvent); }); checkDoorChain.EnqueueChain(); } }
/// <summary> /// Item Magic /// </summary> /// <param name="target"></param> /// <param name="spell"></param> /// <param name="spellStatMod"></param> /// <param name="castByItem"></param> protected string ItemMagic(WorldObject target, SpellBase spell, Database.Models.World.Spell spellStatMod, bool castByItem = false) { Player player = CurrentLandblock.GetObject(Guid) as Player; if ((spell.MetaSpellType == SpellType.PortalLink) || (spell.MetaSpellType == SpellType.PortalRecall) || (spell.MetaSpellType == SpellType.PortalSending) || (spell.MetaSpellType == SpellType.PortalSummon)) { switch (spell.MetaSpellId) { case 2645: // Portal Recall if (!player.TeleToPosition(PositionType.LastPortal)) { // You must link to a portal to recall it! player.Session.Network.EnqueueSend(new GameEventWeenieError(player.Session, WeenieError.YouMustLinkToPortalToRecall)); } break; case 1635: // Lifestone Recall if (!player.TeleToPosition(PositionType.LinkedLifestone)) { // You must link to a lifestone to recall it! player.Session.Network.EnqueueSend(new GameEventWeenieError(player.Session, WeenieError.YouMustLinkToLifestoneToRecall)); } break; case 48: // Primary Portal Recall if (!player.TeleToPosition(PositionType.LinkedPortalOne)) { // You must link to a portal to recall it! player.Session.Network.EnqueueSend(new GameEventWeenieError(player.Session, WeenieError.YouMustLinkToPortalToRecall)); } break; case 2647: // Secondary Portal Recall if (!player.TeleToPosition(PositionType.LinkedPortalTwo)) { // You must link to a portal to recall it! player.Session.Network.EnqueueSend(new GameEventWeenieError(player.Session, WeenieError.YouMustLinkToPortalToRecall)); } break; default: break; } } else if (spell.MetaSpellType == SpellType.Enchantment) { return(CreateEnchantment(target, spell, spellStatMod, castByItem)); } return(""); }
/// <summary> /// Joins a chess game /// </summary> /// <param name="boardGuid">The guid of the chess board</param> public void HandleActionChessJoin(uint boardGuid) { var chessboard = CurrentLandblock.GetObject(boardGuid) as Game; if (chessboard == null) { return; } chessboard.ActOnUse(this); }
public override void ActOnUse(ObjectGuid playerId) { Player player = CurrentLandblock.GetObject(playerId) as Player; if (player == null) { return; } ////if (playerDistanceTo >= 2500) ////{ //// var sendTooFarMsg = new GameEventDisplayStatusMessage(player.Session, StatusMessageType1.Enum_0037); //// player.Session.Network.EnqueueSend(sendTooFarMsg, sendUseDoneEvent); //// return; ////} if (!player.IsWithinUseRadiusOf(this) && Viewer != player.Guid.Full) { player.DoMoveTo(this); } else { if (!(IsLocked ?? false)) { if (!(IsOpen ?? false)) { var turnToMotion = new UniversalMotion(MotionStance.Standing, Location, Guid); turnToMotion.MovementTypes = MovementTypes.TurnToObject; ActionChain turnToTimer = new ActionChain(); turnToTimer.AddAction(this, () => player.CurrentLandblock.EnqueueBroadcastMotion(player, turnToMotion));; turnToTimer.AddDelaySeconds(1); turnToTimer.AddAction(this, () => Open(player)); turnToTimer.EnqueueChain(); return; } else { if (Viewer == player.Guid.Full) { Close(player); } // else error msg? } } else { CurrentLandblock.EnqueueBroadcastSound(this, Sound.OpenFailDueToLock); } player.SendUseDoneEvent(); } }
/// <summary> /// Client Calls this when Sell is clicked. /// </summary> public void HandleActionSellItem(List <ItemProfile> itemprofiles, ObjectGuid vendorId) { var purchaselist = new List <WorldObject>(); foreach (ItemProfile profile in itemprofiles) { // check packs of item. WorldObject item = GetInventoryItem(profile.Guid); if (item == null) { // check to see if this item is wielded item = GetWieldedItem(profile.Guid); if (item != null) { TryDequipObject(item.Guid); Session.Network.EnqueueSend( new GameMessageSound(Guid, Sound.WieldObject, (float)1.0), new GameMessageObjDescEvent(this), new GameMessagePublicUpdateInstanceID(item, PropertyInstanceId.Wielder, new ObjectGuid(0)), new GameMessagePublicUpdatePropertyInt(item, PropertyInt.CurrentWieldedLocation, 0)); } } else { // remove item from inventory. TryRemoveFromInventory(profile.Guid); } //Session.Network.EnqueueSend(new GameMessagePrivateUpdateInstanceId(profile, PropertyInstanceId.Container, new ObjectGuid(0).Full)); item.SetPropertiesForVendor(); // clean up the shard database. throw new NotImplementedException(); // todo fix for EF //DatabaseManager.Shard.DeleteObject(item.SnapShotOfAceObject(), null); Session.Network.EnqueueSend(new GameMessageDeleteObject(item)); purchaselist.Add(item); } var vendor = CurrentLandblock.GetObject(vendorId) as Vendor; if (vendor != null) { vendor.SellItemsValidateTransaction(this, purchaselist); } }
public void ExamineObject(ObjectGuid examinationId) { // TODO: Throttle this request?. The live servers did this, likely for a very good reason, so we should, too. if (examinationId.Full == 0) { // Deselect the formerly selected Target // selectedTarget = ObjectGuid.Invalid; RequestedAppraisalTarget = null; CurrentAppraisalTarget = null; return; } // The object can be in two spots... on the player or on the landblock // First check the player // search packs WorldObject wo = GetInventoryItem(examinationId); // search wielded items if (wo == null) { wo = GetWieldedItem(examinationId); } // search interactive objects if (wo == null) { if (interactiveWorldObjects.ContainsKey(examinationId)) { wo = interactiveWorldObjects[examinationId]; } } // if local, examine it if (wo != null) { wo.Examine(Session); } else { // examine item on landblock wo = CurrentLandblock.GetObject(examinationId); if (wo != null) { wo.Examine(Session); } } RequestedAppraisalTarget = examinationId.Full; CurrentAppraisalTarget = examinationId.Full; }
// =============================== // Game Action Handlers - Use Item // =============================== // These are raised by client actions public void HandleActionUseWithTarget(ObjectGuid sourceObjectId, ObjectGuid targetObjectId) { StopExistingMoveToChains(); new ActionChain(this, () => { var invSource = GetInventoryItem(sourceObjectId); var invTarget = GetInventoryItem(targetObjectId); var worldTarget = (invTarget == null) ? CurrentLandblock.GetObject(targetObjectId) : null; if (invTarget != null) { // inventory on inventory, we can do this now RecipeManager.UseObjectOnTarget(this, invSource, invTarget); } else if (invSource.WeenieType == WeenieType.Healer) { if (!(worldTarget is Player)) { return; } var healer = invSource as Healer; healer.HandleActionUseOnTarget(this, worldTarget as Player); } else if (invSource.WeenieType == WeenieType.Key) { var key = invSource as Key; key.HandleActionUseOnTarget(this, worldTarget); } else if (invSource.WeenieType == WeenieType.Lockpick && worldTarget is Lock) { var lp = invSource as Lockpick; lp.HandleActionUseOnTarget(this, worldTarget); } else if (targetObjectId == Guid) { // using something on ourselves RecipeManager.UseObjectOnTarget(this, invSource, this); } else { RecipeManager.UseObjectOnTarget(this, invSource, worldTarget); } }).EnqueueChain(); }
public void ReadBookPage(ObjectGuid bookId, uint pageNum) { // TODO: Do we want to throttle this request, like appraisals? // The object can be in two spots... on the player or on the landblock // First check the player WorldObject wo = GetInventoryItem(bookId); // book is in the player's inventory... if (wo != null) { wo.ReadBookPage(Session, pageNum); } else { CurrentLandblock.GetObject(bookId).ReadBookPage(Session, pageNum); } }
public void HandleActionTargetedMeleeAttack(ObjectGuid guid, uint attackHeight, float powerLevel) { /*Console.WriteLine("HandleActionTargetedMeleeAttack"); * Console.WriteLine("Target ID: " + guid.Full.ToString("X8")); * Console.WriteLine("Attack height: " + attackHeight); * Console.WriteLine("Power level: " + powerLevel);*/ // sanity check powerLevel = Math.Clamp(powerLevel, 0.0f, 1.0f); AttackHeight = (AttackHeight)attackHeight; PowerLevel = powerLevel; // get world object of target guid var target = CurrentLandblock.GetObject(guid); if (target == null) { log.Warn("Unknown target guid " + guid.Full.ToString("X8")); return; } if (MeleeTarget == null) { MeleeTarget = target; } else { return; } // get distance from target var dist = GetDistance(target); // get angle to target var angle = GetAngle(target); //Console.WriteLine("Dist: " + dist); //Console.WriteLine("Angle: " + angle); // turn / moveto if required Rotate(target); MoveTo(target); // do melee attack Attack(target); }
public virtual void Reset() { var player = CurrentLandblock.GetObject(Viewer) as Player; if (IsOpen) { Close(player); } //if (IsGenerator) //{ // ResetGenerator(); // if (InitCreate > 0) // Generator_Regeneration(); //} ResetMessagePending = false; }
/// <summary> /// Fired when Client clicks on the Vendor World Object /// </summary> /// <param name="playerId"></param> public override void ActOnUse(ObjectGuid playerId) { Player player = CurrentLandblock.GetObject(playerId) as Player; if (player == null) { return; } if (!player.IsWithinUseRadiusOf(this)) { player.DoMoveTo(this); } else { LoadInventory(); ApproachVendor(player); } }
/// <summary> /// Learns spells in bulk, without notification, filtered by school and level /// </summary> public void LearnSpellsInBulk(uint magicSchool, uint spellLevel) { var spells = DatManager.PortalDat.SpellTable.Spells; Player player = CurrentLandblock.GetObject(Guid) as Player; if (Enum.IsDefined(typeof(SpellLevel), (int)WorldObject.CalculateSpellLevel(spellLevel))) { foreach (var spell in spells) { if ((magicSchool == (uint)spell.Value.School) & ((uint)WorldObject.CalculateSpellLevel(spellLevel) == spell.Value.Power)) { if (Enum.IsDefined(typeof(Network.Enum.Spell), spell.Key)) { player.LearnSpellWithNetworking((uint)spell.Key, false); } } } } }
// Called by the Landblock for books that are WorldObjects (some notes pinned to the ground, statues, pedestals and tips in training academy, etc public override void ActOnUse(ObjectGuid playerId) { Player player = CurrentLandblock.GetObject(playerId) as Player; if (player == null) { return; } // Make sure player is within the use radius of the item. if (!player.IsWithinUseRadiusOf(this)) { player.DoMoveTo(this); } else { BookUseHandler(player.Session); } }
/// <summary> /// Handles player targeted casting message /// </summary> public void HandleActionCastTargetedSpell(ObjectGuid guidTarget, uint spellId) { Player player = CurrentLandblock.GetObject(Guid) as Player; WorldObject target = CurrentLandblock.GetObject(guidTarget) as WorldObject; TargetCategory targetCategory = TargetCategory.WorldObject; if (guidTarget == Guid) { targetCategory = TargetCategory.Self; } if (target == null) { target = GetWieldedItem(guidTarget); targetCategory = TargetCategory.Wielded; } if (target == null) { target = GetInventoryItem(guidTarget); targetCategory = TargetCategory.Inventory; } if (target == null) { player.Session.Network.EnqueueSend(new GameEventUseDone(player.Session, errorType: WeenieError.TargetNotAcquired)); targetCategory = TargetCategory.UnDef; return; } if (targetCategory != TargetCategory.WorldObject) { CreatePlayerSpell(guidTarget, spellId); } else { // turn if required var rotateTime = Rotate(target) - 0.25f; var actionChain = new ActionChain(); actionChain.AddDelaySeconds(rotateTime); actionChain.AddAction(this, () => CreatePlayerSpell(guidTarget, spellId)); actionChain.EnqueueChain(); } }
/*public AceObject SnapShotOfAceObject(bool clearDirtyFlags = false) * { * AceObject snapshot = (AceObject)AceObject.Clone(); * if (clearDirtyFlags) * AceObject.ClearDirtyFlags(); * return snapshot; * }*/ public virtual void ActOnUse(ObjectGuid playerId) { // Do Nothing by default if (CurrentLandblock != null) { Player player = CurrentLandblock.GetObject(playerId) as Player; if (player == null) { return; } #if DEBUG var errorMessage = new GameMessageSystemChat($"Default HandleActionOnUse reached, this object ({Name}) not programmed yet.", ChatMessageType.System); player.Session.Network.EnqueueSend(errorMessage); #endif var sendUseDoneEvent = new GameEventUseDone(player.Session); player.Session.Network.EnqueueSend(sendUseDoneEvent); } }
public void HandleActionQueryHealth(ObjectGuid queryId) { if (queryId.Full == 0) { // Deselect the formerly selected Target selectedTarget = ObjectGuid.Invalid; HealthQueryTarget = null; return; } // Remember the selected Target selectedTarget = queryId; HealthQueryTarget = queryId.Full; var obj = CurrentLandblock.GetObject(queryId); if (obj != null) { obj.QueryHealth(Session); } }
public override void ActOnUse(ObjectGuid playerId) { var player = CurrentLandblock.GetObject(playerId) as Player; if (player == null) { return; } if (!player.IsWithinUseRadiusOf(this)) { player.DoMoveTo(this); } else { ActionChain sancTimer = new ActionChain(); sancTimer.AddAction(player, () => { CurrentLandblock.EnqueueBroadcastMotion(player, sanctuary); CurrentLandblock.EnqueueBroadcastSound(player, Sound.LifestoneOn, 1); }); sancTimer.AddDelaySeconds(DatManager.PortalDat.ReadFromDat <MotionTable>(player.MotionTableId).GetAnimationLength(MotionCommand.Sanctuary)); sancTimer.AddAction(player, () => { if (player.IsWithinUseRadiusOf(this)) { player.Session.Network.EnqueueSend(new GameMessageSystemChat(GetProperty(PropertyString.UseMessage), ChatMessageType.Magic)); player.Sanctuary = player.Location; } // Unsure if there was a fail message... //else //{ // var serverMessage = "You wandered too far to attune with the Lifestone!"; // player.Session.Network.EnqueueSend(new GameMessageSystemChat(serverMessage, ChatMessageType.Magic)); //} player.SendUseDoneEvent(); }); sancTimer.EnqueueChain(); } }
/// <summary> /// This is the OnUse method. This is just an initial implemention. I have put in the turn to action at this point. /// If we are out of use radius, move to the object. Once in range, let's turn the creature toward us and get started. /// Note - we may need to make an NPC class vs monster as using a monster does not make them turn towrad you as I recall. Og II /// Also, once we are reading in the emotes table by weenie - this will automatically customize the behavior for creatures. /// </summary> /// <param name="playerId">Identity of the player we are interacting with</param> public override void ActOnUse(ObjectGuid playerId) { Player player = CurrentLandblock.GetObject(playerId) as Player; if (player == null) { return; } if (!player.IsWithinUseRadiusOf(this)) { player.DoMoveTo(this); } else { OnAutonomousMove(player.Location, this.Sequences, MovementTypes.TurnToObject, playerId); GameEventUseDone sendUseDoneEvent = new GameEventUseDone(player.Session); player.Session.Network.EnqueueSend(sendUseDoneEvent); } }
public override void ActOnUse(ObjectGuid playerId) { // All data on a lifestone is constant -- therefore we just run in context of player Player player = CurrentLandblock.GetObject(playerId) as Player; string serverMessage = null; // validate within use range, taking into account the radius of the model itself, as well SetupModel csetup = SetupModel.ReadFromDat(SetupTableId.Value); float radiusSquared = (UseRadius.Value + csetup.Radius) * (UseRadius.Value + csetup.Radius); // Run this animation... // Player Enqueue: var motionSanctuary = new UniversalMotion(MotionStance.Standing, new MotionItem(MotionCommand.Sanctuary)); var animationEvent = new GameMessageUpdateMotion(player.Guid, player.Sequences.GetCurrentSequence(Network.Sequence.SequenceType.ObjectInstance), player.Sequences, motionSanctuary); // This event was present for a pcap in the training dungeon.. Why? The sound comes with animationEvent... var soundEvent = new GameMessageSound(Guid, Sound.LifestoneOn, 1); if (player.Location.SquaredDistanceTo(Location) >= radiusSquared) { serverMessage = "You wandered too far to attune with the Lifestone!"; } else { player.SetCharacterPosition(PositionType.Sanctuary, player.Location); // create the outbound server message serverMessage = "You have attuned your spirit to this Lifestone. You will resurrect here after you die."; player.HandleActionMotion(motionSanctuary); player.Session.Network.EnqueueSend(soundEvent); } var lifestoneBindMessage = new GameMessageSystemChat(serverMessage, ChatMessageType.Magic); // always send useDone event var sendUseDoneEvent = new GameEventUseDone(player.Session); player.Session.Network.EnqueueSend(lifestoneBindMessage, sendUseDoneEvent); }
/// <summary> /// Called by network packet handler 0xA - GameActionTargetedMissileAttack /// </summary> /// <param name="guid">The target guid</param> /// <param name="attackHeight">The attack height 1-3</param> /// <param name="accuracyLevel">The 0-1 accuracy bar level</param> public void HandleActionTargetedMissileAttack(ObjectGuid guid, uint attackHeight, float accuracyLevel) { // sanity check accuracyLevel = Math.Clamp(accuracyLevel, 0.0f, 1.0f); if (GetEquippedAmmo() == null) { return; } AttackHeight = (AttackHeight)attackHeight; AccuracyLevel = accuracyLevel; // get world object of target guid var target = CurrentLandblock.GetObject(guid); if (target == null) { log.Warn("Unknown target guid " + guid.Full.ToString("X8")); return; } if (MissileTarget == null) { MissileTarget = target; } else { return; } // turn if required var rotateTime = Rotate(target); var actionChain = new ActionChain(); actionChain.AddDelaySeconds(rotateTime); // do missile attack actionChain.AddAction(this, () => LaunchMissile(target)); actionChain.EnqueueChain(); }