mirror of
https://github.com/mangosfour/server.git
synced 2025-12-12 01:37:00 +00:00
[11825] Implement creature offhand attack. based on patch from maxxx2021
also drop some archaic Unit's code
This commit is contained in:
parent
4bd3976e30
commit
70a6a1ce76
9 changed files with 104 additions and 102 deletions
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*#######################################
|
||||
|
|
|
|||
|
|
@ -209,8 +209,6 @@ Unit::Unit() :
|
|||
|
||||
m_castCounter = 0;
|
||||
|
||||
m_addDmgOnce = 0;
|
||||
|
||||
//m_Aura = NULL;
|
||||
//m_AurasCheck = 2000;
|
||||
//m_removeAuraTimer = 4;
|
||||
|
|
@ -234,6 +232,7 @@ Unit::Unit() :
|
|||
m_auraModifiersGroup[i][TOTAL_VALUE] = 0.0f;
|
||||
m_auraModifiersGroup[i][TOTAL_PCT] = 1.0f;
|
||||
}
|
||||
|
||||
// implement 50% base damage from offhand
|
||||
m_auraModifiersGroup[UNIT_MOD_DAMAGE_OFFHAND][TOTAL_PCT] = 0.5f;
|
||||
|
||||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#ifndef __REVISION_NR_H__
|
||||
#define __REVISION_NR_H__
|
||||
#define REVISION_NR "11824"
|
||||
#define REVISION_NR "11825"
|
||||
#endif // __REVISION_NR_H__
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue