Handle() публичный статический Метод

Handles Heavy Stander bonuses and auto-defense, reducing damage and setting the appropriate options on tAction. Returns whether or not Heavy Stander pinged.
All active and passive Heavy Standers are checked in sequence, followed by the equipment, with the passive damage reduction stacking. It's unknown whether this is official, and assumedly no monsters have multiple Heavy Stander skills. The ping reduction is only applied once, no matter where it came from.
public static Handle ( Creature attacker, Creature target, float &damage, TargetAction tAction ) : bool
attacker Aura.Channel.World.Entities.Creature
target Aura.Channel.World.Entities.Creature
damage float
tAction TargetAction
Результат bool
Пример #1
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"))
            {
                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;
        }
Пример #2
0
        /// <summary>
        /// Handles attack.
        /// </summary>
        /// <param name="attacker">The creature attacking.</param>
        /// <param name="skill">The skill being used.</param>
        /// <param name="targetEntityId">The entity id of the target.</param>
        /// <returns></returns>
        public CombatSkillResult Use(Creature attacker, Skill skill, long targetEntityId)
        {
            if (attacker.IsStunned)
            {
                return(CombatSkillResult.Okay);
            }

            var target = attacker.Region.GetCreature(targetEntityId);

            if (target == null)
            {
                return(CombatSkillResult.Okay);
            }

            if (!attacker.GetPosition().InRange(target.GetPosition(), attacker.AttackRangeFor(target)))
            {
                return(CombatSkillResult.OutOfRange);
            }

            attacker.StopMove();
            var targetPosition = target.StopMove();

            // Counter
            if (Counterattack.Handle(target, attacker))
            {
                return(CombatSkillResult.Okay);
            }

            var rightWeapon = attacker.Inventory.RightHand;
            var leftWeapon  = attacker.Inventory.LeftHand;
            var magazine    = attacker.Inventory.Magazine;
            var maxHits     = (byte)(attacker.IsDualWielding ? 2 : 1);
            int prevId      = 0;

            for (byte i = 1; i <= maxHits; ++i)
            {
                var weapon          = (i == 1 ? rightWeapon : leftWeapon);
                var weaponIsKnuckle = (weapon != null && weapon.Data.HasTag("/knuckle/"));

                var aAction = new AttackerAction(CombatActionType.Attacker, attacker, targetEntityId);
                aAction.Set(AttackerOptions.Result);

                var tAction = new TargetAction(CombatActionType.TakeHit, target, attacker, skill.Info.Id);
                tAction.Set(TargetOptions.Result);

                var cap = new CombatActionPack(attacker, skill.Info.Id, aAction, tAction);
                cap.Hit    = i;
                cap.Type   = (attacker.IsDualWielding ? CombatActionPackType.TwinSwordAttack : CombatActionPackType.NormalAttack);
                cap.PrevId = prevId;
                prevId     = cap.Id;

                // Default attacker options
                aAction.Set(AttackerOptions.Result);
                if (attacker.IsDualWielding)
                {
                    aAction.Set(AttackerOptions.DualWield);
                    aAction.WeaponParameterType = (byte)(i == 1 ? 2 : 1);
                }

                // Base damage
                var damage = (i == 1 ? attacker.GetRndRightHandDamage() : attacker.GetRndLeftHandDamage());

                // Elementals
                damage *= attacker.CalculateElementalDamageMultiplier(target);

                // Critical Hit
                var critChance = (i == 1 ? attacker.GetRightCritChance(target.Protection) : attacker.GetLeftCritChance(target.Protection));
                CriticalHit.Handle(attacker, critChance, ref damage, tAction);

                // Subtract target def/prot
                SkillHelper.HandleDefenseProtection(target, ref damage);

                // Defense
                Defense.Handle(aAction, tAction, ref damage);

                // Mana Shield
                ManaShield.Handle(target, ref damage, tAction);

                // Heavy Stander
                // Can only happen on the first hit
                var pinged = (cap.Hit == 1 && HeavyStander.Handle(attacker, target, ref damage, tAction));

                // Deal with it!
                if (damage > 0)
                {
                    target.TakeDamage(tAction.Damage = damage, attacker);
                    SkillHelper.HandleInjury(attacker, target, damage);
                }

                // Knock down on deadly
                if (target.Conditions.Has(ConditionsA.Deadly))
                {
                    tAction.Set(TargetOptions.KnockDown);
                    tAction.Stun = GetTargetStun(attacker, weapon, tAction.IsKnockBack);
                }

                // Aggro
                target.Aggro(attacker);

                // Evaluate caused damage
                if (!target.IsDead)
                {
                    if (tAction.SkillId != SkillId.Defense)
                    {
                        target.Stability -= this.GetStabilityReduction(attacker, weapon) / maxHits;

                        // React normal for CombatMastery, knock down if
                        // FH and not dual wield, don't knock at all if dual.
                        if (skill.Info.Id != SkillId.FinalHit)
                        {
                            // Originally we thought you knock enemies back, unless it's a critical
                            // hit, but apparently you knock *down* under normal circumstances.
                            // More research to be done.
                            if (target.IsUnstable && target.Is(RaceStands.KnockBackable))
                            {
                                //tAction.Set(tAction.Has(TargetOptions.Critical) ? TargetOptions.KnockDown : TargetOptions.KnockBack);
                                tAction.Set(TargetOptions.KnockDown);
                            }
                        }
                        else if (!attacker.IsDualWielding && !weaponIsKnuckle)
                        {
                            target.Stability = Creature.MinStability;
                            tAction.Set(TargetOptions.KnockDown);
                        }
                    }
                }
                else
                {
                    tAction.Set(TargetOptions.FinishingKnockDown);
                }

                // React to knock back
                if (tAction.IsKnockBack)
                {
                    attacker.Shove(target, KnockBackDistance);
                    aAction.Set(AttackerOptions.KnockBackHit2);
                }

                // Set stun time if not defended, Defense handles the stun
                // in case the target used it.
                if (tAction.SkillId != SkillId.Defense)
                {
                    aAction.Stun = GetAttackerStun(attacker, weapon, tAction.IsKnockBack && skill.Info.Id != SkillId.FinalHit);
                    tAction.Stun = GetTargetStun(attacker, weapon, tAction.IsKnockBack);
                }

                // Set increased stun if target pinged
                if (pinged)
                {
                    aAction.Stun = GetAttackerStun(attacker, weapon, true);
                }

                // Second hit doubles stun time for normal hits
                if (cap.Hit == 2 && !tAction.IsKnockBack && !pinged)
                {
                    aAction.Stun *= 2;
                }

                // Update current weapon
                SkillHelper.UpdateWeapon(attacker, target, weapon);

                // Consume stamina for weapon
                var staminaUsage = (weapon != null ? weapon.Data.StaminaUsage : Creature.BareHandStaminaUsage);
                if (attacker.Stamina < staminaUsage)
                {
                    Send.Notice(attacker, Localization.Get("Your stamina is too low to fight properly!"));
                }
                attacker.Stamina -= staminaUsage;

                // No second hit if defended, pinged, or knocked back
                if (tAction.IsKnockBack || tAction.SkillId == SkillId.Defense || pinged)
                {
                    // Set to 1 to prevent second run
                    maxHits = 1;

                    // Remove dual wield option if last hit doesn't come from
                    // the second weapon. If this isn't done, the client shows
                    // the second hit.
                    if (cap.Hit != 2)
                    {
                        aAction.Options &= ~AttackerOptions.DualWield;
                    }
                }

                // Handle
                cap.Handle();
            }

            return(CombatSkillResult.Okay);
        }
