Merge remote-tracking branch 'upstream/master' into Playerbot
# Conflicts: # src/server/game/Spells/SpellInfoCorrections.cpp # src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp
This commit is contained in:
@@ -48,6 +48,7 @@
|
||||
#include "SecretMgr.h"
|
||||
#include "SharedDefines.h"
|
||||
#include "SteadyTimer.h"
|
||||
#include "Systemd.h"
|
||||
#include "World.h"
|
||||
#include "WorldSessionMgr.h"
|
||||
#include "WorldSocket.h"
|
||||
@@ -406,7 +407,8 @@ int main(int argc, char** argv)
|
||||
sScriptMgr->OnShutdown();
|
||||
|
||||
// set server offline
|
||||
LoginDatabase.DirectExecute("UPDATE realmlist SET flag = flag | {} WHERE id = '{}'", REALM_FLAG_OFFLINE, realm.Id.Realm);
|
||||
if (!sConfigMgr->GetOption<bool>("Network.UseSocketActivation", false))
|
||||
LoginDatabase.DirectExecute("UPDATE realmlist SET flag = flag | {} WHERE id = '{}'", REALM_FLAG_OFFLINE, realm.Id.Realm);
|
||||
|
||||
LOG_INFO("server.worldserver", "Halting process...");
|
||||
|
||||
|
||||
@@ -397,6 +397,20 @@ Network.TcpNodelay = 1
|
||||
|
||||
Network.EnableProxyProtocol = 0
|
||||
|
||||
#
|
||||
# Network.UseSocketActivation
|
||||
# Description: Enable systemd socket activation support for the worldserver.
|
||||
# When enabled and the process is started by systemd socket activation,
|
||||
# the server will use the socket passed by systemd instead of
|
||||
# creating and binding its own listening socket. Disabled by default.
|
||||
#
|
||||
# When enabled the realm is not automatically set as offline on shutdown.
|
||||
#
|
||||
# Example: 1 - (Enabled)
|
||||
# Default: 0 - (Disabled)
|
||||
|
||||
Network.UseSocketActivation = 0
|
||||
|
||||
#
|
||||
###################################################################################################
|
||||
|
||||
@@ -3363,6 +3377,15 @@ DungeonAccessRequirements.LFGLevelDBCOverride = 0
|
||||
|
||||
DungeonFinder.CastDeserter = 1
|
||||
|
||||
#
|
||||
# DungeonFinder.AllowCompleted
|
||||
#
|
||||
# Description: Controls whether completed heroic dungeons are excluded from LFG queue.
|
||||
# 0 - (Classic WLK mode: Dungeons completed by any group member today are excluded (daily lockout enforced))
|
||||
# Default: 1 - (Blizzlike: All dungeons are available for queue, even if already completed)
|
||||
|
||||
DungeonFinder.AllowCompleted = 1
|
||||
|
||||
#
|
||||
###################################################################################################
|
||||
|
||||
|
||||
@@ -15,12 +15,13 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptedCreature.h"
|
||||
#include "Cell.h"
|
||||
#include "CellImpl.h"
|
||||
#include "Containers.h"
|
||||
#include "GameTime.h"
|
||||
#include "GridNotifiers.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "Spell.h"
|
||||
#include "TemporarySummon.h"
|
||||
|
||||
@@ -141,6 +142,23 @@ Creature* SummonList::GetCreatureWithEntry(uint32 entry) const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Creature* SummonList::GetRandomCreatureWithEntry(uint32 entry) const
|
||||
{
|
||||
std::vector<ObjectGuid> candidates;
|
||||
candidates.reserve(storage_.size());
|
||||
|
||||
for (auto const guid : storage_)
|
||||
if (Creature* summon = ObjectAccessor::GetCreature(*me, guid))
|
||||
if (summon->GetEntry() == entry)
|
||||
candidates.push_back(guid);
|
||||
|
||||
if (candidates.empty())
|
||||
return nullptr;
|
||||
|
||||
ObjectGuid randomGuid = Acore::Containers::SelectRandomContainerElement(candidates);
|
||||
return ObjectAccessor::GetCreature(*me, randomGuid);
|
||||
}
|
||||
|
||||
bool SummonList::IsAnyCreatureAlive() const
|
||||
{
|
||||
for (auto const& guid : storage_)
|
||||
|
||||
@@ -157,6 +157,7 @@ public:
|
||||
uint32 GetEntryCount(uint32 entry) const;
|
||||
void Respawn();
|
||||
Creature* GetCreatureWithEntry(uint32 entry) const;
|
||||
Creature* GetRandomCreatureWithEntry(uint32 entry) const;
|
||||
|
||||
private:
|
||||
Creature* me;
|
||||
|
||||
@@ -858,7 +858,7 @@ void SmartAI::AttackStart(Unit* who)
|
||||
return;
|
||||
}
|
||||
|
||||
if (who && me->Attack(who, me->IsWithinMeleeRange(who)))
|
||||
if (who && me->Attack(who, me->IsWithinMeleeRange(who) || _currentRangeMode))
|
||||
{
|
||||
if (!me->HasUnitState(UNIT_STATE_NO_COMBAT_MOVEMENT))
|
||||
{
|
||||
@@ -870,7 +870,7 @@ void SmartAI::AttackStart(Unit* who)
|
||||
me->GetMotionMaster()->Clear(false);
|
||||
}
|
||||
|
||||
me->GetMotionMaster()->MoveChase(who);
|
||||
me->GetMotionMaster()->MoveChase(who, _attackDistance);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -941,6 +941,35 @@ void SmartAI::PassengerBoarded(Unit* who, int8 seatId, bool apply)
|
||||
void SmartAI::InitializeAI()
|
||||
{
|
||||
GetScript()->OnInitialize(me);
|
||||
|
||||
for (SmartScriptHolder const& event : GetScript()->GetEvents())
|
||||
{
|
||||
if (event.GetActionType() != SMART_ACTION_CAST)
|
||||
continue;
|
||||
|
||||
if (!(event.action.cast.castFlags & SMARTCAST_MAIN_SPELL))
|
||||
continue;
|
||||
|
||||
SetMainSpell(event.action.cast.spell);
|
||||
break;
|
||||
}
|
||||
|
||||
// Fallback: use first SMARTCAST_COMBAT_MOVE if no MAIN_SPELL found
|
||||
if (!_currentRangeMode)
|
||||
{
|
||||
for (SmartScriptHolder const& event : GetScript()->GetEvents())
|
||||
{
|
||||
if (event.GetActionType() != SMART_ACTION_CAST)
|
||||
continue;
|
||||
|
||||
if (!(event.action.cast.castFlags & SMARTCAST_COMBAT_MOVE))
|
||||
continue;
|
||||
|
||||
SetMainSpell(event.action.cast.spell);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!me->isDead())
|
||||
{
|
||||
mJustReset = true;
|
||||
@@ -1083,6 +1112,20 @@ void SmartAI::SetCurrentRangeMode(bool on, float range)
|
||||
me->GetMotionMaster()->MoveChase(victim, _attackDistance);
|
||||
}
|
||||
|
||||
void SmartAI::SetMainSpell(uint32 spellId)
|
||||
{
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||
if (!spellInfo)
|
||||
return;
|
||||
|
||||
float maxRange = spellInfo->GetMaxRange(false);
|
||||
if (maxRange <= NOMINAL_MELEE_RANGE)
|
||||
return;
|
||||
|
||||
_attackDistance = std::max(maxRange - NOMINAL_MELEE_RANGE, 0.0f);
|
||||
_currentRangeMode = true;
|
||||
}
|
||||
|
||||
void SmartAI::DistanceYourself(float range)
|
||||
{
|
||||
Unit* victim = me->GetVictim();
|
||||
|
||||
@@ -67,6 +67,7 @@ public:
|
||||
void SetAutoAttack(bool on) { mCanAutoAttack = on; }
|
||||
void SetCombatMovement(bool on, bool stopOrStartMovement);
|
||||
void SetCurrentRangeMode(bool on, float range = 0.f);
|
||||
void SetMainSpell(uint32 spellId);
|
||||
void DistanceYourself(float range);
|
||||
void SetFollow(Unit* target, float dist = 0.0f, float angle = 0.0f, uint32 credit = 0, uint32 end = 0, uint32 creditType = 0, bool aliveState = true);
|
||||
void StopFollow(bool complete);
|
||||
|
||||
@@ -707,7 +707,6 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
|
||||
continue;
|
||||
}
|
||||
|
||||
// Let us not try to cast spell if we know it is going to fail anyway. Stick to chasing and continue.
|
||||
if (distanceToTarget > spellMaxRange && isWithinLOSInMap)
|
||||
{
|
||||
failedSpellCast = true;
|
||||
@@ -745,12 +744,9 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
|
||||
|
||||
if (e.action.cast.castFlags & SMARTCAST_COMBAT_MOVE)
|
||||
{
|
||||
// If cast flag SMARTCAST_COMBAT_MOVE is set combat movement will not be allowed unless target is outside spell range, out of mana, or LOS.
|
||||
if (result == SPELL_FAILED_OUT_OF_RANGE || result == SPELL_CAST_OK)
|
||||
// if we are just out of range, we only chase until we are back in spell range.
|
||||
if (result == SPELL_FAILED_OUT_OF_RANGE)
|
||||
CAST_AI(SmartAI, me->AI())->SetCurrentRangeMode(true, std::max(spellMaxRange - NOMINAL_MELEE_RANGE, 0.0f));
|
||||
else // move into melee on any other fail
|
||||
// if spell fail for any other reason, we chase to melee range, or stay where we are if spellcast was successful.
|
||||
else if (result != SPELL_CAST_OK)
|
||||
CAST_AI(SmartAI, me->AI())->SetCurrentRangeMode(false, 0.f);
|
||||
}
|
||||
|
||||
@@ -2696,6 +2692,8 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
|
||||
{
|
||||
if (me && me->FindMap())
|
||||
me->FindMap()->LoadGrid(e.target.x, e.target.y);
|
||||
else if (go && go->FindMap())
|
||||
go->FindMap()->LoadGrid(e.target.x, e.target.y);
|
||||
break;
|
||||
}
|
||||
case SMART_ACTION_PLAYER_TALK:
|
||||
|
||||
@@ -207,6 +207,8 @@ public:
|
||||
void AddCreatureSummon(ObjectGuid const& guid);
|
||||
void RemoveCreatureSummon(ObjectGuid const& guid);
|
||||
|
||||
SmartAIEventList const& GetEvents() const { return mEvents; }
|
||||
|
||||
private:
|
||||
void IncPhase(uint32 p);
|
||||
void DecPhase(uint32 p);
|
||||
|
||||
@@ -1932,16 +1932,17 @@ enum SmartEventFlags
|
||||
|
||||
enum SmartCastFlags
|
||||
{
|
||||
SMARTCAST_INTERRUPT_PREVIOUS = 0x001, // Interrupt any spell casting
|
||||
SMARTCAST_TRIGGERED = 0x002, // Triggered (this makes spell cost zero mana and have no cast time)
|
||||
//CAST_FORCE_CAST = 0x004, // Forces cast even if creature is out of mana or out of range
|
||||
//CAST_NO_MELEE_IF_OOM = 0x008, // Prevents creature from entering melee if out of mana or out of range
|
||||
//CAST_FORCE_TARGET_SELF = 0x010, // Forces the target to cast this spell on itself
|
||||
SMARTCAST_AURA_NOT_PRESENT = 0x020, // Only casts the spell if the target does not have an aura from the spell
|
||||
SMARTCAST_COMBAT_MOVE = 0x040, // Prevents combat movement if cast successful. Allows movement on range, OOM, LOS
|
||||
SMARTCAST_THREATLIST_NOT_SINGLE = 0x080, // Only cast if the source's threatlist is higher than one. This includes pets (see Skeram's True Fulfillment)
|
||||
SMARTCAST_TARGET_POWER_MANA = 0x100, // Only cast if the target has power type mana (e.g. Mana Drain)
|
||||
SMARTCAST_ENABLE_COMBAT_MOVE_ON_LOS = 0x200,
|
||||
SMARTCAST_INTERRUPT_PREVIOUS = 0x001, // Interrupt any spell casting
|
||||
SMARTCAST_TRIGGERED = 0x002, // Triggered (this makes spell cost zero mana and have no cast time)
|
||||
//CAST_FORCE_CAST = 0x004, // Forces cast even if creature is out of mana or out of range
|
||||
//CAST_NO_MELEE_IF_OOM = 0x008, // Prevents creature from entering melee if out of mana or out of range
|
||||
//CAST_FORCE_TARGET_SELF = 0x010, // Forces the target to cast this spell on itself
|
||||
SMARTCAST_AURA_NOT_PRESENT = 0x020, // Only casts the spell if the target does not have an aura from the spell
|
||||
SMARTCAST_COMBAT_MOVE = 0x040, // Prevents combat movement if cast successful. Allows movement on range, OOM, LOS
|
||||
SMARTCAST_THREATLIST_NOT_SINGLE = 0x080, // Only cast if the source's threatlist is higher than one. This includes pets (see Skeram's True Fulfillment)
|
||||
SMARTCAST_TARGET_POWER_MANA = 0x100, // Only cast if the target has power type mana (e.g. Mana Drain)
|
||||
SMARTCAST_ENABLE_COMBAT_MOVE_ON_LOS = 0x200, // Allows combat movement when not in line of sight
|
||||
SMARTCAST_MAIN_SPELL = 0x400, // Sets this spell's max range as the creature's chase distance on spawn
|
||||
};
|
||||
|
||||
enum SmartFollowType
|
||||
|
||||
@@ -688,7 +688,7 @@ namespace lfg
|
||||
// xinef: dont check compatibile dungeons for already running group (bind problems)
|
||||
if (!isContinue)
|
||||
{
|
||||
GetCompatibleDungeons(dungeons, players, joinData.lockmap);
|
||||
GetCompatibleDungeons(dungeons, players, joinData.lockmap, rDungeonId);
|
||||
if (dungeons.empty())
|
||||
joinData.result = grp ? LFG_JOIN_PARTY_NOT_MEET_REQS : LFG_JOIN_NOT_MEET_REQS;
|
||||
}
|
||||
@@ -1485,7 +1485,7 @@ namespace lfg
|
||||
@param[in] players Set of players to check their dungeon restrictions
|
||||
@param[out] lockMap Map of players Lock status info of given dungeons (Empty if dungeons is not empty)
|
||||
*/
|
||||
void LFGMgr::GetCompatibleDungeons(LfgDungeonSet& dungeons, LfgGuidSet const& players, LfgLockPartyMap& lockMap)
|
||||
void LFGMgr::GetCompatibleDungeons(LfgDungeonSet& dungeons, LfgGuidSet const& players, LfgLockPartyMap& lockMap, bool isRDF)
|
||||
{
|
||||
lockMap.clear();
|
||||
for (LfgGuidSet::const_iterator it = players.begin(); it != players.end() && !dungeons.empty(); ++it)
|
||||
@@ -1496,6 +1496,9 @@ namespace lfg
|
||||
{
|
||||
uint32 dungeonId = (it2->first & 0x00FFFFFF); // Compare dungeon ids
|
||||
|
||||
if (it2->second == LFG_LOCKSTATUS_RAID_LOCKED && isRDF && sWorld->getBoolConfig(CONFIG_LFG_ALLOW_COMPLETED))
|
||||
continue;
|
||||
|
||||
LfgDungeonSet::iterator itDungeon = dungeons.find(dungeonId);
|
||||
if (itDungeon != dungeons.end())
|
||||
{
|
||||
@@ -1762,10 +1765,8 @@ namespace lfg
|
||||
else
|
||||
{
|
||||
// RDF removes all binds to that map
|
||||
if (randomDungeon && !sInstanceSaveMgr->PlayerIsPermBoundToInstance(player->GetGUID(), dungeon->map, player->GetDungeonDifficulty()))
|
||||
{
|
||||
if (randomDungeon)
|
||||
sInstanceSaveMgr->PlayerUnbindInstance(player->GetGUID(), dungeon->map, player->GetDungeonDifficulty(), true);
|
||||
}
|
||||
}
|
||||
|
||||
playersTeleported.push_back(player);
|
||||
|
||||
@@ -590,7 +590,7 @@ namespace lfg
|
||||
void DecreaseKicksLeft(ObjectGuid guid);
|
||||
void SetState(ObjectGuid guid, LfgState state);
|
||||
void SetCanOverrideRBState(ObjectGuid guid, bool val);
|
||||
void GetCompatibleDungeons(LfgDungeonSet& dungeons, LfgGuidSet const& players, LfgLockPartyMap& lockMap);
|
||||
void GetCompatibleDungeons(LfgDungeonSet& dungeons, LfgGuidSet const& players, LfgLockPartyMap& lockMap, bool isRDF = false);
|
||||
void _SaveToDB(ObjectGuid guid);
|
||||
|
||||
// Proposals
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "PoolMgr.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedGossip.h"
|
||||
#include "SpellAuraDefines.h"
|
||||
#include "SpellAuraEffects.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "TemporarySummon.h"
|
||||
@@ -601,13 +602,13 @@ bool Creature::UpdateEntry(uint32 Entry, const CreatureData* data, bool changele
|
||||
SetMeleeDamageSchool(SpellSchools(cInfo->dmgschool));
|
||||
CreatureBaseStats const* stats = sObjectMgr->GetCreatureBaseStats(GetLevel(), cInfo->unit_class);
|
||||
float armor = stats->GenerateArmor(cInfo);
|
||||
SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, armor);
|
||||
SetModifierValue(UNIT_MOD_RESISTANCE_HOLY, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_HOLY]));
|
||||
SetModifierValue(UNIT_MOD_RESISTANCE_FIRE, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_FIRE]));
|
||||
SetModifierValue(UNIT_MOD_RESISTANCE_NATURE, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_NATURE]));
|
||||
SetModifierValue(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_FROST]));
|
||||
SetModifierValue(UNIT_MOD_RESISTANCE_SHADOW, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_SHADOW]));
|
||||
SetModifierValue(UNIT_MOD_RESISTANCE_ARCANE, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_ARCANE]));
|
||||
SetStatFlatModifier(UNIT_MOD_ARMOR, BASE_VALUE, armor);
|
||||
SetStatFlatModifier(UNIT_MOD_RESISTANCE_HOLY, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_HOLY]));
|
||||
SetStatFlatModifier(UNIT_MOD_RESISTANCE_FIRE, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_FIRE]));
|
||||
SetStatFlatModifier(UNIT_MOD_RESISTANCE_NATURE, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_NATURE]));
|
||||
SetStatFlatModifier(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_FROST]));
|
||||
SetStatFlatModifier(UNIT_MOD_RESISTANCE_SHADOW, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_SHADOW]));
|
||||
SetStatFlatModifier(UNIT_MOD_RESISTANCE_ARCANE, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_ARCANE]));
|
||||
|
||||
SetCanModifyStats(true);
|
||||
UpdateAllStats();
|
||||
@@ -1017,10 +1018,7 @@ void Creature::Regenerate(Powers power)
|
||||
}
|
||||
|
||||
// Apply modifiers (if any).
|
||||
AuraEffectList const& ModPowerRegenPCTAuras = GetAuraEffectsByType(SPELL_AURA_MOD_POWER_REGEN_PERCENT);
|
||||
for (AuraEffectList::const_iterator i = ModPowerRegenPCTAuras.begin(); i != ModPowerRegenPCTAuras.end(); ++i)
|
||||
if (Powers((*i)->GetMiscValue()) == power)
|
||||
AddPct(addvalue, (*i)->GetAmount());
|
||||
addvalue *= GetTotalAuraMultiplierByMiscValue(SPELL_AURA_MOD_POWER_REGEN_PERCENT, power);
|
||||
|
||||
addvalue += GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN, power) * (power == POWER_FOCUS ? PET_FOCUS_REGEN_INTERVAL.count() : CREATURE_REGEN_INTERVAL) / (5 * IN_MILLISECONDS);
|
||||
|
||||
@@ -1056,9 +1054,7 @@ void Creature::RegenerateHealth()
|
||||
}
|
||||
|
||||
// Apply modifiers (if any).
|
||||
AuraEffectList const& ModPowerRegenPCTAuras = GetAuraEffectsByType(SPELL_AURA_MOD_HEALTH_REGEN_PERCENT);
|
||||
for (AuraEffectList::const_iterator i = ModPowerRegenPCTAuras.begin(); i != ModPowerRegenPCTAuras.end(); ++i)
|
||||
AddPct(addvalue, (*i)->GetAmount());
|
||||
addvalue *= GetTotalAuraMultiplier(SPELL_AURA_MOD_HEALTH_REGEN_PERCENT);
|
||||
|
||||
addvalue += GetTotalAuraModifier(SPELL_AURA_MOD_REGEN) * CREATURE_REGEN_INTERVAL / (5 * IN_MILLISECONDS);
|
||||
|
||||
@@ -1559,8 +1555,8 @@ void Creature::SelectLevel(bool changelevel)
|
||||
|
||||
/// @todo: set UNIT_FIELD_POWER*, for some creature class case (energy, etc)
|
||||
|
||||
SetModifierValue(UNIT_MOD_HEALTH, BASE_VALUE, (float)health);
|
||||
SetModifierValue(UNIT_MOD_MANA, BASE_VALUE, (float)mana);
|
||||
SetStatFlatModifier(UNIT_MOD_HEALTH, BASE_VALUE, (float)health);
|
||||
SetStatFlatModifier(UNIT_MOD_MANA, BASE_VALUE, (float)mana);
|
||||
|
||||
// damage
|
||||
|
||||
@@ -1578,8 +1574,8 @@ void Creature::SelectLevel(bool changelevel)
|
||||
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);
|
||||
SetStatFlatModifier(UNIT_MOD_ATTACK_POWER, BASE_VALUE, stats->AttackPower);
|
||||
SetStatFlatModifier(UNIT_MOD_ATTACK_POWER_RANGED, BASE_VALUE, stats->RangedAttackPower);
|
||||
|
||||
sScriptMgr->OnCreatureSelectLevel(cInfo, this);
|
||||
}
|
||||
|
||||
@@ -815,13 +815,6 @@ void Object::ApplyModSignedFloatValue(uint16 index, float val, bool apply)
|
||||
SetFloatValue(index, cur);
|
||||
}
|
||||
|
||||
void Object::ApplyPercentModFloatValue(uint16 index, float val, bool apply)
|
||||
{
|
||||
float value = GetFloatValue(index);
|
||||
ApplyPercentModFloatVar(value, val, apply);
|
||||
SetFloatValue(index, value);
|
||||
}
|
||||
|
||||
void Object::ApplyModPositiveFloatValue(uint16 index, float val, bool apply)
|
||||
{
|
||||
float cur = GetFloatValue(index);
|
||||
|
||||
@@ -165,7 +165,6 @@ public:
|
||||
void ApplyModUInt64Value(uint16 index, int32 val, bool apply);
|
||||
void ApplyModPositiveFloatValue(uint16 index, float val, bool apply);
|
||||
void ApplyModSignedFloatValue(uint16 index, float val, bool apply);
|
||||
void ApplyPercentModFloatValue(uint16 index, float val, bool apply);
|
||||
|
||||
void SetFlag(uint16 index, uint32 newFlag);
|
||||
void RemoveFlag(uint16 index, uint32 oldFlag);
|
||||
|
||||
@@ -1075,7 +1075,7 @@ bool Guardian::InitStatsForLevel(uint8 petlevel)
|
||||
SetMeleeDamageSchool(SpellSchools(cinfo->dmgschool));
|
||||
}
|
||||
|
||||
SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(petlevel * 50));
|
||||
SetStatFlatModifier(UNIT_MOD_ARMOR, BASE_VALUE, float(petlevel * 50));
|
||||
|
||||
uint32 attackTime = BASE_ATTACK_TIME;
|
||||
if (!owner->IsClass(CLASS_HUNTER, CLASS_CONTEXT_PET) && cinfo->BaseAttackTime >= 1000)
|
||||
@@ -1094,7 +1094,7 @@ bool Guardian::InitStatsForLevel(uint8 petlevel)
|
||||
// xinef: hunter pets should not inherit template resistances
|
||||
if (!IsHunterPet())
|
||||
for (uint8 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i)
|
||||
SetModifierValue(UnitMods(UNIT_MOD_RESISTANCE_START + i), BASE_VALUE, float(cinfo->resistance[i]));
|
||||
SetStatFlatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), BASE_VALUE, float(cinfo->resistance[i]));
|
||||
|
||||
//health, mana, armor and resistance
|
||||
PetLevelInfo const* pInfo = sObjectMgr->GetPetLevelInfo(creature_ID, petlevel);
|
||||
@@ -1111,15 +1111,15 @@ bool Guardian::InitStatsForLevel(uint8 petlevel)
|
||||
}
|
||||
|
||||
SetCreateHealth(pInfo->health*factorHealth);
|
||||
SetModifierValue(UNIT_MOD_HEALTH, BASE_VALUE, (float)pInfo->health);
|
||||
SetStatFlatModifier(UNIT_MOD_HEALTH, BASE_VALUE, (float)pInfo->health);
|
||||
if (petType != HUNTER_PET) //hunter pet use focus
|
||||
{
|
||||
SetCreateMana(pInfo->mana);
|
||||
SetModifierValue(UNIT_MOD_MANA, BASE_VALUE, (float)pInfo->mana);
|
||||
SetStatFlatModifier(UNIT_MOD_MANA, BASE_VALUE, (float)pInfo->mana);
|
||||
}
|
||||
|
||||
if (pInfo->armor > 0)
|
||||
SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(pInfo->armor));
|
||||
SetStatFlatModifier(UNIT_MOD_ARMOR, BASE_VALUE, float(pInfo->armor));
|
||||
|
||||
for (uint8 stat = 0; stat < MAX_STATS; ++stat)
|
||||
SetCreateStat(Stats(stat), float(pInfo->stats[stat]));
|
||||
@@ -1138,9 +1138,9 @@ bool Guardian::InitStatsForLevel(uint8 petlevel)
|
||||
}
|
||||
|
||||
SetCreateHealth(std::max<uint32>(1, stats->BaseHealth[cinfo->expansion]*factorHealth));
|
||||
SetModifierValue(UNIT_MOD_HEALTH, BASE_VALUE, GetCreateHealth());
|
||||
SetStatFlatModifier(UNIT_MOD_HEALTH, BASE_VALUE, GetCreateHealth());
|
||||
SetCreateMana(stats->BaseMana * factorMana);
|
||||
SetModifierValue(UNIT_MOD_MANA, BASE_VALUE, GetCreateMana());
|
||||
SetStatFlatModifier(UNIT_MOD_MANA, BASE_VALUE, GetCreateMana());
|
||||
|
||||
// xinef: added some multipliers so debuffs can affect pets in any way...
|
||||
SetCreateStat(STAT_STRENGTH, 22);
|
||||
@@ -1174,24 +1174,6 @@ bool Guardian::InitStatsForLevel(uint8 petlevel)
|
||||
|
||||
switch (GetEntry())
|
||||
{
|
||||
case NPC_FELGUARD:
|
||||
{
|
||||
// xinef: Glyph of Felguard, so ugly im crying... no appropriate spell
|
||||
if (AuraEffect* aurEff = owner->GetAuraEffectDummy(SPELL_GLYPH_OF_FELGUARD))
|
||||
{
|
||||
HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_PCT, aurEff->GetAmount(), true);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case NPC_VOIDWALKER:
|
||||
{
|
||||
if (AuraEffect* aurEff = owner->GetAuraEffectDummy(SPELL_GLYPH_OF_VOIDWALKER))
|
||||
{
|
||||
HandleStatModifier(UNIT_MOD_STAT_STAMINA, TOTAL_PCT, aurEff->GetAmount(), true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NPC_WATER_ELEMENTAL_PERM:
|
||||
{
|
||||
AddAura(SPELL_PET_AVOIDANCE, this);
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "Pet.h"
|
||||
#include "Player.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "SpellAuraDefines.h"
|
||||
#include "SpellAuraEffects.h"
|
||||
|
||||
// KillRewarder incapsulates logic of rewarding player upon kill with:
|
||||
@@ -162,9 +163,7 @@ void KillRewarder::_RewardXP(Player* player, float rate)
|
||||
if (xp)
|
||||
{
|
||||
// 4.2.2. Apply auras modifying rewarded XP (SPELL_AURA_MOD_XP_PCT).
|
||||
Unit::AuraEffectList const& auras = player->GetAuraEffectsByType(SPELL_AURA_MOD_XP_PCT);
|
||||
for (Unit::AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i)
|
||||
AddPct(xp, (*i)->GetAmount());
|
||||
xp *= player->GetTotalAuraMultiplier(SPELL_AURA_MOD_XP_PCT);
|
||||
|
||||
// 4.2.3. Give XP to player.
|
||||
sScriptMgr->OnPlayerGiveXP(player, xp, _victim, PlayerXPSource::XPSOURCE_KILL);
|
||||
|
||||
@@ -69,8 +69,10 @@
|
||||
#include "Realm.h"
|
||||
#include "ReputationMgr.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "SharedDefines.h"
|
||||
#include "SocialMgr.h"
|
||||
#include "Spell.h"
|
||||
#include "SpellAuraDefines.h"
|
||||
#include "SpellAuraEffects.h"
|
||||
#include "SpellAuras.h"
|
||||
#include "SpellMgr.h"
|
||||
@@ -312,8 +314,8 @@ Player::Player(WorldSession* session): Unit(), m_mover(this)
|
||||
|
||||
for (uint8 i = 0; i < BASEMOD_END; ++i)
|
||||
{
|
||||
m_auraBaseMod[i][FLAT_MOD] = 0.0f;
|
||||
m_auraBaseMod[i][PCT_MOD] = 1.0f;
|
||||
m_auraBaseFlatMod[i] = 0.0f;
|
||||
m_auraBasePctMod[i] = 1.0f;
|
||||
}
|
||||
|
||||
for (uint8 i = 0; i < MAX_COMBAT_RATING; i++)
|
||||
@@ -831,9 +833,7 @@ int32 Player::getMaxTimer(MirrorTimerType timer)
|
||||
if (!IsAlive() || HasWaterBreathingAura() || GetSession()->GetSecurity() >= AccountTypes(sWorld->getIntConfig(CONFIG_DISABLE_BREATHING)))
|
||||
return DISABLED_MIRROR_TIMER;
|
||||
int32 UnderWaterTime = sWorld->getIntConfig(CONFIG_WATER_BREATH_TIMER);
|
||||
AuraEffectList const& mModWaterBreathing = GetAuraEffectsByType(SPELL_AURA_MOD_WATER_BREATHING);
|
||||
for (AuraEffectList::const_iterator i = mModWaterBreathing.begin(); i != mModWaterBreathing.end(); ++i)
|
||||
AddPct(UnderWaterTime, (*i)->GetAmount());
|
||||
UnderWaterTime *= GetTotalAuraMultiplier(SPELL_AURA_MOD_WATER_BREATHING);
|
||||
return UnderWaterTime;
|
||||
}
|
||||
case FIRE_TIMER:
|
||||
@@ -1922,10 +1922,7 @@ void Player::Regenerate(Powers power)
|
||||
// Mana regen calculated in Player::UpdateManaRegen(), energy regen calculated in Player::UpdateEnergyRegen()
|
||||
if (power != POWER_MANA && power != POWER_ENERGY)
|
||||
{
|
||||
AuraEffectList const& ModPowerRegenPCTAuras = GetAuraEffectsByType(SPELL_AURA_MOD_POWER_REGEN_PERCENT);
|
||||
for (AuraEffectList::const_iterator i = ModPowerRegenPCTAuras.begin(); i != ModPowerRegenPCTAuras.end(); ++i)
|
||||
if (Powers((*i)->GetMiscValue()) == power)
|
||||
AddPct(addvalue, (*i)->GetAmount());
|
||||
addvalue *= GetTotalAuraMultiplierByMiscValue(SPELL_AURA_MOD_POWER_REGEN_PERCENT, power);
|
||||
|
||||
// Butchery requires combat for this effect
|
||||
if (power != POWER_RUNIC_POWER || IsInCombat())
|
||||
@@ -2008,11 +2005,7 @@ void Player::RegenerateHealth()
|
||||
addvalue *= 1.33f;
|
||||
}
|
||||
|
||||
AuraEffectList const& mModHealthRegenPct = GetAuraEffectsByType(SPELL_AURA_MOD_HEALTH_REGEN_PERCENT);
|
||||
for (AuraEffectList::const_iterator i = mModHealthRegenPct.begin(); i != mModHealthRegenPct.end(); ++i)
|
||||
{
|
||||
AddPct(addvalue, (*i)->GetAmount());
|
||||
}
|
||||
addvalue *= GetTotalAuraMultiplier(SPELL_AURA_MOD_HEALTH_REGEN_PERCENT);
|
||||
|
||||
if (!IsInCombat())
|
||||
{
|
||||
@@ -2666,14 +2659,14 @@ void Player::InitStatsForLevel(bool reapplyMods)
|
||||
|
||||
// set armor (resistance 0) to original value (create_agility*2)
|
||||
SetArmor(int32(m_createStats[STAT_AGILITY] * 2));
|
||||
SetResistanceBuffMods(SpellSchools(0), true, 0.0f);
|
||||
SetResistanceBuffMods(SpellSchools(0), false, 0.0f);
|
||||
SetFloatValue(UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE + AsUnderlyingType(SPELL_SCHOOL_NORMAL), 0.0f);
|
||||
SetFloatValue(UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE + AsUnderlyingType(SPELL_SCHOOL_NORMAL), 0.0f);
|
||||
// set other resistance to original value (0)
|
||||
for (uint8 i = 1; i < MAX_SPELL_SCHOOL; ++i)
|
||||
{
|
||||
SetResistance(SpellSchools(i), 0);
|
||||
SetResistanceBuffMods(SpellSchools(i), true, 0.0f);
|
||||
SetResistanceBuffMods(SpellSchools(i), false, 0.0f);
|
||||
SetFloatValue(UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE + i, 0.0f);
|
||||
SetFloatValue(UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE + i, 0.0f);
|
||||
}
|
||||
|
||||
SetUInt32Value(PLAYER_FIELD_MOD_TARGET_RESISTANCE, 0);
|
||||
@@ -5047,24 +5040,107 @@ void Player::ClearChannelWatch()
|
||||
(*itr)->RemoveWatching(this);
|
||||
}
|
||||
|
||||
void Player::HandleBaseModValue(BaseModGroup modGroup, BaseModType modType, float amount, bool apply)
|
||||
void Player::HandleBaseModFlatValue(BaseModGroup modGroup, float amount, bool apply)
|
||||
{
|
||||
if (modGroup >= BASEMOD_END)
|
||||
{
|
||||
LOG_ERROR("entities.player", "ERROR in HandleBaseModValue(): non existed BaseModGroup!");
|
||||
LOG_ERROR("entities.player", "Player::HandleBaseModFlatValue: Invalid BaseModGroup/BaseModType ({}/{}) for player '{}' ({})",
|
||||
modGroup, FLAT_MOD, GetName(), GetGUID().ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
switch (modType)
|
||||
m_auraBaseFlatMod[modGroup] += apply ? amount : -amount;
|
||||
UpdateBaseModGroup(modGroup);
|
||||
}
|
||||
|
||||
void Player::ApplyBaseModPctValue(BaseModGroup modGroup, float pct)
|
||||
{
|
||||
if (modGroup >= BASEMOD_END)
|
||||
{
|
||||
case FLAT_MOD:
|
||||
m_auraBaseMod[modGroup][modType] += apply ? amount : -amount;
|
||||
LOG_ERROR("entities.player", "Player::ApplyBaseModPctValue: Invalid BaseModGroup/BaseModType ({}/{}) for player '{}' ({})",
|
||||
modGroup, PCT_MOD, GetName(), GetGUID().ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
m_auraBasePctMod[modGroup] += CalculatePct(1.0f, pct);
|
||||
UpdateBaseModGroup(modGroup);
|
||||
}
|
||||
|
||||
void Player::SetBaseModFlatValue(BaseModGroup modGroup, float val)
|
||||
{
|
||||
if (m_auraBaseFlatMod[modGroup] == val)
|
||||
return;
|
||||
|
||||
m_auraBaseFlatMod[modGroup] = val;
|
||||
UpdateBaseModGroup(modGroup);
|
||||
}
|
||||
|
||||
void Player::SetBaseModPctValue(BaseModGroup modGroup, float val)
|
||||
{
|
||||
if (m_auraBasePctMod[modGroup] == val)
|
||||
return;
|
||||
|
||||
m_auraBasePctMod[modGroup] = val;
|
||||
UpdateBaseModGroup(modGroup);
|
||||
}
|
||||
|
||||
void Player::UpdateDamageDoneMods(WeaponAttackType attackType, int32 skipEnchantSlot /*= -1*/)
|
||||
{
|
||||
Unit::UpdateDamageDoneMods(attackType, skipEnchantSlot);
|
||||
|
||||
UnitMods unitMod;
|
||||
switch (attackType)
|
||||
{
|
||||
case BASE_ATTACK:
|
||||
unitMod = UNIT_MOD_DAMAGE_MAINHAND;
|
||||
break;
|
||||
case PCT_MOD:
|
||||
ApplyPercentModFloatVar(m_auraBaseMod[modGroup][modType], amount, apply);
|
||||
case OFF_ATTACK:
|
||||
unitMod = UNIT_MOD_DAMAGE_OFFHAND;
|
||||
break;
|
||||
case RANGED_ATTACK:
|
||||
unitMod = UNIT_MOD_DAMAGE_RANGED;
|
||||
break;
|
||||
default:
|
||||
ABORT();
|
||||
break;
|
||||
}
|
||||
|
||||
float amount = 0.0f;
|
||||
Item* item = GetWeaponForAttack(attackType, true);
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
for (uint8 slot = 0; slot < MAX_ENCHANTMENT_SLOT; ++slot)
|
||||
{
|
||||
if (skipEnchantSlot == slot)
|
||||
continue;
|
||||
|
||||
SpellItemEnchantmentEntry const* enchantmentEntry = sSpellItemEnchantmentStore.LookupEntry(item->GetEnchantmentId(EnchantmentSlot(slot)));
|
||||
if (!enchantmentEntry)
|
||||
continue;
|
||||
|
||||
for (uint8 i = 0; i < MAX_SPELL_ITEM_ENCHANTMENT_EFFECTS; ++i)
|
||||
{
|
||||
switch (enchantmentEntry->type[i])
|
||||
{
|
||||
case ITEM_ENCHANTMENT_TYPE_DAMAGE:
|
||||
amount += enchantmentEntry->amount[i];
|
||||
break;
|
||||
case ITEM_ENCHANTMENT_TYPE_TOTEM:
|
||||
if (IsClass(CLASS_SHAMAN, CLASS_CONTEXT_ABILITY))
|
||||
amount += enchantmentEntry->amount[i] * item->GetTemplate()->Delay / 1000.0f;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HandleStatFlatModifier(unitMod, TOTAL_VALUE, amount, true);
|
||||
}
|
||||
|
||||
void Player::UpdateBaseModGroup(BaseModGroup modGroup)
|
||||
{
|
||||
if (!CanModifyStats())
|
||||
return;
|
||||
|
||||
@@ -5095,10 +5171,7 @@ float Player::GetBaseModValue(BaseModGroup modGroup, BaseModType modType) const
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
if (modType == PCT_MOD && m_auraBaseMod[modGroup][PCT_MOD] <= 0.0f)
|
||||
return 0.0f;
|
||||
|
||||
return m_auraBaseMod[modGroup][modType];
|
||||
return (modType == FLAT_MOD ? m_auraBaseFlatMod[modGroup] : m_auraBasePctMod[modGroup]);
|
||||
}
|
||||
|
||||
float Player::GetTotalBaseModValue(BaseModGroup modGroup) const
|
||||
@@ -5109,15 +5182,15 @@ float Player::GetTotalBaseModValue(BaseModGroup modGroup) const
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
if (m_auraBaseMod[modGroup][PCT_MOD] <= 0.0f)
|
||||
if (m_auraBasePctMod[modGroup] <= 0.0f)
|
||||
return 0.0f;
|
||||
|
||||
return m_auraBaseMod[modGroup][FLAT_MOD] * m_auraBaseMod[modGroup][PCT_MOD];
|
||||
return m_auraBaseFlatMod[modGroup] * m_auraBasePctMod[modGroup];
|
||||
}
|
||||
|
||||
uint32 Player::GetShieldBlockValue() const
|
||||
{
|
||||
float value = (m_auraBaseMod[SHIELD_BLOCK_VALUE][FLAT_MOD] + GetStat(STAT_STRENGTH) * 0.5f - 10) * m_auraBaseMod[SHIELD_BLOCK_VALUE][PCT_MOD];
|
||||
float value = (m_auraBaseFlatMod[SHIELD_BLOCK_VALUE] + GetStat(STAT_STRENGTH) * 0.5f - 10) * m_auraBasePctMod[SHIELD_BLOCK_VALUE];
|
||||
|
||||
value = (value < 0) ? 0 : value;
|
||||
|
||||
@@ -5186,7 +5259,7 @@ void Player::GetDodgeFromAgility(float& diminishing, float& nondiminishing)
|
||||
return;
|
||||
|
||||
/// @todo: research if talents/effects that increase total agility by x% should increase non-diminishing part
|
||||
float base_agility = GetCreateStat(STAT_AGILITY) * m_auraModifiersGroup[UNIT_MOD_STAT_START + static_cast<uint16>(STAT_AGILITY)][BASE_PCT];
|
||||
float base_agility = GetCreateStat(STAT_AGILITY) * GetPctModifierValue(UnitMods(UNIT_MOD_STAT_START + AsUnderlyingType(STAT_AGILITY)), BASE_PCT);
|
||||
float bonus_agility = GetStat(STAT_AGILITY) - base_agility;
|
||||
|
||||
// calculate diminishing (green in char screen) and non-diminishing (white) contribution
|
||||
@@ -6609,20 +6682,22 @@ void Player::_ApplyItemMods(Item* item, uint8 slot, bool apply)
|
||||
|
||||
LOG_DEBUG("entities.player", "applying mods for item {} ", item->GetGUID().ToString());
|
||||
|
||||
WeaponAttackType attacktype = Player::GetAttackBySlot(slot);
|
||||
|
||||
if (item->HasSocket()) //only (un)equipping of items with sockets can influence metagems, so no need to waste time with normal items
|
||||
CorrectMetaGemEnchants(slot, apply);
|
||||
|
||||
if (attacktype < MAX_ATTACK)
|
||||
_ApplyWeaponDependentAuraMods(item, attacktype, apply);
|
||||
|
||||
_ApplyItemBonuses(proto, slot, apply);
|
||||
|
||||
if (slot == EQUIPMENT_SLOT_RANGED)
|
||||
_ApplyAmmoBonuses();
|
||||
|
||||
ApplyItemEquipSpell(item, apply);
|
||||
|
||||
ApplyItemDependentAuras(item, apply);
|
||||
|
||||
WeaponAttackType const attackType = Player::GetAttackBySlot(slot);
|
||||
if (attackType != MAX_ATTACK)
|
||||
UpdateWeaponDependentAuras(attackType);
|
||||
|
||||
ApplyEnchantment(item, apply);
|
||||
|
||||
LOG_DEBUG("entities.player.items", "_ApplyItemMods complete.");
|
||||
@@ -6693,30 +6768,30 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply
|
||||
switch (statType)
|
||||
{
|
||||
case ITEM_MOD_MANA:
|
||||
HandleStatModifier(UNIT_MOD_MANA, BASE_VALUE, float(val), apply);
|
||||
HandleStatFlatModifier(UNIT_MOD_MANA, BASE_VALUE, float(val), apply);
|
||||
break;
|
||||
case ITEM_MOD_HEALTH: // modify HP
|
||||
HandleStatModifier(UNIT_MOD_HEALTH, BASE_VALUE, float(val), apply);
|
||||
HandleStatFlatModifier(UNIT_MOD_HEALTH, BASE_VALUE, float(val), apply);
|
||||
break;
|
||||
case ITEM_MOD_AGILITY: // modify agility
|
||||
HandleStatModifier(UNIT_MOD_STAT_AGILITY, BASE_VALUE, float(val), apply);
|
||||
ApplyStatBuffMod(STAT_AGILITY, float(val), apply);
|
||||
HandleStatFlatModifier(UNIT_MOD_STAT_AGILITY, BASE_VALUE, float(val), apply);
|
||||
UpdateStatBuffMod(STAT_AGILITY);
|
||||
break;
|
||||
case ITEM_MOD_STRENGTH: //modify strength
|
||||
HandleStatModifier(UNIT_MOD_STAT_STRENGTH, BASE_VALUE, float(val), apply);
|
||||
ApplyStatBuffMod(STAT_STRENGTH, float(val), apply);
|
||||
HandleStatFlatModifier(UNIT_MOD_STAT_STRENGTH, BASE_VALUE, float(val), apply);
|
||||
UpdateStatBuffMod(STAT_STRENGTH);
|
||||
break;
|
||||
case ITEM_MOD_INTELLECT: //modify intellect
|
||||
HandleStatModifier(UNIT_MOD_STAT_INTELLECT, BASE_VALUE, float(val), apply);
|
||||
ApplyStatBuffMod(STAT_INTELLECT, float(val), apply);
|
||||
HandleStatFlatModifier(UNIT_MOD_STAT_INTELLECT, BASE_VALUE, float(val), apply);
|
||||
UpdateStatBuffMod(STAT_INTELLECT);
|
||||
break;
|
||||
case ITEM_MOD_SPIRIT: //modify spirit
|
||||
HandleStatModifier(UNIT_MOD_STAT_SPIRIT, BASE_VALUE, float(val), apply);
|
||||
ApplyStatBuffMod(STAT_SPIRIT, float(val), apply);
|
||||
HandleStatFlatModifier(UNIT_MOD_STAT_SPIRIT, BASE_VALUE, float(val), apply);
|
||||
UpdateStatBuffMod(STAT_SPIRIT);
|
||||
break;
|
||||
case ITEM_MOD_STAMINA: //modify stamina
|
||||
HandleStatModifier(UNIT_MOD_STAT_STAMINA, BASE_VALUE, float(val), apply);
|
||||
ApplyStatBuffMod(STAT_STAMINA, float(val), apply);
|
||||
HandleStatFlatModifier(UNIT_MOD_STAT_STAMINA, BASE_VALUE, float(val), apply);
|
||||
UpdateStatBuffMod(STAT_STAMINA);
|
||||
break;
|
||||
case ITEM_MOD_DEFENSE_SKILL_RATING:
|
||||
ApplyRatingMod(CR_DEFENSE_SKILL, int32(val), apply);
|
||||
@@ -6805,11 +6880,11 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply
|
||||
ApplyRatingMod(CR_EXPERTISE, int32(val), apply);
|
||||
break;
|
||||
case ITEM_MOD_ATTACK_POWER:
|
||||
HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(val), apply);
|
||||
HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(val), apply);
|
||||
HandleStatFlatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(val), apply);
|
||||
HandleStatFlatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(val), apply);
|
||||
break;
|
||||
case ITEM_MOD_RANGED_ATTACK_POWER:
|
||||
HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(val), apply);
|
||||
HandleStatFlatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(val), apply);
|
||||
break;
|
||||
// case ITEM_MOD_FERAL_ATTACK_POWER:
|
||||
// ApplyFeralAPBonus(int32(val), apply);
|
||||
@@ -6830,7 +6905,7 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply
|
||||
ApplySpellPenetrationBonus(val, apply);
|
||||
break;
|
||||
case ITEM_MOD_BLOCK_VALUE:
|
||||
HandleBaseModValue(SHIELD_BLOCK_VALUE, FLAT_MOD, float(val), apply);
|
||||
HandleBaseModFlatValue(SHIELD_BLOCK_VALUE, float(val), apply);
|
||||
break;
|
||||
/// @deprecated item mods
|
||||
case ITEM_MOD_SPELL_HEALING_DONE:
|
||||
@@ -6860,7 +6935,7 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply
|
||||
|
||||
if (armor)
|
||||
{
|
||||
UnitModifierType modType = TOTAL_VALUE;
|
||||
UnitModifierFlatType modType = TOTAL_VALUE;
|
||||
if (proto->Class == ITEM_CLASS_ARMOR)
|
||||
{
|
||||
switch (proto->SubClass)
|
||||
@@ -6874,33 +6949,33 @@ void Player::_ApplyItemBonuses(ItemTemplate const* proto, uint8 slot, bool apply
|
||||
break;
|
||||
}
|
||||
}
|
||||
HandleStatModifier(UNIT_MOD_ARMOR, modType, float(armor), apply);
|
||||
HandleStatFlatModifier(UNIT_MOD_ARMOR, modType, float(armor), apply);
|
||||
}
|
||||
|
||||
// Add armor bonus from ArmorDamageModifier if > 0
|
||||
if (proto->ArmorDamageModifier > 0 && sScriptMgr->OnPlayerCanArmorDamageModifier(this))
|
||||
HandleStatModifier(UNIT_MOD_ARMOR, TOTAL_VALUE, float(proto->ArmorDamageModifier), apply);
|
||||
HandleStatFlatModifier(UNIT_MOD_ARMOR, TOTAL_VALUE, float(proto->ArmorDamageModifier), apply);
|
||||
|
||||
if (proto->Block)
|
||||
HandleBaseModValue(SHIELD_BLOCK_VALUE, FLAT_MOD, float(proto->Block), apply);
|
||||
HandleBaseModFlatValue(SHIELD_BLOCK_VALUE, float(proto->Block), apply);
|
||||
|
||||
if (proto->HolyRes)
|
||||
HandleStatModifier(UNIT_MOD_RESISTANCE_HOLY, BASE_VALUE, float(proto->HolyRes), apply);
|
||||
HandleStatFlatModifier(UNIT_MOD_RESISTANCE_HOLY, BASE_VALUE, float(proto->HolyRes), apply);
|
||||
|
||||
if (proto->FireRes)
|
||||
HandleStatModifier(UNIT_MOD_RESISTANCE_FIRE, BASE_VALUE, float(proto->FireRes), apply);
|
||||
HandleStatFlatModifier(UNIT_MOD_RESISTANCE_FIRE, BASE_VALUE, float(proto->FireRes), apply);
|
||||
|
||||
if (proto->NatureRes)
|
||||
HandleStatModifier(UNIT_MOD_RESISTANCE_NATURE, BASE_VALUE, float(proto->NatureRes), apply);
|
||||
HandleStatFlatModifier(UNIT_MOD_RESISTANCE_NATURE, BASE_VALUE, float(proto->NatureRes), apply);
|
||||
|
||||
if (proto->FrostRes)
|
||||
HandleStatModifier(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, float(proto->FrostRes), apply);
|
||||
HandleStatFlatModifier(UNIT_MOD_RESISTANCE_FROST, BASE_VALUE, float(proto->FrostRes), apply);
|
||||
|
||||
if (proto->ShadowRes)
|
||||
HandleStatModifier(UNIT_MOD_RESISTANCE_SHADOW, BASE_VALUE, float(proto->ShadowRes), apply);
|
||||
HandleStatFlatModifier(UNIT_MOD_RESISTANCE_SHADOW, BASE_VALUE, float(proto->ShadowRes), apply);
|
||||
|
||||
if (proto->ArcaneRes)
|
||||
HandleStatModifier(UNIT_MOD_RESISTANCE_ARCANE, BASE_VALUE, float(proto->ArcaneRes), apply);
|
||||
HandleStatFlatModifier(UNIT_MOD_RESISTANCE_ARCANE, BASE_VALUE, float(proto->ArcaneRes), apply);
|
||||
|
||||
WeaponAttackType attType = Player::GetAttackBySlot(slot);
|
||||
if (attType != MAX_ATTACK)
|
||||
@@ -7071,6 +7146,100 @@ void Player::UpdateItemObtainSpells(Item* item, uint8 bag, uint8 slot)
|
||||
ApplyItemObtainSpells(item, true);
|
||||
}
|
||||
|
||||
// this one rechecks weapon auras and stores them in BaseModGroup container
|
||||
// needed for things like axe specialization applying only to axe weapons in case of dual-wield
|
||||
void Player::UpdateWeaponDependentCritAuras(WeaponAttackType attackType)
|
||||
{
|
||||
BaseModGroup modGroup;
|
||||
switch (attackType)
|
||||
{
|
||||
case BASE_ATTACK:
|
||||
modGroup = CRIT_PERCENTAGE;
|
||||
break;
|
||||
case OFF_ATTACK:
|
||||
modGroup = OFFHAND_CRIT_PERCENTAGE;
|
||||
break;
|
||||
case RANGED_ATTACK:
|
||||
modGroup = RANGED_CRIT_PERCENTAGE;
|
||||
break;
|
||||
default:
|
||||
ABORT();
|
||||
break;
|
||||
}
|
||||
|
||||
float amount = 0.0f;
|
||||
amount += GetTotalAuraModifier(SPELL_AURA_MOD_WEAPON_CRIT_PERCENT, std::bind(&Unit::CheckAttackFitToAuraRequirement, this, attackType, std::placeholders::_1));
|
||||
|
||||
// these auras don't have item requirement (only Combat Expertise in 3.3.5a)
|
||||
amount += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_PCT);
|
||||
|
||||
SetBaseModFlatValue(modGroup, amount);
|
||||
}
|
||||
|
||||
void Player::UpdateAllWeaponDependentCritAuras()
|
||||
{
|
||||
for (uint8 i = BASE_ATTACK; i < MAX_ATTACK; ++i)
|
||||
UpdateWeaponDependentCritAuras(WeaponAttackType(i));
|
||||
}
|
||||
|
||||
void Player::UpdateWeaponDependentAuras(WeaponAttackType attackType)
|
||||
{
|
||||
UpdateWeaponDependentCritAuras(attackType);
|
||||
UpdateDamageDoneMods(attackType);
|
||||
UpdateDamagePctDoneMods(attackType);
|
||||
}
|
||||
|
||||
void Player::ApplyItemDependentAuras(Item* item, bool apply)
|
||||
{
|
||||
if (apply)
|
||||
{
|
||||
for (auto [spellId, playerSpell]: GetSpellMap())
|
||||
{
|
||||
if (playerSpell->State == PLAYERSPELL_REMOVED)
|
||||
continue;
|
||||
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||
if (!spellInfo || !spellInfo->IsPassive() || spellInfo->EquippedItemClass < 0)
|
||||
continue;
|
||||
|
||||
if (!HasAura(spellId) && HasItemFitToSpellRequirements(spellInfo))
|
||||
AddAura(spellId, this); // no SMSG_SPELL_GO in sniff found
|
||||
}
|
||||
|
||||
// Check talents (they are stored separately from regular spells)
|
||||
for (auto [spellId, playerTalent] : GetTalentMap())
|
||||
{
|
||||
if (playerTalent->State == PLAYERSPELL_REMOVED)
|
||||
continue;
|
||||
|
||||
if (!(playerTalent->IsInSpec(GetActiveSpec())))
|
||||
continue;
|
||||
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||
if (!spellInfo || !spellInfo->IsPassive() || spellInfo->EquippedItemClass < 0)
|
||||
continue;
|
||||
|
||||
if (!HasAura(spellId) && HasItemFitToSpellRequirements(spellInfo))
|
||||
AddAura(spellId, this);
|
||||
}
|
||||
}
|
||||
else
|
||||
RemoveItemDependentAurasAndCasts(item);
|
||||
}
|
||||
|
||||
bool Player::CheckAttackFitToAuraRequirement(WeaponAttackType attackType, AuraEffect const* aurEff) const
|
||||
{
|
||||
SpellInfo const* spellInfo = aurEff->GetSpellInfo();
|
||||
if (spellInfo->EquippedItemClass == -1)
|
||||
return true;
|
||||
|
||||
Item* item = GetWeaponForAttack(attackType, true);
|
||||
if (!item || !item->IsFitToSpellRequirements(spellInfo))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
SpellSchoolMask Player::GetMeleeDamageSchoolMask(WeaponAttackType attackType /*= BASE_ATTACK*/, uint8 damageIndex /*= 0*/) const
|
||||
{
|
||||
if (Item const* weapon = GetWeaponForAttack(attackType, true))
|
||||
@@ -7081,110 +7250,6 @@ SpellSchoolMask Player::GetMeleeDamageSchoolMask(WeaponAttackType attackType /*=
|
||||
return SPELL_SCHOOL_MASK_NORMAL;
|
||||
}
|
||||
|
||||
void Player::_ApplyWeaponDependentAuraMods(Item* item, WeaponAttackType attackType, bool apply)
|
||||
{
|
||||
AuraEffectList const& auraCritList = GetAuraEffectsByType(SPELL_AURA_MOD_WEAPON_CRIT_PERCENT);
|
||||
for (AuraEffectList::const_iterator itr = auraCritList.begin(); itr != auraCritList.end(); ++itr)
|
||||
_ApplyWeaponDependentAuraCritMod(item, attackType, *itr, apply);
|
||||
|
||||
AuraEffectList const& auraDamageFlatList = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_DONE);
|
||||
for (AuraEffectList::const_iterator itr = auraDamageFlatList.begin(); itr != auraDamageFlatList.end(); ++itr)
|
||||
_ApplyWeaponDependentAuraDamageMod(item, attackType, *itr, apply);
|
||||
|
||||
AuraEffectList const& auraDamagePctList = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE);
|
||||
for (AuraEffectList::const_iterator itr = auraDamagePctList.begin(); itr != auraDamagePctList.end(); ++itr)
|
||||
_ApplyWeaponDependentAuraDamageMod(item, attackType, *itr, apply);
|
||||
}
|
||||
|
||||
void Player::_ApplyWeaponDependentAuraCritMod(Item* item, WeaponAttackType attackType, AuraEffect const* aura, bool apply)
|
||||
{
|
||||
// don't apply mod if item is broken or cannot be used
|
||||
if (item->IsBroken() || !CanUseAttackType(attackType))
|
||||
return;
|
||||
|
||||
// generic not weapon specific case processes in aura code
|
||||
if (aura->GetSpellInfo()->EquippedItemClass == -1)
|
||||
return;
|
||||
|
||||
if (!sScriptMgr->OnPlayerCanApplyWeaponDependentAuraDamageMod(this, item, attackType, aura, apply))
|
||||
return;
|
||||
|
||||
BaseModGroup mod = BASEMOD_END;
|
||||
switch (attackType)
|
||||
{
|
||||
case BASE_ATTACK:
|
||||
mod = CRIT_PERCENTAGE;
|
||||
break;
|
||||
case OFF_ATTACK:
|
||||
mod = OFFHAND_CRIT_PERCENTAGE;
|
||||
break;
|
||||
case RANGED_ATTACK:
|
||||
mod = RANGED_CRIT_PERCENTAGE;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if (item->IsFitToSpellRequirements(aura->GetSpellInfo()))
|
||||
HandleBaseModValue(mod, FLAT_MOD, float (aura->GetAmount()), apply);
|
||||
}
|
||||
|
||||
void Player::_ApplyWeaponDependentAuraDamageMod(Item* item, WeaponAttackType attackType, AuraEffect const* aura, bool apply)
|
||||
{
|
||||
// don't apply mod if item is broken or cannot be used
|
||||
if (item->IsBroken() || !CanUseAttackType(attackType))
|
||||
return;
|
||||
|
||||
// ignore spell mods for not wands
|
||||
if ((aura->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) == 0 && (getClassMask() & CLASSMASK_WAND_USERS) == 0)
|
||||
return;
|
||||
|
||||
// generic not weapon specific case processes in aura code
|
||||
if (aura->GetSpellInfo()->EquippedItemClass == -1)
|
||||
return;
|
||||
|
||||
UnitMods unitMod = UNIT_MOD_END;
|
||||
switch (attackType)
|
||||
{
|
||||
case BASE_ATTACK:
|
||||
unitMod = UNIT_MOD_DAMAGE_MAINHAND;
|
||||
break;
|
||||
case OFF_ATTACK:
|
||||
unitMod = UNIT_MOD_DAMAGE_OFFHAND;
|
||||
break;
|
||||
case RANGED_ATTACK:
|
||||
unitMod = UNIT_MOD_DAMAGE_RANGED;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
UnitModifierType unitModType = TOTAL_VALUE;
|
||||
switch (aura->GetAuraType())
|
||||
{
|
||||
case SPELL_AURA_MOD_DAMAGE_DONE:
|
||||
unitModType = TOTAL_VALUE;
|
||||
break;
|
||||
case SPELL_AURA_MOD_DAMAGE_PERCENT_DONE:
|
||||
unitModType = TOTAL_PCT;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if (item->IsFitToSpellRequirements(aura->GetSpellInfo()))
|
||||
{
|
||||
HandleStatModifier(unitMod, unitModType, float(aura->GetAmount()), apply);
|
||||
if (unitModType == TOTAL_VALUE)
|
||||
{
|
||||
if (aura->GetAmount() > 0)
|
||||
ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS, aura->GetAmount(), apply);
|
||||
else
|
||||
ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG, aura->GetAmount(), apply);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Player::ApplyItemEquipSpell(Item* item, bool apply, bool form_change)
|
||||
{
|
||||
if (!item)
|
||||
@@ -7499,12 +7564,6 @@ void Player::CastItemUseSpell(Item* item, SpellCastTargets const& targets, uint8
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!spellInfo->CheckElixirStacking(this))
|
||||
{
|
||||
Spell::SendCastResult(this, spellInfo, cast_count, SPELL_FAILED_AURA_BOUNCED);
|
||||
continue;
|
||||
}
|
||||
|
||||
Spell* spell = new Spell(this, spellInfo, (count > 0) ? TRIGGERED_FULL_MASK : TRIGGERED_NONE);
|
||||
spell->m_CastItem = item;
|
||||
spell->m_cast_count = cast_count; // set count of casts
|
||||
@@ -7613,10 +7672,7 @@ void Player::_RemoveAllItemMods()
|
||||
if (!proto)
|
||||
continue;
|
||||
|
||||
WeaponAttackType attacktype = Player::GetAttackBySlot(i);
|
||||
if (attacktype < MAX_ATTACK)
|
||||
_ApplyWeaponDependentAuraMods(m_items[i], attacktype, false);
|
||||
|
||||
ApplyItemDependentAuras(m_items[i], false);
|
||||
_ApplyItemBonuses(proto, i, false);
|
||||
|
||||
if (i == EQUIPMENT_SLOT_RANGED)
|
||||
@@ -7642,12 +7698,13 @@ void Player::_ApplyAllItemMods()
|
||||
if (!proto)
|
||||
continue;
|
||||
|
||||
WeaponAttackType attacktype = Player::GetAttackBySlot(i);
|
||||
if (attacktype < MAX_ATTACK)
|
||||
_ApplyWeaponDependentAuraMods(m_items[i], attacktype, true);
|
||||
|
||||
ApplyItemDependentAuras(m_items[i], true);
|
||||
_ApplyItemBonuses(proto, i, true);
|
||||
|
||||
WeaponAttackType const attackType = Player::GetAttackBySlot(i);
|
||||
if (attackType != MAX_ATTACK)
|
||||
UpdateWeaponDependentAuras(attackType);
|
||||
|
||||
if (i == EQUIPMENT_SLOT_RANGED)
|
||||
_ApplyAmmoBonuses();
|
||||
}
|
||||
@@ -7872,7 +7929,9 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type)
|
||||
// And permit out of range GO with no owner in case fishing hole
|
||||
if (!go || (loot_type != LOOT_FISHINGHOLE && ((loot_type != LOOT_FISHING && loot_type != LOOT_FISHING_JUNK) || go->GetOwnerGUID() != GetGUID()) && !go->IsWithinDistInMap(this)) || (loot_type == LOOT_CORPSE && go->GetRespawnTime() && go->isSpawnedByDefault()))
|
||||
{
|
||||
go->ForceValuesUpdateAtIndex(GAMEOBJECT_BYTES_1);
|
||||
if (go)
|
||||
go->ForceValuesUpdateAtIndex(GAMEOBJECT_BYTES_1);
|
||||
|
||||
SendLootRelease(guid);
|
||||
return;
|
||||
}
|
||||
@@ -12646,9 +12705,9 @@ void Player::RemoveItemDependentAurasAndCasts(Item* pItem)
|
||||
{
|
||||
Aura* aura = itr->second;
|
||||
|
||||
// skip passive (passive item dependent spells work in another way) and not self applied auras
|
||||
// skip not self applied auras
|
||||
SpellInfo const* spellInfo = aura->GetSpellInfo();
|
||||
if (aura->IsPassive() || aura->GetCasterGUID() != GetGUID())
|
||||
if (aura->GetCasterGUID() != GetGUID())
|
||||
{
|
||||
++itr;
|
||||
continue;
|
||||
|
||||
@@ -1325,7 +1325,7 @@ public:
|
||||
{
|
||||
return StoreItem(dest, pItem, update);
|
||||
}
|
||||
void RemoveItem(uint8 bag, uint8 slot, bool update, bool swap = false);
|
||||
void RemoveItem(uint8 bag, uint8 slot, bool update);
|
||||
void MoveItemFromInventory(uint8 bag, uint8 slot, bool update);
|
||||
// in trade, auction, guild bank, mail....
|
||||
void MoveItemToInventory(ItemPosCountVec const& dest, Item* pItem, bool update, bool in_characterInventoryDB = false);
|
||||
@@ -2181,11 +2181,19 @@ public:
|
||||
[[nodiscard]] bool CanTameExoticPets() const { return IsGameMaster() || HasAuraType(SPELL_AURA_ALLOW_TAME_PET_TYPE); }
|
||||
|
||||
void SetRegularAttackTime();
|
||||
void SetBaseModValue(BaseModGroup modGroup, BaseModType modType, float value) { m_auraBaseMod[modGroup][modType] = value; }
|
||||
void HandleBaseModValue(BaseModGroup modGroup, BaseModType modType, float amount, bool apply);
|
||||
|
||||
void HandleBaseModFlatValue(BaseModGroup modGroup, float amount, bool apply);
|
||||
void ApplyBaseModPctValue(BaseModGroup modGroup, float pct);
|
||||
|
||||
void SetBaseModFlatValue(BaseModGroup modGroup, float val);
|
||||
void SetBaseModPctValue(BaseModGroup modGroup, float val);
|
||||
|
||||
void UpdateDamageDoneMods(WeaponAttackType attackType, int32 skipEnchantSlot = -1) override;
|
||||
void UpdateBaseModGroup(BaseModGroup modGroup);
|
||||
|
||||
[[nodiscard]] float GetBaseModValue(BaseModGroup modGroup, BaseModType modType) const;
|
||||
[[nodiscard]] float GetTotalBaseModValue(BaseModGroup modGroup) const;
|
||||
[[nodiscard]] float GetTotalPercentageModValue(BaseModGroup modGroup) const { return m_auraBaseMod[modGroup][FLAT_MOD] + m_auraBaseMod[modGroup][PCT_MOD]; }
|
||||
|
||||
void _ApplyAllStatBonuses();
|
||||
void _RemoveAllStatBonuses();
|
||||
|
||||
@@ -2197,9 +2205,13 @@ public:
|
||||
|
||||
SpellSchoolMask GetMeleeDamageSchoolMask(WeaponAttackType attackType = BASE_ATTACK, uint8 damageIndex = 0) const override;
|
||||
|
||||
void _ApplyWeaponDependentAuraMods(Item* item, WeaponAttackType attackType, bool apply);
|
||||
void _ApplyWeaponDependentAuraCritMod(Item* item, WeaponAttackType attackType, AuraEffect const* aura, bool apply);
|
||||
void _ApplyWeaponDependentAuraDamageMod(Item* item, WeaponAttackType attackType, AuraEffect const* aura, bool apply);
|
||||
void UpdateWeaponDependentAuras(WeaponAttackType attackType);
|
||||
void ApplyItemDependentAuras(Item* item, bool apply);
|
||||
|
||||
bool CheckAttackFitToAuraRequirement(WeaponAttackType attackType, AuraEffect const* aurEff) const override;
|
||||
|
||||
void UpdateWeaponDependentCritAuras(WeaponAttackType attackType);
|
||||
void UpdateAllWeaponDependentCritAuras();
|
||||
|
||||
void _ApplyItemMods(Item* item, uint8 slot, bool apply);
|
||||
void _RemoveAllItemMods();
|
||||
@@ -2825,7 +2837,8 @@ protected:
|
||||
|
||||
ActionButtonList m_actionButtons;
|
||||
|
||||
float m_auraBaseMod[BASEMOD_END][MOD_END];
|
||||
float m_auraBaseFlatMod[BASEMOD_END];
|
||||
float m_auraBasePctMod[BASEMOD_END];
|
||||
int32 m_baseRatingValue[MAX_COMBAT_RATING];
|
||||
uint32 m_baseSpellPower;
|
||||
uint32 m_baseSpellDamage;
|
||||
|
||||
@@ -1405,9 +1405,7 @@ uint32 Player::CalculateQuestRewardXP(Quest const* quest)
|
||||
uint32 xp = uint32(quest->XPValue(GetLevel()) * GetQuestRate(quest->IsDFQuest()));
|
||||
|
||||
// handle SPELL_AURA_MOD_XP_QUEST_PCT auras
|
||||
Unit::AuraEffectList const& ModXPPctAuras = GetAuraEffectsByType(SPELL_AURA_MOD_XP_QUEST_PCT);
|
||||
for (Unit::AuraEffectList::const_iterator i = ModXPPctAuras.begin(); i != ModXPPctAuras.end(); ++i)
|
||||
AddPct(xp, (*i)->GetAmount());
|
||||
xp *= GetTotalAuraMultiplier(SPELL_AURA_MOD_XP_QUEST_PCT);
|
||||
|
||||
return xp;
|
||||
}
|
||||
|
||||
@@ -60,6 +60,7 @@
|
||||
#include "StringConvert.h"
|
||||
#include "Tokenize.h"
|
||||
#include "Transport.h"
|
||||
#include "Unit.h"
|
||||
#include "UpdateFieldFlags.h"
|
||||
#include "Util.h"
|
||||
#include "World.h"
|
||||
@@ -2921,7 +2922,7 @@ void Player::VisualizeItem(uint8 slot, Item* pItem)
|
||||
pItem->SetState(ITEM_CHANGED, this);
|
||||
}
|
||||
|
||||
void Player::RemoveItem(uint8 bag, uint8 slot, bool update, bool swap)
|
||||
void Player::RemoveItem(uint8 bag, uint8 slot, bool update)
|
||||
{
|
||||
// note: removeitem does not actually change the item
|
||||
// it only takes the item out of storage temporarily
|
||||
@@ -2956,12 +2957,6 @@ void Player::RemoveItem(uint8 bag, uint8 slot, bool update, bool swap)
|
||||
// remove item dependent auras and casts (only weapon and armor slots)
|
||||
if (slot < INVENTORY_SLOT_BAG_END && slot < EQUIPMENT_SLOT_END)
|
||||
{
|
||||
// Xinef: Ensure that this function is called for places with swap=true
|
||||
if (!swap)
|
||||
{
|
||||
RemoveItemDependentAurasAndCasts(pItem);
|
||||
}
|
||||
|
||||
// remove held enchantments, update expertise
|
||||
if (slot == EQUIPMENT_SLOT_MAINHAND)
|
||||
{
|
||||
@@ -3096,9 +3091,6 @@ void Player::DestroyItem(uint8 bag, uint8 slot, bool update)
|
||||
|
||||
if (slot < EQUIPMENT_SLOT_END)
|
||||
{
|
||||
// remove item dependent auras and casts (only weapon and armor slots)
|
||||
RemoveItemDependentAurasAndCasts(pItem);
|
||||
|
||||
// update expertise and armor penetration - passive auras may need it
|
||||
switch (slot)
|
||||
{
|
||||
@@ -3890,8 +3882,8 @@ void Player::SwapItem(uint16 src, uint16 dst)
|
||||
}
|
||||
|
||||
// now do moves, remove...
|
||||
RemoveItem(dstbag, dstslot, false, true);
|
||||
RemoveItem(srcbag, srcslot, false, true);
|
||||
RemoveItem(dstbag, dstslot, false);
|
||||
RemoveItem(srcbag, srcslot, false);
|
||||
|
||||
// add to dest
|
||||
if (IsInventoryPos(dst))
|
||||
@@ -4380,13 +4372,12 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool
|
||||
// processed in Player::CastItemCombatSpell
|
||||
break;
|
||||
case ITEM_ENCHANTMENT_TYPE_DAMAGE:
|
||||
if (item->GetSlot() == EQUIPMENT_SLOT_MAINHAND)
|
||||
HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_VALUE, float(enchant_amount), apply);
|
||||
else if (item->GetSlot() == EQUIPMENT_SLOT_OFFHAND)
|
||||
HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_VALUE, float(enchant_amount), apply);
|
||||
else if (item->GetSlot() == EQUIPMENT_SLOT_RANGED)
|
||||
HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_VALUE, float(enchant_amount), apply);
|
||||
{
|
||||
WeaponAttackType const attackType = Player::GetAttackBySlot(item->GetSlot());
|
||||
if (attackType != MAX_ATTACK)
|
||||
UpdateDamageDoneMods(attackType, apply ? -1 : slot);
|
||||
break;
|
||||
}
|
||||
case ITEM_ENCHANTMENT_TYPE_EQUIP_SPELL:
|
||||
if (enchant_spell_id)
|
||||
{
|
||||
@@ -4437,7 +4428,7 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool
|
||||
}
|
||||
}
|
||||
|
||||
HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + enchant_spell_id), TOTAL_VALUE, float(enchant_amount), apply);
|
||||
HandleStatFlatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + enchant_spell_id), TOTAL_VALUE, float(enchant_amount), apply);
|
||||
break;
|
||||
case ITEM_ENCHANTMENT_TYPE_STAT:
|
||||
{
|
||||
@@ -4464,36 +4455,36 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool
|
||||
{
|
||||
case ITEM_MOD_MANA:
|
||||
LOG_DEBUG("entities.player.items", "+ {} MANA", enchant_amount);
|
||||
HandleStatModifier(UNIT_MOD_MANA, BASE_VALUE, float(enchant_amount), apply);
|
||||
HandleStatFlatModifier(UNIT_MOD_MANA, BASE_VALUE, float(enchant_amount), apply);
|
||||
break;
|
||||
case ITEM_MOD_HEALTH:
|
||||
LOG_DEBUG("entities.player.items", "+ {} HEALTH", enchant_amount);
|
||||
HandleStatModifier(UNIT_MOD_HEALTH, BASE_VALUE, float(enchant_amount), apply);
|
||||
HandleStatFlatModifier(UNIT_MOD_HEALTH, BASE_VALUE, float(enchant_amount), apply);
|
||||
break;
|
||||
case ITEM_MOD_AGILITY:
|
||||
LOG_DEBUG("entities.player.items", "+ {} AGILITY", enchant_amount);
|
||||
HandleStatModifier(UNIT_MOD_STAT_AGILITY, TOTAL_VALUE, float(enchant_amount), apply);
|
||||
ApplyStatBuffMod(STAT_AGILITY, (float)enchant_amount, apply);
|
||||
HandleStatFlatModifier(UNIT_MOD_STAT_AGILITY, TOTAL_VALUE, float(enchant_amount), apply);
|
||||
UpdateStatBuffMod(STAT_AGILITY);
|
||||
break;
|
||||
case ITEM_MOD_STRENGTH:
|
||||
LOG_DEBUG("entities.player.items", "+ {} STRENGTH", enchant_amount);
|
||||
HandleStatModifier(UNIT_MOD_STAT_STRENGTH, TOTAL_VALUE, float(enchant_amount), apply);
|
||||
ApplyStatBuffMod(STAT_STRENGTH, (float)enchant_amount, apply);
|
||||
HandleStatFlatModifier(UNIT_MOD_STAT_STRENGTH, TOTAL_VALUE, float(enchant_amount), apply);
|
||||
UpdateStatBuffMod(STAT_STRENGTH);
|
||||
break;
|
||||
case ITEM_MOD_INTELLECT:
|
||||
LOG_DEBUG("entities.player.items", "+ {} INTELLECT", enchant_amount);
|
||||
HandleStatModifier(UNIT_MOD_STAT_INTELLECT, TOTAL_VALUE, float(enchant_amount), apply);
|
||||
ApplyStatBuffMod(STAT_INTELLECT, (float)enchant_amount, apply);
|
||||
HandleStatFlatModifier(UNIT_MOD_STAT_INTELLECT, TOTAL_VALUE, float(enchant_amount), apply);
|
||||
UpdateStatBuffMod(STAT_INTELLECT);
|
||||
break;
|
||||
case ITEM_MOD_SPIRIT:
|
||||
LOG_DEBUG("entities.player.items", "+ {} SPIRIT", enchant_amount);
|
||||
HandleStatModifier(UNIT_MOD_STAT_SPIRIT, TOTAL_VALUE, float(enchant_amount), apply);
|
||||
ApplyStatBuffMod(STAT_SPIRIT, (float)enchant_amount, apply);
|
||||
HandleStatFlatModifier(UNIT_MOD_STAT_SPIRIT, TOTAL_VALUE, float(enchant_amount), apply);
|
||||
UpdateStatBuffMod(STAT_SPIRIT);
|
||||
break;
|
||||
case ITEM_MOD_STAMINA:
|
||||
LOG_DEBUG("entities.player.items", "+ {} STAMINA", enchant_amount);
|
||||
HandleStatModifier(UNIT_MOD_STAT_STAMINA, TOTAL_VALUE, float(enchant_amount), apply);
|
||||
ApplyStatBuffMod(STAT_STAMINA, (float)enchant_amount, apply);
|
||||
HandleStatFlatModifier(UNIT_MOD_STAT_STAMINA, TOTAL_VALUE, float(enchant_amount), apply);
|
||||
UpdateStatBuffMod(STAT_STAMINA);
|
||||
break;
|
||||
case ITEM_MOD_DEFENSE_SKILL_RATING:
|
||||
ApplyRatingMod(CR_DEFENSE_SKILL, enchant_amount, apply);
|
||||
@@ -4604,12 +4595,12 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool
|
||||
LOG_DEBUG("entities.player.items", "+ {} EXPERTISE", enchant_amount);
|
||||
break;
|
||||
case ITEM_MOD_ATTACK_POWER:
|
||||
HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(enchant_amount), apply);
|
||||
HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(enchant_amount), apply);
|
||||
HandleStatFlatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(enchant_amount), apply);
|
||||
HandleStatFlatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(enchant_amount), apply);
|
||||
LOG_DEBUG("entities.player.items", "+ {} ATTACK_POWER", enchant_amount);
|
||||
break;
|
||||
case ITEM_MOD_RANGED_ATTACK_POWER:
|
||||
HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(enchant_amount), apply);
|
||||
HandleStatFlatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(enchant_amount), apply);
|
||||
LOG_DEBUG("entities.player.items", "+ {} RANGED_ATTACK_POWER", enchant_amount);
|
||||
break;
|
||||
// case ITEM_MOD_FERAL_ATTACK_POWER:
|
||||
@@ -4637,7 +4628,7 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool
|
||||
LOG_DEBUG("entities.player.items", "+ {} SPELL_PENETRATION", enchant_amount);
|
||||
break;
|
||||
case ITEM_MOD_BLOCK_VALUE:
|
||||
HandleBaseModValue(SHIELD_BLOCK_VALUE, FLAT_MOD, float(enchant_amount), apply);
|
||||
HandleBaseModFlatValue(SHIELD_BLOCK_VALUE, float(enchant_amount), apply);
|
||||
LOG_DEBUG("entities.player.items", "+ {} BLOCK_VALUE", enchant_amount);
|
||||
break;
|
||||
/// @deprecated item mods
|
||||
@@ -4656,20 +4647,9 @@ void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool
|
||||
}
|
||||
case ITEM_ENCHANTMENT_TYPE_TOTEM: // Shaman Rockbiter Weapon
|
||||
{
|
||||
if (IsClass(CLASS_SHAMAN, CLASS_CONTEXT_ABILITY))
|
||||
{
|
||||
float addValue = 0.0f;
|
||||
if (item->GetSlot() == EQUIPMENT_SLOT_MAINHAND)
|
||||
{
|
||||
addValue = float(enchant_amount * item->GetTemplate()->Delay / 1000.0f);
|
||||
HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_VALUE, addValue, apply);
|
||||
}
|
||||
else if (item->GetSlot() == EQUIPMENT_SLOT_OFFHAND)
|
||||
{
|
||||
addValue = float(enchant_amount * item->GetTemplate()->Delay / 1000.0f);
|
||||
HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_VALUE, addValue, apply);
|
||||
}
|
||||
}
|
||||
WeaponAttackType const attackType = Player::GetAttackBySlot(item->GetSlot());
|
||||
if (attackType != MAX_ATTACK)
|
||||
UpdateDamageDoneMods(attackType);
|
||||
break;
|
||||
}
|
||||
case ITEM_ENCHANTMENT_TYPE_USE_SPELL:
|
||||
@@ -6333,7 +6313,7 @@ void Player::_LoadQuestStatus(PreparedQueryResult result)
|
||||
++slot;
|
||||
}
|
||||
|
||||
LOG_DEBUG("entities.player.loading", "Quest status is {{}} for quest {{}} for player ({})", questStatusData.Status, quest_id, GetGUID().ToString());
|
||||
LOG_DEBUG("entities.player.loading", "Quest status is ({}) for quest ({}) for player ({})", questStatusData.Status, quest_id, GetGUID().ToString());
|
||||
}
|
||||
} while (result->NextRow());
|
||||
}
|
||||
@@ -6444,7 +6424,7 @@ void Player::_LoadWeeklyQuestStatus(PreparedQueryResult result)
|
||||
continue;
|
||||
|
||||
m_weeklyquests.insert(quest_id);
|
||||
LOG_DEBUG("entities.player.loading", "Weekly quest {{}} cooldown for player ({})", quest_id, GetGUID().ToString());
|
||||
LOG_DEBUG("entities.player.loading", "Weekly quest ({}) cooldown for player ({})", quest_id, GetGUID().ToString());
|
||||
} while (result->NextRow());
|
||||
}
|
||||
|
||||
@@ -6467,7 +6447,7 @@ void Player::_LoadSeasonalQuestStatus(PreparedQueryResult result)
|
||||
continue;
|
||||
|
||||
m_seasonalquests[event_id].insert(quest_id);
|
||||
LOG_DEBUG("entities.player.loading", "Seasonal quest {{}} cooldown for player ({})", quest_id, GetGUID().ToString());
|
||||
LOG_DEBUG("entities.player.loading", "Seasonal quest ({}) cooldown for player ({})", quest_id, GetGUID().ToString());
|
||||
} while (result->NextRow());
|
||||
}
|
||||
|
||||
@@ -6489,7 +6469,7 @@ void Player::_LoadMonthlyQuestStatus(PreparedQueryResult result)
|
||||
continue;
|
||||
|
||||
m_monthlyquests.insert(quest_id);
|
||||
LOG_DEBUG("entities.player.loading", "Monthly quest {{}} cooldown for player ({})", quest_id, GetGUID().ToString());
|
||||
LOG_DEBUG("entities.player.loading", "Monthly quest ({}) cooldown for player ({})", quest_id, GetGUID().ToString());
|
||||
} while (result->NextRow());
|
||||
}
|
||||
|
||||
|
||||
@@ -702,7 +702,7 @@ void Player::UpdateRating(CombatRating cr)
|
||||
|
||||
void Player::UpdateAllRatings()
|
||||
{
|
||||
for (int cr = 0; cr < MAX_COMBAT_RATING; ++cr)
|
||||
for (uint8 cr = 0; cr < MAX_COMBAT_RATING; ++cr)
|
||||
UpdateRating(CombatRating(cr));
|
||||
}
|
||||
|
||||
|
||||
@@ -157,7 +157,7 @@ bool Player::UpdateStats(Stats stat)
|
||||
mask |= (*i)->GetMiscValue();
|
||||
if (mask)
|
||||
{
|
||||
for (uint32 rating = 0; rating < MAX_COMBAT_RATING; ++rating)
|
||||
for (uint8 rating = 0; rating < MAX_COMBAT_RATING; ++rating)
|
||||
if (mask & (1 << rating))
|
||||
ApplyRatingMod(CombatRating(rating), 0, true);
|
||||
}
|
||||
@@ -204,7 +204,7 @@ void Player::UpdateSpellDamageAndHealingBonus()
|
||||
|
||||
bool Player::UpdateAllStats()
|
||||
{
|
||||
for (int8 i = STAT_STRENGTH; i < MAX_STATS; ++i)
|
||||
for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i)
|
||||
{
|
||||
float value = GetTotalStatValue(Stats(i));
|
||||
SetStat(Stats(i), int32(value));
|
||||
@@ -247,9 +247,9 @@ void Player::UpdateResistances(uint32 school)
|
||||
float value = 0.0f;
|
||||
UnitMods unitMod = UnitMods(UNIT_MOD_RESISTANCE_START + school);
|
||||
|
||||
value = GetModifierValue(unitMod, BASE_VALUE);
|
||||
value *= GetModifierValue(unitMod, BASE_PCT);
|
||||
value += GetModifierValue(unitMod, TOTAL_VALUE);
|
||||
value = GetFlatModifierValue(unitMod, BASE_VALUE);
|
||||
value *= GetPctModifierValue(unitMod, BASE_PCT);
|
||||
value += GetFlatModifierValue(unitMod, TOTAL_VALUE);
|
||||
|
||||
AuraEffectList const& mResbyIntellect = GetAuraEffectsByType(SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT);
|
||||
for(AuraEffectList::const_iterator i = mResbyIntellect.begin(); i != mResbyIntellect.end(); ++i)
|
||||
@@ -258,7 +258,7 @@ void Player::UpdateResistances(uint32 school)
|
||||
value += int32(GetStat(Stats((*i)->GetMiscValueB())) * (*i)->GetAmount() / 100.0f);
|
||||
}
|
||||
|
||||
value *= GetModifierValue(unitMod, TOTAL_PCT);
|
||||
value *= GetPctModifierValue(unitMod, TOTAL_PCT);
|
||||
|
||||
SetResistance(SpellSchools(school), int32(value));
|
||||
}
|
||||
@@ -270,10 +270,10 @@ void Player::UpdateArmor()
|
||||
{
|
||||
UnitMods unitMod = UNIT_MOD_ARMOR;
|
||||
|
||||
float value = GetModifierValue(unitMod, BASE_VALUE); // base armor (from items)
|
||||
value *= GetModifierValue(unitMod, BASE_PCT); // armor percent from items
|
||||
value += GetStat(STAT_AGILITY) * 2.0f; // armor bonus from stats
|
||||
value += GetModifierValue(unitMod, TOTAL_VALUE);
|
||||
float value = GetFlatModifierValue(unitMod, BASE_VALUE); // base armor (from items)
|
||||
value *= GetPctModifierValue(unitMod, BASE_PCT); // armor percent from items
|
||||
value += GetStat(STAT_AGILITY) * 2.0f; // armor bonus from stats
|
||||
value += GetFlatModifierValue(unitMod, TOTAL_VALUE);
|
||||
|
||||
//add dynamic flat mods
|
||||
AuraEffectList const& mResbyIntellect = GetAuraEffectsByType(SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT);
|
||||
@@ -283,7 +283,7 @@ void Player::UpdateArmor()
|
||||
value += CalculatePct(GetStat(Stats((*i)->GetMiscValueB())), (*i)->GetAmount());
|
||||
}
|
||||
|
||||
value *= GetModifierValue(unitMod, TOTAL_PCT);
|
||||
value *= GetPctModifierValue(unitMod, TOTAL_PCT);
|
||||
|
||||
SetArmor(int32(value));
|
||||
|
||||
@@ -314,10 +314,10 @@ void Player::UpdateMaxHealth()
|
||||
{
|
||||
UnitMods unitMod = UNIT_MOD_HEALTH;
|
||||
|
||||
float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreateHealth();
|
||||
value *= GetModifierValue(unitMod, BASE_PCT);
|
||||
value += GetModifierValue(unitMod, TOTAL_VALUE) + GetHealthBonusFromStamina();
|
||||
value *= GetModifierValue(unitMod, TOTAL_PCT);
|
||||
float value = GetFlatModifierValue(unitMod, BASE_VALUE) + GetCreateHealth();
|
||||
value *= GetPctModifierValue(unitMod, BASE_PCT);
|
||||
value += GetFlatModifierValue(unitMod, TOTAL_VALUE) + GetHealthBonusFromStamina();
|
||||
value *= GetPctModifierValue(unitMod, TOTAL_PCT);
|
||||
|
||||
sScriptMgr->OnPlayerAfterUpdateMaxHealth(this, value);
|
||||
SetMaxHealth((uint32)value);
|
||||
@@ -329,10 +329,10 @@ void Player::UpdateMaxPower(Powers power)
|
||||
|
||||
float bonusPower = (power == POWER_MANA && GetCreatePowers(power) > 0) ? GetManaBonusFromIntellect() : 0;
|
||||
|
||||
float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreatePowers(power);
|
||||
value *= GetModifierValue(unitMod, BASE_PCT);
|
||||
value += GetModifierValue(unitMod, TOTAL_VALUE) + bonusPower;
|
||||
value *= GetModifierValue(unitMod, TOTAL_PCT);
|
||||
float value = GetFlatModifierValue(unitMod, BASE_VALUE) + GetCreatePowers(power);
|
||||
value *= GetPctModifierValue(unitMod, BASE_PCT);
|
||||
value += GetFlatModifierValue(unitMod, TOTAL_VALUE) + bonusPower;
|
||||
value *= GetPctModifierValue(unitMod, TOTAL_PCT);
|
||||
|
||||
sScriptMgr->OnPlayerAfterUpdateMaxPower(this, power, value);
|
||||
SetMaxPower(power, uint32(value));
|
||||
@@ -487,10 +487,10 @@ void Player::UpdateAttackPowerAndDamage(bool ranged)
|
||||
}
|
||||
}
|
||||
|
||||
SetModifierValue(unitMod, BASE_VALUE, val2);
|
||||
SetStatFlatModifier(unitMod, BASE_VALUE, val2);
|
||||
|
||||
float base_attPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT);
|
||||
float attPowerMod = GetModifierValue(unitMod, TOTAL_VALUE);
|
||||
float base_attPower = GetFlatModifierValue(unitMod, BASE_VALUE) * GetPctModifierValue(unitMod, BASE_PCT);
|
||||
float attPowerMod = GetFlatModifierValue(unitMod, TOTAL_VALUE);
|
||||
|
||||
//add dynamic flat mods
|
||||
if (ranged)
|
||||
@@ -514,7 +514,7 @@ void Player::UpdateAttackPowerAndDamage(bool ranged)
|
||||
attPowerMod += int32(GetArmor() / (*iter)->GetAmount());
|
||||
}
|
||||
|
||||
float attPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f;
|
||||
float attPowerMultiplier = GetPctModifierValue(unitMod, TOTAL_PCT) - 1.0f;
|
||||
|
||||
sScriptMgr->OnPlayerAfterUpdateAttackPowerAndDamage(this, level, base_attPower, attPowerMod, attPowerMultiplier, ranged);
|
||||
SetInt32Value(index, (uint32)base_attPower); //UNIT_FIELD_(RANGED)_ATTACK_POWER field
|
||||
@@ -576,10 +576,10 @@ void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bo
|
||||
|
||||
float attackSpeedMod = GetAPMultiplier(attType, normalized);
|
||||
|
||||
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 baseValue = GetFlatModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType) / 14.0f * attackSpeedMod;
|
||||
float basePct = GetPctModifierValue(unitMod, BASE_PCT);
|
||||
float totalValue = GetFlatModifierValue(unitMod, TOTAL_VALUE);
|
||||
float totalPct = addTotalPct ? GetPctModifierValue(unitMod, TOTAL_PCT) : 1.0f;
|
||||
|
||||
float weaponMinDamage = GetWeaponDamageRange(attType, MINDAMAGE);
|
||||
float weaponMaxDamage = GetWeaponDamageRange(attType, MAXDAMAGE);
|
||||
@@ -681,7 +681,8 @@ void Player::UpdateCritPercentage(WeaponAttackType attType)
|
||||
break;
|
||||
}
|
||||
|
||||
float value = GetTotalPercentageModValue(modGroup) + GetRatingBonusValue(cr);
|
||||
// flat = bonus from crit auras, pct = bonus from agility, combat rating = mods from items
|
||||
float value = GetBaseModValue(modGroup, FLAT_MOD) + GetBaseModValue(modGroup, PCT_MOD) + GetRatingBonusValue(cr);
|
||||
// Modify crit from weapon skill and maximized defense skill of same level victim difference
|
||||
value += (int32(GetWeaponSkillValue(attType)) - int32(GetMaxSkillValueForLevel())) * 0.04f;
|
||||
|
||||
@@ -698,9 +699,9 @@ void Player::UpdateAllCritPercentages()
|
||||
{
|
||||
float value = GetMeleeCritFromAgility();
|
||||
|
||||
SetBaseModValue(CRIT_PERCENTAGE, PCT_MOD, value);
|
||||
SetBaseModValue(OFFHAND_CRIT_PERCENTAGE, PCT_MOD, value);
|
||||
SetBaseModValue(RANGED_CRIT_PERCENTAGE, PCT_MOD, value);
|
||||
SetBaseModPctValue(CRIT_PERCENTAGE, value);
|
||||
SetBaseModPctValue(OFFHAND_CRIT_PERCENTAGE, value);
|
||||
SetBaseModPctValue(RANGED_CRIT_PERCENTAGE, value);
|
||||
|
||||
UpdateCritPercentage(BASE_ATTACK);
|
||||
UpdateCritPercentage(OFF_ATTACK);
|
||||
@@ -849,7 +850,7 @@ void Player::UpdateSpellCritChance(uint32 school)
|
||||
// Crit from Intellect
|
||||
crit += GetSpellCritFromIntellect();
|
||||
// Increase crit from SPELL_AURA_MOD_SPELL_CRIT_CHANCE
|
||||
crit += GetTotalAuraModifierAreaExclusive(SPELL_AURA_MOD_SPELL_CRIT_CHANCE);
|
||||
crit += GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_CRIT_CHANCE);
|
||||
// Increase crit from SPELL_AURA_MOD_CRIT_PCT
|
||||
crit += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_PCT);
|
||||
// Increase crit by school from SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
|
||||
@@ -900,16 +901,11 @@ void Player::UpdateExpertise(WeaponAttackType attack)
|
||||
|
||||
Item* weapon = GetWeaponForAttack(attack, true);
|
||||
|
||||
AuraEffectList const& expAuras = GetAuraEffectsByType(SPELL_AURA_MOD_EXPERTISE);
|
||||
for (AuraEffectList::const_iterator itr = expAuras.begin(); itr != expAuras.end(); ++itr)
|
||||
expertise += GetTotalAuraModifier(SPELL_AURA_MOD_EXPERTISE, [weapon](AuraEffect const* aurEff)
|
||||
{
|
||||
// item neutral spell
|
||||
if ((*itr)->GetSpellInfo()->EquippedItemClass == -1)
|
||||
expertise += (*itr)->GetAmount();
|
||||
// item dependent spell
|
||||
else if (weapon && weapon->IsFitToSpellRequirements((*itr)->GetSpellInfo()))
|
||||
expertise += (*itr)->GetAmount();
|
||||
}
|
||||
return aurEff->GetSpellInfo()->EquippedItemClass == -1 || // item neutral spell
|
||||
(weapon && weapon->IsFitToSpellRequirements(aurEff->GetSpellInfo())); // item dependent spell
|
||||
});
|
||||
|
||||
if (expertise < 0)
|
||||
expertise = 0;
|
||||
@@ -1100,9 +1096,9 @@ void Creature::UpdateAttackPowerAndDamage(bool ranged)
|
||||
indexMulti = UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER;
|
||||
}
|
||||
|
||||
float baseAttackPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT);
|
||||
float attackPowerMod = GetModifierValue(unitMod, TOTAL_VALUE);
|
||||
float attackPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f;
|
||||
float baseAttackPower = GetFlatModifierValue(unitMod, BASE_VALUE) * GetPctModifierValue(unitMod, BASE_PCT);
|
||||
float attackPowerMod = GetFlatModifierValue(unitMod, TOTAL_VALUE);
|
||||
float attackPowerMultiplier = GetPctModifierValue(unitMod, TOTAL_PCT) - 1.0f;
|
||||
|
||||
SetInt32Value(index, uint32(baseAttackPower)); // UNIT_FIELD_(RANGED)_ATTACK_POWER
|
||||
SetInt32Value(indexMod, uint32(attackPowerMod)); // UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS
|
||||
@@ -1166,10 +1162,10 @@ void Creature::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized,
|
||||
|
||||
float attackPower = GetTotalAttackPowerValue(attType);
|
||||
float attackSpeedMulti = GetAPMultiplier(attType, normalized);
|
||||
float baseValue = GetModifierValue(unitMod, BASE_VALUE) + (attackPower / 14.0f) * variance;
|
||||
float basePct = GetModifierValue(unitMod, BASE_PCT) * attackSpeedMulti;
|
||||
float totalValue = GetModifierValue(unitMod, TOTAL_VALUE);
|
||||
float totalPct = addTotalPct ? GetModifierValue(unitMod, TOTAL_PCT) : 1.0f;
|
||||
float baseValue = GetFlatModifierValue(unitMod, BASE_VALUE) + (attackPower / 14.0f) * variance;
|
||||
float basePct = GetPctModifierValue(unitMod, BASE_PCT) * attackSpeedMulti;
|
||||
float totalValue = GetFlatModifierValue(unitMod, TOTAL_VALUE);
|
||||
float totalPct = addTotalPct ? GetPctModifierValue(unitMod, TOTAL_PCT) : 1.0f;
|
||||
float dmgMultiplier = GetCreatureTemplate()->DamageModifier; // = DamageModifier * _GetDamageMod(rank);
|
||||
|
||||
minDamage = ((weaponMinDamage + baseValue) * dmgMultiplier * basePct + totalValue) * totalPct;
|
||||
@@ -1233,11 +1229,11 @@ bool Guardian::UpdateAllStats()
|
||||
|
||||
void Guardian::UpdateArmor()
|
||||
{
|
||||
float value = GetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE);
|
||||
value *= GetModifierValue(UNIT_MOD_ARMOR, BASE_PCT);
|
||||
float value = GetFlatModifierValue(UNIT_MOD_ARMOR, BASE_VALUE);
|
||||
value *= GetPctModifierValue(UNIT_MOD_ARMOR, BASE_PCT);
|
||||
value += std::max<float>(GetStat(STAT_AGILITY) - GetCreateStat(STAT_AGILITY), 0.0f) * 2.0f;
|
||||
value += GetModifierValue(UNIT_MOD_ARMOR, TOTAL_VALUE);
|
||||
value *= GetModifierValue(UNIT_MOD_ARMOR, TOTAL_PCT);
|
||||
value += GetFlatModifierValue(UNIT_MOD_ARMOR, TOTAL_VALUE);
|
||||
value *= GetPctModifierValue(UNIT_MOD_ARMOR, TOTAL_PCT);
|
||||
SetArmor(int32(value));
|
||||
}
|
||||
|
||||
@@ -1278,10 +1274,10 @@ void Guardian::UpdateMaxHealth()
|
||||
break;
|
||||
}
|
||||
|
||||
float value = GetModifierValue(unitMod, BASE_VALUE);// xinef: Do NOT add base health TWICE + GetCreateHealth();
|
||||
value *= GetModifierValue(unitMod, BASE_PCT);
|
||||
value += GetModifierValue(unitMod, TOTAL_VALUE) + stamina * multiplicator;
|
||||
value *= GetModifierValue(unitMod, TOTAL_PCT);
|
||||
float value = GetFlatModifierValue(unitMod, BASE_VALUE);// xinef: Do NOT add base health TWICE + GetCreateHealth();
|
||||
value *= GetPctModifierValue(unitMod, BASE_PCT);
|
||||
value += GetFlatModifierValue(unitMod, TOTAL_VALUE) + stamina * multiplicator;
|
||||
value *= GetPctModifierValue(unitMod, TOTAL_PCT);
|
||||
|
||||
SetMaxHealth((uint32)value);
|
||||
}
|
||||
@@ -1311,11 +1307,11 @@ void Guardian::UpdateMaxPower(Powers power)
|
||||
break;
|
||||
}
|
||||
|
||||
// xinef: Do NOT add base mana TWICE
|
||||
float value = GetModifierValue(unitMod, BASE_VALUE) + (power != POWER_MANA ? GetCreatePowers(power) : 0);
|
||||
value *= GetModifierValue(unitMod, BASE_PCT);
|
||||
value += GetModifierValue(unitMod, TOTAL_VALUE) + addValue * multiplicator;
|
||||
value *= GetModifierValue(unitMod, TOTAL_PCT);
|
||||
// Do NOT add base mana TWICE
|
||||
float value = GetFlatModifierValue(unitMod, BASE_VALUE) + (power != POWER_MANA ? GetCreatePowers(power) : 0);
|
||||
value *= GetPctModifierValue(unitMod, BASE_PCT);
|
||||
value += GetFlatModifierValue(unitMod, TOTAL_VALUE) + addValue * multiplicator;
|
||||
value *= GetPctModifierValue(unitMod, TOTAL_PCT);
|
||||
|
||||
SetMaxPower(power, uint32(value));
|
||||
}
|
||||
@@ -1335,12 +1331,12 @@ void Guardian::UpdateAttackPowerAndDamage(bool ranged)
|
||||
else
|
||||
val = 2 * GetStat(STAT_STRENGTH) - 20.0f;
|
||||
|
||||
SetModifierValue(unitMod, BASE_VALUE, val);
|
||||
SetStatFlatModifier(unitMod, BASE_VALUE, val);
|
||||
|
||||
//in BASE_VALUE of UNIT_MOD_ATTACK_POWER for creatures we store data of meleeattackpower field in DB
|
||||
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 base_attPower = GetFlatModifierValue(unitMod, BASE_VALUE) * GetPctModifierValue(unitMod, BASE_PCT);
|
||||
float attPowerMod = GetFlatModifierValue(unitMod, TOTAL_VALUE);
|
||||
float attPowerMultiplier = GetPctModifierValue(unitMod, TOTAL_PCT) - 1.0f;
|
||||
|
||||
//UNIT_FIELD_(RANGED)_ATTACK_POWER field
|
||||
SetInt32Value(UNIT_FIELD_ATTACK_POWER, (int32)base_attPower);
|
||||
@@ -1362,10 +1358,10 @@ void Guardian::UpdateDamagePhysical(WeaponAttackType attType)
|
||||
|
||||
float att_speed = float(GetAttackTime(BASE_ATTACK)) / 1000.0f;
|
||||
|
||||
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 = GetModifierValue(unitMod, TOTAL_PCT);
|
||||
float base_value = GetFlatModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType) / 14.0f * att_speed;
|
||||
float base_pct = GetPctModifierValue(unitMod, BASE_PCT);
|
||||
float total_value = GetFlatModifierValue(unitMod, TOTAL_VALUE);
|
||||
float total_pct = GetPctModifierValue(unitMod, TOTAL_PCT);
|
||||
|
||||
float weapon_mindamage = GetWeaponDamageRange(BASE_ATTACK, MINDAMAGE);
|
||||
float weapon_maxdamage = GetWeaponDamageRange(BASE_ATTACK, MAXDAMAGE);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -123,13 +123,18 @@ enum HitInfo
|
||||
HITINFO_FAKE_DAMAGE = 0x01000000 // enables damage animation even if no damage done, set only if no damage
|
||||
};
|
||||
|
||||
enum UnitModifierType
|
||||
enum UnitModifierFlatType
|
||||
{
|
||||
BASE_VALUE = 0,
|
||||
BASE_PCT = 1,
|
||||
TOTAL_VALUE = 2,
|
||||
TOTAL_PCT = 3,
|
||||
MODIFIER_TYPE_END = 4
|
||||
TOTAL_VALUE = 1,
|
||||
MODIFIER_TYPE_FLAT_END = 3
|
||||
};
|
||||
|
||||
enum UnitModifierPctType
|
||||
{
|
||||
BASE_PCT = 0,
|
||||
TOTAL_PCT = 1,
|
||||
MODIFIER_TYPE_PCT_END = 2
|
||||
};
|
||||
|
||||
enum WeaponDamageRange
|
||||
@@ -214,7 +219,7 @@ enum WeaponAttackType : uint8
|
||||
MAX_ATTACK
|
||||
};
|
||||
|
||||
enum CombatRating
|
||||
enum CombatRating : uint8
|
||||
{
|
||||
CR_WEAPON_SKILL = 0,
|
||||
CR_DEFENSE_SKILL = 1,
|
||||
@@ -1050,16 +1055,32 @@ public:
|
||||
for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i) SetFloatValue(static_cast<uint16>(UNIT_FIELD_NEGSTAT0) + i, 0);
|
||||
}
|
||||
|
||||
bool HandleStatModifier(UnitMods unitMod, UnitModifierType modifierType, float amount, bool apply);
|
||||
void SetModifierValue(UnitMods unitMod, UnitModifierType modifierType, float value) { m_auraModifiersGroup[unitMod][modifierType] = value; }
|
||||
[[nodiscard]] float GetModifierValue(UnitMods unitMod, UnitModifierType modifierType) const;
|
||||
bool HandleStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float amount, bool apply);
|
||||
void ApplyStatPctModifier(UnitMods unitMod, UnitModifierPctType modifierType, float amount);
|
||||
|
||||
void SetStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float val);
|
||||
void SetStatPctModifier(UnitMods unitMod, UnitModifierPctType modifierType, float val);
|
||||
|
||||
[[nodiscard]] float GetFlatModifierValue(UnitMods unitMod, UnitModifierFlatType modifierType) const;
|
||||
[[nodiscard]] float GetPctModifierValue(UnitMods unitMod, UnitModifierPctType modifierType) const;
|
||||
|
||||
void UpdateUnitMod(UnitMods unitMod);
|
||||
|
||||
// only players have item requirements
|
||||
[[nodiscard]] virtual bool CheckAttackFitToAuraRequirement(WeaponAttackType /*attackType*/, AuraEffect const* /*aurEff*/) const { return true; }
|
||||
|
||||
virtual void UpdateDamageDoneMods(WeaponAttackType attackType, int32 skipEnchantSlot = -1);
|
||||
void UpdateAllDamageDoneMods();
|
||||
|
||||
void UpdateDamagePctDoneMods(WeaponAttackType attackType);
|
||||
void UpdateAllDamagePctDoneMods();
|
||||
|
||||
[[nodiscard]] float GetTotalStatValue(Stats stat, float additionalValue = 0.0f) const;
|
||||
|
||||
void SetCanModifyStats(bool modifyStats) { m_canModifyStats = modifyStats; }
|
||||
[[nodiscard]] bool CanModifyStats() const { return m_canModifyStats; }
|
||||
|
||||
void ApplyStatBuffMod(Stats stat, float val, bool apply) { ApplyModSignedFloatValue((val > 0 ? static_cast<uint16>(UNIT_FIELD_POSSTAT0) + stat : static_cast<uint16>(UNIT_FIELD_NEGSTAT0) + stat), val, apply); }
|
||||
void ApplyStatPercentBuffMod(Stats stat, float val, bool apply);
|
||||
void UpdateStatBuffMod(Stats stat);
|
||||
|
||||
// Unit level methods
|
||||
[[nodiscard]] uint8 GetLevel() const { return uint8(GetUInt32Value(UNIT_FIELD_LEVEL)); }
|
||||
@@ -1104,7 +1125,6 @@ public:
|
||||
void SetMaxPower(Powers power, uint32 val);
|
||||
|
||||
int32 ModifyPower(Powers power, int32 val, bool withPowerUpdate = true);
|
||||
int32 ModifyPowerPct(Powers power, float pct, bool apply = true);
|
||||
|
||||
void RewardRage(uint32 damage, uint32 weaponSpeedHitFactor, bool attacker);
|
||||
|
||||
@@ -1159,13 +1179,9 @@ public:
|
||||
[[nodiscard]] uint32 GetResistance(SpellSchoolMask mask) const;
|
||||
[[nodiscard]] uint32 GetResistance(SpellSchools school) const { return GetUInt32Value(static_cast<uint16>(UNIT_FIELD_RESISTANCES) + school); }
|
||||
static float GetEffectiveResistChance(Unit const* owner, SpellSchoolMask schoolMask, Unit const* victim);
|
||||
[[nodiscard]] float GetResistanceBuffMods(SpellSchools school, bool positive) const { return GetFloatValue(positive ? static_cast<uint16>(UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE) + school : static_cast<uint16>(UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE) + + school); }
|
||||
|
||||
void SetResistance(SpellSchools school, int32 val) { SetStatInt32Value(static_cast<uint16>(UNIT_FIELD_RESISTANCES) + school, val); }
|
||||
void SetResistanceBuffMods(SpellSchools school, bool positive, float val) { SetFloatValue(positive ? static_cast<uint16>(UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE) + school : static_cast<uint16>(UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE) + + school, val); }
|
||||
|
||||
void ApplyResistanceBuffModsMod(SpellSchools school, bool positive, float val, bool apply) { ApplyModSignedFloatValue(positive ? static_cast<uint16>(UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE) + school : static_cast<uint16>(UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE) + + school, val, apply); }
|
||||
void ApplyResistanceBuffModsPercentMod(SpellSchools school, bool positive, float val, bool apply) { ApplyPercentModFloatValue(positive ? static_cast<uint16>(UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE) + school : static_cast<uint16>(UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE) + + school, val, apply); }
|
||||
void UpdateResistanceBuffModsMod(SpellSchools school);
|
||||
|
||||
//////////// Need triage ////////////////
|
||||
uint16 GetMaxSkillValueForLevel(Unit const* target = nullptr) const { return (target ? getLevelForTarget(target) : GetLevel()) * 5; }
|
||||
@@ -1319,6 +1335,10 @@ public:
|
||||
|
||||
void SetAuraStack(uint32 spellId, Unit* target, uint32 stack);
|
||||
|
||||
int32 GetHighestExclusiveSameEffectSpellGroupValue(AuraEffect const* aurEff, AuraType auraType, bool checkMiscValue = false, int32 miscValue = 0) const;
|
||||
bool IsHighestExclusiveAura(Aura const* aura, bool removeOtherAuraApplications = false);
|
||||
bool IsHighestExclusiveAuraEffect(SpellInfo const* spellInfo, AuraType auraType, int32 effectAmount, uint8 auraEffectMask, bool removeOtherAuraApplications = false);
|
||||
|
||||
// aura apply/remove helpers - you should better not use these
|
||||
Aura* _TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8 effMask, Unit* caster, int32* baseAmount = nullptr, Item* castItem = nullptr, ObjectGuid casterGUID = ObjectGuid::Empty, bool periodicReset = false);
|
||||
void _AddAura(UnitAura* aura, Unit* caster);
|
||||
@@ -1328,7 +1348,7 @@ public:
|
||||
void _UnapplyAura(AuraApplicationMap::iterator& i, AuraRemoveMode removeMode);
|
||||
void _UnapplyAura(AuraApplication* aurApp, AuraRemoveMode removeMode);
|
||||
void _RemoveNoStackAuraApplicationsDueToAura(Aura* aura);
|
||||
void _RemoveNoStackAurasDueToAura(Aura* aura);
|
||||
void _RemoveNoStackAurasDueToAura(Aura* aura, bool owned);
|
||||
bool _IsNoStackAuraDueToAura(Aura* appliedAura, Aura* existingAura) const;
|
||||
void _RegisterAuraEffect(AuraEffect* aurEff, bool apply);
|
||||
|
||||
@@ -1474,15 +1494,19 @@ public:
|
||||
uint32 GetDiseasesByCaster(ObjectGuid casterGUID, uint8 mode = 0);
|
||||
[[nodiscard]] uint32 GetDoTsByCaster(ObjectGuid casterGUID) const;
|
||||
|
||||
[[nodiscard]] int32 GetTotalAuraModifierAreaExclusive(AuraType auratype) const;
|
||||
[[nodiscard]] int32 GetTotalAuraModifier(AuraType auratype) const;
|
||||
[[nodiscard]] float GetTotalAuraMultiplier(AuraType auratype) const;
|
||||
int32 GetMaxPositiveAuraModifier(AuraType auratype);
|
||||
[[nodiscard]] int32 GetMaxPositiveAuraModifier(AuraType auratype) const;
|
||||
[[nodiscard]] int32 GetMaxNegativeAuraModifier(AuraType auratype) const;
|
||||
|
||||
[[nodiscard]] int32 GetTotalAuraModifier(AuraType auratype, std::function<bool(AuraEffect const*)> const& predicate) const;
|
||||
[[nodiscard]] float GetTotalAuraMultiplier(AuraType auraType, std::function<bool(AuraEffect const*)> const& predicate) const;
|
||||
[[nodiscard]] int32 GetMaxPositiveAuraModifier(AuraType auraType, std::function<bool(AuraEffect const*)> const& predicate) const;
|
||||
[[nodiscard]] int32 GetMaxNegativeAuraModifier(AuraType auraType, std::function<bool(AuraEffect const*)> const& predicate) const;
|
||||
|
||||
[[nodiscard]] int32 GetTotalAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask) const;
|
||||
[[nodiscard]] float GetTotalAuraMultiplierByMiscMask(AuraType auratype, uint32 misc_mask) const;
|
||||
int32 GetMaxPositiveAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask, const AuraEffect* except = nullptr) const;
|
||||
[[nodiscard]] int32 GetMaxPositiveAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask, const AuraEffect* except = nullptr) const;
|
||||
[[nodiscard]] int32 GetMaxNegativeAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask) const;
|
||||
|
||||
[[nodiscard]] int32 GetTotalAuraModifierByMiscValue(AuraType auratype, int32 misc_value) const;
|
||||
@@ -1581,7 +1605,6 @@ public:
|
||||
int32 HealBySpell(HealInfo& healInfo, bool critical = false);
|
||||
|
||||
int32 SpellBaseHealingBonusDone(SpellSchoolMask schoolMask);
|
||||
int32 SpellBaseHealingBonusTaken(SpellSchoolMask schoolMask);
|
||||
float SpellPctHealingModsDone(Unit* victim, SpellInfo const* spellProto, DamageEffectType damagetype);
|
||||
uint32 SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, uint8 effIndex, float TotalMod = 0.0f, uint32 stack = 1);
|
||||
uint32 SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, uint32 stack = 1);
|
||||
@@ -2138,7 +2161,8 @@ protected:
|
||||
AuraStateAurasMap m_auraStateAuras; // Used for improve performance of aura state checks on aura apply/remove
|
||||
uint32 m_interruptMask;
|
||||
|
||||
float m_auraModifiersGroup[UNIT_MOD_END][MODIFIER_TYPE_END];
|
||||
float m_auraFlatModifiersGroup[UNIT_MOD_END][MODIFIER_TYPE_FLAT_END];
|
||||
float m_auraPctModifiersGroup[UNIT_MOD_END][MODIFIER_TYPE_PCT_END];
|
||||
float m_weaponDamage[MAX_ATTACK][MAX_WEAPON_DAMAGE_RANGE][MAX_ITEM_PROTO_DAMAGES];
|
||||
bool m_canModifyStats;
|
||||
VisibleAuraMap m_visibleAuras;
|
||||
|
||||
@@ -256,8 +256,8 @@ void WorldSession::HandleAutoEquipItemOpcode(WorldPackets::Item::AutoEquipItem&
|
||||
}
|
||||
|
||||
// now do moves, remove...
|
||||
_player->RemoveItem(dstbag, dstslot, true, true);
|
||||
_player->RemoveItem(packet.SourceBag, packet.SourceSlot, true, true);
|
||||
_player->RemoveItem(dstbag, dstslot, true);
|
||||
_player->RemoveItem(packet.SourceBag, packet.SourceSlot, true);
|
||||
|
||||
// add to dest
|
||||
_player->EquipItem(dest, pSrcItem, true);
|
||||
|
||||
@@ -299,6 +299,8 @@ void WorldSession::HandleMoveTeleportAck(WorldPacket& recvData)
|
||||
|
||||
plMover->UpdatePosition(dest, true);
|
||||
|
||||
plMover->SetFallInformation(GameTime::GetGameTime().count(), dest.GetPositionZ());
|
||||
|
||||
// xinef: teleport pets if they are not unsummoned
|
||||
if (Pet* pet = plMover->GetPet())
|
||||
{
|
||||
|
||||
@@ -24,16 +24,6 @@ void ScriptMgr::OnCalcMaxDuration(Aura const* aura, int32& maxDuration)
|
||||
CALL_ENABLED_HOOKS(AllSpellScript, ALLSPELLHOOK_ON_CALC_MAX_DURATION, script->OnCalcMaxDuration(aura, maxDuration));
|
||||
}
|
||||
|
||||
bool ScriptMgr::CanModAuraEffectDamageDone(AuraEffect const* auraEff, Unit* target, AuraApplication const* aurApp, uint8 mode, bool apply)
|
||||
{
|
||||
CALL_ENABLED_BOOLEAN_HOOKS(AllSpellScript, ALLSPELLHOOK_CAN_MOD_AURA_EFFECT_DAMAGE_DONE, !script->CanModAuraEffectDamageDone(auraEff, target, aurApp, mode, apply));
|
||||
}
|
||||
|
||||
bool ScriptMgr::CanModAuraEffectModDamagePercentDone(AuraEffect const* auraEff, Unit* target, AuraApplication const* aurApp, uint8 mode, bool apply)
|
||||
{
|
||||
CALL_ENABLED_BOOLEAN_HOOKS(AllSpellScript, ALLSPELLHOOK_CAN_MOD_AURA_EFFECT_MOD_DAMAGE_PERCENT_DONE, !script->CanModAuraEffectModDamagePercentDone(auraEff, target, aurApp, mode, apply));
|
||||
}
|
||||
|
||||
void ScriptMgr::OnSpellCheckCast(Spell* spell, bool strict, SpellCastResult& res)
|
||||
{
|
||||
CALL_ENABLED_HOOKS(AllSpellScript, ALLSPELLHOOK_ON_SPELL_CHECK_CAST, script->OnSpellCheckCast(spell, strict, res));
|
||||
|
||||
@@ -24,8 +24,6 @@
|
||||
enum AllSpellHook
|
||||
{
|
||||
ALLSPELLHOOK_ON_CALC_MAX_DURATION,
|
||||
ALLSPELLHOOK_CAN_MOD_AURA_EFFECT_DAMAGE_DONE,
|
||||
ALLSPELLHOOK_CAN_MOD_AURA_EFFECT_MOD_DAMAGE_PERCENT_DONE,
|
||||
ALLSPELLHOOK_ON_SPELL_CHECK_CAST,
|
||||
ALLSPELLHOOK_CAN_PREPARE,
|
||||
ALLSPELLHOOK_CAN_SCALING_EVERYTHING,
|
||||
@@ -56,10 +54,6 @@ public:
|
||||
// Calculate max duration in applying aura
|
||||
virtual void OnCalcMaxDuration(Aura const* /*aura*/, int32& /*maxDuration*/) { }
|
||||
|
||||
[[nodiscard]] virtual bool CanModAuraEffectDamageDone(AuraEffect const* /*auraEff*/, Unit* /*target*/, AuraApplication const* /*aurApp*/, uint8 /*mode*/, bool /*apply*/) { return true; }
|
||||
|
||||
[[nodiscard]] virtual bool CanModAuraEffectModDamagePercentDone(AuraEffect const* /*auraEff*/, Unit* /*target*/, AuraApplication const* /*aurApp*/, uint8 /*mode*/, bool /*apply*/) { return true; }
|
||||
|
||||
virtual void OnSpellCheckCast(Spell* /*spell*/, bool /*strict*/, SpellCastResult& /*res*/) { }
|
||||
|
||||
[[nodiscard]] virtual bool CanPrepare(Spell* /*spell*/, SpellCastTargets const* /*targets*/, AuraEffect const* /*triggeredByAura*/) { return true; }
|
||||
|
||||
@@ -84,21 +84,6 @@ bool ScriptMgr::IfNormalReaction(Unit const* unit, Unit const* target, Reputatio
|
||||
CALL_ENABLED_BOOLEAN_HOOKS(UnitScript, UNITHOOK_IF_NORMAL_REACTION, !script->IfNormalReaction(unit, target, repRank));
|
||||
}
|
||||
|
||||
bool ScriptMgr::IsNeedModSpellDamagePercent(Unit const* unit, AuraEffect* auraEff, float& doneTotalMod, SpellInfo const* spellProto)
|
||||
{
|
||||
CALL_ENABLED_BOOLEAN_HOOKS(UnitScript, UNITHOOK_IS_NEEDMOD_SPELL_DAMAGE_PERCENT, !script->IsNeedModSpellDamagePercent(unit, auraEff, doneTotalMod, spellProto));
|
||||
}
|
||||
|
||||
bool ScriptMgr::IsNeedModMeleeDamagePercent(Unit const* unit, AuraEffect* auraEff, float& doneTotalMod, SpellInfo const* spellProto)
|
||||
{
|
||||
CALL_ENABLED_BOOLEAN_HOOKS(UnitScript, UNITHOOK_IS_NEEDMOD_MELEE_DAMAGE_PERCENT, !script->IsNeedModMeleeDamagePercent(unit, auraEff, doneTotalMod, spellProto));
|
||||
}
|
||||
|
||||
bool ScriptMgr::IsNeedModHealPercent(Unit const* unit, AuraEffect* auraEff, float& doneTotalMod, SpellInfo const* spellProto)
|
||||
{
|
||||
CALL_ENABLED_BOOLEAN_HOOKS(UnitScript, UNITHOOK_IS_NEEDMOD_HEAL_PERCENT, !script->IsNeedModHealPercent(unit, auraEff, doneTotalMod, spellProto));
|
||||
}
|
||||
|
||||
bool ScriptMgr::CanSetPhaseMask(Unit const* unit, uint32 newPhaseMask, bool update)
|
||||
{
|
||||
CALL_ENABLED_BOOLEAN_HOOKS(UnitScript, UNITHOOK_CAN_SET_PHASE_MASK, !script->CanSetPhaseMask(unit, newPhaseMask, update));
|
||||
|
||||
@@ -33,9 +33,6 @@ enum UnitHook
|
||||
UNITHOOK_ON_AURA_APPLY,
|
||||
UNITHOOK_ON_AURA_REMOVE,
|
||||
UNITHOOK_IF_NORMAL_REACTION,
|
||||
UNITHOOK_IS_NEEDMOD_SPELL_DAMAGE_PERCENT,
|
||||
UNITHOOK_IS_NEEDMOD_MELEE_DAMAGE_PERCENT,
|
||||
UNITHOOK_IS_NEEDMOD_HEAL_PERCENT,
|
||||
UNITHOOK_CAN_SET_PHASE_MASK,
|
||||
UNITHOOK_IS_CUSTOM_BUILD_VALUES_UPDATE,
|
||||
UNITHOOK_SHOULD_TRACK_VALUES_UPDATE_POS_BY_INDEX,
|
||||
@@ -89,12 +86,6 @@ public:
|
||||
|
||||
[[nodiscard]] virtual bool IfNormalReaction(Unit const* /*unit*/, Unit const* /*target*/, ReputationRank& /*repRank*/) { return true; }
|
||||
|
||||
[[nodiscard]] virtual bool IsNeedModSpellDamagePercent(Unit const* /*unit*/, AuraEffect* /*auraEff*/, float& /*doneTotalMod*/, SpellInfo const* /*spellProto*/) { return true; }
|
||||
|
||||
[[nodiscard]] virtual bool IsNeedModMeleeDamagePercent(Unit const* /*unit*/, AuraEffect* /*auraEff*/, float& /*doneTotalMod*/, SpellInfo const* /*spellProto*/) { return true; }
|
||||
|
||||
[[nodiscard]] virtual bool IsNeedModHealPercent(Unit const* /*unit*/, AuraEffect* /*auraEff*/, float& /*doneTotalMod*/, SpellInfo const* /*spellProto*/) { return true; }
|
||||
|
||||
[[nodiscard]] virtual bool CanSetPhaseMask(Unit const* /*unit*/, uint32 /*newPhaseMask*/, bool /*update*/) { return true; }
|
||||
|
||||
[[nodiscard]] virtual bool IsCustomBuildValuesUpdate(Unit const* /*unit*/, uint8 /*updateType*/, ByteBuffer& /*fieldBuffer*/, Player const* /*target*/, uint16 /*index*/) { return false; }
|
||||
|
||||
@@ -572,9 +572,6 @@ public: /* UnitScript */
|
||||
void OnAuraApply(Unit* /*unit*/, Aura* /*aura*/);
|
||||
void OnAuraRemove(Unit* unit, AuraApplication* aurApp, AuraRemoveMode mode);
|
||||
bool IfNormalReaction(Unit const* unit, Unit const* target, ReputationRank& repRank);
|
||||
bool IsNeedModSpellDamagePercent(Unit const* unit, AuraEffect* auraEff, float& doneTotalMod, SpellInfo const* spellProto);
|
||||
bool IsNeedModMeleeDamagePercent(Unit const* unit, AuraEffect* auraEff, float& doneTotalMod, SpellInfo const* spellProto);
|
||||
bool IsNeedModHealPercent(Unit const* unit, AuraEffect* auraEff, float& doneTotalMod, SpellInfo const* spellProto);
|
||||
bool CanSetPhaseMask(Unit const* unit, uint32 newPhaseMask, bool update);
|
||||
bool IsCustomBuildValuesUpdate(Unit const* unit, uint8 updateType, ByteBuffer& fieldBuffer, Player const* target, uint16 index);
|
||||
bool ShouldTrackValuesUpdatePosByIndex(Unit const* unit, uint8 updateType, uint16 index);
|
||||
@@ -632,8 +629,6 @@ public: /* Arena Team Script */
|
||||
|
||||
public: /* SpellSC */
|
||||
void OnCalcMaxDuration(Aura const* aura, int32& maxDuration);
|
||||
bool CanModAuraEffectDamageDone(AuraEffect const* auraEff, Unit* target, AuraApplication const* aurApp, uint8 mode, bool apply);
|
||||
bool CanModAuraEffectModDamagePercentDone(AuraEffect const* auraEff, Unit* target, AuraApplication const* aurApp, uint8 mode, bool apply);
|
||||
void OnSpellCheckCast(Spell* spell, bool strict, SpellCastResult& res);
|
||||
bool CanPrepare(Spell* spell, SpellCastTargets const* targets, AuraEffect const* triggeredByAura);
|
||||
bool CanScalingEverything(Spell* spell);
|
||||
|
||||
@@ -125,7 +125,7 @@ WorldSession::WorldSession(uint32 id, std::string&& name, uint32 accountFlags, s
|
||||
m_playerLogout(false),
|
||||
m_playerRecentlyLogout(false),
|
||||
m_playerSave(false),
|
||||
m_sessionDbcLocale(sWorld->GetDefaultDbcLocale()),
|
||||
m_sessionDbcLocale(sWorld->GetAvailableDbcLocale(locale)),
|
||||
m_sessionDbLocaleIndex(locale),
|
||||
m_latency(0),
|
||||
m_TutorialsChanged(false),
|
||||
|
||||
@@ -212,7 +212,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS] =
|
||||
&AuraEffect::HandleModStateImmunityMask, //147 SPELL_AURA_MECHANIC_IMMUNITY_MASK
|
||||
&AuraEffect::HandleAuraRetainComboPoints, //148 SPELL_AURA_RETAIN_COMBO_POINTS
|
||||
&AuraEffect::HandleNoImmediateEffect, //149 SPELL_AURA_REDUCE_PUSHBACK
|
||||
&AuraEffect::HandleShieldBlockValue, //150 SPELL_AURA_MOD_SHIELD_BLOCKVALUE_PCT
|
||||
&AuraEffect::HandleShieldBlockValuePercent, //150 SPELL_AURA_MOD_SHIELD_BLOCKVALUE_PCT
|
||||
&AuraEffect::HandleAuraTrackStealthed, //151 SPELL_AURA_TRACK_STEALTHED
|
||||
&AuraEffect::HandleNoImmediateEffect, //152 SPELL_AURA_MOD_DETECTED_RANGE implemented in Creature::GetAggroRange
|
||||
&AuraEffect::HandleNoImmediateEffect, //153 SPELL_AURA_SPLIT_DAMAGE_FLAT
|
||||
@@ -393,7 +393,6 @@ AuraEffect::AuraEffect(Aura* base, uint8 effIndex, int32* baseAmount, Unit* cast
|
||||
m_amount = CalculateAmount(caster);
|
||||
m_casterLevel = caster ? caster->GetLevel() : 0;
|
||||
m_applyResilience = caster && caster->CanApplyResilience();
|
||||
m_auraGroup = sSpellMgr->GetSpellGroup(GetId());
|
||||
|
||||
CalculateSpellMod();
|
||||
|
||||
@@ -727,9 +726,12 @@ void AuraEffect::ChangeAmount(int32 newAmount, bool mark, bool onStackOrReapply)
|
||||
std::list<AuraApplication*> effectApplications;
|
||||
GetApplicationList(effectApplications);
|
||||
|
||||
for (std::list<AuraApplication*>::const_iterator apptItr = effectApplications.begin(); apptItr != effectApplications.end(); ++apptItr)
|
||||
if ((*apptItr)->HasEffect(GetEffIndex()))
|
||||
HandleEffect(*apptItr, handleMask, false);
|
||||
for (AuraApplication* aurApp : effectApplications)
|
||||
if (aurApp->HasEffect(GetEffIndex()))
|
||||
{
|
||||
aurApp->GetTarget()->_RegisterAuraEffect(this, false);
|
||||
HandleEffect(aurApp, handleMask, false);
|
||||
}
|
||||
|
||||
if (handleMask & AURA_EFFECT_HANDLE_CHANGE_AMOUNT)
|
||||
{
|
||||
@@ -740,9 +742,15 @@ void AuraEffect::ChangeAmount(int32 newAmount, bool mark, bool onStackOrReapply)
|
||||
CalculateSpellMod();
|
||||
}
|
||||
|
||||
for (std::list<AuraApplication*>::const_iterator apptItr = effectApplications.begin(); apptItr != effectApplications.end(); ++apptItr)
|
||||
if ((*apptItr)->HasEffect(GetEffIndex()))
|
||||
HandleEffect(*apptItr, handleMask, true);
|
||||
for (AuraApplication* aurApp : effectApplications)
|
||||
if (aurApp->HasEffect(GetEffIndex()))
|
||||
{
|
||||
if (aurApp->GetRemoveMode() != AURA_REMOVE_NONE)
|
||||
continue;
|
||||
|
||||
aurApp->GetTarget()->_RegisterAuraEffect(this, true);
|
||||
HandleEffect(aurApp, handleMask, true);
|
||||
}
|
||||
}
|
||||
|
||||
void AuraEffect::HandleEffect(AuraApplication* aurApp, uint8 mode, bool apply)
|
||||
@@ -3000,14 +3008,17 @@ void AuraEffect::HandleAuraModDisarm(AuraApplication const* aurApp, uint8 mode,
|
||||
// Handle damage modification, shapeshifted druids are not affected
|
||||
if (target->IsPlayer() && (!target->IsInFeralForm() || target->GetShapeshiftForm() == FORM_GHOSTWOLF))
|
||||
{
|
||||
if (Item* pItem = target->ToPlayer()->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
|
||||
Player* player = target->ToPlayer();
|
||||
if (Item* pItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
|
||||
{
|
||||
WeaponAttackType attacktype = Player::GetAttackBySlot(slot);
|
||||
WeaponAttackType attackType = Player::GetAttackBySlot(slot);
|
||||
|
||||
if (attacktype < MAX_ATTACK)
|
||||
player->ApplyItemDependentAuras(pItem, !apply);
|
||||
if (attackType < MAX_ATTACK)
|
||||
{
|
||||
target->ToPlayer()->_ApplyWeaponDamage(slot, pItem->GetTemplate(), nullptr, !apply);
|
||||
target->ToPlayer()->_ApplyWeaponDependentAuraMods(pItem, attacktype, !apply);
|
||||
player->_ApplyWeaponDamage(slot, pItem->GetTemplate(), nullptr, !apply);
|
||||
if (!apply) // apply case already handled on item dependent aura removal (if any)
|
||||
player->UpdateWeaponDependentAuras(attackType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3439,9 +3450,17 @@ void AuraEffect::HandleModThreat(AuraApplication const* aurApp, uint8 mode, bool
|
||||
return;
|
||||
|
||||
Unit* target = aurApp->GetTarget();
|
||||
for (int8 i = 0; i < MAX_SPELL_SCHOOL; ++i)
|
||||
for (uint8 i = 0; i < MAX_SPELL_SCHOOL; ++i)
|
||||
if (GetMiscValue() & (1 << i))
|
||||
ApplyPercentModFloatVar(target->m_threatModifier[i], float(GetAmount()), apply);
|
||||
{
|
||||
if (apply)
|
||||
AddPct(target->m_threatModifier[i], GetAmount());
|
||||
else
|
||||
{
|
||||
float amount = target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_THREAT, 1 << i);
|
||||
target->m_threatModifier[i] = amount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AuraEffect::HandleAuraModTotalThreat(AuraApplication const* aurApp, uint8 mode, bool apply) const
|
||||
@@ -4318,7 +4337,7 @@ void AuraEffect::HandleAuraModResistanceExclusive(AuraApplication const* aurApp,
|
||||
|
||||
Unit* target = aurApp->GetTarget();
|
||||
|
||||
for (int8 x = SPELL_SCHOOL_NORMAL; x < MAX_SPELL_SCHOOL; x++)
|
||||
for (uint8 x = SPELL_SCHOOL_NORMAL; x < MAX_SPELL_SCHOOL; x++)
|
||||
{
|
||||
if (GetMiscValue() & int32(1 << x))
|
||||
{
|
||||
@@ -4326,9 +4345,9 @@ void AuraEffect::HandleAuraModResistanceExclusive(AuraApplication const* aurApp,
|
||||
if (amount < GetAmount())
|
||||
{
|
||||
float value = float(GetAmount() - amount);
|
||||
target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), BASE_VALUE, value, apply);
|
||||
if (target->IsPlayer())
|
||||
target->ApplyResistanceBuffModsMod(SpellSchools(x), aurApp->IsPositive(), value, apply);
|
||||
target->HandleStatFlatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), BASE_VALUE, value, apply);
|
||||
if (target->IsPlayer() || target->IsPet())
|
||||
target->UpdateResistanceBuffModsMod(SpellSchools(x));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4345,9 +4364,9 @@ void AuraEffect::HandleAuraModResistance(AuraApplication const* aurApp, uint8 mo
|
||||
{
|
||||
if (GetMiscValue() & int32(1 << x))
|
||||
{
|
||||
target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), TOTAL_VALUE, float(GetAmount()), apply);
|
||||
target->HandleStatFlatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), TOTAL_VALUE, float(GetAmount()), apply);
|
||||
if (target->IsPlayer() || target->IsPet())
|
||||
target->ApplyResistanceBuffModsMod(SpellSchools(x), GetAmount() > 0, (float)GetAmount(), apply);
|
||||
target->UpdateResistanceBuffModsMod(SpellSchools(x));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4358,32 +4377,39 @@ void AuraEffect::HandleAuraModBaseResistancePCT(AuraApplication const* aurApp, u
|
||||
return;
|
||||
|
||||
Unit* target = aurApp->GetTarget();
|
||||
for (int8 x = SPELL_SCHOOL_NORMAL; x < MAX_SPELL_SCHOOL; x++)
|
||||
for (uint8 x = SPELL_SCHOOL_NORMAL; x < MAX_SPELL_SCHOOL; x++)
|
||||
{
|
||||
if (GetMiscValue() & int32(1 << x))
|
||||
{
|
||||
target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), BASE_PCT, float(GetAmount()), apply);
|
||||
if (apply)
|
||||
target->ApplyStatPctModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), BASE_PCT, float(GetAmount()));
|
||||
else
|
||||
{
|
||||
float amount = target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_BASE_RESISTANCE_PCT, 1 << x);
|
||||
target->SetStatPctModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), BASE_PCT, amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AuraEffect::HandleModResistancePercent(AuraApplication const* aurApp, uint8 mode, bool apply) const
|
||||
void AuraEffect::HandleModResistancePercent(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const
|
||||
{
|
||||
if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT)))
|
||||
return;
|
||||
|
||||
Unit* target = aurApp->GetTarget();
|
||||
|
||||
for (int8 i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++)
|
||||
for (uint8 i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++)
|
||||
{
|
||||
if (GetMiscValue() & int32(1 << i))
|
||||
{
|
||||
target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_PCT, float(GetAmount()), apply);
|
||||
float amount = target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_RESISTANCE_PCT, 1 << i);
|
||||
if (target->GetPctModifierValue(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_PCT) == amount)
|
||||
continue;
|
||||
|
||||
target->SetStatPctModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_PCT, amount);
|
||||
if (target->IsPlayer() || target->IsPet())
|
||||
{
|
||||
target->ApplyResistanceBuffModsPercentMod(SpellSchools(i), true, (float)GetAmount(), apply);
|
||||
target->ApplyResistanceBuffModsPercentMod(SpellSchools(i), false, (float)GetAmount(), apply);
|
||||
}
|
||||
target->UpdateResistanceBuffModsMod(SpellSchools(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4398,7 +4424,7 @@ void AuraEffect::HandleModBaseResistance(AuraApplication const* aurApp, uint8 mo
|
||||
{
|
||||
if (GetMiscValue() & (1 << i))
|
||||
{
|
||||
target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_VALUE, float(GetAmount()), apply);
|
||||
target->HandleStatFlatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_VALUE, float(GetAmount()), apply);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4430,23 +4456,28 @@ void AuraEffect::HandleAuraModStat(AuraApplication const* aurApp, uint8 mode, bo
|
||||
if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT)))
|
||||
return;
|
||||
|
||||
Unit* target = aurApp->GetTarget();
|
||||
|
||||
if (GetMiscValue() < -2 || GetMiscValue() > 4)
|
||||
{
|
||||
LOG_ERROR("spells.aura.effect", "WARNING: Spell {} effect {} has an unsupported misc value ({}) for SPELL_AURA_MOD_STAT ", GetId(), GetEffIndex(), GetMiscValue());
|
||||
return;
|
||||
}
|
||||
|
||||
Unit* target = aurApp->GetTarget();
|
||||
int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_STAT, true, GetMiscValue());
|
||||
if (std::abs(spellGroupVal) >= std::abs(GetAmount()))
|
||||
return;
|
||||
|
||||
for (int32 i = STAT_STRENGTH; i < MAX_STATS; i++)
|
||||
{
|
||||
// -1 or -2 is all stats (misc < -2 checked in function beginning)
|
||||
if (GetMiscValue() < 0 || GetMiscValue() == i)
|
||||
{
|
||||
//target->ApplyStatMod(Stats(i), m_amount, apply);
|
||||
target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_VALUE, float(GetAmount()), apply);
|
||||
if (spellGroupVal)
|
||||
target->HandleStatFlatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_VALUE, float(GetAmount()), !apply);
|
||||
|
||||
target->HandleStatFlatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_VALUE, float(GetAmount()), apply);
|
||||
if (target->IsPlayer() || target->IsPet())
|
||||
target->ApplyStatBuffMod(Stats(i), (float)GetAmount(), apply);
|
||||
target->UpdateStatBuffMod(Stats(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4470,8 +4501,16 @@ void AuraEffect::HandleModPercentStat(AuraApplication const* aurApp, uint8 mode,
|
||||
|
||||
for (int32 i = STAT_STRENGTH; i < MAX_STATS; ++i)
|
||||
{
|
||||
if (GetMiscValue() == i || GetMiscValue() == -1)
|
||||
target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), BASE_PCT, float(m_amount), apply);
|
||||
if (apply)
|
||||
target->ApplyStatPctModifier(UnitMods(UNIT_MOD_STAT_START + i), BASE_PCT, float(GetAmount()));
|
||||
else
|
||||
{
|
||||
float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_PERCENT_STAT, [i](AuraEffect const* aurEff)
|
||||
{
|
||||
return (aurEff->GetMiscValue() == i || aurEff->GetMiscValue() == -1);
|
||||
});
|
||||
target->SetStatPctModifier(UnitMods(UNIT_MOD_STAT_START + i), BASE_PCT, amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4549,7 +4588,7 @@ void AuraEffect::HandleModHealingDone(AuraApplication const* aurApp, uint8 mode,
|
||||
target->ToPlayer()->UpdateSpellDamageAndHealingBonus();
|
||||
}
|
||||
|
||||
void AuraEffect::HandleModTotalPercentStat(AuraApplication const* aurApp, uint8 mode, bool apply) const
|
||||
void AuraEffect::HandleModTotalPercentStat(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const
|
||||
{
|
||||
if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT)))
|
||||
return;
|
||||
@@ -4565,39 +4604,22 @@ void AuraEffect::HandleModTotalPercentStat(AuraApplication const* aurApp, uint8
|
||||
// save current health state
|
||||
float healthPct = target->GetHealthPct();
|
||||
bool alive = target->IsAlive();
|
||||
float value = GetAmount();
|
||||
|
||||
if (GetId() == 67480) // xinef: hack fix for blessing of sanctuary stats stack with blessing of kings...
|
||||
{
|
||||
if (value) // not turned off
|
||||
value = 10.0f;
|
||||
for (int32 i = STAT_STRENGTH; i < MAX_STATS; i++)
|
||||
{
|
||||
if (i == STAT_STRENGTH || i == STAT_STAMINA)
|
||||
{
|
||||
if (apply && (target->IsPlayer() || target->IsPet()))
|
||||
target->ApplyStatPercentBuffMod(Stats(i), value, apply);
|
||||
|
||||
target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT, value, apply);
|
||||
|
||||
if (!apply && (target->IsPlayer() || target->IsPet()))
|
||||
target->ApplyStatPercentBuffMod(Stats(i), value, apply);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (int32 i = STAT_STRENGTH; i < MAX_STATS; i++)
|
||||
{
|
||||
if (GetMiscValue() == i || GetMiscValue() == -1)
|
||||
{
|
||||
if (apply && (target->IsPlayer() || target->IsPet()))
|
||||
target->ApplyStatPercentBuffMod(Stats(i), value, apply);
|
||||
float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE, [i](AuraEffect const* aurEff)
|
||||
{
|
||||
return (aurEff->GetMiscValue() == i || aurEff->GetMiscValue() == -1);
|
||||
});
|
||||
|
||||
target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT, value, apply);
|
||||
if (target->GetPctModifierValue(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT) == amount)
|
||||
continue;
|
||||
|
||||
if (!apply && (target->IsPlayer() || target->IsPet()))
|
||||
target->ApplyStatPercentBuffMod(Stats(i), value, apply);
|
||||
target->SetStatPctModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT, amount);
|
||||
if (target->IsPlayer() || target->IsPet())
|
||||
target->UpdateStatBuffMod(Stats(i));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4693,7 +4715,7 @@ void AuraEffect::HandleAuraModIncreaseHealth(AuraApplication const* aurApp, uint
|
||||
|
||||
if (apply)
|
||||
{
|
||||
target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetAmount()), apply);
|
||||
target->HandleStatFlatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetAmount()), apply);
|
||||
target->ModifyHealth(GetAmount());
|
||||
}
|
||||
else
|
||||
@@ -4702,7 +4724,7 @@ void AuraEffect::HandleAuraModIncreaseHealth(AuraApplication const* aurApp, uint
|
||||
target->ModifyHealth(-GetAmount());
|
||||
else
|
||||
target->SetHealth(1);
|
||||
target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetAmount()), apply);
|
||||
target->HandleStatFlatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetAmount()), apply);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4716,7 +4738,7 @@ void AuraEffect::HandleAuraModIncreaseMaxHealth(AuraApplication const* aurApp, u
|
||||
uint32 oldhealth = target->GetHealth();
|
||||
double healthPercentage = (double)oldhealth / (double)target->GetMaxHealth();
|
||||
|
||||
target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetAmount()), apply);
|
||||
target->HandleStatFlatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetAmount()), apply);
|
||||
|
||||
// refresh percentage
|
||||
if (oldhealth > 0)
|
||||
@@ -4746,7 +4768,7 @@ void AuraEffect::HandleAuraModIncreaseEnergy(AuraApplication const* aurApp, uint
|
||||
|
||||
UnitMods unitMod = UnitMods(static_cast<uint16>(UNIT_MOD_POWER_START) + PowerType);
|
||||
|
||||
target->HandleStatModifier(unitMod, TOTAL_VALUE, float(GetAmount()), apply);
|
||||
target->HandleStatFlatModifier(unitMod, TOTAL_VALUE, float(GetAmount()), apply);
|
||||
}
|
||||
|
||||
void AuraEffect::HandleAuraModIncreaseEnergyPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const
|
||||
@@ -4765,17 +4787,16 @@ void AuraEffect::HandleAuraModIncreaseEnergyPercent(AuraApplication const* aurAp
|
||||
// return;
|
||||
|
||||
UnitMods unitMod = UnitMods(static_cast<uint16>(UNIT_MOD_POWER_START) + PowerType);
|
||||
float amount = float(GetAmount());
|
||||
|
||||
if (apply)
|
||||
{
|
||||
target->HandleStatModifier(unitMod, TOTAL_PCT, amount, apply);
|
||||
target->ModifyPowerPct(PowerType, amount, apply);
|
||||
float amount = float(GetAmount());
|
||||
target->ApplyStatPctModifier(unitMod, TOTAL_PCT, amount);
|
||||
}
|
||||
else
|
||||
{
|
||||
target->ModifyPowerPct(PowerType, amount, apply);
|
||||
target->HandleStatModifier(unitMod, TOTAL_PCT, amount, apply);
|
||||
float amount = target->GetTotalAuraMultiplierByMiscValue(SPELL_AURA_MOD_INCREASE_ENERGY_PERCENT, GetMiscValue());
|
||||
target->SetStatPctModifier(unitMod, TOTAL_PCT, amount);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4788,7 +4809,14 @@ void AuraEffect::HandleAuraModIncreaseHealthPercent(AuraApplication const* aurAp
|
||||
|
||||
// Unit will keep hp% after MaxHealth being modified if unit is alive.
|
||||
float percent = target->GetHealthPct();
|
||||
target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_PCT, float(GetAmount()), apply);
|
||||
|
||||
if (apply)
|
||||
target->ApplyStatPctModifier(UNIT_MOD_HEALTH, TOTAL_PCT, float(GetAmount()));
|
||||
else
|
||||
{
|
||||
float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_INCREASE_HEALTH_PERCENT);
|
||||
target->SetStatPctModifier(UNIT_MOD_HEALTH, TOTAL_PCT, amount);
|
||||
}
|
||||
|
||||
// Xinef: pct was rounded down and could "kill" creature by setting its health to 0 making npc zombie
|
||||
if (target->IsAlive())
|
||||
@@ -4803,7 +4831,13 @@ void AuraEffect::HandleAuraIncreaseBaseHealthPercent(AuraApplication const* aurA
|
||||
|
||||
Unit* target = aurApp->GetTarget();
|
||||
|
||||
target->HandleStatModifier(UNIT_MOD_HEALTH, BASE_PCT, float(GetAmount()), apply);
|
||||
if (apply)
|
||||
target->ApplyStatPctModifier(UNIT_MOD_HEALTH, BASE_PCT, float(GetAmount()));
|
||||
else
|
||||
{
|
||||
float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_BASE_HEALTH_PCT);
|
||||
target->SetStatPctModifier(UNIT_MOD_HEALTH, BASE_PCT, amount);
|
||||
}
|
||||
}
|
||||
|
||||
/********************************/
|
||||
@@ -4857,34 +4891,17 @@ void AuraEffect::HandleAuraModRegenInterrupt(AuraApplication const* aurApp, uint
|
||||
HandleModManaRegen(aurApp, mode, apply);
|
||||
}
|
||||
|
||||
void AuraEffect::HandleAuraModWeaponCritPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const
|
||||
void AuraEffect::HandleAuraModWeaponCritPercent(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const
|
||||
{
|
||||
if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT)))
|
||||
return;
|
||||
|
||||
Unit* target = aurApp->GetTarget();
|
||||
Player* target = aurApp->GetTarget()->ToPlayer();
|
||||
|
||||
if (!target->IsPlayer())
|
||||
if (!target)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < MAX_ATTACK; ++i)
|
||||
if (Item* pItem = target->ToPlayer()->GetWeaponForAttack(WeaponAttackType(i), true))
|
||||
target->ToPlayer()->_ApplyWeaponDependentAuraCritMod(pItem, WeaponAttackType(i), this, apply);
|
||||
|
||||
// mods must be applied base at equipped weapon class and subclass comparison
|
||||
// with spell->EquippedItemClass and EquippedItemSubClassMask and EquippedItemInventoryTypeMask
|
||||
// GetMiscValue() comparison with item generated damage types
|
||||
|
||||
if (GetSpellInfo()->EquippedItemClass == -1)
|
||||
{
|
||||
target->ToPlayer()->HandleBaseModValue(CRIT_PERCENTAGE, FLAT_MOD, float (GetAmount()), apply);
|
||||
target->ToPlayer()->HandleBaseModValue(OFFHAND_CRIT_PERCENTAGE, FLAT_MOD, float (GetAmount()), apply);
|
||||
target->ToPlayer()->HandleBaseModValue(RANGED_CRIT_PERCENTAGE, FLAT_MOD, float (GetAmount()), apply);
|
||||
}
|
||||
else
|
||||
{
|
||||
// done in Player::_ApplyWeaponDependentAuraMods
|
||||
}
|
||||
target->UpdateAllWeaponDependentCritAuras();
|
||||
}
|
||||
|
||||
void AuraEffect::HandleModHitChance(AuraApplication const* aurApp, uint8 mode, bool apply) const
|
||||
@@ -4960,9 +4977,7 @@ void AuraEffect::HandleAuraModCritPct(AuraApplication const* aurApp, uint8 mode,
|
||||
return;
|
||||
}
|
||||
|
||||
target->ToPlayer()->HandleBaseModValue(CRIT_PERCENTAGE, FLAT_MOD, float (GetAmount()), apply);
|
||||
target->ToPlayer()->HandleBaseModValue(OFFHAND_CRIT_PERCENTAGE, FLAT_MOD, float (GetAmount()), apply);
|
||||
target->ToPlayer()->HandleBaseModValue(RANGED_CRIT_PERCENTAGE, FLAT_MOD, float (GetAmount()), apply);
|
||||
target->ToPlayer()->UpdateAllWeaponDependentCritAuras();
|
||||
|
||||
// included in Player::UpdateSpellCritChance calculation
|
||||
target->ToPlayer()->UpdateAllSpellCritChances();
|
||||
@@ -4986,6 +5001,13 @@ void AuraEffect::HandleModCastingSpeed(AuraApplication const* aurApp, uint8 mode
|
||||
return;
|
||||
}
|
||||
|
||||
int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, GetAuraType());
|
||||
if (std::abs(spellGroupVal) >= std::abs(GetAmount()))
|
||||
return;
|
||||
|
||||
if (spellGroupVal)
|
||||
target->ApplyCastTimePercentMod(float(spellGroupVal), !apply);
|
||||
|
||||
target->ApplyCastTimePercentMod((float)GetAmount(), apply);
|
||||
}
|
||||
|
||||
@@ -5007,6 +5029,17 @@ void AuraEffect::HandleModCombatSpeedPct(AuraApplication const* aurApp, uint8 mo
|
||||
return;
|
||||
|
||||
Unit* target = aurApp->GetTarget();
|
||||
int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MELEE_SLOW);
|
||||
if (std::abs(spellGroupVal) >= std::abs(GetAmount()))
|
||||
return;
|
||||
|
||||
if (spellGroupVal)
|
||||
{
|
||||
target->ApplyCastTimePercentMod(float(spellGroupVal), !apply);
|
||||
target->ApplyAttackTimePercentMod(BASE_ATTACK, float(spellGroupVal), !apply);
|
||||
target->ApplyAttackTimePercentMod(OFF_ATTACK, float(spellGroupVal), !apply);
|
||||
target->ApplyAttackTimePercentMod(RANGED_ATTACK, float(spellGroupVal), !apply);
|
||||
}
|
||||
|
||||
target->ApplyCastTimePercentMod(float(GetAmount()), apply);
|
||||
target->ApplyAttackTimePercentMod(BASE_ATTACK, float(GetAmount()), apply);
|
||||
@@ -5031,7 +5064,15 @@ void AuraEffect::HandleModMeleeSpeedPct(AuraApplication const* aurApp, uint8 mod
|
||||
return;
|
||||
|
||||
Unit* target = aurApp->GetTarget();
|
||||
int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_MELEE_HASTE);
|
||||
if (std::abs(spellGroupVal) >= std::abs(GetAmount()))
|
||||
return;
|
||||
|
||||
if (spellGroupVal)
|
||||
{
|
||||
target->ApplyAttackTimePercentMod(BASE_ATTACK, float(spellGroupVal), !apply);
|
||||
target->ApplyAttackTimePercentMod(OFF_ATTACK, float(spellGroupVal), !apply);
|
||||
}
|
||||
target->ApplyAttackTimePercentMod(BASE_ATTACK, float(GetAmount()), apply);
|
||||
target->ApplyAttackTimePercentMod(OFF_ATTACK, float(GetAmount()), apply);
|
||||
}
|
||||
@@ -5073,7 +5114,7 @@ void AuraEffect::HandleModRating(AuraApplication const* aurApp, uint8 mode, bool
|
||||
if (!target->IsPlayer())
|
||||
return;
|
||||
|
||||
for (uint32 rating = 0; rating < MAX_COMBAT_RATING; ++rating)
|
||||
for (uint8 rating = 0; rating < MAX_COMBAT_RATING; ++rating)
|
||||
if (GetMiscValue() & (1 << rating))
|
||||
target->ToPlayer()->ApplyRatingMod(CombatRating(rating), GetAmount(), apply);
|
||||
}
|
||||
@@ -5089,7 +5130,7 @@ void AuraEffect::HandleModRatingFromStat(AuraApplication const* aurApp, uint8 mo
|
||||
return;
|
||||
|
||||
// Just recalculate ratings
|
||||
for (uint32 rating = 0; rating < MAX_COMBAT_RATING; ++rating)
|
||||
for (uint8 rating = 0; rating < MAX_COMBAT_RATING; ++rating)
|
||||
if (GetMiscValue() & (1 << rating))
|
||||
target->ToPlayer()->ApplyRatingMod(CombatRating(rating), 0, apply);
|
||||
}
|
||||
@@ -5105,7 +5146,7 @@ void AuraEffect::HandleAuraModAttackPower(AuraApplication const* aurApp, uint8 m
|
||||
|
||||
Unit* target = aurApp->GetTarget();
|
||||
|
||||
target->HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(GetAmount()), apply);
|
||||
target->HandleStatFlatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(GetAmount()), apply);
|
||||
}
|
||||
|
||||
void AuraEffect::HandleAuraModRangedAttackPower(AuraApplication const* aurApp, uint8 mode, bool apply) const
|
||||
@@ -5118,7 +5159,7 @@ void AuraEffect::HandleAuraModRangedAttackPower(AuraApplication const* aurApp, u
|
||||
if ((target->getClassMask() & CLASSMASK_WAND_USERS) != 0)
|
||||
return;
|
||||
|
||||
target->HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(GetAmount()), apply);
|
||||
target->HandleStatFlatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(GetAmount()), apply);
|
||||
}
|
||||
|
||||
void AuraEffect::HandleAuraModAttackPowerPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const
|
||||
@@ -5129,7 +5170,13 @@ void AuraEffect::HandleAuraModAttackPowerPercent(AuraApplication const* aurApp,
|
||||
Unit* target = aurApp->GetTarget();
|
||||
|
||||
//UNIT_FIELD_ATTACK_POWER_MULTIPLIER = multiplier - 1
|
||||
target->HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_PCT, float(GetAmount()), apply);
|
||||
if (apply)
|
||||
target->ApplyStatPctModifier(UNIT_MOD_ATTACK_POWER, TOTAL_PCT, float(GetAmount()));
|
||||
else
|
||||
{
|
||||
float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_ATTACK_POWER_PCT);
|
||||
target->SetStatPctModifier(UNIT_MOD_ATTACK_POWER, TOTAL_PCT, amount);
|
||||
}
|
||||
}
|
||||
|
||||
void AuraEffect::HandleAuraModRangedAttackPowerPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const
|
||||
@@ -5143,7 +5190,13 @@ void AuraEffect::HandleAuraModRangedAttackPowerPercent(AuraApplication const* au
|
||||
return;
|
||||
|
||||
//UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER = multiplier - 1
|
||||
target->HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_PCT, float(GetAmount()), apply);
|
||||
if (apply)
|
||||
target->ApplyStatPctModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_PCT, float(GetAmount()));
|
||||
else
|
||||
{
|
||||
float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_RANGED_ATTACK_POWER_PCT);
|
||||
target->SetStatPctModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_PCT, amount);
|
||||
}
|
||||
}
|
||||
|
||||
void AuraEffect::HandleAuraModRangedAttackPowerOfStatPercent(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const
|
||||
@@ -5184,85 +5237,25 @@ void AuraEffect::HandleModDamageDone(AuraApplication const* aurApp, uint8 mode,
|
||||
|
||||
Unit* target = aurApp->GetTarget();
|
||||
|
||||
// apply item specific bonuses for already equipped weapon
|
||||
if (target->IsPlayer())
|
||||
{
|
||||
for (int i = 0; i < MAX_ATTACK; ++i)
|
||||
if (Item* pItem = target->ToPlayer()->GetWeaponForAttack(WeaponAttackType(i), true))
|
||||
target->ToPlayer()->_ApplyWeaponDependentAuraDamageMod(pItem, WeaponAttackType(i), this, apply);
|
||||
}
|
||||
if ((GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) != 0)
|
||||
target->UpdateAllDamageDoneMods();
|
||||
|
||||
// GetMiscValue() is bitmask of spell schools
|
||||
// 1 (0-bit) - normal school damage (SPELL_SCHOOL_MASK_NORMAL)
|
||||
// 126 - full bitmask all magic damages (SPELL_SCHOOL_MASK_MAGIC) including wands
|
||||
// 127 - full bitmask any damages
|
||||
//
|
||||
// mods must be applied base at equipped weapon class and subclass comparison
|
||||
// with spell->EquippedItemClass and EquippedItemSubClassMask and EquippedItemInventoryTypeMask
|
||||
// GetMiscValue() comparison with item generated damage types
|
||||
|
||||
if ((GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) != 0 && sScriptMgr->CanModAuraEffectDamageDone(this, target, aurApp, mode, apply))
|
||||
{
|
||||
// apply generic physical damage bonuses including wand case
|
||||
if (GetSpellInfo()->EquippedItemClass == -1 || !target->IsPlayer())
|
||||
{
|
||||
target->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_VALUE, float(GetAmount()), apply);
|
||||
target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_VALUE, float(GetAmount()), apply);
|
||||
target->HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_VALUE, float(GetAmount()), apply);
|
||||
|
||||
if (target->IsPlayer())
|
||||
{
|
||||
if (GetAmount() > 0)
|
||||
target->ApplyModInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS, GetAmount(), apply);
|
||||
else
|
||||
target->ApplyModInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG, GetAmount(), apply);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// done in Player::_ApplyWeaponDependentAuraMods
|
||||
}
|
||||
}
|
||||
|
||||
// Skip non magic case for Speedup
|
||||
if ((GetMiscValue() & SPELL_SCHOOL_MASK_MAGIC) == 0)
|
||||
return;
|
||||
|
||||
if (GetSpellInfo()->EquippedItemClass != -1 || GetSpellInfo()->EquippedItemInventoryTypeMask != 0)
|
||||
{
|
||||
// wand magic case (skip generic to all item spell bonuses)
|
||||
// done in Player::_ApplyWeaponDependentAuraMods
|
||||
|
||||
// Skip item specific requirements for not wand magic damage
|
||||
return;
|
||||
}
|
||||
|
||||
// Magic damage modifiers implemented in Unit::SpellDamageBonus
|
||||
// Magic damage modifiers implemented in Unit::SpellBaseDamageBonus
|
||||
// This information for client side use only
|
||||
if (target->IsPlayer())
|
||||
{
|
||||
if (GetAmount() > 0)
|
||||
{
|
||||
for (uint32 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; i++)
|
||||
{
|
||||
if ((GetMiscValue() & (1 << i)) != 0)
|
||||
target->ApplyModInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + i, GetAmount(), apply);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint32 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; i++)
|
||||
{
|
||||
if ((GetMiscValue() & (1 << i)) != 0)
|
||||
target->ApplyModInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + i, GetAmount(), apply);
|
||||
}
|
||||
}
|
||||
|
||||
uint16 baseField = GetAmount() >= 0 ? PLAYER_FIELD_MOD_DAMAGE_DONE_POS : PLAYER_FIELD_MOD_DAMAGE_DONE_NEG;
|
||||
for (uint16 i = 0; i < MAX_SPELL_SCHOOL; ++i)
|
||||
if (GetMiscValue() & (1 << i))
|
||||
target->ApplyModUInt32Value(baseField + i, GetAmount(), apply);
|
||||
|
||||
if (Guardian* pet = target->ToPlayer()->GetGuardianPet())
|
||||
pet->UpdateAttackPowerAndDamage();
|
||||
}
|
||||
}
|
||||
|
||||
void AuraEffect::HandleModDamagePercentDone(AuraApplication const* aurApp, uint8 mode, bool apply) const
|
||||
void AuraEffect::HandleModDamagePercentDone(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const
|
||||
{
|
||||
if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT)))
|
||||
return;
|
||||
@@ -5271,39 +5264,32 @@ void AuraEffect::HandleModDamagePercentDone(AuraApplication const* aurApp, uint8
|
||||
if (!target)
|
||||
return;
|
||||
|
||||
if (!sScriptMgr->CanModAuraEffectModDamagePercentDone(this, target, aurApp, mode, apply))
|
||||
return;
|
||||
if ((GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL))
|
||||
target->UpdateAllDamagePctDoneMods();
|
||||
|
||||
if (target->IsPlayer())
|
||||
{
|
||||
for (int i = 0; i < MAX_ATTACK; ++i)
|
||||
if (Item* item = target->ToPlayer()->GetWeaponForAttack(WeaponAttackType(i), false))
|
||||
target->ToPlayer()->_ApplyWeaponDependentAuraDamageMod(item, WeaponAttackType(i), this, apply);
|
||||
}
|
||||
|
||||
if ((GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) && (GetSpellInfo()->EquippedItemClass == -1 || !target->IsPlayer()))
|
||||
{
|
||||
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->IsPlayer())
|
||||
target->ToPlayer()->ApplyPercentModFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT, float (GetAmount()), apply);
|
||||
}
|
||||
else
|
||||
{
|
||||
// done in Player::_ApplyWeaponDependentAuraMods for SPELL_SCHOOL_MASK_NORMAL && EquippedItemClass != -1 and also for wand case
|
||||
for (uint8 i = 0; i < MAX_SPELL_SCHOOL; ++i)
|
||||
{
|
||||
if (GetMiscValue() & (1 << i))
|
||||
{
|
||||
// only aura type modifying PLAYER_FIELD_MOD_DAMAGE_DONE_PCT
|
||||
float amount = target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, 1 << i);
|
||||
target->SetFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT + i, amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AuraEffect::HandleModOffhandDamagePercent(AuraApplication const* aurApp, uint8 mode, bool apply) const
|
||||
void AuraEffect::HandleModOffhandDamagePercent(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const
|
||||
{
|
||||
if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT)))
|
||||
return;
|
||||
|
||||
Unit* target = aurApp->GetTarget();
|
||||
|
||||
target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, float(GetAmount()), apply);
|
||||
// also handles spell group stacks
|
||||
target->UpdateDamagePctDoneMods(OFF_ATTACK);
|
||||
}
|
||||
|
||||
void AuraEffect::HandleShieldBlockValue(AuraApplication const* aurApp, uint8 mode, bool apply) const
|
||||
@@ -5311,14 +5297,29 @@ void AuraEffect::HandleShieldBlockValue(AuraApplication const* aurApp, uint8 mod
|
||||
if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT)))
|
||||
return;
|
||||
|
||||
Unit* target = aurApp->GetTarget();
|
||||
Player* target = aurApp->GetTarget()->ToPlayer();
|
||||
if (!target)
|
||||
return;
|
||||
|
||||
BaseModType modType = FLAT_MOD;
|
||||
if (GetAuraType() == SPELL_AURA_MOD_SHIELD_BLOCKVALUE_PCT)
|
||||
modType = PCT_MOD;
|
||||
target->HandleBaseModFlatValue(SHIELD_BLOCK_VALUE, float(GetAmount()), apply);
|
||||
}
|
||||
|
||||
if (target->IsPlayer())
|
||||
target->ToPlayer()->HandleBaseModValue(SHIELD_BLOCK_VALUE, modType, float(GetAmount()), apply);
|
||||
void AuraEffect::HandleShieldBlockValuePercent(AuraApplication const* aurApp, uint8 mode, bool apply) const
|
||||
{
|
||||
if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT)))
|
||||
return;
|
||||
|
||||
Player* target = aurApp->GetTarget()->ToPlayer();
|
||||
if (!target)
|
||||
return;
|
||||
|
||||
if (apply)
|
||||
target->ApplyBaseModPctValue(SHIELD_BLOCK_VALUE, float(GetAmount()));
|
||||
else
|
||||
{
|
||||
float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_SHIELD_BLOCKVALUE_PCT);
|
||||
target->SetBaseModPctValue(SHIELD_BLOCK_VALUE, amount);
|
||||
}
|
||||
}
|
||||
|
||||
/********************************/
|
||||
|
||||
@@ -112,8 +112,6 @@ public:
|
||||
float GetPctMods() const { return m_pctMods; }
|
||||
void SetPctMods(float pctMods) { m_pctMods = pctMods; }
|
||||
|
||||
// xinef: stacking
|
||||
uint32 GetAuraGroup() const { return m_auraGroup; }
|
||||
int32 GetOldAmount() const { return m_oldAmount; }
|
||||
void SetOldAmount(int32 amount) { m_oldAmount = amount; }
|
||||
void SetEnabled(bool enabled) { m_isAuraEnabled = enabled; }
|
||||
@@ -131,8 +129,6 @@ private:
|
||||
float m_critChance;
|
||||
float m_pctMods;
|
||||
|
||||
// xinef: stacking
|
||||
uint32 m_auraGroup;
|
||||
int32 m_oldAmount;
|
||||
bool m_isAuraEnabled;
|
||||
// xinef: channel information for channel triggering
|
||||
@@ -299,6 +295,7 @@ public:
|
||||
void HandleModDamagePercentDone(AuraApplication const* aurApp, uint8 mode, bool apply) const;
|
||||
void HandleModOffhandDamagePercent(AuraApplication const* aurApp, uint8 mode, bool apply) const;
|
||||
void HandleShieldBlockValue(AuraApplication const* aurApp, uint8 mode, bool apply) const;
|
||||
void HandleShieldBlockValuePercent(AuraApplication const* aurApp, uint8 mode, bool apply) const;
|
||||
// power cost
|
||||
void HandleModPowerCostPCT(AuraApplication const* aurApp, uint8 mode, bool apply) const;
|
||||
void HandleModPowerCost(AuraApplication const* aurApp, uint8 mode, bool apply) const;
|
||||
|
||||
@@ -181,67 +181,6 @@ void AuraApplication::_HandleEffect(uint8 effIndex, bool apply)
|
||||
// Remove all triggered by aura spells vs unlimited duration
|
||||
aurEff->CleanupTriggeredSpells(GetTarget());
|
||||
}
|
||||
|
||||
// Stacking!
|
||||
if (uint32 groupId = aurEff->GetAuraGroup())
|
||||
{
|
||||
SpellGroupStackFlags sFlag = sSpellMgr->GetGroupStackFlags(groupId);
|
||||
if (!aurEff->IsPeriodic() && (sFlag & SPELL_GROUP_STACK_FLAG_EFFECT_EXCLUSIVE))
|
||||
{
|
||||
AuraApplication* strongestApp = apply ? this : nullptr;
|
||||
AuraEffect* strongestEff = apply ? aurEff : nullptr;
|
||||
int32 amount = apply ? std::abs(aurEff->GetAmount()) : 0;
|
||||
Unit* target = GetTarget();
|
||||
Unit::AuraEffectList const& auraList = target->GetAuraEffectsByType(aurEff->GetAuraType());
|
||||
for (Unit::AuraEffectList::const_iterator iter = auraList.begin(); iter != auraList.end(); ++iter)
|
||||
{
|
||||
if ((*iter)->GetAuraGroup() != groupId || (*iter) == strongestEff || (*iter)->GetBase()->IsRemoved())
|
||||
continue;
|
||||
|
||||
// xinef: skip different misc values
|
||||
if (aurEff->GetAuraType() != SPELL_AURA_230 /*SPELL_AURA_MOD_INCREASE_HEALTH_2*/ && aurEff->GetAuraType() != SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK &&
|
||||
aurEff->GetMiscValue() != (*iter)->GetMiscValue())
|
||||
continue;
|
||||
|
||||
// xinef: should not happen
|
||||
AuraApplication* aurApp = (*iter)->GetBase()->GetApplicationOfTarget(target->GetGUID());
|
||||
if (!aurApp)
|
||||
continue;
|
||||
|
||||
if (amount < std::abs((*iter)->GetForcedAmount()))
|
||||
{
|
||||
// xinef: if we have strongest aura and it is active, turn it off
|
||||
// xinef: otherwise just save new aura;
|
||||
if (strongestApp && strongestEff && strongestApp->IsActive(strongestEff->GetEffIndex()))
|
||||
{
|
||||
strongestEff->HandleEffect(strongestApp, AURA_EFFECT_HANDLE_CHANGE_AMOUNT, false);
|
||||
if (!strongestEff->GetSpellInfo()->HasAreaAuraEffect())
|
||||
strongestEff->SetEnabled(false);
|
||||
strongestApp->SetDisableMask(strongestEff->GetEffIndex());
|
||||
}
|
||||
strongestApp = aurApp;
|
||||
strongestEff = (*iter);
|
||||
amount = std::abs((*iter)->GetAmount());
|
||||
}
|
||||
// xinef: itered aura is weaker, deactivate if active
|
||||
else if (aurApp->IsActive((*iter)->GetEffIndex()))
|
||||
{
|
||||
(*iter)->HandleEffect(aurApp, AURA_EFFECT_HANDLE_CHANGE_AMOUNT, false);
|
||||
if (!(*iter)->GetSpellInfo()->HasAreaAuraEffect())
|
||||
(*iter)->SetEnabled(false);
|
||||
aurApp->SetDisableMask((*iter)->GetEffIndex());
|
||||
}
|
||||
}
|
||||
|
||||
// xinef: if we have new strongest aura, and it is not active
|
||||
if (strongestApp && strongestEff && !strongestApp->IsActive(strongestEff->GetEffIndex()))
|
||||
{
|
||||
strongestApp->RemoveDisableMask(strongestEff->GetEffIndex());
|
||||
strongestEff->SetEnabled(true);
|
||||
strongestEff->HandleEffect(strongestApp, AURA_EFFECT_HANDLE_CHANGE_AMOUNT, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
SetNeedClientUpdate();
|
||||
}
|
||||
|
||||
@@ -661,6 +600,9 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply)
|
||||
if (!itr->second || itr->first->IsImmunedToSpell(GetSpellInfo()) || !CanBeAppliedOn(itr->first))
|
||||
addUnit = false;
|
||||
|
||||
if (addUnit && !itr->first->IsHighestExclusiveAura(this, true))
|
||||
addUnit = false;
|
||||
|
||||
if (addUnit)
|
||||
{
|
||||
// persistent area aura does not hit flying targets
|
||||
@@ -684,7 +626,7 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply)
|
||||
for (Unit::AuraApplicationMap::iterator iter = itr->first->GetAppliedAuras().begin(); iter != itr->first->GetAppliedAuras().end(); ++iter)
|
||||
{
|
||||
Aura const* aura = iter->second->GetBase();
|
||||
if (!CanStackWith(aura, false))
|
||||
if (!CanStackWith(aura))
|
||||
{
|
||||
addUnit = false;
|
||||
break;
|
||||
@@ -1069,6 +1011,16 @@ void Aura::RefreshSpellMods()
|
||||
player->RestoreAllSpellMods(0, this);
|
||||
}
|
||||
|
||||
bool Aura::HasMoreThanOneEffectForType(AuraType auraType) const
|
||||
{
|
||||
uint32 count = 0;
|
||||
for (SpellEffectInfo const& spellEffectInfo : GetSpellInfo()->GetEffects())
|
||||
if (HasEffect(spellEffectInfo.EffectIndex) && spellEffectInfo.ApplyAuraName == auraType)
|
||||
++count;
|
||||
|
||||
return count > 1;
|
||||
}
|
||||
|
||||
bool Aura::IsArea() const
|
||||
{
|
||||
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
@@ -1589,7 +1541,7 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b
|
||||
// Alchemy: Mixology
|
||||
if (caster && caster->HasAura(53042) && caster->IsPlayer() && !caster->ToPlayer()->GetSession()->PlayerLoading())
|
||||
{
|
||||
if (sSpellMgr->GetSpellGroup(GetId()) == 1) /*Elixirs*/
|
||||
if (sSpellMgr->IsSpellMemberOfSpellGroup(GetId(), SPELL_GROUP_ELIXIR_BATTLE) || sSpellMgr->IsSpellMemberOfSpellGroup(GetId(), SPELL_GROUP_ELIXIR_GUARDIAN))
|
||||
{
|
||||
if (caster->HasSpell(GetSpellInfo()->Effects[EFFECT_0].TriggerSpell))
|
||||
{
|
||||
@@ -2018,7 +1970,7 @@ bool Aura::IsAuraStronger(Aura const* newAura) const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Aura::CanStackWith(Aura const* existingAura, bool remove) const
|
||||
bool Aura::CanStackWith(Aura const* existingAura) const
|
||||
{
|
||||
// Can stack with self
|
||||
if (this == existingAura)
|
||||
@@ -2056,47 +2008,19 @@ bool Aura::CanStackWith(Aura const* existingAura, bool remove) const
|
||||
return false;
|
||||
|
||||
// check spell group stack rules
|
||||
// xinef: this assures us that both spells are in same group!
|
||||
SpellGroupStackFlags stackFlags = sSpellMgr->CheckSpellGroupStackRules(m_spellInfo, existingSpellInfo, remove, IsArea());
|
||||
if (stackFlags)
|
||||
switch (sSpellMgr->CheckSpellGroupStackRules(m_spellInfo, existingSpellInfo))
|
||||
{
|
||||
// xinef: same caster rule is bounded by spellfamily
|
||||
if (sameCaster && m_spellInfo->SpellFamilyName == existingSpellInfo->SpellFamilyName &&
|
||||
(stackFlags & SPELL_GROUP_STACK_FLAG_NOT_SAME_CASTER))
|
||||
case SPELL_GROUP_STACK_RULE_EXCLUSIVE:
|
||||
case SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST: // if it reaches this point, existing aura is lower/equal
|
||||
return false;
|
||||
|
||||
// xinef: normal exclusive stacking, remove if auras are equal by effects
|
||||
if (stackFlags & SPELL_GROUP_STACK_FLAG_EXCLUSIVE)
|
||||
{
|
||||
if (GetSpellInfo()->IsAuraEffectEqual(existingSpellInfo) || GetSpellInfo()->IsRankOf(existingSpellInfo))
|
||||
{
|
||||
if (remove)
|
||||
return IsAuraStronger(existingAura);
|
||||
else
|
||||
return existingAura->IsAuraStronger(this);
|
||||
}
|
||||
}
|
||||
|
||||
// xinef: check priority before effect mask
|
||||
SpellGroupSpecialFlags thisAuraFlag = sSpellMgr->GetSpellGroupSpecialFlags(GetId());
|
||||
SpellGroupSpecialFlags existingAuraFlag = sSpellMgr->GetSpellGroupSpecialFlags(existingSpellInfo->Id);
|
||||
if (thisAuraFlag >= SPELL_GROUP_SPECIAL_FLAG_PRIORITY1 && thisAuraFlag <= SPELL_GROUP_SPECIAL_FLAG_PRIORITY4 &&
|
||||
existingAuraFlag >= SPELL_GROUP_SPECIAL_FLAG_PRIORITY1 && existingAuraFlag <= SPELL_GROUP_SPECIAL_FLAG_PRIORITY4)
|
||||
{
|
||||
if (thisAuraFlag < existingAuraFlag)
|
||||
{
|
||||
case SPELL_GROUP_STACK_RULE_EXCLUSIVE_FROM_SAME_CASTER:
|
||||
if (sameCaster)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// xinef: forced strongest aura in group by flag
|
||||
if (stackFlags & SPELL_GROUP_STACK_FLAG_FORCED_STRONGEST)
|
||||
return !remove;
|
||||
if (stackFlags & SPELL_GROUP_STACK_FLAG_FORCED_WEAKEST)
|
||||
return remove;
|
||||
|
||||
// xinef: forced return, handle all cases using available flags!
|
||||
return !(stackFlags & SPELL_GROUP_STACK_FLAG_NEVER_STACK);
|
||||
break;
|
||||
case SPELL_GROUP_STACK_RULE_DEFAULT:
|
||||
case SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_spellInfo->SpellFamilyName != existingSpellInfo->SpellFamilyName)
|
||||
|
||||
@@ -153,6 +153,7 @@ public:
|
||||
|
||||
uint8 GetCasterLevel() const { return m_casterLevel; }
|
||||
|
||||
bool HasMoreThanOneEffectForType(AuraType auraType) const;
|
||||
bool IsArea() const;
|
||||
bool IsPassive() const;
|
||||
bool IsDeathPersistent() const;
|
||||
@@ -188,7 +189,7 @@ public:
|
||||
void HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, bool apply, bool onReapply);
|
||||
bool CanBeAppliedOn(Unit* target);
|
||||
bool CheckAreaTarget(Unit* target);
|
||||
bool CanStackWith(Aura const* checkAura, bool remove) const;
|
||||
bool CanStackWith(Aura const* existingAura) const;
|
||||
bool IsAuraStronger(Aura const* newAura) const;
|
||||
|
||||
// Proc system
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include "ArenaSpectator.h"
|
||||
#include "BattlefieldMgr.h"
|
||||
#include "Battleground.h"
|
||||
#include "BattlegroundIC.h"
|
||||
#include "CharmInfo.h"
|
||||
#include "CellImpl.h"
|
||||
#include "Common.h"
|
||||
@@ -33,7 +32,6 @@
|
||||
#include "InstanceScript.h"
|
||||
#include "Log.h"
|
||||
#include "LootMgr.h"
|
||||
#include "MapMgr.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Opcodes.h"
|
||||
@@ -41,6 +39,7 @@
|
||||
#include "Player.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "SharedDefines.h"
|
||||
#include "SpellAuraDefines.h"
|
||||
#include "SpellAuraEffects.h"
|
||||
#include "SpellInfo.h"
|
||||
#include "SpellMgr.h"
|
||||
@@ -1240,11 +1239,7 @@ void Spell::SelectImplicitConeTargets(SpellEffIndex effIndex, SpellImplicitTarge
|
||||
// Other special target selection goes here
|
||||
if (uint32 maxTargets = m_spellValue->MaxAffectedTargets)
|
||||
{
|
||||
Unit::AuraEffectList const& Auras = m_caster->GetAuraEffectsByType(SPELL_AURA_MOD_MAX_AFFECTED_TARGETS);
|
||||
for (Unit::AuraEffectList::const_iterator j = Auras.begin(); j != Auras.end(); ++j)
|
||||
if ((*j)->IsAffectedOnSpell(m_spellInfo))
|
||||
maxTargets += (*j)->GetAmount();
|
||||
|
||||
maxTargets += m_caster->GetTotalAuraModifierByAffectMask(SPELL_AURA_MOD_MAX_AFFECTED_TARGETS, m_spellInfo);
|
||||
Acore::Containers::RandomResize(targets, maxTargets);
|
||||
}
|
||||
|
||||
@@ -1327,11 +1322,7 @@ void Spell::SelectImplicitAreaTargets(SpellEffIndex effIndex, SpellImplicitTarge
|
||||
// Other special target selection goes here
|
||||
if (uint32 maxTargets = m_spellValue->MaxAffectedTargets)
|
||||
{
|
||||
Unit::AuraEffectList const& Auras = m_caster->GetAuraEffectsByType(SPELL_AURA_MOD_MAX_AFFECTED_TARGETS);
|
||||
for (Unit::AuraEffectList::const_iterator j = Auras.begin(); j != Auras.end(); ++j)
|
||||
if ((*j)->IsAffectedOnSpell(m_spellInfo))
|
||||
maxTargets += (*j)->GetAmount();
|
||||
|
||||
maxTargets += m_caster->GetTotalAuraModifierByAffectMask(SPELL_AURA_MOD_MAX_AFFECTED_TARGETS, m_spellInfo);
|
||||
Acore::Containers::RandomResize(targets, maxTargets);
|
||||
}
|
||||
|
||||
@@ -6076,6 +6067,8 @@ SpellCastResult Spell::CheckCast(bool strict)
|
||||
}
|
||||
}
|
||||
|
||||
uint8 approximateAuraEffectMask = 0;
|
||||
uint8 nonAuraEffectMask = 0;
|
||||
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
{
|
||||
// for effects of spells that have only one target
|
||||
@@ -6561,6 +6554,11 @@ SpellCastResult Spell::CheckCast(bool strict)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_spellInfo->Effects[i].IsAura())
|
||||
approximateAuraEffectMask |= 1 << i;
|
||||
else if (m_spellInfo->Effects[i].IsEffect())
|
||||
nonAuraEffectMask |= 1 << i;
|
||||
}
|
||||
|
||||
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
@@ -6609,8 +6607,13 @@ SpellCastResult Spell::CheckCast(bool strict)
|
||||
if (target->IsCreature() && target->ToCreature()->IsVehicle())
|
||||
return SPELL_FAILED_BAD_IMPLICIT_TARGETS;
|
||||
|
||||
// Allow SPELL_AURA_MOD_POSSESS to work on mounted players,
|
||||
// but keep the old restriction for everything else.
|
||||
if (target->IsMounted())
|
||||
return SPELL_FAILED_CANT_BE_CHARMED;
|
||||
{
|
||||
if (!(target->IsPlayer() && m_spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_MOD_POSSESS))
|
||||
return SPELL_FAILED_CANT_BE_CHARMED;
|
||||
}
|
||||
|
||||
if (target->GetCharmerGUID())
|
||||
return SPELL_FAILED_CHARMED;
|
||||
@@ -6718,6 +6721,13 @@ SpellCastResult Spell::CheckCast(bool strict)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// check if target already has the same type, but more powerful aura
|
||||
if (!nonAuraEffectMask && (approximateAuraEffectMask & (1 << i)) && !m_spellInfo->IsTargetingArea())
|
||||
if (Unit* target = m_targets.GetUnitTarget())
|
||||
if (!target->IsHighestExclusiveAuraEffect(m_spellInfo, AuraType(m_spellInfo->Effects[i].ApplyAuraName),
|
||||
m_spellInfo->Effects[i].CalcValue(m_caster, &m_spellValue->EffectBasePoints[i]), approximateAuraEffectMask, false))
|
||||
return SPELL_FAILED_AURA_BOUNCED;
|
||||
}
|
||||
|
||||
// check trade slot case (last, for allow catch any another cast problems)
|
||||
@@ -6968,26 +6978,35 @@ bool Spell::CanAutoCast(Unit* target)
|
||||
{
|
||||
ObjectGuid targetguid = target->GetGUID();
|
||||
|
||||
for (uint32 j = 0; j < MAX_SPELL_EFFECTS; ++j)
|
||||
for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
|
||||
{
|
||||
if (m_spellInfo->Effects[j].Effect == SPELL_EFFECT_APPLY_AURA)
|
||||
if (!spellEffectInfo.IsAura())
|
||||
continue;
|
||||
|
||||
AuraType const& auraType = spellEffectInfo.ApplyAuraName;
|
||||
Unit::AuraEffectList const& auras = target->GetAuraEffectsByType(auraType);
|
||||
for (Unit::AuraEffectList::const_iterator auraIt = auras.begin(); auraIt != auras.end(); ++auraIt)
|
||||
{
|
||||
if (m_spellInfo->StackAmount <= 1)
|
||||
{
|
||||
if (target->HasAuraEffect(m_spellInfo->Id, j))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (AuraEffect* aureff = target->GetAuraEffect(m_spellInfo->Id, j))
|
||||
if (aureff->GetBase()->GetStackAmount() >= m_spellInfo->StackAmount)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (m_spellInfo->Effects[j].IsAreaAuraEffect())
|
||||
{
|
||||
if (target->HasAuraEffect(m_spellInfo->Id, j))
|
||||
if (GetSpellInfo()->Id == (*auraIt)->GetSpellInfo()->Id)
|
||||
return false;
|
||||
|
||||
switch (sSpellMgr->CheckSpellGroupStackRules(GetSpellInfo(), (*auraIt)->GetSpellInfo()))
|
||||
{
|
||||
case SPELL_GROUP_STACK_RULE_EXCLUSIVE:
|
||||
return false;
|
||||
case SPELL_GROUP_STACK_RULE_EXCLUSIVE_FROM_SAME_CASTER:
|
||||
if (GetCaster() == (*auraIt)->GetCaster())
|
||||
return false;
|
||||
break;
|
||||
case SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT: // this one has further checks, but i don't think they're necessary for autocast logic
|
||||
case SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST:
|
||||
if (abs(spellEffectInfo.BasePoints) <= abs((*auraIt)->GetAmount()))
|
||||
return false;
|
||||
break;
|
||||
case SPELL_GROUP_STACK_RULE_DEFAULT:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7905,7 +7924,7 @@ bool Spell::CheckEffectTarget(Unit const* target, uint32 eff) const
|
||||
case SPELL_AURA_AOE_CHARM:
|
||||
if (target->IsCreature() && target->IsVehicle())
|
||||
return false;
|
||||
if (target->IsMounted())
|
||||
if (target->IsMounted() && m_spellInfo->Effects[eff].ApplyAuraName != SPELL_AURA_MOD_POSSESS)
|
||||
return false;
|
||||
if (target->GetCharmerGUID())
|
||||
return false;
|
||||
|
||||
@@ -1952,13 +1952,10 @@ void Spell::EffectEnergize(SpellEffIndex effIndex)
|
||||
Unit::AuraApplicationMap& Auras = unitTarget->GetAppliedAuras();
|
||||
for (Unit::AuraApplicationMap::iterator itr = Auras.begin(); itr != Auras.end(); ++itr)
|
||||
{
|
||||
SpellGroupSpecialFlags sFlag = sSpellMgr->GetSpellGroupSpecialFlags(itr->second->GetBase()->GetId());
|
||||
if (!guardianFound)
|
||||
if (sFlag & SPELL_GROUP_SPECIAL_FLAG_ELIXIR_GUARDIAN)
|
||||
guardianFound = true;
|
||||
if (!battleFound)
|
||||
if (sFlag & SPELL_GROUP_SPECIAL_FLAG_ELIXIR_BATTLE)
|
||||
battleFound = true;
|
||||
if (!guardianFound && sSpellMgr->IsSpellMemberOfSpellGroup(itr->second->GetBase()->GetId(), SPELL_GROUP_ELIXIR_GUARDIAN))
|
||||
guardianFound = true;
|
||||
if (!battleFound && sSpellMgr->IsSpellMemberOfSpellGroup(itr->second->GetBase()->GetId(), SPELL_GROUP_ELIXIR_BATTLE))
|
||||
battleFound = true;
|
||||
if (battleFound && guardianFound)
|
||||
break;
|
||||
}
|
||||
@@ -1966,9 +1963,9 @@ void Spell::EffectEnergize(SpellEffIndex effIndex)
|
||||
// get all available elixirs by mask and spell level
|
||||
std::set<uint32> availableElixirs;
|
||||
if (!guardianFound)
|
||||
sSpellMgr->GetSetOfSpellsInSpellGroupWithFlag(1, SPELL_GROUP_SPECIAL_FLAG_ELIXIR_GUARDIAN, availableElixirs);
|
||||
sSpellMgr->GetSetOfSpellsInSpellGroup(SPELL_GROUP_ELIXIR_GUARDIAN, availableElixirs);
|
||||
if (!battleFound)
|
||||
sSpellMgr->GetSetOfSpellsInSpellGroupWithFlag(1, SPELL_GROUP_SPECIAL_FLAG_ELIXIR_BATTLE, availableElixirs);
|
||||
sSpellMgr->GetSetOfSpellsInSpellGroup(SPELL_GROUP_ELIXIR_BATTLE, availableElixirs);
|
||||
for (std::set<uint32>::iterator itr = availableElixirs.begin(); itr != availableElixirs.end();)
|
||||
{
|
||||
SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(*itr);
|
||||
@@ -3598,7 +3595,7 @@ void Spell::EffectWeaponDmg(SpellEffIndex effIndex)
|
||||
unitMod = UNIT_MOD_DAMAGE_RANGED;
|
||||
break;
|
||||
}
|
||||
float weapon_total_pct = m_caster->GetModifierValue(unitMod, TOTAL_PCT);
|
||||
float weapon_total_pct = m_caster->GetPctModifierValue(unitMod, TOTAL_PCT);
|
||||
fixed_bonus = int32(fixed_bonus * weapon_total_pct);
|
||||
spell_bonus = int32(spell_bonus * weapon_total_pct);
|
||||
}
|
||||
|
||||
@@ -326,9 +326,9 @@ std::array<SpellImplicitTargetInfo::StaticData, TOTAL_SPELL_TARGETS> SpellImplic
|
||||
SpellEffectInfo::SpellEffectInfo(SpellEntry const* spellEntry, SpellInfo const* spellInfo, uint8 effIndex)
|
||||
{
|
||||
_spellInfo = spellInfo;
|
||||
_effIndex = effIndex;
|
||||
EffectIndex = effIndex;
|
||||
Effect = spellEntry->Effect[effIndex];
|
||||
ApplyAuraName = spellEntry->EffectApplyAuraName[effIndex];
|
||||
ApplyAuraName = AuraType(spellEntry->EffectApplyAuraName[effIndex]);
|
||||
Amplitude = spellEntry->EffectAmplitude[effIndex];
|
||||
DieSides = spellEntry->EffectDieSides[effIndex];
|
||||
RealPointsPerLevel = spellEntry->EffectRealPointsPerLevel[effIndex];
|
||||
@@ -456,7 +456,7 @@ int32 SpellEffectInfo::CalcValue(Unit const* caster, int32 const* bp, Unit const
|
||||
value += PointsPerComboPoint * comboPoints;
|
||||
}
|
||||
|
||||
value = caster->ApplyEffectModifiers(_spellInfo, _effIndex, value);
|
||||
value = caster->ApplyEffectModifiers(_spellInfo, EffectIndex, value);
|
||||
|
||||
// amount multiplication based on caster's level
|
||||
if (!caster->IsControlledByPlayer() &&
|
||||
@@ -501,7 +501,7 @@ int32 SpellEffectInfo::CalcValue(Unit const* caster, int32 const* bp, Unit const
|
||||
break;
|
||||
}
|
||||
|
||||
if ((sSpellMgr->GetSpellInfo(_spellInfo->Effects[_effIndex].TriggerSpell) && sSpellMgr->GetSpellInfo(_spellInfo->Effects[_effIndex].TriggerSpell)->HasAttribute(SPELL_ATTR0_SCALES_WITH_CREATURE_LEVEL)) && _spellInfo->HasAttribute(SPELL_ATTR0_SCALES_WITH_CREATURE_LEVEL))
|
||||
if ((sSpellMgr->GetSpellInfo(_spellInfo->Effects[EffectIndex].TriggerSpell) && sSpellMgr->GetSpellInfo(_spellInfo->Effects[EffectIndex].TriggerSpell)->HasAttribute(SPELL_ATTR0_SCALES_WITH_CREATURE_LEVEL)) && _spellInfo->HasAttribute(SPELL_ATTR0_SCALES_WITH_CREATURE_LEVEL))
|
||||
canEffectScale = false;
|
||||
|
||||
if (canEffectScale)
|
||||
@@ -1579,122 +1579,6 @@ SpellCastResult SpellInfo::CheckLocation(uint32 map_id, uint32 zone_id, uint32 a
|
||||
|
||||
return SPELL_CAST_OK;
|
||||
}
|
||||
|
||||
bool SpellInfo::IsStrongerAuraActive(Unit const* caster, Unit const* target) const
|
||||
{
|
||||
if (!target)
|
||||
return false;
|
||||
|
||||
// xinef: check spell group
|
||||
uint32 groupId = sSpellMgr->GetSpellGroup(Id);
|
||||
if (!groupId)
|
||||
return false;
|
||||
|
||||
SpellGroupSpecialFlags sFlag = sSpellMgr->GetSpellGroupSpecialFlags(Id);
|
||||
if (sFlag & SPELL_GROUP_SPECIAL_FLAG_SKIP_STRONGER_CHECK)
|
||||
return false;
|
||||
|
||||
for (uint8 i = EFFECT_0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
{
|
||||
// xinef: Skip Empty effects
|
||||
if (!Effects[i].IsEffect())
|
||||
continue;
|
||||
|
||||
// xinef: if non-aura effect is preset - return false
|
||||
if (!Effects[i].IsAura())
|
||||
return false;
|
||||
|
||||
// xinef: aura is periodic - return false
|
||||
if (Effects[i].Amplitude)
|
||||
return false;
|
||||
|
||||
// xinef: exclude dummy auras
|
||||
if (Effects[i].ApplyAuraName == SPELL_AURA_DUMMY)
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint8 i = EFFECT_0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
{
|
||||
// xinef: skip non-aura efects
|
||||
if (!Effects[i].IsAura())
|
||||
return false;
|
||||
|
||||
Unit::AuraEffectList const& auraList = target->GetAuraEffectsByType((AuraType)Effects[i].ApplyAuraName);
|
||||
for (Unit::AuraEffectList::const_iterator iter = auraList.begin(); iter != auraList.end(); ++iter)
|
||||
{
|
||||
// xinef: aura is not groupped or in different group
|
||||
uint32 auraGroup = (*iter)->GetAuraGroup();
|
||||
if (!auraGroup || auraGroup != groupId)
|
||||
continue;
|
||||
|
||||
if (IsRankOf((*iter)->GetSpellInfo()) && (sFlag & SPELL_GROUP_SPECIAL_FLAG_SKIP_STRONGER_SAME_SPELL))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// xinef: check priority before effect mask
|
||||
if (sFlag >= SPELL_GROUP_SPECIAL_FLAG_PRIORITY1 && sFlag <= SPELL_GROUP_SPECIAL_FLAG_PRIORITY4)
|
||||
{
|
||||
SpellGroupSpecialFlags sFlagCurr = sSpellMgr->GetSpellGroupSpecialFlags((*iter)->GetId());
|
||||
if (sFlagCurr >= SPELL_GROUP_SPECIAL_FLAG_PRIORITY1 && sFlagCurr <= SPELL_GROUP_SPECIAL_FLAG_PRIORITY4 && sFlagCurr < sFlag)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// xinef: check aura effect equal auras only, some auras have different effects on different ranks - check rank also
|
||||
if (!IsAuraEffectEqual((*iter)->GetSpellInfo()) && !IsRankOf((*iter)->GetSpellInfo()))
|
||||
continue;
|
||||
|
||||
// xinef: misc value mismatches
|
||||
// xinef: commented, checked above
|
||||
//if (Effects[i].MiscValue != (*iter)->GetMiscValue())
|
||||
// continue;
|
||||
|
||||
// xinef: should not happen, or effect is not active - stronger one is present
|
||||
AuraApplication* aurApp = (*iter)->GetBase()->GetApplicationOfTarget(target->GetGUID());
|
||||
if (!aurApp || !aurApp->IsActive((*iter)->GetEffIndex()))
|
||||
continue;
|
||||
|
||||
// xinef: assume that all spells are either positive or negative, otherwise they should not be in one group
|
||||
// xinef: take custom values into account
|
||||
|
||||
int32 basePoints = Effects[i].BasePoints;
|
||||
int32 duration = GetMaxDuration();
|
||||
|
||||
// xinef: should have the same id, can be different if spell is triggered
|
||||
// xinef: have to fix spell mods for triggered spell, turn off current spellmodtakingspell for preparing and restore after
|
||||
if (Player const* player = caster->GetSpellModOwner())
|
||||
if (player->m_spellModTakingSpell && player->m_spellModTakingSpell->m_spellInfo->Id == Id)
|
||||
basePoints = player->m_spellModTakingSpell->GetSpellValue()->EffectBasePoints[i];
|
||||
|
||||
int32 curValue = std::abs(Effects[i].CalcValue(caster, &basePoints));
|
||||
int32 auraValue = (sFlag & SPELL_GROUP_SPECIAL_FLAG_BASE_AMOUNT_CHECK) ?
|
||||
std::abs((*iter)->GetSpellInfo()->Effects[(*iter)->GetEffIndex()].CalcValue((*iter)->GetCaster())) :
|
||||
std::abs((*iter)->GetAmount());
|
||||
|
||||
// xinef: for same spells, divide amount by stack amount
|
||||
if (Id == (*iter)->GetId())
|
||||
auraValue /= (*iter)->GetBase()->GetStackAmount();
|
||||
|
||||
if (curValue < auraValue)
|
||||
return true;
|
||||
|
||||
// xinef: little hack, if current spell is the same as aura spell, asume it is not stronger
|
||||
// xinef: if values are the same, duration mods should be taken into account but they are almost always passive
|
||||
if (curValue == auraValue)
|
||||
{
|
||||
if (Id == (*iter)->GetId())
|
||||
continue;
|
||||
if (!(*iter)->GetBase()->IsPassive() && duration < (*iter)->GetBase()->GetDuration())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SpellInfo::IsAuraEffectEqual(SpellInfo const* otherSpellInfo) const
|
||||
{
|
||||
uint8 matchCount = 0;
|
||||
@@ -1938,10 +1822,6 @@ SpellCastResult SpellInfo::CheckTarget(Unit const* caster, WorldObject const* ta
|
||||
if (HasEffect(SPELL_EFFECT_SELF_RESURRECT) || HasEffect(SPELL_EFFECT_RESURRECT) || HasEffect(SPELL_EFFECT_RESURRECT_NEW))
|
||||
return SPELL_FAILED_TARGET_CANNOT_BE_RESURRECTED;
|
||||
|
||||
// xinef: check if stronger aura is active
|
||||
if (IsStrongerAuraActive(caster, unitTarget))
|
||||
return SPELL_FAILED_AURA_BOUNCED;
|
||||
|
||||
return SPELL_CAST_OK;
|
||||
}
|
||||
|
||||
@@ -2316,6 +2196,8 @@ SpellSpecificType SpellInfo::LoadSpellSpecific() const
|
||||
case SPELL_AURA_TRACK_RESOURCES:
|
||||
case SPELL_AURA_TRACK_STEALTHED:
|
||||
return SPELL_SPECIFIC_TRACKER;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2399,6 +2281,8 @@ uint32 SpellInfo::GetMaxTicks() const
|
||||
if (Effects[x].Amplitude != 0)
|
||||
return DotDuration / Effects[x].Amplitude;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2889,50 +2773,3 @@ void SpellInfo::_UnloadImplicitTargetConditionLists()
|
||||
delete cur;
|
||||
}
|
||||
}
|
||||
|
||||
bool SpellInfo::CheckElixirStacking(Unit const* caster) const
|
||||
{
|
||||
if (!caster)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// xinef: check spell group
|
||||
uint32 groupId = sSpellMgr->GetSpellGroup(Id);
|
||||
if (groupId != SPELL_GROUP_GUARDIAN_AND_BATTLE_ELIXIRS)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
SpellGroupSpecialFlags sFlag = sSpellMgr->GetSpellGroupSpecialFlags(Id);
|
||||
for (uint8 i = EFFECT_0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
{
|
||||
if (!Effects[i].IsAura())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Unit::AuraApplicationMap const& Auras = caster->GetAppliedAuras();
|
||||
for (Unit::AuraApplicationMap::const_iterator itr = Auras.begin(); itr != Auras.end(); ++itr)
|
||||
{
|
||||
// xinef: aura is not groupped or in different group
|
||||
uint32 auraGroup = sSpellMgr->GetSpellGroup(itr->first);
|
||||
if (auraGroup != groupId)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Cannot apply guardian/battle elixir if flask is present
|
||||
if (sFlag == SPELL_GROUP_SPECIAL_FLAG_ELIXIR_BATTLE || sFlag == SPELL_GROUP_SPECIAL_FLAG_ELIXIR_GUARDIAN)
|
||||
{
|
||||
SpellGroupSpecialFlags sAuraFlag = sSpellMgr->GetSpellGroupSpecialFlags(itr->first);
|
||||
if ((sAuraFlag & SPELL_GROUP_SPECIAL_FLAG_FLASK) == SPELL_GROUP_SPECIAL_FLAG_FLASK)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -248,10 +248,10 @@ private:
|
||||
class SpellEffectInfo
|
||||
{
|
||||
SpellInfo const* _spellInfo;
|
||||
uint8 _effIndex;
|
||||
public:
|
||||
uint8 EffectIndex;
|
||||
uint32 Effect;
|
||||
uint32 ApplyAuraName;
|
||||
AuraType ApplyAuraName;
|
||||
uint32 Amplitude;
|
||||
int32 DieSides;
|
||||
float RealPointsPerLevel;
|
||||
@@ -272,7 +272,7 @@ public:
|
||||
flag96 SpellClassMask;
|
||||
std::list<Condition*>* ImplicitTargetConditions;
|
||||
|
||||
SpellEffectInfo() : _spellInfo(nullptr), _effIndex(0), Effect(0), ApplyAuraName(0), Amplitude(0), DieSides(0),
|
||||
SpellEffectInfo() : _spellInfo(nullptr), EffectIndex(0), Effect(0), ApplyAuraName(SPELL_AURA_NONE), Amplitude(0), DieSides(0),
|
||||
RealPointsPerLevel(0), BasePoints(0), PointsPerComboPoint(0), ValueMultiplier(0), DamageMultiplier(0),
|
||||
BonusMultiplier(0), MiscValue(0), MiscValueB(0), Mechanic(MECHANIC_NONE), RadiusEntry(nullptr), ChainTarget(0),
|
||||
ItemType(0), TriggerSpell(0), ImplicitTargetConditions(nullptr) {}
|
||||
@@ -482,8 +482,6 @@ public:
|
||||
SpellCastResult CheckExplicitTarget(Unit const* caster, WorldObject const* target, Item const* itemTarget = nullptr) const;
|
||||
bool CheckTargetCreatureType(Unit const* target) const;
|
||||
|
||||
// xinef: aura stacking
|
||||
bool IsStrongerAuraActive(Unit const* caster, Unit const* target) const;
|
||||
bool IsAuraEffectEqual(SpellInfo const* otherSpellInfo) const;
|
||||
bool ValidateAttribute6SpellDamageMods(Unit const* caster, const AuraEffect* auraEffect, bool isDot) const;
|
||||
|
||||
@@ -539,8 +537,6 @@ public:
|
||||
// unloading helpers
|
||||
void _UnloadImplicitTargetConditionLists();
|
||||
|
||||
bool CheckElixirStacking(Unit const* caster) const;
|
||||
|
||||
private:
|
||||
std::array<SpellEffectInfo, MAX_SPELL_EFFECTS>& _GetEffects() { return Effects; }
|
||||
SpellEffectInfo& _GetEffect(SpellEffIndex index) { ASSERT(index < Effects.size()); return Effects[index]; }
|
||||
|
||||
@@ -570,14 +570,6 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPPRESS_CASTER_PROCS;
|
||||
});
|
||||
|
||||
// Blessing of sanctuary stats
|
||||
ApplySpellFix({ 67480 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->Effects[EFFECT_0].MiscValue = -1;
|
||||
spellInfo->SpellFamilyName = SPELLFAMILY_UNK1; // allows stacking
|
||||
spellInfo->Effects[EFFECT_1].ApplyAuraName = SPELL_AURA_DUMMY; // just a marker
|
||||
});
|
||||
|
||||
ApplySpellFix({
|
||||
6940, // Hand of Sacrifice
|
||||
64205 // Divine Sacrifice
|
||||
@@ -5164,6 +5156,20 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
spellInfo->AttributesEx3 |= SPELL_ATTR3_DOT_STACKING_RULE;
|
||||
});
|
||||
|
||||
// King Mrlg-Mrgl's Spare Suit
|
||||
ApplySpellFix({ 45278 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->ProcCharges = 1;
|
||||
});
|
||||
|
||||
ApplySpellFix({
|
||||
56917, // To Icecrown Airship - Teleport to Airship (A)
|
||||
57417, // To Icecrown Airship - Teleport to Airship (H)
|
||||
}, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(6); // 100 yards
|
||||
});
|
||||
|
||||
for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
|
||||
{
|
||||
SpellInfo* spellInfo = mSpellInfoMap[i];
|
||||
@@ -5285,14 +5291,6 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
factionTemplateEntry = const_cast<FactionTemplateEntry*>(sFactionTemplateStore.LookupEntry(1921)); // The Taunka
|
||||
factionTemplateEntry->hostileMask |= 8;
|
||||
|
||||
// Remove 1 from guards friendly mask, making able to attack players
|
||||
factionTemplateEntry = const_cast<FactionTemplateEntry*>(sFactionTemplateStore.LookupEntry(1857)); // Area 52 Bruiser
|
||||
factionTemplateEntry->friendlyMask &= ~1;
|
||||
factionTemplateEntry = const_cast<FactionTemplateEntry*>(sFactionTemplateStore.LookupEntry(1806)); // Netherstorm Agent
|
||||
factionTemplateEntry->friendlyMask &= ~1;
|
||||
factionTemplateEntry = const_cast<FactionTemplateEntry*>(sFactionTemplateStore.LookupEntry(1812)); // K3 Bruiser
|
||||
factionTemplateEntry->friendlyMask &= ~1;
|
||||
|
||||
// Remove vehicles attr, making accessories selectable
|
||||
VehicleSeatEntry* vse = const_cast<VehicleSeatEntry*>(sVehicleSeatStore.LookupEntry(4689)); // Siege Engine, Accessory
|
||||
vse->m_flags &= ~VEHICLE_SEAT_FLAG_PASSENGER_NOT_SELECTABLE;
|
||||
|
||||
+310
-123
@@ -18,12 +18,9 @@
|
||||
#include "SpellMgr.h"
|
||||
#include "BattlefieldMgr.h"
|
||||
#include "BattlegroundIC.h"
|
||||
#include "BattlegroundMgr.h"
|
||||
#include "Chat.h"
|
||||
#include "DBCStores.h"
|
||||
#include "GameGraveyard.h"
|
||||
#include "InstanceScript.h"
|
||||
#include "MapMgr.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Player.h"
|
||||
#include "ScriptMgr.h"
|
||||
@@ -648,82 +645,143 @@ SpellTargetPosition const* SpellMgr::GetSpellTargetPosition(uint32 spell_id, Spe
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SpellGroupStackFlags SpellMgr::GetGroupStackFlags(uint32 groupid) const
|
||||
SpellSpellGroupMapBounds SpellMgr::GetSpellSpellGroupMapBounds(uint32 spell_id) const
|
||||
{
|
||||
SpellGroupStackMap::const_iterator itr = mSpellGroupStackMap.find(groupid);
|
||||
if (itr != mSpellGroupStackMap.end())
|
||||
spell_id = GetFirstSpellInChain(spell_id);
|
||||
return mSpellSpellGroup.equal_range(spell_id);
|
||||
}
|
||||
|
||||
bool SpellMgr::IsSpellMemberOfSpellGroup(uint32 spell_id, SpellGroup group_id) const
|
||||
{
|
||||
SpellSpellGroupMapBounds spellGroup = GetSpellSpellGroupMapBounds(spell_id);
|
||||
for (SpellSpellGroupMap::const_iterator itr = spellGroup.first; itr != spellGroup.second; ++itr)
|
||||
{
|
||||
if (itr->second == group_id)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
SpellGroupSpellMapBounds SpellMgr::GetSpellGroupSpellMapBounds(SpellGroup group_id) const
|
||||
{
|
||||
return mSpellGroupSpell.equal_range(group_id);
|
||||
}
|
||||
|
||||
void SpellMgr::GetSetOfSpellsInSpellGroup(SpellGroup group_id, std::set<uint32>& foundSpells) const
|
||||
{
|
||||
std::set<SpellGroup> usedGroups;
|
||||
GetSetOfSpellsInSpellGroup(group_id, foundSpells, usedGroups);
|
||||
}
|
||||
|
||||
void SpellMgr::GetSetOfSpellsInSpellGroup(SpellGroup group_id, std::set<uint32>& foundSpells, std::set<SpellGroup>& usedGroups) const
|
||||
{
|
||||
if (usedGroups.find(group_id) != usedGroups.end())
|
||||
return;
|
||||
usedGroups.insert(group_id);
|
||||
|
||||
SpellGroupSpellMapBounds groupSpell = GetSpellGroupSpellMapBounds(group_id);
|
||||
for (SpellGroupSpellMap::const_iterator itr = groupSpell.first; itr != groupSpell.second; ++itr)
|
||||
{
|
||||
if (itr->second < 0)
|
||||
{
|
||||
SpellGroup currGroup = (SpellGroup)abs(itr->second);
|
||||
GetSetOfSpellsInSpellGroup(currGroup, foundSpells, usedGroups);
|
||||
}
|
||||
else
|
||||
{
|
||||
foundSpells.insert(itr->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SpellMgr::AddSameEffectStackRuleSpellGroups(SpellInfo const* spellInfo, uint32 auraType, int32 amount, std::map<SpellGroup, int32>& groups) const
|
||||
{
|
||||
uint32 spellId = spellInfo->GetFirstRankSpell()->Id;
|
||||
auto spellGroupBounds = GetSpellSpellGroupMapBounds(spellId);
|
||||
// Find group with SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT if it belongs to one
|
||||
for (auto itr = spellGroupBounds.first; itr != spellGroupBounds.second; ++itr)
|
||||
{
|
||||
SpellGroup group = itr->second;
|
||||
auto found = mSpellSameEffectStack.find(group);
|
||||
if (found != mSpellSameEffectStack.end())
|
||||
{
|
||||
// check auraTypes
|
||||
if (!found->second.count(auraType))
|
||||
continue;
|
||||
|
||||
// Put the highest amount in the map
|
||||
auto groupItr = groups.find(group);
|
||||
if (groupItr == groups.end())
|
||||
groups.emplace(group, amount);
|
||||
else
|
||||
{
|
||||
int32 curr_amount = groups[group];
|
||||
// Take absolute value because this also counts for the highest negative aura
|
||||
if (std::abs(curr_amount) < std::abs(amount))
|
||||
groupItr->second = amount;
|
||||
}
|
||||
// return because a spell should be in only one SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT group per auraType
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// Not in a SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT group, so return false
|
||||
return false;
|
||||
}
|
||||
|
||||
SpellGroupStackRule SpellMgr::CheckSpellGroupStackRules(SpellInfo const* spellInfo1, SpellInfo const* spellInfo2) const
|
||||
{
|
||||
ASSERT(spellInfo1);
|
||||
ASSERT(spellInfo2);
|
||||
|
||||
uint32 spell_id1 = spellInfo1->GetFirstRankSpell()->Id;
|
||||
uint32 spell_id2 = spellInfo2->GetFirstRankSpell()->Id;
|
||||
|
||||
// find SpellGroups which are common for both spells
|
||||
SpellSpellGroupMapBounds spellGroup1 = GetSpellSpellGroupMapBounds(spell_id1);
|
||||
std::set<SpellGroup> groups;
|
||||
for (SpellSpellGroupMap::const_iterator itr = spellGroup1.first; itr != spellGroup1.second; ++itr)
|
||||
{
|
||||
if (IsSpellMemberOfSpellGroup(spell_id2, itr->second))
|
||||
{
|
||||
bool add = true;
|
||||
SpellGroupSpellMapBounds groupSpell = GetSpellGroupSpellMapBounds(itr->second);
|
||||
for (SpellGroupSpellMap::const_iterator itr2 = groupSpell.first; itr2 != groupSpell.second; ++itr2)
|
||||
{
|
||||
if (itr2->second < 0)
|
||||
{
|
||||
SpellGroup currGroup = (SpellGroup)abs(itr2->second);
|
||||
if (IsSpellMemberOfSpellGroup(spell_id1, currGroup) && IsSpellMemberOfSpellGroup(spell_id2, currGroup))
|
||||
{
|
||||
add = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (add)
|
||||
groups.insert(itr->second);
|
||||
}
|
||||
}
|
||||
|
||||
SpellGroupStackRule rule = SPELL_GROUP_STACK_RULE_DEFAULT;
|
||||
|
||||
for (std::set<SpellGroup>::iterator itr = groups.begin(); itr!= groups.end(); ++itr)
|
||||
{
|
||||
SpellGroupStackMap::const_iterator found = mSpellGroupStack.find(*itr);
|
||||
if (found != mSpellGroupStack.end())
|
||||
rule = found->second;
|
||||
if (rule)
|
||||
break;
|
||||
}
|
||||
return rule;
|
||||
}
|
||||
|
||||
SpellGroupStackRule SpellMgr::GetSpellGroupStackRule(SpellGroup group) const
|
||||
{
|
||||
SpellGroupStackMap::const_iterator itr = mSpellGroupStack.find(group);
|
||||
if (itr != mSpellGroupStack.end())
|
||||
return itr->second;
|
||||
|
||||
return SPELL_GROUP_STACK_FLAG_NONE;
|
||||
}
|
||||
|
||||
uint32 SpellMgr::GetSpellGroup(uint32 spell_id) const
|
||||
{
|
||||
uint32 first_rank = GetFirstSpellInChain(spell_id);
|
||||
SpellGroupMap::const_iterator itr = mSpellGroupMap.find(first_rank);
|
||||
if (itr != mSpellGroupMap.end())
|
||||
return itr->second.groupId;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SpellGroupSpecialFlags SpellMgr::GetSpellGroupSpecialFlags(uint32 spell_id) const
|
||||
{
|
||||
uint32 first_rank = GetFirstSpellInChain(spell_id);
|
||||
SpellGroupMap::const_iterator itr = mSpellGroupMap.find(first_rank);
|
||||
if (itr != mSpellGroupMap.end())
|
||||
return itr->second.specialFlags;
|
||||
|
||||
return SPELL_GROUP_SPECIAL_FLAG_NONE;
|
||||
}
|
||||
|
||||
SpellGroupStackFlags SpellMgr::CheckSpellGroupStackRules(SpellInfo const* spellInfo1, SpellInfo const* spellInfo2, bool remove, bool areaAura) const
|
||||
{
|
||||
uint32 spellid_1 = spellInfo1->GetFirstRankSpell()->Id;
|
||||
uint32 spellid_2 = spellInfo2->GetFirstRankSpell()->Id;
|
||||
|
||||
uint32 groupId = GetSpellGroup(spellid_1);
|
||||
|
||||
SpellGroupSpecialFlags flag1 = GetSpellGroupSpecialFlags(spellid_1);
|
||||
|
||||
// xinef: dunno why i added this
|
||||
if (spellid_1 == spellid_2 && remove && !areaAura)
|
||||
{
|
||||
if (flag1 & SPELL_GROUP_SPECIAL_FLAG_SAME_SPELL_CHECK)
|
||||
{
|
||||
return SPELL_GROUP_STACK_FLAG_EXCLUSIVE;
|
||||
}
|
||||
|
||||
return SPELL_GROUP_STACK_FLAG_NONE;
|
||||
}
|
||||
|
||||
if (groupId > 0 && groupId == GetSpellGroup(spellid_2))
|
||||
{
|
||||
SpellGroupSpecialFlags flag2 = GetSpellGroupSpecialFlags(spellid_2);
|
||||
SpellGroupStackFlags additionFlag = SPELL_GROUP_STACK_FLAG_NONE;
|
||||
// xinef: first flags are used for elixir stacking rules
|
||||
if (flag1 & SPELL_GROUP_SPECIAL_FLAG_STACK_EXCLUSIVE_MAX && flag2 & SPELL_GROUP_SPECIAL_FLAG_STACK_EXCLUSIVE_MAX)
|
||||
{
|
||||
if (flag1 & flag2)
|
||||
return SPELL_GROUP_STACK_FLAG_NEVER_STACK;
|
||||
}
|
||||
// xinef: check only flag1 (new spell)
|
||||
else if (flag1 & SPELL_GROUP_SPECIAL_FLAG_FORCED_STRONGEST)
|
||||
additionFlag = SPELL_GROUP_STACK_FLAG_FORCED_STRONGEST;
|
||||
else if (flag2 & SPELL_GROUP_SPECIAL_FLAG_FORCED_STRONGEST)
|
||||
additionFlag = SPELL_GROUP_STACK_FLAG_FORCED_WEAKEST;
|
||||
|
||||
return SpellGroupStackFlags(GetGroupStackFlags(groupId) | additionFlag);
|
||||
}
|
||||
|
||||
return SPELL_GROUP_STACK_FLAG_NONE;
|
||||
}
|
||||
|
||||
void SpellMgr::GetSetOfSpellsInSpellGroupWithFlag(uint32 group_id, SpellGroupSpecialFlags flag, std::set<uint32>& availableElixirs) const
|
||||
{
|
||||
for (SpellGroupMap::const_iterator itr = mSpellGroupMap.begin(); itr != mSpellGroupMap.end(); ++itr)
|
||||
if (itr->second.groupId == group_id && itr->second.specialFlags == flag)
|
||||
availableElixirs.insert(itr->first); // insert spell id
|
||||
return SPELL_GROUP_STACK_RULE_DEFAULT;
|
||||
}
|
||||
|
||||
SpellProcEventEntry const* SpellMgr::GetSpellProcEvent(uint32 spellId) const
|
||||
@@ -1627,10 +1685,11 @@ void SpellMgr::LoadSpellGroups()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
mSpellGroupMap.clear(); // need for reload case
|
||||
mSpellSpellGroup.clear(); // need for reload case
|
||||
mSpellGroupSpell.clear();
|
||||
|
||||
// 0 1 2
|
||||
QueryResult result = WorldDatabase.Query("SELECT id, spell_id, special_flag FROM spell_group");
|
||||
// 0 1
|
||||
QueryResult result = WorldDatabase.Query("SELECT id, spell_id FROM spell_group");
|
||||
if (!result)
|
||||
{
|
||||
LOG_WARN("server.loading", ">> Loaded 0 spell group definitions. DB table `spell_group` is empty.");
|
||||
@@ -1638,48 +1697,68 @@ void SpellMgr::LoadSpellGroups()
|
||||
return;
|
||||
}
|
||||
|
||||
std::set<uint32> groups;
|
||||
uint32 count = 0;
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
uint32 group_id = fields[0].Get<uint32>();
|
||||
int32 spell_id = fields[1].Get<uint32>();
|
||||
SpellGroupSpecialFlags specialFlag = (SpellGroupSpecialFlags)fields[2].Get<uint32>();
|
||||
SpellInfo const* spellInfo = GetSpellInfo(spell_id);
|
||||
|
||||
if (!spellInfo)
|
||||
if (group_id <= SPELL_GROUP_DB_RANGE_MIN && group_id >= SPELL_GROUP_CORE_RANGE_MAX)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Spell {} listed in `spell_group` does not exist", spell_id);
|
||||
continue;
|
||||
}
|
||||
else if (spellInfo->GetRank() > 1)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Spell {} listed in `spell_group` is not first rank of spell", spell_id);
|
||||
LOG_ERROR("sql.sql", "SpellGroup id {} listed in `spell_group` is in core range, but is not defined in core!", group_id);
|
||||
continue;
|
||||
}
|
||||
int32 spell_id = fields[1].Get<int32>();
|
||||
|
||||
if (mSpellGroupMap.find(spell_id) != mSpellGroupMap.end())
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Spell {} listed in `spell_group` has more than one group", spell_id);
|
||||
continue;
|
||||
}
|
||||
groups.insert(group_id);
|
||||
mSpellGroupSpell.emplace(SpellGroup(group_id), spell_id);
|
||||
|
||||
if (specialFlag >= SPELL_GROUP_SPECIAL_FLAG_MAX)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Spell {} listed in `spell_group` has invalid special flag!", spell_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
SpellStackInfo ssi;
|
||||
ssi.groupId = group_id;
|
||||
ssi.specialFlags = specialFlag;
|
||||
mSpellGroupMap[spell_id] = ssi;
|
||||
|
||||
++count;
|
||||
} while (result->NextRow());
|
||||
|
||||
LOG_INFO("server.loading", ">> Loaded {} Spell Group Definitions in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
for (auto itr = mSpellGroupSpell.begin(); itr!= mSpellGroupSpell.end();)
|
||||
{
|
||||
if (itr->second < 0)
|
||||
{
|
||||
if (groups.find(abs(itr->second)) == groups.end())
|
||||
{
|
||||
LOG_ERROR("sql.sql", "SpellGroup id {} listed in `spell_group` does not exist", abs(itr->second));
|
||||
itr = mSpellGroupSpell.erase(itr);
|
||||
}
|
||||
else
|
||||
++itr;
|
||||
}
|
||||
else
|
||||
{
|
||||
SpellInfo const* spellInfo = GetSpellInfo(itr->second);
|
||||
if (!spellInfo)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Spell {} listed in `spell_group` does not exist", itr->second);
|
||||
itr = mSpellGroupSpell.erase(itr);
|
||||
}
|
||||
else if (spellInfo->GetRank() > 1)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Spell {} listed in `spell_group` is not first rank of spell.", itr->second);
|
||||
itr = mSpellGroupSpell.erase(itr);
|
||||
}
|
||||
else
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto groupItr = groups.begin(); groupItr != groups.end(); ++groupItr)
|
||||
{
|
||||
std::set<uint32> spells;
|
||||
GetSetOfSpellsInSpellGroup(SpellGroup(*groupItr), spells);
|
||||
|
||||
for (auto spellItr = spells.begin(); spellItr != spells.end(); ++spellItr)
|
||||
{
|
||||
++count;
|
||||
mSpellSpellGroup.emplace(*spellItr, SpellGroup(*groupItr));
|
||||
}
|
||||
}
|
||||
|
||||
LOG_INFO("server.loading", ">> Loaded {} spell group Definitions in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
LOG_INFO("server.loading", " ");
|
||||
}
|
||||
|
||||
@@ -1687,7 +1766,10 @@ void SpellMgr::LoadSpellGroupStackRules()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
mSpellGroupStackMap.clear(); // need for reload case
|
||||
mSpellGroupStack.clear(); // need for reload case
|
||||
mSpellSameEffectStack.clear();
|
||||
|
||||
std::vector<uint32> sameEffectGroups;
|
||||
|
||||
// 0 1
|
||||
QueryResult result = WorldDatabase.Query("SELECT group_id, stack_rule FROM spell_group_stack_rules");
|
||||
@@ -1705,32 +1787,132 @@ void SpellMgr::LoadSpellGroupStackRules()
|
||||
|
||||
uint32 group_id = fields[0].Get<uint32>();
|
||||
uint8 stack_rule = fields[1].Get<int8>();
|
||||
if (stack_rule >= SPELL_GROUP_STACK_FLAG_MAX)
|
||||
if (stack_rule >= SPELL_GROUP_STACK_RULE_MAX)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "SpellGroupStackRule {} listed in `spell_group_stack_rules` does not exist", stack_rule);
|
||||
LOG_ERROR("sql.sql", "SpellGroupStackRule {} listed in `spell_group_stack_rules` does not exist.", stack_rule);
|
||||
continue;
|
||||
}
|
||||
|
||||
bool present = false;
|
||||
for (SpellGroupMap::const_iterator itr = mSpellGroupMap.begin(); itr != mSpellGroupMap.end(); ++itr)
|
||||
if (itr->second.groupId == group_id)
|
||||
{
|
||||
present = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!present)
|
||||
auto bounds = GetSpellGroupSpellMapBounds((SpellGroup)group_id);
|
||||
if (bounds.first == bounds.second)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "SpellGroup id {} listed in `spell_group_stack_rules` does not exist", group_id);
|
||||
LOG_ERROR("sql.sql", "SpellGroup id {} listed in `spell_group_stack_rules` does not exist.", group_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
mSpellGroupStackMap[group_id] = (SpellGroupStackFlags)stack_rule;
|
||||
mSpellGroupStack.emplace(SpellGroup(group_id), SpellGroupStackRule(stack_rule));
|
||||
|
||||
// different container for same effect stack rules, need to check effect types
|
||||
if (stack_rule == SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT)
|
||||
sameEffectGroups.push_back(group_id);
|
||||
|
||||
++count;
|
||||
} while (result->NextRow());
|
||||
|
||||
LOG_INFO("server.loading", ">> Loaded {} Spell Group Stack Rules in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
LOG_INFO("server.loading", ">> Loaded {} spell group stack rules in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
LOG_INFO("server.loading", " ");
|
||||
|
||||
count = 0;
|
||||
oldMSTime = getMSTime();
|
||||
|
||||
for (uint32 group_id : sameEffectGroups)
|
||||
{
|
||||
std::set<uint32> spellIds;
|
||||
GetSetOfSpellsInSpellGroup(SpellGroup(group_id), spellIds);
|
||||
|
||||
std::unordered_set<uint32> auraTypes;
|
||||
|
||||
// we have to 'guess' what effect this group corresponds to
|
||||
{
|
||||
std::unordered_multiset<uint32 /*auraName*/> frequencyContainer;
|
||||
|
||||
// only waylay for the moment (shared group)
|
||||
std::vector<std::vector<uint32 /*auraName*/>> const SubGroups =
|
||||
{
|
||||
{ SPELL_AURA_MOD_MELEE_HASTE, SPELL_AURA_MOD_MELEE_RANGED_HASTE, SPELL_AURA_MOD_RANGED_HASTE }
|
||||
};
|
||||
|
||||
for (uint32 spellId : spellIds)
|
||||
{
|
||||
SpellInfo const* spellInfo = AssertSpellInfo(spellId);
|
||||
for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
|
||||
{
|
||||
if (!spellEffectInfo.IsAura())
|
||||
continue;
|
||||
|
||||
uint32 auraName = spellEffectInfo.ApplyAuraName;
|
||||
for (std::vector<uint32> const& subGroup : SubGroups)
|
||||
{
|
||||
if (std::find(subGroup.begin(), subGroup.end(), auraName) != subGroup.end())
|
||||
{
|
||||
// count as first aura
|
||||
auraName = subGroup.front();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
frequencyContainer.insert(auraName);
|
||||
}
|
||||
}
|
||||
|
||||
uint32 auraType = 0;
|
||||
size_t auraTypeCount = 0;
|
||||
for (uint32 auraName : frequencyContainer)
|
||||
{
|
||||
size_t currentCount = frequencyContainer.count(auraName);
|
||||
if (currentCount > auraTypeCount)
|
||||
{
|
||||
auraType = auraName;
|
||||
auraTypeCount = currentCount;
|
||||
}
|
||||
}
|
||||
|
||||
for (std::vector<uint32> const& subGroup : SubGroups)
|
||||
{
|
||||
if (auraType == subGroup.front())
|
||||
{
|
||||
auraTypes.insert(subGroup.begin(), subGroup.end());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (auraTypes.empty())
|
||||
auraTypes.insert(auraType);
|
||||
}
|
||||
|
||||
// re-check spells against guessed group
|
||||
for (uint32 spellId : spellIds)
|
||||
{
|
||||
SpellInfo const* spellInfo = AssertSpellInfo(spellId);
|
||||
|
||||
bool found = false;
|
||||
while (spellInfo)
|
||||
{
|
||||
for (uint32 auraType : auraTypes)
|
||||
{
|
||||
if (spellInfo->HasAura(AuraType(auraType)))
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found)
|
||||
break;
|
||||
|
||||
spellInfo = spellInfo->GetNextRankSpell();
|
||||
}
|
||||
|
||||
// not found either, log error
|
||||
if (!found)
|
||||
LOG_ERROR("sql.sql", "SpellId {} listed in `spell_group` with stack rule 3 does not share aura assigned for group {}", spellId, group_id);
|
||||
}
|
||||
|
||||
mSpellSameEffectStack[SpellGroup(group_id)] = auraTypes;
|
||||
++count;
|
||||
}
|
||||
|
||||
LOG_INFO("server.loading", ">> Loaded {} SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT stack rules in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
LOG_INFO("server.loading", " ");
|
||||
}
|
||||
|
||||
@@ -2920,6 +3102,8 @@ void SpellMgr::LoadSpellInfoCustomAttributes()
|
||||
case SPELL_AURA_WATER_BREATHING:
|
||||
spellInfo->AttributesCu |= SPELL_ATTR0_CU_NO_INITIAL_THREAT;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (spellInfo->Effects[j].ApplyAuraName)
|
||||
@@ -3494,6 +3678,9 @@ void SpellMgr::LoadSpellInfoCustomAttributes()
|
||||
if (triggerSpell->AttributesCu & SPELL_ATTR0_CU_BINARY_SPELL)
|
||||
allNonBinary = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
|
||||
// For static or at-server-startup loaded spell data
|
||||
|
||||
#include "Common.h"
|
||||
#include "Log.h"
|
||||
#include "SharedDefines.h"
|
||||
#include "Unit.h"
|
||||
@@ -330,56 +329,49 @@ struct SpellBonusEntry
|
||||
|
||||
typedef std::unordered_map<uint32, SpellBonusEntry> SpellBonusMap;
|
||||
|
||||
enum SpellGroupSpecialFlags
|
||||
enum SpellGroup
|
||||
{
|
||||
SPELL_GROUP_SPECIAL_FLAG_NONE = 0x000,
|
||||
SPELL_GROUP_SPECIAL_FLAG_ELIXIR_BATTLE = 0x001,
|
||||
SPELL_GROUP_SPECIAL_FLAG_ELIXIR_GUARDIAN = 0x002,
|
||||
SPELL_GROUP_SPECIAL_FLAG_ELIXIR_UNSTABLE = 0x004,
|
||||
SPELL_GROUP_SPECIAL_FLAG_ELIXIR_SHATTRATH = 0x008,
|
||||
SPELL_GROUP_SPECIAL_FLAG_STACK_EXCLUSIVE_MAX = 0x00F,
|
||||
SPELL_GROUP_SPECIAL_FLAG_FORCED_STRONGEST = 0x010, // xinef: specially helpful flag if some spells have different auras, but only one should be present
|
||||
SPELL_GROUP_SPECIAL_FLAG_SKIP_STRONGER_CHECK = 0x020,
|
||||
SPELL_GROUP_SPECIAL_FLAG_BASE_AMOUNT_CHECK = 0x040,
|
||||
SPELL_GROUP_SPECIAL_FLAG_PRIORITY1 = 0x100,
|
||||
SPELL_GROUP_SPECIAL_FLAG_PRIORITY2 = 0x200,
|
||||
SPELL_GROUP_SPECIAL_FLAG_PRIORITY3 = 0x400,
|
||||
SPELL_GROUP_SPECIAL_FLAG_PRIORITY4 = 0x800,
|
||||
SPELL_GROUP_SPECIAL_FLAG_SAME_SPELL_CHECK = 0x1000,
|
||||
SPELL_GROUP_SPECIAL_FLAG_SKIP_STRONGER_SAME_SPELL = 0x2000,
|
||||
SPELL_GROUP_SPECIAL_FLAG_MAX = 0x4000,
|
||||
|
||||
SPELL_GROUP_SPECIAL_FLAG_FLASK = SPELL_GROUP_SPECIAL_FLAG_ELIXIR_BATTLE | SPELL_GROUP_SPECIAL_FLAG_ELIXIR_GUARDIAN
|
||||
SPELL_GROUP_NONE = 0,
|
||||
SPELL_GROUP_ELIXIR_BATTLE = 1,
|
||||
SPELL_GROUP_ELIXIR_GUARDIAN = 2,
|
||||
SPELL_GROUP_CORE_RANGE_MAX = 3
|
||||
};
|
||||
|
||||
enum SpellGroupStackFlags
|
||||
namespace std
|
||||
{
|
||||
SPELL_GROUP_STACK_FLAG_NONE = 0x00,
|
||||
SPELL_GROUP_STACK_FLAG_EXCLUSIVE = 0x01,
|
||||
SPELL_GROUP_STACK_FLAG_NOT_SAME_CASTER = 0x02,
|
||||
SPELL_GROUP_STACK_FLAG_FLAGGED = 0x04, // xinef: just a marker
|
||||
SPELL_GROUP_STACK_FLAG_NEVER_STACK = 0x08,
|
||||
SPELL_GROUP_STACK_FLAG_EFFECT_EXCLUSIVE = 0x10,
|
||||
SPELL_GROUP_STACK_FLAG_MAX = 0x20,
|
||||
template<>
|
||||
struct hash<SpellGroup>
|
||||
{
|
||||
size_t operator()(SpellGroup const& group) const
|
||||
{
|
||||
return hash<uint32>()(uint32(group));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Internal use
|
||||
SPELL_GROUP_STACK_FLAG_FORCED_STRONGEST = 0x100,
|
||||
SPELL_GROUP_STACK_FLAG_FORCED_WEAKEST = 0x200,
|
||||
#define SPELL_GROUP_DB_RANGE_MIN 1000
|
||||
|
||||
// spell_id, group_id
|
||||
typedef std::unordered_multimap<uint32, SpellGroup> SpellSpellGroupMap;
|
||||
typedef std::pair<SpellSpellGroupMap::const_iterator, SpellSpellGroupMap::const_iterator> SpellSpellGroupMapBounds;
|
||||
|
||||
// group_id, spell_id
|
||||
typedef std::unordered_multimap<SpellGroup, int32> SpellGroupSpellMap;
|
||||
typedef std::pair<SpellGroupSpellMap::const_iterator, SpellGroupSpellMap::const_iterator> SpellGroupSpellMapBounds;
|
||||
|
||||
enum SpellGroupStackRule
|
||||
{
|
||||
SPELL_GROUP_STACK_RULE_DEFAULT,
|
||||
SPELL_GROUP_STACK_RULE_EXCLUSIVE,
|
||||
SPELL_GROUP_STACK_RULE_EXCLUSIVE_FROM_SAME_CASTER,
|
||||
SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT,
|
||||
SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST,
|
||||
SPELL_GROUP_STACK_RULE_MAX
|
||||
};
|
||||
|
||||
enum SpellGroupIDs
|
||||
{
|
||||
SPELL_GROUP_GUARDIAN_AND_BATTLE_ELIXIRS = 1
|
||||
};
|
||||
typedef std::unordered_map<SpellGroup, SpellGroupStackRule> SpellGroupStackMap;
|
||||
|
||||
struct SpellStackInfo
|
||||
{
|
||||
uint32 groupId;
|
||||
SpellGroupSpecialFlags specialFlags;
|
||||
};
|
||||
// spell_id, group_id
|
||||
typedef std::map<uint32, SpellStackInfo> SpellGroupMap;
|
||||
typedef std::map<uint32, SpellGroupStackFlags> SpellGroupStackMap;
|
||||
typedef std::unordered_map<SpellGroup, std::unordered_set<uint32 /*auraName*/>> SameEffectStackMap;
|
||||
|
||||
struct SpellThreatEntry
|
||||
{
|
||||
@@ -679,12 +671,18 @@ public:
|
||||
// Spell target coordinates
|
||||
[[nodiscard]] SpellTargetPosition const* GetSpellTargetPosition(uint32 spell_id, SpellEffIndex effIndex) const;
|
||||
|
||||
// Spell Groups
|
||||
[[nodiscard]] uint32 GetSpellGroup(uint32 spellid) const;
|
||||
[[nodiscard]] SpellGroupSpecialFlags GetSpellGroupSpecialFlags(uint32 spell_id) const;
|
||||
[[nodiscard]] SpellGroupStackFlags GetGroupStackFlags(uint32 groupid) const;
|
||||
SpellGroupStackFlags CheckSpellGroupStackRules(SpellInfo const* spellInfo1, SpellInfo const* spellInfo2, bool remove, bool areaAura) const;
|
||||
void GetSetOfSpellsInSpellGroupWithFlag(uint32 group_id, SpellGroupSpecialFlags flag, std::set<uint32>& availableElixirs) const;
|
||||
// Spell Groups table
|
||||
SpellSpellGroupMapBounds GetSpellSpellGroupMapBounds(uint32 spell_id) const;
|
||||
bool IsSpellMemberOfSpellGroup(uint32 spell_id, SpellGroup group_id) const;
|
||||
|
||||
SpellGroupSpellMapBounds GetSpellGroupSpellMapBounds(SpellGroup group_id) const;
|
||||
void GetSetOfSpellsInSpellGroup(SpellGroup group_id, std::set<uint32>& foundSpells) const;
|
||||
void GetSetOfSpellsInSpellGroup(SpellGroup group_id, std::set<uint32>& foundSpells, std::set<SpellGroup>& usedGroups) const;
|
||||
|
||||
// Spell Group Stack Rules table
|
||||
bool AddSameEffectStackRuleSpellGroups(SpellInfo const* spellInfo, uint32 auraType, int32 amount, std::map<SpellGroup, int32>& groups) const;
|
||||
SpellGroupStackRule CheckSpellGroupStackRules(SpellInfo const* spellInfo1, SpellInfo const* spellInfo2) const;
|
||||
SpellGroupStackRule GetSpellGroupStackRule(SpellGroup group_id) const;
|
||||
|
||||
// Spell proc event table
|
||||
[[nodiscard]] SpellProcEventEntry const* GetSpellProcEvent(uint32 spellId) const;
|
||||
@@ -798,8 +796,10 @@ private:
|
||||
SpellRequiredMap mSpellReq;
|
||||
SpellLearnSkillMap mSpellLearnSkills;
|
||||
SpellTargetPositionMap mSpellTargetPositions;
|
||||
SpellGroupMap mSpellGroupMap;
|
||||
SpellGroupStackMap mSpellGroupStackMap;
|
||||
SpellSpellGroupMap mSpellSpellGroup;
|
||||
SpellGroupSpellMap mSpellGroupSpell;
|
||||
SpellGroupStackMap mSpellGroupStack;
|
||||
SameEffectStackMap mSpellSameEffectStack;
|
||||
SpellProcEventMap mSpellProcEventMap;
|
||||
SpellProcMap mSpellProcMap;
|
||||
SpellBonusMap mSpellBonusMap;
|
||||
|
||||
@@ -555,8 +555,8 @@ void WorldConfig::BuildConfigCache()
|
||||
|
||||
// Dungeon finder
|
||||
SetConfigValue<uint32>(CONFIG_LFG_OPTIONSMASK, "DungeonFinder.OptionsMask", 5);
|
||||
|
||||
SetConfigValue<bool>(CONFIG_LFG_CAST_DESERTER, "DungeonFinder.CastDeserter", true);
|
||||
SetConfigValue<bool>(CONFIG_LFG_ALLOW_COMPLETED, "DungeonFinder.AllowCompleted", true);
|
||||
|
||||
// DBC_ItemAttributes
|
||||
SetConfigValue<bool>(CONFIG_DBC_ENFORCE_ITEM_ATTRIBUTES, "DBC.EnforceItemAttributes", true);
|
||||
|
||||
@@ -94,6 +94,7 @@ enum ServerConfigs
|
||||
CONFIG_ALLOW_TICKETS,
|
||||
CONFIG_DELETE_CHARACTER_TICKET_TRACE,
|
||||
CONFIG_LFG_CAST_DESERTER,
|
||||
CONFIG_LFG_ALLOW_COMPLETED,
|
||||
CONFIG_DBC_ENFORCE_ITEM_ATTRIBUTES,
|
||||
CONFIG_PRESERVE_CUSTOM_CHANNELS,
|
||||
CONFIG_PDUMP_NO_PATHS,
|
||||
|
||||
@@ -78,6 +78,10 @@ Position const PosMoveOnSpawn[1] =
|
||||
{ -11561.9f, -1627.868f, 41.29941f, 0.0f }
|
||||
};
|
||||
|
||||
// hack
|
||||
float const DamageIncrease = 35.0f;
|
||||
float const DamageDecrease = 100.f / (1.f + DamageIncrease / 100.f) - 100.f;
|
||||
|
||||
class boss_arlokk : public CreatureScript
|
||||
{
|
||||
public:
|
||||
@@ -90,7 +94,7 @@ public:
|
||||
void Reset() override
|
||||
{
|
||||
if (events.IsInPhase(PHASE_TWO))
|
||||
me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, false); // hack
|
||||
me->ApplyStatPctModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, DamageDecrease); // hack
|
||||
_Reset();
|
||||
_summonCountA = 0;
|
||||
_summonCountB = 0;
|
||||
@@ -253,7 +257,7 @@ public:
|
||||
events.ScheduleEvent(EVENT_RAVAGE, 10s, 14s, 0, PHASE_TWO);
|
||||
events.ScheduleEvent(EVENT_TRANSFORM_BACK, 30s, 40s, 0, PHASE_TWO);
|
||||
events.SetPhase(PHASE_TWO);
|
||||
me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, true); // hack
|
||||
me->ApplyStatPctModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, DamageIncrease); // hack
|
||||
break;
|
||||
case EVENT_RAVAGE:
|
||||
DoCastVictim(SPELL_RAVAGE, true);
|
||||
@@ -265,7 +269,7 @@ public:
|
||||
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));
|
||||
me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, false); // hack
|
||||
me->ApplyStatPctModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, DamageDecrease); // hack
|
||||
events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, 4s, 7s, 0, PHASE_ONE);
|
||||
events.ScheduleEvent(EVENT_GOUGE, 12s, 15s, 0, PHASE_ONE);
|
||||
events.ScheduleEvent(EVENT_TRANSFORM, 30s, 0, PHASE_ONE);
|
||||
|
||||
@@ -73,6 +73,10 @@ enum Misc
|
||||
GO_SPIDER_EGGS = 179985,
|
||||
};
|
||||
|
||||
// hack
|
||||
float const DamageIncrease = 35.0f;
|
||||
float const DamageDecrease = 100.f / (1.f + DamageIncrease / 100.f) - 100.f;
|
||||
|
||||
// High Priestess Mar'li (14510)
|
||||
struct boss_marli : public BossAI
|
||||
{
|
||||
@@ -84,7 +88,7 @@ public:
|
||||
if (_phase == PHASE_SPIDER)
|
||||
{
|
||||
me->RemoveAura(SPELL_SPIDER_FORM);
|
||||
me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, false);
|
||||
me->ApplyStatPctModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, DamageDecrease);
|
||||
_phase = PHASE_TROLL;
|
||||
}
|
||||
|
||||
@@ -143,7 +147,7 @@ private:
|
||||
me->RemoveAura(SPELL_SPIDER_FORM);
|
||||
DoCastSelf(SPELL_TRANSFORM_BACK, true);
|
||||
Talk(SAY_TRANSFORM_BACK);
|
||||
me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, false);
|
||||
me->ApplyStatPctModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, DamageDecrease);
|
||||
|
||||
scheduler.CancelGroup(PHASE_SPIDER);
|
||||
}
|
||||
@@ -186,7 +190,7 @@ private:
|
||||
|
||||
Talk(SAY_TRANSFORM);
|
||||
DoCastSelf(SPELL_SPIDER_FORM, true);
|
||||
me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, true);
|
||||
me->ApplyStatPctModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, DamageIncrease);
|
||||
|
||||
scheduler.Schedule(5s, PHASE_SPIDER, [this](TaskContext context)
|
||||
{
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
*/
|
||||
|
||||
#include "AchievementCriteriaScript.h"
|
||||
#include "Containers.h"
|
||||
#include "CreatureScript.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "ScriptedCreature.h"
|
||||
@@ -209,7 +208,7 @@ struct boss_jedoga_shadowseeker : public BossAI
|
||||
}
|
||||
}
|
||||
|
||||
sacraficeTarget_GUID.Clear();
|
||||
sacrificeTargetGUID.Clear();
|
||||
sayPreachTimer = 120000;
|
||||
ritualTriggered = false;
|
||||
volunteerWork = true;
|
||||
@@ -268,12 +267,12 @@ struct boss_jedoga_shadowseeker : public BossAI
|
||||
}
|
||||
case NPC_TWILIGHT_VOLUNTEER:
|
||||
{
|
||||
if (sacraficeTarget_GUID && summon->GetGUID() != sacraficeTarget_GUID)
|
||||
if (sacrificeTargetGUID && summon->GetGUID() != sacrificeTargetGUID)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (killer != me && killer->GetGUID() != sacraficeTarget_GUID)
|
||||
if (killer != me && killer->GetGUID() != sacrificeTargetGUID)
|
||||
{
|
||||
volunteerWork = false;
|
||||
}
|
||||
@@ -315,7 +314,7 @@ struct boss_jedoga_shadowseeker : public BossAI
|
||||
{
|
||||
if (action == ACTION_SACRAFICE)
|
||||
{
|
||||
if (Creature* target = ObjectAccessor::GetCreature(*me, sacraficeTarget_GUID))
|
||||
if (Creature* target = ObjectAccessor::GetCreature(*me, sacrificeTargetGUID))
|
||||
{
|
||||
Unit::Kill(me, target);
|
||||
}
|
||||
@@ -395,9 +394,9 @@ struct boss_jedoga_shadowseeker : public BossAI
|
||||
me->SetFacingTo(5.66f);
|
||||
if (!summons.empty())
|
||||
{
|
||||
sacraficeTarget_GUID = Acore::Containers::SelectRandomContainerElement(summons);
|
||||
if (ObjectAccessor::GetCreature(*me, sacraficeTarget_GUID))
|
||||
if (Creature* creature = summons.GetRandomCreatureWithEntry(NPC_TWILIGHT_VOLUNTEER))
|
||||
{
|
||||
sacrificeTargetGUID = creature->GetGUID();
|
||||
events.ScheduleEvent(EVENT_JEDGA_START_RITUAL, 3s, 0, PHASE_RITUAL);
|
||||
}
|
||||
// Something failed, let players continue but do not grant achievement
|
||||
@@ -518,15 +517,16 @@ struct boss_jedoga_shadowseeker : public BossAI
|
||||
}
|
||||
case EVENT_JEDGA_START_RITUAL:
|
||||
{
|
||||
sacraficeTarget_GUID = Acore::Containers::SelectRandomContainerElement(summons);
|
||||
if (Creature* volunteer = ObjectAccessor::GetCreature(*me, sacraficeTarget_GUID))
|
||||
if (Creature* creature = summons.GetRandomCreatureWithEntry(NPC_TWILIGHT_VOLUNTEER))
|
||||
{
|
||||
sacrificeTargetGUID = creature->GetGUID();
|
||||
Talk(SAY_SACRIFICE_1);
|
||||
sacraficeTarget_GUID = volunteer->GetGUID();
|
||||
volunteer->AI()->DoAction(ACTION_RITUAL_BEGIN);
|
||||
creature->AI()->DoAction(ACTION_RITUAL_BEGIN);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -546,7 +546,7 @@ struct boss_jedoga_shadowseeker : public BossAI
|
||||
private:
|
||||
GuidList oocSummons;
|
||||
GuidList oocTriggers;
|
||||
ObjectGuid sacraficeTarget_GUID;
|
||||
ObjectGuid sacrificeTargetGUID;
|
||||
uint32 sayPreachTimer;
|
||||
bool combatSummonsSummoned;
|
||||
bool ritualTriggered;
|
||||
|
||||
+1
-1
@@ -2037,7 +2037,7 @@ public:
|
||||
npc_toc_enh_shamanAI(Creature* pCreature) : boss_faction_championsAI(pCreature, AI_MELEE)
|
||||
{
|
||||
SetEquipmentSlots(false, 51803, 48013, EQUIP_NO_CHANGE);
|
||||
me->SetModifierValue(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, 1.0f);
|
||||
me->SetStatPctModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, 1.0f);
|
||||
me->UpdateDamagePhysical(OFF_ATTACK);
|
||||
|
||||
events.Reset();
|
||||
|
||||
+1
-1
@@ -109,7 +109,7 @@ struct boss_twin_valkyrAI : public ScriptedAI
|
||||
{
|
||||
pInstance = pCreature->GetInstanceScript();
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->SetModifierValue(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, 1.0f);
|
||||
me->SetStatPctModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, 1.0f);
|
||||
me->UpdateDamagePhysical(OFF_ATTACK);
|
||||
LastSynchroHP = (int32)me->GetMaxHealth();
|
||||
SpecialMask = 0;
|
||||
|
||||
@@ -36,7 +36,8 @@ enum Misc
|
||||
EVENT_ECK_BITE = 2,
|
||||
EVENT_ECK_SPIT = 3,
|
||||
EVENT_ECK_SPRING = 4,
|
||||
EVENT_ECK_HEALTH = 5
|
||||
EVENT_ECK_CRAZED_EMOTE = 5,
|
||||
EMOTE_CRAZED = 1
|
||||
};
|
||||
|
||||
class boss_eck : public CreatureScript
|
||||
@@ -89,7 +90,8 @@ public:
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
BossAI::JustEngagedWith(who);
|
||||
events.ScheduleEvent(EVENT_ECK_BERSERK, 60s, 90s);
|
||||
events.ScheduleEvent(EVENT_ECK_CRAZED_EMOTE, 76s, 78s);
|
||||
events.ScheduleEvent(EVENT_ECK_BERSERK, 90s);
|
||||
events.ScheduleEvent(EVENT_ECK_BITE, 5s);
|
||||
events.ScheduleEvent(EVENT_ECK_SPIT, 10s, 37s);
|
||||
events.ScheduleEvent(EVENT_ECK_SPRING, 10s, 24s);
|
||||
@@ -111,18 +113,11 @@ public:
|
||||
|
||||
switch (events.ExecuteEvent())
|
||||
{
|
||||
case EVENT_ECK_HEALTH:
|
||||
if (me->HealthBelowPct(21))
|
||||
{
|
||||
events.CancelEvent(EVENT_ECK_BERSERK);
|
||||
me->CastSpell(me, SPELL_ECK_BERSERK, false);
|
||||
break;
|
||||
}
|
||||
events.ScheduleEvent(EVENT_ECK_HEALTH, 1s);
|
||||
case EVENT_ECK_CRAZED_EMOTE:
|
||||
Talk(EMOTE_CRAZED);
|
||||
break;
|
||||
case EVENT_ECK_BERSERK:
|
||||
me->CastSpell(me, SPELL_ECK_BERSERK, false);
|
||||
events.CancelEvent(EVENT_ECK_HEALTH);
|
||||
break;
|
||||
case EVENT_ECK_BITE:
|
||||
me->CastSpell(me->GetVictim(), SPELL_ECK_BITE, false);
|
||||
|
||||
@@ -547,12 +547,17 @@ public:
|
||||
}
|
||||
case DONE:
|
||||
{
|
||||
if (!horsemanKilled) // if no horsemen are found, assume wing is cleared
|
||||
{
|
||||
ActivateWingPortal(DATA_HORSEMAN_PORTAL);
|
||||
break;
|
||||
}
|
||||
|
||||
_events.RescheduleEvent(EVENT_AND_THEY_WOULD_ALL_GO_DOWN_TOGETHER, 15s);
|
||||
|
||||
if (horsemanKilled != HorsemanCount)
|
||||
return false;
|
||||
|
||||
// all horsemans are killed
|
||||
if (Creature* cr = GetCreature(DATA_BARON_RIVENDARE_BOSS))
|
||||
cr->CastSpell(cr, SPELL_THE_FOUR_HORSEMAN_CREDIT, true);
|
||||
|
||||
|
||||
@@ -75,17 +75,15 @@ enum NaxxramasData
|
||||
DATA_DANCE_FAIL = 301,
|
||||
DATA_SPORE_KILLED = 302,
|
||||
DATA_FRENZY_REMOVED = 303,
|
||||
DATA_THADDIUS_INTRO = 304,
|
||||
DATA_CHARGES_CROSSED = 305,
|
||||
DATA_HUNDRED_CLUB = 306,
|
||||
DATA_ABOMINATION_KILLED = 307,
|
||||
DATA_CHARGES_CROSSED = 304,
|
||||
DATA_HUNDRED_CLUB = 305,
|
||||
DATA_ABOMINATION_KILLED = 306,
|
||||
};
|
||||
|
||||
enum NaxxramasPersistentData
|
||||
{
|
||||
PERSISTENT_DATA_THADDIUS_INTRO = 0,
|
||||
PERSISTENT_DATA_KELTHUZAD_DIALOG = 1,
|
||||
PERSISTENT_DATA_IMMORTAL_FAIL = 2,
|
||||
PERSISTENT_DATA_KELTHUZAD_DIALOG = 0,
|
||||
PERSISTENT_DATA_IMMORTAL_FAIL = 1,
|
||||
PERSISTENT_DATA_COUNT
|
||||
};
|
||||
|
||||
|
||||
@@ -676,7 +676,6 @@ public:
|
||||
me->CastSpell(me, 59046, true); // credit
|
||||
}
|
||||
|
||||
me->ReplaceAllNpcFlags(UNIT_NPC_FLAG_GOSSIP | UNIT_NPC_FLAG_QUESTGIVER);
|
||||
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_STAND);
|
||||
me->SendMovementFlagUpdate();
|
||||
|
||||
@@ -883,6 +882,7 @@ void brann_bronzebeard::brann_bronzebeardAI::WaypointReached(uint32 id)
|
||||
//Tribunal end, stand in the middle of the sky room
|
||||
case 17:
|
||||
SetEscortPaused(true);
|
||||
me->ReplaceAllNpcFlags(UNIT_NPC_FLAG_GOSSIP | UNIT_NPC_FLAG_QUESTGIVER);
|
||||
me->SetOrientation(3.91672f);
|
||||
me->SendMovementFlagUpdate();
|
||||
break;
|
||||
|
||||
@@ -82,30 +82,33 @@ struct npc_dragonflayer_forge_master : public ScriptedAI
|
||||
|
||||
enum EnslavedProtoDrake
|
||||
{
|
||||
TYPE_PROTODRAKE_AT = 28,
|
||||
DATA_PROTODRAKE_MOVE = 6,
|
||||
|
||||
PATH_PROTODRAKE = 125946,
|
||||
|
||||
EVENT_REND = 1,
|
||||
EVENT_FLAME_BREATH = 2,
|
||||
EVENT_KNOCKAWAY = 3,
|
||||
|
||||
SPELL_REND = 43931,
|
||||
SPELL_FLAME_BREATH = 50653,
|
||||
SPELL_KNOCK_AWAY = 49722,
|
||||
|
||||
POINT_LAST = 6,
|
||||
EVENT_REND = 1,
|
||||
EVENT_FLAME_BREATH = 2,
|
||||
EVENT_KNOCKAWAY = 3,
|
||||
// Special
|
||||
EVENT_PRE_LAND = 4,
|
||||
EVENT_LAND = 5,
|
||||
|
||||
// Special
|
||||
TYPE_PROTODRAKE_AT = 28,
|
||||
DATA_PROTODRAKE_MOVE = 6,
|
||||
POINT_TAKE_OFF = 1,
|
||||
POINT_PRE_LAND = 2,
|
||||
POINT_LAND = 3,
|
||||
};
|
||||
|
||||
const Position protodrakeCheckPos = {206.24f, -190.28f, 200.11f, 0.f};
|
||||
const Position protodrakeCheckPos{206.24f, -190.28f, 200.11f, 0.f};
|
||||
const Position protodrakeTakeOffPos{209.1206f, -187.86578f, 215.00346f};
|
||||
const Position protodrakePreLandPos{230.80234f, -164.99632f, 196.74878f};
|
||||
const Position protodrakeLandPos{241.2079f, -163.06265f, 193.47125f};
|
||||
|
||||
struct npc_enslaved_proto_drake : public ScriptedAI
|
||||
{
|
||||
npc_enslaved_proto_drake(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
_setData = false;
|
||||
}
|
||||
explicit npc_enslaved_proto_drake(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
@@ -113,22 +116,35 @@ struct npc_enslaved_proto_drake : public ScriptedAI
|
||||
_events.ScheduleEvent(EVENT_REND, 2s, 3s);
|
||||
_events.ScheduleEvent(EVENT_FLAME_BREATH, 5500ms, 7s);
|
||||
_events.ScheduleEvent(EVENT_KNOCKAWAY, 3500ms, 6s);
|
||||
scheduler.CancelAll();
|
||||
}
|
||||
|
||||
void MovementInform(uint32 type, uint32 id) override
|
||||
{
|
||||
if (type == WAYPOINT_MOTION_TYPE && id == POINT_LAST)
|
||||
if (type == EFFECT_MOTION_TYPE && id == POINT_TAKE_OFF)
|
||||
{
|
||||
ScheduleUniqueTimedEvent(500ms, [&]
|
||||
{
|
||||
me->GetMotionMaster()->MovePoint(POINT_PRE_LAND, protodrakePreLandPos);
|
||||
}, EVENT_PRE_LAND);
|
||||
}
|
||||
|
||||
if (type == POINT_MOTION_TYPE && id == POINT_PRE_LAND)
|
||||
{
|
||||
ScheduleUniqueTimedEvent(0s, [&]
|
||||
{
|
||||
me->GetMotionMaster()->MovePoint(POINT_LAND, protodrakeLandPos);
|
||||
}, EVENT_LAND);
|
||||
}
|
||||
|
||||
if (type == POINT_MOTION_TYPE && id == POINT_LAND)
|
||||
{
|
||||
me->SetFacingTo(0.25f);
|
||||
me->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0.25f);
|
||||
if (Vehicle* v = me->GetVehicleKit())
|
||||
if (Unit* p = v->GetPassenger(0))
|
||||
if (Creature* rider = p->ToCreature())
|
||||
rider->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0.25f);
|
||||
|
||||
me->SetCanFly(false);
|
||||
me->SetDisableGravity(false);
|
||||
me->SetFacingTo(0.25f);
|
||||
me->SetImmuneToAll(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,14 +153,14 @@ struct npc_enslaved_proto_drake : public ScriptedAI
|
||||
if (type == TYPE_PROTODRAKE_AT && data == DATA_PROTODRAKE_MOVE && !_setData && me->IsAlive() && me->GetDistance(protodrakeCheckPos) < 10.0f)
|
||||
{
|
||||
_setData = true;
|
||||
me->SetCanFly(true);
|
||||
me->SetDisableGravity(true);
|
||||
me->GetMotionMaster()->MoveWaypoint(PATH_PROTODRAKE, false);
|
||||
me->GetMotionMaster()->MoveTakeoff(POINT_TAKE_OFF, protodrakeTakeOffPos, 8.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
scheduler.Update(diff);
|
||||
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
@@ -178,7 +194,7 @@ struct npc_enslaved_proto_drake : public ScriptedAI
|
||||
}
|
||||
|
||||
private:
|
||||
bool _setData;
|
||||
bool _setData{false};
|
||||
EventMap _events;
|
||||
};
|
||||
|
||||
|
||||
@@ -15,52 +15,100 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CombatAI.h"
|
||||
#include "CreatureScript.h"
|
||||
#include "PassiveAI.h"
|
||||
#include "Player.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "SmartScriptMgr.h"
|
||||
#include "SpellAuras.h"
|
||||
#include "SpellScript.h"
|
||||
#include "Transport.h"
|
||||
#include "Vehicle.h"
|
||||
|
||||
enum ePreparationsForWar
|
||||
{
|
||||
NPC_HAMMERHEAD = 30585,
|
||||
NPC_CLOUDBUSTER = 30470,
|
||||
TRANSPORT_ORGRIMS_HAMMER = 192241,
|
||||
TRANSPORT_THE_SKYBREAKER = 192242
|
||||
NPC_CLOUDBUSTER = 30470,
|
||||
NPC_HAMMERHEAD = 30585,
|
||||
TRANSPORT_ORGRIMS_HAMMER = 192241,
|
||||
TRANSPORT_THE_SKYBREAKER = 192242,
|
||||
SEAT_PLAYER = 0,
|
||||
SPELL_FLIGHT = 48602,
|
||||
SPELL_TO_ICECROWN_PLAYER_AURA_DISMOUNT_A = 56904,
|
||||
SPELL_TO_ICECROWN_PLAYER_AURA_DISMOUNT_H = 57419,
|
||||
SPELL_TO_ICECROWN_AIRSHIP_PLAYER_AURA_TELEPORT_TO_DALARAN = 57460,
|
||||
SPELL_TO_ICECROWN_AIRSHIP_FROST_WYRM_WAITING_TO_SUMMON_AURA = 57498,
|
||||
POINT_END = 16,
|
||||
SPELL_TO_ICECROWN_AIRSHIP_AURA_DISMOUNT_RESPONSE = 56921, // unhandled - vehicle casts 50630 on self
|
||||
SPELL_EJECT_ALL_PASSENGERS = 50630,
|
||||
SPELL_TO_ICECROWN_AIRSHIP_TELEPORT_TO_AIRSHIP_A_FORCE_PLAYER_TO_CAST = 57554,
|
||||
SPELL_TO_ICECROWN_AIRSHIP_TELEPORT_TO_AIRSHIP_H_FORCE_PLAYER_TO_CAST = 57556,
|
||||
SPELL_TO_ICECROWN_AIRSHIP_TELEPORT_TO_AIRSHIP_A = 56917,
|
||||
SPELL_TO_ICECROWN_AIRSHIP_TELEPORT_TO_AIRSHIP_H = 57417,
|
||||
};
|
||||
|
||||
struct npc_preparations_for_war_vehicle : public NullCreatureAI
|
||||
struct npc_preparations_for_war_vehicle : public VehicleAI
|
||||
{
|
||||
npc_preparations_for_war_vehicle(Creature* creature) : NullCreatureAI(creature) { }
|
||||
|
||||
uint8 pointId;
|
||||
uint32 searchForShipTimer;
|
||||
uint32 transportEntry;
|
||||
|
||||
void InitializeAI() override
|
||||
explicit npc_preparations_for_war_vehicle(Creature* creature) : VehicleAI(creature), searchForShipTimer(0), transportEntry(me->GetEntry() == NPC_CLOUDBUSTER ? TRANSPORT_THE_SKYBREAKER : TRANSPORT_ORGRIMS_HAMMER)
|
||||
{
|
||||
me->GetMotionMaster()->MovePath(me->GetEntry(), FORCED_MOVEMENT_NONE, PathSource::SMART_WAYPOINT_MGR);
|
||||
|
||||
NullCreatureAI::InitializeAI();
|
||||
pointId = 0;
|
||||
searchForShipTimer = 0;
|
||||
transportEntry = (me->GetEntry() == NPC_HAMMERHEAD ? TRANSPORT_ORGRIMS_HAMMER : TRANSPORT_THE_SKYBREAKER);
|
||||
if (transportEntry == TRANSPORT_THE_SKYBREAKER)
|
||||
{
|
||||
// 30476 - [DND] Icecrown Flight To Airship Bunny (A)
|
||||
passenger_x = 31.41805;
|
||||
passenger_y = 0.126893;
|
||||
passenger_z = 41.69821;
|
||||
}
|
||||
else // TRANSPORT_ORGRIMS_HAMMER
|
||||
{
|
||||
// 30588 - [DND] Icecrown Flight To Airship Bunny (H)
|
||||
passenger_x = -18.10283;
|
||||
passenger_y = -0.042108;
|
||||
passenger_z = 45.31725;
|
||||
}
|
||||
}
|
||||
|
||||
void MovementInform(uint32 type, uint32 /*id*/) override
|
||||
void PassengerBoarded(Unit* who, int8 /*seatId*/, bool apply) override
|
||||
{
|
||||
if (type == ESCORT_MOTION_TYPE)
|
||||
if (++pointId == 17) // path size
|
||||
searchForShipTimer = 3000;
|
||||
if (apply)
|
||||
{
|
||||
DoCastSelf(SPELL_TO_ICECROWN_AIRSHIP_PLAYER_AURA_TELEPORT_TO_DALARAN, true);
|
||||
DoCastSelf(SPELL_FLIGHT, true);
|
||||
DoCastSelf(me->GetEntry() == NPC_CLOUDBUSTER ? SPELL_TO_ICECROWN_PLAYER_AURA_DISMOUNT_A : SPELL_TO_ICECROWN_PLAYER_AURA_DISMOUNT_H , true);
|
||||
DoCastSelf(SPELL_TO_ICECROWN_AIRSHIP_FROST_WYRM_WAITING_TO_SUMMON_AURA, true);
|
||||
me->GetMotionMaster()->MovePath(me->GetEntry(), FORCED_MOVEMENT_NONE, PathSource::SMART_WAYPOINT_MGR);
|
||||
}
|
||||
else
|
||||
who->RemoveAurasDueToSpell(VEHICLE_SPELL_PARACHUTE); // maybe vehicle / seat flag should be responsible for parachute gain?
|
||||
}
|
||||
|
||||
void MovementInform(uint32 type, uint32 id) override
|
||||
{
|
||||
if (type == ESCORT_MOTION_TYPE && id == POINT_END)
|
||||
searchForShipTimer = 3000;
|
||||
}
|
||||
|
||||
void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
|
||||
{
|
||||
switch (spell->Id)
|
||||
{
|
||||
case SPELL_TO_ICECROWN_AIRSHIP_AURA_DISMOUNT_RESPONSE:
|
||||
break;
|
||||
case SPELL_TO_ICECROWN_AIRSHIP_TELEPORT_TO_AIRSHIP_A_FORCE_PLAYER_TO_CAST:
|
||||
case SPELL_TO_ICECROWN_AIRSHIP_TELEPORT_TO_AIRSHIP_H_FORCE_PLAYER_TO_CAST:
|
||||
{
|
||||
uint32 teleportSpell = (spell->Id == SPELL_TO_ICECROWN_AIRSHIP_TELEPORT_TO_AIRSHIP_A_FORCE_PLAYER_TO_CAST)
|
||||
? SPELL_TO_ICECROWN_AIRSHIP_TELEPORT_TO_AIRSHIP_A
|
||||
: SPELL_TO_ICECROWN_AIRSHIP_TELEPORT_TO_AIRSHIP_H;
|
||||
DoCastSelf(teleportSpell, true); // hack: cast on self to avoid visual glitch on player when ejecting and teleporting on transport
|
||||
DoCastSelf(SPELL_EJECT_ALL_PASSENGERS, true);
|
||||
me->DespawnOrUnsummon(0s);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
// horde 7.55f, -0.09, 34.44, 3.13, +20
|
||||
// ally 45.18f, 0.03, 40.09, 3.14 +5
|
||||
|
||||
if (searchForShipTimer)
|
||||
{
|
||||
searchForShipTimer += diff;
|
||||
@@ -68,37 +116,14 @@ struct npc_preparations_for_war_vehicle : public NullCreatureAI
|
||||
{
|
||||
searchForShipTimer = 1;
|
||||
TransportsContainer const& transports = me->GetMap()->GetAllTransports();
|
||||
for (TransportsContainer::const_iterator itr = transports.begin(); itr != transports.end(); ++itr)
|
||||
for (auto const transport : transports)
|
||||
{
|
||||
if ((*itr)->GetEntry() == transportEntry)
|
||||
if (transport->GetEntry() == transportEntry)
|
||||
{
|
||||
float x, y, z;
|
||||
if (transportEntry == TRANSPORT_ORGRIMS_HAMMER)
|
||||
{
|
||||
x = 7.55f;
|
||||
y = -0.09f;
|
||||
z = 54.44f;
|
||||
}
|
||||
else
|
||||
{
|
||||
x = 45.18f;
|
||||
y = 0.03f;
|
||||
z = 45.09f;
|
||||
}
|
||||
float x = passenger_x, y = passenger_y, z = passenger_z;
|
||||
transport->CalculatePassengerPosition(x, y, z);
|
||||
|
||||
(*itr)->CalculatePassengerPosition(x, y, z);
|
||||
|
||||
if (me->GetDistance2d(x, y) < 10.0f)
|
||||
{
|
||||
me->DespawnOrUnsummon(1s);
|
||||
if (Vehicle* vehicle = me->GetVehicleKit())
|
||||
if (Unit* passenger = vehicle->GetPassenger(0))
|
||||
{
|
||||
passenger->NearTeleportTo(x, y, z - (transportEntry == TRANSPORT_ORGRIMS_HAMMER ? 19.0f : 4.0f), M_PI);
|
||||
passenger->RemoveAurasDueToSpell(VEHICLE_SPELL_PARACHUTE); // maybe vehicle / seat flag should be responsible for parachute gain?
|
||||
}
|
||||
}
|
||||
else
|
||||
if (me->GetDistance2d(x, y) > 20.0f) // dismount trigger (56905, 57420) range is 30
|
||||
me->GetMotionMaster()->MovePoint(0, x, y, z, FORCED_MOVEMENT_NONE, 0.f, 0.f, false, false);
|
||||
break;
|
||||
}
|
||||
@@ -106,6 +131,10 @@ struct npc_preparations_for_war_vehicle : public NullCreatureAI
|
||||
}
|
||||
}
|
||||
}
|
||||
private:
|
||||
float passenger_x, passenger_y, passenger_z;
|
||||
uint32 searchForShipTimer;
|
||||
uint32 transportEntry;
|
||||
};
|
||||
|
||||
/*******************************************************
|
||||
|
||||
@@ -428,7 +428,7 @@ public:
|
||||
|
||||
struct npc_mageguard_dalaranAI : public ScriptedAI
|
||||
{
|
||||
npc_mageguard_dalaranAI(Creature* creature) : ScriptedAI(creature)
|
||||
explicit npc_mageguard_dalaranAI(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
creature->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
||||
creature->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_NORMAL, true);
|
||||
@@ -449,6 +449,9 @@ public:
|
||||
if (!me->IsWithinDist(who, 5.0f, false))
|
||||
return;
|
||||
|
||||
if (who->IsCreature() && who->GetCreatureType() == CREATURE_TYPE_NON_COMBAT_PET)
|
||||
return;
|
||||
|
||||
Player* player = who->GetCharmerOrOwnerPlayerOrPlayerItself();
|
||||
|
||||
if (!player || player->IsGameMaster() || player->IsBeingTeleported() || (player->GetPositionZ() > 670 && player->GetVehicle()) ||
|
||||
@@ -484,7 +487,6 @@ public:
|
||||
break;
|
||||
}
|
||||
me->SetOrientation(me->GetHomePosition().GetOrientation());
|
||||
return;
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 /*diff*/) override {}
|
||||
|
||||
@@ -66,109 +66,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
// The cleansing
|
||||
enum TurmoilTexts
|
||||
{
|
||||
SAY_TURMOIL_0 = 0,
|
||||
SAY_TURMOIL_1 = 1,
|
||||
SAY_TURMOIL_HALF_HP = 2,
|
||||
SAY_TURMOIL_DEATH = 3,
|
||||
};
|
||||
|
||||
class npc_your_inner_turmoil : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_your_inner_turmoil() : CreatureScript("npc_your_inner_turmoil") { }
|
||||
|
||||
struct npc_your_inner_turmoilAI : public ScriptedAI
|
||||
{
|
||||
npc_your_inner_turmoilAI(Creature* creature) : ScriptedAI(creature) {}
|
||||
|
||||
uint32 timer;
|
||||
short phase;
|
||||
bool health50;
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
timer = 0;
|
||||
phase = 0;
|
||||
health50 = false;
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (timer >= 6000 && phase < 2)
|
||||
{
|
||||
phase++;
|
||||
setphase(phase);
|
||||
timer = 0;
|
||||
}
|
||||
|
||||
timer += diff;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
void DamageTaken(Unit*, uint32& /*damage*/, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/) override
|
||||
{
|
||||
if (HealthBelowPct(50) && !health50)
|
||||
{
|
||||
if (TempSummon const* tempSummon = me->ToTempSummon())
|
||||
{
|
||||
if (WorldObject* summoner = tempSummon->GetSummonerUnit())
|
||||
{
|
||||
Talk(SAY_TURMOIL_HALF_HP, summoner);
|
||||
}
|
||||
}
|
||||
|
||||
health50 = true;
|
||||
}
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
if (TempSummon const* tempSummon = me->ToTempSummon())
|
||||
{
|
||||
if (WorldObject* summoner = tempSummon->GetSummonerUnit())
|
||||
{
|
||||
Talk(SAY_TURMOIL_DEATH, summoner);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setphase(short newPhase)
|
||||
{
|
||||
Unit* summoner = me->ToTempSummon() ? me->ToTempSummon()->GetSummonerUnit() : nullptr;
|
||||
if (!summoner || !summoner->IsPlayer())
|
||||
return;
|
||||
|
||||
switch (newPhase)
|
||||
{
|
||||
case 1:
|
||||
Talk(SAY_TURMOIL_0, summoner->ToPlayer());
|
||||
return;
|
||||
case 2:
|
||||
{
|
||||
Talk(SAY_TURMOIL_1, summoner->ToPlayer());
|
||||
me->SetLevel(summoner->GetLevel());
|
||||
me->SetFaction(FACTION_MONSTER);
|
||||
if (me->GetExactDist(summoner) < 50.0f)
|
||||
{
|
||||
me->UpdatePosition(summoner->GetPositionX(), summoner->GetPositionY(), summoner->GetPositionZ(), 0.0f, true);
|
||||
summoner->CastSpell(me, 50218, true); // clone caster
|
||||
AttackStart(summoner);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return new npc_your_inner_turmoilAI(creature);
|
||||
}
|
||||
};
|
||||
|
||||
/*######
|
||||
## npc_apothecary_hanes
|
||||
######*/
|
||||
@@ -457,13 +354,145 @@ class spell_hawk_hunting : public SpellScript
|
||||
}
|
||||
};
|
||||
|
||||
/*######
|
||||
## Quest 11317, 11322: The Cleansing
|
||||
######*/
|
||||
|
||||
enum TheCleansing
|
||||
{
|
||||
SPELL_CLEANSING_SOUL = 43351,
|
||||
SPELL_SUMMON_INNER_TURMOIL = 50167,
|
||||
SPELL_RECENT_MEDITATION = 61720,
|
||||
SPELL_MIRROR_IMAGE_AURA = 50218,
|
||||
|
||||
QUEST_THE_CLEANSING_H = 11317,
|
||||
QUEST_THE_CLEANSING_A = 11322
|
||||
};
|
||||
|
||||
// 43365 - The Cleansing: Shrine Cast
|
||||
class spell_the_cleansing_shrine_cast : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_the_cleansing_shrine_cast);
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SPELL_RECENT_MEDITATION, SPELL_CLEANSING_SOUL }) &&
|
||||
sObjectMgr->GetQuestTemplate(QUEST_THE_CLEANSING_H) &&
|
||||
sObjectMgr->GetQuestTemplate(QUEST_THE_CLEANSING_A);
|
||||
}
|
||||
|
||||
SpellCastResult CheckCast()
|
||||
{
|
||||
// Error is correct for quest check but may be not correct for aura and this may be a wrong place to send error
|
||||
if (Player* target = GetExplTargetUnit()->ToPlayer())
|
||||
{
|
||||
if (target->HasAura(SPELL_RECENT_MEDITATION) || (!(target->GetQuestStatus(QUEST_THE_CLEANSING_H) == QUEST_STATUS_INCOMPLETE ||
|
||||
target->GetQuestStatus(QUEST_THE_CLEANSING_A) == QUEST_STATUS_INCOMPLETE)))
|
||||
{
|
||||
Spell::SendCastResult(target, GetSpellInfo(), 0, SPELL_FAILED_FIZZLE);
|
||||
return SPELL_FAILED_FIZZLE;
|
||||
}
|
||||
}
|
||||
return SPELL_CAST_OK;
|
||||
}
|
||||
|
||||
void HandleScript(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
GetHitUnit()->CastSpell(GetHitUnit(), SPELL_CLEANSING_SOUL, true);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnCheckCast += SpellCheckCastFn(spell_the_cleansing_shrine_cast::CheckCast);
|
||||
OnEffectHitTarget += SpellEffectFn(spell_the_cleansing_shrine_cast::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
}
|
||||
};
|
||||
|
||||
// 43351 - Cleansing Soul
|
||||
class spell_the_cleansing_cleansing_soul : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_the_cleansing_cleansing_soul);
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SPELL_SUMMON_INNER_TURMOIL, SPELL_RECENT_MEDITATION });
|
||||
}
|
||||
|
||||
void AfterApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
GetTarget()->SetStandState(UNIT_STAND_STATE_SIT);
|
||||
}
|
||||
|
||||
void AfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
Unit* target = GetTarget();
|
||||
target->SetStandState(UNIT_STAND_STATE_STAND);
|
||||
target->CastSpell(target, SPELL_SUMMON_INNER_TURMOIL, true);
|
||||
target->CastSpell(target, SPELL_RECENT_MEDITATION, true);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
AfterEffectApply += AuraEffectApplyFn(spell_the_cleansing_cleansing_soul::AfterApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
|
||||
AfterEffectRemove += AuraEffectRemoveFn(spell_the_cleansing_cleansing_soul::AfterRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
|
||||
}
|
||||
};
|
||||
|
||||
// 50217 - The Cleansing: Script Effect Player Cast Mirror Image
|
||||
class spell_the_cleansing_mirror_image_script_effect : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_the_cleansing_mirror_image_script_effect);
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SPELL_MIRROR_IMAGE_AURA });
|
||||
}
|
||||
|
||||
void HandleScript(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
GetHitUnit()->CastSpell(GetHitUnit(), SPELL_MIRROR_IMAGE_AURA, true);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_the_cleansing_mirror_image_script_effect::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
}
|
||||
};
|
||||
|
||||
// 50238 - The Cleansing: Your Inner Turmoil's On Death Cast on Master
|
||||
class spell_the_cleansing_on_death_cast_on_master : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_the_cleansing_on_death_cast_on_master);
|
||||
|
||||
bool Validate(SpellInfo const* spellInfo) override
|
||||
{
|
||||
return ValidateSpellInfo({ uint32(spellInfo->GetEffect(EFFECT_0).CalcValue()) });
|
||||
}
|
||||
|
||||
void HandleScript(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
if (Unit* caster = GetCaster())
|
||||
if (TempSummon* casterSummon = caster->ToTempSummon())
|
||||
if (Unit* summoner = casterSummon->GetSummonerUnit())
|
||||
summoner->CastSpell(summoner, GetSpellInfo()->Effects[EFFECT_0].CalcValue(), true);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHit += SpellEffectFn(spell_the_cleansing_on_death_cast_on_master::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_howling_fjord()
|
||||
{
|
||||
new npc_attracted_reef_bull();
|
||||
new npc_your_inner_turmoil();
|
||||
new npc_apothecary_hanes();
|
||||
new npc_plaguehound_tracker();
|
||||
new npc_razael_and_lyana();
|
||||
RegisterCreatureAI(npc_rodin_lightning_enabler);
|
||||
RegisterSpellScript(spell_hawk_hunting);
|
||||
RegisterSpellScript(spell_the_cleansing_shrine_cast);
|
||||
RegisterSpellScript(spell_the_cleansing_cleansing_soul);
|
||||
RegisterSpellScript(spell_the_cleansing_mirror_image_script_effect);
|
||||
RegisterSpellScript(spell_the_cleansing_on_death_cast_on_master);
|
||||
}
|
||||
|
||||
@@ -918,72 +918,40 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class npc_hyldsmeet_protodrake : public CreatureScript
|
||||
enum HyldsmeetProtoDrake
|
||||
{
|
||||
enum NPCs
|
||||
NPC_HYLDSMEET_DRAKERIDER = 29694
|
||||
};
|
||||
|
||||
struct npc_hyldsmeet_protodrake : public CreatureAI
|
||||
{
|
||||
explicit npc_hyldsmeet_protodrake(Creature* creature) : CreatureAI(creature), _accessoryRespawnTimer(0) { }
|
||||
|
||||
void PassengerBoarded(Unit* who, int8 /*seat*/, bool apply) override
|
||||
{
|
||||
NPC_HYLDSMEET_DRAKERIDER = 29694
|
||||
};
|
||||
if (apply)
|
||||
return;
|
||||
|
||||
public:
|
||||
npc_hyldsmeet_protodrake() : CreatureScript("npc_hyldsmeet_protodrake") { }
|
||||
|
||||
class npc_hyldsmeet_protodrakeAI : public CreatureAI
|
||||
{
|
||||
public:
|
||||
npc_hyldsmeet_protodrakeAI(Creature* creature) : CreatureAI(creature), _accessoryRespawnTimer(0), _vehicleKit(creature->GetVehicleKit()) { }
|
||||
|
||||
void PassengerBoarded(Unit* who, int8 /*seat*/, bool apply) override
|
||||
{
|
||||
if (apply)
|
||||
{
|
||||
class DelayedTransportPositionOffsets : public BasicEvent
|
||||
{
|
||||
public:
|
||||
DelayedTransportPositionOffsets(Unit* owner) : _owner(owner) { }
|
||||
|
||||
bool Execute(uint64 /*eventTime*/, uint32 /*updateTime*/) override
|
||||
{
|
||||
_owner->m_movementInfo.transport.pos.Relocate(-3.5f, 0.f, -0.2f, 0.f);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
Unit* _owner;
|
||||
};
|
||||
|
||||
if (who->IsPlayer())
|
||||
who->m_Events.AddEventAtOffset(new DelayedTransportPositionOffsets(who), 500ms);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (who->GetEntry() == NPC_HYLDSMEET_DRAKERIDER)
|
||||
_accessoryRespawnTimer = 5 * MINUTE * IN_MILLISECONDS;
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
//! We need to manually reinstall accessories because the vehicle itself is friendly to players,
|
||||
//! so EnterEvadeMode is never triggered. The accessory on the other hand is hostile and killable.
|
||||
if (_accessoryRespawnTimer && _accessoryRespawnTimer <= diff && _vehicleKit)
|
||||
{
|
||||
_vehicleKit->InstallAllAccessories(true);
|
||||
_accessoryRespawnTimer = 0;
|
||||
}
|
||||
else
|
||||
_accessoryRespawnTimer -= diff;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32 _accessoryRespawnTimer;
|
||||
Vehicle* _vehicleKit;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return new npc_hyldsmeet_protodrakeAI(creature);
|
||||
if (who->GetEntry() == NPC_HYLDSMEET_DRAKERIDER)
|
||||
_accessoryRespawnTimer = 5 * MINUTE * IN_MILLISECONDS;
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
//! We need to manually reinstall accessories because the vehicle itself is friendly to players,
|
||||
//! so EnterEvadeMode is never triggered. The accessory on the other hand is hostile and killable.
|
||||
Vehicle* vehicleKit = me->GetVehicleKit();
|
||||
if (_accessoryRespawnTimer && _accessoryRespawnTimer <= diff && vehicleKit)
|
||||
{
|
||||
vehicleKit->InstallAllAccessories(true);
|
||||
_accessoryRespawnTimer = 0;
|
||||
}
|
||||
else
|
||||
_accessoryRespawnTimer -= diff;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32 _accessoryRespawnTimer;
|
||||
};
|
||||
|
||||
enum CloseRift
|
||||
@@ -1218,7 +1186,7 @@ void AddSC_storm_peaks()
|
||||
new npc_brunnhildar_prisoner();
|
||||
new npc_freed_protodrake();
|
||||
new npc_icefang();
|
||||
new npc_hyldsmeet_protodrake();
|
||||
RegisterCreatureAI(npc_hyldsmeet_protodrake);
|
||||
RegisterSpellScript(spell_close_rift_aura);
|
||||
new npc_vehicle_d16_propelled_delivery();
|
||||
RegisterSpellScript(spell_q12823_remove_collapsing_cave_aura);
|
||||
|
||||
@@ -271,12 +271,12 @@ class spell_astromancer_solarian_transform : public AuraScript
|
||||
|
||||
void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
GetUnitOwner()->HandleStatModifier(UnitMods(UNIT_MOD_ARMOR), TOTAL_PCT, 400.0f, true);
|
||||
GetUnitOwner()->ApplyStatPctModifier(UNIT_MOD_ARMOR, TOTAL_PCT, 400.0f);
|
||||
}
|
||||
|
||||
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
GetUnitOwner()->HandleStatModifier(UnitMods(UNIT_MOD_ARMOR), TOTAL_PCT, 400.0f, false);
|
||||
GetUnitOwner()->ApplyStatPctModifier(UnitMods(UNIT_MOD_ARMOR), TOTAL_PCT, -80.0f);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
|
||||
@@ -99,7 +99,7 @@ struct npc_pet_hunter_snake_trap : public ScriptedAI
|
||||
|
||||
uint32 health = uint32(107 * (me->GetLevel() - 40) * 0.025f);
|
||||
me->SetCreateHealth(health);
|
||||
me->SetModifierValue(UNIT_MOD_HEALTH, BASE_VALUE, (float)health);
|
||||
me->SetStatFlatModifier(UNIT_MOD_HEALTH, BASE_VALUE, (float)health);
|
||||
me->SetMaxHealth(health);
|
||||
|
||||
//Add delta to make them not all hit the same time
|
||||
|
||||
@@ -174,8 +174,8 @@ class spell_dk_raise_ally : public SpellScript
|
||||
if (pInfo) // exist in DB
|
||||
{
|
||||
ghoul->SetCreateHealth(pInfo->health);
|
||||
ghoul->SetModifierValue(UNIT_MOD_HEALTH, BASE_VALUE, pInfo->health);
|
||||
ghoul->SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(pInfo->armor));
|
||||
ghoul->SetStatFlatModifier(UNIT_MOD_HEALTH, BASE_VALUE, pInfo->health);
|
||||
ghoul->SetStatFlatModifier(UNIT_MOD_ARMOR, BASE_VALUE, float(pInfo->armor));
|
||||
for (uint8 stat = 0; stat < MAX_STATS; ++stat)
|
||||
ghoul->SetCreateStat(Stats(stat), float(pInfo->stats[stat]));
|
||||
}
|
||||
@@ -194,9 +194,9 @@ class spell_dk_raise_ally : public SpellScript
|
||||
|
||||
// DK Ghoul haste refresh
|
||||
float val = (GetCaster()->m_modAttackSpeedPct[BASE_ATTACK] - 1.0f) * 100.0f;
|
||||
val *= 2000.0f + 2000.0f * ((100.0f + val) / 100.0f);
|
||||
ghoul->m_modAttackSpeedPct[BASE_ATTACK] = GetCaster()->m_modAttackSpeedPct[BASE_ATTACK];
|
||||
ghoul->SetFloatValue(UNIT_FIELD_BASEATTACKTIME, 2000.0f);
|
||||
ghoul->ApplyPercentModFloatValue(UNIT_FIELD_BASEATTACKTIME, val, true); // we want to reduce attack time
|
||||
ghoul->SetFloatValue(UNIT_FIELD_BASEATTACKTIME, val);
|
||||
|
||||
// Strength + Stamina
|
||||
for (uint8 i = STAT_STRENGTH; i <= STAT_STAMINA; ++i)
|
||||
@@ -223,20 +223,20 @@ class spell_dk_raise_ally : public SpellScript
|
||||
value = float(GetCaster()->GetStat(stat)) * mod;
|
||||
value = ghoul->GetTotalStatValue(stat, value);
|
||||
ghoul->SetStat(stat, int32(value));
|
||||
ghoul->ApplyStatBuffMod(stat, value, true);
|
||||
ghoul->UpdateStatBuffMod(stat);
|
||||
}
|
||||
|
||||
// Attack Power
|
||||
ghoul->SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, 589 + ghoul->GetStat(STAT_STRENGTH) + ghoul->GetStat(STAT_AGILITY));
|
||||
ghoul->SetInt32Value(UNIT_FIELD_ATTACK_POWER, (int32)ghoul->GetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE) * ghoul->GetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_PCT));
|
||||
ghoul->SetInt32Value(UNIT_FIELD_ATTACK_POWER_MODS, (int32)ghoul->GetModifierValue(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE));
|
||||
ghoul->SetFloatValue(UNIT_FIELD_ATTACK_POWER_MULTIPLIER, ghoul->GetModifierValue(UNIT_MOD_ATTACK_POWER, TOTAL_PCT) - 1.0f);
|
||||
ghoul->SetStatFlatModifier(UNIT_MOD_ATTACK_POWER, BASE_VALUE, 589 + ghoul->GetStat(STAT_STRENGTH) + ghoul->GetStat(STAT_AGILITY));
|
||||
ghoul->SetInt32Value(UNIT_FIELD_ATTACK_POWER, (int32)ghoul->GetFlatModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE) * ghoul->GetPctModifierValue(UNIT_MOD_ATTACK_POWER, BASE_PCT));
|
||||
ghoul->SetInt32Value(UNIT_FIELD_ATTACK_POWER_MODS, (int32)ghoul->GetFlatModifierValue(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE));
|
||||
ghoul->SetFloatValue(UNIT_FIELD_ATTACK_POWER_MULTIPLIER, ghoul->GetPctModifierValue(UNIT_MOD_ATTACK_POWER, TOTAL_PCT) - 1.0f);
|
||||
|
||||
// Health
|
||||
ghoul->SetModifierValue(UNIT_MOD_HEALTH, TOTAL_VALUE, (ghoul->GetStat(STAT_STAMINA) - ghoul->GetCreateStat(STAT_STAMINA)) * 10.0f);
|
||||
ghoul->SetStatFlatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, (ghoul->GetStat(STAT_STAMINA) - ghoul->GetCreateStat(STAT_STAMINA)) * 10.0f);
|
||||
|
||||
// Power Energy
|
||||
ghoul->SetModifierValue(UnitMods(UNIT_MOD_POWER_START + static_cast<uint8>(POWER_ENERGY)), BASE_VALUE, ghoul->GetCreatePowers(POWER_ENERGY));
|
||||
ghoul->SetStatFlatModifier(UnitMods(UNIT_MOD_POWER_START + static_cast<uint8>(POWER_ENERGY)), BASE_VALUE, ghoul->GetCreatePowers(POWER_ENERGY));
|
||||
ghoul->UpdateAllStats();
|
||||
ghoul->SetFullHealth();
|
||||
|
||||
|
||||
@@ -443,15 +443,16 @@ class spell_dru_enrage : public AuraScript
|
||||
|
||||
void RecalculateBaseArmor()
|
||||
{
|
||||
// Recalculate modifies the list while we're iterating through it, so let's copy it instead
|
||||
Unit::AuraEffectList const& auras = GetTarget()->GetAuraEffectsByType(SPELL_AURA_MOD_BASE_RESISTANCE_PCT);
|
||||
for (Unit::AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i)
|
||||
std::vector<AuraEffect*> aurEffs(auras.begin(), auras.end());
|
||||
|
||||
for (AuraEffect* aurEff : aurEffs)
|
||||
{
|
||||
SpellInfo const* spellInfo = (*i)->GetSpellInfo();
|
||||
SpellInfo const* spellInfo = aurEff->GetSpellInfo();
|
||||
// Dire- / Bear Form (Passive)
|
||||
if (spellInfo->SpellFamilyName == SPELLFAMILY_DRUID && spellInfo->SpellFamilyFlags.HasFlag(0x0, 0x0, 0x2))
|
||||
{
|
||||
(*i)->RecalculateAmount();
|
||||
}
|
||||
aurEff->RecalculateAmount();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4422,7 +4422,9 @@ class spell_gen_eject_all_passengers : public SpellScript
|
||||
}
|
||||
};
|
||||
|
||||
/* 62539 - Eject Passenger 2
|
||||
/* 49259 - Despawn Driver
|
||||
49261 - Dismount Passenger
|
||||
62539 - Eject Passenger 2
|
||||
64614 - Eject Passenger 4
|
||||
64629 - Eject Passenger 1
|
||||
64630 - Eject Passenger 2
|
||||
@@ -5670,6 +5672,29 @@ class spell_gen_bm_on : public SpellScript
|
||||
}
|
||||
};
|
||||
|
||||
class spell_gen_whisper_to_controller : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_gen_whisper_to_controller);
|
||||
|
||||
bool Validate(SpellInfo const* spellInfo) override
|
||||
{
|
||||
return sObjectMgr->GetBroadcastText(uint32(spellInfo->GetEffect(EFFECT_0).CalcValue()));
|
||||
}
|
||||
|
||||
void HandleScript(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
if (Unit* caster = GetCaster())
|
||||
if (TempSummon* casterSummon = caster->ToTempSummon())
|
||||
if (Player* target = casterSummon->GetSummonerUnit()->ToPlayer())
|
||||
casterSummon->Unit::Whisper(uint32(GetEffectValue()), target, false);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHit += SpellEffectFn(spell_gen_whisper_to_controller::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_generic_spell_scripts()
|
||||
{
|
||||
RegisterSpellScript(spell_silithyst);
|
||||
@@ -5843,4 +5868,5 @@ void AddSC_generic_spell_scripts()
|
||||
RegisterSpellScript(spell_gen_invis_on);
|
||||
RegisterSpellScript(spell_gen_bm_on);
|
||||
RegisterSpellScript(spell_gen_bm_off);
|
||||
RegisterSpellScript(spell_gen_whisper_to_controller);
|
||||
}
|
||||
|
||||
@@ -473,11 +473,7 @@ class spell_pal_blessing_of_sanctuary : public AuraScript
|
||||
{
|
||||
Unit* target = GetTarget();
|
||||
if (Unit* caster = GetCaster())
|
||||
{
|
||||
// xinef: hack
|
||||
int32 value = 9;
|
||||
caster->CastCustomSpell(target, SPELL_PALADIN_BLESSING_OF_SANCTUARY_BUFF, &value, &value, 0, true);
|
||||
}
|
||||
caster->CastSpell(target, SPELL_PALADIN_BLESSING_OF_SANCTUARY_BUFF, true);
|
||||
}
|
||||
|
||||
void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||
@@ -965,6 +961,24 @@ class spell_pal_lay_on_hands : public SpellScript
|
||||
return true;
|
||||
}
|
||||
|
||||
void HandleMaxHealthHeal(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
Unit* caster = GetCaster();
|
||||
Unit* target = GetExplTargetUnit();
|
||||
|
||||
if (!target || !caster)
|
||||
return;
|
||||
|
||||
uint32 baseHeal = caster->GetMaxHealth();
|
||||
uint32 modifiedHeal = target->SpellHealingBonusTaken(caster, GetSpellInfo(), baseHeal, HEAL);
|
||||
|
||||
// EffectHealMaxHealth() ignores healing modifiers, so we pre-apply the
|
||||
// difference here; this delta will be added on top of the raw heal.
|
||||
int64 healAdjustment = int64(modifiedHeal) - int64(baseHeal);
|
||||
|
||||
SetHitHeal(healAdjustment);
|
||||
}
|
||||
|
||||
SpellCastResult CheckCast()
|
||||
{
|
||||
Unit* caster = GetCaster();
|
||||
@@ -1004,6 +1018,7 @@ class spell_pal_lay_on_hands : public SpellScript
|
||||
{
|
||||
OnCheckCast += SpellCheckCastFn(spell_pal_lay_on_hands::CheckCast);
|
||||
AfterHit += SpellHitFn(spell_pal_lay_on_hands::HandleScript);
|
||||
OnEffectHitTarget += SpellEffectFn(spell_pal_lay_on_hands::HandleMaxHealthHeal, EFFECT_0, SPELL_EFFECT_HEAL_MAX_HEALTH);
|
||||
}
|
||||
|
||||
int32 _manaAmount;
|
||||
|
||||
@@ -247,28 +247,6 @@ class spell_q10525_vision_guide : public AuraScript
|
||||
}
|
||||
};
|
||||
|
||||
class spell_q11322_q11317_the_cleansing : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_q11322_q11317_the_cleansing)
|
||||
|
||||
void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
Unit* ar = GetCaster();
|
||||
if (ar && ar->ToPlayer())
|
||||
{
|
||||
if (ar->ToPlayer()->GetQuestStatus(11317) == QUEST_STATUS_INCOMPLETE || ar->ToPlayer()->GetQuestStatus(11322) == QUEST_STATUS_INCOMPLETE)
|
||||
ar->SummonCreature(27959, 3032.0f, -5095.0f, 723.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000);
|
||||
|
||||
ar->SetStandState(UNIT_STAND_STATE_SIT);
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectApply += AuraEffectApplyFn(spell_q11322_q11317_the_cleansing::HandleEffectApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
|
||||
}
|
||||
};
|
||||
|
||||
class spell_q10714_on_spirits_wings : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_q10714_on_spirits_wings);
|
||||
@@ -2499,7 +2477,6 @@ void AddSC_quest_spell_scripts()
|
||||
RegisterSpellScript(spell_q12014_steady_as_a_rock);
|
||||
RegisterSpellAndAuraScriptPair(spell_q11026_a11051_banish_the_demons, spell_q11026_a11051_banish_the_demons_aura);
|
||||
RegisterSpellScript(spell_q10525_vision_guide);
|
||||
RegisterSpellScript(spell_q11322_q11317_the_cleansing);
|
||||
RegisterSpellScript(spell_q10714_on_spirits_wings);
|
||||
RegisterSpellScript(spell_q10720_the_smallest_creature);
|
||||
RegisterSpellScript(spell_q13086_last_line_of_defence);
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "AreaDefines.h"
|
||||
#include "CreatureScript.h"
|
||||
#include "Pet.h"
|
||||
#include "PetDefines.h"
|
||||
#include "Player.h"
|
||||
#include "SpellAuraEffects.h"
|
||||
#include "SpellInfo.h"
|
||||
@@ -25,6 +26,8 @@
|
||||
#include "SpellScript.h"
|
||||
#include "SpellScriptLoader.h"
|
||||
#include "TemporarySummon.h"
|
||||
#include "Unit.h"
|
||||
#include "Util.h"
|
||||
/*
|
||||
* Scripts for spells with SPELLFAMILY_WARLOCK and SPELLFAMILY_GENERIC spells used by warlock players.
|
||||
* Ordered alphabetically using scriptname.
|
||||
@@ -73,6 +76,7 @@ enum WarlockSpells
|
||||
SPELL_WARLOCK_EYE_OF_KILROGG_FLY = 58083,
|
||||
SPELL_WARLOCK_PET_VOID_STAR_TALISMAN = 37386, // Void Star Talisman
|
||||
SPELL_WARLOCK_DEMONIC_PACT_PROC = 48090,
|
||||
SPELL_WARLOCK_GLYPH_OF_VOIDWALKER = 56247,
|
||||
};
|
||||
|
||||
enum WarlockSpellIcons
|
||||
@@ -292,7 +296,7 @@ class spell_warl_generic_scaling : public AuraScript
|
||||
|
||||
void CalculateResistanceAmount(AuraEffect const* aurEff, int32& amount, bool& /*canBeRecalculated*/)
|
||||
{
|
||||
// xinef: pet inherits 40% of resistance from owner and 35% of armor
|
||||
// pet inherits 40% of resistance from owner and 35% of armor
|
||||
if (Unit* owner = GetUnitOwner()->GetOwner())
|
||||
{
|
||||
SpellSchoolMask schoolMask = SpellSchoolMask(aurEff->GetSpellInfo()->Effects[aurEff->GetEffIndex()].MiscValue);
|
||||
@@ -308,7 +312,7 @@ class spell_warl_generic_scaling : public AuraScript
|
||||
|
||||
void CalculateStatAmount(AuraEffect const* aurEff, int32& amount, bool& /*canBeRecalculated*/)
|
||||
{
|
||||
// xinef: by default warlock pet inherits 75% of stamina and 30% of intellect
|
||||
// by default warlock pet inherits 75% of stamina and 30% of intellect
|
||||
if (Unit* owner = GetUnitOwner()->GetOwner())
|
||||
{
|
||||
Stats stat = Stats(aurEff->GetSpellInfo()->Effects[aurEff->GetEffIndex()].MiscValue);
|
||||
@@ -317,21 +321,33 @@ class spell_warl_generic_scaling : public AuraScript
|
||||
}
|
||||
}
|
||||
|
||||
void CalculateAPAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/)
|
||||
void CalculateAPAmount(AuraEffect const* aurEff, int32& amount, bool& /*canBeRecalculated*/)
|
||||
{
|
||||
// xinef: by default warlock pet inherits 57% of max(SP FIRE, SP SHADOW) as AP
|
||||
if (Unit* owner = GetUnitOwner()->GetOwner())
|
||||
if (Unit* pet = GetUnitOwner())
|
||||
{
|
||||
int32 fire = owner->SpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_FIRE);
|
||||
int32 shadow = owner->SpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_SHADOW);
|
||||
int32 maximum = (fire > shadow) ? fire : shadow;
|
||||
amount = CalculatePct(std::max<int32>(0, maximum), 57);
|
||||
// by default warlock pet inherits 57% of max(SP FIRE, SP SHADOW) as AP
|
||||
if (Unit* owner = pet->GetOwner())
|
||||
{
|
||||
int32 fire = owner->SpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_FIRE);
|
||||
int32 shadow = owner->SpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_SHADOW);
|
||||
int32 maximum = (fire > shadow) ? fire : shadow;
|
||||
amount = CalculatePct(std::max<int32>(0, maximum), 57);
|
||||
|
||||
// Glyph of felguard, 99% sure this is a HACK
|
||||
if (pet->GetEntry() == NPC_FELGUARD)
|
||||
{
|
||||
if (AuraEffect* glyph = owner->GetAuraEffect(SPELL_GLYPH_OF_FELGUARD, EFFECT_0))
|
||||
{
|
||||
amount += CalculatePct(pet->GetTotalAuraModValue(UNIT_MOD_ATTACK_POWER) - aurEff->GetAmount() + amount, glyph->GetAmount());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CalculateSPAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/)
|
||||
{
|
||||
// xinef: by default warlock pet inherits 15% of max(SP FIRE, SP SHADOW) as SP
|
||||
// by default warlock pet inherits 15% of max(SP FIRE, SP SHADOW) as SP
|
||||
if (Unit* owner = GetUnitOwner()->GetOwner())
|
||||
{
|
||||
int32 fire = owner->SpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_FIRE);
|
||||
@@ -339,7 +355,7 @@ class spell_warl_generic_scaling : public AuraScript
|
||||
int32 maximum = (fire > shadow) ? fire : shadow;
|
||||
amount = CalculatePct(std::max<int32>(0, maximum), 15);
|
||||
|
||||
// xinef: Update appropriate player field
|
||||
// Update appropriate player field
|
||||
if (owner->IsPlayer())
|
||||
owner->SetUInt32Value(PLAYER_PET_SPELL_POWER, (uint32)amount);
|
||||
}
|
||||
@@ -1370,81 +1386,27 @@ class spell_warl_shadowburn : public AuraScript
|
||||
}
|
||||
};
|
||||
|
||||
class spell_warl_glyph_of_felguard : public AuraScript
|
||||
class spell_warl_voidwalker_pet_passive : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_warl_glyph_of_felguard);
|
||||
PrepareAuraScript(spell_warl_voidwalker_pet_passive);
|
||||
|
||||
void HandleApply(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
if (Player* player = GetCaster()->ToPlayer())
|
||||
{
|
||||
if (Pet* pet = player->GetPet())
|
||||
{
|
||||
if (pet->GetEntry() == NPC_FELGUARD)
|
||||
{
|
||||
pet->HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_PCT, aurEff->GetAmount(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ValidateSpellInfo({ SPELL_WARLOCK_GLYPH_OF_VOIDWALKER });
|
||||
}
|
||||
|
||||
void HandleRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
|
||||
void CalculateAmount(AuraEffect const* /* aurEff */, int32& amount, bool& /*canBeRecalculated*/)
|
||||
{
|
||||
if (Player* player = GetCaster()->ToPlayer())
|
||||
{
|
||||
if (Pet* pet = player->GetPet())
|
||||
{
|
||||
if (pet->GetEntry() == NPC_FELGUARD)
|
||||
{
|
||||
pet->HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_PCT, aurEff->GetAmount(), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Unit* pet = GetUnitOwner())
|
||||
if (pet->IsPet())
|
||||
if (Unit* owner = pet->ToPet()->GetOwner())
|
||||
if (AuraEffect* aurEff = owner->GetAuraEffect(SPELL_WARLOCK_GLYPH_OF_VOIDWALKER, EFFECT_0))
|
||||
amount += aurEff->GetAmount();
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectApply += AuraEffectApplyFn(spell_warl_glyph_of_felguard::HandleApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
|
||||
OnEffectRemove += AuraEffectRemoveFn(spell_warl_glyph_of_felguard::HandleRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
|
||||
}
|
||||
};
|
||||
|
||||
class spell_warl_glyph_of_voidwalker : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_warl_glyph_of_voidwalker);
|
||||
|
||||
void HandleApply(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
if (Player* player = GetCaster()->ToPlayer())
|
||||
{
|
||||
if (Pet* pet = player->GetPet())
|
||||
{
|
||||
if (pet->GetEntry() == NPC_VOIDWALKER)
|
||||
{
|
||||
pet->HandleStatModifier(UNIT_MOD_STAT_STAMINA, TOTAL_PCT, aurEff->GetAmount(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HandleRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
if (Player* player = GetCaster()->ToPlayer())
|
||||
{
|
||||
if (Pet* pet = player->GetPet())
|
||||
{
|
||||
if (pet->GetEntry() == NPC_VOIDWALKER)
|
||||
{
|
||||
pet->HandleStatModifier(UNIT_MOD_STAT_STAMINA, TOTAL_PCT, aurEff->GetAmount(), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectApply += AuraEffectApplyFn(spell_warl_glyph_of_voidwalker::HandleApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
|
||||
OnEffectRemove += AuraEffectRemoveFn(spell_warl_glyph_of_voidwalker::HandleRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
|
||||
DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_warl_voidwalker_pet_passive::CalculateAmount, EFFECT_0, SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1529,7 +1491,6 @@ void AddSC_warlock_spell_scripts()
|
||||
RegisterSpellScript(spell_warl_unstable_affliction);
|
||||
RegisterSpellScript(spell_warl_drain_soul);
|
||||
RegisterSpellScript(spell_warl_shadowburn);
|
||||
RegisterSpellScript(spell_warl_glyph_of_felguard);
|
||||
RegisterSpellScript(spell_warl_glyph_of_voidwalker);
|
||||
RegisterSpellScript(spell_warl_voidwalker_pet_passive);
|
||||
RegisterSpellScript(spell_warl_demonic_pact_aura);
|
||||
}
|
||||
|
||||
@@ -563,10 +563,6 @@ public:
|
||||
if (!SpawnAssoc)
|
||||
return;
|
||||
|
||||
// check if they're hostile
|
||||
if (!(me->IsHostileTo(who) || who->IsHostileTo(me)))
|
||||
return;
|
||||
|
||||
if (me->IsValidAttackTarget(who))
|
||||
{
|
||||
Player* playerTarget = who->ToPlayer();
|
||||
|
||||
@@ -1244,8 +1244,7 @@ struct ItemRandomPropertiesEntry
|
||||
{
|
||||
uint32 ID; // 0
|
||||
//char const* InternalName; // 1
|
||||
std::array<uint32, MAX_ITEM_ENCHANTMENT_EFFECTS> Enchantment; // 2-4
|
||||
//std::array<uint32, 2> UnusedEnchantment; // 5-6
|
||||
std::array<uint32, MAX_ITEM_ENCHANTMENT_EFFECTS> Enchantment; // 2-6
|
||||
std::array<char const*, 16> Name; // 7-22
|
||||
//uint32 Name_lang_mask; // 23
|
||||
};
|
||||
@@ -1256,10 +1255,8 @@ struct ItemRandomSuffixEntry
|
||||
std::array<char const*, 16> Name; // 1-16
|
||||
//uint32 Name_lang_mask; // 17
|
||||
//char const* InternalName; // 18
|
||||
std::array<uint32, MAX_ITEM_ENCHANTMENT_EFFECTS> Enchantment; // 19-21
|
||||
//std::array<uint32, 2> UnusedEnchantment; // 22-23
|
||||
std::array<uint32, MAX_ITEM_ENCHANTMENT_EFFECTS> AllocationPct; // 24-26
|
||||
//std::array<uint32, 2> UnusedAllocationPct; // 27-28
|
||||
std::array<uint32, MAX_ITEM_ENCHANTMENT_EFFECTS> Enchantment; // 19-23
|
||||
std::array<uint32, MAX_ITEM_ENCHANTMENT_EFFECTS> AllocationPct; // 24-28
|
||||
};
|
||||
|
||||
#define MAX_ITEM_SET_ITEMS 10
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "IpAddress.h"
|
||||
#include "Log.h"
|
||||
#include "Systemd.h"
|
||||
#include <atomic>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <functional>
|
||||
@@ -33,10 +34,20 @@ class AsyncAcceptor
|
||||
public:
|
||||
typedef void(*AcceptCallback)(tcp::socket&& newSocket, uint32 threadIndex);
|
||||
|
||||
AsyncAcceptor(Acore::Asio::IoContext& ioContext, std::string const& bindIp, uint16 port) :
|
||||
AsyncAcceptor(Acore::Asio::IoContext& ioContext, std::string const& bindIp, uint16 port, bool supportSocketActivation = false) :
|
||||
_acceptor(ioContext), _endpoint(Acore::Net::make_address(bindIp), port),
|
||||
_socket(ioContext), _closed(false), _socketFactory([this](){ return DefaultSocketFactory(); })
|
||||
_socket(ioContext), _closed(false), _socketFactory([this](){ return DefaultSocketFactory(); }),
|
||||
_supportSocketActivation(supportSocketActivation)
|
||||
{
|
||||
int const listen_fd = get_listen_fd();
|
||||
if (_supportSocketActivation && listen_fd > 0)
|
||||
{
|
||||
LOG_DEBUG("network", "Using socket from systemd socket activation");
|
||||
boost::system::error_code errorCode;
|
||||
_acceptor.assign(boost::asio::ip::tcp::v4(), listen_fd, errorCode);
|
||||
if (errorCode)
|
||||
LOG_WARN("network", "Failed to assign socket {}", errorCode.message());
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
@@ -72,27 +83,31 @@ public:
|
||||
bool Bind()
|
||||
{
|
||||
boost::system::error_code errorCode;
|
||||
_acceptor.open(_endpoint.protocol(), errorCode);
|
||||
if (errorCode)
|
||||
// with socket activation the acceptor is already open and bound
|
||||
if (!_acceptor.is_open())
|
||||
{
|
||||
LOG_INFO("network", "Failed to open acceptor {}", errorCode.message());
|
||||
return false;
|
||||
}
|
||||
_acceptor.open(_endpoint.protocol(), errorCode);
|
||||
if (errorCode)
|
||||
{
|
||||
LOG_INFO("network", "Failed to open acceptor {}", errorCode.message());
|
||||
return false;
|
||||
}
|
||||
|
||||
#if AC_PLATFORM != AC_PLATFORM_WINDOWS
|
||||
_acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true), errorCode);
|
||||
if (errorCode)
|
||||
{
|
||||
LOG_INFO("network", "Failed to set reuse_address option on acceptor {}", errorCode.message());
|
||||
return false;
|
||||
}
|
||||
_acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true), errorCode);
|
||||
if (errorCode)
|
||||
{
|
||||
LOG_INFO("network", "Failed to set reuse_address option on acceptor {}", errorCode.message());
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
_acceptor.bind(_endpoint, errorCode);
|
||||
if (errorCode)
|
||||
{
|
||||
LOG_INFO("network", "Could not bind to {}:{} {}", _endpoint.address().to_string(), _endpoint.port(), errorCode.message());
|
||||
return false;
|
||||
_acceptor.bind(_endpoint, errorCode);
|
||||
if (errorCode)
|
||||
{
|
||||
LOG_INFO("network", "Could not bind to {}:{} {}", _endpoint.address().to_string(), _endpoint.port(), errorCode.message());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
_acceptor.listen(ACORE_MAX_LISTEN_CONNECTIONS, errorCode);
|
||||
@@ -124,6 +139,7 @@ private:
|
||||
tcp::socket _socket;
|
||||
std::atomic<bool> _closed;
|
||||
std::function<std::pair<tcp::socket*, uint32>()> _socketFactory;
|
||||
bool _supportSocketActivation;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#define SocketMgr_h__
|
||||
|
||||
#include "AsyncAcceptor.h"
|
||||
#include "Config.h"
|
||||
#include "Errors.h"
|
||||
#include "NetworkThread.h"
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
@@ -42,7 +43,8 @@ public:
|
||||
std::unique_ptr<AsyncAcceptor> acceptor;
|
||||
try
|
||||
{
|
||||
acceptor = std::make_unique<AsyncAcceptor>(ioContext, bindIp, port);
|
||||
bool supportSocketActivation = sConfigMgr->GetOption<bool>("Network.UseSocketActivation", false);
|
||||
acceptor = std::make_unique<AsyncAcceptor>(ioContext, bindIp, port, supportSocketActivation);
|
||||
}
|
||||
catch (boost::system::system_error const& err)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user