Beispiel #1
0
        public uint CalculateRageRegen(ref UnitStructs.CalcDamageInfo damageinfo, bool isCrit, Unit victim, bool asPlayer)
        {
            uint rageToRegen = 0;

            if (asPlayer)
            {
                bool  isMain = damageinfo.attackType == AttackTypes.BASE_ATTACK;
                float speed  = ((Player)this).BaseAttackTime;
                if (!isMain)
                {
                    Item offHand = ((Player)this).Inventory.Backpack.GetItem((byte)InventorySlots.SLOT_OFFHAND);
                    if (offHand != null)
                    {
                        speed = offHand.Template.WeaponSpeed;
                    }
                }
                rageToRegen = (uint)(((15 * damageinfo.damage) / (4 * FormulaData.RageConversionValue(this.Level))) + (((isMain ? 3.5 : 1.75) * (isCrit ? 2 : 1)) / 2));
            }
            else
            {
                rageToRegen = (uint)(2.5 * (damageinfo.damage / FormulaData.RageConversionValue(victim.Level)));
            }
            return(rageToRegen < 1 ? 1 : rageToRegen);
        }
Beispiel #2
0
        public void SendAttackStateUpdate(UnitStructs.CalcDamageInfo damageInfo)
        {
            PacketWriter data = new PacketWriter(Opcodes.SMSG_ATTACKERSTATEUPDATE);

            data.WriteUInt32(0xE2); //TODO : Figure out what each of these types are
            data.WriteUInt64(this.Guid);
            data.WriteUInt64(damageInfo.target);
            data.WriteUInt32(damageInfo.damage);
            data.WriteUInt8(1);

            data.WriteUInt32(damageInfo.damageSchoolMask);
            data.WriteFloat(damageInfo.damage);
            data.WriteUInt32(damageInfo.damage);
            data.WriteUInt32(damageInfo.absorb);
            data.WriteUInt32((uint)damageInfo.TargetState);
            data.WriteUInt32(damageInfo.resist); //?
            data.WriteUInt32(0);                 //?
            data.WriteUInt32(0);                 //?
            data.WriteUInt32(damageInfo.blocked_amount);
            GridManager.Instance.SendSurrounding(data, this);

            //Damage Effects
            DealDamage(damageInfo.target, damageInfo.damage);
        }
