Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement Elapsed Time compensation to Attack Timer adjustements and DW adjustment #2410

Open
wants to merge 8 commits into
base: development
Choose a base branch
from
67 changes: 36 additions & 31 deletions src/game/Objects/Unit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -291,14 +291,17 @@ void Unit::Update(uint32 update_diff, uint32 p_time)
ExtraAttacksLocked(false);
}

if (uint32 base_att = GetAttackTimer(BASE_ATTACK))
SetAttackTimer(BASE_ATTACK, (update_diff >= base_att ? 0 : base_att - update_diff));
if (int32 base_att = GetAttackTimer(BASE_ATTACK))
if (base_att > 0)
SetAttackTimer(BASE_ATTACK, base_att - update_diff);

if (uint32 base_att = GetAttackTimer(OFF_ATTACK))
SetAttackTimer(OFF_ATTACK, (update_diff >= base_att ? 0 : base_att - update_diff));
if (int32 off_att = GetAttackTimer(OFF_ATTACK))
if (off_att > 0)
SetAttackTimer(OFF_ATTACK, off_att - update_diff);

if (uint32 ranged_att = GetAttackTimer(RANGED_ATTACK))
SetAttackTimer(RANGED_ATTACK, (update_diff >= ranged_att ? 0 : ranged_att - update_diff));
if (int32 ranged_att = GetAttackTimer(RANGED_ATTACK))
if (ranged_att > 0)
SetAttackTimer(RANGED_ATTACK, ranged_att - update_diff);

if (IsAlive())
ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, GetHealth() < GetMaxHealth() * 0.20f);
Expand Down Expand Up @@ -357,6 +360,18 @@ void Unit::DelayAutoAttacks()
SetAttackTimer(OFF_ATTACK, 100);
}

void Unit::FirstAttackDelay()
{
if (IsAttackReady(BASE_ATTACK))
SetAttackTimer(BASE_ATTACK, 0); // Erase saved update timer diff from the swing timer
if (HaveOffhandWeapon()) // Doing an attack command sets offhand timer equal to half its swing speed.
{
int32 halfattack = int32(GetAttackTime(OFF_ATTACK) * m_modAttackSpeedPct[OFF_ATTACK] * 0.5);
if (GetAttackTimer(OFF_ATTACK) < halfattack)
SetAttackTimer(OFF_ATTACK, halfattack);
}
}

bool Unit::UpdateMeleeAttackingState()
{
Unit* pVictim = GetVictim();
Expand All @@ -379,24 +394,13 @@ bool Unit::UpdateMeleeAttackingState()

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(pVictim, BASE_ATTACK);
ResetAttackTimer(BASE_ATTACK);
ResetAttackTimer(BASE_ATTACK, true);
}
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(pVictim, OFF_ATTACK);
ResetAttackTimer(OFF_ATTACK);
ResetAttackTimer(OFF_ATTACK, true);
}
break;
}
Expand Down Expand Up @@ -473,9 +477,12 @@ void Unit::SendMovementPacket(uint16 opcode, bool includingSelf)
SendMovementMessageToSet(std::move(data), includingSelf);
}

void Unit::ResetAttackTimer(WeaponAttackType type)
void Unit::ResetAttackTimer(WeaponAttackType type, bool compensateDiff/*= false*/)
{
m_attackTimer[type] = uint32(GetAttackTime(type) * m_modAttackSpeedPct[type]);
if (compensateDiff && m_attackTimer[type] < 0)
m_attackTimer[type] += int32(GetAttackTime(type) * m_modAttackSpeedPct[type]);
else
m_attackTimer[type] = int32(GetAttackTime(type) * m_modAttackSpeedPct[type]);
}

void Unit::RemoveSpellsCausingAura(AuraType auraType, AuraRemoveMode mode)
Expand Down Expand Up @@ -1599,23 +1606,23 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss)
float percent20 = pVictim->GetAttackTime(OFF_ATTACK) * 0.20f;
float percent60 = 3.0f * percent20;
if (offtime > percent20 && offtime <= percent60)
pVictim->SetAttackTimer(OFF_ATTACK, uint32(percent20));
pVictim->SetAttackTimer(OFF_ATTACK, int32(percent20));
else if (offtime > percent60)
{
offtime -= 2.0f * percent20;
pVictim->SetAttackTimer(OFF_ATTACK, uint32(offtime));
pVictim->SetAttackTimer(OFF_ATTACK, int32(offtime));
}
}
else
{
float percent20 = pVictim->GetAttackTime(BASE_ATTACK) * 0.20f;
float percent60 = 3.0f * percent20;
if (basetime > percent20 && basetime <= percent60)
pVictim->SetAttackTimer(BASE_ATTACK, uint32(percent20));
pVictim->SetAttackTimer(BASE_ATTACK, int32(percent20));
else if (basetime > percent60)
{
basetime -= 2.0f * percent20;
pVictim->SetAttackTimer(BASE_ATTACK, uint32(basetime));
pVictim->SetAttackTimer(BASE_ATTACK, int32(basetime));
}
}
}
Expand Down Expand Up @@ -2866,7 +2873,7 @@ void Unit::_UpdateAutoRepeatSpell()
spell->prepare(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_targets);