Пример #3
0
        /// <summary>
        /// Handles skill usage.
        /// </summary>
        /// <param name="attacker"></param>
        /// <param name="skill"></param>
        /// <param name="targetEntityId"></param>
        /// <returns></returns>
        public override CombatSkillResult Use(Creature attacker, Skill skill, long targetEntityId)
        {
            // Check target
            var mainTarget = attacker.Region.GetCreature(targetEntityId);

            if (mainTarget == null)
            {
                return(CombatSkillResult.InvalidTarget);
            }

            // Check range
            var targetPosition = mainTarget.GetPosition();

            if (!attacker.GetPosition().InRange(targetPosition, attacker.AttackRangeFor(mainTarget)))
            {
                return(CombatSkillResult.OutOfRange);
            }

            // Stop movement
            attacker.StopMove();

            // Get targets, incl. splash.
            // Splash happens from r5 onwards, but we'll base it on Var4,
            // which is the splash damage and first != 0 on r5.
            var targets = new HashSet <Creature>()
            {
                mainTarget
            };

            if (skill.RankData.Var4 != 0)
            {
                targets.UnionWith(attacker.GetTargetableCreaturesInCone(mainTarget.GetPosition(), attacker.GetTotalSplashRadius(), attacker.GetTotalSplashAngle()));
            }

            // Counter
            if (Counterattack.Handle(targets, attacker))
            {
                return(CombatSkillResult.Okay);
            }

            // Prepare combat actions
            var aAction = new AttackerAction(CombatActionType.HardHit, attacker, targetEntityId);

            aAction.Set(AttackerOptions.Result | AttackerOptions.KnockBackHit2);
            aAction.Stun = StunTime;

            var cap = new CombatActionPack(attacker, skill.Info.Id, aAction);

            // Calculate damage
            var mainDamage = this.GetDamage(attacker, skill);

            foreach (var target in targets)
            {
                // Stop movement
                target.StopMove();

                var tAction = new TargetAction(CombatActionType.TakeHit, target, attacker, skill.Info.Id);
                tAction.Set(TargetOptions.Result | TargetOptions.Smash);

                cap.Add(tAction);

                // Damage
                var damage = mainDamage;

                // Elementals
                damage *= attacker.CalculateElementalDamageMultiplier(target);

                // Splash modifier
                if (target != mainTarget)
                {
                    damage *= (skill.RankData.Var4 / 100f);
                }

                // Critical Hit
                var critChance = this.GetCritChance(attacker, target, skill);
                CriticalHit.Handle(attacker, critChance, ref damage, tAction);

                // Subtract target def/prot
                SkillHelper.HandleDefenseProtection(target, ref damage);

                // Mana Shield
                ManaShield.Handle(target, ref damage, tAction);

                // Heavy Stander
                HeavyStander.Handle(attacker, target, ref damage, tAction);

                // Apply damage
                if (damage > 0)
                {
                    target.TakeDamage(tAction.Damage = damage, attacker);
                    SkillHelper.HandleInjury(attacker, target, damage);
                }

                // Aggro
                if (target == mainTarget)
                {
                    target.Aggro(attacker);
                }

                if (target.IsDead)
                {
                    tAction.Set(TargetOptions.FinishingHit | TargetOptions.Finished);
                }

                // Set Stun/Knockback
                target.Stun      = tAction.Stun = StunTime;
                target.Stability = Creature.MinStability;

                // Set knockbacked position
                attacker.Shove(target, KnockbackDistance);
            }

            // Response
            Send.SkillUseStun(attacker, skill.Info.Id, AfterUseStun, 1);

            // Update both weapons
            SkillHelper.UpdateWeapon(attacker, mainTarget, ProficiencyGainType.Melee, attacker.RightHand, attacker.LeftHand);

            // Action!
            cap.Handle();

            return(CombatSkillResult.Okay);
        }
