Beispiel #1
0
		/// <summary>
		/// Rage for the attacker of an AttackAction
		/// </summary>
		public static void GenerateDefaultAttackerRage(AttackAction action)
		{
			var attacker = action.Attacker;

			// only generate Rage for white damage
			if (action.IsWeaponAttack)
			{
				double hitFactor;
				if (action.Weapon == attacker.OffHandWeapon)
				{
					hitFactor = 1.75;
				}
				else
				{
					hitFactor = 3.5;
				}
				if (action.IsCritical)
				{
					hitFactor *= 2;
				}

				hitFactor *= action.Weapon.AttackTime;

				var lvl = attacker.Level;
				var c = 0.0092f * lvl * lvl + 3.23f * lvl + 4.27f;

				var rage = ((15 * action.ActualDamage / c) + (hitFactor / 2000f)) + 1;
                // Multiplied by 2 to match an approximate value, check the formula instead.
				attacker.Power += (int)(rage*2);
			}
		}
Beispiel #2
0
		/// <summary>
		/// Rage for the victim of an AttackAction
		/// </summary>
		public static void GenerateDefaultVictimRage(AttackAction action)
		{
			var victim = action.Victim;

			var lvl = victim.Level;
			var c = (int)(0.0092 * lvl * lvl + 3.23f * lvl + 4.27f);			// polynomial rage co-efficient
			victim.Power += (5 * (action.ActualDamage + 1) / (2 * c))*10;
		}
Beispiel #3
0
		/// <summary>
		/// Any spell and ranged damage
		/// SMSG_SPELLNONMELEEDAMAGELOG
		/// </summary>
		/*
			Target: High: 0xF530 (Unit) - Low: 619710 - Entry: UmbralBrute (30922)
			Caster: High: 0x0000 (Player) - Low: 2211871
			Spell: ClassSkillArcaneShot_11 (49045)
			Damage: 776
			Overkill: 0
			SchoolMask: Arcane (64)
			Absorbed: 0
			Resisted: 0
			UnkByte1: 0
			UnkByte2 (Unused): 0
			Blocked: 0
			HitFlags: 37
			UnkByte3 (Unused): 0
		 */
		public static void SendMagicDamage(AttackAction state)
		{
			using (var packet = new RealmPacketOut(RealmServerOpCode.SMSG_SPELLNONMELEEDAMAGELOG, 40))
			{
				state.Victim.EntityId.WritePacked(packet);
				if (state.Attacker != null)
				{
					state.Attacker.EntityId.WritePacked(packet);
				}
				else
				{
					packet.Write((byte)0);
				}
				packet.Write(state.SpellEffect != null ? state.SpellEffect.Spell.Id : 0);

				packet.Write(state.Damage);
				packet.Write(0); // overkill?
				packet.Write((byte)state.Schools);
				packet.Write(state.Absorbed);
				packet.Write(state.Resisted);
				//packet.Write(0);				// is always 0
				packet.Write((state.Schools & DamageSchoolMask.Physical) != 0);
				packet.Write((byte)0);			// 0 or 1
				packet.Write(state.Blocked);

				// also flags 0x8, 0x10, 
				var hitFlags = state.IsCritical ? SpellLogFlags.Critical : SpellLogFlags.None;
				packet.Write((int)hitFlags);
				packet.Write((byte)0);// unused by client

				state.Victim.SendPacketToArea(packet, true);
			}
		}
