/// <summary> /// Uses WM, attacking targets. /// </summary> /// <param name="attacker"></param> /// <param name="skill"></param> /// <param name="targetAreaId"></param> /// <param name="unkInt1"></param> /// <param name="unkInt2"></param> public void Use(Creature attacker, Skill skill, long targetAreaId = 0, int unkInt1 = 0, int unkInt2 = 0) { bool wasKnockedDown = (attacker.IsKnockedDown || attacker.WasKnockedBack); if ((attacker.Stun > 500 && wasKnockedDown || attacker.IsStunned && !wasKnockedDown || DateTime.Now.AddMilliseconds(2000) < attacker.AttackDelayTime && (wasKnockedDown)) && attacker.InterceptingSkillId == SkillId.None) { Send.SkillUseSilentCancel(attacker); return; } var range = this.GetRange(attacker, skill); ICollection<Creature> targets = attacker.GetTargetableCreaturesInRange(range, true).Where(t => !(DateTime.Now.AddMilliseconds(2000) < t.NotReadyToBeHitTime)).ToList(); //Able to be attacked at 1/3 of knock down time. // Check targets if (targets.Count == 0) { Send.Notice(attacker, Localization.Get("There isn't a target nearby to use that on.")); Send.SkillUseSilentCancel(attacker); return; } // Create actions var cap = new CombatActionPack(attacker, skill.Info.Id); var aAction = new AttackerAction(CombatActionType.SpecialHit, attacker, skill.Info.Id, targetAreaId); aAction.Set(AttackerOptions.Result); cap.Add(aAction); var survived = new List<Creature>(); var skipped = new List<Creature>(); var i = 0; foreach (var target in targets) { i++; target.StopMove(); Skill smash = target.Skills.Get(SkillId.Smash); if (smash != null && target.Skills.IsReady(SkillId.Smash) && !attacker.IsPlayer) attacker.InterceptingSkillId = SkillId.Smash; TargetAction tAction; if (attacker.InterceptingSkillId == SkillId.Smash && target.GetPosition().InRange(attacker.GetPosition(), target.AttackRangeFor(attacker))) { aAction.Options |= AttackerOptions.Result; tAction = new TargetAction(CombatActionType.CounteredHit, target, attacker, SkillId.Smash); tAction.Options |= TargetOptions.Result; } else { tAction = new TargetAction(CombatActionType.TakeHit, target, attacker, skill.Info.Id); } attacker.InterceptingSkillId = SkillId.None; tAction.Delay = 300; // Usually 300, sometimes 350? // Calculate damage float damage = 0f; if (attacker.RightHand != null && ( attacker.RightHand.Data.HasTag("/weapon/bow01/") || attacker.RightHand.Data.HasTag("/weapon/bow/") || attacker.RightHand.Data.HasTag("/weapon/crossbow/") || attacker.RightHand.Data.HasTag("/weapon/shuriken/") || attacker.RightHand.Data.HasTag("/weapon/atlatl/") || attacker.RightHand.Data.HasTag("/weapon/gun/dualgun/"))) { damage = attacker.GetRndBareHandDamage(); } else { damage = attacker.GetRndTotalDamage(); } damage *= skill.RankData.Var1 / 100f; // Handle skills and reductions var allCrit = false; var critSkill = target.Skills.Get(SkillId.CriticalHit); if (allCrit) { // Add crit bonus var bonus = critSkill.RankData.Var1 / 100f; damage = damage + (damage * bonus); // Set target option tAction.Set(TargetOptions.Critical); } else if (i == 1) { CriticalHit.Handle(attacker, attacker.GetTotalCritChance(0), ref damage, tAction); if (tAction.Has(TargetOptions.Critical)) allCrit = true; } var maxDamage = damage; //Damage without Defense and Protection SkillHelper.HandleDefenseProtection(target, ref damage); Defense.Handle(aAction, tAction, ref damage); ManaShield.Handle(target, ref damage, tAction, maxDamage); // Clean Hit if not defended nor critical if (!tAction.Is(CombatActionType.Defended) && !tAction.Has(TargetOptions.Critical)) tAction.Set(TargetOptions.CleanHit); // Take damage if any is left if (damage > 0) target.TakeDamage(tAction.Damage = damage, attacker); // Finish if dead, knock down if not defended if (target.IsDead) tAction.Set(TargetOptions.KnockDownFinish); else if (!tAction.Is(CombatActionType.Defended)) tAction.Set(TargetOptions.KnockDown); // Anger Management if (!target.IsDead) survived.Add(target); if (target.UseBattleStanceFromAOE) target.IsInBattleStance = true; // Stun & knock back aAction.Stun = CombatMastery.GetAttackerStun(attacker.AverageKnockCount, attacker.AverageAttackSpeed, true); if (!tAction.Is(CombatActionType.Defended)) { tAction.Stun = CombatMastery.GetTargetStun(attacker.AverageKnockCount, attacker.AverageAttackSpeed, true); target.Stability = Creature.MinStability; attacker.Shove(target, KnockbackDistance); } // Add action cap.Add(tAction); } // Only select a random aggro if there is no aggro yet, // WM only aggroes one target at a time. if (survived.Count != 0 && attacker.Region.CountAggro(attacker) < 1) { var rnd = RandomProvider.Get(); var aggroTarget = survived.Random(); aggroTarget.Aggro(attacker); } // Reduce life in old combat system if (!AuraData.FeaturesDb.IsEnabled("CombatSystemRenewal")) { var amount = (attacker.LifeMax < 10 ? 2 : attacker.LifeMax / 10); attacker.ModifyLife(-amount); attacker.InvincibilityTime = DateTime.Now.AddMilliseconds(2300); } // Spin it~ Send.UseMotion(attacker, 8, 4); cap.Handle(); Send.SkillUse(attacker, skill.Info.Id, targetAreaId, unkInt1, unkInt2); skill.Stacks = 0; }
/// <summary> /// Uses WM, attacking targets. /// </summary> /// <param name="attacker"></param> /// <param name="skill"></param> /// <param name="targetAreaId"></param> /// <param name="unkInt1"></param> /// <param name="unkInt2"></param> public void Use(Creature attacker, Skill skill, long targetAreaId, int unkInt1, int unkInt2) { var range = this.GetRange(attacker, skill); var targets = attacker.GetTargetableCreaturesInRange(range, true); // Check targets if (targets.Count == 0) { Send.Notice(attacker, Localization.Get("There isn't a target nearby to use that on.")); Send.SkillUseSilentCancel(attacker); return; } // Create actions var cap = new CombatActionPack(attacker, skill.Info.Id); var aAction = new AttackerAction(CombatActionType.SpecialHit, attacker, skill.Info.Id, targetAreaId); aAction.Set(AttackerOptions.Result); cap.Add(aAction); var survived = new List<Creature>(); foreach (var target in targets) { target.StopMove(); var tAction = new TargetAction(CombatActionType.TakeHit, target, attacker, skill.Info.Id); tAction.Delay = 300; // Usually 300, sometimes 350? // Calculate damage var damage = attacker.GetRndTotalDamage(); damage *= skill.RankData.Var1 / 100f; // Handle skills and reductions CriticalHit.Handle(attacker, attacker.GetTotalCritChance(0), ref damage, tAction); SkillHelper.HandleDefenseProtection(target, ref damage); Defense.Handle(aAction, tAction, ref damage); ManaShield.Handle(target, ref damage, tAction); // Clean Hit if not defended nor critical if (tAction.SkillId != SkillId.Defense && !tAction.Has(TargetOptions.Critical)) tAction.Set(TargetOptions.CleanHit); // Take damage if any is left if (damage > 0) target.TakeDamage(tAction.Damage = damage, attacker); // Finish if dead, knock down if not defended if (target.IsDead) tAction.Set(TargetOptions.KnockDownFinish); else if (tAction.SkillId != SkillId.Defense) tAction.Set(TargetOptions.KnockDown); // Anger Management if (!target.IsDead) survived.Add(target); // Stun & knock back aAction.Stun = CombatMastery.GetAttackerStun(attacker.AverageKnockCount, attacker.AverageAttackSpeed, true); if (tAction.SkillId != SkillId.Defense) { tAction.Stun = CombatMastery.GetTargetStun(attacker.AverageKnockCount, attacker.AverageAttackSpeed, true); target.Stability = Creature.MinStability; attacker.Shove(target, KnockbackDistance); } // Add action cap.Add(tAction); } // Only select a random aggro if there is no aggro yet, // WM only aggroes one target at a time. if (survived.Count != 0 && attacker.Region.CountAggro(attacker) < 1) { var rnd = RandomProvider.Get(); var aggroTarget = survived.Random(); aggroTarget.Aggro(attacker); } // Reduce life in old combat system if (!AuraData.FeaturesDb.IsEnabled("CombatSystemRenewal")) { var amount = (attacker.LifeMax < 10 ? 2 : attacker.LifeMax / 10); attacker.ModifyLife(-amount); // TODO: Invincibility } // Spin it~ Send.UseMotion(attacker, 8, 4); cap.Handle(); Send.SkillUse(attacker, skill.Info.Id, targetAreaId, unkInt1, unkInt2); skill.Stacks = 0; }
/// <summary> /// Uses WM, attacking targets. /// </summary> /// <param name="attacker"></param> /// <param name="skill"></param> /// <param name="targetAreaId"></param> /// <param name="unkInt1"></param> /// <param name="unkInt2"></param> public void Use(Creature attacker, Skill skill, long targetAreaId, int unkInt1, int unkInt2) { var range = this.GetRange(attacker, skill); var targets = attacker.GetTargetableCreaturesInRange(range, TargetableOptions.AddAttackRange); // Check targets if (targets.Count == 0) { Send.Notice(attacker, Localization.Get("There isn't a target nearby to use that on.")); Send.SkillUseSilentCancel(attacker); return; } // Create actions var cap = new CombatActionPack(attacker, skill.Info.Id); var aAction = new AttackerAction(CombatActionType.SpecialHit, attacker, targetAreaId); aAction.Set(AttackerOptions.Result); aAction.Stun = CombatMastery.GetAttackerStun(attacker.AverageKnockCount, attacker.AverageAttackSpeed, true); cap.Add(aAction); var survived = new List<Creature>(); var rnd = RandomProvider.Get(); // Check crit var crit = false; if (attacker.Skills.Has(SkillId.CriticalHit, SkillRank.RF)) crit = (rnd.Next(100) < attacker.GetTotalCritChance(0)); // Handle all targets foreach (var target in targets) { target.StopMove(); var tAction = new TargetAction(CombatActionType.TakeHit, target, attacker, skill.Info.Id); tAction.Delay = 300; // Usually 300, sometimes 350? // Calculate damage var damage = attacker.GetRndTotalDamage(); damage *= skill.RankData.Var1 / 100f; // Elementals damage *= attacker.CalculateElementalDamageMultiplier(target); // Crit bonus if (crit) CriticalHit.Handle(attacker, 100, ref damage, tAction); // Handle skills and reductions SkillHelper.HandleDefenseProtection(target, ref damage); SkillHelper.HandleConditions(attacker, target, ref damage); Defense.Handle(aAction, tAction, ref damage); ManaShield.Handle(target, ref damage, tAction); HeavyStander.Handle(attacker, target, ref damage, tAction); // Clean Hit if not defended nor critical if (tAction.SkillId != SkillId.Defense && !tAction.Has(TargetOptions.Critical)) tAction.Set(TargetOptions.CleanHit); // Take damage if any is left if (damage > 0) target.TakeDamage(tAction.Damage = damage, attacker); // Knock down on deadly if (target.Conditions.Has(ConditionsA.Deadly)) { tAction.Set(TargetOptions.KnockDown); tAction.Stun = CombatMastery.GetTargetStun(attacker.AverageKnockCount, attacker.AverageAttackSpeed, true); } // Finish if dead, knock down if not defended if (target.IsDead) tAction.Set(TargetOptions.KnockDownFinish); else if (tAction.SkillId != SkillId.Defense) tAction.Set(TargetOptions.KnockDown); // Anger Management if (!target.IsDead) survived.Add(target); // Stun and shove if not defended if (target.IsDead || tAction.SkillId != SkillId.Defense || target.Conditions.Has(ConditionsA.Deadly)) { tAction.Stun = CombatMastery.GetTargetStun(attacker.AverageKnockCount, attacker.AverageAttackSpeed, true); target.Stability = Creature.MinStability; attacker.Shove(target, KnockbackDistance); } // Add action cap.Add(tAction); } // Update current weapon SkillHelper.UpdateWeapon(attacker, targets.FirstOrDefault(), ProficiencyGainType.Melee, attacker.RightHand, attacker.LeftHand); // Only select a random aggro if there is no aggro yet, // WM only aggroes one target at a time. if (survived.Count != 0 && attacker.Region.CountAggro(attacker) < 1) { var aggroTarget = survived.Random(); aggroTarget.Aggro(attacker); } // Reduce life in old combat system if (!AuraData.FeaturesDb.IsEnabled("CombatSystemRenewal")) { // Default reduction is 10%, it's reduced to 2% if attacker // has less max life than the rate is set to. var lifeReducationRate = skill.RankData.Var2; if (attacker.LifeMax < lifeReducationRate) lifeReducationRate /= 5; var amount = attacker.LifeMax / 100f * lifeReducationRate; attacker.ModifyLife(-amount); // TODO: Invincibility } // Spin it~ Send.UseMotion(attacker, 8, 4); cap.Handle(); Send.SkillUse(attacker, skill.Info.Id, targetAreaId, unkInt1, unkInt2); skill.Stacks = 0; }