Пример #4
0
        /// <summary>
        /// Handles attack.
        /// </summary>
        /// <param name="attacker">The creature attacking.</param>
        /// <param name="skill">The skill being used.</param>
        /// <param name="targetEntityId">The entity id of the target.</param>
        /// <returns></returns>
        public CombatSkillResult Use(Creature attacker, Skill skill, long targetEntityId)
        {
            if (attacker.IsStunned)
            {
                return(CombatSkillResult.Okay);
            }

            var mainTarget = attacker.Region.GetCreature(targetEntityId);

            if (mainTarget == null)
            {
                return(CombatSkillResult.Okay);
            }

            if (!attacker.GetPosition().InRange(mainTarget.GetPosition(), attacker.AttackRangeFor(mainTarget)))
            {
                return(CombatSkillResult.OutOfRange);
            }

            attacker.StopMove();

            // Get targets, incl. splash.
            var targets = new HashSet <Creature>()
            {
                mainTarget
            };

            targets.UnionWith(attacker.GetTargetableCreaturesInCone(mainTarget.GetPosition(), attacker.GetTotalSplashRadius(), attacker.GetTotalSplashAngle()));

            // Counter
            if (Counterattack.Handle(targets, attacker))
            {
                return(CombatSkillResult.Okay);
            }

            var rightWeapon = attacker.Inventory.RightHand;
            var leftWeapon  = attacker.Inventory.LeftHand;
            var magazine    = attacker.Inventory.Magazine;
            var maxHits     = (byte)(attacker.IsDualWielding ? 2 : 1);
            int prevId      = 0;

            for (byte i = 1; i <= maxHits; ++i)
            {
                var weapon          = (i == 1 ? rightWeapon : leftWeapon);
                var weaponIsKnuckle = (weapon != null && weapon.Data.HasTag("/knuckle/"));

                var aAction = new AttackerAction(CombatActionType.Attacker, attacker, targetEntityId);
                aAction.Set(AttackerOptions.Result);

                if (attacker.IsDualWielding)
                {
                    aAction.Set(AttackerOptions.DualWield);
                    aAction.WeaponParameterType = (byte)(i == 1 ? 2 : 1);
                }

                var cap = new CombatActionPack(attacker, skill.Info.Id, aAction);
                cap.Hit    = i;
                cap.Type   = (attacker.IsDualWielding ? CombatActionPackType.TwinSwordAttack : CombatActionPackType.NormalAttack);
                cap.PrevId = prevId;
                prevId     = cap.Id;

                var mainDamage = (i == 1 ? attacker.GetRndRightHandDamage() : attacker.GetRndLeftHandDamage());

                foreach (var target in targets)
                {
                    if (target.IsDead)
                    {
                        continue;
                    }

                    target.StopMove();

                    var tAction = new TargetAction(CombatActionType.TakeHit, target, attacker, skill.Info.Id);
                    tAction.Set(TargetOptions.Result);
                    cap.Add(tAction);

                    // Base damage
                    var damage = mainDamage;

                    // Elementals
                    damage *= attacker.CalculateElementalDamageMultiplier(target);

                    // Splash modifier
                    if (target != mainTarget)
                    {
                        damage *= attacker.GetSplashDamage(weapon);
                    }

                    // Critical Hit
                    var critChance = (i == 1 ? attacker.GetRightCritChance(target.Protection) : attacker.GetLeftCritChance(target.Protection));
                    CriticalHit.Handle(attacker, critChance, ref damage, tAction);

                    // Subtract target def/prot
                    SkillHelper.HandleDefenseProtection(target, ref damage);

                    // Conditions
                    SkillHelper.HandleConditions(attacker, target, ref damage);

                    // Defense
                    Defense.Handle(aAction, tAction, ref damage);

                    // Mana Shield
                    ManaShield.Handle(target, ref damage, tAction);

                    // Heavy Stander
                    // Can only happen on the first hit
                    var pinged = (cap.Hit == 1 && HeavyStander.Handle(attacker, target, ref damage, tAction));

                    // Deal with it!
                    if (damage > 0)
                    {
                        target.TakeDamage(tAction.Damage = damage, attacker);
                        SkillHelper.HandleInjury(attacker, target, damage);
                    }

                    // Knock down on deadly
                    if (target.Conditions.Has(ConditionsA.Deadly))
                    {
                        tAction.Set(TargetOptions.KnockDown);
                        tAction.Stun = GetTargetStun(attacker, weapon, tAction.IsKnockBack);
                    }

                    // Aggro
                    if (target == mainTarget)
                    {
                        target.Aggro(attacker);
                    }

                    // Evaluate caused damage
                    if (!target.IsDead)
                    {
                        if (tAction.SkillId != SkillId.Defense)
                        {
                            target.Stability -= this.GetStabilityReduction(attacker, weapon) / maxHits;

                            // React normal for CombatMastery, knock down if
                            // FH and not dual wield, don't knock at all if dual.
                            if (skill.Info.Id != SkillId.FinalHit)
                            {
                                // Originally we thought you knock enemies back, unless it's a critical
                                // hit, but apparently you knock *down* under normal circumstances.
                                // More research to be done.
                                if (target.IsUnstable && target.Is(RaceStands.KnockBackable))
                                {
                                    //tAction.Set(tAction.Has(TargetOptions.Critical) ? TargetOptions.KnockDown : TargetOptions.KnockBack);
                                    tAction.Set(TargetOptions.KnockDown);
                                }
                            }
                            else if (!attacker.IsDualWielding && !weaponIsKnuckle && target.Is(RaceStands.KnockBackable))
                            {
                                target.Stability = Creature.MinStability;
                                tAction.Set(TargetOptions.KnockDown);
                            }
                        }
                    }
                    else
                    {
                        tAction.Set(TargetOptions.FinishingKnockDown);
                    }

                    // React to knock back
                    if (tAction.IsKnockBack)
                    {
                        attacker.Shove(target, KnockBackDistance);
                        if (target == mainTarget)
                        {
                            aAction.Set(AttackerOptions.KnockBackHit2);
                        }
                    }

                    // Set stun time if not defended, Defense handles the stun
                    // in case the target used it.
                    if (tAction.SkillId != SkillId.Defense)
                    {
                        if (target == mainTarget)
                        {
                            aAction.Stun = GetAttackerStun(attacker, weapon, tAction.IsKnockBack && skill.Info.Id != SkillId.FinalHit);
                        }
                        tAction.Stun = GetTargetStun(attacker, weapon, tAction.IsKnockBack);
                    }

                    if (target == mainTarget)
                    {
                        // Set increased stun if target pinged
                        if (pinged)
                        {
                            aAction.Stun = GetAttackerStun(attacker, weapon, true);
                        }

                        // Second hit doubles stun time for normal hits
                        if (cap.Hit == 2 && !tAction.IsKnockBack && !pinged)
                        {
                            aAction.Stun *= 2;
                        }

                        // Update current weapon
                        SkillHelper.UpdateWeapon(attacker, target, ProficiencyGainType.Melee, weapon);

                        // Consume stamina for weapon
                        var staminaUsage = (weapon != null ? weapon.Data.StaminaUsage : Creature.BareHandStaminaUsage);
                        if (attacker.Stamina < staminaUsage)
                        {
                            Send.Notice(attacker, Localization.Get("Your stamina is too low to fight properly!"));
                        }
                        attacker.Stamina -= staminaUsage;

                        // No second hit if defended, pinged, or knocked back
                        if (tAction.IsKnockBack || tAction.SkillId == SkillId.Defense || pinged)
                        {
                            // Set to 1 to prevent second run
                            maxHits = 1;

                            // Remove dual wield option if last hit doesn't come from
                            // the second weapon. If this isn't done, the client shows
                            // the second hit.
                            if (cap.Hit != 2)
                            {
                                aAction.Options &= ~AttackerOptions.DualWield;
                            }
                        }

                        // Reduce attacker's knockback stun in new combat, to allow
                        // movement after sooner.
                        // It's unknown when exactly this was added, but older EU logs
                        // don't have this packet, so we'll assume it was part of the the
                        // new combat, which's purpose was to be faster.
                        // Sending the packet appears to reset the movement lock, and
                        // officials seem to send this about 1s after the attack, for
                        // an effective 1s movement lock after an attack.
                        // If it's send for non-knockback hits, it can add a delay,
                        // maybe increasing the time of the lock, like for dual-wielding.
                        if (AuraData.FeaturesDb.IsEnabled("CombatSystemRenewal"))
                        {
                            if (tAction.IsKnockBack)
                            {
                                Task.Delay(1000).ContinueWith(_ =>
                                                              Send.CharacterLockUpdate(attacker, 18, 1500));
                            }
                        }
                    }
                }

                // Handle
                cap.Handle();
            }

            return(CombatSkillResult.Okay);
        }
Пример #5
0
        /// <summary>
        /// Handles usage of the skill.
        /// </summary>
        /// <param name="attacker"></param>
        /// <param name="target"></param>
        public void Use(Creature attacker, Creature target)
        {
            // Updating unlock because of the updating lock for pre-renovation
            // Has to be done here because we can't have an updating unlock
            // after the combat action, it resets the stun.
            if (!AuraData.FeaturesDb.IsEnabled("TalentRenovationCloseCombat"))
            {
                attacker.Unlock(Locks.Move, true);
            }

            var skill = attacker.Skills.Get(SkillId.Counterattack);

            var aAction = new AttackerAction(CombatActionType.RangeHit, attacker, target.EntityId);

            aAction.Options |= AttackerOptions.Result | AttackerOptions.KnockBackHit2;

            var tAction = new TargetAction(CombatActionType.CounteredHit2, target, attacker, skill.Info.Id);

            tAction.Options |= TargetOptions.Result | TargetOptions.Smash;

            var cap = new CombatActionPack(attacker, skill.Info.Id);

            cap.Add(aAction, tAction);

            var damage =
                (attacker.GetRndTotalDamage() * (skill.RankData.Var2 / 100f)) +
                (target.GetRndTotalDamage() * (skill.RankData.Var1 / 100f));

            // Elementals
            damage *= attacker.CalculateElementalDamageMultiplier(target);

            // Critical Hit
            var critChance = attacker.GetTotalCritChance(target.Protection) + skill.RankData.Var3;

            CriticalHit.Handle(attacker, critChance, ref damage, tAction, true);

            // Subtract target def/prot
            SkillHelper.HandleDefenseProtection(target, ref damage, true, true);

            // Mana Shield
            ManaShield.Handle(target, ref damage, tAction);

            // Heavy Stander
            HeavyStander.Handle(attacker, target, ref damage, tAction);

            // Deal with it!
            if (damage > 0)
            {
                target.TakeDamage(tAction.Damage = damage, attacker);
                SkillHelper.HandleInjury(attacker, target, damage);
            }

            target.Aggro(attacker);

            if (target.IsDead)
            {
                tAction.Options |= TargetOptions.FinishingKnockDown;
            }

            aAction.Stun = StunTime;
            tAction.Stun = StunTime;

            target.Stability = Creature.MinStability;
            attacker.Shove(target, KnockbackDistance);

            // Update both weapons
            SkillHelper.UpdateWeapon(attacker, target, ProficiencyGainType.Melee, attacker.RightHand, attacker.LeftHand);

            Send.SkillUseStun(attacker, skill.Info.Id, StunTime, 1);

            this.Training(aAction, tAction);

            cap.Handle();
        }
