Merge branch 'azerothcore:master' into Playerbot
This commit is contained in:
@@ -4059,6 +4059,13 @@ void SmartScript::UpdateTimer(SmartScriptHolder& e, uint32 const diff)
|
||||
}
|
||||
}
|
||||
|
||||
// Delay flee for assist event if casting
|
||||
if (e.GetActionType() == SMART_ACTION_FLEE_FOR_ASSIST && me && me->HasUnitState(UNIT_STATE_CASTING))
|
||||
{
|
||||
e.timer = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
e.active = true;//activate events with cooldown
|
||||
switch (e.GetEventType())//process ONLY timed events
|
||||
{
|
||||
|
||||
@@ -1745,11 +1745,13 @@ void GameObject::Use(Unit* user)
|
||||
|
||||
LOG_DEBUG("entities.gameobject", "Fishing check (skill: {} zone min skill: {} chance {} roll: {}", skill, zone_skill, chance, roll);
|
||||
|
||||
if (sScriptMgr->OnUpdateFishingSkill(player, skill, zone_skill, chance, roll))
|
||||
{
|
||||
player->UpdateFishingSkill();
|
||||
}
|
||||
// but you will likely cause junk in areas that require a high fishing skill (not yet implemented)
|
||||
if (chance >= roll)
|
||||
{
|
||||
player->UpdateFishingSkill();
|
||||
|
||||
//TODO: I do not understand this hack. Need some explanation.
|
||||
// prevent removing GO at spell cancel
|
||||
RemoveFromOwner();
|
||||
|
||||
@@ -169,6 +169,7 @@ ProcEventInfo::ProcEventInfo(Unit* actor, Unit* actionTarget, Unit* procTarget,
|
||||
: _actor(actor), _actionTarget(actionTarget), _procTarget(procTarget), _typeMask(typeMask), _spellTypeMask(spellTypeMask), _spellPhaseMask(spellPhaseMask),
|
||||
_hitMask(hitMask), _spell(spell), _damageInfo(damageInfo), _healInfo(healInfo), _triggeredByAuraSpell(triggeredByAuraSpell), _procAuraEffectIndex(procAuraEffectIndex)
|
||||
{
|
||||
_chance.reset();
|
||||
}
|
||||
|
||||
SpellInfo const* ProcEventInfo::GetSpellInfo() const
|
||||
@@ -15869,18 +15870,29 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u
|
||||
if (!active && !isVictim && !(procFlag & PROC_FLAG_DONE_PERIODIC) && procSpellInfo && procSpellInfo->SpellFamilyName && (procSpellInfo->HasAura(SPELL_AURA_PERIODIC_DAMAGE) || procSpellInfo->HasAura(SPELL_AURA_PERIODIC_HEAL)))
|
||||
active = true;
|
||||
|
||||
if (!IsTriggeredAtSpellProcEvent(target, triggerData.aura, attType, isVictim, active, triggerData.spellProcEvent, eventInfo))
|
||||
// AuraScript Hook
|
||||
if (!triggerData.aura->CallScriptCheckProcHandlers(itr->second, eventInfo))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
bool isTriggeredAtSpellProcEvent = IsTriggeredAtSpellProcEvent(target, triggerData.aura, attType, isVictim, active, triggerData.spellProcEvent, eventInfo);
|
||||
|
||||
// AuraScript Hook
|
||||
triggerData.aura->CallScriptCheckAfterProcHandlers(itr->second, eventInfo);
|
||||
|
||||
if (!isTriggeredAtSpellProcEvent)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// do checks using conditions table
|
||||
ConditionList conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_SPELL_PROC, spellProto->Id);
|
||||
ConditionSourceInfo condInfo = ConditionSourceInfo(eventInfo.GetActor(), eventInfo.GetActionTarget());
|
||||
if (!sConditionMgr->IsObjectMeetToConditions(condInfo, conditions))
|
||||
{
|
||||
continue;
|
||||
|
||||
// AuraScript Hook
|
||||
if (!triggerData.aura->CallScriptCheckProcHandlers(itr->second, eventInfo))
|
||||
continue;
|
||||
}
|
||||
|
||||
// Triggered spells not triggering additional spells
|
||||
//bool triggered = !spellProto->HasAttribute(SPELL_ATTR3_CAN_PROC_FROM_PROCS) ?
|
||||
@@ -17181,11 +17193,17 @@ bool Unit::IsTriggeredAtSpellProcEvent(Unit* victim, Aura* aura, WeaponAttackTyp
|
||||
}
|
||||
}
|
||||
|
||||
if (eventInfo.GetProcChance())
|
||||
{
|
||||
chance = *eventInfo.GetProcChance();
|
||||
}
|
||||
|
||||
// Apply chance modifer aura
|
||||
if (Player* modOwner = GetSpellModOwner())
|
||||
{
|
||||
modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CHANCE_OF_SUCCESS, chance);
|
||||
}
|
||||
|
||||
return roll_chance_f(chance);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "HostileRefMgr.h"
|
||||
#include "MotionMaster.h"
|
||||
#include "Object.h"
|
||||
#include "Optional.h"
|
||||
#include "SpellAuraDefines.h"
|
||||
#include "SpellDefines.h"
|
||||
#include "ThreatMgr.h"
|
||||
@@ -836,6 +837,7 @@ private:
|
||||
HealInfo* _healInfo;
|
||||
SpellInfo const* const _triggeredByAuraSpell;
|
||||
int8 _procAuraEffectIndex;
|
||||
std::optional<float> _chance;
|
||||
|
||||
public:
|
||||
explicit ProcEventInfo(Unit* actor, Unit* actionTarget, Unit* procTarget, uint32 typeMask, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell const* spell, DamageInfo* damageInfo, HealInfo* healInfo, SpellInfo const* triggeredByAuraSpell = nullptr, int8 procAuraEffectIndex = -1);
|
||||
@@ -855,6 +857,9 @@ public:
|
||||
[[nodiscard]] int8 GetTriggerAuraEffectIndex() const { return _procAuraEffectIndex; }
|
||||
[[nodiscard]] uint32 GetProcCooldown() const { return _cooldown; }
|
||||
void SetProcCooldown(uint32 cooldown) { _cooldown = cooldown; }
|
||||
[[nodiscard]] std::optional<float> GetProcChance() const { return _chance; }
|
||||
void SetProcChance(float chance) { _chance = chance; }
|
||||
void ResetProcChance() { _chance.reset(); }
|
||||
};
|
||||
|
||||
// Struct for use in Unit::CalculateMeleeDamage
|
||||
|
||||
@@ -422,6 +422,11 @@ void WorldSession::HandleCharCreateOpcode(WorldPacket& recvData)
|
||||
|
||||
std::function<void(PreparedQueryResult)> finalizeCharacterCreation = [this, createInfo](PreparedQueryResult result)
|
||||
{
|
||||
if (!sScriptMgr->CanAccountCreateCharacter(createInfo, GetAccountId()))
|
||||
{
|
||||
SendCharCreate(CHAR_CREATE_DISABLED);
|
||||
return;
|
||||
}
|
||||
bool haveSameRace = false;
|
||||
uint32 heroicReqLevel = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_MIN_LEVEL_FOR_HEROIC_CHARACTER);
|
||||
bool hasHeroicReqLevel = (heroicReqLevel == 0);
|
||||
|
||||
@@ -153,13 +153,7 @@ void MailDraft::SendReturnToSender(uint32 /*sender_acc*/, ObjectGuid::LowType se
|
||||
{
|
||||
Player* receiver = ObjectAccessor::FindPlayerByLowGUID(receiver_guid);
|
||||
|
||||
uint32 rc_account = 0;
|
||||
if (!receiver)
|
||||
{
|
||||
rc_account = sCharacterCache->GetCharacterAccountIdByGuid(ObjectGuid(HighGuid::Player, receiver_guid));
|
||||
}
|
||||
|
||||
if (!receiver && !rc_account) // sender not exist
|
||||
if (!receiver && !sCharacterCache->GetCharacterAccountIdByGuid(ObjectGuid(HighGuid::Player, receiver_guid)))
|
||||
{
|
||||
deleteIncludedItems(trans, true);
|
||||
return;
|
||||
@@ -200,7 +194,6 @@ void MailDraft::SendMailTo(CharacterDatabaseTransaction trans, MailReceiver cons
|
||||
return;
|
||||
|
||||
Player* pReceiver = receiver.GetPlayer(); // can be nullptr
|
||||
Player* pSender = ObjectAccessor::FindPlayerByLowGUID(sender.GetSenderId());
|
||||
|
||||
if (pReceiver)
|
||||
prepareItems(pReceiver, trans); // generate mail template items
|
||||
@@ -219,14 +212,14 @@ void MailDraft::SendMailTo(CharacterDatabaseTransaction trans, MailReceiver cons
|
||||
else if (sender.GetMailMessageType() == MAIL_CREATURE && sBattlegroundMgr->GetBattleMasterBG(sender.GetSenderId()) != BATTLEGROUND_TYPE_NONE)
|
||||
expire_delay = DAY;
|
||||
// default case: expire time if COD 3 days, if no COD 30 days (or 90 days if sender is a game master)
|
||||
else if (m_COD)
|
||||
expire_delay = 3 * DAY;
|
||||
else if (custom_expiration > 0)
|
||||
expire_delay = custom_expiration * DAY;
|
||||
else
|
||||
{
|
||||
if (m_COD)
|
||||
expire_delay = 3 * DAY;
|
||||
else if (custom_expiration > 0 )
|
||||
expire_delay = custom_expiration * DAY;
|
||||
else
|
||||
expire_delay = pSender && pSender->GetSession()->GetSecurity() ? 90 * DAY : 30 * DAY;
|
||||
Player* pSender = ObjectAccessor::FindPlayerByLowGUID(sender.GetSenderId());
|
||||
expire_delay = pSender && pSender->GetSession()->GetSecurity() ? 90 * DAY : 30 * DAY;
|
||||
}
|
||||
|
||||
time_t expire_time = deliver_time + expire_delay;
|
||||
@@ -235,27 +228,26 @@ void MailDraft::SendMailTo(CharacterDatabaseTransaction trans, MailReceiver cons
|
||||
uint8 index = 0;
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_MAIL);
|
||||
stmt->SetData( index, mailId);
|
||||
stmt->SetData (++index, uint8(sender.GetMailMessageType()));
|
||||
stmt->SetData (++index, int8(sender.GetStationery()));
|
||||
stmt->SetData(++index, uint8(sender.GetMailMessageType()));
|
||||
stmt->SetData(++index, int8(sender.GetStationery()));
|
||||
stmt->SetData(++index, GetMailTemplateId());
|
||||
stmt->SetData(++index, sender.GetSenderId());
|
||||
stmt->SetData(++index, receiver.GetPlayerGUIDLow());
|
||||
stmt->SetData(++index, GetSubject());
|
||||
stmt->SetData(++index, GetBody());
|
||||
stmt->SetData (++index, !m_items.empty());
|
||||
stmt->SetData(++index, !m_items.empty());
|
||||
stmt->SetData(++index, uint32(expire_time));
|
||||
stmt->SetData(++index, uint32(deliver_time));
|
||||
stmt->SetData(++index, m_money);
|
||||
stmt->SetData(++index, m_COD);
|
||||
stmt->SetData (++index, uint8(checked));
|
||||
stmt->SetData(++index, uint8(checked));
|
||||
trans->Append(stmt);
|
||||
|
||||
for (MailItemMap::const_iterator mailItemIter = m_items.begin(); mailItemIter != m_items.end(); ++mailItemIter)
|
||||
{
|
||||
Item* pItem = mailItemIter->second;
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_MAIL_ITEM);
|
||||
stmt->SetData(0, mailId);
|
||||
stmt->SetData(1, pItem->GetGUID().GetCounter());
|
||||
stmt->SetData(1, mailItemIter->second->GetGUID().GetCounter());
|
||||
stmt->SetData(2, receiver.GetPlayerGUIDLow());
|
||||
trans->Append(stmt);
|
||||
}
|
||||
@@ -302,7 +294,6 @@ void MailDraft::SendMailTo(CharacterDatabaseTransaction trans, MailReceiver cons
|
||||
}
|
||||
else if (!m_items.empty())
|
||||
{
|
||||
CharacterDatabaseTransaction temp = CharacterDatabaseTransaction(nullptr);
|
||||
deleteIncludedItems(temp);
|
||||
deleteIncludedItems(CharacterDatabaseTransaction(nullptr));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,3 +81,18 @@ void ScriptMgr::OnFailedPasswordChange(uint32 accountId)
|
||||
script->OnFailedPasswordChange(accountId);
|
||||
});
|
||||
}
|
||||
|
||||
bool ScriptMgr::CanAccountCreateCharacter(std::shared_ptr<CharacterCreateInfo> createInfo, uint32 accountId)
|
||||
{
|
||||
auto ret = IsValidBoolScript<AccountScript>([&](AccountScript* script)
|
||||
{
|
||||
return !script->CanAccountCreateCharacter(createInfo, accountId);
|
||||
});
|
||||
|
||||
if (ret && *ret)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -936,6 +936,21 @@ void ScriptMgr::OnGetMaxSkillValue(Player* player, uint32 skill, int32& result,
|
||||
});
|
||||
}
|
||||
|
||||
bool ScriptMgr::OnUpdateFishingSkill(Player* player, int32 skill, int32 zone_skill, int32 chance, int32 roll)
|
||||
{
|
||||
auto ret = IsValidBoolScript<PlayerScript>([&](PlayerScript* script)
|
||||
{
|
||||
return !script->OnUpdateFishingSkill(player, skill, zone_skill, chance, roll);
|
||||
});
|
||||
|
||||
if (ret && *ret)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ScriptMgr::CanAreaExploreAndOutdoor(Player* player)
|
||||
{
|
||||
auto ret = IsValidBoolScript<PlayerScript>([&](PlayerScript* script)
|
||||
|
||||
@@ -73,6 +73,7 @@ class Vehicle;
|
||||
class WorldObject;
|
||||
class WorldPacket;
|
||||
class WorldSocket;
|
||||
class CharacterCreateInfo;
|
||||
|
||||
struct AchievementCriteriaData;
|
||||
struct AuctionEntry;
|
||||
@@ -1251,6 +1252,8 @@ public:
|
||||
|
||||
virtual void OnGetMaxSkillValue(Player* /*player*/, uint32 /*skill*/, int32& /*result*/, bool /*IsPure*/) { }
|
||||
|
||||
[[nodiscard]] virtual bool OnUpdateFishingSkill(Player* /*player*/, int32 /*skill*/, int32 /*zone_skill*/, int32 /*chance*/, int32 /*roll*/) { return true; }
|
||||
|
||||
[[nodiscard]] virtual bool CanAreaExploreAndOutdoor(Player* /*player*/) { return true; }
|
||||
|
||||
virtual void OnVictimRewardBefore(Player* /*player*/, Player* /*victim*/, uint32& /*killer_title*/, uint32& /*victim_title*/) { }
|
||||
@@ -1458,6 +1461,9 @@ public:
|
||||
|
||||
// Called when Password failed to change for Account
|
||||
virtual void OnFailedPasswordChange(uint32 /*accountId*/) { }
|
||||
|
||||
// Called when creating a character on the Account
|
||||
[[nodiscard]] virtual bool CanAccountCreateCharacter(std::shared_ptr<CharacterCreateInfo> /*createInfo*/, uint32 /*accountId*/) { return true;}
|
||||
};
|
||||
|
||||
class GuildScript : public ScriptObject
|
||||
@@ -2330,6 +2336,7 @@ public: /* PlayerScript */
|
||||
void OnDeleteFromDB(CharacterDatabaseTransaction trans, uint32 guid);
|
||||
bool CanRepopAtGraveyard(Player* player);
|
||||
void OnGetMaxSkillValue(Player* player, uint32 skill, int32& result, bool IsPure);
|
||||
bool OnUpdateFishingSkill(Player* player, int32 skill, int32 zone_skill, int32 chance, int32 roll);
|
||||
bool CanAreaExploreAndOutdoor(Player* player);
|
||||
void OnVictimRewardBefore(Player* player, Player* victim, uint32& killer_title, uint32& victim_title);
|
||||
void OnVictimRewardAfter(Player* player, Player* victim, uint32& killer_title, uint32& victim_rank, float& honor_f);
|
||||
@@ -2394,6 +2401,7 @@ public: /* AccountScript */
|
||||
void OnFailedEmailChange(uint32 accountId);
|
||||
void OnPasswordChange(uint32 accountId);
|
||||
void OnFailedPasswordChange(uint32 accountId);
|
||||
bool CanAccountCreateCharacter(std::shared_ptr<CharacterCreateInfo> createInfo, uint32 accountId);
|
||||
|
||||
public: /* GuildScript */
|
||||
void OnGuildAddMember(Guild* guild, Player* player, uint8& plRank);
|
||||
|
||||
@@ -1450,6 +1450,26 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b
|
||||
else
|
||||
target->AddAura(74396, target);
|
||||
}
|
||||
break;
|
||||
case 12494: // Frostbite, synchronise with Fingers of Frost
|
||||
{
|
||||
// Find Fingers of Frost
|
||||
if (AuraEffect* aurEff = caster->GetAuraEffect(SPELL_AURA_PROC_TRIGGER_SPELL, SPELLFAMILY_MAGE, 2947, EFFECT_0))
|
||||
{
|
||||
if (SpellInfo const* triggeringSpellInfo = GetTriggeredByAuraSpellInfo())
|
||||
{
|
||||
uint8 fbRank = sSpellMgr->GetSpellRank(triggeringSpellInfo->Id);
|
||||
uint8 fofRank = sSpellMgr->GetSpellRank(aurEff->GetId());
|
||||
uint8 chance = uint8(std::ceil(fofRank * fbRank * 16.6f));
|
||||
|
||||
if (roll_chance_i(chance))
|
||||
{
|
||||
caster->CastSpell(caster, aurEff->GetSpellInfo()->Effects[EFFECT_0].TriggerSpell, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -2620,6 +2640,22 @@ bool Aura::CallScriptCheckProcHandlers(AuraApplication const* aurApp, ProcEventI
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Aura::CallScriptCheckAfterProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo)
|
||||
{
|
||||
bool result = true;
|
||||
for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
|
||||
{
|
||||
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_CHECK_AFTER_PROC, aurApp);
|
||||
std::list<AuraScript::CheckProcHandler>::iterator hookItrEnd = (*scritr)->DoCheckAfterProc.end(), hookItr = (*scritr)->DoCheckAfterProc.begin();
|
||||
for (; hookItr != hookItrEnd; ++hookItr)
|
||||
result &= hookItr->Call(*scritr, eventInfo);
|
||||
|
||||
(*scritr)->_FinishScriptCall();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Aura::CallScriptPrepareProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo)
|
||||
{
|
||||
bool prepare = true;
|
||||
|
||||
@@ -226,6 +226,7 @@ public:
|
||||
|
||||
// Spell Proc Hooks
|
||||
bool CallScriptCheckProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo);
|
||||
bool CallScriptCheckAfterProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo);
|
||||
bool CallScriptPrepareProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo);
|
||||
bool CallScriptProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo);
|
||||
void CallScriptAfterProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo);
|
||||
|
||||
@@ -3278,12 +3278,14 @@ void Spell::DoTriggersOnSpellHit(Unit* unit, uint8 effMask)
|
||||
}
|
||||
else
|
||||
{
|
||||
m_caster->CastCustomSpell(i->triggeredSpell->Id, SPELLVALUE_AURA_DURATION, _duration, unit, true);
|
||||
AuraEffect const* triggeringAuraEffect = m_caster->GetAuraEffect(i->triggeredByAura->Id, i->triggeredByEffIdx);
|
||||
m_caster->CastCustomSpell(i->triggeredSpell->Id, SPELLVALUE_AURA_DURATION, _duration, unit, true, nullptr, triggeringAuraEffect);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_caster->CastSpell(unit, i->triggeredSpell, true);
|
||||
AuraEffect const* triggeringAuraEffect = m_caster->GetAuraEffect(i->triggeredByAura->Id, i->triggeredByEffIdx);
|
||||
m_caster->CastSpell(unit, i->triggeredSpell, true, nullptr, triggeringAuraEffect);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8766,6 +8768,7 @@ void Spell::PrepareTriggersExecutedOnHit()
|
||||
HitTriggerSpell spellTriggerInfo;
|
||||
spellTriggerInfo.triggeredSpell = spellInfo;
|
||||
spellTriggerInfo.triggeredByAura = auraSpellInfo;
|
||||
spellTriggerInfo.triggeredByEffIdx = (*i)->GetEffIndex();
|
||||
spellTriggerInfo.chance = chance * (*i)->GetBase()->GetStackAmount();
|
||||
m_hitTriggerSpells.push_back(spellTriggerInfo);
|
||||
}
|
||||
|
||||
@@ -741,7 +741,7 @@ public:
|
||||
{
|
||||
SpellInfo const* triggeredSpell;
|
||||
SpellInfo const* triggeredByAura;
|
||||
// uint8 triggeredByEffIdx This might be needed at a later stage - No need known for now
|
||||
uint8 triggeredByEffIdx;
|
||||
int32 chance;
|
||||
};
|
||||
|
||||
|
||||
@@ -733,6 +733,10 @@ bool AuraScript::_Validate(SpellInfo const* entry)
|
||||
if (!entry->HasEffect(SPELL_EFFECT_APPLY_AURA) && !entry->HasAreaAuraEffect())
|
||||
LOG_ERROR("spells.scripts", "Spell `{}` of script `{}` does not have apply aura effect - handler bound to hook `DoCheckProc` of AuraScript won't be executed", entry->Id, m_scriptName->c_str());
|
||||
|
||||
for (std::list<CheckProcHandler>::iterator itr = DoCheckAfterProc.begin(); itr != DoCheckAfterProc.end(); ++itr)
|
||||
if (!entry->HasEffect(SPELL_EFFECT_APPLY_AURA) && !entry->HasAreaAuraEffect())
|
||||
LOG_ERROR("spells.scripts", "Spell `{}` of script `{}` does not have apply aura effect - handler bound to hook `DoCheckAfterProc` of AuraScript won't be executed", entry->Id, m_scriptName->c_str());
|
||||
|
||||
for (std::list<AuraProcHandler>::iterator itr = DoPrepareProc.begin(); itr != DoPrepareProc.end(); ++itr)
|
||||
if (!entry->HasEffect(SPELL_EFFECT_APPLY_AURA) && !entry->HasAreaAuraEffect())
|
||||
LOG_ERROR("spells.scripts", "Spell `{}` of script `{}` does not have apply aura effect - handler bound to hook `DoPrepareProc` of AuraScript won't be executed", entry->Id, m_scriptName->c_str());
|
||||
@@ -1163,6 +1167,7 @@ Unit* AuraScript::GetTarget() const
|
||||
case AURA_SCRIPT_HOOK_EFFECT_AFTER_MANASHIELD:
|
||||
case AURA_SCRIPT_HOOK_EFFECT_SPLIT:
|
||||
case AURA_SCRIPT_HOOK_CHECK_PROC:
|
||||
case AURA_SCRIPT_HOOK_CHECK_AFTER_PROC:
|
||||
case AURA_SCRIPT_HOOK_PREPARE_PROC:
|
||||
case AURA_SCRIPT_HOOK_PROC:
|
||||
case AURA_SCRIPT_HOOK_AFTER_PROC:
|
||||
|
||||
@@ -499,6 +499,7 @@ enum AuraScriptHookType
|
||||
AURA_SCRIPT_HOOK_AFTER_DISPEL,
|
||||
// Spell Proc Hooks
|
||||
AURA_SCRIPT_HOOK_CHECK_PROC,
|
||||
AURA_SCRIPT_HOOK_CHECK_AFTER_PROC,
|
||||
AURA_SCRIPT_HOOK_PREPARE_PROC,
|
||||
AURA_SCRIPT_HOOK_PROC,
|
||||
AURA_SCRIPT_HOOK_EFFECT_PROC,
|
||||
@@ -804,6 +805,10 @@ public:
|
||||
// example: DoCheckProc += AuraCheckProcFn(class::function);
|
||||
// where function is: bool function (ProcEventInfo& eventInfo);
|
||||
HookList<CheckProcHandler> DoCheckProc;
|
||||
// executed when aura checks if it can proc
|
||||
// example: DoCheckAfterProc += AuraCheckProcFn(class::function);
|
||||
// where function is: bool function (ProcEventInfo& eventInfo);
|
||||
HookList<CheckProcHandler> DoCheckAfterProc;
|
||||
#define AuraCheckProcFn(F) CheckProcHandlerFunction(&F)
|
||||
|
||||
// executed before aura procs (possibility to prevent charge drop/cooldown)
|
||||
|
||||
+4
-1
@@ -76,6 +76,8 @@ enum CreaturesIds
|
||||
NPC_BLACKHAND_INCARCERATOR = 10316,
|
||||
NPC_LORD_VICTOR_NEFARIUS = 10162,
|
||||
|
||||
NPC_SCARSHIELD_INFILTRATOR = 10299,
|
||||
|
||||
NPC_SOLAKAR = 10264,
|
||||
NPC_ROOKERY_GUARDIAN = 10258,
|
||||
NPC_ROOKERY_HATCHER = 10683,
|
||||
@@ -95,7 +97,8 @@ enum AdditionalData
|
||||
AREATRIGGER = 1,
|
||||
AREATRIGGER_DRAGONSPIRE_HALL = 2046,
|
||||
AREATRIGGER_BLACKROCK_STADIUM = 2026,
|
||||
SAY_FINKLE_GANG = 0
|
||||
SAY_FINKLE_GANG = 0,
|
||||
ITEM_UNADORNED_SEAL = 12219
|
||||
};
|
||||
|
||||
enum GameObjectsIds
|
||||
|
||||
+57
-1
@@ -53,7 +53,8 @@ Position SolakarPosBoss = Position(80.0f, -280.0f, 93.0f, 3.0f * M_PI / 2.0);
|
||||
enum Texts
|
||||
{
|
||||
SAY_NEFARIUS_REND_WIPE = 11,
|
||||
SAY_SOLAKAR_FIRST_HATCHER = 0
|
||||
SAY_SOLAKAR_FIRST_HATCHER = 0,
|
||||
SAY_SCARSHIELD_INF_WHISPER = 0
|
||||
};
|
||||
|
||||
MinionData const minionData[] =
|
||||
@@ -823,10 +824,65 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class near_scarshield_infiltrator : public AreaTriggerScript
|
||||
{
|
||||
public:
|
||||
near_scarshield_infiltrator() : AreaTriggerScript("near_scarshield_infiltrator") { }
|
||||
|
||||
bool OnTrigger(Player* player, const AreaTrigger* /*at*/) override
|
||||
{
|
||||
if (player && player->IsAlive())
|
||||
{
|
||||
if (Creature* creature = player->FindNearestCreature(NPC_SCARSHIELD_INFILTRATOR, 100.0f, true))
|
||||
{
|
||||
bool transformHasStarted = creature->AI()->GetData(0) == 1;
|
||||
if ((player->getLevel() < 57 || !player->HasItemCount(ITEM_UNADORNED_SEAL)) && !transformHasStarted)
|
||||
{
|
||||
// Send whisper if not already sent
|
||||
std::list<ObjectGuid>::iterator itr = std::find(whisperedTargets.begin(), whisperedTargets.end(), player->GetGUID());
|
||||
if (itr == whisperedTargets.end())
|
||||
{
|
||||
creature->AI()->Talk(SAY_SCARSHIELD_INF_WHISPER, player);
|
||||
whisperedTargets.push_back(player->GetGUID());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private:
|
||||
GuidList whisperedTargets;
|
||||
};
|
||||
|
||||
class at_scarshield_infiltrator : public AreaTriggerScript
|
||||
{
|
||||
public:
|
||||
at_scarshield_infiltrator() : AreaTriggerScript("at_scarshield_infiltrator") { }
|
||||
|
||||
bool OnTrigger(Player* player, const AreaTrigger* /*at*/) override
|
||||
{
|
||||
if (player && player->IsAlive())
|
||||
{
|
||||
if (Creature* creature = player->FindNearestCreature(NPC_SCARSHIELD_INFILTRATOR, 100.0f, true))
|
||||
{
|
||||
if (player->getLevel() >= 57 && player->HasItemCount(ITEM_UNADORNED_SEAL))
|
||||
{
|
||||
creature->AI()->SetData(0, 1); // Start transform into Vaelan
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_instance_blackrock_spire()
|
||||
{
|
||||
new instance_blackrock_spire();
|
||||
new at_dragonspire_hall();
|
||||
new at_blackrock_stadium();
|
||||
new go_father_flame();
|
||||
new near_scarshield_infiltrator();
|
||||
new at_scarshield_infiltrator();
|
||||
}
|
||||
|
||||
@@ -89,6 +89,7 @@ struct boss_ayamiss : public BossAI
|
||||
_enraged = false;
|
||||
SetCombatMovement(false);
|
||||
_scheduler.CancelAll();
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* who) override
|
||||
@@ -120,6 +121,7 @@ struct boss_ayamiss : public BossAI
|
||||
|
||||
me->m_Events.AddEventAtOffset([this]()
|
||||
{
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
if (me->GetVictim())
|
||||
{
|
||||
me->GetMotionMaster()->MoveChase(me->GetVictim());
|
||||
@@ -157,7 +159,7 @@ struct boss_ayamiss : public BossAI
|
||||
}
|
||||
|
||||
context.Repeat(RAND(2400ms, 3600ms));
|
||||
}).Schedule(15s, [this](TaskContext context) {
|
||||
}).Schedule(15s, 28s, [this](TaskContext context) {
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0, true))
|
||||
{
|
||||
DoCast(target, SPELL_PARALYZE, true);
|
||||
@@ -215,6 +217,7 @@ struct boss_ayamiss : public BossAI
|
||||
{
|
||||
_phase = PHASE_GROUND;
|
||||
me->ClearUnitState(UNIT_STATE_ROOT);
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->SetCanFly(false);
|
||||
me->SetDisableGravity(false);
|
||||
me->GetMotionMaster()->MovePath(me->GetEntry() * 10, false);
|
||||
|
||||
@@ -134,8 +134,6 @@ struct boss_skeram : public BossAI
|
||||
{
|
||||
_JustDied();
|
||||
Talk(SAY_DEATH);
|
||||
|
||||
instance->HandleGameObject(instance->GetGuidData(AQ40_DOOR_3), true);
|
||||
}
|
||||
else
|
||||
me->RemoveCorpse();
|
||||
|
||||
@@ -31,6 +31,14 @@ ObjectData const creatureData[] =
|
||||
{ NPC_VEKNILASH, DATA_VEKNILASH }
|
||||
};
|
||||
|
||||
DoorData const doorData[] =
|
||||
{
|
||||
{ AQ40_DOOR_SKERAM, DATA_SKERAM, DOOR_TYPE_PASSAGE },
|
||||
{ AQ40_DOOR_TE_ENTRANCE, DATA_TWIN_EMPERORS, DOOR_TYPE_ROOM },
|
||||
{ AQ40_DOOR_TE_EXIT, DATA_TWIN_EMPERORS, DOOR_TYPE_PASSAGE },
|
||||
{ 0, 0, DOOR_TYPE_ROOM}
|
||||
};
|
||||
|
||||
class instance_temple_of_ahnqiraj : public InstanceMapScript
|
||||
{
|
||||
public:
|
||||
@@ -45,9 +53,9 @@ public:
|
||||
{
|
||||
instance_temple_of_ahnqiraj_InstanceMapScript(Map* map) : InstanceScript(map)
|
||||
{
|
||||
LoadObjectData(creatureData, nullptr);
|
||||
doorGUIDs.fill(ObjectGuid::Empty);
|
||||
SetBossNumber(MAX_BOSS_NUMBER);
|
||||
LoadObjectData(creatureData, nullptr);
|
||||
LoadDoorData(doorData);
|
||||
}
|
||||
|
||||
ObjectGuid SkeramGUID;
|
||||
@@ -57,7 +65,6 @@ public:
|
||||
ObjectGuid ViscidusGUID;
|
||||
ObjectGuid CThunGUID;
|
||||
GuidVector CThunGraspGUIDs;
|
||||
std::array<ObjectGuid, 3> doorGUIDs;
|
||||
|
||||
uint32 BugTrioDeathCount;
|
||||
uint32 CthunPhase;
|
||||
@@ -74,10 +81,6 @@ public:
|
||||
{
|
||||
case NPC_SKERAM:
|
||||
SkeramGUID = creature->GetGUID();
|
||||
if (!creature->IsAlive())
|
||||
{
|
||||
HandleGameObject(doorGUIDs[2], true);
|
||||
}
|
||||
break;
|
||||
case NPC_VEM:
|
||||
VemGUID = creature->GetGUID();
|
||||
@@ -123,29 +126,6 @@ public:
|
||||
{
|
||||
switch (go->GetEntry())
|
||||
{
|
||||
case AQ40_DOOR_1:
|
||||
doorGUIDs[0] = go->GetGUID();
|
||||
break;
|
||||
case AQ40_DOOR_2:
|
||||
doorGUIDs[1] = go->GetGUID();
|
||||
if (Creature* veklor = GetCreature(DATA_VEKLOR))
|
||||
{
|
||||
if (!veklor->IsAlive())
|
||||
{
|
||||
HandleGameObject(go->GetGUID(), true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AQ40_DOOR_3:
|
||||
doorGUIDs[2] = go->GetGUID();
|
||||
if (Creature* skeram = instance->GetCreature(SkeramGUID))
|
||||
{
|
||||
if (!skeram->IsAlive())
|
||||
{
|
||||
HandleGameObject(go->GetGUID(), true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GO_CTHUN_GRASP:
|
||||
CThunGraspGUIDs.push_back(go->GetGUID());
|
||||
if (Creature* CThun = instance->GetCreature(CThunGUID))
|
||||
@@ -190,12 +170,6 @@ public:
|
||||
return YaujGUID;
|
||||
case DATA_VISCIDUS:
|
||||
return ViscidusGUID;
|
||||
case AQ40_DOOR_1:
|
||||
return doorGUIDs[0];
|
||||
case AQ40_DOOR_2:
|
||||
return doorGUIDs[1];
|
||||
case AQ40_DOOR_3:
|
||||
return doorGUIDs[2];
|
||||
}
|
||||
return ObjectGuid::Empty;
|
||||
}
|
||||
|
||||
@@ -36,25 +36,30 @@ enum Spells
|
||||
SPELL_EXPLODE = 25699,
|
||||
SPELL_SUMMON_WARRIOR = 17431,
|
||||
SPELL_SUMMON_SWARMGUARD = 17430,
|
||||
|
||||
SPELL_FEAR = 26070,
|
||||
SPELL_ENTAGLING_ROOTS = 26071,
|
||||
SPELL_SILENCE = 26069,
|
||||
SPELL_DUST_CLOUD = 26072,
|
||||
SPELL_FIRE_NOVA = 26073,
|
||||
|
||||
SPELL_SUMMON_LARGE_OBSIDIAN_CHUNK = 27630, // Server-side
|
||||
|
||||
SPELL_SHOCK_BLAST = 26458,
|
||||
SPELL_DRAIN_MANA = 25671,
|
||||
SPELL_DRAIN_MANA_VISUAL = 26639,
|
||||
|
||||
TALK_ENRAGE = 0,
|
||||
|
||||
// Vekniss Stinger
|
||||
SPELL_VEKNISS_CATALYST = 26078,
|
||||
SPELL_STINGER_CHARGE_NORMAL = 26081,
|
||||
SPELL_STINGER_CHARGE_BUFFED = 26082,
|
||||
|
||||
// Obsidian Eradicator
|
||||
SPELL_SHOCK_BLAST = 26458,
|
||||
SPELL_DRAIN_MANA = 25671,
|
||||
SPELL_DRAIN_MANA_VISUAL = 26639,
|
||||
|
||||
// Anubisath Warder
|
||||
SPELL_FEAR = 26070,
|
||||
SPELL_ENTAGLING_ROOTS = 26071,
|
||||
SPELL_SILENCE = 26069,
|
||||
SPELL_DUST_CLOUD = 26072,
|
||||
SPELL_FIRE_NOVA = 26073,
|
||||
|
||||
// Obsidian Nullifier
|
||||
SPELL_NULLIFY = 26552,
|
||||
SPELL_CLEAVE = 40504
|
||||
};
|
||||
|
||||
struct npc_anubisath_defender : public ScriptedAI
|
||||
@@ -220,38 +225,6 @@ private:
|
||||
TaskScheduler _scheduler;
|
||||
};
|
||||
|
||||
enum NPCs
|
||||
{
|
||||
NPC_VEKNISS_DRONE = 15300
|
||||
};
|
||||
|
||||
class spell_aggro_drones : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_aggro_drones);
|
||||
|
||||
void HandleDummy(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
if (Unit* caster = GetCaster())
|
||||
{
|
||||
if (Creature* target = GetHitCreature())
|
||||
{
|
||||
if (target->GetEntry() == NPC_VEKNISS_DRONE)
|
||||
{
|
||||
if (Unit* victim = caster->GetVictim())
|
||||
{
|
||||
target->AI()->AttackStart(victim);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_aggro_drones::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
|
||||
}
|
||||
};
|
||||
|
||||
struct npc_obsidian_eradicator : public ScriptedAI
|
||||
{
|
||||
npc_obsidian_eradicator(Creature* creature) : ScriptedAI(creature)
|
||||
@@ -316,27 +289,6 @@ private:
|
||||
std::list<Player*> _targets;
|
||||
};
|
||||
|
||||
class spell_drain_mana : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_drain_mana);
|
||||
|
||||
void HandleScript(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
if (Unit* caster = GetCaster())
|
||||
{
|
||||
if (Unit* target = GetHitUnit())
|
||||
{
|
||||
target->CastSpell(caster, SPELL_DRAIN_MANA_VISUAL, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_drain_mana::HandleScript, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
}
|
||||
};
|
||||
|
||||
struct npc_anubisath_warder : public ScriptedAI
|
||||
{
|
||||
npc_anubisath_warder(Creature* creature) : ScriptedAI(creature)
|
||||
@@ -406,12 +358,132 @@ private:
|
||||
TaskScheduler _scheduler;
|
||||
};
|
||||
|
||||
struct npc_obsidian_nullifier : public ScriptedAI
|
||||
{
|
||||
npc_obsidian_nullifier(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
_scheduler.CancelAll();
|
||||
me->SetPower(POWER_MANA, 0);
|
||||
_targets.clear();
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/) override
|
||||
{
|
||||
_scheduler.Schedule(6s, [this](TaskContext context)
|
||||
{
|
||||
if (_targets.empty())
|
||||
{
|
||||
Map::PlayerList const& players = me->GetMap()->GetPlayers();
|
||||
for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
|
||||
{
|
||||
if (Player* player = itr->GetSource())
|
||||
{
|
||||
if (player->IsAlive() && !player->IsGameMaster() && !player->IsSpectator() && player->GetPower(POWER_MANA) > 0)
|
||||
{
|
||||
_targets.push_back(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Acore::Containers::RandomResize(_targets, 11);
|
||||
}
|
||||
|
||||
for (Unit* target : _targets)
|
||||
{
|
||||
DoCast(target, SPELL_DRAIN_MANA, true);
|
||||
}
|
||||
|
||||
if (me->GetPowerPct(POWER_MANA) >= 100.f)
|
||||
{
|
||||
DoCastAOE(SPELL_NULLIFY, true);
|
||||
}
|
||||
|
||||
context.Repeat(6s);
|
||||
})
|
||||
.Schedule(6000ms, 8400ms, [this](TaskContext context)
|
||||
{
|
||||
DoCastVictim(SPELL_CLEAVE, true);
|
||||
context.Repeat(6000ms, 8400ms);
|
||||
});
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_scheduler.Update(diff,
|
||||
std::bind(&ScriptedAI::DoMeleeAttackIfReady, this));
|
||||
}
|
||||
|
||||
private:
|
||||
TaskScheduler _scheduler;
|
||||
std::list<Player*> _targets;
|
||||
};
|
||||
|
||||
enum NPCs
|
||||
{
|
||||
NPC_VEKNISS_DRONE = 15300
|
||||
};
|
||||
|
||||
class spell_aggro_drones : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_aggro_drones);
|
||||
|
||||
void HandleDummy(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
if (Unit* caster = GetCaster())
|
||||
{
|
||||
if (Creature* target = GetHitCreature())
|
||||
{
|
||||
if (target->GetEntry() == NPC_VEKNISS_DRONE)
|
||||
{
|
||||
if (Unit* victim = caster->GetVictim())
|
||||
{
|
||||
target->AI()->AttackStart(victim);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_aggro_drones::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
|
||||
}
|
||||
};
|
||||
|
||||
class spell_nullify : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_nullify);
|
||||
|
||||
void HandleApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
if (Unit* target = GetTarget())
|
||||
{
|
||||
target->SetHealth(1);
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
AfterEffectApply += AuraEffectApplyFn(spell_nullify::HandleApply, EFFECT_1, SPELL_AURA_SCHOOL_IMMUNITY, AURA_EFFECT_HANDLE_REAL);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_temple_of_ahnqiraj()
|
||||
{
|
||||
RegisterTempleOfAhnQirajCreatureAI(npc_anubisath_defender);
|
||||
RegisterTempleOfAhnQirajCreatureAI(npc_vekniss_stinger);
|
||||
RegisterSpellScript(spell_aggro_drones);
|
||||
RegisterTempleOfAhnQirajCreatureAI(npc_obsidian_eradicator);
|
||||
RegisterSpellScript(spell_drain_mana);
|
||||
RegisterTempleOfAhnQirajCreatureAI(npc_anubisath_warder);
|
||||
RegisterTempleOfAhnQirajCreatureAI(npc_obsidian_nullifier);
|
||||
RegisterSpellScript(spell_aggro_drones);
|
||||
RegisterSpellScript(spell_nullify);
|
||||
}
|
||||
|
||||
@@ -80,9 +80,9 @@ enum Creatures
|
||||
|
||||
enum ObjectsAQ40
|
||||
{
|
||||
AQ40_DOOR_1 = 180634,
|
||||
AQ40_DOOR_2 = 180635,
|
||||
AQ40_DOOR_3 = 180636,
|
||||
AQ40_DOOR_TE_ENTRANCE = 180634,
|
||||
AQ40_DOOR_TE_EXIT = 180635,
|
||||
AQ40_DOOR_SKERAM = 180636,
|
||||
GO_CTHUN_GRASP = 180745
|
||||
};
|
||||
|
||||
|
||||
@@ -87,19 +87,25 @@ public:
|
||||
switch (waypointId)
|
||||
{
|
||||
case 19:
|
||||
me->SummonCreature(ENTRY_STOMPER, -6391.69f, -1730.49f, -272.83f, 4.96f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000);
|
||||
Talk(SAY_AGGRO1, player);
|
||||
if (Creature* summoned = me->SummonCreature(ENTRY_STOMPER, -6391.69f, -1730.49f, -272.83f, 4.96f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000))
|
||||
{
|
||||
Talk(SAY_AGGRO1, summoned);
|
||||
}
|
||||
break;
|
||||
case 28:
|
||||
Talk(SAY_SEARCH, player);
|
||||
break;
|
||||
case 38:
|
||||
me->SummonCreature(ENTRY_TARLORD, -6370.75f, -1382.84f, -270.51f, 6.06f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000);
|
||||
Talk(SAY_AGGRO2, player);
|
||||
if (Creature* summoned = me->SummonCreature(ENTRY_TARLORD, -6370.75f, -1382.84f, -270.51f, 6.06f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000))
|
||||
{
|
||||
Talk(SAY_AGGRO2, summoned);
|
||||
}
|
||||
break;
|
||||
case 49:
|
||||
me->SummonCreature(ENTRY_TARLORD1, -6324.44f, -1181.05f, -270.17f, 4.34f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000);
|
||||
Talk(SAY_AGGRO3, player);
|
||||
if (Creature* summoned = me->SummonCreature(ENTRY_TARLORD1, -6324.44f, -1181.05f, -270.17f, 4.34f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000))
|
||||
{
|
||||
Talk(SAY_AGGRO3, summoned);
|
||||
}
|
||||
break;
|
||||
case 55:
|
||||
Talk(SAY_FINISH, player);
|
||||
|
||||
@@ -55,6 +55,7 @@ enum MageSpells
|
||||
SPELL_MAGE_SUMMON_WATER_ELEMENTAL_PERMANENT = 70908,
|
||||
SPELL_MAGE_SUMMON_WATER_ELEMENTAL_TEMPORARY = 70907,
|
||||
SPELL_MAGE_GLYPH_OF_BLAST_WAVE = 62126,
|
||||
SPELL_MAGE_FINGERS_OF_FROST = 44543
|
||||
};
|
||||
|
||||
class spell_mage_arcane_blast : public SpellScript
|
||||
@@ -932,6 +933,114 @@ class spell_mage_summon_water_elemental : public SpellScript
|
||||
}
|
||||
};
|
||||
|
||||
#define FingersOfFrostScriptName "spell_mage_fingers_of_frost_proc_aura"
|
||||
class spell_mage_fingers_of_frost_proc_aura : public AuraScript
|
||||
{ PrepareAuraScript(spell_mage_fingers_of_frost_proc_aura);
|
||||
|
||||
bool CheckProc(ProcEventInfo& eventInfo)
|
||||
{
|
||||
if (eventInfo.GetSpellPhaseMask() != PROC_SPELL_PHASE_CAST)
|
||||
{
|
||||
eventInfo.SetProcChance(_chance);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CheckAfterProc(ProcEventInfo& eventInfo)
|
||||
{
|
||||
if (eventInfo.GetSpellPhaseMask() != PROC_SPELL_PHASE_CAST)
|
||||
{
|
||||
eventInfo.ResetProcChance();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void HandleOnEffectProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo)
|
||||
{
|
||||
if (eventInfo.GetSpellPhaseMask() == PROC_SPELL_PHASE_CAST)
|
||||
{
|
||||
_chance = 100.f;
|
||||
_spell = eventInfo.GetProcSpell();
|
||||
|
||||
if (!_spell || _spell->GetDelayMoment() <= 0)
|
||||
{
|
||||
PreventDefaultAction();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (eventInfo.GetSpellPhaseMask() == PROC_SPELL_PHASE_FINISH || ((_spell && _spell->GetDelayMoment() > 0) || !eventInfo.GetDamageInfo()))
|
||||
{
|
||||
PreventDefaultAction();
|
||||
}
|
||||
|
||||
_chance = 0.f;
|
||||
_spell = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void HandleAfterEffectProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo)
|
||||
{
|
||||
if (eventInfo.GetSpellPhaseMask() == PROC_SPELL_PHASE_HIT)
|
||||
{
|
||||
_chance = 100.f;
|
||||
}
|
||||
else if (eventInfo.GetSpellPhaseMask() == PROC_SPELL_PHASE_FINISH)
|
||||
{
|
||||
_chance = 0.f;
|
||||
_spell = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Register()
|
||||
{
|
||||
DoCheckProc += AuraCheckProcFn(spell_mage_fingers_of_frost_proc_aura::CheckProc);
|
||||
DoCheckAfterProc += AuraCheckProcFn(spell_mage_fingers_of_frost_proc_aura::CheckAfterProc);
|
||||
OnEffectProc += AuraEffectProcFn(spell_mage_fingers_of_frost_proc_aura::HandleOnEffectProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
|
||||
AfterEffectProc += AuraEffectProcFn(spell_mage_fingers_of_frost_proc_aura::HandleAfterEffectProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
|
||||
}
|
||||
|
||||
public:
|
||||
Spell const* GetProcSpell() const { return _spell; }
|
||||
|
||||
private:
|
||||
float _chance = 0.f;
|
||||
Spell const* _spell = nullptr;
|
||||
};
|
||||
|
||||
typedef spell_mage_fingers_of_frost_proc_aura spell_mage_fingers_of_frost_proc_aura_script;
|
||||
|
||||
class spell_mage_fingers_of_frost_proc : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_mage_fingers_of_frost_proc);
|
||||
|
||||
bool CheckProc(ProcEventInfo& eventInfo)
|
||||
{
|
||||
if (Aura* aura = GetCaster()->GetAuraOfRankedSpell(SPELL_MAGE_FINGERS_OF_FROST))
|
||||
{
|
||||
if (spell_mage_fingers_of_frost_proc_aura_script* script = dynamic_cast<spell_mage_fingers_of_frost_proc_aura_script*>(aura->GetScriptByName(FingersOfFrostScriptName)))
|
||||
{
|
||||
if (Spell const* fofProcSpell = script->GetProcSpell())
|
||||
{
|
||||
if (fofProcSpell == eventInfo.GetProcSpell())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Register()
|
||||
{
|
||||
DoCheckProc += AuraCheckProcFn(spell_mage_fingers_of_frost_proc::CheckProc);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_mage_spell_scripts()
|
||||
{
|
||||
RegisterSpellScript(spell_mage_arcane_blast);
|
||||
@@ -955,4 +1064,6 @@ void AddSC_mage_spell_scripts()
|
||||
RegisterSpellScript(spell_mage_master_of_elements);
|
||||
RegisterSpellScript(spell_mage_polymorph_cast_visual);
|
||||
RegisterSpellScript(spell_mage_summon_water_elemental);
|
||||
RegisterSpellScript(spell_mage_fingers_of_frost_proc_aura);
|
||||
RegisterSpellScript(spell_mage_fingers_of_frost_proc);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user