Beispiel #3
0
        public void CalculateMeleeDamage(Unit victim, uint damage, out UnitStructs.CalcDamageInfo damageInfo, AttackTypes attackType)
        {
            damageInfo = new UnitStructs.CalcDamageInfo
            {
                attacker         = this.Guid,
                target           = victim.Guid,
                damageSchoolMask = 0,
                attackType       = attackType,
                damage           = 0,
                cleanDamage      = 0,
                absorb           = 0,
                resist           = 0,
                blocked_amount   = 0,

                TargetState  = 0,
                HitInfo      = 0,
                procAttacker = ProcFlags.NONE,
                procVictim   = ProcFlags.NONE,
                procEx       = ProcFlagsExLegacy.NONE
            };

            if (victim == null)
            {
                if (this.IsTypeOf(ObjectTypes.TYPE_PLAYER))
                {
                    ((Player)this).LeaveCombat();
                }
                return;
            }


            if (this.IsDead || victim.IsDead)
            {
                if (this.IsTypeOf(ObjectTypes.TYPE_PLAYER))
                {
                    ((Player)this).LeaveCombat();
                }
                return;
            }

            // Select HitInfo/procAttacker/procVictim flag based on attack type
            switch (attackType)
            {
            case AttackTypes.BASE_ATTACK:
                damageInfo.procAttacker = ProcFlags.DONE_MELEE_AUTO_ATTACK | ProcFlags.DONE_MAINHAND_ATTACK;
                damageInfo.procVictim   = ProcFlags.TAKEN_MELEE_AUTO_ATTACK;
                break;

            case AttackTypes.OFFHAND_ATTACK:
                damageInfo.procAttacker = ProcFlags.DONE_MELEE_AUTO_ATTACK | ProcFlags.DONE_OFFHAND_ATTACK;
                damageInfo.procVictim   = ProcFlags.TAKEN_MELEE_AUTO_ATTACK;
                damageInfo.HitInfo      = HitInfo.OFFHAND;
                break;

            default:
                return;
            }

            // Physical Immune check

            damageInfo.damage += CalculateDamage(damageInfo.attackType, false, true);
            // Add melee damage bonus
            //damage = MeleeDamageBonusDone(damageInfo.target, damage, damageInfo.attackType);
            //damage = damageInfo.target.MeleeDamageBonusTaken(this, damage, damageInfo.attackType);

            // Calculate armor reduction
            //if (IsDamageReducedByArmor((SpellSchoolMask)(damageInfo.damageSchoolMask)))
            //{
            //damageInfo.damage = CalcArmorReducedDamage(damageInfo.target, damage, NULL, damageInfo.attackType);
            //damageInfo.cleanDamage += damage - damageInfo.damage;
            //}

            float critChance = 5 + ((float)this.Agility.Current / (this.Level < 3 || this.Agility.Current < 3 ? 1 : this.Level / 3)); //Just a quick dummy formula for crit percentage; 5% base + 1% for each (1/3 level X agility)
            bool  isCrit     = (new Random().Next(0, 100) <= critChance);

            damageInfo.TargetState = RollMeleeOutcome(victim);

            switch (damageInfo.TargetState)
            {
            case VictimStates.VS_EVADE:
                damageInfo.HitInfo    |= HitInfo.MISS | HitInfo.SWINGNOHITSOUND;
                damageInfo.procEx     |= ProcFlagsExLegacy.EVADE;
                damageInfo.damage      = 0;
                damageInfo.cleanDamage = 0;
                return;

            case VictimStates.VS_NONE:
                damageInfo.HitInfo    |= HitInfo.MISS;
                damageInfo.procEx     |= ProcFlagsExLegacy.MISS;
                damageInfo.damage      = 0;
                damageInfo.cleanDamage = 0;
                break;

            case VictimStates.VS_WOUND:
                if (isCrit)
                {
                    damageInfo.HitInfo |= HitInfo.CRITICALHIT;

                    damageInfo.procEx |= ProcFlagsExLegacy.CRITICAL_HIT;
                    // Crit bonus calc
                    damageInfo.damage += damageInfo.damage;
                    //float mod = 0.0f;

                    // Apply SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE or SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE
                    //if (damageInfo.attackType == RANGED_ATTACK)
                    //mod += damageInfo.target.GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE);
                    //else
                    //mod += damageInfo.target.GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE);

                    // Increase crit damage from SPELL_AURA_MOD_CRIT_DAMAGE_BONUS
                    //mod += (GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, damageInfo.damageSchoolMask) - 1.0f) * 100;

                    //if (mod != 0)
                    //AddPct(damageInfo.damage, mod);
                }
                else
                {
                    damageInfo.procEx |= ProcFlagsExLegacy.NORMAL_HIT;
                }
                break;

            case VictimStates.VS_PARRY:
                damageInfo.procEx      |= ProcFlagsExLegacy.PARRY;
                damageInfo.cleanDamage += damageInfo.damage;
                damageInfo.damage       = 0;
                break;

            case VictimStates.VS_DODGE:
                damageInfo.procEx      |= ProcFlagsExLegacy.DODGE;
                damageInfo.cleanDamage += damageInfo.damage;
                damageInfo.damage       = 0;
                break;

            case VictimStates.VS_BLOCK:
                //damageInfo.TargetState = VICTIMSTATE_HIT;
                damageInfo.procEx |= ProcFlagsExLegacy.BLOCK | ProcFlagsExLegacy.NORMAL_HIT;
                //30% damage blocked, double blocked amount if block is critical
                //damageInfo.blocked_amount = CalculatePct(damageInfo.damage, damageInfo.target.isBlockCritical() ? damageInfo.target.GetBlockPercent() * 2 : damageInfo.target.GetBlockPercent());
                damageInfo.damage      -= damageInfo.blocked_amount;
                damageInfo.cleanDamage += damageInfo.blocked_amount;
                break;
            }

            //Always apply HITINFO_AFFECTS_VICTIM in case its not a miss
            if (!Convert.ToBoolean(damageInfo.HitInfo & HitInfo.MISS))
            {
                damageInfo.HitInfo |= HitInfo.AFFECTS_VICTIM;
            }

            float resilienceReduction = (this.Armor.BaseAmount + 400 + 85 * (int)this.Level);

            if (resilienceReduction > 0.75f)
            {
                resilienceReduction = 0.75f;
            }
            else if (resilienceReduction < 0)
            {
                resilienceReduction = 0;
            }

            damageInfo.resist = (uint)resilienceReduction;

            //Calculate absorb resist
            if ((int)damageInfo.damage > 0)
            {
                damageInfo.procVictim |= ProcFlags.TAKEN_DAMAGE;
                // Calculate absorb & resists
                //CalcAbsorbResist(damageInfo.target, SpellSchoolMask(damageInfo.damageSchoolMask), DIRECT_DAMAGE, damageInfo.damage, &damageInfo.absorb, &damageInfo.resist);

                if (damageInfo.absorb != 0)
                {
                    damageInfo.HitInfo |= (damageInfo.damage - damageInfo.absorb == 0 ? HitInfo.FULL_ABSORB : HitInfo.PARTIAL_ABSORB);
                    damageInfo.procEx  |= ProcFlagsExLegacy.ABSORB;
                }

                if (damageInfo.resist != 0)
                {
                    damageInfo.HitInfo |= (damageInfo.damage - damageInfo.resist == 0 ? HitInfo.FULL_RESIST : HitInfo.PARTIAL_RESIST);
                }

                damageInfo.damage -= damageInfo.absorb + damageInfo.resist;
            }
            else //Just incase
            {
                damageInfo.damage = 0;
            }

            if (damageInfo.damage < 0)
            {
                damageInfo.damage = 0;
            }

            if (damageInfo.cleanDamage < 0)
            {
                damageInfo.cleanDamage = 0;
            }

            // Rage calculation
            if (damageInfo.damage > 0)
            {
                if (this.Class == (byte)Classes.CLASS_WARRIOR)
                {
                    this.Rage.Current = (this.Rage.Current / 10) + CalculateRageRegen(ref damageInfo, isCrit, victim, true);
                    if (this.Rage.Current > 1000)
                    {
                        this.Rage.Current = 100;
                    }
                }
                if (victim is Player && ((Player)victim).Class == (byte)Classes.CLASS_WARRIOR)
                {
                    victim.Rage.Current = (victim.Rage.Current / 10) + CalculateRageRegen(ref damageInfo, isCrit, victim, false);
                    if (victim.Rage.Current > 1000)
                    {
                        victim.Rage.Current = 100;
                    }
                }
            }
        }
