/// <summary> /// This is raised by Player.HandleActionUseItem, and is wrapped in ActionChain.<para /> /// The actor of the ActionChain is the item being used.<para /> /// The item does not exist in the players possession.<para /> /// If the item was outside of range, the player will have been commanded to move using DoMoveTo before ActOnUse is called.<para /> /// When this is called, it should be assumed that the player is within range. /// </summary> public override void ActOnUse(Player player) { 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(); }
public override void HandleActionOnUse(ObjectGuid playerId) { ActionChain chain = new ActionChain(); CurrentLandblock.ChainOnObject(chain, playerId, (WorldObject wo) => { Player player = wo 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) { if (!IsOpen) { 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(); } }); chain.EnqueueChain(); }
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(); } }
public void TakeDamage(WorldObject source, DamageType damageType, float _amount, BodyPart bodyPart, bool crit = false) { if (Invincible ?? false) { return; } var amount = (uint)Math.Round(_amount); var percent = (float)amount / Health.MaxValue; // update health Health.Current = (uint)Math.Max(0, (int)Health.Current - amount); if (Health.Current == 0) { HandleActionDie(); return; } var damageLocation = (DamageLocation)BodyParts.Indices[bodyPart]; // send network messages Session.Network.EnqueueSend(new GameMessagePrivateUpdateAttribute2ndLevel(this, Vital.Health, Health.Current)); var creature = source as Creature; var hotspot = source as Hotspot; if (creature != null) { var hitSound = new GameMessageSound(Guid, GetHitSound(source, bodyPart), 1.0f); var splatter = new GameMessageScript(Guid, (PlayScript)Enum.Parse(typeof(PlayScript), "Splatter" + GetSplatterHeight() + creature.GetSplatterDir(this))); var text = new GameEventDefenderNotification(Session, creature.Name, damageType, percent, amount, damageLocation, crit, AttackConditions.None); Session.Network.EnqueueSend(text, hitSound, splatter); } else if (hotspot != null) { if (!string.IsNullOrWhiteSpace(hotspot.ActivationTalkString)) { Session.Network.EnqueueSend(new GameMessageSystemChat(hotspot.ActivationTalkString.Replace("%i", amount.ToString()), ChatMessageType.Craft)); } if (!(hotspot.Visibility ?? false)) { CurrentLandblock.EnqueueBroadcastSound(hotspot, Sound.TriggerActivated); } } if (percent >= 0.1f) { var wound = new GameMessageSound(Guid, Sound.Wound1, 1.0f); Session.Network.EnqueueSend(wound); } }
//private static readonly MotionState motionStateOpen = new UniversalMotion(MotionStance.Standing, new MotionItem(MotionCommand.On)); //private static readonly MotionState motionStateClosed = new UniversalMotion(MotionStance.Standing, new MotionItem(MotionCommand.Off)); /// <summary> /// This is raised by Player.HandleActionUseItem, and is wrapped in ActionChain.<para /> /// The actor of the ActionChain is the item being used.<para /> /// The item does not exist in the players possession.<para /> /// If the item was outside of range, the player will have been commanded to move using DoMoveTo before ActOnUse is called.<para /> /// When this is called, it should be assumed that the player is within range. /// </summary> public override void ActOnUse(WorldObject worldObject) { if (worldObject is Player) { var player = worldObject as Player; ////if (playerDistanceTo >= 2500) ////{ //// var sendTooFarMsg = new GameEventDisplayStatusMessage(player.Session, StatusMessageType1.Enum_0037); //// player.Session.Network.EnqueueSend(sendTooFarMsg, sendUseDoneEvent); //// return; ////} 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; } if (Viewer == player.Guid.Full) { Close(player); } // else error msg? } else { player.Session.Network.EnqueueSend(new GameEventCommunicationTransientString(player.Session, $"The {Name} is locked!")); CurrentLandblock?.EnqueueBroadcastSound(this, Sound.OpenFailDueToLock); } player.SendUseDoneEvent(); } }
/// <summary> /// Used for unlocking a door via a key /// </summary> public UnlockDoorResults UnlockDoor(string keyCode) { if (IsOpen ?? false) { return(UnlockDoorResults.DoorOpen); } if (keyCode == LockCode) { if (!IsLocked ?? false) { return(UnlockDoorResults.AlreadyUnlocked); } IsLocked = false; CurrentLandblock.EnqueueBroadcast(Location, Landblock.MaxObjectRange, new GameMessagePublicUpdatePropertyBool(Sequences, Guid, PropertyBool.Locked, IsLocked ?? false)); CurrentLandblock.EnqueueBroadcastSound(this, Sound.LockSuccess); return(UnlockDoorResults.UnlockSuccess); } return(UnlockDoorResults.IncorrectKey); }
/// <summary> /// Used for unlocking a door via lockpick, so contains a skill check /// player.Skills[Skill.Lockpick].ActiveValue should be sent for the skill check /// </summary> public UnlockDoorResults UnlockDoor(uint playerLockpickSkillLvl) { if (ResistLockpick == 0) { return(UnlockDoorResults.CannotBePicked); } if (playerLockpickSkillLvl >= ResistLockpick) { if (!IsLocked ?? false) { return(UnlockDoorResults.AlreadyUnlocked); } IsLocked = false; CurrentLandblock.EnqueueBroadcast(Location, Landblock.MaxObjectRange, new GameMessagePublicUpdatePropertyBool(Sequences, Guid, PropertyBool.Locked, IsLocked ?? false)); CurrentLandblock.EnqueueBroadcastSound(this, Sound.LockSuccess); return(UnlockDoorResults.UnlockSuccess); } return(UnlockDoorResults.PickLockFailed); }
/// <summary> /// Method used for handling player targeted spell casts /// </summary> public void CreatePlayerSpell(ObjectGuid guidTarget, uint spellId) { Player player = CurrentLandblock.GetObject(Guid) as Player; WorldObject target = CurrentLandblock.GetObject(guidTarget); TargetCategory targetCategory = TargetCategory.WorldObject; 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; } SpellTable spellTable = DatManager.PortalDat.SpellTable; if (!spellTable.Spells.ContainsKey(spellId)) { player.Session.Network.EnqueueSend(new GameEventUseDone(player.Session, errorType: WeenieError.MagicInvalidSpellType)); return; } SpellBase spell = spellTable.Spells[spellId]; if (IsInvalidTarget(spell, target)) { player.Session.Network.EnqueueSend(new GameEventCommunicationTransientString(player.Session, $"{spell.Name} cannot be cast on {target.Name}.")); player.Session.Network.EnqueueSend(new GameEventUseDone(player.Session, errorType: WeenieError.None)); return; } Database.Models.World.Spell spellStatMod = DatabaseManager.World.GetCachedSpell(spellId); if (spellStatMod == null) { player.Session.Network.EnqueueSend(new GameMessageSystemChat($"{spell.Name} spell not implemented, yet!", ChatMessageType.System)); player.Session.Network.EnqueueSend(new GameEventUseDone(player.Session, errorType: WeenieError.MagicInvalidSpellType)); return; } if (player.IsBusy == true) { player.Session.Network.EnqueueSend(new GameEventUseDone(player.Session, errorType: WeenieError.YoureTooBusy)); return; } else { player.IsBusy = true; } uint targetEffect = spell.TargetEffect; // Grab player's skill level in the spell's Magic School var magicSkill = player.GetCreatureSkill(spell.School).Current; if (targetCategory == TargetCategory.WorldObject) { if (guidTarget != Guid) { float distanceTo = Location.Distance2D(target.Location); if (distanceTo > spell.BaseRangeConstant + magicSkill * spell.BaseRangeMod) { player.Session.Network.EnqueueSend(new GameEventUseDone(player.Session, errorType: WeenieError.MagicTargetOutOfRange), new GameMessageSystemChat($"{target.Name} is out of range!", ChatMessageType.Magic)); player.IsBusy = false; return; } } } // Ensure that a harmful spell isn't being cast on a player target that doesn't have the same PK status if (target.WeenieClassId == 1 && player.PlayerKillerStatus != ACE.Entity.Enum.PlayerKillerStatus.NPK) { bool isSpellHarmful = IsSpellHarmful(spell); if (player.PlayerKillerStatus != target.PlayerKillerStatus && isSpellHarmful) { player.Session.Network.EnqueueSend(new GameEventUseDone(player.Session, errorType: WeenieError.InvalidPkStatus)); player.IsBusy = false; return; } } float scale = SpellAttributes(player.Session.Account, spellId, out float castingDelay, out MotionCommand windUpMotion, out MotionCommand spellGesture); var formula = SpellTable.GetSpellFormula(spellTable, spellId, player.Session.Account); bool spellCastSuccess = false || ((Physics.Common.Random.RollDice(0.0f, 1.0f) > (1.0f - SkillCheck.GetMagicSkillChance((int)magicSkill, (int)spell.Power))) && (magicSkill >= (int)spell.Power - 50) && (magicSkill > 0)); // Calculating mana usage #region CreatureSkill mc = player.GetCreatureSkill(Skill.ManaConversion); double z = mc.Current; double baseManaPercent = 1; if (z > spell.Power) { baseManaPercent = spell.Power / z; } double preCost; uint manaUsed; if ((int)Math.Floor(baseManaPercent) == 1) { preCost = spell.BaseMana; manaUsed = (uint)preCost; } else { preCost = spell.BaseMana * baseManaPercent; if (preCost < 1) { preCost = 1; } manaUsed = (uint)Physics.Common.Random.RollDice(1, (int)preCost); } if (spell.MetaSpellType == SpellType.Transfer) { uint vitalChange, casterVitalChange; vitalChange = (uint)(player.GetCurrentCreatureVital((PropertyAttribute2nd)spellStatMod.Source) * spellStatMod.Proportion); if (spellStatMod.TransferCap != 0) { if (vitalChange > spellStatMod.TransferCap) { vitalChange = (uint)spellStatMod.TransferCap; } } casterVitalChange = (uint)(vitalChange * (1.0f - spellStatMod.LossPercent)); vitalChange = (uint)(casterVitalChange / (1.0f - spellStatMod.LossPercent)); if (spellStatMod.Source == (int)PropertyAttribute2nd.Mana && (vitalChange + 10 + manaUsed) > player.Mana.Current) { ActionChain resourceCheckChain = new ActionChain(); resourceCheckChain.AddAction(this, () => { CurrentLandblock.EnqueueBroadcast(Location, new GameMessageScript(Guid, ACE.Entity.Enum.PlayScript.Fizzle, 0.5f)); }); resourceCheckChain.AddDelaySeconds(2.0f); resourceCheckChain.AddAction(this, () => { player.Session.Network.EnqueueSend(new GameEventUseDone(player.Session, errorType: WeenieError.YouDontHaveEnoughManaToCast)); player.IsBusy = false; }); resourceCheckChain.EnqueueChain(); return; } else if ((vitalChange + 10) > player.GetCurrentCreatureVital((PropertyAttribute2nd)spellStatMod.Source)) { ActionChain resourceCheckChain = new ActionChain(); resourceCheckChain.AddAction(this, () => { CurrentLandblock.EnqueueBroadcast(Location, new GameMessageScript(Guid, ACE.Entity.Enum.PlayScript.Fizzle, 0.5f)); }); resourceCheckChain.AddDelaySeconds(2.0f); resourceCheckChain.AddAction(this, () => player.IsBusy = false); resourceCheckChain.EnqueueChain(); return; } } else if (manaUsed > player.Mana.Current) { ActionChain resourceCheckChain = new ActionChain(); resourceCheckChain.AddAction(this, () => { CurrentLandblock.EnqueueBroadcast(Location, new GameMessageScript(Guid, ACE.Entity.Enum.PlayScript.Fizzle, 0.5f)); }); resourceCheckChain.AddDelaySeconds(2.0f); resourceCheckChain.AddAction(this, () => { player.Session.Network.EnqueueSend(new GameEventUseDone(player.Session, errorType: WeenieError.YouDontHaveEnoughManaToCast)); player.IsBusy = false; }); resourceCheckChain.EnqueueChain(); return; } else { player.UpdateVital(player.Mana, player.Mana.Current - manaUsed); } #endregion ActionChain spellChain = new ActionChain(); uint fastCast = (spell.Bitfield >> 14) & 0x1u; if (fastCast != 1) { spellChain.AddAction(this, () => { var motionWindUp = new UniversalMotion(MotionStance.Spellcasting); motionWindUp.MovementData.CurrentStyle = (ushort)((uint)MotionStance.Spellcasting & 0xFFFF); motionWindUp.MovementData.ForwardCommand = (uint)windUpMotion; motionWindUp.MovementData.ForwardSpeed = 2; DoMotion(motionWindUp); }); } spellChain.AddAction(this, () => { CurrentLandblock.EnqueueBroadcast(Location, new GameMessageCreatureMessage(SpellComponentsTable.GetSpellWords(DatManager.PortalDat.SpellComponentsTable, formula), Name, Guid.Full, ChatMessageType.Magic)); }); spellChain.AddAction(this, () => { var motionCastSpell = new UniversalMotion(MotionStance.Spellcasting); motionCastSpell.MovementData.CurrentStyle = (ushort)((uint)MotionStance.Spellcasting & 0xFFFF); motionCastSpell.MovementData.ForwardCommand = (uint)spellGesture; motionCastSpell.MovementData.ForwardSpeed = 2; DoMotion(motionCastSpell); }); if (fastCast == 1) { spellChain.AddDelaySeconds(castingDelay * 0.26f); } else { spellChain.AddDelaySeconds(castingDelay); } if (spellCastSuccess == false) { spellChain.AddAction(this, () => CurrentLandblock.EnqueueBroadcast(Location, new GameMessageScript(Guid, ACE.Entity.Enum.PlayScript.Fizzle, 0.5f))); } else { spellChain.AddAction(this, () => { bool targetDeath; string message; switch (spell.School) { case MagicSchool.WarMagic: WarMagic(target, spell, spellStatMod); break; case MagicSchool.VoidMagic: VoidMagic(target, spell, spellStatMod); break; case MagicSchool.CreatureEnchantment: if (IsSpellHarmful(spell)) { // Retrieve player's skill level in the Magic School var playerMagicSkill = player.GetCreatureSkill(spell.School).Current; // Retrieve target's Magic Defense Skill Creature creature = (Creature)target; var targetMagicDefenseSkill = creature.GetCreatureSkill(Skill.MagicDefense).Current; if (MagicDefenseCheck(playerMagicSkill, targetMagicDefenseSkill)) { CurrentLandblock.EnqueueBroadcastSound(player, Sound.ResistSpell); player.Session.Network.EnqueueSend(new GameMessageSystemChat($"{creature.Name} resists {spell.Name}", ChatMessageType.Magic)); break; } } CurrentLandblock.EnqueueBroadcast(Location, new GameMessageScript(target.Guid, (PlayScript)spell.TargetEffect, scale)); message = CreatureMagic(target, spell, spellStatMod); if (message != "") { player.Session.Network.EnqueueSend(new GameMessageSystemChat(message, ChatMessageType.Magic)); } break; case MagicSchool.LifeMagic: if (spell.MetaSpellType != SpellType.LifeProjectile) { if (IsSpellHarmful(spell)) { // Retrieve player's skill level in the Magic School var playerMagicSkill = player.GetCreatureSkill(spell.School).Current; // Retrieve target's Magic Defense Skill Creature creature = (Creature)target; var targetMagicDefenseSkill = creature.GetCreatureSkill(Skill.MagicDefense).Current; if (MagicDefenseCheck(playerMagicSkill, targetMagicDefenseSkill)) { CurrentLandblock.EnqueueBroadcastSound(player, Sound.ResistSpell); player.Session.Network.EnqueueSend(new GameMessageSystemChat($"{creature.Name} resists {spell.Name}", ChatMessageType.Magic)); break; } } } CurrentLandblock.EnqueueBroadcast(Location, new GameMessageScript(target.Guid, (PlayScript)spell.TargetEffect, scale)); targetDeath = LifeMagic(target, spell, spellStatMod, out message); if (message != null) { player.Session.Network.EnqueueSend(new GameMessageSystemChat(message, ChatMessageType.Magic)); } if (targetDeath == true) { Creature creatureTarget = (Creature)target; creatureTarget.Die(); Strings.DeathMessages.TryGetValue(DamageType.Base, out var messages); player.Session.Network.EnqueueSend(new GameMessageSystemChat(string.Format(messages[0], target.Name), ChatMessageType.Broadcast)); player.EarnXP((long)target.XpOverride); } break; case MagicSchool.ItemEnchantment: if (guidTarget == Guid) { CurrentLandblock.EnqueueBroadcast(Location, new GameMessageScript(Guid, (PlayScript)spell.CasterEffect, scale)); } else { CurrentLandblock.EnqueueBroadcast(Location, new GameMessageScript(target.Guid, (PlayScript)spell.TargetEffect, scale)); } message = ItemMagic(target, spell, spellStatMod); if (message != "") { player.Session.Network.EnqueueSend(new GameMessageSystemChat(message, ChatMessageType.Magic)); } break; default: break; } }); } spellChain.AddAction(this, () => { var motionReturnToCastStance = new UniversalMotion(MotionStance.Spellcasting); motionReturnToCastStance.MovementData.CurrentStyle = (ushort)((uint)MotionStance.Spellcasting & 0xFFFF); motionReturnToCastStance.MovementData.ForwardCommand = (uint)MotionCommand.Invalid; DoMotion(motionReturnToCastStance); }); spellChain.AddDelaySeconds(1.0f); spellChain.AddAction(this, () => { player.Session.Network.EnqueueSend(new GameEventUseDone(player.Session, errorType: WeenieError.None)); player.IsBusy = false; }); spellChain.EnqueueChain(); return; }