public static bool HandleMarry(Models.Entities.Player player, Models.Packets.Entities.InteractionPacket packet) { if (packet.TargetClientId == player.ClientId) { return(false); } if (player.Spouse != "None") { return(true); } Models.Maps.IMapObject obj; if (player.GetFromScreen(packet.TargetClientId, out obj)) { var marriageTarget = obj as Models.Entities.Player; if (marriageTarget != null) { if (marriageTarget.Spouse != "None") { return(true); } if (marriageTarget.PendingSpouse != player.ClientId) { return(true); } player.AddActionLog("Marriage", player.Name + " : " + marriageTarget.Name); marriageTarget.Spouse = player.Name; player.Spouse = marriageTarget.Name; player.ClientSocket.Send(new Models.Packets.Misc.StringPacket { Action = Enums.StringAction.Mate, Data = player.ClientId, String = marriageTarget.Name }); marriageTarget.ClientSocket.Send(new Models.Packets.Misc.StringPacket { Action = Enums.StringAction.Mate, Data = marriageTarget.ClientId, String = player.Name }); var fireworks = new Models.Packets.Misc.StringPacket { Action = Enums.StringAction.MapEffect, PositionX = player.X, PositionY = player.Y, String = "firework-2love" }; player.ClientSocket.Send(fireworks); fireworks.PositionX = marriageTarget.X; fireworks.PositionY = marriageTarget.Y; marriageTarget.ClientSocket.Send(fireworks); Collections.PlayerCollection.BroadcastFormattedMessage("MARRIAGE_CONGRATZ", player.Name, marriageTarget.Name); } } return(true); }
/// <summary> /// Handles a circular skill. /// </summary> /// <param name="attacker">The attacker.</param> /// <param name="packet">The packet.</param> /// <param name="spellPacket">The spell packet.</param> /// <param name="spellInfo">The spell info.</param> /// <param name="isMagic">Boolean determining whether the circular skill is a magic skill or not.</param> /// <returns>True if the skill was handled correct.</returns> /// <remarks>This handles all types of circular skills (Physical, Magic, Ranged.) however ranged and physical is determined from either the skill id or whether isMagic is set.</remarks> public static bool Handle(AttackableEntityController attacker, Models.Packets.Entities.InteractionPacket packet, Models.Packets.Spells.SpellPacket spellPacket, Models.Spells.SpellInfo spellInfo, bool isMagic) { spellPacket.Process = true; if (!isMagic && spellInfo.Id < 8000 && packet.TargetClientId == attacker.AttackableEntity.ClientId) { return(false); } var attackerPlayer = attacker as Models.Entities.Player; if (attackerPlayer != null) { if (DateTime.UtcNow < attackerPlayer.NextLongSkill) { attackerPlayer.SendSystemMessage("REST"); return(false); } attackerPlayer.NextLongSkill = DateTime.UtcNow.AddMilliseconds(Data.Constants.Time.LongSkillTime); } foreach (var possibleTarget in attacker.GetAllInScreen()) { if (spellPacket.Targets.Count > 8) { return(true); } var target = possibleTarget as AttackableEntityController; if (target != null) { if (!TargetValidation.Validate(attacker, target)) { continue; } if (target.ContainsStatusFlag(Enums.StatusFlag.Fly)) { continue; } if (Tools.RangeTools.GetDistanceU(attacker.MapObject.X, attacker.MapObject.Y, target.MapObject.X, target.MapObject.Y) >= 8) { continue; } bool isRanged = (spellInfo.Id == 8030 || spellInfo.Id == 10308 || spellInfo.Id == 7013 || spellInfo.Id > 10360); uint damage = isRanged ? Calculations.RangedCalculations.GetDamage(attacker.AttackableEntity, target.AttackableEntity) : isMagic? Calculations.MagicCalculations.GetDamage(attacker.AttackableEntity, target.AttackableEntity, spellInfo) : Calculations.PhysicalCalculations.GetDamage(attacker.AttackableEntity, target.AttackableEntity); Damage.Process(attacker, target, ref damage, false); if (isRanged && attackerPlayer != null) { Ranged.DecreaseArrows(attackerPlayer, 3); } if (damage > 0) { TargetFinalization.SkillFinalize(attacker, target, spellPacket, damage); } } } return(true); }
/// <summary> /// Handles the sector skills. /// </summary> /// <param name="attacker">The attacker.</param> /// <param name="packet">The packet.</param> /// <param name="spellPacket">The spell packet.</param> /// <param name="spellInfo">The spell info.</param> /// <param name="isMagic">Boolean determining whether the attack is magic or not.</param> /// <param name="isPoison">Booealning determining whether the attack is poisonous (Toxic fog.)</param> /// <returns>True if the skill was handled correctly.</returns> public static bool Handle(AttackableEntityController attacker, Models.Packets.Entities.InteractionPacket packet, Models.Packets.Spells.SpellPacket spellPacket, Models.Spells.SpellInfo spellInfo, bool isMagic, bool isPoison = false) { spellPacket.Process = true; if (packet.TargetClientId == attacker.AttackableEntity.ClientId) { return(false); } if (isPoison && Tools.RangeTools.GetDistanceU(attacker.MapObject.X, attacker.MapObject.Y, packet.X, packet.Y) >= 9) { return(false); } var attackerPlayer = attacker as Models.Entities.Player; if (attackerPlayer != null) { if (DateTime.UtcNow < attackerPlayer.NextLongSkill) { attackerPlayer.SendSystemMessage("REST"); return(false); } attackerPlayer.NextLongSkill = DateTime.UtcNow.AddMilliseconds(Data.Constants.Time.LongSkillTime); } ushort x = attacker.MapObject.X; ushort y = attacker.MapObject.Y; if (spellInfo.Id == 6001) { if (Tools.RangeTools.GetDistanceU(x, y, packet.X, packet.Y) > spellInfo.DbSpellInfo.Distance) { return(false); } x = packet.X; y = packet.Y; } var sector = new Tools.Sector(x, y, packet.X, packet.Y); sector.Arrange(spellInfo.Sector, spellInfo.DbSpellInfo.Range); foreach (var possibleTarget in attacker.GetAllInScreen()) { if (spellPacket.Targets.Count > 8) { return(true); } var target = possibleTarget as AttackableEntityController; if (target != null) { if (!TargetValidation.Validate(attacker, target)) { continue; } if (target.ContainsStatusFlag(Enums.StatusFlag.Fly)) { continue; } if (!sector.Inside(target.MapObject.X, target.MapObject.Y)) { continue; } if (isPoison && target.ContainsStatusFlag(Enums.StatusFlag.Poisoned)) { continue; } uint damage = isPoison ? (uint)target.AttackableEntity.HP / 10 : isMagic? Calculations.MagicCalculations.GetDamage(attacker.AttackableEntity, target.AttackableEntity, spellInfo) : Calculations.PhysicalCalculations.GetDamage(attacker.AttackableEntity, target.AttackableEntity); if (isPoison) { target.AttackableEntity.PoisonEffect = (spellInfo.DbSpellInfo.Power - 30000); target.AddStatusFlag(Enums.StatusFlag.Poisoned, 60000); } Damage.Process(attacker, target, ref damage, false); if (damage > 0) { TargetFinalization.SkillFinalize(attacker, target, spellPacket, damage); } } } return(true); }
/// <summary> /// Handles the thread. /// </summary> public static void Handle() { Collections.PlayerCollection .ForEach(player => { try { #region Stamina player.UpdateStamina(); #endregion #region Poison if (player.ContainsStatusFlag(Enums.StatusFlag.Poisoned)) { if (DateTime.UtcNow >= player.NextPoison) { player.NextPoison = DateTime.UtcNow.AddMilliseconds(3000); if (player.PoisonEffect > 0) { uint damage = (uint)Math.Max(1, (player.HP / 100) * player.PoisonEffect); if (player.HP > damage) { Helpers.Packets.Interaction.Battle.Damage.Hit(null, player, damage); var poisonPacket = new Models.Packets.Entities.InteractionPacket { Action = Enums.InteractionAction.Attack, ClientId = player.ClientId, TargetClientId = player.ClientId, X = player.X, Y = player.Y, Data = damage }; player.UpdateScreen(false, poisonPacket); player.ClientSocket.Send(poisonPacket); } else { player.PoisonEffect = 0; player.RemoveStatusFlag(Enums.StatusFlag.Poisoned); } } else { player.RemoveStatusFlag(Enums.StatusFlag.Poisoned); } } } #endregion #region PKPoints if (player.PKPoints > 0) { if (DateTime.UtcNow > player.NextPKPointRemoval) { player.NextPKPointRemoval = DateTime.UtcNow.AddMilliseconds(Data.Constants.Time.PKPointsRemovalTime); player.PKPoints--; } } #endregion } catch { player.ClientSocket.Disconnect("Thread Failure."); } }); }
/// <summary> /// Handling buffs and curse skills /// </summary> /// <param name="attacker">The attacker.</param> /// <param name="target">The target.</param> /// <param name="packet">The packet.</param> /// <param name="spellPacket">The spell packet.</param> /// <param name="spellInfo">The spell info.</param> /// <param name="curse">Boolean determining whether it should handle the skill as a curse.</param> /// <param name="disspell">Boolean determining whether it should handle the skill as a disspelling skill.</param> /// <returns>True if the skill was handled correct.</returns> public static bool Handle(AttackableEntityController attacker, AttackableEntityController target, Models.Packets.Entities.InteractionPacket packet, Models.Packets.Spells.SpellPacket spellPacket, Models.Spells.SpellInfo spellInfo, bool curse = false, bool disspell = false) { if (target == null) { return(false); } var targetPlayer = target as Models.Entities.Player; if (targetPlayer == null) { return(false); } if (!attacker.AttackableEntity.Alive) { return(false); } var attackerPlayer = attacker as Models.Entities.Player; if (attackerPlayer != null) { if (DateTime.UtcNow < attackerPlayer.NextSmallLongSkill) { attackerPlayer.SendSystemMessage("REST"); return(false); } attackerPlayer.NextSmallLongSkill = DateTime.UtcNow.AddMilliseconds(Data.Constants.Time.SmallLongSkillTime); } if (!targetPlayer.LoggedIn) { return(false); } uint damage = 0; if (curse) { if (!TargetValidation.Validate(attacker, target)) { return(false); } targetPlayer.AddStatusFlag(Enums.StatusFlag.NoPotion, (5000 * (spellInfo.Level + 1))); } else if (disspell) { targetPlayer.RemoveStatusFlag(Enums.StatusFlag.Fly); damage = (uint)Math.Max(1, (targetPlayer.HP / 10)); if (damage > 0) { Damage.Process(attacker, target, ref damage, false); } } else { var duration = spellInfo.DbSpellInfo.StepSecs * 1000; switch (spellInfo.Id) { case 1075: targetPlayer.AddStatusFlag(Enums.StatusFlag.PartiallyInvisible, duration); break; case 1085: targetPlayer.AddStatusFlag(Enums.StatusFlag.StarOfAccuracy, duration); break; case 1090: targetPlayer.AddStatusFlag(Enums.StatusFlag.Shield, duration); break; case 1095: targetPlayer.AddStatusFlag(Enums.StatusFlag.Stigma, duration); break; } } var maxExp = (int)(Math.Max(25, (int)targetPlayer.Level) / 2); uint newExperience = (uint)Drivers.Repositories.Safe.Random.Next(maxExp / 2, maxExp); var skill = targetPlayer.Spells.GetOrCreateSkill(spellInfo.Id); if (skill != null) { skill.Raise(newExperience); } TargetFinalization.SkillFinalize(attackerPlayer, targetPlayer, spellPacket, damage); return(true); }
/// <summary> /// Handles single skills. /// </summary> /// <param name="attacker">The attacker.</param> /// <param name="target">The target.</param> /// <param name="packet">The packet.</param> /// <param name="spellPacket">The spell packet.</param> /// <param name="spellInfo">The spell info.</param> /// <param name="isMagic">Boolean determining whether the single attack is magic.</param> /// <param name="isRanged">Boolean determining whether the single attack is ranged.</param> /// <returns>True if the skill was handled correctly.</returns> /// <remarks>If both isMagic and isRanged is set to false then it's assumed as a physical skill.</remarks> public static bool Handle(AttackableEntityController attacker, AttackableEntityController target, Models.Packets.Entities.InteractionPacket packet, Models.Packets.Spells.SpellPacket spellPacket, Models.Spells.SpellInfo spellInfo, bool isMagic, bool isRanged = false) { if (target == null) { return(false); } if (attacker.AttackableEntity.ClientId == target.AttackableEntity.ClientId) { return(false); } if (!TargetValidation.Validate(attacker, target)) { return(false); } var attackerPlayer = attacker as Models.Entities.Player; if (isRanged) { if (attackerPlayer != null) { if (!Ranged.ProcessPlayer(attackerPlayer, packet, 1)) { return(false); } } Ranged.DecreaseArrows(attackerPlayer, 1); } uint damage = isRanged ? Calculations.RangedCalculations.GetDamage(attacker.AttackableEntity, target.AttackableEntity) : isMagic? Calculations.MagicCalculations.GetDamage(attacker.AttackableEntity, target.AttackableEntity, spellInfo) : Calculations.PhysicalCalculations.GetDamage(attacker.AttackableEntity, target.AttackableEntity); if (!isMagic) { damage = (uint)Math.Max(1, (int)(((double)damage) * (1.1 + (0.1 * spellInfo.Level)))); if (spellInfo.Id == 1290 && damage > 0 && !isRanged) { double damagePercentage = (double)((damage / 100) * 26.6); damage += (uint)(damagePercentage * spellInfo.Level); } if (spellInfo.Id == 6000 && damage > 0 && !isRanged) { damage = (uint)((damage / 100) * (spellInfo.DbSpellInfo.Power - 30000)); } } Damage.Process(attacker, target, ref damage, true); if (damage > 0) { TargetFinalization.SkillFinalize(attacker, target, spellPacket, damage); return(true); } return(false); }
/// <summary> /// Validates a magic attack. /// </summary> /// <param name="attacker">The attacker.</param> /// <param name="packet">The packet.</param> /// <param name="target">The target.</param> /// <returns>The status of the validation. (0 = success.)</returns> private static int ValidateMagicAttack(AttackableEntityController attacker, Models.Packets.Entities.InteractionPacket packet, out AttackableEntityController target) { target = null; if (packet == null) { return(1); } if (!attacker.AttackableEntity.Alive) { return(2); } if (!Tools.RangeTools.ValidDistance(attacker.MapObject.X, attacker.MapObject.Y, packet.X, packet.Y)) { return(3); } Models.Maps.IMapObject targetMapObject = null; bool requiresTarget = false; if (packet.TargetClientId > 0) { if (!attacker.GetFromScreen(packet.TargetClientId, out targetMapObject) && packet.TargetClientId != attacker.AttackableEntity.ClientId) { return(4); } else { requiresTarget = packet.TargetClientId != attacker.AttackableEntity.ClientId; } } target = targetMapObject as AttackableEntityController; if (target != null) { var targetPlayer = target as Player; if (targetPlayer != null) { if (!targetPlayer.LoggedIn) { return(5); } if (DateTime.UtcNow < targetPlayer.LoginProtectionEndTime) { return(5); } if (DateTime.UtcNow < targetPlayer.ReviveProtectionEndTime) { return(6); } } if (!Tools.RangeTools.ValidDistance(attacker.MapObject.X, attacker.MapObject.Y, target.MapObject.X, target.MapObject.Y)) { return(7); } if (!target.AttackableEntity.Alive && packet.MagicType != 1100 && packet.MagicType != 1050) { return(8); } } else if (requiresTarget) { return(10); } return(0); }
/// <summary> /// Checks whether the player can use auto attack or not. /// </summary> /// <param name="packet">The packet.</param> /// <returns>True if the player can use auto attack.</returns> public bool CanUseAutoAttack(Models.Packets.Entities.InteractionPacket packet) { return(Player.AttackPacket != null && Player.AttackPacket.Packetstamp == packet.Packetstamp); }
/// <summary> /// Handling a base magic attack. /// </summary> /// <param name="attacker">The attacker.</param> /// <param name="packet">The packet.</param> public static void Handle(Controllers.Entities.AttackableEntityController attacker, Models.Packets.Entities.InteractionPacket packet) { if (packet == null) { return; } Controllers.Entities.AttackableEntityController target; var canAttack = ValidateMagicAttack(attacker, packet, out target); if (canAttack == 0) { var spellPacket = new Models.Packets.Spells.SpellPacket { ClientId = attacker.AttackableEntity.ClientId, SpellId = packet.MagicType, SpellX = packet.X, SpellY = packet.Y, SpellLevel = 0 }; Models.Spells.SpellInfo spellInfo = null; var player = attacker as Player; var monster = attacker as Monster; if (player != null) { if (!ProcessPlayer(player, packet, spellPacket, out spellInfo)) { return; } // TODO: AI BOT ... } else if (monster != null) { if (Collections.SpellInfoCollection.ContainsSpell(packet.MagicType)) { spellInfo = Collections.SpellInfoCollection.GetHighestSpell(packet.MagicType); } } if (spellInfo != null) { if (packet.ClientId != attacker.AttackableEntity.ClientId && target != null) { spellPacket.SpellX = target.MapObject.X; spellPacket.SpellY = target.MapObject.Y; } if (spellInfo.DbSpellInfo.UseEP > 0) { if (player != null) { // TODO: IF NOT AI BOT if (spellInfo.Id != 7001 && player.Stamina < spellInfo.DbSpellInfo.UseEP || spellInfo.Id == 7001 && player.ContainsStatusFlag(Enums.StatusFlag.Riding) && player.Stamina < spellInfo.DbSpellInfo.UseEP) { return; } } } if (spellInfo.DbSpellInfo.UseMP > 0) { if (monster != null) { if (monster.MP < spellInfo.DbSpellInfo.UseMP && !monster.IsGuard) { return; } } else if (attacker.AttackableEntity.MP < spellInfo.DbSpellInfo.UseMP) { return; } } if (attacker.MapObject.Map == null) { return; } bool success = false; switch (packet.MagicType) { #region Line Skills case 1045: case 1046: case 11005: case 11000: success = Skills.LineSkills.Handle(attacker, packet, spellPacket, spellInfo); break; #endregion #region SectorSkills #region Magic case 1165: case 7014: success = Skills.SectorSkills.Handle(attacker, packet, spellPacket, spellInfo, true); break; #endregion #region Physical case 1250: case 5050: case 5020: case 1300: success = Skills.SectorSkills.Handle(attacker, packet, spellPacket, spellInfo, false); break; #endregion #endregion #region Single #region Magic case 10310: case 1000: case 1001: case 1002: case 1150: case 1160: case 1180: success = Skills.SingleSkills.Handle(attacker, target, packet, spellPacket, spellInfo, true); break; #endregion #region Physical case 1290: case 5030: case 5040: case 7000: case 7010: case 7030: case 7040: success = Skills.SingleSkills.Handle(attacker, target, packet, spellPacket, spellInfo, false); break; #endregion #endregion #region Circle #region Magic case 1010: //lightning tao case 1120: //fc case 1125: //volc case 3090: //pervade case 5001: //speed case 8030: //arrows case 7013: //flame shower case 30011: //small ice circle case 30012: //large ice circle case 10360: case 10361: case 10392: case 10308: success = Skills.CircleSkills.Handle(attacker, packet, spellPacket, spellInfo, true); break; #endregion #region Physical case 5010: case 7020: case 1115: //herc success = Skills.CircleSkills.Handle(attacker, packet, spellPacket, spellInfo, false); break; #endregion #endregion #region MountSkill case 7001: if (player != null) { success = Skills.MountSkill.Handle(player, spellPacket); } else { success = false; } break; #endregion #region Buff case 1075: case 1085: case 1090: case 1095: success = Skills.BuffCurseSkills.Handle(attacker, target, packet, spellPacket, spellInfo); break; #endregion #region Revive case 1050: case 1100: success = Skills.ReviveSkills.Handle(attacker, target, packet, spellPacket); break; #endregion #region Fly case 8002: case 8003: success = Skills.FlySkills.Handle(attacker); break; #endregion #region Scatter case 8001: success = Skills.ScatterSkill.Handle(attacker, packet, spellPacket, spellInfo); break; #endregion #region Cure #region Self case 1190: case 1195: case 7016: success = Skills.CureSkills.HandleSelf(attacker, target, packet, spellPacket, spellInfo); break; #endregion #region Surroundings case 1005: case 1055: case 1170: case 1175: success = Skills.CureSkills.HandleSurroundings(attacker, target, packet, spellPacket, spellInfo); break; #endregion #endregion #region Archer case 10313: case 8000: case 9991: case 7012: case 7015: case 7017: case 1320: success = Skills.SingleSkills.Handle(attacker, target, packet, spellPacket, spellInfo, false, true); break; #endregion #region Ninja #region Toxic Fog case 6001: success = Skills.SectorSkills.Handle(attacker, packet, spellPacket, spellInfo, false, true); break; #endregion #region TwoFold case 6000: success = Skills.SingleSkills.Handle(attacker, target, packet, spellPacket, spellInfo, false, false); break; #endregion #region PoisonStar case 6002: success = Skills.BuffCurseSkills.Handle(attacker, target, packet, spellPacket, spellInfo, true); break; #endregion #region ArcherBane case 6004: success = Skills.BuffCurseSkills.Handle(attacker, target, packet, spellPacket, spellInfo, false, true); break; #endregion #endregion default: { if (player != null) { player.SendFormattedSystemMessage("INVALID_SKILL", true, spellInfo.Id); } success = false; break; } } if (success) { if (spellInfo.DbSpellInfo.UseEP > 0) { if (player != null) { player.Stamina = (byte)Math.Max(0, (((int)player.Stamina) - spellInfo.DbSpellInfo.UseEP)); } } if (spellInfo.DbSpellInfo.UseMP > 0) { attacker.AttackableEntity.MP -= spellInfo.DbSpellInfo.UseMP; } attacker.UpdateScreen(false, spellPacket); // Not a single skill and skill is not safe, do damage here ... if (spellPacket.Targets.Count > 0 && !spellPacket.Safe && spellPacket.Process) { foreach (var spellTarget in spellPacket.Targets) { if (spellTarget.AssociatedEntity != null) { Damage.Hit(attacker, spellTarget.AssociatedEntity, spellTarget.Damage); } } } if (player != null) { player.ClientSocket.Send(spellPacket); if (spellPacket.SpellId >= 1000 && spellPacket.SpellId <= 1002) { packet.ActivationType = 0; packet.ActivationValue = 0; player.AttackPacket = packet; player.UseAutoAttack(packet); } } } } } }
/// <summary> /// Validates an attack. /// </summary> /// <param name="packet">The packet.</param> /// <param name="target">The target.</param> /// <returns>The status of the validation. (0 = success)</returns> public int ValidateAttack(Models.Packets.Entities.InteractionPacket packet, out AttackableEntityController target) { target = null; if (packet == null) { return(1); } Models.Maps.IMapObject targetMapObject; if (!GetFromScreen(packet.TargetClientId, out targetMapObject)) { return(2); } target = targetMapObject as AttackableEntityController; if (target == null) { return(3); } if (AttackableEntity.ClientId != target.AttackableEntity.ClientId) { var player = target as Player; if (player != null) { if (!player.LoggedIn) { return(4); } if (DateTime.UtcNow < player.LoginProtectionEndTime) { return(5); } if (DateTime.UtcNow < player.ReviveProtectionEndTime) { return(6); } // Can't attack flying players if not ranged if (packet.Action != Enums.InteractionAction.Shoot && target.ContainsStatusFlag(Enums.StatusFlag.Fly)) { return(7); } var attackerPlayer = AttackableEntity as Player; if (attackerPlayer != null) { var pkStatus = attackerPlayer.ValidPkTarget(player); if (pkStatus != 0) { return(8); } } } } if (!Tools.RangeTools.ValidDistance(MapObject.X, MapObject.Y, target.MapObject.X, target.MapObject.Y)) { return(9); } if (!AttackableEntity.Alive) { return(10); } if (!target.AttackableEntity.Alive) { return(11); } return(0); }
/// <summary> /// Handles cure skills for surroundings. /// </summary> /// <param name="attacker">The attacker.</param> /// <param name="target">The target.</param> /// <param name="packet">The packet.</param> /// <param name="spellPacket">The spell packet.</param> /// <param name="spellInfo">The spell info.</param> /// <returns>True if the skill was handled correct.</returns> public static bool HandleSurroundings(AttackableEntityController attacker, AttackableEntityController target, Models.Packets.Entities.InteractionPacket packet, Models.Packets.Spells.SpellPacket spellPacket, Models.Spells.SpellInfo spellInfo) { spellPacket.Safe = true; if (target == null) { return(false); } var attackerPlayer = attacker as Models.Entities.Player; if (attackerPlayer != null) { if (DateTime.UtcNow < attackerPlayer.NextSmallLongSkill) { attackerPlayer.SendSystemMessage("REST"); return(false); } attackerPlayer.NextSmallLongSkill = DateTime.UtcNow.AddMilliseconds(Data.Constants.Time.SmallLongSkillTime); } var targetMonster = target as Models.Entities.Monster; if (targetMonster != null) { if (targetMonster.IsGuard) { return(false); } } target.AttackableEntity.HP += spellInfo.DbSpellInfo.Power; TargetFinalization.SkillFinalize(attacker, target, spellPacket, spellInfo.DbSpellInfo.Power); if (spellInfo.Id == 1055) { foreach (var possibleTarget in attacker.GetAllInScreen()) { if (possibleTarget.ClientId == target.AttackableEntity.ClientId) { continue; } if (Tools.RangeTools.GetDistanceU(possibleTarget.X, possibleTarget.Y, target.MapObject.X, target.MapObject.Y) > spellInfo.DbSpellInfo.Distance) { continue; } target = possibleTarget as AttackableEntityController; if (target == null) { continue; } targetMonster = possibleTarget as Models.Entities.Monster; if (targetMonster != null) { if (targetMonster.IsGuard) { continue; } } var targetPlayer = possibleTarget as Models.Entities.Player; if (targetPlayer != null) { if (!targetPlayer.LoggedIn) { continue; } } TargetFinalization.SkillFinalize(attacker, target, spellPacket, spellInfo.DbSpellInfo.Power); } } if (attackerPlayer != null) { uint newExperience = (uint)Drivers.Repositories.Safe.Random.Next((int)spellInfo.DbSpellInfo.Power, (int)(spellInfo.DbSpellInfo.Power * 2)); newExperience *= (uint)spellPacket.Targets.Count; var skill = attackerPlayer.Spells.GetOrCreateSkill(spellInfo.Id); if (skill != null) { skill.Raise(newExperience); } } return(true); }
/// <summary> /// Handles attack for a monster. /// </summary> /// <param name="monster">The monster to handle attack for.</param> private static void HandleAttack(Models.Entities.Monster monster) { if (!monster.Alive) { return; } #region Poison if (monster.ContainsStatusFlag(Enums.StatusFlag.Poisoned)) { if (DateTime.UtcNow >= monster.NextPoison) { monster.NextPoison = DateTime.UtcNow.AddMilliseconds(3000); if (monster.PoisonEffect > 0) { uint damage = (uint)Math.Max(1, (monster.HP / 100) * monster.PoisonEffect); if (monster.HP > damage) { Helpers.Packets.Interaction.Battle.Damage.Hit(null, monster, damage); var poisonPacket = new Models.Packets.Entities.InteractionPacket { Action = Enums.InteractionAction.Attack, ClientId = monster.ClientId, TargetClientId = monster.ClientId, X = monster.X, Y = monster.Y, Data = damage }; monster.UpdateScreen(false, poisonPacket); } else { monster.PoisonEffect = 0; monster.RemoveStatusFlag(Enums.StatusFlag.Poisoned); } } else { monster.RemoveStatusFlag(Enums.StatusFlag.Poisoned); } } } #endregion var target = monster.Target as Models.Maps.IMapObject; if (target != null && target.Alive) { if (Tools.RangeTools.GetDistance(monster.X, monster.Y, target.X, target.Y) <= monster.AttackRange && monster.ContainsInScreen(target.ClientId) && DateTime.UtcNow >= monster.NextAttackTime) { monster.NextAttackTime = DateTime.UtcNow.AddMilliseconds( Drivers.Repositories.Safe.Random.Next(monster.AttackSpeed, monster.AttackSpeed * 3)); Helpers.Packets.Interaction.Battle.Physical.Handle(monster, new Models.Packets.Entities.InteractionPacket { Action = Enums.InteractionAction.Attack, ClientId = monster.ClientId, TargetClientId = target.ClientId, X = target.X, Y = target.Y }); return; } } var possibleTarget = monster.FindClosest <Models.Entities.Player>(); if (possibleTarget != null && possibleTarget.Alive && !possibleTarget.ContainsStatusFlag(Enums.StatusFlag.PartiallyInvisible)) { if (monster.Behaviour == Enums.MonsterBehaviour.Peaceful && (possibleTarget.Target == null || possibleTarget.Target.ClientId != monster.ClientId)) { monster.Target = null; } else { monster.Target = possibleTarget; } } else { monster.Target = null; } monster.Idle = possibleTarget == null; }
/// <summary> /// Handling a base ranged attack. /// </summary> /// <param name="attacker">The attacker.</param> /// <param name="packet">The packet.</param> public static void Handle(Controllers.Entities.AttackableEntityController attacker, Models.Packets.Entities.InteractionPacket packet) { Controllers.Entities.AttackableEntityController target; var canAttack = attacker.ValidateAttack(packet, out target); if (canAttack == 0 && target != null) { var player = attacker as Player; if (player != null) { if (!ProcessPlayer(player, packet, 1)) { return; } } uint damage = Calculations.RangedCalculations.GetDamage(attacker as IAttackableEntity, target as IAttackableEntity); Damage.Process(attacker, target, ref damage, true); if (damage > 0 && player != null) { var targetMonster = target as Monster; if (targetMonster != null) { uint newExperience = Calculations.Experience.GetProficiencyExperience(player, targetMonster, damage); if (packet.WeaponTypeRight > 0) { var prof = player.Spells.GetOrCreateProficiency(packet.WeaponTypeRight); if (prof != null) { prof.Raise(newExperience); } } } DecreaseArrows(player, 1); } packet.Data = damage; attacker.UpdateScreen(false, packet); if (player != null) { player.ClientSocket.Send(packet); packet.ActivationType = 0; packet.ActivationValue = 0; player.AttackPacket = packet; player.UseAutoAttack(packet); } } }