Exemple #1
0
        /// <summary>
        /// Handles knock back/stun/death.
        /// </summary>
        protected virtual void HandleKnockBack(Creature attacker, Creature target, TargetAction tAction)
        {
            if (target.IsDead)
            {
                tAction.Set(TargetOptions.FinishingKnockDown);
                attacker.Shove(target, KnockbackDistance);
            }
            else
            {
                // If knocked down, instant recovery,
                // if repeat hit, knock down,
                // otherwise potential knock back.

                if (target.IsKnockedDown)
                {
                    tAction.Stun = 0;
                }
                else if (target.IsUnstable)
                {
                    tAction.Set(TargetOptions.KnockDown);
                }
                else
                {
                    target.Stability -= StabilityReduction;
                    if (target.IsUnstable)
                    {
                        tAction.Set(TargetOptions.KnockBack);
                        attacker.Shove(target, KnockbackDistance);
                    }
                }
            }
        }
Exemple #2
0
		/// <summary>
		/// Handles knock back/stun/death.
		/// </summary>
		protected override void HandleKnockBack(Creature attacker, Creature target, TargetAction tAction, bool overcharge)
		{
			attacker.Shove(target, KnockbackDistance);
			if (target.IsDead)
				tAction.Set(TargetOptions.FinishingKnockDown);
			else
				tAction.Set(TargetOptions.KnockDown);
		}
Exemple #3
0
		/// <summary>
		/// Handles explosion.
		/// </summary>
		/// <param name="attacker"></param>
		/// <param name="skill"></param>
		/// <param name="fireballProp"></param>
		private void Impact(Creature attacker, Skill skill, Prop fireballProp)
		{
			var regionId = attacker.RegionId;
			var propPos = fireballProp.GetPosition();
			var targetLocation = new Location(regionId, propPos);
			var targets = attacker.GetTargetableCreaturesAround(propPos, ExplosionRadius);

			var aAction = new AttackerAction(CombatActionType.SpecialHit, attacker, targetLocation.ToLocationId(), skill.Info.Id);
			aAction.Set(AttackerOptions.UseEffect);
			aAction.PropId = fireballProp.EntityId;

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

			foreach (var target in targets)
			{
				target.StopMove();

				var tAction = new TargetAction(CombatActionType.TakeHit, target, attacker, skill.Info.Id);
				tAction.Set(TargetOptions.Result | TargetOptions.KnockDown);
				tAction.Stun = TargetStun;
				tAction.Delay = 200;
				tAction.EffectFlags = EffectFlags.SpecialRangeHit;

				cap.Add(tAction);

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

				// Elements
				damage *= this.GetElementalDamageMultiplier(attacker, target);

				// Critical Hit
				var critChance = attacker.GetTotalCritChance(target.Protection, true);
				CriticalHit.Handle(attacker, critChance, ref damage, tAction);

				// Reduce damage
				SkillHelper.HandleMagicDefenseProtection(target, ref damage);
				SkillHelper.HandleConditions(attacker, target, ref damage);
				ManaShield.Handle(target, ref damage, tAction);
				ManaDeflector.Handle(attacker, target, ref damage, tAction);

				// Deal damage
				if (damage > 0)
					target.TakeDamage(tAction.Damage = damage, attacker);
				target.Aggro(attacker);

				// Knockback
				target.Stability = Creature.MinStability;
				target.GetShoved(fireballProp, KnockbackDistance);
				if (target.IsDead)
					tAction.Set(TargetOptions.FinishingKnockDown);

				this.Train(skill, tAction);
			}

			cap.Handle();
		}
Exemple #4
0
 /// <summary>
 /// Handles knock back/stun/death.
 /// </summary>
 protected override void HandleKnockBack(Creature attacker, Creature target, TargetAction tAction)
 {
     attacker.Shove(target, KnockbackDistance);
     if (target.IsDead)
     {
         tAction.Set(TargetOptions.FinishingKnockDown);
     }
     else
     {
         tAction.Set(TargetOptions.KnockDown);
     }
 }
Exemple #5
0
        /// <summary>
        /// Checks if attacker has Critical Hit and applies crit bonus
        /// by chance. Also sets the target action's critical option if a
        /// crit happens.
        /// </summary>
        /// <param name="attacker"></param>
        /// <param name="critChance"></param>
        /// <param name="damage"></param>
        /// <param name="tAction"></param>
        public static void Handle(Creature attacker, float critChance, ref float damage, TargetAction tAction, bool bypassNoviceCheck = false)
        {
            // Check if attacker actually has critical hit
            var critSkill = attacker.Skills.Get(SkillId.CriticalHit);

            if (critSkill == null || (critSkill.Info.Rank == SkillRank.Novice && !bypassNoviceCheck))
            {
                return;
            }

            // Cap crit chance at 30%
            critChance = Math2.Clamp(0, 30, critChance);

            // Cancel if crit doesn't happen
            if (RandomProvider.Get().NextDouble() * 100 >= critChance)
            {
                return;
            }

            // Add crit bonus
            var bonus = critSkill.RankData.Var1 / 100f;

            damage = damage + (damage * bonus);

            // Set target option
            tAction.Set(TargetOptions.Critical);
        }
Exemple #6
0
		/// <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();
		}
Exemple #7
0
		/// <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 target)
		{
			attacker.StopMove();
			target.StopMove();

			// Create actions
			var aAction = new AttackerAction(CombatActionType.RangeHit, attacker, target.EntityId);
			aAction.Set(AttackerOptions.Result);

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

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

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

			// Elements
			damage *= this.GetElementalDamageMultiplier(attacker, target);

			// Reduce damage
			SkillHelper.HandleMagicDefenseProtection(target, ref damage);
			ManaShield.Handle(target, ref damage, tAction);
			ManaDeflector.Handle(attacker, target, ref damage, tAction);

			// Deal damage
			if (damage > 0)
				target.TakeDamage(tAction.Damage = damage, attacker);
			target.Aggro(attacker);

			// Knock down on deadly
			if (target.Conditions.Has(ConditionsA.Deadly))
			{
				tAction.Set(TargetOptions.KnockDown);
				tAction.Stun = TargetStun;
			}

			// Death/Knockback
			attacker.Shove(target, KnockbackDistance);
			if (target.IsDead)
				tAction.Set(TargetOptions.FinishingKnockDown);
			else
				tAction.Set(TargetOptions.KnockDown);

			// Override stun set by defense
			aAction.Stun = AttackerStun;

			Send.Effect(attacker, Effect.UseMagic, EffectSkillName);
			Send.SkillUseStun(attacker, skill.Info.Id, aAction.Stun, 1);

			skill.Stacks = 0;

			cap.Handle();
		}
Exemple #8
0
        /// <summary>
        /// Bolt specific use code.
        /// </summary>
        /// <param name="attacker"></param>
        /// <param name="skill"></param>
        /// <param name="target"></param>
        protected virtual void UseSkillOnTarget(Creature attacker, Skill skill, Creature target)
        {
            target.StopMove();

            // Create actions
            var aAction = new AttackerAction(CombatActionType.RangeHit, attacker, skill.Info.Id, target.EntityId);

            aAction.Set(AttackerOptions.Result);

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

            tAction.Set(TargetOptions.Result);
            tAction.Stun = TargetStun;

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

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

            // Reduce damage
            if (this.Defendable)
            {
                Defense.Handle(aAction, tAction, ref damage);
            }
            SkillHelper.HandleMagicDefenseProtection(target, ref damage);
            ManaShield.Handle(target, ref damage, tAction);

            // Deal damage
            if (damage > 0)
            {
                target.TakeDamage(tAction.Damage = damage, attacker);
            }
            target.Aggro(attacker);

            // Death/Knockback
            this.HandleKnockBack(attacker, target, 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();
        }
Exemple #9
0
		/// <summary>
		/// Checks if attacker has Critical Hit and applies crit bonus
		/// by chance. Also sets the target action's critical option if a
		/// crit happens.
		/// </summary>
		/// <param name="attacker"></param>
		/// <param name="critChance"></param>
		/// <param name="damage"></param>
		/// <param name="tAction"></param>
		public static void Handle(Creature attacker, float critChance, ref float damage, TargetAction tAction, bool bypassNoviceCheck = false)
		{
			// Check if attacker actually has critical hit
			var critSkill = attacker.Skills.Get(SkillId.CriticalHit);
			if (critSkill == null || (critSkill.Info.Rank == SkillRank.Novice && !bypassNoviceCheck))
				return;

			// Cancel if crit doesn't happen
			if (RandomProvider.Get().Next(100) >= critChance)
				return;

			// Add crit bonus
			var bonus = critSkill.RankData.Var1 / 100f;
			damage = damage + (damage * bonus);

			// Set target option
			tAction.Set(TargetOptions.Critical);
		}
Exemple #10
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 target = attacker.Region.GetCreature(targetEntityId);
			if (target == null)
				return CombatSkillResult.InvalidTarget;

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

			var aAction = new AttackerAction(CombatActionType.RangeHit, attacker, skill.Info.Id, targetEntityId);
			aAction.Set(AttackerOptions.Result);
			aAction.Stun = AttackerStun;
			cap.Add(aAction);

			// Hit by chance
			var chance = attacker.AimMeter.GetAimChance(target);
			var rnd = RandomProvider.Get();
			if (rnd.NextDouble() * 100 < chance)
			{
				target.StopMove();

				aAction.Set(AttackerOptions.KnockBackHit2);

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

				// TODO: Splash damage

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

				// More damage with fire arrow
				if (attacker.Temp.FireArrow)
					damage *= FireBonus;

				// Critical Hit
				var critChance = attacker.GetRightCritChance(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);

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

				// TODO: We have to calculate knockback distance right
				// TODO: Target with Defense and shield shouldn't be knocked back
				attacker.Shove(target, KnockBackDistance);

				// Aggro
				target.Aggro(attacker);

				tAction.Set(TargetOptions.KnockDownFinish);

				if (target.IsDead)
				{
					aAction.Set(AttackerOptions.KnockBackHit1);
					tAction.Set(TargetOptions.Finished);
				}
			}
			else
			{
				aAction.Set(AttackerOptions.Missed);
			}

			// Reduce arrows
			if (attacker.Magazine != null && !ChannelServer.Instance.Conf.World.InfiniteArrows)
				attacker.Inventory.Decrement(attacker.Magazine);

			// Disable fire arrow effect
			if (attacker.Temp.FireArrow)
				Send.Effect(attacker, Effect.FireArrow, false);

			// "Cancels" the skill
			// 800 = old load time? == aAction.Stun? Varies? Doesn't seem to be a stun.
			Send.SkillUse(attacker, skill.Info.Id, 800, 1);

			cap.Handle();

			return CombatSkillResult.Okay;
		}
Exemple #11
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;
		}
Exemple #12
0
        /// <summary>
        /// Handles initial bolts.
        /// </summary>
        private void Bolts(Creature attacker, Skill skill, int stacks, Creature mainTarget, List <Creature> targets, int thunderboltDelay)
        {
            // Combat action
            var aAction = new AttackerAction(CombatActionType.RangeHit, attacker, mainTarget.EntityId);

            aAction.Set(AttackerOptions.Result);
            aAction.Stun = (short)thunderboltDelay;

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

            foreach (var target in targets)
            {
                target.StopMove();
                target.Aggro(attacker);

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

                var damage = this.GetBoltDamage(attacker, skill, stacks);

                // Critical Hit
                var critChance = attacker.GetTotalCritChance(target.Protection, true);
                CriticalHit.Handle(attacker, critChance, ref damage, tAction);

                // Reduce damage
                Defense.Handle(aAction, tAction, ref damage);
                SkillHelper.HandleMagicDefenseProtection(target, ref damage);
                SkillHelper.HandleConditions(attacker, target, ref damage);
                ManaShield.Handle(target, ref damage, tAction);

                // Mana Deflector
                var mdResult       = ManaDeflector.Handle(attacker, target, ref damage, tAction);
                var delayReduction = mdResult.DelayReduction;
                var pinged         = mdResult.Pinged;

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

                // Reduce stun, based on ping
                if (pinged && delayReduction > 0)
                {
                    tAction.Stun = (short)Math.Max(0, tAction.Stun - (tAction.Stun / 100 * delayReduction));
                }

                // Death/Knockback
                if (target.IsDead)
                {
                    tAction.Set(TargetOptions.FinishingKnockDown);
                }
                else
                {
                    // If knocked down, instant recovery,
                    // if repeat hit, knock down,
                    // otherwise potential knock back.
                    if (target.IsKnockedDown)
                    {
                        tAction.Stun = 0;
                    }
                    else if (target.Stability < MinStability)
                    {
                        tAction.Set(TargetOptions.KnockDown);
                    }
                    else
                    {
                        var stabilityReduction = StabilityReduction;

                        if (delayReduction > 0)
                        {
                            stabilityReduction = (short)Math.Max(0, stabilityReduction - (stabilityReduction / 100 * delayReduction));
                        }

                        target.Stability -= stabilityReduction;

                        if (target.IsUnstable)
                        {
                            tAction.Set(TargetOptions.KnockBack);
                        }
                    }
                }

                cap.Add(tAction);

                this.Train(skill, tAction);
            }

            cap.Handle();
        }