Beispiel #4
0
        public static void SendAttackerStateUpdate(AttackAction action)
        {
            using (var packet = new RealmPacketOut(RealmServerOpCode.SMSG_ATTACKERSTATEUPDATE, 100))
            {
                var evade = action.VictimState == VictimState.Evade;
                if (evade)
                {
                    //action.HitFlags |= HitFlags.HitFlag_0x800 | HitFlags.Absorb_1;
                }
                packet.Write((uint)action.HitFlags);
                action.Attacker.EntityId.WritePacked(packet);
                action.Victim.EntityId.WritePacked(packet);

                var dmg = action.ActualDamage;

                packet.Write(dmg);
                packet.Write(0);					// unknown (overkill?)

                //damage count
                const byte damageCount = 1;
                packet.Write(damageCount);

                for (byte i = 0; i < damageCount; i++)
                {
                    packet.Write((uint) action.Schools);
                    packet.Write((float) dmg);
                    packet.Write(dmg);
                }

                if (action.HitFlags.HasAny(HitFlags.Absorb_1 | HitFlags.Absorb_2))
                {
                    for (byte i = 0; i < damageCount; i++)
                    {
                        packet.Write(action.Absorbed);
                    }
                }

                if (action.HitFlags.HasAny(HitFlags.Resist_1 | HitFlags.Resist_2))
                {
                    for (byte i =0;i<damageCount;i++)
                    {
                        packet.Write(action.Resisted);
                    }
                }

                packet.Write((byte)action.VictimState);
                if (evade)
                {
                    packet.Write(0x1000002);
                }
                else
                {
                    packet.Write(dmg > 0 ? -1 : 0); // 0 if no damage, else -1 or 1000 or very rarely something else (eg when evading)
                }

                packet.Write(0);// this is a spell id

                if (action.HitFlags.HasAny(HitFlags.Block))
                {
                    packet.Write(action.Blocked);
                }

                //if ((hitFlags & HitFlags.HitFlag_0x800000) != 0)
                //{
                //    packet.Write(0);
                //}

                //if ((hitFlags & HitFlags.HitFlag_0x1) != 0)
                //{
                //    packet.Write(0);
                //    packet.Write((float)0);
                //    packet.Write((float)0);
                //    packet.Write((float)0);
                //    packet.Write((float)0);
                //    packet.Write((float)0);
                //    packet.Write((float)0);
                //    packet.Write((float)0);
                //    packet.Write((float)0);
                //    for (int i = 0; i < 5; i++)
                //    {
                //        packet.Write(0);
                //        packet.Write(0);
                //    }
                //    packet.Write(0);
                //}

                action.Victim.SendPacketToArea(packet, true);
            }
        }
Beispiel #5
0
		/// <summary>
		/// Does spell-damage to this Unit
		/// </summary>
		public void DoSpellDamage(Unit attacker, SpellEffect effect, int dmg)
		{
			DamageSchool school;
			if (effect != null)
			{
				school = GetLeastResistant(effect.Spell);
			}
			else
			{
				school = DamageSchool.Physical;
			}

			if (IsEvading || IsImmune(school) || IsInvulnerable || !IsAlive)
			{
				return;
			}

			var action = attacker != null ? attacker.m_AttackAction : m_AttackAction;
			if (action == null || action.IsInUse)
			{
				// currently in use
				action = new AttackAction(attacker);
			}
			else
			{
				action.Attacker = attacker;
				action.HitFlags = 0;
				action.VictimState = 0;
				action.Weapon = null;
			}

			if (effect != null)
			{
				action.UsedSchool = school;
				action.Schools = effect.Spell.SchoolMask;
				action.IsDot = effect.IsPeriodic;
			}
			else
			{
				action.UsedSchool = DamageSchool.Physical;
				action.Schools = DamageSchoolMask.Physical;
				action.IsDot = false;
			}

			var resChance = GetResistChance(this, action.UsedSchool);

			action.Victim = this;

			if (attacker != null)
			{
				action.Damage = attacker.AddDamageMods(dmg, action.SpellEffect, action.UsedSchool);

				if (effect != null && !action.IsDot && !effect.Spell.AttributesExB.Has(SpellAttributesExB.CannotCrit) &&
					attacker.CalcSpellCritChance(this, action.UsedSchool, resChance, effect.Spell) > Utility.Random(0f, 100f))
				{
					action.Damage = attacker.CalcCritDamage(action.ActualDamage, this, effect).RoundInt();
					action.IsCritical = true;
				}
				else
				{
					action.IsCritical = false;
				}
			}


			action.Absorbed = Absorb(action.UsedSchool, action.Damage);
			action.Resisted = (int)Math.Round(action.Damage * resChance);
			action.Blocked = 0; // TODO: Deflect
			action.SpellEffect = effect;

			//TODO: figure this out: However, when spells do only damage, it's not just a full hit or full miss situation. Pure damage spells can be resisted for 0%, 25%, 50%, 75%, or 100% of their regular damage. 

			DoRawDamage(action);
			CombatLogHandler.SendMagicDamage(action);
			action.OnFinished();
			//Your average resistance can still be anywhere betweeen 0% and 75%. If your average resistance is maxed out, then there's a really good chance of having 75% of the spell's damage be resisted. 
			//There's also a fairly good chance of having 100% of the spell's damage be resisted, a slightly lower chance of 50% of its damage being resisted, a small chances of only 25%, or even 0% of the damage being resisted. 
			//It's a weighted average. Visualize it as a bell curve around your average resistance.
		}