Пример #6
0
        /// <summary>
        /// Uses the skill
        /// </summary>
        /// <param name="attacker"></param>
        /// <param name="skill"></param>
        /// <param name="targetEntityId"></param>
        /// <returns></returns>
        public void Use(Creature attacker, Skill skill, Packet packet)
        {
            // Check for full charge
            if (DateTime.Now < attacker.Temp.ExcaliburPrepareTime.AddMilliseconds(skill.RankData.Var1))             // Not enough time has passed during charging
            {
                Send.SkillUseSilentCancel(attacker);
                Send.Effect(attacker, Effect.Excalibur, ExcaliburEffect.Cancel);
                return;
            }

            // Skill Data
            var skillDamage = skill.RankData.Var2 / 100f;
            var skillLength = (int)skill.RankData.Var3;
            var skillWidth  = (int)skill.RankData.Var4;

            // Get targets in rectangular area
            Position endPos;             // Position on the skill area rectangle opposite of the attacker
            var      targets = SkillHelper.GetTargetableCreaturesInSkillArea(attacker, skillLength, skillWidth, out endPos);

            // TargetProp
            var targetProp = new Prop(280, attacker.RegionId, endPos.X, endPos.Y, Mabi.MabiMath.ByteToRadian(attacker.Direction), 1f, 0f, "single");

            attacker.Region.AddProp(targetProp);

            // Turn to target area
            attacker.TurnTo(endPos);

            // Prepare Combat Actions
            var cap = new CombatActionPack(attacker, skill.Info.Id);

            var targetAreaId = new Location(attacker.RegionId, endPos).ToLocationId();

            var aAction = new AttackerAction(CombatActionType.SpecialHit, attacker, targetAreaId);

            aAction.Set(AttackerOptions.UseEffect);
            aAction.PropId = targetProp.EntityId;
            cap.Add(aAction);

            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 = 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.Delay = 1200;
                cap.Add(tAction);

                // Stop target movement
                target.StopMove();

                var damage = (attacker.GetRndTotalDamage() * skillDamage);

                // Critical Hit
                if (crit)
                {
                    CriticalHit.Handle(attacker, 100, ref damage, tAction);
                }

                // Handle skills and reductions
                SkillHelper.HandleDefenseProtection(target, ref damage);
                Defense.Handle(aAction, tAction, ref damage);
                HeavyStander.Handle(attacker, target, ref damage, tAction);
                SkillHelper.HandleConditions(attacker, target, ref damage);
                ManaShield.Handle(target, ref damage, tAction);

                // Apply Damage
                target.TakeDamage(tAction.Damage = damage, attacker);

                // Aggro
                target.Aggro(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.Excalibur, ExcaliburEffect.Attack, (float)endPos.X, (float)endPos.Y);
            Send.SkillUse(attacker, skill.Info.Id, targetAreaId, 0, 1);

            // Remove skill prop
            attacker.Region.RemoveProp(targetProp);
        }
Пример #7
0
        /// <summary>
        /// Uses the skill
        /// </summary>
        /// <param name="attacker"></param>
        /// <param name="skill"></param>
        /// <param name="targetEntityId"></param>
        /// <returns></returns>
        public CombatSkillResult Use(Creature attacker, Skill skill, long targetEntityId)
        {
            // Get Target
            var initTarget = attacker.Region.GetCreature(targetEntityId);

            // Check Target
            if (initTarget == null)
            {
                return(CombatSkillResult.InvalidTarget);
            }

            var attackerPos   = attacker.StopMove();
            var initTargetPos = initTarget.GetPosition();

            // Check Range
            var range = (int)skill.RankData.Var2;

            if (!attacker.GetPosition().InRange(initTargetPos, range))
            {
                return(CombatSkillResult.OutOfRange);
            }

            // Check for Collisions
            if (attacker.Region.Collisions.Any(attackerPos, initTargetPos))
            {
                return(CombatSkillResult.InvalidTarget);
            }

            initTarget.StopMove();

            // Effects
            Send.Effect(attacker, Effect.TheFakeSpiralSword, TheFakeSpiralSwordEffect.Attack, (DateTime.Now.Ticks / 10000), (byte)1);

            // Skill Use
            Send.SkillUseStun(attacker, skill.Info.Id, AttackerStun, 1);
            skill.Stacks = 0;

            // Prepare Combat Actions
            var cap = new CombatActionPack(attacker, skill.Info.Id);

            var aAction = new AttackerAction(CombatActionType.RangeHit, attacker, targetEntityId);

            aAction.Set(AttackerOptions.KnockBackHit1 | AttackerOptions.KnockBackHit2 | AttackerOptions.Result);
            cap.Add(aAction);

            aAction.Stun = AttackerStun;

            // Get Explosion Radius of Attack
            var explosionRadius = (int)skill.RankData.Var3 / 2;

            // Get Explosion Targets
            var targets = attacker.GetTargetableCreaturesAround(initTargetPos, explosionRadius);

            var rnd = RandomProvider.Get();

            // Get Critical Hit
            var crit = false;

            if (attacker.Skills.Has(SkillId.CriticalHit, SkillRank.RF))
            {
                var critChance = attacker.GetRightCritChance(0);
                crit = (rnd.Next(100) < critChance);
            }

            foreach (var target in targets)
            {
                var tAction = new TargetAction(CombatActionType.TakeHit, target, attacker, skill.Info.Id);
                tAction.Set(TargetOptions.Result);
                tAction.Delay = attackerPos.GetDistance(initTargetPos) / 2;
                cap.Add(tAction);

                // Damage
                var damage = (attacker.GetRndTotalDamage() * (skill.RankData.Var1 / 100f));

                // Critical Hit
                if (crit)
                {
                    CriticalHit.Handle(attacker, 100, ref damage, tAction);
                }

                // Defense and Prot
                SkillHelper.HandleDefenseProtection(target, ref damage);

                // Defense
                Defense.Handle(aAction, tAction, ref damage);

                // Mana Shield
                ManaShield.Handle(target, ref damage, tAction);

                // Heavy Stander
                HeavyStander.Handle(attacker, target, ref damage, tAction);

                // Apply Damage
                target.TakeDamage(tAction.Damage = damage, attacker);

                // Aggro
                target.Aggro(attacker);

                // Stun Time
                tAction.Stun = TargetStun;

                // Death and Knockback
                if (target.Is(RaceStands.KnockDownable))
                {
                    if (target.IsDead)
                    {
                        tAction.Set(TargetOptions.FinishingKnockDown);
                    }
                    else
                    {
                        tAction.Set(TargetOptions.KnockDown);
                    }

                    // Shove
                    if (target == initTarget)
                    {
                        attacker.Shove(target, KnockbackDistance);
                    }
                    else
                    {
                        initTarget.Shove(target, KnockbackDistance);
                    }
                }
            }

            aAction.Creature.Stun = aAction.Stun;
            cap.Handle();

            // User can attack multiple times if attack isn't locked, which will cause them to freeze.
            // This is automatically unlocked by the skill after Use is finished.
            attacker.Lock(Locks.Attack);

            return(CombatSkillResult.Okay);
        }
