public CanTarget ( |
||
creature | ||
return | bool |
/// <summary> /// Bolt specific use code. /// </summary> /// <param name="attacker"></param> /// <param name="skill"></param> /// <param name="target"></param> protected override void UseSkillOnTarget(Creature attacker, Skill skill, Creature mainTarget) { // Create actions var aAction = new AttackerAction(CombatActionType.RangeHit, attacker, skill.Info.Id, mainTarget.EntityId); aAction.Set(AttackerOptions.Result); var cap = new CombatActionPack(attacker, skill.Info.Id, aAction); var targets = new List<Creature>(); targets.Add(mainTarget); targets.AddRange(mainTarget.Region.GetCreaturesInRange(mainTarget.GetPosition(), SplashRange).Where(a => a != mainTarget && attacker.CanTarget(a) && attacker.CanAttack(a))); // Damage var damage = this.GetDamage(attacker, skill); var max = Math.Min(targets.Count, skill.Stacks); for (int i = 0; i < max; ++i) { var target = targets[i]; var targetDamage = damage; target.StopMove(); var tAction = new TargetAction(CombatActionType.TakeHit, target, attacker, skill.Info.Id); tAction.Set(TargetOptions.Result); tAction.Stun = TargetStun; // Full damage for the first target, -10% for every subsequent one. targetDamage -= (targetDamage * 0.1f) * i; // Reduce damage var maxDamage = damage; //Damage without Defense and Protection // Reduce damage Defense.Handle(aAction, tAction); SkillHelper.HandleMagicDefenseProtection(target, ref targetDamage); ManaShield.Handle(target, ref targetDamage, tAction, maxDamage, true); // Deal damage if (targetDamage > 0) target.TakeDamage(tAction.Damage = targetDamage, attacker); if (target == mainTarget) target.Aggro(attacker); // Death/Knockback this.HandleKnockBack(attacker, target, tAction); cap.Add(tAction); } // Override stun set by defense aAction.Stun = AttackerStun; Send.Effect(attacker, Effect.UseMagic, EffectSkillName); Send.SkillUseStun(attacker, skill.Info.Id, aAction.Stun, 1); this.BeforeHandlingPack(attacker, skill); cap.Handle(); }
/// <summary> /// Uses LightningRod /// </summary> /// <param name="attacker"></param> /// <param name="skill"></param> /// <param name="packet"></param> public void Use(Creature attacker, Skill skill, Packet packet) { // Set full charge variable attacker.Temp.LightningRodFullCharge = (DateTime.Now >= attacker.Temp.LightningRodPrepareTime.AddMilliseconds(skill.RankData.Var3)); // Get direction for target Area var direction = Mabi.MabiMath.ByteToRadian(attacker.Direction); var attackerPos = attacker.GetPosition(); // Calculate polygon points var r = MabiMath.ByteToRadian(attacker.Direction); var poe = attackerPos.GetRelative(r, 800); var pivot = new Point(poe.X, poe.Y); var p1 = new Point(pivot.X - SkillLength / 2, pivot.Y - SkillWidth / 2); var p2 = new Point(pivot.X - SkillLength / 2, pivot.Y + SkillWidth / 2); var p3 = new Point(pivot.X + SkillLength / 2, pivot.Y + SkillWidth / 2); var p4 = new Point(pivot.X + SkillLength / 2, pivot.Y - SkillWidth / 2); p1 = this.RotatePoint(p1, pivot, r); p2 = this.RotatePoint(p2, pivot, r); p3 = this.RotatePoint(p3, pivot, r); p4 = this.RotatePoint(p4, pivot, r); // TargetProp var lProp = new Prop(280, attacker.RegionId, poe.X, poe.Y, MabiMath.ByteToRadian(attacker.Direction), 1f, 0f, "single"); attacker.Region.AddProp(lProp); // Prepare Combat Actions var cap = new CombatActionPack(attacker, skill.Info.Id); var targetAreaId = new Location(attacker.RegionId, poe).ToLocationId(); var aAction = new AttackerAction(CombatActionType.SpecialHit, attacker, targetAreaId); aAction.Set(AttackerOptions.KnockBackHit1 | AttackerOptions.UseEffect); aAction.PropId = lProp.EntityId; cap.Add(aAction); // Get targets in Polygon - includes collission check var targets = attacker.Region.GetCreaturesInPolygon(p1, p2, p3, p4).Where(x => attacker.CanTarget(x) && !attacker.Region.Collisions.Any(attacker.GetPosition(), x.GetPosition())).ToList(); var rnd = RandomProvider.Get(); // Check crit var crit = false; var critSkill = attacker.Skills.Get(SkillId.CriticalHit); if (critSkill != null && critSkill.Info.Rank > SkillRank.Novice) { var critChance = Math2.Clamp(0, 30, attacker.GetTotalCritChance(0)); if (rnd.NextDouble() * 100 < critChance) crit = true; } foreach (var target in targets) { var tAction = new TargetAction(CombatActionType.TakeHit, target, attacker, SkillId.CombatMastery); tAction.Set(TargetOptions.None); tAction.AttackerSkillId = skill.Info.Id; cap.Add(tAction); var damage = attacker.GetRndMagicDamage(skill, skill.RankData.Var1, skill.RankData.Var2); // Add damage if the skill is fully charged var dmgMultiplier = skill.RankData.Var4 / 100f; if (attacker.Temp.LightningRodFullCharge) { damage += (damage * dmgMultiplier); } // Critical Hit if (crit) { var bonus = critSkill.RankData.Var1 / 100f; damage = damage + (damage * bonus); tAction.Set(TargetOptions.Critical); } // MDef and MProt SkillHelper.HandleMagicDefenseProtection(target, ref damage); // Conditions SkillHelper.HandleConditions(attacker, target, ref damage); // Mana Deflector var delayReduction = ManaDeflector.Handle(attacker, target, ref damage, tAction); // Mana Shield ManaShield.Handle(target, ref damage, tAction); // Apply Damage target.TakeDamage(tAction.Damage = damage, attacker); // Stun Time tAction.Stun = TargetStun; // Death or Knockback if (target.IsDead) { tAction.Set(TargetOptions.FinishingKnockDown); attacker.Shove(target, KnockbackDistance); } else { // Always knock down if (target.Is(RaceStands.KnockDownable)) { tAction.Set(TargetOptions.KnockDown); attacker.Shove(target, KnockbackDistance); } } } // Update current weapon SkillHelper.UpdateWeapon(attacker, targets.FirstOrDefault(), ProficiencyGainType.Melee, attacker.RightHand); cap.Handle(); Send.Effect(attacker, Effect.LightningRod, (int)LightningRodEffect.Attack, poe.X, poe.Y); Send.SkillUse(attacker, skill.Info.Id, targetAreaId, 0, 1); skill.Train(1); // Use the Skill attacker.Region.RemoveProp(lProp); }
/// <summary> /// Handles skill usage. /// </summary> /// <param name="creature"></param> /// <param name="skill"></param> /// <param name="packet"></param> public void Use(Creature creature, Skill skill, Packet packet) { var targetEntityId = packet.GetLong(); // Similar to WM there is a case where these aren't sent. // Apparently this can happen if you activate the skill while // targetting an enemy. var unk1 = (packet.Peek() != PacketElementType.None ? packet.GetInt() : 0); var unk2 = (packet.Peek() != PacketElementType.None ? packet.GetInt() : 0); if (_cm == null) _cm = ChannelServer.Instance.SkillManager.GetHandler<CombatMastery>(SkillId.CombatMastery); // TODO: Check duration var attackResult = false; var target = creature.Region.GetCreature(targetEntityId); if (target != null && !creature.IsStunned && creature.CanTarget(target)) { var pos = creature.GetPosition(); var targetPos = target.GetPosition(); var inRange = pos.InRange(targetPos, creature.AttackRangeFor(target)); if (!inRange) { var telePos = pos.GetRelative(targetPos, -creature.AttackRangeFor(target) + 100); // Check teleport distance if (pos.GetDistance(telePos) > skill.RankData.Var3 + 100) { Send.Notice(creature, "Out of range"); } else { Send.Effect(creature, Effect.SilentMoveTeleport, targetEntityId, (byte)0); creature.SetPosition(telePos.X, telePos.Y); Send.SkillTeleport(creature, telePos.X, telePos.Y); inRange = true; } } if (inRange) attackResult = (_cm.Use(creature, skill, targetEntityId) == CombatSkillResult.Okay); } Send.CombatAttackR(creature, attackResult); Send.SkillUse(creature, skill.Info.Id, targetEntityId, unk1, unk2); }
/// <summary> /// Returns targetable creatures in given range of prop. /// Owner of the prop and creatures he can't target are excluded. /// </summary> /// <param name="owner">Owner of the prop, who is excluded and used as reference for CanTarget (null to ignore).</param> /// <param name="range"></param> /// <returns></returns> public ICollection<Creature> GetTargetableCreaturesInRange(Creature owner, int range) { var pos = this.GetPosition(); var targetable = this.Region.GetCreatures(target => { var targetPos = target.GetPosition(); return target != owner // Exclude owner && (owner == null || owner.CanTarget(target)) // Check targetability && !target.IsDead // Check if target's alive (in case owner is null) && !target.Has(CreatureStates.NamedNpc) // Don't hit NamedNpcs (in case owner is null) && targetPos.InRange(pos, range) // Check range && !this.Region.Collisions.Any(pos, targetPos) // Check collisions between entities && !target.Conditions.Has(ConditionsA.Invisible); // Check visiblility (GM) }); return targetable; }
public void Use(Creature creature, Skill skill, long targetEntityId, int unk1, int unk2) { if (_cm == null) _cm = ChannelServer.Instance.SkillManager.GetHandler<CombatMastery>(SkillId.CombatMastery); var attackResult = false; var target = creature.Region.GetCreature(targetEntityId); if (target != null && !creature.IsStunned && !creature.IsOnAttackDelay && creature.CanTarget(target) && creature.CanAttack(target)) { var pos = creature.GetPosition(); var targetPos = target.GetPosition(); var inRange = (pos.InRange(targetPos, creature.AttackRangeFor(target)) && !creature.Region.Collisions.Any(pos, targetPos) // Check collisions between position && !target.Conditions.Has(ConditionsA.Invisible)); // Check visiblility (GM) if (!inRange && !target.IsNotReadyToBeHit) { var telePos = pos.GetRelative(targetPos, -creature.AttackRangeFor(target) + 100); // Check teleport distance if (pos.GetDistance(telePos) > skill.RankData.Var3 + 100) { Send.Notice(creature, "Out of range"); } else { Send.Effect(creature, Effect.SilentMoveTeleport, targetEntityId, (byte)0); creature.SetPosition(telePos.X, telePos.Y); Send.SkillTeleport(creature, telePos.X, telePos.Y); inRange = true; } } if (inRange) attackResult = (_cm.Use(creature, skill, targetEntityId) == CombatSkillResult.Okay); } Send.CombatAttackR(creature, attackResult); Send.SkillUse(creature, skill.Info.Id, targetEntityId, unk1, unk2); }