Beispiel #6
0
		/// <summary>
		/// Do a single attack using the given Weapon and AttackAction.
		/// </summary>
		/// <param name="weapon"></param>
		/// <param name="action"></param>
		public void Strike(IWeapon weapon, AttackAction action, Unit target)
		{
			if (weapon == null)
			{
				log.Error("Trying to strike without weapon: " + this);
				return;
			}

			//if (IsMovementConrolled)
			//{
			//    // stop running when landing a hit
			//    m_Movement.Stop();
			//}

			// calc damage
			if (weapon == m_offhandWeapon)
			{
				action.Damage = Utility.Random((int)MinOffHandDamage, (int)MaxOffHandDamage + 1);
			}
			else
			{
				if (weapon.IsRanged)
				{
					action.Damage = Utility.Random((int)MinRangedDamage, (int)MaxRangedDamage + 1);
				}
				else
				{
					action.Damage = Utility.Random((int)MinDamage, (int)MaxDamage + 1);
				}
			}

			action.Victim = target;
			action.Attacker = this;
			action.Weapon = weapon;

			if (m_pendingCombatAbility != null && m_pendingCombatAbility.IsCasting)
			{
				// Pending combat ability
				var ability = m_pendingCombatAbility;
				// get boni, damage and let the Spell impact
				var multiplier = 100;
				SpellEffect effect = null;
				foreach (var effectHandler in ability.Handlers)
				{
					if (effectHandler.Effect.IsStrikeEffectFlat)
					{
						action.Damage += effectHandler.CalcEffectValue();
					}
					else if (effectHandler.Effect.IsStrikeEffectPct)
					{
						multiplier += effectHandler.CalcEffectValue();
					}

					if (effect == null)
					{
						// use the first effect
						effect = effectHandler.Effect;
					}
				}
				action.Damage = (action.Damage * multiplier) / 100;

				// send pending animation
				if (ability.IsInstant)
				{
					m_pendingCombatAbility.SendCastStart();
				}

				if (!ability.Spell.IsRangedAbility)
				{
					m_pendingCombatAbility.CheckHitAndSendSpellGo(true);
				}

				// prevent the ability from cancelling itself
				m_pendingCombatAbility = null;

				action.Schools = ability.Spell.SchoolMask;
				action.SpellEffect = effect;

				if (ability.Spell.IsAreaSpell)
				{
					var totalDmg = action.Damage;
					action.IsDot = false;

					// AoE spell
					foreach (var targ in ability.Targets)
					{
						action.Reset(this, (Unit)targ, weapon, totalDmg);
						action.DoAttack();
						if (ability.Spell.IsDualWieldAbility)
						{
							action.Reset(this, (Unit)targ, weapon, Utility.Random((int)MinOffHandDamage, (int)MaxOffHandDamage + 1));
							action.DoAttack();
						}
					}
				}
				else
				{
					// single target
					if (!action.DoAttack() &&
						ability.Spell.AttributesExC.Has(SpellAttributesExC.RequiresTwoWeapons))
					{
						// missed and is not attacking with both weapons -> don't trigger spell
						CancelPendingAbility();
						return;
					}
				}

				// Impact and trigger remaining effects (if not cancelled)
				if (!ability.Spell.IsRangedAbility)
				{
					ability.Impact(ability.Spell.IsOnNextStrike);
				}
			}
			else
			{
				m_extraAttacks += 1;
				do
				{
					action.Schools = weapon.Damages.AllSchools();
					if (action.Schools == DamageSchoolMask.None)
					{
						action.Schools = DamageSchoolMask.Physical;
					}

					// normal attack
					action.DoAttack();
				} while (--m_extraAttacks > 0);
			}
			action.OnFinished();
		}