Exemple #13
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 target = attacker.Region.GetCreature(targetEntityId);
			if (target == null)
				return CombatSkillResult.InvalidTarget;

			// "Cancels" the skill
			// 800 = old load time? == aAction.Stun? Varies? Doesn't seem to be a stun.
			Send.SkillUse(attacker, skill.Info.Id, AttackerStun, 1);

			var chance = attacker.AimMeter.GetAimChance(target);
			var rnd = RandomProvider.Get().NextDouble() * 100;
			var successfulHit = (rnd < chance);

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

			var aAction = new AttackerAction(CombatActionType.RangeHit, attacker, targetEntityId);
			aAction.Set(AttackerOptions.Result);
			aAction.Stun = AttackerStun;
			cap.Add(aAction);

			// Target action if hit
			if (successfulHit)
			{
				target.StopMove();

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

				cap.Add(tAction);

				// Damage
				// Formula unofficial, but it kinda matches what you would
				// expect from the skill, and what players believed the damage
				// to be, back in G2.
				// bonus = (100 - (6 - stacks) * 5 + rank, +var2 on last shot
				// I'm using rank instead of Var1, which goes from 1-15 in
				// AR2, so AR1 gets a little bonus as well, as AR1's Var1 and
				// 2 are 0.
				// With this formula, the bonus range (1st shot rF vs 5th shot
				// r1) is 76~110% for AR1, and 76~140% for AR2.
				var bonus = 100f - (6 - skill.Stacks) * 5f + (byte)skill.Info.Rank;
				if (skill.Stacks == 1)
					bonus += skill.RankData.Var2;

				var damage = attacker.GetRndRangedDamage() * (bonus / 100f);

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

				// More damage with fire arrow
				if (attacker.Temp.FireArrow)
					damage *= FireBonus;

				// Critical Hit
				var critChance = attacker.GetRightCritChance(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);

				// Natural Shield
				var delayReduction = NaturalShield.Handle(attacker, target, ref damage, tAction);

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

				// Aggro
				target.Aggro(attacker);

				// Knock down on deadly
				if (target.Conditions.Has(ConditionsA.Deadly))
					tAction.Set(TargetOptions.KnockDown);

				// Death/Knockback
				if (target.IsDead)
				{
					tAction.Set(TargetOptions.FinishingKnockDown);
				}
				else
				{
					// Insta-recover in knock down
					if (target.IsKnockedDown)
					{
						tAction.Stun = 0;
					}
					// Knock down if hit repeatedly
					else if (target.Stability < 30)
					{
						tAction.Set(TargetOptions.KnockDown);
					}
					// Normal stability reduction
					else
					{
						var stabilityReduction = StabilityReduction;

						// Reduce reduction, based on ping
						// According to the Wiki, "the Knockdown Gauge
						// [does not] build up", but it's still possible
						// to knock back with repeated hits. The stability
						// reduction is probably reduced, just like stun.
						if (delayReduction > 0)
							stabilityReduction = (short)Math.Max(0, stabilityReduction - (stabilityReduction / 100 * delayReduction));

						target.Stability -= stabilityReduction;
						if (target.IsUnstable)
						{
							tAction.Set(TargetOptions.KnockBack);
						}
					}
				}

				// Knock Back
				if (tAction.IsKnockBack)
					attacker.Shove(target, KnockBackDistance);

				// Reduce stun, based on ping
				if (delayReduction > 0)
					tAction.Stun = (short)Math.Max(0, tAction.Stun - (tAction.Stun / 100 * delayReduction));
			}

			// Skill training
			if (skill.Info.Rank == SkillRank.RF)
				skill.Train(1); // Try attacking with Arrow Revolver.

			// Reduce arrows
			if (attacker.Magazine != null && !ChannelServer.Instance.Conf.World.InfiniteArrows && !attacker.Magazine.HasTag("/unlimited_arrow/"))
				attacker.Inventory.Decrement(attacker.Magazine);

			// Reduce stack
			skill.Stacks--;

			// Handle
			cap.Handle();

			// Disable fire arrow effect
			if (attacker.Temp.FireArrow)
				Send.Effect(attacker, Effect.FireArrow, false);

			return CombatSkillResult.Okay;
		}
Exemple #14
0
        /// <summary>
        /// Uses WM, attacking targets.
        /// </summary>
        /// <param name="attacker"></param>
        /// <param name="skill"></param>
        /// <param name="packet"></param>
        public void Use(Creature attacker, Skill skill, Packet packet)
        {
            var targetAreaId = packet.GetLong();
            var unkInt1      = packet.GetInt();
            var unkInt2      = packet.GetInt();

            var range   = this.GetRange(attacker, skill);
            var targets = attacker.GetTargetableCreaturesInRange(range);

            // 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 and crit
                var damage     = attacker.GetRndTotalDamage();
                var critChance = attacker.CriticalBase;

                damage *= skill.RankData.Var1 / 100f;

                // Handle skills and reductions
                CriticalHit.Handle(attacker, critChance, 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.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);
                }

                // 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);
            }

            // Spin it~
            Send.UseMotion(attacker, 8, 4);

            cap.Handle();

            Send.SkillUse(attacker, skill.Info.Id, targetAreaId, unkInt1, unkInt2);

            skill.Stacks = 0;
        }
Exemple #15
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, true);
            var rnd     = RandomProvider.Get();

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

            var aAction = new AttackerAction(CombatActionType.Attacker, attacker, skill.Info.Id, 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);

                // Handle skills and reductions
                CriticalHit.Handle(attacker, attacker.GetTotalCritChance(0), ref damage, tAction);
                SkillHelper.HandleDefenseProtection(target, ref damage);
                ManaShield.Handle(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);
                }

                // 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);
        }
Exemple #16
0
        /// <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, 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)));

            // 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
                Defense.Handle(aAction, tAction, ref targetDamage);
                SkillHelper.HandleMagicDefenseProtection(target, ref targetDamage);
                ManaShield.Handle(target, ref targetDamage, tAction);

                // Deal damage
                if (targetDamage > 0)
                {
                    target.TakeDamage(tAction.Damage = targetDamage, attacker);
                }

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

                // Death/Knockback
                var overcharge = (skill.Stacks > targets.Count);
                this.HandleKnockBack(attacker, target, tAction, overcharge);

                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();
        }
Exemple #17
0
        /// <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 target)
        {
            attacker.StopMove();
            target.StopMove();

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

            aAction.Set(AttackerOptions.Result);

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

            tAction.Set(TargetOptions.Result);
            tAction.Stun = TargetStun;

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

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

            // Elements
            damage *= this.GetElementalDamageMultiplier(attacker, target);

            // Critical Hit
            var critChance = attacker.GetTotalCritChance(target.Protection, true);

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

            // Reduce damage
            Defense.Handle(aAction, tAction, ref damage);
            SkillHelper.HandleMagicDefenseProtection(target, ref damage);
            ManaShield.Handle(target, ref damage, tAction);

            // Mana Deflector
            var delayReduction = ManaDeflector.Handle(attacker, target, ref damage, tAction);

            // Deal damage
            if (damage > 0)
            {
                target.TakeDamage(tAction.Damage = damage, attacker);
            }
            target.Aggro(attacker);

            // Knock down on deadly
            if (target.Conditions.Has(ConditionsA.Deadly))
            {
                tAction.Set(TargetOptions.KnockDown);
                tAction.Stun = TargetStun;
            }

            // Reduce stun, based on ping
            if (delayReduction > 0)
            {
                tAction.Stun = (short)Math.Max(0, tAction.Stun - (tAction.Stun / 100 * delayReduction));
            }

            // Death/Knockback
            if (target.IsDead)
            {
                tAction.Set(TargetOptions.FinishingKnockDown);
            }
            else
            {
                // If knocked down, instant recovery,
                // if repeat hit, knock down,
                // otherwise potential knock back.
                if (target.IsKnockedDown)
                {
                    tAction.Stun = 0;
                }
                else if (target.Stability < MinStability)
                {
                    tAction.Set(TargetOptions.KnockDown);
                }
                else
                {
                    var stabilityReduction = StabilityReduction;

                    // Reduce reduction, based on ping
                    // While the Wiki says that "the Knockdown Gauge [does not]
                    // build up", tests show that it does. However, it's
                    // reduced, assumedly based on the MD rank.
                    if (delayReduction > 0)
                    {
                        stabilityReduction = (short)Math.Max(0, stabilityReduction - (stabilityReduction / 100 * delayReduction));
                    }

                    target.Stability -= stabilityReduction;

                    if (target.IsUnstable)
                    {
                        tAction.Set(TargetOptions.KnockBack);
                    }
                }
            }

            if (tAction.IsKnockBack)
            {
                attacker.Shove(target, KnockbackDistance);
            }

            // Override stun set by defense
            aAction.Stun = AttackerStun;

            Send.Effect(attacker, Effect.UseMagic, EffectSkillName);
            Send.SkillUseStun(attacker, skill.Info.Id, aAction.Stun, 1);

            skill.Stacks--;

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

            cap.Handle();
        }
Exemple #18
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 dualWield = (rightWeapon != null && leftWeapon != null && leftWeapon.Data.WeaponType != 0);
			var maxHits = (byte)(dualWield ? 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, skill.Info.Id, 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 = (dualWield ? CombatActionPackType.TwinSwordAttack : CombatActionPackType.NormalAttack);
				cap.PrevId = prevId;
				prevId = cap.Id;

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

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

				// 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);

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

				// 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 (!dualWield && !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);

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

				// Set stun time
				if (tAction.SkillId != SkillId.Defense)
				{
					aAction.Stun = GetAttackerStun(attacker, weapon, tAction.IsKnockBack && skill.Info.Id != SkillId.FinalHit);
					tAction.Stun = GetTargetStun(attacker, weapon, tAction.IsKnockBack);
				}

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

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

				cap.Handle();

				// No second hit if target was knocked back
				if (tAction.IsKnockBack)
					break;
			}

			return CombatSkillResult.Okay;
		}
Exemple #19
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 mainTarget = attacker.Region.GetCreature(targetEntityId);
			if (mainTarget == null)
				return CombatSkillResult.InvalidTarget;

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

			var aAction = new AttackerAction(CombatActionType.RangeHit, attacker, targetEntityId);
			aAction.Set(AttackerOptions.Result);
			aAction.Stun = AttackerStun;
			cap.Add(aAction);

			// Hit by chance
			var chance = attacker.AimMeter.GetAimChance(mainTarget);
			var rnd = RandomProvider.Get();
			if (rnd.NextDouble() * 100 < chance)
			{
				aAction.Set(AttackerOptions.KnockBackHit2);

				// 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)
				{
					var targetPosition = mainTarget.GetPosition();
					var direction = attacker.GetPosition().GetDirection(targetPosition);
					targets.UnionWith(attacker.GetTargetableCreaturesInCone(targetPosition, direction, skill.RankData.Var5, skill.RankData.Var6));
				}

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

				foreach (var target in targets)
				{
					var tAction = new TargetAction(CombatActionType.TakeHit, target, attacker, skill.Info.Id);
					tAction.Set(TargetOptions.Result | TargetOptions.CleanHit);
					tAction.Stun = TargetStun;
					cap.Add(tAction);

					// Damage
					var damage = mainDamage;

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

					// More damage with fire arrow
					// XXX: Does this affect the element?
					if (attacker.Temp.FireArrow)
						damage *= FireBonus;

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

					// Critical Hit
					var critChance = attacker.GetRightCritChance(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);

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

					// Natural Shield
					// Ignore delay reduction, as knock downs shouldn't be shortened
					NaturalShield.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
					// If target is using a shield and defense, don't KD.
					var targetLeftHand = target.LeftHand;
					if (tAction.SkillId != SkillId.Defense || targetLeftHand == null || !targetLeftHand.IsShield)
					{
						// TODO: We have to calculate knockback distance right
						attacker.Shove(target, KnockBackDistance);
						tAction.Set(TargetOptions.KnockDownFinish);
					}

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

					if (target.IsDead)
					{
						tAction.Set(TargetOptions.Finished);
						if (target == mainTarget)
							aAction.Set(AttackerOptions.KnockBackHit1);
					}
				}
			}
			else
			{
				aAction.Set(AttackerOptions.Missed);
			}

			// Update current weapon
			SkillHelper.UpdateWeapon(attacker, mainTarget, ProficiencyGainType.Ranged, attacker.RightHand);

			// Reduce arrows
			if (attacker.Magazine != null && !ChannelServer.Instance.Conf.World.InfiniteArrows && !attacker.Magazine.HasTag("/unlimited_arrow/"))
				attacker.Inventory.Decrement(attacker.Magazine);

			// Disable fire arrow effect
			if (attacker.Temp.FireArrow)
				Send.Effect(attacker, Effect.FireArrow, false);

			// "Cancels" the skill
			// 800 = old load time? == aAction.Stun? Varies? Doesn't seem to be a stun.
			Send.SkillUse(attacker, skill.Info.Id, 800, 1);

			cap.Handle();

			return CombatSkillResult.Okay;
		}
Exemple #20
0
        /// <summary>
        /// Uses the skill
        /// </summary>
        /// <param name="attacker"></param>
        /// <param name="skill"></param>
        /// <param name="packet"></param>
        public void UseSkill(Creature attacker, Skill skill, long targetEntityId)
        {
            var target = attacker.Region.GetCreature(targetEntityId);

            var attackerPos = attacker.GetPosition();
            var targetPos   = target.GetPosition();

            // Check target + collisions
            if (target == null || attacker.Region.Collisions.Any(attackerPos, targetPos))
            {
                Send.SkillUseSilentCancel(attacker);
                return;
            }

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

            Send.SkillUseEntity(attacker, skill.Info.Id, targetEntityId);
            skill.State = SkillState.Used;

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

            // Defense/Protection decrease on target
            var debuffChance = (int)skill.RankData.Var6;
            var defDecrease  = (int)skill.RankData.Var3;
            var protDecrease = (int)skill.RankData.Var4;

            var extra = new MabiDictionary();

            extra.SetShort("NEW_DEF", (short)defDecrease);
            extra.SetShort("NEW_PROT", (short)protDecrease);
            extra.SetLong("DDP_CHAR", attacker.EntityId);
            extra.SetShort("DDP_SKILL", (short)skill.Info.Id);

            var rnd = RandomProvider.Get();

            if (rnd.NextDouble() * 100 < debuffChance)
            {
                Send.Effect(target, Effect.SpinningUppercutDebuff, (short)skill.Info.Id, 0, defDecrease, protDecrease);
                target.Conditions.Activate(ConditionsC.DefProtectDebuff, extra);
                attacker.Temp.SpinningUppercutDebuffApplied = true;
            }

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

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

            aAction.Set(AttackerOptions.Result);

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

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

            cap.Add(aAction, tAction);

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

            // Chain Mastery Damage Bonus
            var chainMasterySkill = attacker.Skills.Get(SkillId.ChainMastery);
            var damageBonus       = (chainMasterySkill == null ? 0 : chainMasterySkill.RankData.Var1);

            damage += damage * (damageBonus / 100f);

            // Master Title - Damage +20%
            if (attacker.Titles.SelectedTitle == skill.Data.MasterTitle)
            {
                damage += (damage * 0.2f);
            }

            // Critical Hit
            var critChance = attacker.GetRightCritChance(target.Protection);

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

            // Handle skills and reductions
            SkillHelper.HandleDefenseProtection(target, 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 Times
            tAction.Stun = TargetStun;
            aAction.Stun = AttackerStun;

            // Death and Knockback
            if (target.IsDead)
            {
                if (target.Is(RaceStands.KnockDownable))
                {
                    tAction.Set(TargetOptions.FinishingKnockDown);
                    attacker.Shove(target, KnockbackDistance);
                }
                else
                {
                    tAction.Set(TargetOptions.Finished | TargetOptions.FinishingHit);
                }
            }
            else
            {
                if (!target.IsKnockedDown)
                {
                    target.Stability -= StabilityReduction;
                }

                if (target.IsUnstable && target.Is(RaceStands.KnockDownable))
                {
                    tAction.Set(TargetOptions.KnockDown);
                    attacker.Shove(target, KnockbackDistance);
                }
            }
            cap.Handle();

            // Chain Progress to Stage 3
            attacker.Temp.FighterChainStartTime = DateTime.Now;
            attacker.Temp.FighterChainLevel     = 3;
        }
Exemple #21
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;
		}
