diff options
22 files changed, 337 insertions, 310 deletions
diff --git a/sql/updates/world/2014_01_04_00_world_creature_classlevelstats.sql b/sql/updates/world/2014_01_04_00_world_creature_classlevelstats.sql new file mode 100644 index 00000000000..d55561bbe0e --- /dev/null +++ b/sql/updates/world/2014_01_04_00_world_creature_classlevelstats.sql @@ -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; diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index d5ccaab27da..8019a14a0bd 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -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; + + SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, weaponBaseMinDamage); + SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, weaponBaseMaxDamage); - float damagemod = 1.0f;//_GetDamageMod(rank); + SetBaseWeaponDamage(OFF_ATTACK, MINDAMAGE, weaponBaseMinDamage); + SetBaseWeaponDamage(OFF_ATTACK, MAXDAMAGE, weaponBaseMaxDamage); - SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, stats->AttackPower * damagemod); + 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(); } diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index 2f78d29a968..e9abd7c0e0a 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -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; } diff --git a/src/server/game/Entities/Creature/TemporarySummon.h b/src/server/game/Entities/Creature/TemporarySummon.h index 5455bad904a..e93f66ed726 100644 --- a/src/server/game/Entities/Creature/TemporarySummon.h +++ b/src/server/game/Entities/Creature/TemporarySummon.h @@ -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); diff --git a/src/server/game/Entities/Pet/Pet.h b/src/server/game/Entities/Pet/Pet.h index c375cd30ad3..ef5e792e939 100644 --- a/src/server/game/Entities/Pet/Pet.h +++ b/src/server/game/Entities/Pet/Pet.h @@ -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); diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index f7658f73321..457f5af8361 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -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);} diff --git a/src/server/game/Entities/Totem/Totem.h b/src/server/game/Entities/Totem/Totem.h index d20a58abd01..6364157982e 100644 --- a/src/server/game/Entities/Totem/Totem.h +++ b/src/server/game/Entities/Totem/Totem.h @@ -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; diff --git a/src/server/game/Entities/Unit/StatSystem.cpp b/src/server/game/Entities/Unit/StatSystem.cpp index 3077b143bb0..3afa6b016d2 100644 --- a/src/server/game/Entities/Unit/StatSystem.cpp +++ b/src/server/game/Entities/Unit/StatSystem.cpp @@ -48,6 +48,43 @@ inline bool _ModifyUInt32(bool apply, uint32& baseValue, int32& amount) /*####################################### ######## ######## +######## 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) { diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index e5fb575d8eb..cb390cc4654 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -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 diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index eb236666976..9cfdbbc77eb 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -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; diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index a84e2910e52..0d6990acb01 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -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; diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index 9d63e97a159..e5d3a5312de 100644 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -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, diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 6a3e804eb57..4cc7e60ceaa 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -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); diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 9a2b3815285..81eb45191bf 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -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(); diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_prince_malchezaar.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_prince_malchezaar.cpp index b82c0099ce4..bde326a5c37 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_prince_malchezaar.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_prince_malchezaar.cpp @@ -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) diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/boss_arlokk.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/boss_arlokk.cpp index 4bf50581108..5b943fd57f2 100644 --- a/src/server/scripts/EasternKingdoms/ZulGurub/boss_arlokk.cpp +++ b/src/server/scripts/EasternKingdoms/ZulGurub/boss_arlokk.cpp @@ -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); diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/boss_marli.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/boss_marli.cpp index 3ff18d81032..efd79d89a2b 100644 --- a/src/server/scripts/EasternKingdoms/ZulGurub/boss_marli.cpp +++ b/src/server/scripts/EasternKingdoms/ZulGurub/boss_marli.cpp @@ -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); diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/boss_thekal.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/boss_thekal.cpp index d857bff69e0..a70dd5e0a30 100644 --- a/src/server/scripts/EasternKingdoms/ZulGurub/boss_thekal.cpp +++ b/src/server/scripts/EasternKingdoms/ZulGurub/boss_thekal.cpp @@ -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 diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/instance_zulgurub.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/instance_zulgurub.cpp index 673450f83d0..67d40abaea3 100644 --- a/src/server/scripts/EasternKingdoms/ZulGurub/instance_zulgurub.cpp +++ b/src/server/scripts/EasternKingdoms/ZulGurub/instance_zulgurub.cpp @@ -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; }; diff --git a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_elder_nadox.cpp b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_elder_nadox.cpp index 0b281c58839..84c9181e495 100644 --- a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_elder_nadox.cpp +++ b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_elder_nadox.cpp @@ -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 { } diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp index d0120e4c2de..0d7dc9062ad 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp @@ -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 diff --git a/src/server/scripts/Pet/pet_hunter.cpp b/src/server/scripts/Pet/pet_hunter.cpp index 0db35bf2fe6..8a0b78b5478 100644 --- a/src/server/scripts/Pet/pet_hunter.cpp +++ b/src/server/scripts/Pet/pet_hunter.cpp @@ -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(); } |