Core/Entities: correct creature damage, offhand damage should work too

* todo: some creatures need dmg_multiplier update in creature_template
This commit is contained in:
joschiwald
2014-01-04 18:22:06 +01:00
parent ff61e4d79d
commit cd76d32907
22 changed files with 337 additions and 310 deletions
@@ -0,0 +1,10 @@
ALTER TABLE `creature_classlevelstats`
CHANGE `level` `level` TINYINT(3) UNSIGNED NOT NULL,
CHANGE `class` `class` TINYINT(3) UNSIGNED NOT NULL,
CHANGE `basehp0` `basehp0` SMALLINT(5) UNSIGNED DEFAULT 1 NOT NULL,
CHANGE `basehp1` `basehp1` SMALLINT(5) UNSIGNED DEFAULT 1 NOT NULL,
CHANGE `basehp2` `basehp2` SMALLINT(5) UNSIGNED DEFAULT 1 NOT NULL,
CHANGE `basemana` `basemana` SMALLINT(5) UNSIGNED DEFAULT 0 NOT NULL,
CHANGE `basearmor` `basearmor` SMALLINT(5) UNSIGNED DEFAULT 1 NOT NULL,
CHANGE `attackpower` `attackpower` SMALLINT(5) UNSIGNED DEFAULT 0 NOT NULL,
CHANGE `rangedattackpower` `rangedattackpower` SMALLINT(5) UNSIGNED DEFAULT 0 NOT NULL;
+33 -21
View File
@@ -182,8 +182,8 @@ void Creature::AddToWorld()
///- Register the creature for guid lookup
if (!IsInWorld())
{
if (m_zoneScript)
m_zoneScript->OnCreatureCreate(this);
if (GetZoneScript())
GetZoneScript()->OnCreatureCreate(this);
sObjectAccessor->AddObject(this);
Unit::AddToWorld();
SearchFormation();
@@ -197,8 +197,8 @@ void Creature::RemoveFromWorld()
{
if (IsInWorld())
{
if (m_zoneScript)
m_zoneScript->OnCreatureRemove(this);
if (GetZoneScript())
GetZoneScript()->OnCreatureRemove(this);
if (m_formation)
sFormationMgr->RemoveCreatureFromGroup(m_formation, this);
Unit::RemoveFromWorld();
@@ -312,7 +312,7 @@ bool Creature::InitEntry(uint32 entry, uint32 /*team*/, const CreatureData* data
CreatureModelInfo const* minfo = sObjectMgr->GetCreatureModelRandomGender(&displayID);
if (!minfo) // Cancel load if no model defined
{
TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has no model defined in table `creature_template`, can't load. ", entry);
TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has invalid model %u defined in table `creature_template`, can't load.", entry, displayID);
return false;
}
@@ -367,7 +367,6 @@ bool Creature::UpdateEntry(uint32 Entry, uint32 team, const CreatureData* data)
if (!GetCreatureAddon())
SetSheath(SHEATH_STATE_MELEE);
SelectLevel(GetCreatureTemplate());
if (team == HORDE)
setFaction(cInfo->faction_H);
else
@@ -381,10 +380,6 @@ bool Creature::UpdateEntry(uint32 Entry, uint32 team, const CreatureData* data)
else
SetUInt32Value(UNIT_NPC_FLAGS, npcflag);
SetAttackTime(BASE_ATTACK, cInfo->baseattacktime);
SetAttackTime(OFF_ATTACK, cInfo->baseattacktime);
SetAttackTime(RANGED_ATTACK, cInfo->rangeattacktime);
SetUInt32Value(UNIT_FIELD_FLAGS, unit_flags);
SetUInt32Value(UNIT_FIELD_FLAGS_2, cInfo->unit_flags2);
@@ -392,6 +387,12 @@ bool Creature::UpdateEntry(uint32 Entry, uint32 team, const CreatureData* data)
RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT);
SetAttackTime(BASE_ATTACK, cInfo->baseattacktime);
SetAttackTime(OFF_ATTACK, cInfo->baseattacktime);
SetAttackTime(RANGED_ATTACK, cInfo->rangeattacktime);
SelectLevel(GetCreatureTemplate());
SetMeleeDamageSchool(SpellSchools(cInfo->dmgschool));
CreatureBaseStats const* stats = sObjectMgr->GetCreatureBaseStats(getLevel(), cInfo->unit_class);
float armor = (float)stats->GenerateArmor(cInfo); /// @todo Why is this treated as uint32 when it's a float?
@@ -1073,19 +1074,24 @@ void Creature::SelectLevel(const CreatureTemplate* cinfo)
SetModifierValue(UNIT_MOD_HEALTH, BASE_VALUE, (float)health);
SetModifierValue(UNIT_MOD_MANA, BASE_VALUE, (float)mana);
//damage
// damage
float basedamage = stats->GenerateBaseDamage(cinfo);
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, ((basedamage + (stats->AttackPower / 14)) * cinfo->dmg_multiplier) * (cinfo->baseattacktime / 1000));
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, (((basedamage * 1.5) + (stats->AttackPower / 14)) * cinfo->dmg_multiplier) * (cinfo->baseattacktime / 1000));
SetBaseWeaponDamage(RANGED_ATTACK, MINDAMAGE, (basedamage + (stats->RangedAttackPower / 14)) * (cinfo->rangeattacktime / 1000));
SetBaseWeaponDamage(RANGED_ATTACK, MAXDAMAGE, ((basedamage * 1.5) + (stats->RangedAttackPower / 14)) * (cinfo->rangeattacktime / 1000));
float weaponBaseMinDamage = basedamage;
float weaponBaseMaxDamage = basedamage * 1.5;
float damagemod = 1.0f;//_GetDamageMod(rank);
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, weaponBaseMinDamage);
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, weaponBaseMaxDamage);
SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, stats->AttackPower * damagemod);
SetBaseWeaponDamage(OFF_ATTACK, MINDAMAGE, weaponBaseMinDamage);
SetBaseWeaponDamage(OFF_ATTACK, MAXDAMAGE, weaponBaseMaxDamage);
SetBaseWeaponDamage(RANGED_ATTACK, MINDAMAGE, weaponBaseMinDamage);
SetBaseWeaponDamage(RANGED_ATTACK, MAXDAMAGE, weaponBaseMaxDamage);
SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, stats->AttackPower);
SetModifierValue(UNIT_MOD_ATTACK_POWER_RANGED, BASE_VALUE, stats->RangedAttackPower);
}
float Creature::_GetHealthMod(int32 Rank)
@@ -1154,9 +1160,9 @@ float Creature::GetSpellDamageMod(int32 Rank) const
bool Creature::CreateFromProto(uint32 guidlow, uint32 Entry, uint32 vehId, uint32 team, const CreatureData* data)
{
SetZoneScript();
if (m_zoneScript && data)
if (GetZoneScript() && data)
{
Entry = m_zoneScript->GetCreatureEntry(guidlow, data);
Entry = GetZoneScript()->GetCreatureEntry(guidlow, data);
if (!Entry)
return false;
}
@@ -1258,6 +1264,12 @@ bool Creature::LoadCreatureFromDB(uint32 guid, Map* map, bool addToMap)
return true;
}
void Creature::SetCanDualWield(bool value)
{
Unit::SetCanDualWield(value);
UpdateDamagePhysical(OFF_ATTACK);
}
void Creature::LoadEquipment(int8 id, bool force /*= true*/)
{
if (id == 0)
@@ -1965,7 +1977,7 @@ bool Creature::CanCreatureAttack(Unit const* victim, bool /*force*/) const
if (IsAIEnabled && !AI()->CanAIAttack(victim))
return false;
if (sMapStore.LookupEntry(GetMapId())->IsDungeon())
if (GetMap()->IsDungeon())
return true;
//Use AttackDistance in distance check if threat radius is lower. This prevents creature bounce in and out of combat every update tick.
@@ -2427,7 +2439,7 @@ void Creature::SetPosition(float x, float y, float z, float o)
return;
}
GetMap()->CreatureRelocation(ToCreature(), x, y, z, o);
GetMap()->CreatureRelocation(this, x, y, z, o);
if (IsVehicle())
GetVehicleKit()->RelocatePassengers();
}
+4 -8
View File
@@ -173,11 +173,6 @@ struct CreatureTemplate
// Benchmarked: Faster than std::map (insert/find)
typedef UNORDERED_MAP<uint32, CreatureTemplate> CreatureTemplateContainer;
// Represents max amount of expansions.
/// @todo: Add MAX_EXPANSION constant.
#define MAX_CREATURE_BASE_HP 3
#define MAX_CREATURE_BASE_DAMAGE 3
// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push, N), also any gcc version not support it at some platform
#if defined(__GNUC__)
#pragma pack(1)
@@ -188,12 +183,12 @@ typedef UNORDERED_MAP<uint32, CreatureTemplate> CreatureTemplateContainer;
// Defines base stats for creatures (used to calculate HP/mana/armor/attackpower/rangedattackpower/all damage).
struct CreatureBaseStats
{
uint32 BaseHealth[MAX_CREATURE_BASE_HP];
uint32 BaseHealth[MAX_EXPANSIONS];
uint32 BaseMana;
uint32 BaseArmor;
uint32 AttackPower;
uint32 RangedAttackPower;
float BaseDamage[MAX_CREATURE_BASE_DAMAGE];
float BaseDamage[MAX_EXPANSIONS];
// Helpers
@@ -521,8 +516,9 @@ class Creature : public Unit, public GridObject<Creature>, public MapObject
void UpdateMaxHealth();
void UpdateMaxPower(Powers power);
void UpdateAttackPowerAndDamage(bool ranged = false);
void UpdateDamagePhysical(WeaponAttackType attType);
void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage) OVERRIDE;
void SetCanDualWield(bool value) OVERRIDE;
int8 GetOriginalEquipmentId() const { return m_originalEquipmentId; }
uint8 GetCurrentEquipmentId() { return m_equipmentId; }
void SetCurrentEquipmentId(uint8 id) { m_equipmentId = id; }
@@ -95,7 +95,7 @@ class Guardian : public Minion
void UpdateMaxHealth();
void UpdateMaxPower(Powers power);
void UpdateAttackPowerAndDamage(bool ranged = false);
void UpdateDamagePhysical(WeaponAttackType attType);
void UpdateDamagePhysical(WeaponAttackType attType) OVERRIDE;
int32 GetBonusDamage() const { return m_bonusSpellDamage; }
void SetBonusDamage(int32 damage);
+1 -1
View File
@@ -95,7 +95,7 @@ class Pet : public Guardian
void UpdateMaxHealth();
void UpdateMaxPower(Powers power);
void UpdateAttackPowerAndDamage(bool ranged = false);
void UpdateDamagePhysical(WeaponAttackType attType);
void UpdateDamagePhysical(WeaponAttackType attType) OVERRIDE;
*/
void ToggleAutocast(SpellInfo const* spellInfo, bool apply);
+1 -2
View File
@@ -1747,14 +1747,13 @@ class Player : public Unit, public GridObject<Player>
void ApplyFeralAPBonus(int32 amount, bool apply);
void UpdateAttackPowerAndDamage(bool ranged = false);
void UpdateShieldBlockValue();
void UpdateDamagePhysical(WeaponAttackType attType);
void ApplySpellPowerBonus(int32 amount, bool apply);
void UpdateSpellDamageAndHealingBonus();
void ApplyRatingMod(CombatRating cr, int32 value, bool apply);
void UpdateRating(CombatRating cr);
void UpdateAllRatings();
void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& min_damage, float& max_damage);
void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage) OVERRIDE;
void UpdateDefenseBonusesMod();
inline void RecalculateRating(CombatRating cr) { ApplyRatingMod(cr, 0, true);}
+1 -1
View File
@@ -53,7 +53,7 @@ class Totem : public Minion
void UpdateMaxHealth() { }
void UpdateMaxPower(Powers /*power*/) { }
void UpdateAttackPowerAndDamage(bool /*ranged*/) { }
void UpdateDamagePhysical(WeaponAttackType /*attType*/) { }
void UpdateDamagePhysical(WeaponAttackType /*attType*/) OVERRIDE { }
bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) const;
+104 -101
View File
@@ -46,6 +46,43 @@ inline bool _ModifyUInt32(bool apply, uint32& baseValue, int32& amount)
return apply;
}
/*#######################################
######## ########
######## UNIT STAT SYSTEM ########
######## ########
#######################################*/
void Unit::UpdateAllResistances()
{
for (uint8 i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i)
UpdateResistances(i);
}
void Unit::UpdateDamagePhysical(WeaponAttackType attType)
{
float minDamage = 0.0f;
float maxDamage = 0.0f;
CalculateMinMaxDamage(attType, false, true, minDamage, maxDamage);
switch (attType)
{
case BASE_ATTACK:
default:
SetStatFloatValue(UNIT_FIELD_MINDAMAGE, minDamage);
SetStatFloatValue(UNIT_FIELD_MAXDAMAGE, maxDamage);
break;
case OFF_ATTACK:
SetStatFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE, minDamage);
SetStatFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE, maxDamage);
break;
case RANGED_ATTACK:
SetStatFloatValue(UNIT_FIELD_MINRANGEDDAMAGE, minDamage);
SetStatFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE, maxDamage);
break;
}
}
/*#######################################
######## ########
######## PLAYERS STAT SYSTEM ########
@@ -178,8 +215,7 @@ bool Player::UpdateAllStats()
UpdateExpertise(BASE_ATTACK);
UpdateExpertise(OFF_ATTACK);
RecalculateRating(CR_ARMOR_PENETRATION);
for (int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i)
UpdateResistances(i);
UpdateAllResistances();
return true;
}
@@ -477,7 +513,7 @@ void Player::UpdateShieldBlockValue()
SetUInt32Value(PLAYER_SHIELD_BLOCK, GetShieldBlockValue());
}
void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& min_damage, float& max_damage)
void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage)
{
UnitMods unitMod;
@@ -495,70 +531,45 @@ void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bo
break;
}
float att_speed = GetAPMultiplier(attType, normalized);
float attackSpeedMod = GetAPMultiplier(attType, normalized);
float base_value = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType)/ 14.0f * att_speed;
float base_pct = GetModifierValue(unitMod, BASE_PCT);
float total_value = GetModifierValue(unitMod, TOTAL_VALUE);
float total_pct = addTotalPct ? GetModifierValue(unitMod, TOTAL_PCT) : 1.0f;
float baseValue = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType) / 14.0f * attackSpeedMod;
float basePct = GetModifierValue(unitMod, BASE_PCT);
float totalValue = GetModifierValue(unitMod, TOTAL_VALUE);
float totalPct = addTotalPct ? GetModifierValue(unitMod, TOTAL_PCT) : 1.0f;
float weapon_mindamage = GetWeaponDamageRange(attType, MINDAMAGE);
float weapon_maxdamage = GetWeaponDamageRange(attType, MAXDAMAGE);
float weaponMinDamage = GetWeaponDamageRange(attType, MINDAMAGE);
float weaponMaxDamage = GetWeaponDamageRange(attType, MAXDAMAGE);
if (IsInFeralForm()) //check if player is druid and in cat or bear forms
if (IsInFeralForm()) // check if player is druid and in cat or bear forms
{
uint8 lvl = getLevel();
if (lvl > 60)
lvl = 60;
weapon_mindamage = lvl*0.85f*att_speed;
weapon_maxdamage = lvl*1.25f*att_speed;
weaponMinDamage = lvl * 0.85f * attackSpeedMod;
weaponMaxDamage = lvl * 1.25f * attackSpeedMod;
}
else if (!CanUseAttackType(attType)) //check if player not in form but still can't use (disarm case)
else if (!CanUseAttackType(attType)) // check if player not in form but still can't use (disarm case)
{
//cannot use ranged/off attack, set values to 0
// cannot use ranged/off attack, set values to 0
if (attType != BASE_ATTACK)
{
min_damage = 0;
max_damage = 0;
minDamage = 0;
maxDamage = 0;
return;
}
weapon_mindamage = BASE_MINDAMAGE;
weapon_maxdamage = BASE_MAXDAMAGE;
weaponMinDamage = BASE_MINDAMAGE;
weaponMaxDamage = BASE_MAXDAMAGE;
}
else if (attType == RANGED_ATTACK) //add ammo DPS to ranged damage
else if (attType == RANGED_ATTACK) // add ammo DPS to ranged damage
{
weapon_mindamage += GetAmmoDPS() * att_speed;
weapon_maxdamage += GetAmmoDPS() * att_speed;
weaponMinDamage += GetAmmoDPS() * attackSpeedMod;
weaponMaxDamage += GetAmmoDPS() * attackSpeedMod;
}
min_damage = ((base_value + weapon_mindamage) * base_pct + total_value) * total_pct;
max_damage = ((base_value + weapon_maxdamage) * base_pct + total_value) * total_pct;
}
void Player::UpdateDamagePhysical(WeaponAttackType attType)
{
float mindamage;
float maxdamage;
CalculateMinMaxDamage(attType, false, true, mindamage, maxdamage);
switch (attType)
{
case BASE_ATTACK:
default:
SetStatFloatValue(UNIT_FIELD_MINDAMAGE, mindamage);
SetStatFloatValue(UNIT_FIELD_MAXDAMAGE, maxdamage);
break;
case OFF_ATTACK:
SetStatFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE, mindamage);
SetStatFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE, maxdamage);
break;
case RANGED_ATTACK:
SetStatFloatValue(UNIT_FIELD_MINRANGEDDAMAGE, mindamage);
SetStatFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE, maxdamage);
break;
}
minDamage = ((weaponMinDamage + baseValue) * basePct + totalValue) * totalPct;
maxDamage = ((weaponMaxDamage + baseValue) * basePct + totalValue) * totalPct;
}
void Player::UpdateDefenseBonusesMod()
@@ -841,9 +852,14 @@ void Player::UpdateExpertise(WeaponAttackType attack)
switch (attack)
{
case BASE_ATTACK: SetUInt32Value(PLAYER_EXPERTISE, expertise); break;
case OFF_ATTACK: SetUInt32Value(PLAYER_OFFHAND_EXPERTISE, expertise); break;
default: break;
case BASE_ATTACK:
SetUInt32Value(PLAYER_EXPERTISE, expertise);
break;
case OFF_ATTACK:
SetUInt32Value(PLAYER_OFFHAND_EXPERTISE, expertise);
break;
default:
break;
}
}
@@ -950,8 +966,7 @@ bool Creature::UpdateAllStats()
for (uint8 i = POWER_MANA; i < MAX_POWERS; ++i)
UpdateMaxPower(Powers(i));
for (int8 i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i)
UpdateResistances(i);
UpdateAllResistances();
return true;
}
@@ -976,7 +991,7 @@ void Creature::UpdateArmor()
void Creature::UpdateMaxHealth()
{
float value = GetTotalAuraModValue(UNIT_MOD_HEALTH);
SetMaxHealth((uint32)value);
SetMaxHealth(uint32(value));
}
void Creature::UpdateMaxPower(Powers power)
@@ -992,25 +1007,25 @@ void Creature::UpdateAttackPowerAndDamage(bool ranged)
UnitMods unitMod = ranged ? UNIT_MOD_ATTACK_POWER_RANGED : UNIT_MOD_ATTACK_POWER;
uint16 index = UNIT_FIELD_ATTACK_POWER;
uint16 index_mod = UNIT_FIELD_ATTACK_POWER_MODS;
uint16 index_mult = UNIT_FIELD_ATTACK_POWER_MULTIPLIER;
uint16 indexMod = UNIT_FIELD_ATTACK_POWER_MODS;
uint16 indexMulti = UNIT_FIELD_ATTACK_POWER_MULTIPLIER;
if (ranged)
{
index = UNIT_FIELD_RANGED_ATTACK_POWER;
index_mod = UNIT_FIELD_RANGED_ATTACK_POWER_MODS;
index_mult = UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER;
indexMod = UNIT_FIELD_RANGED_ATTACK_POWER_MODS;
indexMulti = UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER;
}
float base_attPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT);
float attPowerMod = GetModifierValue(unitMod, TOTAL_VALUE);
float attPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f;
float baseAttackPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT);
float attackPowerMod = GetModifierValue(unitMod, TOTAL_VALUE);
float attackPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f;
SetInt32Value(index, (uint32)base_attPower); //UNIT_FIELD_(RANGED)_ATTACK_POWER field
SetInt32Value(index_mod, (uint32)attPowerMod); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field
SetFloatValue(index_mult, attPowerMultiplier); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field
SetInt32Value(index, uint32(baseAttackPower)); // UNIT_FIELD_(RANGED)_ATTACK_POWER
SetInt32Value(indexMod, uint32(attackPowerMod)); // UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS
SetFloatValue(indexMulti, attackPowerMultiplier); // UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER
//automatically update weapon damage after attack power modification
// automatically update weapon damage after attack power modification
if (ranged)
UpdateDamagePhysical(RANGED_ATTACK);
else
@@ -1020,7 +1035,7 @@ void Creature::UpdateAttackPowerAndDamage(bool ranged)
}
}
void Creature::UpdateDamagePhysical(WeaponAttackType attType)
void Creature::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage)
{
UnitMods unitMod;
switch (attType)
@@ -1037,44 +1052,32 @@ void Creature::UpdateDamagePhysical(WeaponAttackType attType)
break;
}
//float att_speed = float(GetAttackTime(attType))/1000.0f;
float weapon_mindamage = GetWeaponDamageRange(attType, MINDAMAGE);
float weapon_maxdamage = GetWeaponDamageRange(attType, MAXDAMAGE);
/* difference in AP between current attack power and base value from DB */
float att_pwr_change = GetTotalAttackPowerValue(attType) - GetCreatureTemplate()->attackpower;
float base_value = GetModifierValue(unitMod, BASE_VALUE) + (att_pwr_change * GetAPMultiplier(attType, false) / 14.0f);
float base_pct = GetModifierValue(unitMod, BASE_PCT);
float total_value = GetModifierValue(unitMod, TOTAL_VALUE);
float total_pct = GetModifierValue(unitMod, TOTAL_PCT);
float dmg_multiplier = GetCreatureTemplate()->dmg_multiplier;
if (!CanUseAttackType(attType))
if (attType == OFF_ATTACK && !haveOffhandWeapon())
{
weapon_mindamage = 0;
weapon_maxdamage = 0;
minDamage = 0.0f;
maxDamage = 0.0f;
return;
}
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 weaponMinDamage = GetWeaponDamageRange(attType, MINDAMAGE);
float weaponMaxDamage = GetWeaponDamageRange(attType, MAXDAMAGE);
switch (attType)
if (!CanUseAttackType(attType)) // disarm case
{
case BASE_ATTACK:
default:
SetStatFloatValue(UNIT_FIELD_MINDAMAGE, mindamage);
SetStatFloatValue(UNIT_FIELD_MAXDAMAGE, maxdamage);
break;
case OFF_ATTACK:
SetStatFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE, mindamage);
SetStatFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE, maxdamage);
break;
case RANGED_ATTACK:
SetStatFloatValue(UNIT_FIELD_MINRANGEDDAMAGE, mindamage);
SetStatFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE, maxdamage);
break;
weaponMinDamage = 0.0f;
weaponMaxDamage = 0.0f;
}
float attackPower = GetTotalAttackPowerValue(attType);
float attackSpeedMulti = GetAPMultiplier(attType, normalized);
float baseValue = GetModifierValue(unitMod, BASE_VALUE) + (attackPower / 14.0f);
float basePct = GetModifierValue(unitMod, BASE_PCT) * attackSpeedMulti;
float totalValue = GetModifierValue(unitMod, TOTAL_VALUE);
float totalPct = addTotalPct ? GetModifierValue(unitMod, TOTAL_PCT) : 1.0f;
float dmgMultiplier = GetCreatureTemplate()->dmg_multiplier; // = dmg_multiplier * _GetDamageMod(rank);
minDamage = ((weaponMinDamage + baseValue) * dmgMultiplier * basePct + totalValue) * totalPct;
maxDamage = ((weaponMaxDamage + baseValue) * dmgMultiplier * basePct + totalValue) * totalPct;
}
/*#######################################
@@ -1197,8 +1200,7 @@ bool Guardian::UpdateAllStats()
for (uint8 i = POWER_MANA; i < MAX_POWERS; ++i)
UpdateMaxPower(Powers(i));
for (uint8 i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i)
UpdateResistances(i);
UpdateAllResistances();
return true;
}
@@ -1436,6 +1438,7 @@ void Guardian::UpdateDamagePhysical(WeaponAttackType attType)
}
}
/// @todo: remove this
Unit::AuraEffectList const& mDummy = GetAuraEffectsByType(SPELL_AURA_MOD_ATTACKSPEED);
for (Unit::AuraEffectList::const_iterator itr = mDummy.begin(); itr != mDummy.end(); ++itr)
{
+19 -21
View File
@@ -368,10 +368,10 @@ void Unit::Update(uint32 p_time)
bool Unit::haveOffhandWeapon() const
{
if (GetTypeId() == TYPEID_PLAYER)
return ToPlayer()->GetWeaponForAttack(OFF_ATTACK, true);
else
return m_canDualWield;
if (Player const* player = ToPlayer())
return player->GetWeaponForAttack(OFF_ATTACK, true);
return CanDualWield();
}
void Unit::MonsterMoveWithSpeed(float x, float y, float z, float speed, bool generatePath, bool forceDestination)
@@ -2160,41 +2160,39 @@ MeleeHitOutcome Unit::RollMeleeOutcomeAgainst (const Unit* victim, WeaponAttackT
uint32 Unit::CalculateDamage(WeaponAttackType attType, bool normalized, bool addTotalPct)
{
float min_damage, max_damage;
float minDamage = 0.0f;
float maxDamage = 0.0f;
if (GetTypeId() == TYPEID_PLAYER && (normalized || !addTotalPct))
ToPlayer()->CalculateMinMaxDamage(attType, normalized, addTotalPct, min_damage, max_damage);
if (normalized || !addTotalPct)
CalculateMinMaxDamage(attType, normalized, addTotalPct, minDamage, maxDamage);
else
{
switch (attType)
{
case RANGED_ATTACK:
min_damage = GetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE);
max_damage = GetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE);
minDamage = GetFloatValue(UNIT_FIELD_MINRANGEDDAMAGE);
maxDamage = GetFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE);
break;
case BASE_ATTACK:
min_damage = GetFloatValue(UNIT_FIELD_MINDAMAGE);
max_damage = GetFloatValue(UNIT_FIELD_MAXDAMAGE);
minDamage = GetFloatValue(UNIT_FIELD_MINDAMAGE);
maxDamage = GetFloatValue(UNIT_FIELD_MAXDAMAGE);
break;
case OFF_ATTACK:
min_damage = GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE);
max_damage = GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE);
minDamage = GetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE);
maxDamage = GetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE);
break;
// Just for good manner
default:
min_damage = 0.0f;
max_damage = 0.0f;
break;
}
}
if (min_damage > max_damage)
std::swap(min_damage, max_damage);
if (minDamage > maxDamage)
std::swap(minDamage, maxDamage);
if (max_damage == 0.0f)
max_damage = 5.0f;
if (maxDamage == 0.0f)
maxDamage = 5.0f;
return urand((uint32)min_damage, (uint32)max_damage);
return urand(uint32(minDamage), uint32(maxDamage));
}
float Unit::CalculateLevelPenalty(SpellInfo const* spellProto) const
+6 -5
View File
@@ -1292,7 +1292,7 @@ class Unit : public WorldObject
bool isAttackReady(WeaponAttackType type = BASE_ATTACK) const { return m_attackTimer[type] == 0; }
bool haveOffhandWeapon() const;
bool CanDualWield() const { return m_canDualWield; }
void SetCanDualWield(bool value) { m_canDualWield = value; }
virtual void SetCanDualWield(bool value) { m_canDualWield = value; }
float GetCombatReach() const { return m_floatValues[UNIT_FIELD_COMBATREACH]; }
float GetMeleeReach() const;
bool IsWithinCombatRange(const Unit* obj, float dist2compare) const;
@@ -1870,14 +1870,18 @@ class Unit : public WorldObject
virtual bool UpdateStats(Stats stat) = 0;
virtual bool UpdateAllStats() = 0;
virtual void UpdateResistances(uint32 school) = 0;
virtual void UpdateAllResistances();
virtual void UpdateArmor() = 0;
virtual void UpdateMaxHealth() = 0;
virtual void UpdateMaxPower(Powers power) = 0;
virtual void UpdateAttackPowerAndDamage(bool ranged = false) = 0;
virtual void UpdateDamagePhysical(WeaponAttackType attType) = 0;
virtual void UpdateDamagePhysical(WeaponAttackType attType);
float GetTotalAttackPowerValue(WeaponAttackType attType) const;
float GetWeaponDamageRange(WeaponAttackType attType, WeaponDamageRange type) const;
void SetBaseWeaponDamage(WeaponAttackType attType, WeaponDamageRange damageRange, float value) { m_weaponDamage[attType][damageRange] = value; }
virtual void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage) = 0;
uint32 CalculateDamage(WeaponAttackType attType, bool normalized, bool addTotalPct);
float GetAPMultiplier(WeaponAttackType attType, bool normalized);
bool isInFrontInMap(Unit const* target, float distance, float arc = M_PI) const;
bool isInBackInMap(Unit const* target, float distance, float arc = M_PI) const;
@@ -1935,8 +1939,6 @@ class Unit : public WorldObject
void RemoveGameObject(uint32 spellid, bool del);
void RemoveAllGameObjects();
uint32 CalculateDamage(WeaponAttackType attType, bool normalized, bool addTotalPct);
float GetAPMultiplier(WeaponAttackType attType, bool normalized);
void ModifyAuraState(AuraStateType flag, bool apply);
uint32 BuildAuraStateUpdateForTarget(Unit* target) const;
bool HasAuraState(AuraStateType flag, SpellInfo const* spellProto = NULL, Unit const* Caster = NULL) const;
@@ -1956,7 +1958,6 @@ class Unit : public WorldObject
uint32 MeleeDamageBonusDone(Unit* pVictim, uint32 damage, WeaponAttackType attType, SpellInfo const* spellProto = NULL);
uint32 MeleeDamageBonusTaken(Unit* attacker, uint32 pdamage, WeaponAttackType attType, SpellInfo const* spellProto = NULL);
bool isSpellBlocked(Unit* victim, SpellInfo const* spellProto, WeaponAttackType attackType = BASE_ATTACK);
bool isBlockCritical();
bool isSpellCrit(Unit* victim, SpellInfo const* spellProto, SpellSchoolMask schoolMask, WeaponAttackType attackType = BASE_ATTACK) const;
+52 -44
View File
@@ -883,7 +883,7 @@ void ObjectMgr::CheckCreatureTemplate(CreatureTemplate const* cInfo)
const_cast<CreatureTemplate*>(cInfo)->scale = 1.0f;
}
if (cInfo->expansion > (MAX_CREATURE_BASE_HP - 1))
if (cInfo->expansion > (MAX_EXPANSIONS - 1))
{
TC_LOG_ERROR("sql.sql", "Table `creature_template` lists creature (Entry: %u) with expansion %u. Ignored and set to 0.", cInfo->Entry, cInfo->expansion);
const_cast<CreatureTemplate*>(cInfo)->expansion = 0;
@@ -1772,7 +1772,7 @@ bool ObjectMgr::MoveCreData(uint32 guid, uint32 mapId, const Position& pos)
// We use spawn coords to spawn
if (!map->Instanceable() && map->IsGridLoaded(data.posX, data.posY))
{
Creature* creature = new Creature;
Creature* creature = new Creature();
if (!creature->LoadCreatureFromDB(guid, map))
{
TC_LOG_ERROR("misc", "MoveCreData: Cannot add creature guid %u to map", guid);
@@ -1824,7 +1824,7 @@ uint32 ObjectMgr::AddCreData(uint32 entry, uint32 /*team*/, uint32 mapId, float
// We use spawn coords to spawn
if (!map->Instanceable() && !map->IsRemovalGrid(x, y))
{
Creature* creature = new Creature;
Creature* creature = new Creature();
if (!creature->LoadCreatureFromDB(guid, map))
{
TC_LOG_ERROR("misc", "AddCreature: Cannot add creature entry %u to map", entry);
@@ -3044,8 +3044,8 @@ void ObjectMgr::LoadPetLevelInfo()
{
if (pInfo[level].health == 0)
{
TC_LOG_ERROR("sql.sql", "Creature %u has no data for Level %i pet stats data, using data of Level %i.", itr->first, level+1, level);
pInfo[level] = pInfo[level-1];
TC_LOG_ERROR("sql.sql", "Creature %u has no data for Level %i pet stats data, using data of Level %i.", itr->first, level + 1, level);
pInfo[level] = pInfo[level - 1];
}
}
}
@@ -3266,7 +3266,7 @@ void ObjectMgr::LoadPlayerInfo()
if (!result)
{
TC_LOG_ERROR("server.loading", ">> Loaded 0 player create spells. DB table `%s` is empty.", sWorld->getBoolConfig(CONFIG_START_ALL_SPELLS) ? "playercreateinfo_spell_custom" : "playercreateinfo_spell");
TC_LOG_ERROR("server.loading", ">> Loaded 0 player create spells. DB table `%s` is empty.", tableName.c_str());
}
else
{
@@ -3281,13 +3281,13 @@ void ObjectMgr::LoadPlayerInfo()
if (raceMask != 0 && !(raceMask & RACEMASK_ALL_PLAYABLE))
{
TC_LOG_ERROR("sql.sql", "Wrong race mask %u in `playercreateinfo_spell` table, ignoring.", raceMask);
TC_LOG_ERROR("sql.sql", "Wrong race mask %u in `%s` table, ignoring.", raceMask, tableName.c_str());
continue;
}
if (classMask != 0 && !(classMask & CLASSMASK_ALL_PLAYABLE))
{
TC_LOG_ERROR("sql.sql", "Wrong class mask %u in `playercreateinfo_spell` table, ignoring.", classMask);
TC_LOG_ERROR("sql.sql", "Wrong class mask %u in `%s` table, ignoring.", classMask, tableName.c_str());
continue;
}
@@ -3307,7 +3307,7 @@ void ObjectMgr::LoadPlayerInfo()
// We need something better here, the check is not accounting for spells used by multiple races/classes but not all of them.
// Either split the masks per class, or per race, which kind of kills the point yet.
// else if (raceMask != 0 && classMask != 0)
// TC_LOG_ERROR("sql.sql", "Racemask/classmask (%u/%u) combination was found containing an invalid race/class combination (%u/%u) in `playercreateinfo_spell` (Spell %u), ignoring.", raceMask, classMask, raceIndex, classIndex, spellId);
// TC_LOG_ERROR("sql.sql", "Racemask/classmask (%u/%u) combination was found containing an invalid race/class combination (%u/%u) in `%s` (Spell %u), ignoring.", raceMask, classMask, raceIndex, classIndex, tableName.c_str(), spellId);
}
}
}
@@ -3374,7 +3374,7 @@ void ObjectMgr::LoadPlayerInfo()
if (!result)
{
TC_LOG_ERROR("server.loading", ">> Loaded 0 level health/mana definitions. DB table `game_event_condition` is empty.");
TC_LOG_ERROR("server.loading", ">> Loaded 0 level health/mana definitions. DB table `player_classlevelstats` is empty.");
exit(1);
}
@@ -3437,8 +3437,8 @@ void ObjectMgr::LoadPlayerInfo()
{
if (pClassInfo->levelInfo[level].basehealth == 0)
{
TC_LOG_ERROR("sql.sql", "Class %i Level %i does not have health/mana data. Using stats data of level %i.", class_, level+1, level);
pClassInfo->levelInfo[level] = pClassInfo->levelInfo[level-1];
TC_LOG_ERROR("sql.sql", "Class %i Level %i does not have health/mana data. Using stats data of level %i.", class_, level + 1, level);
pClassInfo->levelInfo[level] = pClassInfo->levelInfo[level - 1];
}
}
}
@@ -3498,9 +3498,9 @@ void ObjectMgr::LoadPlayerInfo()
if (!info->levelInfo)
info->levelInfo = new PlayerLevelInfo[sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)];
PlayerLevelInfo& levelInfo = info->levelInfo[current_level-1];
PlayerLevelInfo& levelInfo = info->levelInfo[current_level - 1];
for (int i = 0; i < MAX_STATS; i++)
levelInfo.stats[i] = fields[i+3].GetUInt8();
levelInfo.stats[i] = fields[i + 3].GetUInt8();
}
++count;
@@ -3525,11 +3525,11 @@ void ObjectMgr::LoadPlayerInfo()
continue;
// skip expansion races if not playing with expansion
if (sWorld->getIntConfig(CONFIG_EXPANSION) < 1 && (race == RACE_BLOODELF || race == RACE_DRAENEI))
if (sWorld->getIntConfig(CONFIG_EXPANSION) < EXPANSION_THE_BURNING_CRUSADE && (race == RACE_BLOODELF || race == RACE_DRAENEI))
continue;
// skip expansion classes if not playing with expansion
if (sWorld->getIntConfig(CONFIG_EXPANSION) < 2 && class_ == CLASS_DEATH_KNIGHT)
if (sWorld->getIntConfig(CONFIG_EXPANSION) < EXPANSION_WRATH_OF_THE_LICH_KING && class_ == CLASS_DEATH_KNIGHT)
continue;
// fatal error if no level 1 data
@@ -3544,8 +3544,8 @@ void ObjectMgr::LoadPlayerInfo()
{
if (info->levelInfo[level].stats[0] == 0)
{
TC_LOG_ERROR("sql.sql", "Race %i Class %i Level %i does not have stats data. Using stats data of level %i.", race, class_, level+1, level);
info->levelInfo[level] = info->levelInfo[level-1];
TC_LOG_ERROR("sql.sql", "Race %i Class %i Level %i does not have stats data. Using stats data of level %i.", race, class_, level + 1, level);
info->levelInfo[level] = info->levelInfo[level - 1];
}
}
}
@@ -3603,8 +3603,8 @@ void ObjectMgr::LoadPlayerInfo()
{
if (_playerXPperLevel[level] == 0)
{
TC_LOG_ERROR("sql.sql", "Level %i does not have XP for level data. Using data of level [%i] + 100.", level+1, level);
_playerXPperLevel[level] = _playerXPperLevel[level-1]+100;
TC_LOG_ERROR("sql.sql", "Level %i does not have XP for level data. Using data of level [%i] + 100.", level + 1, level);
_playerXPperLevel[level] = _playerXPperLevel[level - 1] + 100;
}
}
@@ -7468,9 +7468,9 @@ void ObjectMgr::LoadGameObjectForQuests()
{
switch (itr->second.type)
{
// scan GO chest with loot including quest items
case GAMEOBJECT_TYPE_CHEST:
{
// scan GO chest with loot including quest items
uint32 loot_id = (itr->second.GetLootId());
// find quest loot for GO
@@ -7486,7 +7486,7 @@ void ObjectMgr::LoadGameObjectForQuests()
if (itr->second._generic.questID > 0) //quests objects
{
_gameObjectForQuestStore.insert(itr->second.entry);
count++;
++count;
}
break;
}
@@ -7495,7 +7495,7 @@ void ObjectMgr::LoadGameObjectForQuests()
if (itr->second.goober.questId > 0) //quests objects
{
_gameObjectForQuestStore.insert(itr->second.entry);
count++;
++count;
}
break;
}
@@ -8519,13 +8519,18 @@ CreatureBaseStats const* ObjectMgr::GetCreatureBaseStats(uint8 level, uint8 unit
DefaultCreatureBaseStats()
{
BaseArmor = 1;
for (uint8 j = 0; j < MAX_CREATURE_BASE_HP; ++j)
for (uint8 j = 0; j < MAX_EXPANSIONS; ++j)
{
BaseHealth[j] = 1;
BaseDamage[j] = 0.0f;
}
BaseMana = 0;
AttackPower = 0;
RangedAttackPower = 0;
}
};
static const DefaultCreatureBaseStats def_stats;
return &def_stats;
static const DefaultCreatureBaseStats defStats;
return &defStats;
}
void ObjectMgr::LoadCreatureClassLevelStats()
@@ -8545,35 +8550,38 @@ void ObjectMgr::LoadCreatureClassLevelStats()
{
Field* fields = result->Fetch();
uint8 Level = fields[0].GetInt8();
uint8 Class = fields[1].GetInt8();
CreatureBaseStats stats;
for (uint8 i = 0; i < MAX_CREATURE_BASE_HP; ++i)
stats.BaseHealth[i] = fields[i + 2].GetInt16();
stats.BaseMana = fields[5].GetInt16();
stats.BaseArmor = fields[6].GetInt16();
stats.AttackPower = fields[7].GetInt16();
stats.RangedAttackPower = fields[8].GetInt16();
for (uint8 i = 0; i < MAX_CREATURE_BASE_DAMAGE; ++i)
stats.BaseDamage[i] = fields[i + 9].GetFloat();
uint8 Level = fields[0].GetUInt8();
uint8 Class = fields[1].GetUInt8();
if (!Class || ((1 << (Class - 1)) & CLASSMASK_ALL_CREATURES) == 0)
TC_LOG_ERROR("sql.sql", "Creature base stats for level %u has invalid class %u", Level, Class);
for (uint8 i = 0; i < MAX_CREATURE_BASE_HP; ++i)
CreatureBaseStats stats;
for (uint8 i = 0; i < MAX_EXPANSIONS; ++i)
{
if (stats.BaseHealth[i] < 1)
stats.BaseHealth[i] = fields[2 + i].GetUInt16();
if (stats.BaseHealth[i] == 0)
{
TC_LOG_ERROR("sql.sql", "Creature base stats for class %u, level %u has invalid zero base HP[%u] - set to 1", Class, Level, i);
stats.BaseHealth[i] = 1;
}
stats.BaseDamage[i] = fields[9 + i].GetFloat();
if (stats.BaseDamage[i] < 0.0f)
{
TC_LOG_ERROR("sql.sql", "Creature base stats for class %u, level %u has invalid negative base damage[%u] - set to 0.0", Class, Level, i);
stats.BaseDamage[i] = 0.0f;
}
}
stats.BaseMana = fields[5].GetUInt16();
stats.BaseArmor = fields[6].GetUInt16();
stats.AttackPower = fields[7].GetUInt16();
stats.RangedAttackPower = fields[8].GetUInt16();
_creatureBaseStatsStore[MAKE_PAIR16(Level, Class)] = stats;
++count;
@@ -44,6 +44,14 @@ enum LootModes
LOOT_MODE_HARD_MODE_4 = 0x10
};
enum Expansions
{
EXPANSION_CLASSIC = 0,
EXPANSION_THE_BURNING_CRUSADE = 1,
EXPANSION_WRATH_OF_THE_LICH_KING = 2,
MAX_EXPANSIONS = 3
};
enum Gender
{
GENDER_MALE = 0,
@@ -2214,26 +2214,26 @@ void AuraEffect::HandleAuraModDisarm(AuraApplication const* aurApp, uint8 mode,
WeaponAttackType attType;
switch (type)
{
case SPELL_AURA_MOD_DISARM:
field=UNIT_FIELD_FLAGS;
flag=UNIT_FLAG_DISARMED;
slot=EQUIPMENT_SLOT_MAINHAND;
attType=BASE_ATTACK;
break;
case SPELL_AURA_MOD_DISARM_OFFHAND:
field=UNIT_FIELD_FLAGS_2;
flag=UNIT_FLAG2_DISARM_OFFHAND;
slot=EQUIPMENT_SLOT_OFFHAND;
attType=OFF_ATTACK;
break;
case SPELL_AURA_MOD_DISARM_RANGED:
field=UNIT_FIELD_FLAGS_2;
flag=UNIT_FLAG2_DISARM_RANGED;
slot=EQUIPMENT_SLOT_RANGED;
attType=RANGED_ATTACK;
break;
default:
return;
case SPELL_AURA_MOD_DISARM:
field = UNIT_FIELD_FLAGS;
flag = UNIT_FLAG_DISARMED;
slot = EQUIPMENT_SLOT_MAINHAND;
attType = BASE_ATTACK;
break;
case SPELL_AURA_MOD_DISARM_OFFHAND:
field = UNIT_FIELD_FLAGS_2;
flag = UNIT_FLAG2_DISARM_OFFHAND;
slot = EQUIPMENT_SLOT_OFFHAND;
attType = OFF_ATTACK;
break;
case SPELL_AURA_MOD_DISARM_RANGED:
field = UNIT_FIELD_FLAGS_2;
flag = UNIT_FLAG2_DISARM_RANGED;
slot = EQUIPMENT_SLOT_RANGED;
attType = RANGED_ATTACK;
break;
default:
return;
}
// if disarm aura is to be removed, remove the flag first to reapply damage/aura mods
@@ -4112,7 +4112,7 @@ void AuraEffect::HandleModAttackSpeed(AuraApplication const* aurApp, uint8 mode,
Unit* target = aurApp->GetTarget();
target->ApplyAttackTimePercentMod(BASE_ATTACK, (float)GetAmount(), apply);
target->ApplyAttackTimePercentMod(BASE_ATTACK, float(GetAmount()), apply);
target->UpdateDamagePhysical(BASE_ATTACK);
}
@@ -4123,8 +4123,8 @@ void AuraEffect::HandleModMeleeSpeedPct(AuraApplication const* aurApp, uint8 mod
Unit* target = aurApp->GetTarget();
target->ApplyAttackTimePercentMod(BASE_ATTACK, (float)GetAmount(), apply);
target->ApplyAttackTimePercentMod(OFF_ATTACK, (float)GetAmount(), apply);
target->ApplyAttackTimePercentMod(BASE_ATTACK, float(GetAmount()), apply);
target->ApplyAttackTimePercentMod(OFF_ATTACK, float(GetAmount()), apply);
}
void AuraEffect::HandleAuraModRangedHaste(AuraApplication const* aurApp, uint8 mode, bool apply) const
@@ -4371,9 +4371,9 @@ void AuraEffect::HandleModDamagePercentDone(AuraApplication const* aurApp, uint8
if ((GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) && (GetSpellInfo()->EquippedItemClass == -1 || target->GetTypeId() != TYPEID_PLAYER))
{
target->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, float (GetAmount()), apply);
target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, float (GetAmount()), apply);
target->HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_PCT, float (GetAmount()), apply);
target->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, float(GetAmount()), apply);
target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, float(GetAmount()), apply);
target->HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_PCT, float(GetAmount()), apply);
if (target->GetTypeId() == TYPEID_PLAYER)
target->ToPlayer()->ApplyPercentModFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT, float (GetAmount()), apply);
+2 -4
View File
@@ -2538,8 +2538,6 @@ void Spell::EffectDualWield(SpellEffIndex /*effIndex*/)
return;
unitTarget->SetCanDualWield(true);
if (unitTarget->GetTypeId() == TYPEID_UNIT)
unitTarget->ToCreature()->UpdateDamagePhysical(OFF_ATTACK);
}
void Spell::EffectPull(SpellEffIndex effIndex)
@@ -5819,11 +5817,11 @@ void Spell::SummonGuardian(uint32 i, uint32 entry, SummonPropertiesEntry const*
{
if (uint32 weapon = m_caster->GetUInt32Value(PLAYER_VISIBLE_ITEM_16_ENTRYID))
{
summon->SetDisplayId(11686);
summon->SetDisplayId(11686); // modelid2
summon->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID, weapon);
}
else
summon->SetDisplayId(1126);
summon->SetDisplayId(1126); // modelid1
}
summon->AI()->EnterEvadeMode();
@@ -297,12 +297,7 @@ public:
void ClearWeapons()
{
SetEquipmentSlots(false, EQUIP_UNEQUIP, EQUIP_UNEQUIP, EQUIP_NO_CHANGE);
//damage
const CreatureTemplate* cinfo = me->GetCreatureTemplate();
me->SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, cinfo->mindmg);
me->SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, cinfo->maxdmg);
me->UpdateDamagePhysical(BASE_ATTACK);
me->SetCanDualWield(false);
}
void EnfeebleHealthEffect()
@@ -419,19 +414,8 @@ public:
//models
SetEquipmentSlots(false, EQUIP_ID_AXE, EQUIP_ID_AXE, EQUIP_NO_CHANGE);
//damage
const CreatureTemplate* cinfo = me->GetCreatureTemplate();
me->SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, 2*cinfo->mindmg);
me->SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, 2*cinfo->maxdmg);
me->UpdateDamagePhysical(BASE_ATTACK);
me->SetBaseWeaponDamage(OFF_ATTACK, MINDAMAGE, cinfo->mindmg);
me->SetBaseWeaponDamage(OFF_ATTACK, MAXDAMAGE, cinfo->maxdmg);
//Sigh, updating only works on main attack, do it manually ....
me->SetFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE, cinfo->mindmg);
me->SetFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE, cinfo->maxdmg);
me->SetAttackTime(OFF_ATTACK, (me->GetAttackTime(BASE_ATTACK)*150)/100);
me->SetCanDualWield(true);
}
}
else if (phase == 2)
@@ -96,24 +96,21 @@ class boss_arlokk : public CreatureScript
void Reset() OVERRIDE
{
if (events.IsInPhase(PHASE_TWO))
me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, false); // hack
_Reset();
_summonCountA = 0;
_summonCountB = 0;
me->RemoveAllAuras();
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, uint32(WEAPON_DAGGER));
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, uint32(WEAPON_DAGGER));
if (GameObject* gate = me->GetMap()->GetGameObject(instance->GetData64(GO_FORCEFIELD)))
gate->SetGoState(GO_STATE_READY);
me->SetWalk(false);
me->GetMotionMaster()->MovePoint(0, PosMoveOnSpawn[0]);
}
void JustDied(Unit* /*killer*/) OVERRIDE
{
_JustDied();
Talk(SAY_DEATH);
me->RemoveAllAuras();
if (GameObject* gate = me->GetMap()->GetGameObject(instance->GetData64(GO_FORCEFIELD)))
gate->SetGoState(GO_STATE_ACTIVE);
instance->SetBossState(DATA_ARLOKK, DONE);
}
void EnterCombat(Unit* /*who*/) OVERRIDE
@@ -154,11 +151,9 @@ class boss_arlokk : public CreatureScript
void EnterEvadeMode() OVERRIDE
{
if (GameObject* object = me->GetMap()->GetGameObject(instance->GetData64(GO_FORCEFIELD)))
object->SetGoState(GO_STATE_ACTIVE);
if (GameObject* object = me->GetMap()->GetGameObject(instance->GetData64(GO_GONG_OF_BETHEKK)))
BossAI::EnterEvadeMode();
if (GameObject* object = ObjectAccessor::GetGameObject(*me, instance->GetData64(GO_GONG_OF_BETHEKK)))
object->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
instance->SetBossState(DATA_ARLOKK, NOT_STARTED);
me->DespawnOrUnsummon(4000);
}
@@ -194,7 +189,7 @@ class boss_arlokk : public CreatureScript
case EVENT_SUMMON_PROWLERS:
if (_summonCountA < MAX_PROWLERS_PER_SIDE)
{
if (Unit* trigger = me->GetUnit(*me, _triggersSideAGUID[urand(0, 4)]))
if (Unit* trigger = ObjectAccessor::GetUnit(*me, _triggersSideAGUID[urand(0, 4)]))
{
trigger->CastSpell(trigger, SPELL_SUMMON_PROWLER);
++_summonCountA;
@@ -202,7 +197,7 @@ class boss_arlokk : public CreatureScript
}
if (_summonCountB < MAX_PROWLERS_PER_SIDE)
{
if (Unit* trigger = me->GetUnit(*me, _triggersSideBGUID[urand(0, 4)]))
if (Unit* trigger = ObjectAccessor::GetUnit(*me, _triggersSideBGUID[urand(0, 4)]))
{
trigger->CastSpell(trigger, SPELL_SUMMON_PROWLER);
++_summonCountB;
@@ -225,13 +220,15 @@ class boss_arlokk : public CreatureScript
}
case EVENT_TRANSFORM:
{
DoCast(me, SPELL_PANTHER_TRANSFORM);
DoCast(me, SPELL_PANTHER_TRANSFORM); // SPELL_AURA_TRANSFORM
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, uint32(EQUIP_UNEQUIP));
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, uint32(EQUIP_UNEQUIP));
/*
const CreatureTemplate* cinfo = me->GetCreatureTemplate();
me->SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, (cinfo->mindmg +((cinfo->mindmg/100) * 35)));
me->SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, (cinfo->maxdmg +((cinfo->maxdmg/100) * 35)));
me->UpdateDamagePhysical(BASE_ATTACK);
*/
me->AttackStop();
DoResetThreat();
me->SetReactState(REACT_PASSIVE);
@@ -262,6 +259,7 @@ class boss_arlokk : public CreatureScript
events.ScheduleEvent(EVENT_RAVAGE, urand(10000, 14000), 0, PHASE_TWO);
events.ScheduleEvent(EVENT_TRANSFORM_BACK, urand(15000, 18000), 0, PHASE_TWO);
events.SetPhase(PHASE_TWO);
me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, true); // hack
break;
case EVENT_RAVAGE:
DoCastVictim(SPELL_RAVAGE, true);
@@ -269,14 +267,17 @@ class boss_arlokk : public CreatureScript
break;
case EVENT_TRANSFORM_BACK:
{
me->RemoveAura(SPELL_PANTHER_TRANSFORM);
me->RemoveAura(SPELL_PANTHER_TRANSFORM); // SPELL_AURA_TRANSFORM
DoCast(me, SPELL_VANISH_VISUAL);
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, uint32(WEAPON_DAGGER));
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, uint32(WEAPON_DAGGER));
/*
const CreatureTemplate* cinfo = me->GetCreatureTemplate();
me->SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, (cinfo->mindmg));
me->SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, (cinfo->maxdmg));
me->UpdateDamagePhysical(BASE_ATTACK);
*/
me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, false); // hack
events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, urand(4000, 7000), 0, PHASE_ONE);
events.ScheduleEvent(EVENT_GOUGE, urand(12000, 15000), 0, PHASE_ONE);
events.ScheduleEvent(EVENT_TRANSFORM, urand(16000, 20000), 0, PHASE_ONE);
@@ -64,11 +64,6 @@ enum Phases
PHASE_THREE = 3
};
enum ModelId
{
MODEL_MARLI = 15220
};
class boss_marli : public CreatureScript
{
public: boss_marli() : CreatureScript("boss_marli") { }
@@ -79,6 +74,8 @@ class boss_marli : public CreatureScript
void Reset() OVERRIDE
{
if (events.IsInPhase(PHASE_THREE))
me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, false); // hack
_Reset();
}
@@ -155,11 +152,14 @@ class boss_marli : public CreatureScript
case EVENT_TRANSFORM:
{
Talk(SAY_TRANSFORM);
DoCast(me, SPELL_SPIDER_FORM);
DoCast(me, SPELL_SPIDER_FORM); // SPELL_AURA_TRANSFORM
/*
CreatureTemplate const* cinfo = me->GetCreatureTemplate();
me->SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, (cinfo->mindmg +((cinfo->mindmg/100) * 35)));
me->SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, (cinfo->maxdmg +((cinfo->maxdmg/100) * 35)));
me->UpdateDamagePhysical(BASE_ATTACK);
*/
me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, true); // hack
DoCastVictim(SPELL_ENVOLWINGWEB);
if (DoGetThreat(me->GetVictim()))
DoModifyThreatPercent(me->GetVictim(), -100);
@@ -188,11 +188,14 @@ class boss_marli : public CreatureScript
}
case EVENT_TRANSFORM_BACK:
{
me->SetDisplayId(MODEL_MARLI);
me->RemoveAura(SPELL_SPIDER_FORM);
/*
CreatureTemplate const* cinfo = me->GetCreatureTemplate();
me->SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, (cinfo->mindmg +((cinfo->mindmg/100) * 1)));
me->SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, (cinfo->maxdmg +((cinfo->maxdmg/100) * 1)));
me->UpdateDamagePhysical(BASE_ATTACK);
*/
me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, false); // hack
events.ScheduleEvent(EVENT_ASPECT_OF_MARLI, 12000, 0, PHASE_TWO);
events.ScheduleEvent(EVENT_TRANSFORM, 45000, 0, PHASE_TWO);
events.ScheduleEvent(EVENT_POISON_VOLLEY, 15000);
@@ -89,6 +89,8 @@ class boss_thekal : public CreatureScript
void Reset() OVERRIDE
{
if (events.IsInPhase(PHASE_TWO))
me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, false); // hack
_Reset();
Enraged = false;
WasDead = false;
@@ -141,15 +143,17 @@ class boss_thekal : public CreatureScript
//Thekal will transform to Tiger if he died and was not resurrected after 10 seconds.
if (WasDead)
{
DoCast(me, SPELL_TIGER_FORM);
DoCast(me, SPELL_TIGER_FORM); // SPELL_AURA_TRANSFORM
me->SetObjectScale(2.00f);
me->SetStandState(UNIT_STAND_STATE_STAND);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
me->SetFullHealth();
/*
const CreatureTemplate* cinfo = me->GetCreatureTemplate();
me->SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, (cinfo->mindmg +((cinfo->mindmg/100) * 40)));
me->SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, (cinfo->maxdmg +((cinfo->maxdmg/100) * 40)));
me->UpdateDamagePhysical(BASE_ATTACK);
*/
me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 40.0f, true); // hack
DoResetThreat();
events.ScheduleEvent(EVENT_FRENZY, 30000, 0, PHASE_TWO); // Phase 2
events.ScheduleEvent(EVENT_FORCEPUNCH, 4000, 0, PHASE_TWO); // Phase 2
@@ -27,6 +27,12 @@ EndScriptData */
#include "InstanceScript.h"
#include "zulgurub.h"
DoorData const doorData[] =
{
{ GO_FORCEFIELD, DATA_ARLOKK, DOOR_TYPE_ROOM, BOUNDARY_NONE },
{ 0, 0, DOOR_TYPE_ROOM, BOUNDARY_NONE } // END
};
class instance_zulgurub : public InstanceMapScript
{
public: instance_zulgurub(): InstanceMapScript(ZGScriptName, 309) { }
@@ -36,6 +42,7 @@ class instance_zulgurub : public InstanceMapScript
instance_zulgurub_InstanceMapScript(Map* map) : InstanceScript(map)
{
SetBossNumber(EncounterCount);
LoadDoorData(doorData);
}
void Initialize() OVERRIDE
@@ -46,7 +53,6 @@ class instance_zulgurub : public InstanceMapScript
_jindoTheHexxerGUID = 0;
_vilebranchSpeakerGUID = 0;
_arlokkGUID = 0;
_goForcefieldGUID = 0;
_goGongOfBethekkGUID = 0;
}
@@ -86,7 +92,7 @@ class instance_zulgurub : public InstanceMapScript
switch (go->GetEntry())
{
case GO_FORCEFIELD:
_goForcefieldGUID = go->GetGUID();
AddDoor(go, true);
break;
case GO_GONG_OF_BETHEKK:
_goGongOfBethekkGUID = go->GetGUID();
@@ -100,6 +106,18 @@ class instance_zulgurub : public InstanceMapScript
}
}
void OnGameObjectRemove(GameObject* go) OVERRIDE
{
switch (go->GetEntry())
{
case GO_FORCEFIELD:
AddDoor(go, false);
break;
default:
break;
}
}
uint64 GetData64(uint32 uiData) const OVERRIDE
{
switch (uiData)
@@ -119,9 +137,6 @@ class instance_zulgurub : public InstanceMapScript
case NPC_ARLOKK:
return _arlokkGUID;
break;
case GO_FORCEFIELD:
return _goForcefieldGUID;
break;
case GO_GONG_OF_BETHEKK:
return _goGongOfBethekkGUID;
break;
@@ -181,7 +196,6 @@ class instance_zulgurub : public InstanceMapScript
uint64 _jindoTheHexxerGUID;
uint64 _vilebranchSpeakerGUID;
uint64 _arlokkGUID;
uint64 _goForcefieldGUID;
uint64 _goGongOfBethekkGUID;
};
@@ -232,7 +232,6 @@ public:
npc_nadox_eggsAI(Creature* creature) : ScriptedAI(creature)
{
creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE);
creature->UpdateAllStats();
}
void Reset() OVERRIDE { }
@@ -281,7 +281,6 @@ struct boss_twin_baseAI : public BossAI
{
SetEquipmentSlots(false, Weapon, mode ? Weapon : int32(EQUIP_UNEQUIP), EQUIP_UNEQUIP);
me->SetCanDualWield(mode);
me->UpdateDamagePhysical(mode ? OFF_ATTACK : BASE_ATTACK);
}
void UpdateAI(uint32 diff) OVERRIDE
+15 -25
View File
@@ -25,9 +25,9 @@
enum HunterSpells
{
SPELL_HUNTER_CRIPPLING_POISON = 30981, // Viper
SPELL_HUNTER_DEADLY_POISON = 34655, // Venomous Snake
SPELL_HUNTER_MIND_NUMBING_POISON = 25810 // Viper
SPELL_HUNTER_CRIPPLING_POISON = 30981, // Viper
SPELL_HUNTER_DEADLY_POISON_PASSIVE = 34657, // Venomous Snake
SPELL_HUNTER_MIND_NUMBING_POISON = 25810 // Viper
};
enum HunterCreatures
@@ -57,14 +57,17 @@ 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
uint32 delta = (rand() % 7) * 100;
me->SetStatFloatValue(UNIT_FIELD_BASEATTACKTIME, float(Info->baseattacktime + delta));
me->SetStatFloatValue(UNIT_FIELD_RANGED_ATTACK_POWER, float(Info->attackpower));
me->SetAttackTime(BASE_ATTACK, Info->baseattacktime + delta);
//me->SetStatFloatValue(UNIT_FIELD_RANGED_ATTACK_POWER, float(Info->attackpower));
// Start attacking attacker of owner on first ai update after spawn - move in line of sight may choose better target
if (!me->GetVictim() && me->IsSummon())
if (Unit* Owner = me->ToTempSummon()->GetSummoner())
if (Owner->getAttackerForHelper())
AttackStart(Owner->getAttackerForHelper());
if (!_isViper)
DoCast(me, SPELL_HUNTER_DEADLY_POISON_PASSIVE, true);
}
// Redefined for random target selection:
@@ -99,32 +102,19 @@ class npc_pet_hunter_snake_trap : public CreatureScript
return;
}
if (_spellTimer <= diff)
// Viper
if (_isViper)
{
if (_isViper) // Viper
if (_spellTimer <= diff)
{
if (urand(0, 2) == 0) //33% chance to cast
{
uint32 spell;
if (urand(0, 1) == 0)
spell = SPELL_HUNTER_MIND_NUMBING_POISON;
else
spell = SPELL_HUNTER_CRIPPLING_POISON;
DoCastVictim(spell);
}
if (urand(0, 2) == 0) // 33% chance to cast
DoCastVictim(RAND(SPELL_HUNTER_MIND_NUMBING_POISON, SPELL_HUNTER_CRIPPLING_POISON));
_spellTimer = 3000;
}
else // Venomous Snake
{
if (urand(0, 2) == 0) // 33% chance to cast
DoCastVictim(SPELL_HUNTER_DEADLY_POISON);
_spellTimer = 1500 + (rand() % 5) * 100;
}
else
_spellTimer -= diff;
}
else
_spellTimer -= diff;
DoMeleeAttackIfReady();
}