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:
@@ -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;
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user