[11825] Implement creature offhand attack. based on patch from maxxx2021

also drop some archaic Unit's code
This commit is contained in:
SilverIce 2011-10-16 00:00:58 +03:00
parent 4bd3976e30
commit 70a6a1ce76
9 changed files with 104 additions and 102 deletions

View file

@ -350,8 +350,10 @@ bool Creature::UpdateEntry(uint32 Entry, Team team, const CreatureData *data /*=
SetUInt32Value(UNIT_NPC_FLAGS,GetCreatureInfo()->npcflag); SetUInt32Value(UNIT_NPC_FLAGS,GetCreatureInfo()->npcflag);
SetAttackTime(BASE_ATTACK, GetCreatureInfo()->baseattacktime); uint32 attackTimer = GetCreatureInfo()->baseattacktime;
SetAttackTime(OFF_ATTACK, GetCreatureInfo()->baseattacktime);
SetAttackTime(BASE_ATTACK, attackTimer);
SetAttackTime(OFF_ATTACK, attackTimer - attackTimer/4);
SetAttackTime(RANGED_ATTACK,GetCreatureInfo()->rangeattacktime); SetAttackTime(RANGED_ATTACK,GetCreatureInfo()->rangeattacktime);
uint32 unitFlags = GetCreatureInfo()->unit_flags; 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, MINDAMAGE, cinfo->mindmg * damagemod);
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, cinfo->maxdmg * damagemod); SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, cinfo->maxdmg * damagemod);
SetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE,cinfo->minrangedmg * damagemod); SetBaseWeaponDamage(OFF_ATTACK, MINDAMAGE, cinfo->mindmg * damagemod);
SetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE,cinfo->maxrangedmg * 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); SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, cinfo->attackpower * damagemod);
} }

View file

@ -120,20 +120,5 @@ CanCastResult CreatureAI::DoCastSpellIfCan(Unit* pTarget, uint32 uiSpell, uint32
bool CreatureAI::DoMeleeAttackIfReady() bool CreatureAI::DoMeleeAttackIfReady()
{ {
// Check target return m_creature->UpdateMeleeAttackingState();
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;
} }

View file

@ -159,12 +159,8 @@ void PetAI::UpdateAI(const uint32 diff)
return; return;
} }
// not required to be stopped case // 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()) if (!m_creature->getVictim())
return; return;

View file

@ -1230,71 +1230,11 @@ void Player::Update( uint32 update_diff, uint32 p_time )
if (hasUnitState(UNIT_STAT_MELEE_ATTACKING)) if (hasUnitState(UNIT_STAT_MELEE_ATTACKING))
{ {
UpdateMeleeAttackingState();
Unit *pVictim = getVictim(); Unit *pVictim = getVictim();
if (pVictim && !IsNonMeleeSpellCasted(false)) 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(); Player *vOwner = pVictim->GetCharmerOrOwnerPlayerOrPlayerItself();
if (vOwner && vOwner->IsPvP() && !IsInDuelWith(vOwner)) if (vOwner && vOwner->IsPvP() && !IsInDuelWith(vOwner))
{ {

View file

@ -1821,6 +1821,9 @@ class MANGOS_DLL_SPEC Player : public Unit
void DestroyForPlayer( Player *target, bool anim = false ) const; void DestroyForPlayer( Player *target, bool anim = false ) const;
void SendLogXPGain(uint32 GivenXP,Unit* victim,uint32 RestXP); void SendLogXPGain(uint32 GivenXP,Unit* victim,uint32 RestXP);
uint8 LastSwingErrorMsg() const { return m_swingErrorMsg; }
void SwingErrorMsg(uint8 val) { m_swingErrorMsg = val; }
// notifiers // notifiers
void SendAttackSwingCantAttack(); void SendAttackSwingCantAttack();
void SendAttackSwingCancelAttack(); void SendAttackSwingCancelAttack();

View file

@ -870,7 +870,7 @@ void Creature::UpdateAttackPowerAndDamage(bool ranged)
uint16 index_mod = UNIT_FIELD_ATTACK_POWER_MODS; uint16 index_mod = UNIT_FIELD_ATTACK_POWER_MODS;
uint16 index_mult = UNIT_FIELD_ATTACK_POWER_MULTIPLIER; uint16 index_mult = UNIT_FIELD_ATTACK_POWER_MULTIPLIER;
if(ranged) if (ranged)
{ {
index = UNIT_FIELD_RANGED_ATTACK_POWER; index = UNIT_FIELD_RANGED_ATTACK_POWER;
index_mod = UNIT_FIELD_RANGED_ATTACK_POWER_MODS; 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 SetInt32Value(index_mod, (uint32)attPowerMod); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field
SetFloatValue(index_mult, attPowerMultiplier); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field SetFloatValue(index_mult, attPowerMultiplier); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field
if(ranged) if (ranged)
return; return;
//automatically update weapon damage after attack power modification //automatically update weapon damage after attack power modification
UpdateDamagePhysical(BASE_ATTACK); UpdateDamagePhysical(BASE_ATTACK);
UpdateDamagePhysical(OFF_ATTACK);
} }
void Creature::UpdateDamagePhysical(WeaponAttackType attType) void Creature::UpdateDamagePhysical(WeaponAttackType attType)
{ {
if(attType > BASE_ATTACK) if (attType > OFF_ATTACK)
return; 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 */ /* difference in AP between current attack power and base value from DB */
float att_pwr_change = GetTotalAttackPowerValue(attType) - GetCreatureInfo()->attackpower; 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 total_pct = GetModifierValue(unitMod, TOTAL_PCT);
float dmg_multiplier = GetCreatureInfo()->dmg_multiplier; float dmg_multiplier = GetCreatureInfo()->dmg_multiplier;
float weapon_mindamage = GetWeaponDamageRange(BASE_ATTACK, MINDAMAGE); float weapon_mindamage = GetWeaponDamageRange(attType, MINDAMAGE);
float weapon_maxdamage = GetWeaponDamageRange(BASE_ATTACK, MAXDAMAGE); float weapon_maxdamage = GetWeaponDamageRange(attType, MAXDAMAGE);
float mindamage = ((base_value + weapon_mindamage) * dmg_multiplier * base_pct + total_value) * total_pct; 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; float maxdamage = ((base_value + weapon_maxdamage) * dmg_multiplier * base_pct + total_value) * total_pct;
SetStatFloatValue(UNIT_FIELD_MINDAMAGE, mindamage); SetStatFloatValue(attType == BASE_ATTACK ? UNIT_FIELD_MINDAMAGE : UNIT_FIELD_MINOFFHANDDAMAGE, mindamage);
SetStatFloatValue(UNIT_FIELD_MAXDAMAGE, maxdamage); SetStatFloatValue(attType == BASE_ATTACK ? UNIT_FIELD_MAXDAMAGE : UNIT_FIELD_MAXOFFHANDDAMAGE, maxdamage);
} }
/*####################################### /*#######################################

View file

@ -209,8 +209,6 @@ Unit::Unit() :
m_castCounter = 0; m_castCounter = 0;
m_addDmgOnce = 0;
//m_Aura = NULL; //m_Aura = NULL;
//m_AurasCheck = 2000; //m_AurasCheck = 2000;
//m_removeAuraTimer = 4; //m_removeAuraTimer = 4;
@ -234,7 +232,8 @@ Unit::Unit() :
m_auraModifiersGroup[i][TOTAL_VALUE] = 0.0f; m_auraModifiersGroup[i][TOTAL_VALUE] = 0.0f;
m_auraModifiersGroup[i][TOTAL_PCT] = 1.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; m_auraModifiersGroup[UNIT_MOD_DAMAGE_OFFHAND][TOTAL_PCT] = 0.5f;
for (int i = 0; i < MAX_ATTACK; ++i) 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) ); 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 // update abilities available only for fraction of time
UpdateReactives( update_diff ); UpdateReactives( update_diff );
@ -351,6 +355,67 @@ void Unit::Update( uint32 update_diff, uint32 p_time )
i_motionMaster.UpdateMotion(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 bool Unit::haveOffhandWeapon() const
{ {
if (!CanUseEquippedWeapon(OFF_ATTACK)) if (!CanUseEquippedWeapon(OFF_ATTACK))
@ -359,7 +424,15 @@ bool Unit::haveOffhandWeapon() const
if(GetTypeId() == TYPEID_PLAYER) if(GetTypeId() == TYPEID_PLAYER)
return ((Player*)this)->GetWeaponForAttack(OFF_ATTACK,true,true); return ((Player*)this)->GetWeaponForAttack(OFF_ATTACK,true,true);
else 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; return false;
}
} }
void Unit::SendHeartBeat() void Unit::SendHeartBeat()

View file

@ -1112,6 +1112,7 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
uint32 getAttackTimer(WeaponAttackType type) const { return m_attackTimer[type]; } uint32 getAttackTimer(WeaponAttackType type) const { return m_attackTimer[type]; }
bool isAttackReady(WeaponAttackType type = BASE_ATTACK) const { return m_attackTimer[type] == 0; } bool isAttackReady(WeaponAttackType type = BASE_ATTACK) const { return m_attackTimer[type] == 0; }
bool haveOffhandWeapon() const; bool haveOffhandWeapon() const;
bool UpdateMeleeAttackingState();
bool CanUseEquippedWeapon(WeaponAttackType attackType) const bool CanUseEquippedWeapon(WeaponAttackType attackType) const
{ {
if (IsInFeralForm()) if (IsInFeralForm())
@ -1426,8 +1427,6 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
void SendThreatRemove(HostileReference* pHostileReference); void SendThreatRemove(HostileReference* pHostileReference);
void SendThreatUpdate(); void SendThreatUpdate();
virtual void MoveOutOfRange(Player &) { };
bool isAlive() const { return (m_deathState == ALIVE); }; bool isAlive() const { return (m_deathState == ALIVE); };
bool isDead() const { return ( m_deathState == DEAD || m_deathState == CORPSE ); }; bool isDead() const { return ( m_deathState == DEAD || m_deathState == CORPSE ); };
DeathState getDeathState() const { return m_deathState; }; DeathState getDeathState() const { return m_deathState; };
@ -1592,7 +1591,6 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
bool CheckAndIncreaseCastCounter(); bool CheckAndIncreaseCastCounter();
void DecreaseCastCounter() { if (m_castCounter) --m_castCounter; } void DecreaseCastCounter() { if (m_castCounter) --m_castCounter; }
uint32 m_addDmgOnce;
ObjectGuid m_ObjectSlotGuid[4]; ObjectGuid m_ObjectSlotGuid[4];
uint32 m_detectInvisibilityMask; uint32 m_detectInvisibilityMask;
uint32 m_invisibilityMask; uint32 m_invisibilityMask;

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__ #ifndef __REVISION_NR_H__
#define __REVISION_NR_H__ #define __REVISION_NR_H__
#define REVISION_NR "11824" #define REVISION_NR "11825"
#endif // __REVISION_NR_H__ #endif // __REVISION_NR_H__