Beispiel #4
0
        public void SendAttackStateUpdate(UnitStructs.CalcDamageInfo damageInfo)
        {
            PacketWriter data = new PacketWriter(Opcodes.SMSG_ATTACKERSTATEUPDATE);

            data.WriteUInt32(0xE2); //TODO : Figure out what each of these types are
            data.WriteUInt64(this.Guid);
            data.WriteUInt64(damageInfo.target);
            data.WriteUInt32(damageInfo.damage);
            data.WriteUInt8(1);

            data.WriteUInt32(damageInfo.damageSchoolMask);
            data.WriteFloat(damageInfo.damage);
            data.WriteUInt32(damageInfo.damage);
            data.WriteUInt32(damageInfo.absorb);
            data.WriteUInt32((uint)damageInfo.TargetState);
            data.WriteUInt32(damageInfo.resist); //?
            data.WriteUInt32(0);                 //?
            data.WriteUInt32(0);                 //?
            data.WriteUInt32(damageInfo.blocked_amount);
            GridManager.Instance.SendSurrounding(data, this);

            //Damage Effects
            if (damageInfo.damage > 0)
            {
                if (!this.UnitFlags.HasFlag((uint)Common.Constants.UnitFlags.UNIT_FLAG_IN_COMBAT))
                {
                    Flag.SetFlag(ref UnitFlags, (uint)Common.Constants.UnitFlags.UNIT_FLAG_IN_COMBAT);
                }

                Unit target = Database.Creatures.TryGet <Unit>(damageInfo.target) ?? Database.Players.TryGet <Unit>(damageInfo.target);
                if (target == null)
                {
                    return;
                }

                if (!target.UnitFlags.HasFlag((uint)Common.Constants.UnitFlags.UNIT_FLAG_IN_COMBAT))
                {
                    Flag.SetFlag(ref target.UnitFlags, (uint)Common.Constants.UnitFlags.UNIT_FLAG_IN_COMBAT);
                }

                int health = (int)target.Health.Current - (int)damageInfo.damage;
                if (health < 0)
                {
                    health = 0;                       //Prevent uint overflow
                }
                target.Health.Current = (uint)health; //Update health

                //Update units
                if (IsTypeOf(ObjectTypes.TYPE_PLAYER))
                {
                    Player   p = ((Player)this);
                    Creature c = ((Creature)target);

                    if (!c.IsAttacking) //Set attacking state
                    {
                        c.IsAttacking  = true;
                        c.InCombat     = true;
                        c.CombatTarget = this.Guid;
                    }

                    if (c.AttackTimers[AttackTypes.BASE_ATTACK] != (int)c.BaseAttackTime)
                    {
                        if (c.AttackTimers[AttackTypes.BASE_ATTACK] + 200 > c.BaseAttackTime)
                        {
                            c.SetAttackTimer(AttackTypes.BASE_ATTACK, c.BaseAttackTime);
                        }
                        else
                        {
                            c.SetAttackTimer(AttackTypes.OFFHAND_ATTACK, c.AttackTimers[AttackTypes.BASE_ATTACK] + 200);
                        }
                    }

                    if (c.Health.Current <= 0)
                    {
                        Unit dump;
                        c.Die(p);

                        if (p.Attackers.ContainsKey(c.Guid))
                        {
                            p.Attackers.TryRemove(c.Guid, out dump);
                        }

                        p.LeaveCombat();
                    }
                }
                else
                {
                    Player   p = (Player)target;
                    Creature c = (Creature)this;

                    if (p.Health.Current <= 0)
                    {
                        p.SetRoot(true);
                        p.IsDead       = true;
                        p.UnitFlags    = (uint)Common.Constants.UnitFlags.UNIT_FLAG_DEAD;
                        p.DynamicFlags = (uint)UnitDynamicTypes.UNIT_DYNAMIC_DEAD;
                        p.StandState   = (byte)Common.Constants.StandState.UNIT_DEAD;

                        Flag.RemoveFlag(ref p.UnitFlags, (uint)Common.Constants.UnitFlags.UNIT_FLAG_IN_COMBAT); //Remove combat flags
                        Flag.RemoveFlag(ref c.UnitFlags, (uint)Common.Constants.UnitFlags.UNIT_FLAG_IN_COMBAT);

                        p.LeaveCombat();
                    }
                }

                GridManager.Instance.SendSurrounding(target.BuildUpdate(), target);
            }
        }