Exemple #22
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 target = attacker.Region.GetCreature(targetEntityId);

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

            // "Cancels" the skill
            // 800 = old load time? == aAction.Stun? Varies? Doesn't seem to be a stun.
            Send.SkillUse(attacker, skill.Info.Id, AttackerStun, 1);

            var chance        = attacker.AimMeter.GetAimChance(target);
            var rnd           = RandomProvider.Get().NextDouble() * 100;
            var successfulHit = (rnd < chance);

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

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

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

            // Target action if hit
            if (successfulHit)
            {
                target.StopMove();

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

                cap.Add(tAction);

                // Damage
                // Formula unofficial, but it kinda matches what you would
                // expect from the skill, and what players believed the damage
                // to be, back in G2.
                // bonus = (100 - (6 - stacks) * 5 + rank, +var2 on last shot
                // I'm using rank instead of Var1, which goes from 1-15 in
                // AR2, so AR1 gets a little bonus as well, as AR1's Var1 and
                // 2 are 0.
                // With this formula, the bonus range (1st shot rF vs 5th shot
                // r1) is 76~110% for AR1, and 76~140% for AR2.
                var bonus = 100f - (6 - skill.Stacks) * 5f + (byte)skill.Info.Rank;
                if (skill.Stacks == 1)
                {
                    bonus += skill.RankData.Var2;
                }

                var damage = attacker.GetRndRangedDamage() * (bonus / 100f);

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

                // More damage with fire arrow
                if (attacker.Temp.FireArrow)
                {
                    damage *= FireBonus;
                }

                // Critical Hit
                var critChance = attacker.GetRightCritChance(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);

                // Natural Shield
                var delayReduction = NaturalShield.Handle(attacker, target, ref damage, tAction);

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

                // Aggro
                target.Aggro(attacker);

                // Knock down on deadly
                if (target.Conditions.Has(ConditionsA.Deadly))
                {
                    tAction.Set(TargetOptions.KnockDown);
                }

                // Death/Knockback
                if (target.IsDead)
                {
                    tAction.Set(TargetOptions.FinishingKnockDown);
                }
                else
                {
                    // Insta-recover in knock down
                    if (target.IsKnockedDown)
                    {
                        tAction.Stun = 0;
                    }
                    // Knock down if hit repeatedly
                    else if (target.Stability < 30)
                    {
                        tAction.Set(TargetOptions.KnockDown);
                    }
                    // Normal stability reduction
                    else
                    {
                        var stabilityReduction = StabilityReduction;

                        // Reduce reduction, based on ping
                        // According to the Wiki, "the Knockdown Gauge
                        // [does not] build up", but it's still possible
                        // to knock back with repeated hits. The stability
                        // reduction is probably reduced, just like stun.
                        if (delayReduction > 0)
                        {
                            stabilityReduction = (short)Math.Max(0, stabilityReduction - (stabilityReduction / 100 * delayReduction));
                        }

                        target.Stability -= stabilityReduction;
                        if (target.IsUnstable)
                        {
                            tAction.Set(TargetOptions.KnockBack);
                        }
                    }
                }

                // Knock Back
                if (tAction.IsKnockBack)
                {
                    attacker.Shove(target, KnockBackDistance);
                }

                // Reduce stun, based on ping
                if (delayReduction > 0)
                {
                    tAction.Stun = (short)Math.Max(0, tAction.Stun - (tAction.Stun / 100 * delayReduction));
                }
            }

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

            // Skill training
            if (skill.Info.Rank == SkillRank.RF)
            {
                skill.Train(1);                 // Try attacking with Arrow Revolver.
            }
            // Reduce arrows
            if (attacker.Magazine != null && !ChannelServer.Instance.Conf.World.InfiniteArrows && !attacker.Magazine.HasTag("/unlimited_arrow/"))
            {
                attacker.Inventory.Decrement(attacker.Magazine);
            }

            // Reduce stack
            skill.Stacks--;

            // Handle
            cap.Handle();

            // Disable fire arrow effect
            if (attacker.Temp.FireArrow)
            {
                Send.Effect(attacker, Effect.FireArrow, false);
            }

            return(CombatSkillResult.Okay);
        }
Exemple #23
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 dualWield   = (rightWeapon != null && leftWeapon != null && leftWeapon.Data.WeaponType != 0);
            var maxHits     = (byte)(dualWield ? 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.Hit, attacker, skill.Info.Id, targetEntityId);
                var tAction = new TargetAction(CombatActionType.TakeHit, target, attacker, skill.Info.Id);

                var cap = new CombatActionPack(attacker, skill.Info.Id, aAction, tAction);
                cap.Hit     = i;
                cap.MaxHits = maxHits;
                cap.PrevId  = prevId;
                prevId      = cap.Id;

                // Default attacker options
                aAction.Set(AttackerOptions.Result);
                if (dualWield)
                {
                    aAction.Set(AttackerOptions.DualWield);
                }

                // Base damage
                var damage = attacker.GetRndDamage(weapon);

                // Critical Hit
                CriticalHit.Handle(attacker, attacker.GetCritChanceFor(target), 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);

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

                // Aggro
                target.Aggro(attacker);

                // Evaluate caused damage
                if (!target.IsDead)
                {
                    if (tAction.Type != CombatActionType.Defended)
                    {
                        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 (!dualWield && !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);

                    // Remove dual wield option if last hit doesn't come from
                    // the second weapon.
                    if (cap.MaxHits != cap.Hit)
                    {
                        aAction.Options &= ~AttackerOptions.DualWield;
                    }
                }

                // Set stun time
                if (tAction.Type != CombatActionType.Defended)
                {
                    aAction.Stun = GetAttackerStun(attacker, weapon, tAction.IsKnockBack && (skill.Info.Id != SkillId.FinalHit || !dualWield));
                    tAction.Stun = GetTargetStun(attacker, weapon, tAction.IsKnockBack);
                }

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

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

                cap.Handle();

                // No second hit if target was knocked back
                if (tAction.IsKnockBack)
                {
                    break;
                }
            }

            return(CombatSkillResult.Okay);
        }
Exemple #24
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;
        }
Exemple #25
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 target = attacker.Region.GetCreature(targetEntityId);
			if (target == null)
				return CombatSkillResult.InvalidTarget;

			var targetPos = target.GetPosition();
			var attackerPos = attacker.GetPosition();

			var actionType = (attacker.IsElf ? CombatActionPackType.ChainRangeAttack : CombatActionPackType.NormalAttack);
			var attackerStun = (short)(actionType == CombatActionPackType.ChainRangeAttack ? AttackerStunElf : AttackerStun);

			// "Cancels" the skill
			// 800 = old load time? == aAction.Stun? Varies? Doesn't seem to be a stun.
			Send.SkillUse(attacker, skill.Info.Id, attackerStun, 1);

			var chance = attacker.AimMeter.GetAimChance(target);
			var rnd = RandomProvider.Get().NextDouble() * 100;
			var successfulHit = (rnd < chance);

			var maxHits = (actionType == CombatActionPackType.ChainRangeAttack && successfulHit ? 2 : 1);
			var prevId = 0;

			for (byte i = 1; i <= maxHits; ++i)
			{
				target.StopMove();

				// Actions
				var cap = new CombatActionPack(attacker, skill.Info.Id);
				cap.Hit = i;
				cap.Type = actionType;
				cap.PrevId = prevId;
				prevId = cap.Id;

				var aAction = new AttackerAction(CombatActionType.RangeHit, attacker, skill.Info.Id, targetEntityId);
				aAction.Set(AttackerOptions.Result);
				aAction.Stun = attackerStun;
				cap.Add(aAction);

				// Target action if hit
				if (successfulHit)
				{
					var targetSkillId = target.Skills.ActiveSkill != null ? target.Skills.ActiveSkill.Info.Id : SkillId.CombatMastery;

					var tAction = new TargetAction(CombatActionType.TakeHit, target, attacker, targetSkillId);
					tAction.Set(TargetOptions.Result);
					tAction.AttackerSkillId = skill.Info.Id;
					tAction.Stun = (short)(actionType == CombatActionPackType.ChainRangeAttack ? TargetStunElf : TargetStun);
					if (actionType == CombatActionPackType.ChainRangeAttack)
						tAction.EffectFlags = 0x20;
					cap.Add(tAction);

					// Damage
					var damage = attacker.GetRndRangedDamage();

					// More damage with fire arrow
					if (attacker.Temp.FireArrow)
						damage *= FireBonus;

					// Critical Hit
					var critChance = attacker.GetRightCritChance(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);

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

					// Aggro
					target.Aggro(attacker);

					// Death/Knockback
					if (target.IsDead)
					{
						tAction.Set(TargetOptions.FinishingKnockDown);
						attacker.Shove(target, KnockBackDistance);
						maxHits = 1;
					}
					else
					{
						// Insta-recover in knock down
						// TODO: Tied to stability?
						if (target.IsKnockedDown)
						{
							tAction.Stun = 0;
						}
						// Knock down if hit repeatedly
						else if (target.Stability < 30)
						{
							tAction.Set(TargetOptions.KnockDown);
						}
						// Normal stability reduction
						else
						{
							target.Stability -= (actionType == CombatActionPackType.ChainRangeAttack ? StabilityReductionElf : StabilityReduction);
							if (target.IsUnstable)
							{
								tAction.Set(TargetOptions.KnockBack);
								attacker.Shove(target, KnockBackDistance);
							}
						}
						tAction.Creature.Stun = tAction.Stun;
					}
				}

				aAction.Creature.Stun = aAction.Stun;

				// Skill training
				if (skill.Info.Rank == SkillRank.Novice || skill.Info.Rank == SkillRank.RF)
					skill.Train(1); // Try ranged attack.

				// Reduce arrows
				if (attacker.Magazine != null && !ChannelServer.Instance.Conf.World.InfiniteArrows && attacker.Magazine.Info.Id != 67220)
					attacker.Inventory.Decrement(attacker.Magazine);

				cap.Handle();
			}

			// Disable fire arrow effect
			if (attacker.Temp.FireArrow)
				Send.Effect(attacker, Effect.FireArrow, false);

			return CombatSkillResult.Okay;
		}
Exemple #26
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;
		}
Exemple #27
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 target = attacker.Region.GetCreature(targetEntityId);
			if (target == null)
				return CombatSkillResult.InvalidTarget;

			// "Cancels" the skill
			// 800 = old load time? == aAction.Stun? Varies? Doesn't seem to be a stun.
			Send.SkillUse(attacker, skill.Info.Id, AttackerStun, 1);

			var chance = attacker.AimMeter.GetAimChance(target);
			var rnd = RandomProvider.Get().NextDouble() * 100;
			var successfulHit = (rnd < chance);

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

			var aAction = new AttackerAction(CombatActionType.RangeHit, attacker, targetEntityId);
			aAction.Set(AttackerOptions.Result);
			aAction.Stun = AttackerStun;
			cap.Add(aAction);

			// Target action if hit
			if (successfulHit)
			{
				target.StopMove();

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

				cap.Add(tAction);

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

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

				// More damage with fire arrow
				if (attacker.Temp.FireArrow)
					damage *= FireBonus;

				// Critical Hit
				var critChance = attacker.GetRightCritChance(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);

				// Natural Shield
				var delayReduction = NaturalShield.Handle(attacker, target, ref damage, tAction);

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

				// Aggro
				target.Aggro(attacker);

				// Knock down on deadly
				if (target.Conditions.Has(ConditionsA.Deadly))
					tAction.Set(TargetOptions.KnockDown);

				// Death/Knockback
				if (target.IsDead)
					tAction.Set(TargetOptions.FinishingKnockDown);

				// Knock Back
				if (tAction.IsKnockBack)
					attacker.Shove(target, KnockBackDistance);

				// Reduce stun, based on ping
				if (delayReduction > 0)
					tAction.Stun = (short)Math.Max(0, tAction.Stun - (tAction.Stun / 100 * delayReduction));

				// TODO: "Weakened" state (G12S2 gfSupportShotRenewal)
			}

			// Reduce arrows
			if (attacker.Magazine != null && !ChannelServer.Instance.Conf.World.InfiniteArrows && !attacker.Magazine.HasTag("/unlimited_arrow/"))
				attacker.Inventory.Decrement(attacker.Magazine);

			cap.Handle();

			// Disable fire arrow effect
			if (attacker.Temp.FireArrow)
				Send.Effect(attacker, Effect.FireArrow, false);

			return CombatSkillResult.Okay;
		}
Exemple #28
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, skill.Info.Id, 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);
            var critChance = this.GetCritChance(attacker, target, skill);

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

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

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

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

            // 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);
        }