Пример #8
0
        /// <summary>
        /// Handles using the skill.
        /// </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);
            var rnd     = RandomProvider.Get();

            // Create actions
            var cap = new CombatActionPack(attacker, skill.Info.Id);

            var aAction = new AttackerAction(CombatActionType.Attacker, attacker, targetAreaId);

            aAction.Set(AttackerOptions.Result);
            aAction.Stun = AttackerStun;

            cap.Add(aAction);

            foreach (var target in targets)
            {
                // Check if hit
                var hitChance = this.GetHitChance(attacker, target, skill);
                if (rnd.Next(0, 100) > hitChance)
                {
                    continue;
                }

                target.StopMove();

                var tAction = new TargetAction(CombatActionType.TakeHit, target, attacker, skill.Info.Id);
                tAction.Set(TargetOptions.Result);
                tAction.Delay = 300;

                // Calculate damage
                var damage = this.GetDamage(attacker, skill);

                // Elementals
                damage *= attacker.CalculateElementalDamageMultiplier(target);

                // Handle skills and reductions
                CriticalHit.Handle(attacker, attacker.GetTotalCritChance(0), ref damage, tAction);
                SkillHelper.HandleDefenseProtection(target, ref damage);
                ManaShield.Handle(target, ref damage, tAction);
                HeavyStander.Handle(attacker, target, ref damage, tAction);

                // Clean Hit if not critical
                if (!tAction.Has(TargetOptions.Critical))
                {
                    tAction.Set(TargetOptions.CleanHit);
                }

                // Take damage if any is left
                if (damage > 0)
                {
                    target.TakeDamage(tAction.Damage = damage, attacker);
                    SkillHelper.HandleInjury(attacker, target, damage);
                }

                // Finish if dead, knock down if not defended
                if (target.IsDead)
                {
                    tAction.Set(TargetOptions.KnockDownFinish);
                }
                else
                {
                    tAction.Set(TargetOptions.KnockDown);
                }

                // Anger Management
                if (!target.IsDead)
                {
                    target.Aggro(attacker);
                }

                // Stun & knock down
                tAction.Stun     = CombatMastery.GetTargetStun(attacker.AverageKnockCount, attacker.AverageAttackSpeed, true);
                target.Stability = Creature.MinStability;

                // Add action
                cap.Add(tAction);
            }

            Send.UseMotion(attacker, 10, 1);

            cap.Handle();

            Send.SkillUse(attacker, skill.Info.Id, targetAreaId, unkInt1, unkInt2);
        }
