Core/Units: ported base attack time refactors from master branch

This commit is contained in:
Ovahlord committed 2025-06-19 23:18:17 +02:00
1 parent ab866ca985
commit 4539f848ac
14 files changed
+69 -45

No files matched your search

@@ -605,9 +605,9 @@ bool Creature::UpdateEntry(uint32 entry, CreatureData const* data /*= nullptr*/,
SetCanDualWield(cInfo->flags_extra & CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK);
SetAttackTime(BASE_ATTACK, cInfo->BaseAttackTime);
SetAttackTime(OFF_ATTACK, cInfo->BaseAttackTime);
SetAttackTime(RANGED_ATTACK, cInfo->RangeAttackTime);
SetBaseAttackTime(BASE_ATTACK, cInfo->BaseAttackTime);
SetBaseAttackTime(OFF_ATTACK, cInfo->BaseAttackTime);
SetBaseAttackTime(RANGED_ATTACK, cInfo->RangeAttackTime);
if (updateLevel)
SelectLevel();
+5 -5
View File
@@ -743,9 +743,9 @@ bool Guardian::InitStatsForLevel(uint8 petlevel)
SetMeleeDamageSchool(SpellSchools(cinfo->dmgschool));
SetAttackTime(BASE_ATTACK, BASE_ATTACK_TIME);
SetAttackTime(OFF_ATTACK, BASE_ATTACK_TIME);
SetAttackTime(RANGED_ATTACK, BASE_ATTACK_TIME);
SetBaseAttackTime(BASE_ATTACK, BASE_ATTACK_TIME);
SetBaseAttackTime(OFF_ATTACK, BASE_ATTACK_TIME);
SetBaseAttackTime(RANGED_ATTACK, BASE_ATTACK_TIME);
SetFloatValue(UNIT_MOD_CAST_SPEED, 1.0f);
SetFloatValue(UNIT_MOD_CAST_HASTE, 1.0f);
@@ -887,7 +887,7 @@ bool Guardian::InitStatsForLevel(uint8 petlevel)
SetBonusDamage(int32(m_owner->GetTotalAttackPowerValue(BASE_ATTACK) * dmg_multiplier));
// wolf attack speed is 1.5s
SetAttackTime(BASE_ATTACK, cinfo->BaseAttackTime);
SetBaseAttackTime(BASE_ATTACK, cinfo->BaseAttackTime);
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float((petlevel * 4 - petlevel)));
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float((petlevel * 4 + petlevel)));
@@ -923,7 +923,7 @@ bool Guardian::InitStatsForLevel(uint8 petlevel)
case ENTRY_BLOODWORM:
{
SetCreateHealth(m_owner->CountPctFromMaxHealth(18));
SetAttackTime(BASE_ATTACK, 1400);
SetBaseAttackTime(BASE_ATTACK, 1400);
SetBonusDamage(int32(m_owner->GetTotalAttackPowerValue(BASE_ATTACK) * 0.006f));
float minDamage = m_owner->GetTotalAttackPowerValue(BASE_ATTACK) * 0.05f;
float maxDamage = m_owner->GetTotalAttackPowerValue(BASE_ATTACK) * 0.05f;
+8 -8
View File
@@ -5064,10 +5064,10 @@ void Player::SetRegularAttackTime()
{
ItemTemplate const* proto = tmpitem->GetTemplate();
if (proto->GetDelay())
SetAttackTime(WeaponAttackType(i), proto->GetDelay());
SetBaseAttackTime(WeaponAttackType(i), proto->GetDelay());
}
else
SetAttackTime(WeaponAttackType(i), BASE_ATTACK_TIME); // If there is no weapon reset attack time to base (might have been changed from forms)
SetBaseAttackTime(WeaponAttackType(i), BASE_ATTACK_TIME); // If there is no weapon reset attack time to base (might have been changed from forms)
}
}
@@ -7583,7 +7583,7 @@ void Player::_ApplyWeaponDamage(uint8 slot, ItemTemplate const* proto, bool appl
}
if (proto->GetDelay() && !IsInFeralForm())
SetAttackTime(attType, apply ? proto->GetDelay() : BASE_ATTACK_TIME);
SetBaseAttackTime(attType, apply ? proto->GetDelay() : BASE_ATTACK_TIME);
// No need to modify any physical damage for ferals as it is calculated from stats only
if (IsInFeralForm())
@@ -7906,7 +7906,7 @@ void Player::CastItemCombatSpell(DamageInfo const& damageInfo, Item* item, ItemT
if (proto->SpellPPMRate)
{
uint32 WeaponSpeed = GetAttackTime(damageInfo.GetAttackType());
uint32 WeaponSpeed = GetBaseAttackTime(damageInfo.GetAttackType());
chance = GetPPMProcChance(WeaponSpeed, proto->SpellPPMRate, spellInfo);
}
else if (chance > 100.0f)
@@ -19911,7 +19911,7 @@ void Player::outDebugValues() const
TC_LOG_DEBUG("entities.unit", "MIN_DAMAGE is: \t\t%f\tMAX_DAMAGE is: \t\t%f", GetFloatValue(UNIT_FIELD_MINDAMAGE), GetFloatValue(UNIT_FIELD_MAXDAMAGE));
TC_LOG_DEBUG("entities.unit", "MIN_OFFHAND_DAMAGE is: \t%f\tMAX_OFFHAND_DAMAGE is: \t%f", GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE), GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE));
TC_LOG_DEBUG("entities.unit", "MIN_RANGED_DAMAGE is: \t%f\tMAX_RANGED_DAMAGE is: \t%f", GetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE), GetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE));
TC_LOG_DEBUG("entities.unit", "ATTACK_TIME is: \t%u\t\tRANGE_ATTACK_TIME is: \t%u", GetAttackTime(BASE_ATTACK), GetAttackTime(RANGED_ATTACK));
TC_LOG_DEBUG("entities.unit", "ATTACK_TIME is: \t%u\t\tRANGE_ATTACK_TIME is: \t%u", GetBaseAttackTime(BASE_ATTACK), GetBaseAttackTime(RANGED_ATTACK));
}
/*********************************************************/
@@ -21464,9 +21464,9 @@ void Player::InitDataForForm(bool reapplyMods)
SpellShapeshiftFormEntry const* ssEntry = sSpellShapeshiftFormStore.LookupEntry(form);
if (ssEntry && ssEntry->CombatRoundTime)
{
SetAttackTime(BASE_ATTACK, ssEntry->CombatRoundTime);
SetAttackTime(OFF_ATTACK, ssEntry->CombatRoundTime);
SetAttackTime(RANGED_ATTACK, BASE_ATTACK_TIME);
SetBaseAttackTime(BASE_ATTACK, ssEntry->CombatRoundTime);
SetBaseAttackTime(OFF_ATTACK, ssEntry->CombatRoundTime);
SetBaseAttackTime(RANGED_ATTACK, BASE_ATTACK_TIME);
}
else
SetRegularAttackTime();
+1 -1
View File
@@ -1271,7 +1271,7 @@ void Guardian::UpdateDamagePhysical(WeaponAttackType attType)
UnitMods unitMod = UNIT_MOD_DAMAGE_MAINHAND;
float att_speed = float(GetAttackTime(BASE_ATTACK))/1000.0f;
float att_speed = float(GetBaseAttackTime(BASE_ATTACK))/1000.0f;
float base_value = GetFlatModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType) / 14.0f * att_speed + bonusDamage;
float base_pct = GetPctModifierValue(unitMod, BASE_PCT);
+38 -15
View File
@@ -313,6 +313,7 @@ Unit::Unit(bool isWorldObject) :
m_updateFlag.MovementUpdate = true;
m_baseAttackSpeed = { };
m_attackTimer = { };
m_modAttackSpeedPct.fill(1.0f);
@@ -612,7 +613,7 @@ void Unit::DisableSpline()
void Unit::resetAttackTimer(WeaponAttackType type)
{
m_attackTimer[type] = uint32(GetAttackTime(type) * m_modAttackSpeedPct[type]);
m_attackTimer[type] = uint32(GetBaseAttackTime(type) * m_modAttackSpeedPct[type]);
}
bool Unit::IsWithinCombatRange(Unit const* obj, float dist2compare) const
@@ -1362,7 +1363,7 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss)
// Reduce attack time
if (victim->haveOffhandWeapon() && offtime < basetime)
{
float percent20 = victim->GetAttackTime(OFF_ATTACK) * 0.20f;
float percent20 = victim->GetBaseAttackTime(OFF_ATTACK) * 0.20f;
float percent60 = 3.0f * percent20;
if (offtime > percent20 && offtime <= percent60)
victim->setAttackTimer(OFF_ATTACK, uint32(percent20));
@@ -1374,7 +1375,7 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss)
}
else
{
float percent20 = victim->GetAttackTime(BASE_ATTACK) * 0.20f;
float percent20 = victim->GetBaseAttackTime(BASE_ATTACK) * 0.20f;
float percent60 = 3.0f * percent20;
if (basetime > percent20 && basetime <= percent60)
victim->setAttackTimer(BASE_ATTACK, uint32(percent20));
@@ -7829,9 +7830,9 @@ float Unit::GetWeaponProcChance() const
// normalized proc chance for weapon attack speed
// (odd formula...)
if (isAttackReady(BASE_ATTACK))
return (GetAttackTime(BASE_ATTACK) * 1.8f / 1000.0f);
return (GetBaseAttackTime(BASE_ATTACK) * 1.8f / 1000.0f);
else if (haveOffhandWeapon() && isAttackReady(OFF_ATTACK))
return (GetAttackTime(OFF_ATTACK) * 1.6f / 1000.0f);
return (GetBaseAttackTime(OFF_ATTACK) * 1.6f / 1000.0f);
return 0;
}
@@ -8250,12 +8251,6 @@ float Unit::GetPowerRegen(Powers powerType, bool isInCombat) const
return result;
}
uint32 Unit::GetAttackTime(WeaponAttackType att) const
{
float f_BaseAttackTime = GetFloatValue(UNIT_FIELD_BASEATTACKTIME + AsUnderlyingType(att)) / m_modAttackSpeedPct[att];
return (uint32)f_BaseAttackTime;
}
bool Unit::IsAlwaysVisibleFor(WorldObject const* seer) const
{
if (WorldObject::IsAlwaysVisibleFor(seer))
@@ -10340,13 +10335,40 @@ void ApplyPercentModFloatVar(float& var, float val, bool apply)
var *= (apply ? (100.0f + val) / 100.0f : 100.0f / (100.0f + val));
}
uint32 Unit::GetBaseAttackTime(WeaponAttackType att) const
{
return m_baseAttackSpeed[att];
}
void Unit::SetBaseAttackTime(WeaponAttackType att, uint32 val)
{
m_baseAttackSpeed[att] = val;
UpdateAttackTimeField(att);
}
void Unit::UpdateAttackTimeField(WeaponAttackType att)
{
switch (att)
{
case BASE_ATTACK:
case OFF_ATTACK:
SetFloatValue(UNIT_FIELD_BASEATTACKTIME + att, uint32(m_baseAttackSpeed[att] * m_modAttackSpeedPct[att]));
break;
case RANGED_ATTACK:
SetFloatValue(UNIT_FIELD_RANGEDATTACKTIME, uint32(m_baseAttackSpeed[RANGED_ATTACK] * m_modAttackSpeedPct[RANGED_ATTACK]));
break;
default:
break;
}
}
void Unit::ApplyAttackTimePercentMod(WeaponAttackType att, float val, bool apply)
{
float amount = GetFloatValue(UNIT_FIELD_BASEATTACKTIME + AsUnderlyingType(att));
float hasteAmount = GetTypeId() == TYPEID_PLAYER ? GetFloatValue(PLAYER_FIELD_MOD_HASTE) : 0.f;
float rangedHasteAmount = GetTypeId() == TYPEID_PLAYER ? GetFloatValue(PLAYER_FIELD_MOD_RANGED_HASTE) : 0.f;
float remainingTimePct = (float)m_attackTimer[att] / (GetAttackTime(att) * m_modAttackSpeedPct[att]);
float remainingTimePct = float(m_attackTimer[att]) / (m_baseAttackSpeed[att] * m_modAttackSpeedPct[att]);
if (val > 0.f)
{
ApplyPercentModFloatVar(m_modAttackSpeedPct[att], val, !apply);
@@ -10382,7 +10404,8 @@ void Unit::ApplyAttackTimePercentMod(WeaponAttackType att, float val, bool apply
SetFloatValue(PLAYER_FIELD_MOD_RANGED_HASTE, rangedHasteAmount);
}
m_attackTimer[att] = uint32(GetAttackTime(att) * m_modAttackSpeedPct[att] * remainingTimePct);
UpdateAttackTimeField(att);
m_attackTimer[att] = uint32(m_baseAttackSpeed[att] * m_modAttackSpeedPct[att] * remainingTimePct);
}
void Unit::ApplyHasteRegenMod(float val, bool apply)
@@ -10592,11 +10615,11 @@ float Unit::CalculateDefaultCoefficient(SpellInfo const* spellInfo, DamageEffect
float Unit::GetAPMultiplier(WeaponAttackType attType, bool normalized) const
{
if (GetTypeId() != TYPEID_PLAYER || (IsInFeralForm() && !normalized))
return GetAttackTime(attType) / 1000.0f;
return GetBaseAttackTime(attType) / 1000.0f;
Item* weapon = ToPlayer()->GetWeaponForAttack(attType, true);
if (!weapon)
return BASE_ATTACK_TIME / 1000.0f;
return 2.0f;
if (!normalized)
return weapon->GetTemplate()->GetDelay() / 1000.0f;
+5 -4
View File
@@ -821,8 +821,9 @@ class TC_GAME_API Unit : public WorldObject
virtual void RegenerateHealth() { }
uint32 GetAttackTime(WeaponAttackType att) const;
void SetAttackTime(WeaponAttackType att, uint32 val) { SetFloatValue(UNIT_FIELD_BASEATTACKTIME + AsUnderlyingType(att), val * m_modAttackSpeedPct[att]); }
uint32 GetBaseAttackTime(WeaponAttackType att) const;
void SetBaseAttackTime(WeaponAttackType att, uint32 val);
void UpdateAttackTimeField(WeaponAttackType att);
void ApplyAttackTimePercentMod(WeaponAttackType att, float val, bool apply);
void ApplyHasteRegenMod(float val, bool apply);
void ApplyCastTimePercentMod(float val, bool apply, bool withCastHaste = true, bool withCastSpeed = true);
@@ -1328,7 +1329,9 @@ class TC_GAME_API Unit : public WorldObject
float m_modSpellHitChance;
int32 m_baseSpellCritChance;
std::array<uint32, MAX_ATTACK> m_baseAttackSpeed;
std::array<float, MAX_ATTACK> m_modAttackSpeedPct;
std::array<uint32, MAX_ATTACK> m_attackTimer;
// stat system
void HandleStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float amount, bool apply);
@@ -1655,8 +1658,6 @@ class TC_GAME_API Unit : public WorldObject
void _UpdateAutoRepeatSpell();
std::array<uint32, MAX_ATTACK> m_attackTimer;
std::array<float, MAX_STATS> m_createStats;
AttackerSet m_attackers;
+1 -1
View File
@@ -1962,7 +1962,7 @@ float Aura::CalcProcChance(SpellProcEntry const& procEntry, ProcEventInfo& event
// calculate ppm chance if present and we're using weapon
if (eventInfo.GetDamageInfo() && procEntry.ProcsPerMinute != 0)
{
uint32 WeaponSpeed = caster->GetAttackTime(eventInfo.GetDamageInfo()->GetAttackType());
uint32 WeaponSpeed = caster->GetBaseAttackTime(eventInfo.GetDamageInfo()->GetAttackType());
chance = caster->GetPPMProcChance(WeaponSpeed, procEntry.ProcsPerMinute, GetSpellInfo());
}
// apply chance modifer aura, applies also to ppm chance (see improved judgement of light spell)
+1 -1
View File
@@ -3741,7 +3741,7 @@ int32 SpellInfo::CalcPowerCost(WorldObject const* caster, SpellSchoolMask school
if (!HasAttribute(SPELL_ATTR3_REQUIRES_MAIN_HAND_WEAPON) && HasAttribute(SPELL_ATTR3_REQUIRES_OFF_HAND_WEAPON))
slot = OFF_ATTACK;
speed = unitCaster->GetAttackTime(slot);
speed = unitCaster->GetBaseAttackTime(slot);
}
powerCost += speed / 100;
@@ -419,7 +419,7 @@ public:
//models
SetEquipmentSlots(false, EQUIP_ID_AXE, EQUIP_ID_AXE, EQUIP_NO_CHANGE);
me->SetAttackTime(OFF_ATTACK, (me->GetAttackTime(BASE_ATTACK)*150)/100);
me->SetBaseAttackTime(OFF_ATTACK, (me->GetBaseAttackTime(BASE_ATTACK)*150)/100);
me->SetCanDualWield(true);
}
}
+1 -1
View File
@@ -69,7 +69,7 @@ class npc_pet_hunter_snake_trap : public CreatureScript
me->SetMaxHealth(uint32(107 * (me->getLevel() - 40) * 0.025f));
// Add delta to make them not all hit the same time
me->SetAttackTime(BASE_ATTACK, me->GetAttackTime(BASE_ATTACK) + urandms(0,6));
me->SetBaseAttackTime(BASE_ATTACK, me->GetBaseAttackTime(BASE_ATTACK) + urandms(0,6));
if (!_isViper && !me->HasAura(SPELL_HUNTER_DEADLY_POISON_PASSIVE))
DoCast(me, SPELL_HUNTER_DEADLY_POISON_PASSIVE, true);
+1 -1
View File
@@ -888,7 +888,7 @@ class spell_pal_seal_of_righteousness : public AuraScript
float ap = target->GetTotalAttackPowerValue(BASE_ATTACK);
int32 holy = target->SpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_HOLY);
int32 bp = int32((ap * 0.011f + 0.022f * holy) * target->GetAttackTime(BASE_ATTACK) / 1000);
int32 bp = int32((ap * 0.011f + 0.022f * holy) * target->GetBaseAttackTime(BASE_ATTACK) / 1000);
if (target->GetDummyAuraEffect(SPELLFAMILY_PALADIN, PALADIN_ICON_ID_SEALS_OF_COMMAND, EFFECT_1))
target->CastSpell(target, SPELL_PALADIN_SEAL_OF_RIGHTEOUSNESS_DAMAGE_AOE, CastSpellExtraArgs(aurEff).AddSpellBP0(bp));
+2 -2
View File
@@ -1423,7 +1423,7 @@ class spell_sha_flametongue_weapon : public AuraScript
return;
float basePoints = spell->Effects[EFFECT_1].CalcValue(player);
float attackSpeed = player->GetAttackTime(attType) / 1000.f;
float attackSpeed = player->GetBaseAttackTime(attType) / 1000.f;
float fireDamage = basePoints / 100.0f;
fireDamage *= attackSpeed;
@@ -1497,7 +1497,7 @@ class spell_sha_windfury_weapon : public AuraScript
return;
int32 attackPower = spell->Effects[EFFECT_1].CalcValue(player);
int32 amount = static_cast<int32>(attackPower / 14.f * player->GetAttackTime(attType) / 1000.f);
int32 amount = static_cast<int32>(attackPower / 14.f * player->GetBaseAttackTime(attType) / 1000.f);
uint32 spellId = attType == BASE_ATTACK ? SPELL_SHAMAN_WINDFURY_ATTACK_MAINHAND : SPELL_SHAMAN_WINDFURY_ATTACK_OFFHAND;
for (uint8 i = 0; i < 3; i++)
+1 -1
View File
@@ -435,7 +435,7 @@ class spell_warr_rend : public AuraScript
// $0.25 * (($MWB + $mwb) / 2 + $AP / 14 * $MWS) bonus per tick
float ap = caster->GetTotalAttackPowerValue(BASE_ATTACK);
int32 mws = caster->GetAttackTime(BASE_ATTACK);
int32 mws = caster->GetBaseAttackTime(BASE_ATTACK);
float mwbMin = caster->GetWeaponDamageRange(BASE_ATTACK, MINDAMAGE);
float mwbMax = caster->GetWeaponDamageRange(BASE_ATTACK, MAXDAMAGE);
float mwb = ((mwbMin + mwbMax) / 2 + ap * mws / 14000) * 0.25f;
@@ -34,7 +34,7 @@ public:
trigger_periodicAI(Creature* creature) : NullCreatureAI(creature)
{
spell = me->m_spells[0] ? sSpellMgr->GetSpellInfo(me->m_spells[0]) : nullptr;
interval = me->GetAttackTime(BASE_ATTACK);
interval = me->GetBaseAttackTime(BASE_ATTACK);
timer = interval;
}