Exemple #29
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 target = attacker.Region.GetCreature(targetEntityId);
			if (target == null)
				return CombatSkillResult.InvalidTarget;

			if (target.IsNotReadyToBeHit)
				return CombatSkillResult.Okay;

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

			var aAction = new AttackerAction(CombatActionType.RangeHit, attacker, skill.Info.Id, targetEntityId);
			aAction.Set(AttackerOptions.Result);
			aAction.Stun = AttackerStun;
			cap.Add(aAction);

			// Hit by chance
			var chance = attacker.AimMeter.GetAimChance(target);
			var rnd = RandomProvider.Get();
			if (rnd.NextDouble() * 100 < chance)
			{
				aAction.Set(AttackerOptions.KnockBackHit2);

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

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

				// More damage with fire arrow
				if (attacker.Temp.FireArrow)
					damage *= FireBonus;

				// Critical Hit
				var critShieldReduction = (target.LeftHand != null ? target.LeftHand.Data.DefenseBonusCrit : 0);
				var critChance = attacker.GetRightCritChance(target.Protection + critShieldReduction);
				CriticalHit.Handle(attacker, critChance, ref damage, tAction);

				var maxDamage = damage; //Damage without Defense and Protection
				// Subtract target def/prot
				SkillHelper.HandleDefenseProtection(target, ref damage);

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

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

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

				// TODO: We have to calculate knockback distance right
				// TODO: Target with Defense and shield shouldn't be knocked back
				attacker.Shove(target, KnockBackDistance);

				// Aggro
				target.Aggro(attacker);

				tAction.Set(TargetOptions.KnockDownFinish);

				if (target.IsDead)
				{
					aAction.Set(AttackerOptions.KnockBackHit1);
					tAction.Set(TargetOptions.Finished);
				}

				var weapon = attacker.RightHand;
				var critSkill = attacker.Skills.Get(SkillId.CriticalHit);
				if (skill.Info.Rank >= SkillRank.R5 && weapon != null && weapon.Data.SplashRadius != 0 && weapon.Data.SplashAngle != 0)
				{
					ICollection<Creature> targets = attacker.GetTargetableCreaturesInCone(weapon != null ? (int)weapon.Data.SplashRadius : 200, weapon != null ? (int)weapon.Data.SplashAngle : 20);
					foreach (var splashTarget in targets)
					{
						if (splashTarget != target)
						{
							if (splashTarget.IsNotReadyToBeHit)
								continue;
							TargetAction tSplashAction = new TargetAction(CombatActionType.TakeHit, splashTarget, attacker, skill.Info.Id);
							tSplashAction.Set(TargetOptions.Result | TargetOptions.CleanHit);
							splashTarget.Stun = TargetStun;

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

							// Critical Hit

							if (critSkill != null && tAction.Has(TargetOptions.Critical))
							{
								// Add crit bonus
								var bonus = critSkill.RankData.Var1 / 100f;
								damageSplash = damageSplash + (damageSplash * bonus);

								// Set splashTarget option
								tSplashAction.Set(TargetOptions.Critical);
							}

							var maxDamageSplash = damage; //Damage without Defense and Protection
							// Subtract splashTarget def/prot
							SkillHelper.HandleDefenseProtection(splashTarget, ref damageSplash);

							// Defense
							Defense.Handle(aAction, tSplashAction, ref damageSplash, true);

							// Mana Shield
							ManaShield.Handle(splashTarget, ref damageSplash, tSplashAction, maxDamageSplash);

							//Splash Damage Reduction
							damageSplash *= skill.Info.Rank < SkillRank.R1 ? 0.1f : 0.2f;

							// Deal with it!
							if (damageSplash > 0)
								splashTarget.TakeDamage(tSplashAction.Damage = damageSplash, attacker);

							attacker.Shove(splashTarget, KnockBackDistance);

							// Alert
							Network.Sending.Send.SetCombatTarget(splashTarget, attacker.EntityId, TargetMode.Alert);

							tAction.Set(TargetOptions.KnockDownFinish);

							if (splashTarget.IsDead)
							{
								aAction.Set(AttackerOptions.KnockBackHit1);
								tSplashAction.Set(TargetOptions.Finished);
							}

							cap.Add(tSplashAction);
						}

					}

				}
			}
			else
			{
				aAction.Set(AttackerOptions.Missed);
			}

			// Reduce arrows
			if (attacker.Magazine != null && !ChannelServer.Instance.Conf.World.InfiniteArrows)
				attacker.Inventory.Decrement(attacker.Magazine);

			// Disable fire arrow effect
			if (attacker.Temp.FireArrow)
				Send.Effect(attacker, Effect.FireArrow, false);

			// "Cancels" the skill
			// 800 = old load time? == aAction.Stun? Varies? Doesn't seem to be a stun.
			Send.SkillUse(attacker, skill.Info.Id, 800, 1);

			cap.Handle();

			return CombatSkillResult.Okay;
		}
Exemple #30
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);
        }
Exemple #31
0
        /// <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);

                // 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);
                    }
                }
            }
            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);
        }
Exemple #32
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);
        }
Exemple #33
0
        /// <summary>
        ///  Hits targets with thunderbolt.
        /// </summary>
        /// <param name="attacker"></param>
        /// <param name="skill"></param>
        /// <param name="stacks"></param>
        /// <param name="damageProp"></param>
        /// <param name="targets"></param>
        private void Thunderbolt(Creature attacker, Skill skill, int stacks, Prop damageProp, List <Creature> targets)
        {
            // Skip if all targets are already dead
            if (targets.All(a => a.IsDead))
            {
                return;
            }

            var locationId = damageProp.GetLocation().ToLocationId();
            var aAction    = new AttackerAction(CombatActionType.SpecialHit, attacker, locationId, skill.Info.Id);

            aAction.Set(AttackerOptions.KnockBackHit1 | AttackerOptions.UseEffect);
            aAction.PropId = damageProp.EntityId;

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

            foreach (var target in targets.Where(a => !a.IsDead))
            {
                var tAction = new TargetAction(CombatActionType.TakeHit, target, attacker, skill.Info.Id);
                tAction.Set(TargetOptions.Result | TargetOptions.KnockDown);
                tAction.EffectFlags = EffectFlags.SpecialRangeHit;
                tAction.Delay       = 313;
                tAction.Stun        = (short)ThunderboltTargetStun;

                var damage = this.GetThunderboltDamage(attacker, skill, stacks);

                // Critical Hit
                var critChance = attacker.GetTotalCritChance(target.Protection, true);
                CriticalHit.Handle(attacker, critChance, ref damage, tAction);

                // Reduce damage
                Defense.Handle(aAction, tAction, ref damage);
                SkillHelper.HandleMagicDefenseProtection(target, ref damage);
                SkillHelper.HandleConditions(attacker, target, ref damage);
                ManaShield.Handle(target, ref damage, tAction);

                // Mana Deflector
                var mdResult       = ManaDeflector.Handle(attacker, target, ref damage, tAction);
                var delayReduction = mdResult.DelayReduction;
                var pinged         = mdResult.Pinged;

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

                // Reduce stun, based on ping
                if (pinged && delayReduction > 0)
                {
                    tAction.Stun = (short)Math.Max(0, tAction.Stun - (tAction.Stun / 100 * delayReduction));
                }

                // Death/Knockback
                if (target.IsDead)
                {
                    tAction.Set(TargetOptions.FinishingKnockDown);
                }

                cap.Add(tAction);
            }

            cap.Handle();
        }
        /// <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);
        }
Exemple #35
0
        /// <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 target)
        {
            attacker.StopMove();
            target.StopMove();

            // Create actions
            var aAction = new AttackerAction(CombatActionType.RangeHit, attacker, target.EntityId);
            aAction.Set(AttackerOptions.Result);

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

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

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

            // Elements
            damage *= this.GetElementalDamageMultiplier(attacker, target);

            // Critical Hit
            var critChance = attacker.GetTotalCritChance(target.Protection, true);
            CriticalHit.Handle(attacker, critChance, ref damage, tAction);

            // Reduce damage
            Defense.Handle(aAction, tAction, ref damage);
            SkillHelper.HandleMagicDefenseProtection(target, ref damage);
            ManaShield.Handle(target, ref damage, tAction);

            // Mana Deflector
            var delayReduction = ManaDeflector.Handle(attacker, target, ref damage, tAction);

            // Deal damage
            if (damage > 0)
                target.TakeDamage(tAction.Damage = damage, attacker);
            target.Aggro(attacker);

            // Knock down on deadly
            if (target.Conditions.Has(ConditionsA.Deadly))
            {
                tAction.Set(TargetOptions.KnockDown);
                tAction.Stun = TargetStun;
            }

            // Reduce stun, based on ping
            if (delayReduction > 0)
                tAction.Stun = (short)Math.Max(0, tAction.Stun - (tAction.Stun / 100 * delayReduction));

            // Death/Knockback
            if (target.IsDead)
            {
                tAction.Set(TargetOptions.FinishingKnockDown);
            }
            else
            {
                // If knocked down, instant recovery,
                // if repeat hit, knock down,
                // otherwise potential knock back.
                if (target.IsKnockedDown)
                {
                    tAction.Stun = 0;
                }
                else if (target.Stability < MinStability)
                {
                    tAction.Set(TargetOptions.KnockDown);
                }
                else
                {
                    var stabilityReduction = StabilityReduction;

                    // Reduce reduction, based on ping
                    // While the Wiki says that "the Knockdown Gauge [does not]
                    // build up", tests show that it does. However, it's
                    // reduced, assumedly based on the MD rank.
                    if (delayReduction > 0)
                        stabilityReduction = (short)Math.Max(0, stabilityReduction - (stabilityReduction / 100 * delayReduction));

                    target.Stability -= stabilityReduction;

                    if (target.IsUnstable)
                    {
                        tAction.Set(TargetOptions.KnockBack);
                    }
                }
            }

            if (tAction.IsKnockBack)
                attacker.Shove(target, KnockbackDistance);

            // Override stun set by defense
            aAction.Stun = AttackerStun;

            Send.Effect(attacker, Effect.UseMagic, EffectSkillName);
            Send.SkillUseStun(attacker, skill.Info.Id, aAction.Stun, 1);

            skill.Stacks--;

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

            cap.Handle();
        }
Exemple #36
0
        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 (SkillHelper.HandleCounter(target, attacker))
            {
                return(CombatSkillResult.Okay);
            }

            var rightWeapon = attacker.Inventory.RightHand;
            var leftWeapon  = attacker.Inventory.LeftHand;
            var magazine    = attacker.Inventory.Magazine;
            var dualWield   = (rightWeapon != null && leftWeapon != null && leftWeapon.Data.WeaponType != 0);
            var maxHits     = (byte)(dualWield ? 2 : 1);
            int prevId      = 0;

            for (byte i = 1; i <= maxHits; ++i)
            {
                var weapon = (i == 1 ? rightWeapon : leftWeapon);

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

                var cap = new CombatActionPack(attacker, skill.Info.Id, aAction, tAction);
                cap.Hit     = i;
                cap.MaxHits = maxHits;
                cap.PrevId  = prevId;
                prevId      = cap.Id;

                // Default attacker options
                aAction.Set(AttackerOptions.Result);
                if (dualWield)
                {
                    aAction.Set(AttackerOptions.DualWield);
                }

                // Base damage
                var damage = attacker.GetRndDamage(weapon);

                // Critical Hit
                SkillHelper.HandleCritical(attacker, attacker.GetCritChanceFor(target), ref damage, tAction);

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

                // Defense
                SkillHelper.HandleDefense(aAction, tAction, ref damage);

                // Mana Shield
                SkillHelper.HandleManaShield(target, ref damage, tAction);

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

                // Evaluate caused damage
                if (!target.IsDead)
                {
                    if (tAction.Type != CombatActionType.Defended)
                    {
                        target.KnockBack += this.GetKnockBack(weapon) / maxHits;
                        if (target.KnockBack >= 100 && target.Is(RaceStands.KnockBackable))
                        {
                            tAction.Set(tAction.Has(TargetOptions.Critical) ? TargetOptions.KnockDown : TargetOptions.KnockBack);
                        }
                    }
                }
                else
                {
                    tAction.Set(TargetOptions.FinishingKnockDown);
                }

                // React to knock back
                if (tAction.IsKnockBack)
                {
                    var newPos = attacker.GetPosition().GetRelative(targetPosition, KnockBackDistance);

                    Position intersection;
                    if (target.Region.Collisions.Find(targetPosition, newPos, out intersection))
                    {
                        newPos = targetPosition.GetRelative(intersection, -50);
                    }

                    target.SetPosition(newPos.X, newPos.Y);

                    aAction.Set(AttackerOptions.KnockBackHit2);

                    // Remove dual wield option if last hit doesn't come from
                    // the second weapon.
                    if (cap.MaxHits != cap.Hit)
                    {
                        aAction.Options &= ~AttackerOptions.DualWield;
                    }
                }

                // Set stun time
                if (tAction.Type != CombatActionType.Defended)
                {
                    aAction.Stun = this.GetAttackerStun(weapon, tAction.IsKnockBack);
                    tAction.Stun = this.GetTargetStun(weapon, tAction.IsKnockBack);
                }

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

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

                cap.Handle();

                // No second hit if target was knocked back
                if (tAction.IsKnockBack)
                {
                    break;
                }
            }

            return(CombatSkillResult.Okay);
        }
Exemple #37
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 target = attacker.Region.GetCreature(targetEntityId);
			if (target == null)
				return CombatSkillResult.InvalidTarget;

			var targetPos = target.GetPosition();
			var attackerPos = attacker.GetPosition();

			var actionType = (attacker.IsElf ? CombatActionPackType.ChainRangeAttack : CombatActionPackType.NormalAttack);
			var attackerStun = (short)(actionType == CombatActionPackType.ChainRangeAttack ? AttackerStunElf : AttackerStun);

			// "Cancels" the skill
			// 800 = old load time? == aAction.Stun? Varies? Doesn't seem to be a stun.
			Send.SkillUse(attacker, skill.Info.Id, attackerStun, 1);

			var chance = attacker.AimMeter.GetAimChance(target);
			var rnd = RandomProvider.Get().NextDouble() * 100;
			var successfulHit = (rnd < chance);

			var maxHits = (actionType == CombatActionPackType.ChainRangeAttack && successfulHit ? 2 : 1);
			var prevId = 0;

			for (byte i = 1; i <= maxHits; ++i)
			{
				target.StopMove();

				// Actions
				var cap = new CombatActionPack(attacker, skill.Info.Id);
				cap.Hit = i;
				cap.Type = actionType;
				cap.PrevId = prevId;
				prevId = cap.Id;

				var aAction = new AttackerAction(CombatActionType.RangeHit, attacker, targetEntityId);
				aAction.Set(AttackerOptions.Result);
				aAction.Stun = attackerStun;
				cap.Add(aAction);

				// Target action if hit
				if (successfulHit)
				{
					var tAction = new TargetAction(CombatActionType.TakeHit, target, attacker, skill.Info.Id);
					tAction.Set(TargetOptions.Result);
					tAction.Stun = (short)(actionType == CombatActionPackType.ChainRangeAttack ? TargetStunElf : TargetStun);
					if (actionType == CombatActionPackType.ChainRangeAttack)
						tAction.EffectFlags = EffectFlags.Unknown;

					cap.Add(tAction);

					// Damage
					var damage = attacker.GetRndRangedDamage();

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

					// More damage with fire arrow
					// XXX: Does this affect the element?
					if (attacker.Temp.FireArrow)
						damage *= FireBonus;

					// Critical Hit
					var critChance = attacker.GetRightCritChance(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);

					// Natural Shield
					var delayReduction = NaturalShield.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 = (short)(actionType == CombatActionPackType.ChainRangeAttack ? TargetStunElf : TargetStun);
					}

					// Aggro
					target.Aggro(attacker);

					// Death/Knockback
					if (target.IsDead)
					{
						tAction.Set(TargetOptions.FinishingKnockDown);
						maxHits = 1;
					}
					else
					{
						// Insta-recover in knock down
						// TODO: Tied to stability?
						if (target.IsKnockedDown)
						{
							tAction.Stun = 0;
						}
						// Knock down if hit repeatedly
						else if (target.Stability < 30)
						{
							tAction.Set(TargetOptions.KnockDown);
						}
						// Normal stability reduction
						else
						{
							var stabilityReduction = (actionType == CombatActionPackType.ChainRangeAttack ? StabilityReductionElf : StabilityReduction);

							// Reduce reduction, based on ping
							// According to the Wiki, "the Knockdown Gauge
							// [does not] build up", but it's still possible
							// to knock back with repeated hits. The stability
							// reduction is probably reduced, just like stun.
							if (delayReduction > 0)
								stabilityReduction = (short)Math.Max(0, stabilityReduction - (stabilityReduction / 100 * delayReduction));

							target.Stability -= stabilityReduction;
							if (target.IsUnstable)
							{
								tAction.Set(TargetOptions.KnockBack);
							}
						}
					}

					// Knock Back
					if (tAction.IsKnockBack)
						attacker.Shove(target, KnockBackDistance);

					// Reduce stun, based on ping
					if (delayReduction > 0)
						tAction.Stun = (short)Math.Max(0, tAction.Stun - (tAction.Stun / 100 * delayReduction));
				}

				// Skill training
				if (skill.Info.Rank == SkillRank.Novice || skill.Info.Rank == SkillRank.RF)
					skill.Train(1); // Try ranged attack.

				// Reduce arrows
				if (attacker.Magazine != null && !ChannelServer.Instance.Conf.World.InfiniteArrows && !attacker.Magazine.HasTag("/unlimited_arrow/"))
					attacker.Inventory.Decrement(attacker.Magazine);

				cap.Handle();
			}

			// Disable fire arrow effect
			if (attacker.Temp.FireArrow)
				Send.Effect(attacker, Effect.FireArrow, false);

			return CombatSkillResult.Okay;
		}
Exemple #38
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;

			if (target.IsNotReadyToBeHit)
				return CombatSkillResult.Okay;

			if ((attacker.IsStunned || attacker.IsOnAttackDelay) && attacker.InterceptingSkillId == SkillId.None)
				return CombatSkillResult.Okay;

			// Check range
			var attackerPosition = attacker.GetPosition();
			var targetPosition = target.GetPosition();
			if (!attacker.IgnoreAttackRange &&
				(!attackerPosition.InRange(targetPosition, attacker.AttackRangeFor(target))))
			{ return CombatSkillResult.OutOfRange; }
			if (!attacker.IgnoreAttackRange &&
				(attacker.Region.Collisions.Any(attackerPosition, targetPosition) // Check collisions between position
				|| target.Conditions.Has(ConditionsA.Invisible))) // Check visiblility (GM)
			{ return CombatSkillResult.Okay; }

			attacker.IgnoreAttackRange = false;
			// Against Normal Attack
			Skill combatMastery = target.Skills.Get(SkillId.CombatMastery);
			if (combatMastery != null && (target.Skills.ActiveSkill == null || target.Skills.ActiveSkill == combatMastery || target.Skills.IsReady(SkillId.FinalHit)) && target.IsInBattleStance && target.Target == attacker && target.AttemptingAttack && (!target.IsStunned || target.IsKnockedDown))
			{
				target.InterceptingSkillId = SkillId.Smash;
				target.IgnoreAttackRange = true;
				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;
				}
				skillHandler.Use(target, combatMastery, attacker.EntityId);
				return CombatSkillResult.Okay;
			}

			// Against Windmill
			//TODO: Change this into the new NPC client system when it comes out if needed.
			Skill windmill = target.Skills.Get(SkillId.Windmill);
			if (windmill != null && target.Skills.IsReady(SkillId.Windmill) && !target.IsPlayer && target.CanAttack(attacker))
			{
				target.InterceptingSkillId = SkillId.Smash;
				var skillHandler = ChannelServer.Instance.SkillManager.GetHandler<IUseable>(windmill.Info.Id) as Windmill;
				if (skillHandler == null)
				{
					Log.Error("Smash.Use: Target's skill handler not found for '{0}'.", windmill.Info.Id);
					return CombatSkillResult.Okay;
				}
				skillHandler.Use(target, windmill);
				return CombatSkillResult.Okay;
			}

			// Against Smash
			Skill smash = target.Skills.Get(SkillId.Smash);
			if (smash != null && target.Skills.IsReady(SkillId.Smash) && target.IsInBattleStance && target.Target == attacker && !target.IsStunned && attacker.CanAttack(target))
			{
				var attackerStunTime = CombatMastery.GetAttackerStun(attacker, attacker.RightHand, false);
				var targetStunTime = CombatMastery.GetAttackerStun(target, target.Inventory.RightHand, false);
				if ((target.LastKnockedBackBy == attacker && target.KnockDownTime > attacker.KnockDownTime &&
						target.KnockDownTime.AddMilliseconds(targetStunTime) < DateTime.Now //If last knocked down within the time it takes for you to finish attacking.
						|| attackerStunTime > targetStunTime &&
						!Math2.Probability(((2725 - attackerStunTime) / 2500) * 100) //Probability in percentage that you will not lose.  2725 is 2500 (Slowest stun) + 225 (Fastest stun divided by two so that the fastest stun isn't 100%)
						&& !(attacker.LastKnockedBackBy == target && attacker.KnockDownTime > target.KnockDownTime && attacker.KnockDownTime.AddMilliseconds(attackerStunTime) < DateTime.Now)))
				{
					if (target.CanAttack(attacker))
					{
						target.InterceptingSkillId = SkillId.Smash;
						target.IgnoreAttackRange = true;
						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;
						}
						skillHandler.Use(target, smash, attacker.EntityId);
						return CombatSkillResult.Okay;
					}
				}
				else
				{
					attacker.InterceptingSkillId = SkillId.Smash;
				}
			}

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

			target.IgnoreAttackRange = false;

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

			var weapon = attacker.RightHand;
			ICollection<Creature> targets = null;
			if (skill.Info.Rank >= SkillRank.R5 && weapon != null && weapon.Data.SplashRadius != 0 && weapon.Data.SplashAngle != 0 || weapon == null)
			{
				targets = attacker.GetTargetableCreaturesInCone(weapon != null ? (int)weapon.Data.SplashRadius : 200, weapon != null ? (int)weapon.Data.SplashAngle : 20);

				foreach (var splashTarget in targets)
				{
					if (splashTarget != target)
					{
						// Counter
						if (Counterattack.Handle(target, attacker))
							return CombatSkillResult.Okay;
					}

				}
			}

			// Prepare combat actions
			var aAction = new AttackerAction(CombatActionType.HardHit, attacker, skill.Info.Id, targetEntityId);
			aAction.Set(AttackerOptions.Result | AttackerOptions.KnockBackHit2);

			TargetAction tAction;
			if (attacker.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);
			}
			tAction.Set(TargetOptions.Result | TargetOptions.Smash);

			attacker.InterceptingSkillId = SkillId.None;

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

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

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

			var maxDamage = damage; //Damage without Defense and Protection
			// Subtract target def/prot
			SkillHelper.HandleDefenseProtection(target, ref damage);

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

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

			// 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);

			var critSkill = attacker.Skills.Get(SkillId.CriticalHit);
			if (skill.Info.Rank >= SkillRank.R5 && weapon != null && weapon.Data.SplashRadius != 0 && weapon.Data.SplashAngle != 0)
			{
				foreach (var splashTarget in targets)
				{
					if (splashTarget != target)
					{
						if (splashTarget.IsNotReadyToBeHit)
							continue;
						TargetAction tSplashAction = new TargetAction(CombatActionType.TakeHit, splashTarget, attacker, skill.Info.Id);
						tSplashAction.Set(TargetOptions.Result | TargetOptions.Smash);

						// Base damage
						float damageSplash = this.GetDamage(attacker, skill);
						attacker.CalculateSplashDamage(splashTarget, ref damageSplash, skill, critSkill, aAction, tAction, tSplashAction);

						// Deal with it!
						if (damageSplash > 0)
							splashTarget.TakeDamage(tSplashAction.Damage = damageSplash, attacker);

						// Alert
						splashTarget.Aggro(attacker, true);

						if (splashTarget.IsDead)
							tSplashAction.Set(TargetOptions.FinishingHit | TargetOptions.Finished);

						splashTarget.Stun = tSplashAction.Stun = StunTime;
						splashTarget.Stability = Creature.MinStability;

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

						cap.Add(tSplashAction);
					}

				}
			}

			// Action!
			cap.Handle();

			return CombatSkillResult.Okay;
		}