Пример #9
0
        public CombatSkillResult UseWithoutRangeCheck(Creature attacker, Skill skill, long targetEntityId, Creature mainTarget, SkillId interceptingSkillId = SkillId.None)
        {
            //Against Smash
            Skill smash = mainTarget.Skills.Get(SkillId.Smash);

            if (interceptingSkillId == SkillId.None && smash != null && mainTarget.Skills.IsReady(SkillId.Smash))
            {
                interceptingSkillId = SkillId.Smash;
            }

            var rightWeapon = attacker.Inventory.RightHand;
            var leftWeapon  = attacker.Inventory.LeftHand;
            var dualWield   = (rightWeapon != null && leftWeapon != null && leftWeapon.Data.WeaponType != 0 && (leftWeapon.HasTag("/weapon/edged/") || leftWeapon.HasTag("/weapon/blunt/")));

            // Against Combat Mastery
            Skill combatMastery          = mainTarget.Skills.Get(SkillId.CombatMastery);
            var   simultaneousAttackStun = 0;

            if (interceptingSkillId == SkillId.None)
            {
                if (combatMastery != null && (mainTarget.Skills.ActiveSkill == null || mainTarget.Skills.ActiveSkill == combatMastery || mainTarget.Skills.IsReady(SkillId.FinalHit)) && mainTarget.IsInBattleStance && mainTarget.Target == attacker && mainTarget.AttemptingAttack && (!mainTarget.IsStunned || mainTarget.IsKnockedDown))
                {
                    var    attackerStunTime   = CombatMastery.GetAttackerStun(attacker, attacker.RightHand, false);
                    var    mainTargetStunTime = CombatMastery.GetAttackerStun(mainTarget, mainTarget.Inventory.RightHand, false);
                    var    slowestStun        = CombatMastery.GetAttackerStun(1, AttackSpeed.VerySlow, false);
                    var    additionalStun     = slowestStun + (CombatMastery.GetAttackerStun(5, AttackSpeed.VeryFast, false) / 2);                                                                                            //Fastest stun divided by two so that the fastest stun doesn't always beat out the slowest stun.  The addition is so that the subtration (Ex. additionalStun - attackerStunTime) ends in the desired range.
                    var    formulaMultiplier  = 320;                                                                                                                                                                          //Multiplier to keep the result reasonable, found through trial and error?
                    var    formulaEqualizer   = 50;                                                                                                                                                                           //Balances the subtraction to keep the result in a reasonable range and balanced out no matter the order.
                    double chances            = ((((additionalStun - attackerStunTime) / slowestStun) * formulaMultiplier) - (((additionalStun - mainTargetStunTime) / slowestStun) * formulaMultiplier)) + formulaEqualizer; //Probability in percentage that you will not lose.
                    chances = Math2.Clamp(0.0, 99.0, chances);                                                                                                                                                                //Cap the stun, just in case.

                    if (((mainTarget.LastKnockedBackBy == attacker && mainTarget.KnockDownTime > attacker.KnockDownTime && mainTarget.KnockDownTime.AddMilliseconds(mainTargetStunTime) > DateTime.Now ||
                          /*attackerStunTime > initialTargetStunTime && */
                          !Math2.Probability(chances) && !(attacker.LastKnockedBackBy == mainTarget && attacker.KnockDownTime > mainTarget.KnockDownTime && attacker.KnockDownTime.AddMilliseconds(attackerStunTime) > DateTime.Now))))
                    {
                        if (!Math2.Probability(chances))                                        //Probability in percentage that it will be an interception instead of a double hit.  Always in favor of the faster attacker.
                        {
                            if (mainTarget.CanTarget(attacker) && mainTarget.Can(Locks.Attack)) //TODO: Add Hit lock when available.
                            {
                                var skillHandler = ChannelServer.Instance.SkillManager.GetHandler <ICombatSkill>(combatMastery.Info.Id);
                                if (skillHandler == null)
                                {
                                    Log.Error("CombatMastery.Use: Target's skill handler not found for '{0}'.", combatMastery.Info.Id);
                                    return(CombatSkillResult.Okay);
                                }
                                ((CombatMastery)skillHandler).UseWithoutRangeCheck(mainTarget, combatMastery, attacker.EntityId, attacker, SkillId.CombatMastery);
                                return(CombatSkillResult.Okay);
                            }
                        }
                        else
                        {
                            interceptingSkillId = SkillId.CombatMastery;
                            if (mainTarget.CanTarget(attacker) && mainTarget.Can(Locks.Attack))                             //TODO: Add Hit lock when available.
                            {
                                var skillHandler = ChannelServer.Instance.SkillManager.GetHandler <ICombatSkill>(combatMastery.Info.Id);
                                if (skillHandler == null)
                                {
                                    Log.Error("CombatMastery.Use: Target's skill handler not found for '{0}'.", combatMastery.Info.Id);
                                }
                                else
                                {
                                    ((CombatMastery)skillHandler).UseWithoutRangeCheck(mainTarget, combatMastery, attacker.EntityId, attacker, SkillId.CombatMastery);
                                    simultaneousAttackStun = attacker.Stun;
                                    attacker.Stun          = 0;
                                }
                            }
                        }
                    }
                    else
                    {
                        if (Math2.Probability(chances))                         //Probability in percentage that it will be an interception instead of a double hit.  Always in favor of the faster attacker.
                        {
                            interceptingSkillId = SkillId.CombatMastery;
                        }
                        else
                        {
                            interceptingSkillId = SkillId.CombatMastery;
                            if (mainTarget.CanTarget(attacker) && mainTarget.Can(Locks.Attack))                             //TODO: Add Hit lock when available.
                            {
                                var skillHandler = ChannelServer.Instance.SkillManager.GetHandler <ICombatSkill>(combatMastery.Info.Id);
                                if (skillHandler == null)
                                {
                                    Log.Error("CombatMastery.Use: Target's skill handler not found for '{0}'.", combatMastery.Info.Id);
                                }
                                else
                                {
                                    ((CombatMastery)skillHandler).UseWithoutRangeCheck(mainTarget, combatMastery, attacker.EntityId, attacker, SkillId.CombatMastery);
                                    simultaneousAttackStun = attacker.Stun;
                                    attacker.Stun          = 0;
                                }
                            }
                        }
                    }
                }
            }

            attacker.StopMove();
            mainTarget.StopMove();

            // Get targets, incl. splash.
            var targets = new HashSet <Creature>()
            {
                mainTarget
            };

            targets.UnionWith(attacker.GetTargetableCreaturesInCone(mainTarget.GetPosition(), attacker.GetTotalSplashRadius(), attacker.GetTotalSplashAngle()));

            // Counter
            if (Counterattack.Handle(targets, attacker))
            {
                return(CombatSkillResult.Okay);
            }

            var magazine = attacker.Inventory.Magazine;
            var maxHits  = (byte)(attacker.IsDualWielding ? 2 : 1);
            int prevId   = 0;

            var knockedBackTargets = new HashSet <long>();

            for (byte i = 1; i <= maxHits; ++i)
            {
                var weapon          = (i == 1 ? rightWeapon : leftWeapon);
                var weaponIsKnuckle = (weapon != null && weapon.Data.HasTag("/knuckle/"));

                AttackerAction aAction;

                if (interceptingSkillId == SkillId.Smash)
                {
                    aAction = new AttackerAction(CombatActionType.SimultaneousHit, attacker, targetEntityId);
                }
                else if (interceptingSkillId == SkillId.CombatMastery)
                {
                    aAction = new AttackerAction(CombatActionType.SimultaneousHit, attacker, targetEntityId);
                }
                else
                {
                    aAction = new AttackerAction(CombatActionType.Attacker, attacker, targetEntityId);
                }

                aAction.Set(AttackerOptions.Result);

                if (attacker.IsDualWielding)
                {
                    aAction.Set(AttackerOptions.DualWield);
                    aAction.WeaponParameterType = (byte)(i == 1 ? 2 : 1);
                }

                var cap = new CombatActionPack(attacker, skill.Info.Id);
                if (interceptingSkillId != SkillId.Smash)
                {
                    cap.Add(aAction);
                }
                cap.Hit    = i;
                cap.Type   = (attacker.IsDualWielding ? CombatActionPackType.TwinSwordAttack : CombatActionPackType.NormalAttack);
                cap.PrevId = prevId;
                prevId     = cap.Id;

                var mainDamage = (i == 1 ? attacker.GetRndRightHandDamage() : attacker.GetRndLeftHandDamage());

                foreach (var target in targets)
                {
                    // Skip targets that were knocked back, as they aren't in
                    // range anymore.
                    if (knockedBackTargets.Contains(target.EntityId))
                    {
                        continue;
                    }

                    target.StopMove();

                    TargetAction tAction;

                    if (target == mainTarget)
                    {
                        if (interceptingSkillId == SkillId.Smash)
                        {
                            tAction = new TargetAction(CombatActionType.CounteredHit, target, attacker, SkillId.Smash);
                        }
                        else if (interceptingSkillId == SkillId.CombatMastery)
                        {
                            tAction = new TargetAction(CombatActionType.CounteredHit, target, attacker, target.Skills.IsReady(SkillId.FinalHit) ? SkillId.FinalHit : SkillId.CombatMastery);
                        }
                        else
                        {
                            tAction = new TargetAction(CombatActionType.TakeHit, target, attacker, target.Skills.IsReady(SkillId.FinalHit) ? SkillId.FinalHit : SkillId.CombatMastery);
                        }
                    }
                    else
                    {
                        tAction = new TargetAction(CombatActionType.TakeHit, target, attacker, target.Skills.IsReady(SkillId.FinalHit) ? SkillId.FinalHit : SkillId.CombatMastery);
                    }

                    tAction.Set(TargetOptions.Result);

                    cap.Add(tAction);
                    if (target == mainTarget && interceptingSkillId == SkillId.Smash)
                    {
                        cap.Add(aAction);
                    }


                    // Base damage
                    var damage = mainDamage;

                    // Elementals
                    damage *= attacker.CalculateElementalDamageMultiplier(target);

                    // Splash modifier
                    if (target != mainTarget)
                    {
                        damage *= attacker.GetSplashDamage(weapon);
                    }

                    // Critical Hit
                    var critChance = (i == 1 ? attacker.GetRightCritChance(target.Protection) : attacker.GetLeftCritChance(target.Protection));
                    CriticalHit.Handle(attacker, critChance, ref damage, tAction);

                    // Subtract target def/prot
                    SkillHelper.HandleDefenseProtection(target, ref damage);

                    // Conditions
                    SkillHelper.HandleConditions(attacker, target, ref damage);

                    // Defense
                    Defense.Handle(aAction, tAction, ref damage);

                    // Mana Shield
                    ManaShield.Handle(target, ref damage, tAction);

                    // Heavy Stander
                    // Can only happen on the first hit
                    var pinged = (cap.Hit == 1 && HeavyStander.Handle(attacker, target, ref damage, tAction));

                    // Deal with it!
                    if (damage > 0)
                    {
                        target.TakeDamage(tAction.Damage = damage, attacker);
                        SkillHelper.HandleInjury(attacker, target, damage);
                    }

                    // Knock down on deadly
                    if (target.Conditions.Has(ConditionsA.Deadly))
                    {
                        tAction.Set(TargetOptions.KnockDown);
                        tAction.Stun = GetTargetStun(attacker, weapon, tAction.IsKnockBack);
                    }

                    // Aggro
                    if (target == mainTarget)
                    {
                        target.Aggro(attacker);
                    }

                    // Evaluate caused damage
                    if (!target.IsDead)
                    {
                        if (tAction.SkillId != SkillId.Defense)
                        {
                            target.Stability -= this.GetStabilityReduction(attacker, weapon) / maxHits;

                            // React normal for CombatMastery, knock down if
                            // FH and not dual wield, don't knock at all if dual.
                            if (skill.Info.Id != SkillId.FinalHit)
                            {
                                // Originally we thought you knock enemies back, unless it's a critical
                                // hit, but apparently you knock *down* under normal circumstances.
                                // More research to be done.
                                if (target.IsUnstable && target.Is(RaceStands.KnockBackable))
                                {
                                    //tAction.Set(tAction.Has(TargetOptions.Critical) ? TargetOptions.KnockDown : TargetOptions.KnockBack);
                                    tAction.Set(TargetOptions.KnockDown);
                                }
                            }
                            else if (!attacker.IsDualWielding && !weaponIsKnuckle && target.Is(RaceStands.KnockBackable))
                            {
                                target.Stability = Creature.MinStability;
                                tAction.Set(TargetOptions.KnockDown);
                            }
                        }
                    }
                    else
                    {
                        tAction.Set(TargetOptions.FinishingKnockDown);
                    }

                    // React to knock back
                    if (tAction.IsKnockBack)
                    {
                        attacker.Shove(target, KnockBackDistance);
                        if (target == mainTarget)
                        {
                            aAction.Set(AttackerOptions.KnockBackHit2);
                        }

                        knockedBackTargets.Add(target.EntityId);
                    }

                    // Set stun time if not defended, Defense handles the stun
                    // in case the target used it.
                    if (tAction.SkillId != SkillId.Defense)
                    {
                        if (target == mainTarget)
                        {
                            aAction.Stun = GetAttackerStun(attacker, weapon, tAction.IsKnockBack && skill.Info.Id != SkillId.FinalHit);
                        }
                        tAction.Stun = GetTargetStun(attacker, weapon, tAction.IsKnockBack);
                    }

                    if (target == mainTarget)
                    {
                        // Set increased stun if target pinged
                        if (pinged)
                        {
                            aAction.Stun = GetAttackerStun(attacker, weapon, true);
                        }

                        // Second hit doubles stun time for normal hits
                        if (cap.Hit == 2 && !tAction.IsKnockBack && !pinged)
                        {
                            aAction.Stun *= 2;
                        }

                        // Update current weapon
                        SkillHelper.UpdateWeapon(attacker, target, ProficiencyGainType.Melee, weapon);

                        // Consume stamina for weapon
                        var staminaUsage = (rightWeapon != null && rightWeapon.Data.StaminaUsage != 0 ? rightWeapon.Data.StaminaUsage : 0.7f) + (dualWield ? leftWeapon.Data.StaminaUsage : 0f);
                        if (attacker.Stamina < staminaUsage)
                        {
                            Send.Notice(attacker, Localization.Get("Your stamina is too low to fight properly!"));
                        }
                        attacker.Stamina -= staminaUsage;

                        // No second hit if defended, pinged, or knocked back
                        if (tAction.IsKnockBack || tAction.SkillId == SkillId.Defense || pinged)
                        {
                            // Set to 1 to prevent second run
                            maxHits = 1;

                            // Remove dual wield option if last hit doesn't come from
                            // the second weapon. If this isn't done, the client shows
                            // the second hit.
                            if (cap.Hit != 2)
                            {
                                aAction.Options &= ~AttackerOptions.DualWield;
                            }
                        }

                        // Reduce attacker's knockback stun in new combat, to allow
                        // movement after sooner.
                        // It's unknown when exactly this was added, but older EU logs
                        // don't have this packet, so we'll assume it was part of the the
                        // new combat, which's purpose was to be faster.
                        // Sending the packet appears to reset the movement lock, and
                        // officials seem to send this about 1s after the attack, for
                        // an effective 1s movement lock after an attack.
                        // If it's send for non-knockback hits, it can add a delay,
                        // maybe increasing the time of the lock, like for dual-wielding.
                        if (AuraData.FeaturesDb.IsEnabled("CombatSystemRenewal"))
                        {
                            if (tAction.IsKnockBack)
                            {
                                Task.Delay(1000).ContinueWith(_ =>
                                                              Send.CharacterLockUpdate(attacker, 18, 1500));
                            }
                        }
                    }
                }

                // Handle
                cap.Handle();
            }

            attacker.AttemptingAttack = false;
            return(CombatSkillResult.Okay);
        }
