diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp index 35de0325d..682a67085 100644 --- a/src/game/Creature.cpp +++ b/src/game/Creature.cpp @@ -350,8 +350,10 @@ bool Creature::UpdateEntry(uint32 Entry, Team team, const CreatureData *data /*= SetUInt32Value(UNIT_NPC_FLAGS,GetCreatureInfo()->npcflag); - SetAttackTime(BASE_ATTACK, GetCreatureInfo()->baseattacktime); - SetAttackTime(OFF_ATTACK, GetCreatureInfo()->baseattacktime); + uint32 attackTimer = GetCreatureInfo()->baseattacktime; + + SetAttackTime(BASE_ATTACK, attackTimer); + SetAttackTime(OFF_ATTACK, attackTimer - attackTimer/4); SetAttackTime(RANGED_ATTACK,GetCreatureInfo()->rangeattacktime); uint32 unitFlags = GetCreatureInfo()->unit_flags; @@ -1178,8 +1180,11 @@ void Creature::SelectLevel(const CreatureInfo *cinfo, float percentHealth, float SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, cinfo->mindmg * damagemod); SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, cinfo->maxdmg * damagemod); - SetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE,cinfo->minrangedmg * damagemod); - SetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE,cinfo->maxrangedmg * damagemod); + SetBaseWeaponDamage(OFF_ATTACK, MINDAMAGE, cinfo->mindmg * damagemod); + SetBaseWeaponDamage(OFF_ATTACK, MAXDAMAGE, cinfo->maxdmg * damagemod); + + SetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE, cinfo->minrangedmg * damagemod); + SetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE, cinfo->maxrangedmg * damagemod); SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, cinfo->attackpower * damagemod); } diff --git a/src/game/CreatureAI.cpp b/src/game/CreatureAI.cpp index fd0829ca4..4dcc82848 100644 --- a/src/game/CreatureAI.cpp +++ b/src/game/CreatureAI.cpp @@ -120,20 +120,5 @@ CanCastResult CreatureAI::DoCastSpellIfCan(Unit* pTarget, uint32 uiSpell, uint32 bool CreatureAI::DoMeleeAttackIfReady() { - // Check target - if (!m_creature->getVictim()) - return false; - - // Make sure our attack is ready before checking distance - if (!m_creature->isAttackReady()) - return false; - - // If we are within range melee the target - if (!m_creature->CanReachWithMeleeAttack(m_creature->getVictim())) - return false; - - m_creature->AttackerStateUpdate(m_creature->getVictim()); - m_creature->resetAttackTimer(); - - return true; + return m_creature->UpdateMeleeAttackingState(); } diff --git a/src/game/PetAI.cpp b/src/game/PetAI.cpp index 8bf259597..b5ca2d3ab 100644 --- a/src/game/PetAI.cpp +++ b/src/game/PetAI.cpp @@ -159,12 +159,8 @@ void PetAI::UpdateAI(const uint32 diff) return; } // not required to be stopped case - else if (m_creature->isAttackReady() && meleeReach) + else if (DoMeleeAttackIfReady()) { - m_creature->AttackerStateUpdate(m_creature->getVictim()); - - m_creature->resetAttackTimer(); - if (!m_creature->getVictim()) return; diff --git a/src/game/Player.cpp b/src/game/Player.cpp index e97826e68..aaac2126c 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -1230,71 +1230,11 @@ void Player::Update( uint32 update_diff, uint32 p_time ) if (hasUnitState(UNIT_STAT_MELEE_ATTACKING)) { + UpdateMeleeAttackingState(); + Unit *pVictim = getVictim(); if (pVictim && !IsNonMeleeSpellCasted(false)) { - // default combat reach 10 - // TODO add weapon,skill check - - if (isAttackReady(BASE_ATTACK)) - { - if (!CanReachWithMeleeAttack(pVictim)) - { - setAttackTimer(BASE_ATTACK,100); - if (m_swingErrorMsg != 1) // send single time (client auto repeat) - { - SendAttackSwingNotInRange(); - m_swingErrorMsg = 1; - } - } - //120 degrees of radiant range - else if (!HasInArc(2*M_PI_F/3, pVictim)) - { - setAttackTimer(BASE_ATTACK,100); - if (m_swingErrorMsg != 2) // send single time (client auto repeat) - { - SendAttackSwingBadFacingAttack(); - m_swingErrorMsg = 2; - } - } - else - { - m_swingErrorMsg = 0; // reset swing error state - - // prevent base and off attack in same time, delay attack at 0.2 sec - if (haveOffhandWeapon()) - { - uint32 off_att = getAttackTimer(OFF_ATTACK); - if(off_att < ATTACK_DISPLAY_DELAY) - setAttackTimer(OFF_ATTACK,ATTACK_DISPLAY_DELAY); - } - AttackerStateUpdate(pVictim, BASE_ATTACK); - resetAttackTimer(BASE_ATTACK); - } - } - - if (haveOffhandWeapon() && isAttackReady(OFF_ATTACK)) - { - if (!CanReachWithMeleeAttack(pVictim)) - { - setAttackTimer(OFF_ATTACK,100); - } - else if (!HasInArc(2*M_PI_F/3, pVictim)) - { - setAttackTimer(OFF_ATTACK,100); - } - else - { - // prevent base and off attack in same time, delay attack at 0.2 sec - uint32 base_att = getAttackTimer(BASE_ATTACK); - if(base_att < ATTACK_DISPLAY_DELAY) - setAttackTimer(BASE_ATTACK,ATTACK_DISPLAY_DELAY); - // do attack - AttackerStateUpdate(pVictim, OFF_ATTACK); - resetAttackTimer(OFF_ATTACK); - } - } - Player *vOwner = pVictim->GetCharmerOrOwnerPlayerOrPlayerItself(); if (vOwner && vOwner->IsPvP() && !IsInDuelWith(vOwner)) { diff --git a/src/game/Player.h b/src/game/Player.h index 4c8669b7b..d3bf2160a 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -1821,6 +1821,9 @@ class MANGOS_DLL_SPEC Player : public Unit void DestroyForPlayer( Player *target, bool anim = false ) const; void SendLogXPGain(uint32 GivenXP,Unit* victim,uint32 RestXP); + uint8 LastSwingErrorMsg() const { return m_swingErrorMsg; } + void SwingErrorMsg(uint8 val) { m_swingErrorMsg = val; } + // notifiers void SendAttackSwingCantAttack(); void SendAttackSwingCancelAttack(); diff --git a/src/game/StatSystem.cpp b/src/game/StatSystem.cpp index e8eea707c..3fc450f9f 100644 --- a/src/game/StatSystem.cpp +++ b/src/game/StatSystem.cpp @@ -870,7 +870,7 @@ void Creature::UpdateAttackPowerAndDamage(bool ranged) uint16 index_mod = UNIT_FIELD_ATTACK_POWER_MODS; uint16 index_mult = UNIT_FIELD_ATTACK_POWER_MULTIPLIER; - if(ranged) + if (ranged) { index = UNIT_FIELD_RANGED_ATTACK_POWER; index_mod = UNIT_FIELD_RANGED_ATTACK_POWER_MODS; @@ -885,18 +885,20 @@ void Creature::UpdateAttackPowerAndDamage(bool ranged) SetInt32Value(index_mod, (uint32)attPowerMod); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field SetFloatValue(index_mult, attPowerMultiplier); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field - if(ranged) + if (ranged) return; + //automatically update weapon damage after attack power modification UpdateDamagePhysical(BASE_ATTACK); + UpdateDamagePhysical(OFF_ATTACK); } void Creature::UpdateDamagePhysical(WeaponAttackType attType) { - if(attType > BASE_ATTACK) + if (attType > OFF_ATTACK) return; - UnitMods unitMod = UNIT_MOD_DAMAGE_MAINHAND; + UnitMods unitMod = (attType == BASE_ATTACK ? UNIT_MOD_DAMAGE_MAINHAND : UNIT_MOD_DAMAGE_OFFHAND); /* difference in AP between current attack power and base value from DB */ float att_pwr_change = GetTotalAttackPowerValue(attType) - GetCreatureInfo()->attackpower; @@ -906,14 +908,14 @@ void Creature::UpdateDamagePhysical(WeaponAttackType attType) float total_pct = GetModifierValue(unitMod, TOTAL_PCT); float dmg_multiplier = GetCreatureInfo()->dmg_multiplier; - float weapon_mindamage = GetWeaponDamageRange(BASE_ATTACK, MINDAMAGE); - float weapon_maxdamage = GetWeaponDamageRange(BASE_ATTACK, MAXDAMAGE); + float weapon_mindamage = GetWeaponDamageRange(attType, MINDAMAGE); + float weapon_maxdamage = GetWeaponDamageRange(attType, MAXDAMAGE); float mindamage = ((base_value + weapon_mindamage) * dmg_multiplier * base_pct + total_value) * total_pct; float maxdamage = ((base_value + weapon_maxdamage) * dmg_multiplier * base_pct + total_value) * total_pct; - SetStatFloatValue(UNIT_FIELD_MINDAMAGE, mindamage); - SetStatFloatValue(UNIT_FIELD_MAXDAMAGE, maxdamage); + SetStatFloatValue(attType == BASE_ATTACK ? UNIT_FIELD_MINDAMAGE : UNIT_FIELD_MINOFFHANDDAMAGE, mindamage); + SetStatFloatValue(attType == BASE_ATTACK ? UNIT_FIELD_MAXDAMAGE : UNIT_FIELD_MAXOFFHANDDAMAGE, maxdamage); } /*####################################### diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index 5bbeb130f..7b43aa0f2 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -209,8 +209,6 @@ Unit::Unit() : m_castCounter = 0; - m_addDmgOnce = 0; - //m_Aura = NULL; //m_AurasCheck = 2000; //m_removeAuraTimer = 4; @@ -234,7 +232,8 @@ Unit::Unit() : m_auraModifiersGroup[i][TOTAL_VALUE] = 0.0f; m_auraModifiersGroup[i][TOTAL_PCT] = 1.0f; } - // implement 50% base damage from offhand + + // implement 50% base damage from offhand m_auraModifiersGroup[UNIT_MOD_DAMAGE_OFFHAND][TOTAL_PCT] = 0.5f; for (int i = 0; i < MAX_ATTACK; ++i) @@ -341,6 +340,11 @@ void Unit::Update( uint32 update_diff, uint32 p_time ) setAttackTimer(BASE_ATTACK, (update_diff >= base_att ? 0 : base_att - update_diff) ); } + if (uint32 base_att = getAttackTimer(OFF_ATTACK)) + { + setAttackTimer(OFF_ATTACK, (update_diff >= base_att ? 0 : base_att - update_diff) ); + } + // update abilities available only for fraction of time UpdateReactives( update_diff ); @@ -351,6 +355,67 @@ void Unit::Update( uint32 update_diff, uint32 p_time ) i_motionMaster.UpdateMotion(p_time); } +bool Unit::UpdateMeleeAttackingState() +{ + Unit *victim = getVictim(); + if (!victim || IsNonMeleeSpellCasted(false)) + return false; + + if (!isAttackReady(BASE_ATTACK) && !(isAttackReady(OFF_ATTACK) && haveOffhandWeapon())) + return false; + + uint8 swingError = 0; + if (!CanReachWithMeleeAttack(victim)) + { + setAttackTimer(BASE_ATTACK,100); + setAttackTimer(OFF_ATTACK,100); + swingError = 1; + } + //120 degrees of radiant range + else if (!HasInArc(2*M_PI_F/3, victim)) + { + setAttackTimer(BASE_ATTACK,100); + setAttackTimer(OFF_ATTACK,100); + swingError = 2; + } + else + { + if (isAttackReady(BASE_ATTACK)) + { + // prevent base and off attack in same time, delay attack at 0.2 sec + if (haveOffhandWeapon()) + { + if (getAttackTimer(OFF_ATTACK) < ATTACK_DISPLAY_DELAY) + setAttackTimer(OFF_ATTACK,ATTACK_DISPLAY_DELAY); + } + AttackerStateUpdate(victim, BASE_ATTACK); + resetAttackTimer(BASE_ATTACK); + } + if (haveOffhandWeapon() && isAttackReady(OFF_ATTACK)) + { + // prevent base and off attack in same time, delay attack at 0.2 sec + uint32 base_att = getAttackTimer(BASE_ATTACK); + if (base_att < ATTACK_DISPLAY_DELAY) + setAttackTimer(BASE_ATTACK,ATTACK_DISPLAY_DELAY); + // do attack + AttackerStateUpdate(victim, OFF_ATTACK); + resetAttackTimer(OFF_ATTACK); + } + } + + Player* player = (GetTypeId() == TYPEID_PLAYER ? (Player*)this : NULL); + if (player && swingError != player->LastSwingErrorMsg()) + { + if (swingError == 1) + player->SendAttackSwingNotInRange(); + else if (swingError == 2) + player->SendAttackSwingBadFacingAttack(); + player->SwingErrorMsg(swingError); + } + + return swingError == 0; +} + bool Unit::haveOffhandWeapon() const { if (!CanUseEquippedWeapon(OFF_ATTACK)) @@ -359,7 +424,15 @@ bool Unit::haveOffhandWeapon() const if(GetTypeId() == TYPEID_PLAYER) return ((Player*)this)->GetWeaponForAttack(OFF_ATTACK,true,true); else + { + uint32 ItemId = GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1); + ItemEntry const* itemInfo = sItemStore.LookupEntry(ItemId); + + if (itemInfo && itemInfo->Class == ITEM_CLASS_WEAPON) + return true; + return false; + } } void Unit::SendHeartBeat() diff --git a/src/game/Unit.h b/src/game/Unit.h index 9ab30450c..bcd7a91cf 100644 --- a/src/game/Unit.h +++ b/src/game/Unit.h @@ -1112,6 +1112,7 @@ class MANGOS_DLL_SPEC Unit : public WorldObject uint32 getAttackTimer(WeaponAttackType type) const { return m_attackTimer[type]; } bool isAttackReady(WeaponAttackType type = BASE_ATTACK) const { return m_attackTimer[type] == 0; } bool haveOffhandWeapon() const; + bool UpdateMeleeAttackingState(); bool CanUseEquippedWeapon(WeaponAttackType attackType) const { if (IsInFeralForm()) @@ -1426,8 +1427,6 @@ class MANGOS_DLL_SPEC Unit : public WorldObject void SendThreatRemove(HostileReference* pHostileReference); void SendThreatUpdate(); - virtual void MoveOutOfRange(Player &) { }; - bool isAlive() const { return (m_deathState == ALIVE); }; bool isDead() const { return ( m_deathState == DEAD || m_deathState == CORPSE ); }; DeathState getDeathState() const { return m_deathState; }; @@ -1592,7 +1591,6 @@ class MANGOS_DLL_SPEC Unit : public WorldObject bool CheckAndIncreaseCastCounter(); void DecreaseCastCounter() { if (m_castCounter) --m_castCounter; } - uint32 m_addDmgOnce; ObjectGuid m_ObjectSlotGuid[4]; uint32 m_detectInvisibilityMask; uint32 m_invisibilityMask; diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 77993be6b..efbf94549 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "11824" + #define REVISION_NR "11825" #endif // __REVISION_NR_H__