Exemple #39
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)
		{
			var target = attacker.Region.GetCreature(targetEntityId);
			if (target == null)
				return CombatSkillResult.Okay;

			if (target.IsNotReadyToBeHit)
				return CombatSkillResult.Okay;

			if ((attacker.IsStunned || attacker.IsOnAttackDelay) && attacker.InterceptingSkillId == SkillId.None)
				return CombatSkillResult.Okay;

			var attackerPosition = attacker.GetPosition();
			var targetPosition = target.GetPosition();
			if (!attacker.IgnoreAttackRange &&
				(!attackerPosition.InRange(targetPosition, attacker.AttackRangeFor(target))))
			{ return CombatSkillResult.OutOfRange; }
			if (!attacker.IgnoreAttackRange &&
				(attacker.Region.Collisions.Any(attackerPosition, targetPosition) // Check collisions between position
				|| target.Conditions.Has(ConditionsA.Invisible))) // Check visiblility (GM)
			{ return CombatSkillResult.Okay; }

			attacker.IgnoreAttackRange = false;

			//Against Smash
			Skill smash = target.Skills.Get(SkillId.Smash);
			if (smash != null && target.Skills.IsReady(SkillId.Smash) && attacker.CanAttack(target))
				attacker.InterceptingSkillId = SkillId.Smash;

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


			var staminaUsage = (rightWeapon != null && rightWeapon.Data.StaminaUsage != 0 ? rightWeapon.Data.StaminaUsage : 0.7f) + (dualWield ? leftWeapon.Data.StaminaUsage : 0f);
			var lowStamina = false;
			if (attacker.Stamina < staminaUsage)
			{
				lowStamina = true;
				Send.Notice(attacker, Localization.Get("Your stamina is too low to attack properly!"));
			}
			attacker.Stamina -= staminaUsage;
			Send.StatUpdate(attacker, StatUpdateType.Private, Stat.Stamina);

			// Against Combat Mastery
			Skill combatMastery = target.Skills.Get(SkillId.CombatMastery);
			var simultaneousAttackStun = 0;
			if (attacker.InterceptingSkillId != SkillId.CombatMastery && target.InterceptingSkillId != SkillId.CombatMastery)
			{
				if (combatMastery != null && (target.Skills.ActiveSkill == null || target.Skills.ActiveSkill == combatMastery || target.Skills.IsReady(SkillId.FinalHit)) && target.IsInBattleStance && target.Target == attacker && target.AttemptingAttack && (!target.IsStunned || target.IsKnockedDown) && attacker.CanAttack(target))
				{
					var attackerStunTime = CombatMastery.GetAttackerStun(attacker, attacker.RightHand, false);
					var targetStunTime = CombatMastery.GetAttackerStun(target, target.Inventory.RightHand, false);
					if ((target.LastKnockedBackBy == attacker && target.KnockDownTime > attacker.KnockDownTime &&
						target.KnockDownTime.AddMilliseconds(targetStunTime) < DateTime.Now //If last knocked down within the time it takes for you to finish attacking.
						|| attackerStunTime > targetStunTime &&
						!Math2.Probability(((2725 - attackerStunTime) / 2500) * 100) //Probability in percentage that you will not lose.  2725 is 2500 (Slowest stun) + 225 (Fastest stun divided by two so that the fastest stun isn't 100%)
						&& !(attacker.LastKnockedBackBy == target && attacker.KnockDownTime > target.KnockDownTime && attacker.KnockDownTime.AddMilliseconds(attackerStunTime) < DateTime.Now)))
					{
						if (target.CanAttack(attacker))
						{
							target.InterceptingSkillId = SkillId.CombatMastery;
							target.IgnoreAttackRange = true;
							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;
							}
							skillHandler.Use(target, combatMastery, attacker.EntityId);
							return CombatSkillResult.Okay;
						}
					}
					else
					{
						if (Math2.Probability(((2725 - attackerStunTime) / 2500) * 100)) //Probability in percentage that it will be an interception instead of a double hit.
						{
							attacker.InterceptingSkillId = SkillId.CombatMastery;
						}
						else
						{
							attacker.InterceptingSkillId = SkillId.CombatMastery;
							if (target.CanAttack(attacker))
							{
								target.InterceptingSkillId = SkillId.CombatMastery;
								target.IgnoreAttackRange = true;
								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
								{
									skillHandler.Use(target, combatMastery, attacker.EntityId);
									simultaneousAttackStun = attacker.Stun;
									attacker.Stun = 0;
								}
							}
						}
					}
				}
			}

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

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

			ICollection<Creature> targets = null;
			if (rightWeapon != null && rightWeapon.Data.SplashRadius != 0 && rightWeapon.Data.SplashAngle != 0 || rightWeapon == null)
			{
				targets = attacker.GetTargetableCreaturesInCone(rightWeapon != null ? (int)rightWeapon.Data.SplashRadius : 204, rightWeapon != null ? (int)rightWeapon.Data.SplashAngle : 60);

				foreach (var splashTarget in targets)
				{
					if (splashTarget != target)
					{
						// Counter
						if (Counterattack.Handle(target, attacker))
							return CombatSkillResult.Okay;
					}

				}
			}

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

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

				AttackerAction aAction;
				TargetAction tAction;
				if (attacker.InterceptingSkillId == SkillId.Smash)
				{
					aAction = new AttackerAction(CombatActionType.SimultaneousHit, attacker, SkillId.CombatMastery, target.EntityId);
					aAction.Options |= AttackerOptions.Result;
					tAction = new TargetAction(CombatActionType.CounteredHit, target, attacker, SkillId.Smash);
					tAction.Options |= TargetOptions.Result;

				}
				else if (attacker.InterceptingSkillId == SkillId.CombatMastery)
				{
					aAction = new AttackerAction(CombatActionType.SimultaneousHit, attacker, SkillId.CombatMastery, target.EntityId);
					aAction.Options |= AttackerOptions.Result;
					tAction = new TargetAction(CombatActionType.CounteredHit, target, attacker, target.Skills.IsReady(SkillId.FinalHit) ? SkillId.FinalHit : SkillId.CombatMastery);
					tAction.Options |= TargetOptions.Result;

				}
				else
				{
					aAction = new AttackerAction(CombatActionType.Hit, attacker, skill.Info.Id, targetEntityId);
					tAction = new TargetAction(CombatActionType.TakeHit, target, attacker, target.Skills.IsReady(SkillId.FinalHit) ? SkillId.FinalHit : SkillId.CombatMastery);
					aAction.Options |= AttackerOptions.Result;
					tAction.Options |= TargetOptions.Result;
				}

				attacker.InterceptingSkillId = SkillId.None;

				var cap = new CombatActionPack(attacker, skill.Info.Id, tAction, aAction);
				cap.Hit = i;
				cap.MaxHits = maxHits;
				cap.PrevId = prevId;
				prevId = cap.Id;

				// Default attacker options
				aAction.Set(AttackerOptions.Result);
				if (dualWield)
					aAction.Set(AttackerOptions.DualWield);

				// Base damage
				var damage = (i == 1 ? attacker.GetRndRightHandDamage() : attacker.GetRndLeftHandDamage());
				if (lowStamina)
				{
					damage = attacker.GetRndBareHandDamage();
				}

				// Critical Hit
				var critShieldReduction = (target.LeftHand != null ? target.LeftHand.Data.DefenseBonusCrit : 0);
				var critChance = (i == 1 ? attacker.GetRightCritChance(target.Protection + critShieldReduction) : attacker.GetLeftCritChance(target.Protection + critShieldReduction));
				CriticalHit.Handle(attacker, critChance, ref damage, tAction);

				var maxDamage = damage; //Damage without Defense and Protection
										// Subtract target def/prot
				SkillHelper.HandleDefenseProtection(target, ref damage);

				// Defense
				var tActionOldType = tAction.Type;
				Defense.Handle(aAction, tAction, ref damage);
				if (i == 1 && tAction.Type == CombatActionType.Defended)
				{
					defenseStun = tAction.Stun;
				}


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

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

				if (tAction.Type == CombatActionType.Defended && target.Life <= 0)
				{
					tAction.Type = tActionOldType;
				}

				// Aggro
				target.Aggro(attacker);

				// Evaluate caused damage
				if (!target.IsDead)
				{
					if (tAction.Type != CombatActionType.Defended)
					{
						if (!target.Skills.IsReady(SkillId.FinalHit))
						{
							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);
								if (target.Life < 0)
									tAction.Set(TargetOptions.KnockDown);
							}
							else if (!dualWield && !weaponIsKnuckle)
							{
								target.Stability = Creature.MinStability;
								tAction.Set(TargetOptions.KnockDown);
							}
						}
					}
				}
				else
				{
					tAction.Set(TargetOptions.FinishingKnockDown);
				}

				// React to knock back
				if (tAction.IsKnockBack && tAction.Type != CombatActionType.Defended)
				{
					if (!target.Skills.IsReady(SkillId.FinalHit))
					{
						attacker.Shove(target, KnockBackDistance);
					}

					aAction.Set(AttackerOptions.KnockBackHit2);

					// Remove dual wield option if last hit doesn't come from
					// the second weapon.
					if (cap.MaxHits != cap.Hit)
						aAction.Options &= ~AttackerOptions.DualWield;


				}
				else if (tAction.Type == CombatActionType.Defended)
				{
					// Remove dual wield option if last hit doesn't come from
					// the second weapon.
					if (cap.MaxHits != cap.Hit)
						aAction.Options &= ~AttackerOptions.DualWield;
				}


				// Set stun time
				if (tAction.Type != CombatActionType.Defended)
				{
					if (simultaneousAttackStun == 0)
					{
						aAction.Stun = GetAttackerStun(attacker, weapon, tAction.IsKnockBack && ((skill.Info.Id != SkillId.FinalHit) && !target.IsDead || AuraData.FeaturesDb.IsEnabled("CombatSystemRenewal")));
					}
					else
					{
						aAction.Stun = (short)simultaneousAttackStun;
					}
					if (!target.Skills.IsReady(SkillId.FinalHit))
					{
						tAction.Stun = GetTargetStun(attacker, weapon, tAction.IsKnockBack);
					}

					if (target.IsDead && skill.Info.Id != SkillId.FinalHit)
					{
						attacker.AttackDelayTime = DateTime.Now.AddMilliseconds(GetAttackerStun(attacker, weapon, true));
					}
				}

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

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

				var critSkill = attacker.Skills.Get(SkillId.CriticalHit);
				if (weapon != null && weapon.Data.SplashRadius != 0 && weapon.Data.SplashAngle != 0)
				{
					foreach (var splashTarget in targets)
					{
						if (splashTarget != target)
						{
							if (splashTarget.IsNotReadyToBeHit)
								continue;
							TargetAction tSplashAction = new TargetAction(CombatActionType.TakeHit, splashTarget, attacker, skill.Info.Id);

							// Base damage
							float damageSplash;
							if (lowStamina)
							{
								damageSplash = attacker.GetRndBareHandDamage();
							}
							else
							{
								damageSplash = (i == 1 ? attacker.GetRndRightHandDamage() : attacker.GetRndLeftHandDamage());
                            }
							attacker.CalculateSplashDamage(splashTarget, ref damageSplash, skill, critSkill, aAction, tAction, tSplashAction, weapon);

							// Deal with it!
							if (damageSplash > 0)
								splashTarget.TakeDamage(tSplashAction.Damage = damageSplash, attacker);

							// Alert
							splashTarget.Aggro(attacker, true);

							// Evaluate caused damage
							if (!splashTarget.IsDead)
							{
								if (tSplashAction.Type != CombatActionType.Defended)
								{
									if (!splashTarget.Skills.IsReady(SkillId.FinalHit))
									{

										splashTarget.Stability -= (this.GetStabilityReduction(attacker, weapon) / maxHits) / 2;  //Less stability reduction for splash damage.

										// 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 (splashTarget.IsUnstable && splashTarget.Is(RaceStands.KnockBackable))
												//tSplashAction.Set(tSplashAction.Has(TargetOptions.Critical) ? TargetOptions.KnockDown : TargetOptions.KnockBack);
												tSplashAction.Set(TargetOptions.KnockDown);
											if (splashTarget.Life < 0)
												tSplashAction.Set(TargetOptions.KnockDown);
										}
										else if (!dualWield && !weaponIsKnuckle)
										{
											splashTarget.Stability = Creature.MinStability;
											tSplashAction.Set(TargetOptions.KnockDown);
										}
									}
								}
							}
							else
							{
								tSplashAction.Set(TargetOptions.FinishingKnockDown);
							}

							// React to knock back
							if (tSplashAction.IsKnockBack && tSplashAction.Type != CombatActionType.Defended)
							{

								if (!splashTarget.Skills.IsReady(SkillId.FinalHit))
								{
									attacker.Shove(splashTarget, KnockBackDistance);
								}
							}


							// Set stun time
							if (tSplashAction.Type != CombatActionType.Defended)
							{
								if (!splashTarget.Skills.IsReady(SkillId.FinalHit))
								{
									if (defenseStun != 0)
										tSplashAction.Stun = (short)defenseStun;
									else
										tSplashAction.Stun = GetTargetStun(attacker, weapon, tSplashAction.IsKnockBack);
								}
							}

							cap.Add(tSplashAction);
						}

					}
				}

				cap.Handle();

				// No second hit if target was knocked back or defended.
				if (tAction.IsKnockBack || tAction.Type == CombatActionType.Defended)
					break;
			}
			attacker.AttemptingAttack = false;
			return CombatSkillResult.Okay;
		}
Exemple #40
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 target = attacker.Region.GetCreature(targetEntityId);

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

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

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

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

            // Hit by chance
            var chance = attacker.AimMeter.GetAimChance(target);
            var rnd    = RandomProvider.Get();

            if (rnd.NextDouble() * 100 < chance)
            {
                target.StopMove();

                aAction.Set(AttackerOptions.KnockBackHit2);

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

                // TODO: Splash damage

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

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

                // More damage with fire arrow
                // XXX: Does this affect the element?
                if (attacker.Temp.FireArrow)
                {
                    damage *= FireBonus;
                }

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

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

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

                // Natural Shield
                // Ignore delay reduction, as knock downs shouldn't be shortened
                NaturalShield.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
                // If target is using a shield and defense, don't KD.
                var targetLeftHand = target.LeftHand;
                if (tAction.SkillId != SkillId.Defense || targetLeftHand == null || !targetLeftHand.IsShield)
                {
                    // TODO: We have to calculate knockback distance right
                    attacker.Shove(target, KnockBackDistance);
                    tAction.Set(TargetOptions.KnockDownFinish);
                }

                // Aggro
                target.Aggro(attacker);

                if (target.IsDead)
                {
                    aAction.Set(AttackerOptions.KnockBackHit1);
                    tAction.Set(TargetOptions.Finished);
                }
            }
            else
            {
                aAction.Set(AttackerOptions.Missed);
            }

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

            // Reduce arrows
            if (attacker.Magazine != null && !ChannelServer.Instance.Conf.World.InfiniteArrows && !attacker.Magazine.HasTag("/unlimited_arrow/"))
            {
                attacker.Inventory.Decrement(attacker.Magazine);
            }

            // Disable fire arrow effect
            if (attacker.Temp.FireArrow)
            {
                Send.Effect(attacker, Effect.FireArrow, false);
            }

            // "Cancels" the skill
            // 800 = old load time? == aAction.Stun? Varies? Doesn't seem to be a stun.
            Send.SkillUse(attacker, skill.Info.Id, 800, 1);

            cap.Handle();

            return(CombatSkillResult.Okay);
        }
Exemple #41
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 target = attacker.Region.GetCreature(targetEntityId);
			if (target == null)
				return CombatSkillResult.InvalidTarget;

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

			var aAction = new AttackerAction(CombatActionType.RangeHit, attacker, targetEntityId);
			aAction.Set(AttackerOptions.Result);
			aAction.Stun = AttackerStun;
			cap.Add(aAction);

			// Hit by chance
			var chance = attacker.AimMeter.GetAimChance(target);
			var rnd = RandomProvider.Get();
			if (rnd.NextDouble() * 100 < chance)
			{
				target.StopMove();

				aAction.Set(AttackerOptions.KnockBackHit2);

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

				// TODO: Splash damage

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

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

				// More damage with fire arrow
				// XXX: Does this affect the element?
				if (attacker.Temp.FireArrow)
					damage *= FireBonus;

				// Critical Hit
				var critChance = attacker.GetRightCritChance(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);

				// Natural Shield
				// Ignore delay reduction, as knock downs shouldn't be shortened
				NaturalShield.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
				// If target is using a shield and defense, don't KD.
				var targetLeftHand = target.LeftHand;
				if (tAction.SkillId != SkillId.Defense || targetLeftHand == null || !targetLeftHand.IsShield)
				{
					// TODO: We have to calculate knockback distance right
					attacker.Shove(target, KnockBackDistance);
					tAction.Set(TargetOptions.KnockDownFinish);
				}

				// Aggro
				target.Aggro(attacker);

				if (target.IsDead)
				{
					aAction.Set(AttackerOptions.KnockBackHit1);
					tAction.Set(TargetOptions.Finished);
				}
			}
			else
			{
				aAction.Set(AttackerOptions.Missed);
			}

			// Reduce arrows
			if (attacker.Magazine != null && !ChannelServer.Instance.Conf.World.InfiniteArrows && !attacker.Magazine.HasTag("/unlimited_arrow/"))
				attacker.Inventory.Decrement(attacker.Magazine);

			// Disable fire arrow effect
			if (attacker.Temp.FireArrow)
				Send.Effect(attacker, Effect.FireArrow, false);

			// "Cancels" the skill
			// 800 = old load time? == aAction.Stun? Varies? Doesn't seem to be a stun.
			Send.SkillUse(attacker, skill.Info.Id, 800, 1);

			cap.Handle();

			return CombatSkillResult.Okay;
		}