Пример #10
0
        /// <summary>
        /// Handles skill usage.
        /// </summary>
        /// <param name="attacker"></param>
        /// <param name="skill"></param>
        /// <param name="targetEntityId"></param>
        /// <returns></returns>
        public override CombatSkillResult Use(Creature attacker, Skill skill, long targetEntityId)
        {
            // Check target
            var target = attacker.Region.GetCreature(targetEntityId);

            if (target == null)
            {
                return(CombatSkillResult.InvalidTarget);
            }

            // Check range
            var targetPosition = target.GetPosition();

            if (!attacker.GetPosition().InRange(targetPosition, attacker.AttackRangeFor(target)))
            {
                return(CombatSkillResult.OutOfRange);
            }

            // Stop movement
            attacker.StopMove();
            target.StopMove();

            // Counter
            if (Counterattack.Handle(target, attacker))
            {
                return(CombatSkillResult.Okay);
            }

            // Prepare combat actions
            var aAction = new AttackerAction(CombatActionType.HardHit, attacker, targetEntityId);

            aAction.Set(AttackerOptions.Result | AttackerOptions.KnockBackHit2);

            var tAction = new TargetAction(CombatActionType.TakeHit, target, attacker, skill.Info.Id);

            tAction.Set(TargetOptions.Result | TargetOptions.Smash);

            var cap = new CombatActionPack(attacker, skill.Info.Id, aAction, tAction);

            // Calculate damage
            var damage = this.GetDamage(attacker, skill);

            // Elementals
            damage *= attacker.CalculateElementalDamageMultiplier(target);

            // Critical Hit
            var critChance = this.GetCritChance(attacker, target, skill);

            CriticalHit.Handle(attacker, critChance, ref damage, tAction);

            // Subtract target def/prot
            SkillHelper.HandleDefenseProtection(target, ref damage);

            // Mana Shield
            ManaShield.Handle(target, ref damage, tAction);

            // Heavy Stander
            HeavyStander.Handle(attacker, target, ref damage, tAction);

            // Apply damage
            if (damage > 0)
            {
                target.TakeDamage(tAction.Damage = damage, attacker);
                SkillHelper.HandleInjury(attacker, target, damage);
            }

            // Aggro
            target.Aggro(attacker);

            if (target.IsDead)
            {
                tAction.Set(TargetOptions.FinishingHit | TargetOptions.Finished);
            }

            // Set Stun/Knockback
            attacker.Stun    = aAction.Stun = StunTime;
            target.Stun      = tAction.Stun = StunTime;
            target.Stability = Creature.MinStability;

            // Set knockbacked position
            attacker.Shove(target, KnockbackDistance);

            // Response
            Send.SkillUseStun(attacker, skill.Info.Id, AfterUseStun, 1);

            // Update both weapons
            SkillHelper.UpdateWeapon(attacker, target, attacker.RightHand, attacker.LeftHand);

            // Action!
            cap.Handle();

            return(CombatSkillResult.Okay);
        }