// all went good, reset attack
ResetAttackTimer(RANGED_ATTACK);
ResetAttackTimer(RANGED_ATTACK, true); //Compensate Diff always because opener Attack delay is handled by m_AutoRepeatFirstCast
SetStandState(UNIT_STAND_STATE_STAND);
}
}
Expand Down Expand Up @@ -4614,6 +4621,8 @@ bool Unit::Attack(Unit* victim, bool meleeAttack)
// remove old target data
AttackStop(true);
}
else // not fighting already, do swing timer delays.
FirstAttackDelay();

// Set our target
SetTargetGuid(victim->GetObjectGuid());
Expand All @@ -4639,10 +4648,6 @@ bool Unit::Attack(Unit* victim, bool meleeAttack)
pGuardian->AI()->OwnerAttacked(victim);
}

// delay offhand weapon attack to next attack time
if (HaveOffhandWeapon())
ResetAttackTimer(OFF_ATTACK);

if (meleeAttack)
SendMeleeAttackStart(victim);

Expand Down Expand Up @@ -9274,7 +9279,7 @@ bool Unit::IsPolymorphed() const

bool Unit::IsAttackReady(WeaponAttackType type) const
{
return m_attackTimer[type] == 0;
return m_attackTimer[type] <= 0;
}

void Unit::SetDisplayId(uint32 displayId)
Expand Down
14 changes: 10 additions & 4 deletions src/game/Objects/Unit.h
Original file line number Diff line number Diff line change
Expand Up @@ -908,7 +908,7 @@ class Unit : public SpellCaster
HostileRefManager m_HostileRefManager; // Manage all Units that are threatened by us
std::vector<ObjectGuid> m_tauntGuids;
protected:
uint32 m_attackTimer[MAX_ATTACK];
int32 m_attackTimer[MAX_ATTACK];
AttackerSet m_attackers;
Unit* m_attacking;
uint32 m_reactiveTimer[MAX_REACTIVE];
Expand All @@ -922,19 +922,20 @@ class Unit : public SpellCaster
* @param type The type of weapon that we want to update the time for
* @param time the remaining time until we can attack with the WeaponAttackType again
*/
void SetAttackTimer(WeaponAttackType type, uint32 time) { m_attackTimer[type] = time; }
void SetAttackTimer(WeaponAttackType type, int32 time) { m_attackTimer[type] = time; }
/**
* Resets the attack timer to the base value decided by Unit::m_modAttackSpeedPct and
* Unit::GetAttackTime
* @param type The weapon attack type to reset the attack timer for.
* @param compensateDiff Deduct the diff in update tick from the reseted timer.
*/
void ResetAttackTimer(WeaponAttackType type = BASE_ATTACK);
void ResetAttackTimer(WeaponAttackType type = BASE_ATTACK, bool compensateDiff = false);
/**
* Get's the remaining time until we can do an attack
* @param type The weapon type to check the remaining time for
* @return The remaining time until we can attack with this weapon type.
*/
uint32 GetAttackTimer(WeaponAttackType type) const { return m_attackTimer[type]; }
int32 GetAttackTimer(WeaponAttackType type) const { return m_attackTimer[type]; }
/**
* Checks whether the unit can do an attack. Does this by checking the attacktimer for the
* WeaponAttackType, can probably be thought of as a cooldown for each swing/shot
Expand All @@ -960,6 +961,11 @@ class Unit : public SpellCaster
* Called from UpdateMeleeAttackingState if attack can't happen now.
*/
void DelayAutoAttacks();
/**
* When a starts autoattacking. Erases the saved update diff on its swing timer
* and delays the offhand attack to half its attack speed
*/
void FirstAttackDelay();
/**
* Checks that need to be done before an auto attack swing happens.
* Target's faction is only checked for players since its done elsewhere
Expand Down
Loading