Exemple #42
0
		/// <summary>
		/// Handles knock back/stun/death.
		/// </summary>
		protected virtual void HandleKnockBack(Creature attacker, Creature target, TargetAction tAction)
		{
			if (target.IsDead)
			{
				tAction.Set(TargetOptions.FinishingKnockDown);
				attacker.Shove(target, KnockbackDistance);
			}
			else
			{
				// If knocked down, instant recovery,
				// if repeat hit, knock down,
				// otherwise potential knock back.

				if (target.IsKnockedDown)
				{
					tAction.Stun = 0;
				}
				else if (target.IsUnstable)
				{
					tAction.Set(TargetOptions.KnockDown);
				}
				else
				{
					target.Stability -= StabilityReduction;
					if (target.IsUnstable)
					{
						tAction.Set(TargetOptions.KnockBack);
						attacker.Shove(target, KnockbackDistance);
					}
				}
			}
		}
        /// <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 target = attacker.Region.GetCreature(targetEntityId);

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

            var targetPos   = target.GetPosition();
            var attackerPos = attacker.GetPosition();

            var actionType   = (attacker.IsElf ? CombatActionPackType.ChainRangeAttack : CombatActionPackType.NormalAttack);
            var attackerStun = (short)(actionType == CombatActionPackType.ChainRangeAttack ? AttackerStunElf : AttackerStun);

            // "Cancels" the skill
            // 800 = old load time? == aAction.Stun? Varies? Doesn't seem to be a stun.
            Send.SkillUse(attacker, skill.Info.Id, attackerStun, 1);

            var chance        = attacker.AimMeter.GetAimChance(target);
            var rnd           = RandomProvider.Get().NextDouble() * 100;
            var successfulHit = (rnd < chance);

            var maxHits = (actionType == CombatActionPackType.ChainRangeAttack && successfulHit ? 2 : 1);
            var prevId  = 0;

            for (byte i = 1; i <= maxHits; ++i)
            {
                target.StopMove();

                // Actions
                var cap = new CombatActionPack(attacker, skill.Info.Id);
                cap.Hit    = i;
                cap.Type   = actionType;
                cap.PrevId = prevId;
                prevId     = cap.Id;

                var aAction = new AttackerAction(CombatActionType.RangeHit, attacker, targetEntityId);
                aAction.Set(AttackerOptions.Result);
                aAction.Stun = attackerStun;
                cap.Add(aAction);

                // Target action if hit
                if (successfulHit)
                {
                    var tAction = new TargetAction(CombatActionType.TakeHit, target, attacker, skill.Info.Id);
                    tAction.Set(TargetOptions.Result);
                    tAction.Stun = (short)(actionType == CombatActionPackType.ChainRangeAttack ? TargetStunElf : TargetStun);
                    if (actionType == CombatActionPackType.ChainRangeAttack)
                    {
                        tAction.EffectFlags = EffectFlags.SpecialRangeHit;
                    }

                    cap.Add(tAction);

                    // Damage
                    var damage = attacker.GetRndRangedDamage();

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

                    // More damage with fire arrow
                    // XXX: Does this affect the element?
                    if (attacker.Temp.FireArrow)
                    {
                        damage *= FireBonus;
                    }

                    // Critical Hit
                    var critChance = attacker.GetRightCritChance(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);

                    // Natural Shield
                    var nsResult       = NaturalShield.Handle(attacker, target, ref damage, tAction);
                    var delayReduction = nsResult.DelayReduction;
                    var pinged         = nsResult.Pinged;

                    // 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 = (short)(actionType == CombatActionPackType.ChainRangeAttack ? TargetStunElf : TargetStun);
                    }

                    // Aggro
                    target.Aggro(attacker);

                    // Death/Knockback
                    if (target.IsDead)
                    {
                        tAction.Set(TargetOptions.FinishingKnockDown);
                        maxHits = 1;
                    }
                    else
                    {
                        // Insta-recover in knock down
                        // TODO: Tied to stability?
                        if (target.IsKnockedDown)
                        {
                            tAction.Stun = 0;
                        }
                        // Knock down if hit repeatedly
                        else if (target.Stability < 30)
                        {
                            tAction.Set(TargetOptions.KnockDown);
                        }
                        // Normal stability reduction
                        else
                        {
                            var stabilityReduction = (actionType == CombatActionPackType.ChainRangeAttack ? StabilityReductionElf : StabilityReduction);

                            // Reduce reduction, based on ping
                            // According to the Wiki, "the Knockdown Gauge
                            // [does not] build up", but it's still possible
                            // to knock back with repeated hits. The stability
                            // reduction is probably reduced, just like stun.
                            if (delayReduction > 0)
                            {
                                stabilityReduction = (short)Math.Max(0, stabilityReduction - (stabilityReduction / 100 * delayReduction));
                            }

                            target.Stability -= stabilityReduction;
                            if (target.IsUnstable)
                            {
                                tAction.Set(TargetOptions.KnockBack);
                            }
                        }
                    }

                    // Knock Back
                    if (tAction.IsKnockBack)
                    {
                        attacker.Shove(target, KnockBackDistance);
                    }

                    // Reduce stun, based on ping
                    if (pinged && delayReduction > 0)
                    {
                        tAction.Stun = (short)Math.Max(0, tAction.Stun - (tAction.Stun / 100 * delayReduction));
                    }

                    // No second hit if defended
                    if (tAction.SkillId == SkillId.Defense)
                    {
                        // Set to 1 to prevent second run
                        maxHits = 1;

                        // Set normal type if hit didn't come from the second
                        // arrow.
                        if (cap.Hit != 2)
                        {
                            cap.Type = CombatActionPackType.NormalAttack;
                        }

                        // Override stun set by Defense
                        aAction.Stun = DefenseAttackerStun;
                    }
                }
                else
                {
                    // Dummy target action on miss, so the client knows what
                    // the target would've been. Possibly affects arrow
                    // animations.
                    var tAction = new TargetAction(CombatActionType.None, target, attacker, SkillId.None);
                    cap.Add(tAction);
                }

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

                // Skill training
                if (skill.Info.Rank == SkillRank.Novice || skill.Info.Rank == SkillRank.RF)
                {
                    skill.Train(1);                     // Try ranged attack.
                }
                // Reduce arrows
                if (attacker.Magazine != null && !ChannelServer.Instance.Conf.World.InfiniteArrows && !attacker.Magazine.HasTag("/unlimited_arrow/"))
                {
                    attacker.Inventory.Decrement(attacker.Magazine);
                }

                cap.Handle();
            }

            // Disable fire arrow effect
            if (attacker.Temp.FireArrow)
            {
                Send.Effect(attacker, Effect.FireArrow, false);
            }

            return(CombatSkillResult.Okay);
        }
Exemple #44
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 target = attacker.Region.GetCreature(targetEntityId);
			if (target == null)
				return CombatSkillResult.InvalidTarget;

			if (target.IsNotReadyToBeHit)
				return CombatSkillResult.Okay;

			var targetPos = target.GetPosition();
			var attackerPos = attacker.GetPosition();

			// Check range
			//if (!attackerPos.InRange(targetPos, attacker.RightHand.OptionInfo.EffectiveRange + 100))
			//	return CombatSkillResult.OutOfRange;

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

			var aAction = new AttackerAction(CombatActionType.RangeHit, attacker, skill.Info.Id, targetEntityId);
			aAction.Set(AttackerOptions.Result);
			aAction.Stun = AttackerStun;
			cap.Add(aAction);

			// Hit by chance
			var chance = attacker.AimMeter.GetAimChance(target);
			var rnd = RandomProvider.Get();
			if (rnd.NextDouble() * 100 < chance)
			{
				var tAction = new TargetAction(CombatActionType.TakeHit, target, attacker, skill.Info.Id);
				tAction.Set(TargetOptions.Result);
				tAction.Stun = TargetStun;
				cap.Add(tAction);

				// Damage
				var damage = attacker.GetRndRangedDamage();

				// More damage with fire arrow
				if (attacker.Temp.FireArrow)
					damage *= FireBonus;

				// Critical Hit
				var critShieldReduction = (target.LeftHand != null ? target.LeftHand.Data.DefenseBonusCrit : 0);
				var critChance = attacker.GetRightCritChance(target.Protection + critShieldReduction);
				CriticalHit.Handle(attacker, critChance, ref damage, tAction);

				var maxDamage = damage; //Damage without Defense and Protection
				// Subtract target def/prot
				SkillHelper.HandleDefenseProtection(target, ref damage);

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

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

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

				// Aggro
				target.Aggro(attacker);

				// Death/Knockback
				if (target.IsDead)
				{
					tAction.Set(TargetOptions.FinishingKnockDown);
					attacker.Shove(target, KnockBackDistance);
				}
				else
				{
					// Insta-recover in knock down
					// TODO: Tied to stability?
					if (target.IsKnockedDown)
					{
						tAction.Stun = 0;
					}
					// Knock down if hit repeatedly
					else if (target.Stability < 30)
					{
						tAction.Set(TargetOptions.KnockDown);
					}
					// Normal stability reduction
					else
					{
						target.Stability -= StabilityReduction;
						if (target.IsUnstable)
						{
							tAction.Set(TargetOptions.KnockBack);
							attacker.Shove(target, KnockBackDistance);
						}
					}
				}
			}

			// Skill training
			if (skill.Info.Rank == SkillRank.Novice || skill.Info.Rank == SkillRank.RF)
				skill.Train(1); // Try ranged attack.

			// Reduce arrows
			if (attacker.Magazine != null && !ChannelServer.Instance.Conf.World.InfiniteArrows)
				attacker.Inventory.Decrement(attacker.Magazine);

			// Disable fire arrow effect
			if (attacker.Temp.FireArrow)
				Send.Effect(attacker, Effect.FireArrow, false);

			// "Cancels" the skill
			// 800 = old load time? == aAction.Stun? Varies? Doesn't seem to be a stun.
			Send.SkillUse(attacker, skill.Info.Id, 800, 1);

			cap.Handle();

			return CombatSkillResult.Okay;
		}
Exemple #45
0
        /// <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, mainTarget.EntityId);

            aAction.Set(AttackerOptions.Result);

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

            // Get targets
            // Add the main target as first target, so it gets the first hit,
            // and the full damage.
            var targets = new List <Creature>();

            targets.Add(mainTarget);

            var inSplashRange = attacker.GetTargetableCreaturesAround(mainTarget.GetPosition(), SplashRange);

            targets.AddRange(inSplashRange.Where(a => a != mainTarget));

            // 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;

                // Critical Hit
                var critChance = attacker.GetTotalCritChance(target.Protection, true);
                CriticalHit.Handle(attacker, critChance, ref damage, tAction);

                // Reduce damage
                Defense.Handle(aAction, tAction, ref targetDamage);
                SkillHelper.HandleMagicDefenseProtection(target, ref targetDamage);
                SkillHelper.HandleConditions(attacker, target, ref damage);
                ManaShield.Handle(target, ref targetDamage, tAction);

                // Mana Deflector
                var delayReduction = ManaDeflector.Handle(attacker, target, ref targetDamage, tAction);

                // Deal damage
                if (targetDamage > 0)
                {
                    target.TakeDamage(tAction.Damage = targetDamage, attacker);
                }

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

                // Reduce stun, based on ping
                if (delayReduction > 0)
                {
                    tAction.Stun = (short)Math.Max(0, tAction.Stun - (tAction.Stun / 100 * delayReduction));
                }

                // Death/Knockback
                if (target.IsDead)
                {
                    tAction.Set(TargetOptions.FinishingKnockDown);
                }
                else
                {
                    // If knocked down, instant recovery,
                    // if repeat hit, knock down,
                    // otherwise potential knock back.
                    if (target.IsKnockedDown)
                    {
                        tAction.Stun = 0;
                    }
                    else if (target.Stability < MinStability)
                    {
                        tAction.Set(TargetOptions.KnockDown);
                    }
                    else
                    {
                        // If number of stacks is greater than the number of
                        // targets hit, the targets are knocked back, which is
                        // done by reducing the stability to min here.
                        // Targets with high enough Mana Deflector might
                        // negate this knock back, by reducing the stability
                        // reduction to 0.
                        var stabilityReduction = (skill.Stacks > targets.Count ? OverchargeStabilityReduction : StabilityReduction);

                        // Reduce reduction, based on ping
                        // While the Wiki says that "the Knockdown Gauge [does not]
                        // build up", tests show that it does. However, it's
                        // reduced, assumedly based on the MD rank.
                        if (delayReduction > 0)
                        {
                            stabilityReduction = (short)Math.Max(0, stabilityReduction - (stabilityReduction / 100 * delayReduction));
                        }

                        target.Stability -= stabilityReduction;

                        if (target.IsUnstable)
                        {
                            tAction.Set(TargetOptions.KnockBack);
                        }
                    }
                }

                if (tAction.IsKnockBack)
                {
                    attacker.Shove(target, KnockbackDistance);
                }

                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);

            skill.Stacks = 0;

            // Update current weapon
            SkillHelper.UpdateWeapon(attacker, targets.FirstOrDefault(), ProficiencyGainType.Melee, attacker.RightHand);

            cap.Handle();
        }
Exemple #46
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 target = attacker.Region.GetCreature(targetEntityId);

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

            // "Cancels" the skill
            // 800 = old load time? == aAction.Stun? Varies? Doesn't seem to be a stun.
            Send.SkillUse(attacker, skill.Info.Id, AttackerStun, 1);

            var chance        = attacker.AimMeter.GetAimChance(target);
            var rnd           = RandomProvider.Get().NextDouble() * 100;
            var successfulHit = (rnd < chance);

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

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

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

            // Target action if hit
            if (successfulHit)
            {
                target.StopMove();

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

                cap.Add(tAction);

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

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

                // More damage with fire arrow
                if (attacker.Temp.FireArrow)
                {
                    damage *= FireBonus;
                }

                // Critical Hit
                var critChance = attacker.GetRightCritChance(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);

                // Natural Shield
                var delayReduction = NaturalShield.Handle(attacker, target, ref damage, tAction);

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

                // Aggro
                target.Aggro(attacker);

                // Knock down on deadly
                if (target.Conditions.Has(ConditionsA.Deadly))
                {
                    tAction.Set(TargetOptions.KnockDown);
                }

                // Death/Knockback
                if (target.IsDead)
                {
                    tAction.Set(TargetOptions.FinishingKnockDown);
                }

                // Knock Back
                if (tAction.IsKnockBack)
                {
                    attacker.Shove(target, KnockBackDistance);
                }

                // Reduce stun, based on ping
                if (delayReduction > 0)
                {
                    tAction.Stun = (short)Math.Max(0, tAction.Stun - (tAction.Stun / 100 * delayReduction));
                }

                // TODO: "Weakened" state (G12S2 gfSupportShotRenewal)
            }

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

            // Reduce arrows
            if (attacker.Magazine != null && !ChannelServer.Instance.Conf.World.InfiniteArrows && !attacker.Magazine.HasTag("/unlimited_arrow/"))
            {
                attacker.Inventory.Decrement(attacker.Magazine);
            }

            cap.Handle();

            // Disable fire arrow effect
            if (attacker.Temp.FireArrow)
            {
                Send.Effect(attacker, Effect.FireArrow, false);
            }

            return(CombatSkillResult.Okay);
        }
Exemple #47
0
		/// <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);
		}
Exemple #48
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);
        }
Exemple #49
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);
		}
Exemple #50
0
        /// <summary>
        /// Uses Charging Strike
        /// </summary>
        /// <param name="attacker"></param>
        /// <param name="skill"></param>
        /// <param name="packet"></param>
        public void Use(Creature attacker, Skill skill, Packet packet)
        {
            // Get Target
            var targetEntityId = packet.GetLong();

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

            var attackerPos = attacker.GetPosition();
            var targetPos   = target.GetPosition();

            // Check target + collisions
            if (target == null || attacker.Region.Collisions.Any(attackerPos, targetPos))
            {
                Send.SkillUseSilentCancel(attacker);
                attacker.Unlock(Locks.All);
                return;
            }

            // Stop movement
            attacker.Lock(Locks.Walk | Locks.Run);
            attacker.StopMove();
            target.StopMove();

            // Effects
            Send.EffectDelayed(attacker, attackerPos.GetDistance(targetPos), Effect.ChargingStrike, (byte)0, targetEntityId);

            // Conditions
            var extra = new MabiDictionary();

            extra.SetBool("CONDITION_FAST_MOVE_NO_LOCK", false);
            attacker.Conditions.Activate(ConditionsC.FastMove, extra);

            Send.ForceRunTo(attacker, targetPos);
            attacker.SetPosition(targetPos.X, targetPos.Y);

            Send.SkillUseEntity(attacker, skill.Info.Id, targetEntityId);

            Send.EffectDelayed(attacker, attackerPos.GetDistance(targetPos), Effect.ChargingStrike, (byte)1, targetEntityId);

            // Counter
            if (Counterattack.Handle(target, attacker))
            {
                attacker.Conditions.Deactivate(ConditionsC.FastMove);
                return;
            }

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

            var aAction = new AttackerAction(CombatActionType.SpecialHit, attacker, targetEntityId, skill.Info.Id);

            aAction.Set(AttackerOptions.UseEffect);
            aAction.PropId = targetEntityId;

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

            tAction.Set(TargetOptions.Result);
            tAction.Delay = attackerPos.GetDistance(targetPos);

            cap.Add(aAction, tAction);

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

            // Chain Mastery Damage Bonus
            var chainMasterySkill = attacker.Skills.Get(SkillId.ChainMastery);
            var damageBonus       = (chainMasterySkill == null ? 0 : chainMasterySkill.RankData.Var1);

            damage += damage * (damageBonus / 100f);

            // Master Title - Damage +30%
            if (attacker.Titles.SelectedTitle == skill.Data.MasterTitle)
            {
                damage += (damage * 0.3f);
            }

            // Critical Hit
            var critChance = attacker.GetRightCritChance(target.Protection);

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

            // Handle skills and reductions
            SkillHelper.HandleDefenseProtection(target, 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 Times
            tAction.Stun = TargetStun;
            aAction.Stun = AttackerStun;

            // Death and Knockback
            if (target.IsDead)
            {
                if (target.Is(RaceStands.KnockDownable))
                {
                    tAction.Set(TargetOptions.FinishingKnockDown);
                    attacker.Shove(target, KnockbackDistance);
                }
                else
                {
                    tAction.Set(TargetOptions.Finished | TargetOptions.FinishingHit);
                }
            }
            else             // This skill never knocks back normally
            {
                if (!target.IsKnockedDown)
                {
                    target.Stability -= StabilityReduction;
                }
            }
            cap.Handle();

            attacker.Conditions.Deactivate(ConditionsC.FastMove);
            Send.SkillComplete(attacker, skill.Info.Id);

            // Chain Progress to Stage 2
            attacker.Temp.FighterChainStartTime = DateTime.Now;
            attacker.Temp.FighterChainLevel     = 2;

            attacker.Skills.ActiveSkill = null;

            // Charging strike locks EVERYTHING for some reason...
            attacker.Unlock(Locks.All);
        }
Exemple #51
0
		/// <summary>
		/// Bolt specific use code.
		/// </summary>
		/// <param name="attacker"></param>
		/// <param name="skill"></param>
		/// <param name="target"></param>
		protected virtual void UseSkillOnTarget(Creature attacker, Skill skill, Creature target)
		{
			target.StopMove();

			// Create actions
			var aAction = new AttackerAction(CombatActionType.RangeHit, attacker, skill.Info.Id, target.EntityId);
			aAction.Set(AttackerOptions.Result);

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

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

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

			// Reduce damage
			if (this.Defendable)
				Defense.Handle(aAction, tAction, ref damage);
			SkillHelper.HandleMagicDefenseProtection(target, ref damage);
			ManaShield.Handle(target, ref damage, tAction);

			// Deal damage
			if (damage > 0)
				target.TakeDamage(tAction.Damage = damage, attacker);
			target.Aggro(attacker);

			// Death/Knockback
			this.HandleKnockBack(attacker, target, 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();
		}
Exemple #52
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);

                    // 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;
                        }
                    }
                }

                // Handle
                cap.Handle();
            }

            return CombatSkillResult.Okay;
        }
Exemple #53
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;
        }
Exemple #54
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 target = attacker.Region.GetCreature(targetEntityId);

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

            var targetPos   = target.GetPosition();
            var attackerPos = attacker.GetPosition();

            var actionType   = (attacker.IsElf ? CombatActionPackType.ChainRangeAttack : CombatActionPackType.NormalAttack);
            var attackerStun = (short)(actionType == CombatActionPackType.ChainRangeAttack ? AttackerStunElf : AttackerStun);

            // "Cancels" the skill
            // 800 = old load time? == aAction.Stun? Varies? Doesn't seem to be a stun.
            Send.SkillUse(attacker, skill.Info.Id, attackerStun, 1);

            var chance        = attacker.AimMeter.GetAimChance(target);
            var rnd           = RandomProvider.Get().NextDouble() * 100;
            var successfulHit = (rnd < chance);

            var maxHits = (actionType == CombatActionPackType.ChainRangeAttack && successfulHit ? 2 : 1);
            var prevId  = 0;

            for (byte i = 1; i <= maxHits; ++i)
            {
                target.StopMove();

                // Actions
                var cap = new CombatActionPack(attacker, skill.Info.Id);
                cap.Hit    = i;
                cap.Type   = actionType;
                cap.PrevId = prevId;
                prevId     = cap.Id;

                var aAction = new AttackerAction(CombatActionType.RangeHit, attacker, skill.Info.Id, targetEntityId);
                aAction.Set(AttackerOptions.Result);
                aAction.Stun = attackerStun;
                cap.Add(aAction);

                // Target action if hit
                if (successfulHit)
                {
                    var targetSkillId = target.Skills.ActiveSkill != null ? target.Skills.ActiveSkill.Info.Id : SkillId.CombatMastery;

                    var tAction = new TargetAction(CombatActionType.TakeHit, target, attacker, targetSkillId);
                    tAction.Set(TargetOptions.Result);
                    tAction.AttackerSkillId = skill.Info.Id;
                    tAction.Stun            = (short)(actionType == CombatActionPackType.ChainRangeAttack ? TargetStunElf : TargetStun);
                    if (actionType == CombatActionPackType.ChainRangeAttack)
                    {
                        tAction.EffectFlags = 0x20;
                    }
                    cap.Add(tAction);

                    // Damage
                    var damage = attacker.GetRndRangedDamage();

                    // More damage with fire arrow
                    if (attacker.Temp.FireArrow)
                    {
                        damage *= FireBonus;
                    }

                    // Critical Hit
                    var critChance = attacker.GetRightCritChance(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);

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

                    // Aggro
                    target.Aggro(attacker);

                    // Death/Knockback
                    if (target.IsDead)
                    {
                        tAction.Set(TargetOptions.FinishingKnockDown);
                        attacker.Shove(target, KnockBackDistance);
                        maxHits = 1;
                    }
                    else
                    {
                        // Insta-recover in knock down
                        // TODO: Tied to stability?
                        if (target.IsKnockedDown)
                        {
                            tAction.Stun = 0;
                        }
                        // Knock down if hit repeatedly
                        else if (target.Stability < 30)
                        {
                            tAction.Set(TargetOptions.KnockDown);
                        }
                        // Normal stability reduction
                        else
                        {
                            target.Stability -= (actionType == CombatActionPackType.ChainRangeAttack ? StabilityReductionElf : StabilityReduction);
                            if (target.IsUnstable)
                            {
                                tAction.Set(TargetOptions.KnockBack);
                                attacker.Shove(target, KnockBackDistance);
                            }
                        }
                        tAction.Creature.Stun = tAction.Stun;
                    }
                }

                aAction.Creature.Stun = aAction.Stun;

                // Skill training
                if (skill.Info.Rank == SkillRank.Novice || skill.Info.Rank == SkillRank.RF)
                {
                    skill.Train(1);                     // Try ranged attack.
                }
                // Reduce arrows
                if (attacker.Magazine != null && !ChannelServer.Instance.Conf.World.InfiniteArrows && !attacker.Magazine.HasTag("/unlimited_arrow/"))
                {
                    attacker.Inventory.Decrement(attacker.Magazine);
                }

                cap.Handle();
            }

            // Disable fire arrow effect
            if (attacker.Temp.FireArrow)
            {
                Send.Effect(attacker, Effect.FireArrow, false);
            }

            return(CombatSkillResult.Okay);
        }
Exemple #55
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);
        }
Exemple #56
0
        /// <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 target)
        {
            attacker.StopMove();
            target.StopMove();

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

            aAction.Set(AttackerOptions.Result);

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

            tAction.Set(TargetOptions.Result | TargetOptions.KnockDown);
            tAction.Stun = TargetStun;

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

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

            // Elements
            damage *= this.GetElementalDamageMultiplier(attacker, target);

            // Critical Hit
            var critChance = attacker.GetTotalCritChance(target.Protection, true);

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

            // Reduce damage
            SkillHelper.HandleMagicDefenseProtection(target, ref damage);
            SkillHelper.HandleConditions(attacker, target, ref damage);
            ManaShield.Handle(target, ref damage, tAction);
            ManaDeflector.Handle(attacker, target, ref damage, tAction);

            // Deal damage
            if (damage > 0)
            {
                target.TakeDamage(tAction.Damage = damage, attacker);
            }
            target.Aggro(attacker);

            // Knockback
            target.Stability = Creature.MinStability;
            attacker.Shove(target, KnockbackDistance);
            if (target.IsDead)
            {
                tAction.Set(TargetOptions.FinishingKnockDown);
            }

            // Override stun set by defense
            aAction.Stun = AttackerStun;

            Send.Effect(attacker, Effect.UseMagic, EffectSkillName);
            Send.SkillUseStun(attacker, skill.Info.Id, aAction.Stun, 1);

            skill.Stacks = 0;

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

            cap.Handle();
        }
Exemple #57
0
		/// <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, mainTarget.EntityId);
			aAction.Set(AttackerOptions.Result);

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

			// Get targets
			// Add the main target as first target, so it gets the first hit,
			// and the full damage.
			var targets = new List<Creature>();
			targets.Add(mainTarget);

			var inSplashRange = attacker.GetTargetableCreaturesAround(mainTarget.GetPosition(), SplashRange);
			targets.AddRange(inSplashRange.Where(a => a != mainTarget));

			// 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;

				// Critical Hit
				var critChance = attacker.GetTotalCritChance(target.Protection, true);
				CriticalHit.Handle(attacker, critChance, ref damage, tAction);

				// Reduce damage
				Defense.Handle(aAction, tAction, ref targetDamage);
				SkillHelper.HandleMagicDefenseProtection(target, ref targetDamage);
				SkillHelper.HandleConditions(attacker, target, ref damage);
				ManaShield.Handle(target, ref targetDamage, tAction);

				// Mana Deflector
				var mdResult = ManaDeflector.Handle(attacker, target, ref targetDamage, tAction);
				var delayReduction = mdResult.DelayReduction;
				var pinged = mdResult.Pinged;

				// Deal damage
				if (targetDamage > 0)
					target.TakeDamage(tAction.Damage = targetDamage, attacker);

				if (target == mainTarget)
					target.Aggro(attacker);

				// Reduce stun, based on ping
				if (pinged && delayReduction > 0)
					tAction.Stun = (short)Math.Max(0, tAction.Stun - (tAction.Stun / 100 * delayReduction));

				// Death/Knockback
				if (target.IsDead)
				{
					tAction.Set(TargetOptions.FinishingKnockDown);
				}
				else
				{
					// If knocked down, instant recovery,
					// if repeat hit, knock down,
					// otherwise potential knock back.
					if (target.IsKnockedDown)
					{
						tAction.Stun = 0;
					}
					else if (target.Stability < MinStability)
					{
						tAction.Set(TargetOptions.KnockDown);
					}
					else
					{
						// If number of stacks is greater than the number of
						// targets hit, the targets are knocked back, which is
						// done by reducing the stability to min here.
						// Targets with high enough Mana Deflector might
						// negate this knock back, by reducing the stability
						// reduction to 0.
						var stabilityReduction = (skill.Stacks > targets.Count ? OverchargeStabilityReduction : StabilityReduction);

						// Reduce reduction, based on ping
						// While the Wiki says that "the Knockdown Gauge [does not]
						// build up", tests show that it does. However, it's
						// reduced, assumedly based on the MD rank.
						if (delayReduction > 0)
							stabilityReduction = (short)Math.Max(0, stabilityReduction - (stabilityReduction / 100 * delayReduction));

						target.Stability -= stabilityReduction;

						if (target.IsUnstable)
						{
							tAction.Set(TargetOptions.KnockBack);
						}
					}
				}

				if (tAction.IsKnockBack)
					attacker.Shove(target, KnockbackDistance);

				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);

			skill.Stacks = 0;

			// Update current weapon
			SkillHelper.UpdateWeapon(attacker, targets.FirstOrDefault(), ProficiencyGainType.Melee, attacker.RightHand);

			cap.Handle();
		}
Exemple #58
0
        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();

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

            for (byte i = 1; i <= maxHits; ++i)
            {
                var weapon = (i == 1 ? rightWeapon : leftWeapon);

                var cap = new CombatActionPack(attacker, skill.Info.Id);
                var aAction = new AttackerAction(CombatActionType.Hit, attacker, skill.Info.Id, targetEntityId);
                var tAction = new TargetAction(CombatActionType.TakeHit, target, attacker, skill.Info.Id);
                cap.Add(aAction, tAction);

                cap.Hit = i;
                cap.MaxHits = maxHits;
                cap.PrevId = prevId;
                prevId = cap.Id;

                aAction.Set(AttackerOptions.Result);
                if (dualWield)
                    aAction.Set(AttackerOptions.DualWield);

                var damage = attacker.GetRndDamage(weapon);
                tAction.Damage = damage;

                target.TakeDamage(tAction.Damage, attacker);

                if (!target.IsDead)
                {
                    target.KnockBack += this.GetKnockBack(weapon) / maxHits;
                    if (target.KnockBack >= 100 && target.Is(RaceStands.KnockBackable))
                        tAction.Set(tAction.Has(TargetOptions.Critical) ? TargetOptions.KnockDown : TargetOptions.KnockBack);
                }
                else
                {
                    tAction.Set(TargetOptions.FinishingKnockDown);
                }

                if (tAction.IsKnockBack)
                {
                    var newPos = attacker.GetPosition().GetRelative(targetPosition, KnockBackDistance);

                    Position intersection;
                    if (target.Region.Collissions.Find(targetPosition, newPos, out intersection))
                        newPos = targetPosition.GetRelative(intersection, -50);

                    target.SetPosition(newPos.X, newPos.Y);

                    aAction.Set(AttackerOptions.KnockBackHit2);

                    cap.MaxHits = cap.Hit;
                }

                aAction.Stun = this.GetAttackerStun(weapon, tAction.IsKnockBack);
                tAction.Stun = this.GetTargetStun(weapon, tAction.IsKnockBack);

                cap.Handle();

                if (tAction.IsKnockBack)
                    break;
            }

            return CombatSkillResult.Okay;
        }