Пример #11
0
        /// <summary>
        /// Handles skill usage while ignoring range.
        /// </summary>
        /// <param name="attacker"></param>
        /// <param name="skill"></param>
        /// <param name="targetEntityId"></param>
        /// <returns></returns>
        public CombatSkillResult UseWithoutRangeCheck(Creature attacker, Skill skill, long targetEntityId, Creature mainTarget, SkillId interceptingSkillId = SkillId.None)
        {
            // Against Normal Attack
            Skill combatMastery = mainTarget.Skills.Get(SkillId.CombatMastery);

            if (interceptingSkillId == SkillId.None && combatMastery != null && (mainTarget.Skills.ActiveSkill == null || mainTarget.Skills.ActiveSkill == combatMastery || mainTarget.Skills.IsReady(SkillId.FinalHit)) && mainTarget.IsInBattleStance && mainTarget.Target == attacker && mainTarget.AttemptingAttack && (!mainTarget.IsStunned || mainTarget.IsKnockedDown))
            {
                if (mainTarget.CanTarget(attacker) && mainTarget.Can(Locks.Attack))                 //TODO: Add Hit lock when available.
                {
                    var skillHandler = ChannelServer.Instance.SkillManager.GetHandler <ICombatSkill>(combatMastery.Info.Id);
                    if (skillHandler == null)
                    {
                        Log.Error("Smash.Use: Target's skill handler not found for '{0}'.", combatMastery.Info.Id);
                        return(CombatSkillResult.Okay);
                    }
                    ((CombatMastery)skillHandler).UseWithoutRangeCheck(mainTarget, combatMastery, attacker.EntityId, attacker, SkillId.Smash);
                    return(CombatSkillResult.Okay);
                }
            }

            // Against Smash
            Skill smash = mainTarget.Skills.Get(SkillId.Smash);

            if (interceptingSkillId == SkillId.None && smash != null && mainTarget.Skills.IsReady(SkillId.Smash) && mainTarget.IsInBattleStance && mainTarget.Target == attacker && !mainTarget.IsStunned)
            {
                var    attackerStunTime   = CombatMastery.GetAttackerStun(attacker, attacker.RightHand, false);
                var    mainTargetStunTime = CombatMastery.GetAttackerStun(mainTarget, mainTarget.Inventory.RightHand, false);
                var    slowestStun        = CombatMastery.GetAttackerStun(1, AttackSpeed.VerySlow, false);
                var    additionalStun     = slowestStun + (CombatMastery.GetAttackerStun(5, AttackSpeed.VeryFast, false) / 2);                                                                                            //Fastest stun divided by two so that the fastest stun doesn't always beat out the slowest stun.  The addition is so that the subtration (Ex. additionalStun - attackerStunTime) ends in the desired range.
                var    formulaMultiplier  = 320;                                                                                                                                                                          //Multiplier to keep the result reasonable, found through trial and error?
                var    formulaEqualizer   = 50;                                                                                                                                                                           //Balances the subtraction to keep the result in a reasonable range and balanced out no matter the order.
                double chances            = ((((additionalStun - attackerStunTime) / slowestStun) * formulaMultiplier) - (((additionalStun - mainTargetStunTime) / slowestStun) * formulaMultiplier)) + formulaEqualizer; //Probability in percentage that you will not lose.
                chances = Math2.Clamp(0.0, 99.0, chances);                                                                                                                                                                //Cap the stun, just in case.

                if (((mainTarget.LastKnockedBackBy == attacker && mainTarget.KnockDownTime > attacker.KnockDownTime && mainTarget.KnockDownTime.AddMilliseconds(mainTargetStunTime) > DateTime.Now ||
                      /*attackerStunTime > initialTargetStunTime && */
                      !(attacker.LastKnockedBackBy == mainTarget && attacker.KnockDownTime > mainTarget.KnockDownTime && attacker.KnockDownTime.AddMilliseconds(attackerStunTime) > DateTime.Now))))
                {
                    if (mainTarget.CanTarget(attacker) && mainTarget.Can(Locks.Attack))                     //TODO: Add Hit lock when available.
                    {
                        var skillHandler = ChannelServer.Instance.SkillManager.GetHandler <ICombatSkill>(smash.Info.Id);
                        if (skillHandler == null)
                        {
                            Log.Error("Smash.Use: Target's skill handler not found for '{0}'.", smash.Info.Id);
                            return(CombatSkillResult.Okay);
                        }
                        ((Smash)skillHandler).UseWithoutRangeCheck(mainTarget, smash, attacker.EntityId, attacker, SkillId.Smash);
                        return(CombatSkillResult.Okay);
                    }
                }
                else
                {
                    interceptingSkillId = SkillId.Smash;
                }
            }

            // Stop movement
            attacker.StopMove();
            mainTarget.StopMove();

            // Get targets, incl. splash.
            // Splash happens from r5 onwards, but we'll base it on Var4,
            // which is the splash damage and first != 0 on r5.
            var targets = new HashSet <Creature>()
            {
                mainTarget
            };

            if (skill.RankData.Var4 != 0)
            {
                targets.UnionWith(attacker.GetTargetableCreaturesInCone(mainTarget.GetPosition(), attacker.GetTotalSplashRadius(), attacker.GetTotalSplashAngle()));
            }

            // Counter
            if (Counterattack.Handle(targets, attacker))
            {
                return(CombatSkillResult.Okay);
            }

            // Prepare combat actions
            var aAction = new AttackerAction(CombatActionType.HardHit, attacker, targetEntityId);

            aAction.Set(AttackerOptions.Result | AttackerOptions.KnockBackHit2);
            aAction.Stun = StunTime;

            var cap = new CombatActionPack(attacker, skill.Info.Id);

            // Calculate damage
            var mainDamage = this.GetDamage(attacker, skill);

            foreach (var target in targets)
            {
                // Stop movement
                target.StopMove();

                TargetAction tAction;
                if (target == mainTarget)
                {
                    if (interceptingSkillId == SkillId.Smash)
                    {
                        aAction.Options |= AttackerOptions.Result;
                        tAction          = new TargetAction(CombatActionType.CounteredHit, target, attacker, SkillId.Smash);
                    }
                    else
                    {
                        tAction = new TargetAction(CombatActionType.TakeHit, target, attacker, skill.Info.Id);
                    }
                }
                else
                {
                    tAction = new TargetAction(CombatActionType.TakeHit, target, attacker, skill.Info.Id);
                }

                tAction.Set(TargetOptions.Result | TargetOptions.Smash);

                cap.Add(tAction);
                if (target == mainTarget)
                {
                    cap.Add(aAction);
                }

                // Damage
                var damage = mainDamage;

                // Elementals
                damage *= attacker.CalculateElementalDamageMultiplier(target);

                // Splash modifier
                if (target != mainTarget)
                {
                    damage *= (skill.RankData.Var4 / 100f);
                }

                // Critical Hit
                var critChance = this.GetCritChance(attacker, target, skill);
                CriticalHit.Handle(attacker, critChance, ref damage, tAction);

                // Subtract target def/prot
                SkillHelper.HandleDefenseProtection(target, ref damage);

                // Conditions
                SkillHelper.HandleConditions(attacker, target, ref damage);

                // Mana Shield
                ManaShield.Handle(target, ref damage, tAction);

                // Heavy Stander
                HeavyStander.Handle(attacker, target, ref damage, tAction);

                // Apply damage
                if (damage > 0)
                {
                    target.TakeDamage(tAction.Damage = damage, attacker);
                    SkillHelper.HandleInjury(attacker, target, damage);
                }

                // Aggro
                if (target == mainTarget)
                {
                    target.Aggro(attacker);
                }

                if (target.IsDead)
                {
                    tAction.Set(TargetOptions.FinishingHit | TargetOptions.Finished);
                }

                // Set Stun/Knockback
                target.Stun      = tAction.Stun = StunTime;
                target.Stability = Creature.MinStability;

                // Set knockbacked position
                attacker.Shove(target, KnockbackDistance);
            }

            // Response
            Send.SkillUseStun(attacker, skill.Info.Id, AfterUseStun, 1);

            // Update both weapons
            SkillHelper.UpdateWeapon(attacker, mainTarget, ProficiencyGainType.Melee, attacker.RightHand, attacker.LeftHand);

            // Action!
            cap.Handle();

            return(CombatSkillResult.Okay);
        }