mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-26 07:06:23 +00:00
Merge branch 'master' into Playerbot
# Conflicts: # src/server/apps/worldserver/worldserver.conf.dist # src/server/game/Battlegrounds/Battleground.h # src/server/game/Entities/Player/Player.cpp # src/server/game/World/World.cpp
This commit is contained in:
@@ -58,7 +58,8 @@ public:
|
||||
{ "cinematic", HandleDebugPlayCinematicCommand, SEC_ADMINISTRATOR, Console::No },
|
||||
{ "movie", HandleDebugPlayMovieCommand, SEC_ADMINISTRATOR, Console::No },
|
||||
{ "sound", HandleDebugPlaySoundCommand, SEC_ADMINISTRATOR, Console::No },
|
||||
{ "music", HandleDebugPlayMusicCommand, SEC_ADMINISTRATOR, Console::No }
|
||||
{ "music", HandleDebugPlayMusicCommand, SEC_ADMINISTRATOR, Console::No },
|
||||
{ "visual", HandleDebugVisualCommand, SEC_ADMINISTRATOR, Console::No }
|
||||
};
|
||||
static ChatCommandTable debugSendCommandTable =
|
||||
{
|
||||
@@ -203,6 +204,28 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleDebugVisualCommand(ChatHandler* handler, uint32 visualId)
|
||||
{
|
||||
if (!visualId)
|
||||
{
|
||||
handler->SendSysMessage(LANG_BAD_VALUE);
|
||||
handler->SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
Player* player = handler->GetPlayer();
|
||||
Unit* target = handler->getSelectedUnit();
|
||||
|
||||
if (!target)
|
||||
{
|
||||
player->SendPlaySpellVisual(visualId);
|
||||
return true;
|
||||
}
|
||||
|
||||
player->SendPlaySpellImpact(target->GetGUID(), visualId);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleDebugSendSpellFailCommand(ChatHandler* handler, SpellCastResult result, Optional<uint32> failArg1, Optional<uint32> failArg2)
|
||||
{
|
||||
WorldPacket data(SMSG_CAST_FAILED, 5);
|
||||
|
||||
@@ -88,9 +88,11 @@ public:
|
||||
*
|
||||
* Example Usage:
|
||||
* @code
|
||||
* .deserter instance add 1h30m
|
||||
* .deserter instance add 1h30m (using player target or self)
|
||||
* -or-
|
||||
* .deserter bg add 1h30m
|
||||
* .deserter bg add 1h30m (using player target or self)
|
||||
* -or-
|
||||
* .deserter bg add Tester 1h30m (using player of name 'Tester')
|
||||
* @endcode
|
||||
*/
|
||||
static bool HandleDeserterAdd(ChatHandler* handler, Optional<std::string> playerName, Optional<std::string> time, bool isInstance)
|
||||
@@ -156,16 +158,18 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 deserterSpell = isInstance ? LFG_SPELL_DUNGEON_DESERTER : BG_SPELL_DESERTER;
|
||||
|
||||
if (target)
|
||||
{
|
||||
Aura* aura = target->GetAura(isInstance ? LFG_SPELL_DUNGEON_DESERTER : BG_SPELL_DESERTER);
|
||||
Aura* aura = target->GetAura(deserterSpell);
|
||||
if (aura && aura->GetDuration() >= duration * IN_MILLISECONDS)
|
||||
{
|
||||
handler->PSendSysMessage("Player %s already has a longer %s Deserter active.", handler->playerLink(*playerName), isInstance ? "Instance" : "Battleground");
|
||||
return true;
|
||||
}
|
||||
|
||||
aura = target->AddAura(isInstance ? LFG_SPELL_DUNGEON_DESERTER : BG_SPELL_DESERTER, target);
|
||||
aura = target->AddAura(deserterSpell, target);
|
||||
if (!aura)
|
||||
{
|
||||
handler->SendSysMessage(LANG_BAD_VALUE);
|
||||
@@ -173,44 +177,45 @@ public:
|
||||
return false;
|
||||
}
|
||||
aura->SetDuration(duration * IN_MILLISECONDS);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int32 remainTime = 0;
|
||||
if (QueryResult result = CharacterDatabase.Query("SELECT remainTime FROM character_aura WHERE guid = {} AND spell = {}", guid.GetCounter(), isInstance ? LFG_SPELL_DUNGEON_DESERTER : BG_SPELL_DESERTER))
|
||||
else
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
remainTime = fields[0].Get<int32>();
|
||||
|
||||
if (remainTime < 0 || remainTime >= duration * IN_MILLISECONDS)
|
||||
int32 remainTime = 0;
|
||||
if (QueryResult result = CharacterDatabase.Query("SELECT remainTime FROM character_aura WHERE guid = {} AND spell = {}", guid.GetCounter(), deserterSpell))
|
||||
{
|
||||
handler->PSendSysMessage("Player %s already has a longer %s Deserter active.", handler->playerLink(*playerName), isInstance ? "Instance" : "Battleground");
|
||||
return true;
|
||||
Field* fields = result->Fetch();
|
||||
remainTime = fields[0].Get<int32>();
|
||||
|
||||
if (remainTime < 0 || remainTime >= duration * IN_MILLISECONDS)
|
||||
{
|
||||
handler->PSendSysMessage("Player %s already has a longer %s Deserter active.", handler->playerLink(*playerName), isInstance ? "Instance" : "Battleground");
|
||||
return true;
|
||||
}
|
||||
CharacterDatabase.Query("DELETE FROM character_aura WHERE guid = {} AND spell = {}", guid.GetCounter(), deserterSpell);
|
||||
}
|
||||
CharacterDatabase.Query("DELETE FROM character_aura WHERE guid = {} AND spell = {}", guid.GetCounter(), isInstance ? LFG_SPELL_DUNGEON_DESERTER : BG_SPELL_DESERTER);
|
||||
|
||||
uint8 index = 0;
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_AURA);
|
||||
stmt->SetData(index++, guid.GetCounter());
|
||||
stmt->SetData(index++, guid.GetCounter());
|
||||
stmt->SetData(index++, 0);
|
||||
stmt->SetData(index++, deserterSpell);
|
||||
stmt->SetData(index++, 1);
|
||||
stmt->SetData(index++, 1);
|
||||
stmt->SetData(index++, 1);
|
||||
stmt->SetData(index++, 0);
|
||||
stmt->SetData(index++, 0);
|
||||
stmt->SetData(index++, 0);
|
||||
stmt->SetData(index++, 0);
|
||||
stmt->SetData(index++, 0);
|
||||
stmt->SetData(index++, 0);
|
||||
stmt->SetData(index++, isInstance ? 1800000 : 900000);
|
||||
stmt->SetData(index++, duration * IN_MILLISECONDS);
|
||||
stmt->SetData(index, 0);
|
||||
CharacterDatabase.Execute(stmt);
|
||||
}
|
||||
|
||||
uint8 index = 0;
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_AURA);
|
||||
stmt->SetData(index++, guid.GetCounter());
|
||||
stmt->SetData(index++, guid.GetCounter());
|
||||
stmt->SetData(index++, 0);
|
||||
stmt->SetData(index++, isInstance ? LFG_SPELL_DUNGEON_DESERTER : BG_SPELL_DESERTER);
|
||||
stmt->SetData(index++, 1);
|
||||
stmt->SetData(index++, 1);
|
||||
stmt->SetData(index++, 1);
|
||||
stmt->SetData(index++, 0);
|
||||
stmt->SetData(index++, 0);
|
||||
stmt->SetData(index++, 0);
|
||||
stmt->SetData(index++, 0);
|
||||
stmt->SetData(index++, 0);
|
||||
stmt->SetData(index++, 0);
|
||||
stmt->SetData(index++, isInstance ? 1800000 : 900000);
|
||||
stmt->SetData(index++, duration * 1000);
|
||||
stmt->SetData(index, 0);
|
||||
CharacterDatabase.Execute(stmt);
|
||||
|
||||
handler->PSendSysMessage("%s of %s Deserter has been added to player %s.", secsToTimeString(duration), isInstance ? "Instance" : "Battleground", handler->playerLink(*playerName));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -221,6 +226,7 @@ public:
|
||||
* selected player.
|
||||
*
|
||||
* @param handler The ChatHandler, passed by the system.
|
||||
* @param player The target player, either by name, the target or self
|
||||
* @param isInstance provided by the relaying functions, so we don't have
|
||||
* to write that much code :)
|
||||
*
|
||||
@@ -228,9 +234,11 @@ public:
|
||||
*
|
||||
* Example Usage:
|
||||
* @code
|
||||
* .deserter instance remove
|
||||
* .deserter instance remove (using player target or self)
|
||||
* -or-
|
||||
* .deserter bg remove
|
||||
* .deserter bg remove (using player target or self)
|
||||
* -or-
|
||||
* .deserter bg remove Tester (using player of name 'Tester')
|
||||
* @endcode
|
||||
*/
|
||||
static bool HandleDeserterRemove(ChatHandler* handler, Optional<PlayerIdentifier> player, bool isInstance)
|
||||
@@ -248,21 +256,75 @@ public:
|
||||
}
|
||||
|
||||
Player* target = player->GetConnectedPlayer();
|
||||
uint32 deserterSpell = isInstance ? LFG_SPELL_DUNGEON_DESERTER : BG_SPELL_DESERTER;
|
||||
int32 duration = 0;
|
||||
|
||||
if (target)
|
||||
{
|
||||
target->RemoveAura(isInstance ? LFG_SPELL_DUNGEON_DESERTER : BG_SPELL_DESERTER);
|
||||
if (Aura* aura = target->GetAura(deserterSpell))
|
||||
{
|
||||
duration = aura->GetDuration();
|
||||
target->RemoveAura(deserterSpell);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (QueryResult result = CharacterDatabase.Query("SELECT remainTime FROM character_aura WHERE guid = {} AND spell = {}", player->GetGUID().GetCounter(), deserterSpell))
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
duration = fields[0].Get<int32>();
|
||||
CharacterDatabase.Execute("DELETE FROM character_aura WHERE guid = {} AND spell = {}", player->GetGUID().GetCounter(), deserterSpell);
|
||||
}
|
||||
}
|
||||
|
||||
if (duration == 0)
|
||||
{
|
||||
handler->PSendSysMessage("Player %s does not have %s Deserter.", handler->playerLink(player->GetName()), isInstance ? "Instance" : "Battleground");
|
||||
handler->SetSentErrorMessage(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
CharacterDatabase.Query("DELETE FROM character_aura WHERE guid = {} AND spell = {}", player->GetGUID().GetCounter(), isInstance ? LFG_SPELL_DUNGEON_DESERTER : BG_SPELL_DESERTER);
|
||||
if (duration < 0)
|
||||
{
|
||||
handler->PSendSysMessage("Permanent %s Deserter has been removed from player %s (GUID %u).", isInstance ? "Instance" : "Battleground", handler->playerLink(player->GetName()), player->GetGUID().GetCounter());
|
||||
handler->SetSentErrorMessage(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
handler->PSendSysMessage("%s of %s Deserter has been removed from player %s (GUID %u).", secsToTimeString(duration / IN_MILLISECONDS), isInstance ? "Instance" : "Battleground", handler->playerLink(player->GetName()), player->GetGUID().GetCounter());
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes the Deserter Debuff from all players
|
||||
*
|
||||
* This function removes a Deserter Debuff of the given type (Instance or BG) from
|
||||
* all players, online or offline.
|
||||
*
|
||||
* @param handler The ChatHandler, passed by the system.
|
||||
* @param isInstance provided by the relaying functions, so we don't have
|
||||
* to write that much code :)
|
||||
* @param maxTime Optional: The maximum remaining time of the Debuff on players to be removed.
|
||||
* Any Player with a Deserter Debuff of this time or less will get their Debuff removed. Use -1 for any.
|
||||
* Default: 15m for BG, 30m for Instance.
|
||||
*
|
||||
* @return true if everything was correct, false if an error occured.
|
||||
*
|
||||
* Example Usage:
|
||||
* @code
|
||||
* .deserter bg remove all
|
||||
* -or-
|
||||
* .deserter bg remove all 30m
|
||||
* -or-
|
||||
* .deserter bg remove all -1
|
||||
* @endcode
|
||||
*/
|
||||
static bool HandleDeserterRemoveAll(ChatHandler* handler, bool isInstance, Optional<std::string> maxTime)
|
||||
{
|
||||
uint32 deserterSpell = isInstance ? LFG_SPELL_DUNGEON_DESERTER : BG_SPELL_DESERTER;
|
||||
int32 remainTime = isInstance ? 1800 : 900;
|
||||
uint64 deserterCount = 0;
|
||||
bool countOnline = true;
|
||||
|
||||
if (maxTime)
|
||||
{
|
||||
@@ -273,6 +335,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// Optimization. Do not execute any further functions or Queries if remainTime is 0.
|
||||
if (remainTime == 0)
|
||||
{
|
||||
handler->SendSysMessage(LANG_BAD_VALUE);
|
||||
@@ -280,13 +343,33 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (remainTime < 0)
|
||||
QueryResult result;
|
||||
if (remainTime > 0)
|
||||
{
|
||||
CharacterDatabase.Execute("DELETE FROM character_aura WHERE spell = {}", isInstance ? LFG_SPELL_DUNGEON_DESERTER : BG_SPELL_DESERTER);
|
||||
result = CharacterDatabase.Query("SELECT COUNT(guid) FROM character_aura WHERE spell = {} AND remainTime <= {}", deserterSpell, remainTime * IN_MILLISECONDS);
|
||||
}
|
||||
else
|
||||
{
|
||||
CharacterDatabase.Execute("DELETE FROM character_aura WHERE spell = {} AND remainTime <= {}", isInstance ? LFG_SPELL_DUNGEON_DESERTER : BG_SPELL_DESERTER, remainTime * IN_MILLISECONDS);
|
||||
result = CharacterDatabase.Query("SELECT COUNT(guid) FROM character_aura WHERE spell = {}", deserterSpell);
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
deserterCount = (*result)[0].Get<uint64>();
|
||||
}
|
||||
|
||||
// Optimization. Only execute these if there even is a result.
|
||||
if (deserterCount > 0)
|
||||
{
|
||||
countOnline = false;
|
||||
if (remainTime > 0)
|
||||
{
|
||||
CharacterDatabase.Execute("DELETE FROM character_aura WHERE spell = {} AND remainTime <= {}", deserterSpell, remainTime * IN_MILLISECONDS);
|
||||
}
|
||||
else
|
||||
{
|
||||
CharacterDatabase.Execute("DELETE FROM character_aura WHERE spell = {}", deserterSpell);
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_lock<std::shared_mutex> lock(*HashMapHolder<Player>::GetLock());
|
||||
@@ -294,14 +377,28 @@ public:
|
||||
for (HashMapHolder<Player>::MapType::const_iterator itr = onlinePlayerList.begin(); itr != onlinePlayerList.end(); ++itr)
|
||||
{
|
||||
Player* player = itr->second;
|
||||
Aura* aura = player->GetAura(isInstance ? LFG_SPELL_DUNGEON_DESERTER : BG_SPELL_DESERTER);
|
||||
Aura* aura = player->GetAura(deserterSpell);
|
||||
if (aura && (remainTime < 0 || aura->GetDuration() <= remainTime * IN_MILLISECONDS))
|
||||
{
|
||||
player->RemoveAura(isInstance ? LFG_SPELL_DUNGEON_DESERTER : BG_SPELL_DESERTER);
|
||||
if (countOnline)
|
||||
deserterCount++;
|
||||
player->RemoveAura(deserterSpell);
|
||||
}
|
||||
}
|
||||
|
||||
handler->PSendSysMessage("%s Deserter has been removed from all players", isInstance ? "Instance" : "Battleground");
|
||||
std::string remainTimeStr = secsToTimeString(remainTime);
|
||||
if (remainTime < 0)
|
||||
{
|
||||
remainTimeStr = "infinity";
|
||||
}
|
||||
|
||||
if (deserterCount == 0)
|
||||
{
|
||||
handler->PSendSysMessage("No player on this realm has %s Deserter with a duration of %s or less.", isInstance ? "Instance" : "Battleground", remainTimeStr);
|
||||
return true;
|
||||
}
|
||||
|
||||
handler->PSendSysMessage("%s Deserter has been removed from %u player(s) with a duration of %s or less.", isInstance ? "Instance" : "Battleground", deserterCount, remainTimeStr);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -143,9 +143,9 @@ public:
|
||||
return commandTable;
|
||||
}
|
||||
|
||||
static bool HandleSkirmishCommand(ChatHandler* handler, std::string_view args)
|
||||
static bool HandleSkirmishCommand(ChatHandler* handler, std::vector<std::string_view> args)
|
||||
{
|
||||
auto tokens = Acore::Tokenize(args, ' ', true);
|
||||
auto tokens = args;
|
||||
|
||||
if (args.empty() || !tokens.size())
|
||||
{
|
||||
|
||||
@@ -148,6 +148,7 @@ public:
|
||||
_hasSubmergedOnce = false;
|
||||
_isKnockbackEmoteAllowed = true;
|
||||
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, 0);
|
||||
me->SetControlled(true, UNIT_STATE_ROOT);
|
||||
_lavaBurstGUIDS.clear();
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,8 @@ enum Spells
|
||||
{
|
||||
SPELL_AVATAR = 24646, // Enrage Spell
|
||||
SPELL_GROUND_TREMOR = 6524,
|
||||
SPELL_ENTANGLING_ROOTS = 24648
|
||||
SPELL_ENTANGLING_ROOTS = 24648,
|
||||
SPELL_SWEEPING_STRIKES = 18765
|
||||
};
|
||||
|
||||
enum Events
|
||||
@@ -39,7 +40,8 @@ enum Events
|
||||
EVENT_GROUND_TREMOR = 2,
|
||||
EVENT_START_PURSUIT = 3,
|
||||
EVENT_STOP_PURSUIT = 4,
|
||||
EVENT_ENTANGLING_ROOTS = 5
|
||||
EVENT_ENTANGLING_ROOTS = 5,
|
||||
EVENT_SWEEPING_STRIKES = 6
|
||||
};
|
||||
|
||||
class boss_grilek : public CreatureScript // grilek
|
||||
@@ -65,6 +67,7 @@ public:
|
||||
events.ScheduleEvent(EVENT_AVATAR, 20s, 30s);
|
||||
events.ScheduleEvent(EVENT_GROUND_TREMOR, 15s, 25s);
|
||||
events.ScheduleEvent(EVENT_ENTANGLING_ROOTS, 5s, 15s);
|
||||
events.ScheduleEvent(EVENT_SWEEPING_STRIKES, 30s);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
@@ -115,6 +118,10 @@ public:
|
||||
DoCastVictim(SPELL_ENTANGLING_ROOTS);
|
||||
events.ScheduleEvent(EVENT_ENTANGLING_ROOTS, 10s, 20s);
|
||||
break;
|
||||
case EVENT_SWEEPING_STRIKES:
|
||||
DoCastSelf(SPELL_SWEEPING_STRIKES, true);
|
||||
events.ScheduleEvent(EVENT_SWEEPING_STRIKES, 30s);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -34,15 +34,17 @@ enum Says
|
||||
SAY_FLEEING = 1,
|
||||
SAY_MINION_DESTROY = 2,
|
||||
SAY_PROTECT_ALTAR = 3,
|
||||
SAY_PROTECT_GURUBASHI_EMPIRE = 4
|
||||
SAY_PROTECT_GURUBASHI_EMPIRE = 4,
|
||||
SAY_PLEDGE_ALLEGIANCE = 5,
|
||||
SAY_WORLD_WILL_SUFFER = 6,
|
||||
SAY_EVADE = 7
|
||||
};
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_POISONOUS_BLOOD = 24321,
|
||||
SPELL_BLOOD_SIPHON_HEAL = 24322,
|
||||
SPELL_BLOOD_SIPHON_DMG = 24323,
|
||||
SPELL_BLOOD_SIPHON = 24324,
|
||||
SPELL_BLOOD_SIPHON_HEAL = 24322,
|
||||
SPELL_BLOOD_SIPHON_DAMAGE = 24323,
|
||||
SPELL_CORRUPTED_BLOOD = 24328,
|
||||
SPELL_CAUSE_INSANITY = 24327,
|
||||
SPELL_ENRAGE = 24318,
|
||||
@@ -51,7 +53,8 @@ enum Spells
|
||||
SPELL_ASPECT_OF_VENOXIS = 24688,
|
||||
SPELL_ASPECT_OF_MARLI = 24686,
|
||||
SPELL_ASPECT_OF_THEKAL = 24689,
|
||||
SPELL_ASPECT_OF_ARLOKK = 24690
|
||||
SPELL_ASPECT_OF_ARLOKK = 24690,
|
||||
SPELL_POISONOUS_BLOOD = 24321
|
||||
};
|
||||
|
||||
enum Events
|
||||
@@ -87,9 +90,19 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
void ApplyHakkarPowerStacks()
|
||||
{
|
||||
me->RemoveAurasDueToSpell(SPELL_HAKKAR_POWER);
|
||||
for (int i = DATA_JEKLIK; i < DATA_HAKKAR; i++)
|
||||
if (instance->GetBossState(i) != DONE)
|
||||
DoCastSelf(SPELL_HAKKAR_POWER, true);
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
_Reset();
|
||||
|
||||
ApplyHakkarPowerStacks();
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
@@ -105,18 +118,25 @@ public:
|
||||
events.ScheduleEvent(EVENT_CAUSE_INSANITY, 17000);
|
||||
events.ScheduleEvent(EVENT_ENRAGE, 600000);
|
||||
if (instance->GetBossState(DATA_JEKLIK) != DONE)
|
||||
events.ScheduleEvent(EVENT_ASPECT_OF_JEKLIK, 4000);
|
||||
events.ScheduleEvent(EVENT_ASPECT_OF_JEKLIK, 21000);
|
||||
if (instance->GetBossState(DATA_VENOXIS) != DONE)
|
||||
events.ScheduleEvent(EVENT_ASPECT_OF_VENOXIS, 7000);
|
||||
events.ScheduleEvent(EVENT_ASPECT_OF_VENOXIS, 14000);
|
||||
if (instance->GetBossState(DATA_MARLI) != DONE)
|
||||
events.ScheduleEvent(EVENT_ASPECT_OF_MARLI, 12000);
|
||||
events.ScheduleEvent(EVENT_ASPECT_OF_MARLI, 15000);
|
||||
if (instance->GetBossState(DATA_THEKAL) != DONE)
|
||||
events.ScheduleEvent(EVENT_ASPECT_OF_THEKAL, 8000);
|
||||
events.ScheduleEvent(EVENT_ASPECT_OF_THEKAL, 10000);
|
||||
if (instance->GetBossState(DATA_ARLOKK) != DONE)
|
||||
events.ScheduleEvent(EVENT_ASPECT_OF_ARLOKK, 18000);
|
||||
Talk(SAY_AGGRO);
|
||||
}
|
||||
|
||||
void EnterEvadeMode(EvadeReason evadeReason) override
|
||||
{
|
||||
BossAI::EnterEvadeMode(evadeReason);
|
||||
|
||||
Talk(SAY_EVADE);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim() || !CheckInRoom())
|
||||
@@ -140,9 +160,12 @@ public:
|
||||
events.ScheduleEvent(EVENT_CORRUPTED_BLOOD, urand(30000, 45000));
|
||||
break;
|
||||
case EVENT_CAUSE_INSANITY:
|
||||
if (Unit* victim = SelectTarget(SelectTargetMethod::MaxThreat, 0, 30.f, true))
|
||||
if (me->GetThreatMgr().getThreatList().size() > 1)
|
||||
{
|
||||
DoCast(victim, SPELL_CAUSE_INSANITY);
|
||||
if (Unit* victim = SelectTarget(SelectTargetMethod::MaxThreat, 0, 30.f, true))
|
||||
{
|
||||
DoCast(victim, SPELL_CAUSE_INSANITY);
|
||||
}
|
||||
}
|
||||
events.ScheduleEvent(EVENT_CAUSE_INSANITY, urand(35000, 45000));
|
||||
break;
|
||||
@@ -153,11 +176,11 @@ public:
|
||||
break;
|
||||
case EVENT_ASPECT_OF_JEKLIK:
|
||||
DoCastVictim(SPELL_ASPECT_OF_JEKLIK, true);
|
||||
events.ScheduleEvent(EVENT_ASPECT_OF_JEKLIK, urand(10000, 14000));
|
||||
events.ScheduleEvent(EVENT_ASPECT_OF_JEKLIK, 24000);
|
||||
break;
|
||||
case EVENT_ASPECT_OF_VENOXIS:
|
||||
DoCastVictim(SPELL_ASPECT_OF_VENOXIS, true);
|
||||
events.ScheduleEvent(EVENT_ASPECT_OF_VENOXIS, 8000);
|
||||
events.ScheduleEvent(EVENT_ASPECT_OF_VENOXIS, urand(16000, 18000));
|
||||
break;
|
||||
case EVENT_ASPECT_OF_MARLI:
|
||||
if (Unit* victim = SelectTarget(SelectTargetMethod::MaxThreat, 0, 5.f, true))
|
||||
@@ -165,7 +188,7 @@ public:
|
||||
DoCast(victim, SPELL_ASPECT_OF_MARLI, true);
|
||||
me->GetThreatMgr().modifyThreatPercent(victim, -100.f);
|
||||
}
|
||||
events.ScheduleEvent(EVENT_ASPECT_OF_MARLI, 10000);
|
||||
events.ScheduleEvent(EVENT_ASPECT_OF_MARLI, 45000);
|
||||
break;
|
||||
case EVENT_ASPECT_OF_THEKAL:
|
||||
DoCastVictim(SPELL_ASPECT_OF_THEKAL, true);
|
||||
@@ -215,8 +238,8 @@ public:
|
||||
hakkar->AI()->Talk(SAY_PROTECT_GURUBASHI_EMPIRE);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
@@ -230,6 +253,10 @@ public:
|
||||
{
|
||||
if (InstanceScript* instance = player->GetInstanceScript())
|
||||
{
|
||||
// Instance map's enormous, Hakkar's GRID is not loaded by the time players enter.
|
||||
// Without this, the creature never says anything, because it doesn't load in time.
|
||||
player->GetMap()->LoadGrid(-11783.99f, -1655.27f);
|
||||
|
||||
if (Creature* hakkar = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_HAKKAR)))
|
||||
{
|
||||
if (hakkar->GetAI())
|
||||
@@ -237,8 +264,8 @@ public:
|
||||
hakkar->AI()->Talk(SAY_PROTECT_ALTAR);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
@@ -252,6 +279,10 @@ public:
|
||||
{
|
||||
if (InstanceScript* instance = player->GetInstanceScript())
|
||||
{
|
||||
// Instance map's enormous, Hakkar's GRID is not loaded by the time players enter.
|
||||
// Without this, the creature never says anything, because it doesn't load in time.
|
||||
player->GetMap()->LoadGrid(-11783.99f, -1655.27f);
|
||||
|
||||
if (Creature* hakkar = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_HAKKAR)))
|
||||
{
|
||||
if (hakkar->GetAI())
|
||||
@@ -259,37 +290,114 @@ public:
|
||||
hakkar->AI()->Talk(SAY_MINION_DESTROY);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class spell_hakkar_blood_siphon : public SpellScript
|
||||
class at_zulgurub_bloodfire_pit_speech : public OnlyOnceAreaTriggerScript
|
||||
{
|
||||
PrepareSpellScript(spell_hakkar_blood_siphon);
|
||||
public:
|
||||
at_zulgurub_bloodfire_pit_speech() : OnlyOnceAreaTriggerScript("at_zulgurub_bloodfire_pit_speech") {}
|
||||
|
||||
bool _OnTrigger(Player* player, const AreaTrigger* /*at*/) override
|
||||
{
|
||||
if (InstanceScript* instance = player->GetInstanceScript())
|
||||
{
|
||||
// Instance map's enormous, Hakkar's GRID is not loaded by the time players enter.
|
||||
// Without this, the creature never says anything, because it doesn't load in time.
|
||||
player->GetMap()->LoadGrid(-11783.99f, -1655.27f);
|
||||
|
||||
if (Creature* hakkar = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_HAKKAR)))
|
||||
{
|
||||
if (hakkar->GetAI())
|
||||
{
|
||||
hakkar->AI()->Talk(SAY_PLEDGE_ALLEGIANCE, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class at_zulgurub_edge_of_madness_speech : public OnlyOnceAreaTriggerScript
|
||||
{
|
||||
public:
|
||||
at_zulgurub_edge_of_madness_speech() : OnlyOnceAreaTriggerScript("at_zulgurub_edge_of_madness_speech") {}
|
||||
|
||||
bool _OnTrigger(Player* player, const AreaTrigger* /*at*/) override
|
||||
{
|
||||
if (InstanceScript* instance = player->GetInstanceScript())
|
||||
{
|
||||
// Instance map's enormous, Hakkar's GRID is not loaded by the time players enter.
|
||||
// Without this, the creature never says anything, because it doesn't load in time.
|
||||
player->GetMap()->LoadGrid(-11783.99f, -1655.27f);
|
||||
|
||||
if (Creature* hakkar = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_HAKKAR)))
|
||||
{
|
||||
if (hakkar->GetAI())
|
||||
{
|
||||
hakkar->AI()->Talk(SAY_WORLD_WILL_SUFFER, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class spell_blood_siphon : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_blood_siphon);
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SPELL_BLOOD_SIPHON_HEAL, SPELL_BLOOD_SIPHON_DMG });
|
||||
return ValidateSpellInfo({ SPELL_BLOOD_SIPHON_DAMAGE, SPELL_BLOOD_SIPHON_HEAL });
|
||||
}
|
||||
|
||||
void OnSpellHit()
|
||||
void FilterTargets(std::list<WorldObject*>& targets)
|
||||
{
|
||||
Unit* caster = GetCaster();
|
||||
Unit* target = GetHitUnit();
|
||||
if (!caster || !target)
|
||||
return;
|
||||
// Max. 20 targets
|
||||
if (!targets.empty())
|
||||
{
|
||||
Acore::Containers::RandomResize(targets, 20);
|
||||
}
|
||||
}
|
||||
|
||||
if (target->HasAura(SPELL_POISONOUS_BLOOD))
|
||||
target->CastSpell(caster, SPELL_BLOOD_SIPHON_DMG, true);
|
||||
else
|
||||
target->CastSpell(caster, SPELL_BLOOD_SIPHON_HEAL, true);
|
||||
void HandleScriptEffect(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
if (Unit* caster = GetCaster())
|
||||
{
|
||||
if (Player* player = GetHitPlayer())
|
||||
{
|
||||
player->CastSpell(caster, player->HasAura(SPELL_POISONOUS_BLOOD) ? SPELL_BLOOD_SIPHON_DAMAGE : SPELL_BLOOD_SIPHON_HEAL, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnHit += SpellHitFn(spell_hakkar_blood_siphon::OnSpellHit);
|
||||
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_blood_siphon::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
|
||||
OnEffectHitTarget += SpellEffectFn(spell_blood_siphon::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
}
|
||||
};
|
||||
|
||||
class spell_hakkar_power_down : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_hakkar_power_down);
|
||||
|
||||
void HandleOnHit()
|
||||
{
|
||||
if (Unit* caster = GetCaster())
|
||||
if (caster->HasAura(SPELL_HAKKAR_POWER))
|
||||
caster->RemoveAuraFromStack(SPELL_HAKKAR_POWER);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnHit += SpellHitFn(spell_hakkar_power_down::HandleOnHit);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -299,5 +407,8 @@ void AddSC_boss_hakkar()
|
||||
new at_zulgurub_entrance_speech();
|
||||
new at_zulgurub_bridge_speech();
|
||||
new at_zulgurub_temple_speech();
|
||||
RegisterSpellScript(spell_hakkar_blood_siphon);
|
||||
new at_zulgurub_bloodfire_pit_speech();
|
||||
new at_zulgurub_edge_of_madness_speech();
|
||||
RegisterSpellScript(spell_blood_siphon);
|
||||
RegisterSpellScript(spell_hakkar_power_down);
|
||||
}
|
||||
|
||||
@@ -15,13 +15,6 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* ScriptData
|
||||
SDName: Boss_Hazzarah
|
||||
SD%Complete: 100
|
||||
SDComment:
|
||||
SDCategory: Zul'Gurub
|
||||
EndScriptData */
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "SpellScript.h"
|
||||
@@ -45,100 +38,98 @@ enum Events
|
||||
EVENT_ILLUSIONS = 4
|
||||
};
|
||||
|
||||
class boss_hazzarah : public CreatureScript
|
||||
struct boss_hazzarah : public BossAI
|
||||
{
|
||||
public:
|
||||
boss_hazzarah() : CreatureScript("boss_hazzarah") { }
|
||||
boss_hazzarah(Creature* creature) : BossAI(creature, DATA_EDGE_OF_MADNESS) { }
|
||||
|
||||
struct boss_hazzarahAI : public BossAI
|
||||
void JustSummoned(Creature* summon) override
|
||||
{
|
||||
boss_hazzarahAI(Creature* creature) : BossAI(creature, DATA_EDGE_OF_MADNESS) { }
|
||||
summons.Summon(summon);
|
||||
|
||||
void JustSummoned(Creature* summon) override
|
||||
{
|
||||
summons.Summon(summon);
|
||||
|
||||
summon->SetCorpseDelay(10);
|
||||
summon->SetReactState(REACT_PASSIVE);
|
||||
summon->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE);
|
||||
summon->SetVisible(false);
|
||||
summon->m_Events.AddEventAtOffset([summon]()
|
||||
summon->SetCorpseDelay(10);
|
||||
summon->SetReactState(REACT_PASSIVE);
|
||||
summon->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE);
|
||||
summon->SetVisible(false);
|
||||
summon->m_Events.AddEventAtOffset([summon]()
|
||||
{
|
||||
summon->SetVisible(true);
|
||||
}, 2s);
|
||||
|
||||
summon->m_Events.AddEventAtOffset([summon]()
|
||||
summon->m_Events.AddEventAtOffset([summon]()
|
||||
{
|
||||
summon->RemoveUnitFlag(UNIT_FLAG_DISABLE_MOVE);
|
||||
summon->SetReactState(REACT_AGGRESSIVE);
|
||||
summon->SetInCombatWithZone();
|
||||
}, 3500ms);
|
||||
}
|
||||
}, 5s);
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/) override
|
||||
void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override
|
||||
{
|
||||
summons.Despawn(summon);
|
||||
summon->DespawnOrUnsummon();
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/) override
|
||||
{
|
||||
_EnterCombat();
|
||||
events.ScheduleEvent(EVENT_SLEEP, 12s, 15s);
|
||||
events.ScheduleEvent(EVENT_EARTH_SHOCK, 8s, 18s);
|
||||
events.ScheduleEvent(EVENT_CHAIN_BURN, 12s, 28s);
|
||||
events.ScheduleEvent(EVENT_ILLUSIONS, 16s, 24s);
|
||||
}
|
||||
|
||||
bool CanAIAttack(Unit const* target) const override
|
||||
{
|
||||
if (me->GetThreatMgr().getThreatList().size() > 1 && me->GetThreatMgr().getOnlineContainer().getMostHated()->getTarget() == target)
|
||||
return !target->HasAura(SPELL_SLEEP);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
_EnterCombat();
|
||||
events.ScheduleEvent(EVENT_SLEEP, 12s, 15s);
|
||||
events.ScheduleEvent(EVENT_EARTH_SHOCK, 8s, 18s);
|
||||
events.ScheduleEvent(EVENT_CHAIN_BURN, 12s, 28s);
|
||||
events.ScheduleEvent(EVENT_ILLUSIONS, 16s, 24s);
|
||||
}
|
||||
|
||||
bool CanAIAttack(Unit const* target) const override
|
||||
{
|
||||
if (me->GetThreatMgr().getThreatList().size() > 1 && me->GetThreatMgr().getOnlineContainer().getMostHated()->getTarget() == target)
|
||||
return !target->HasAura(SPELL_SLEEP);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
switch (eventId)
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_SLEEP:
|
||||
DoCastVictim(SPELL_SLEEP, true);
|
||||
events.ScheduleEvent(EVENT_SLEEP, 24s, 32s);
|
||||
return;
|
||||
case EVENT_EARTH_SHOCK:
|
||||
DoCastVictim(SPELL_EARTH_SHOCK);
|
||||
events.ScheduleEvent(EVENT_EARTH_SHOCK, 8s, 18s);
|
||||
break;
|
||||
case EVENT_CHAIN_BURN:
|
||||
case EVENT_SLEEP:
|
||||
DoCastVictim(SPELL_SLEEP, true);
|
||||
events.ScheduleEvent(EVENT_SLEEP, 24s, 32s);
|
||||
return;
|
||||
case EVENT_EARTH_SHOCK:
|
||||
DoCastVictim(SPELL_EARTH_SHOCK);
|
||||
events.ScheduleEvent(EVENT_EARTH_SHOCK, 8s, 18s);
|
||||
break;
|
||||
case EVENT_CHAIN_BURN:
|
||||
if (me->GetPowerPct(POWER_MANA) > 5.f) // totally guessed
|
||||
{
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, [&](Unit* u) { return u && !u->IsPet() && u->getPowerType() == POWER_MANA; }))
|
||||
{
|
||||
DoCast(target, SPELL_CHAIN_BURN, false);
|
||||
DoCast(target, SPELL_CHAIN_BURN);
|
||||
}
|
||||
events.ScheduleEvent(EVENT_CHAIN_BURN, 12s, 28s);
|
||||
break;
|
||||
case EVENT_ILLUSIONS:
|
||||
DoCastSelf(SPELL_SUMMON_NIGHTMARE_ILLUSION_LEFT, true);
|
||||
DoCastSelf(SPELL_SUMMON_NIGHTMARE_ILLUSION_BACK, true);
|
||||
DoCastSelf(SPELL_SUMMON_NIGHTMARE_ILLUSION_RIGHT, true);
|
||||
events.ScheduleEvent(EVENT_ILLUSIONS, 16s, 24s);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
events.ScheduleEvent(EVENT_CHAIN_BURN, 12s, 28s);
|
||||
break;
|
||||
case EVENT_ILLUSIONS:
|
||||
DoCastSelf(SPELL_SUMMON_NIGHTMARE_ILLUSION_LEFT, true);
|
||||
DoCastSelf(SPELL_SUMMON_NIGHTMARE_ILLUSION_BACK, true);
|
||||
DoCastSelf(SPELL_SUMMON_NIGHTMARE_ILLUSION_RIGHT, true);
|
||||
events.ScheduleEvent(EVENT_ILLUSIONS, 15s, 25s);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetZulGurubAI<boss_hazzarahAI>(creature);
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -164,6 +155,6 @@ class spell_chain_burn : public SpellScript
|
||||
|
||||
void AddSC_boss_hazzarah()
|
||||
{
|
||||
new boss_hazzarah();
|
||||
RegisterZulGurubCreatureAI(boss_hazzarah);
|
||||
RegisterSpellScript(spell_chain_burn);
|
||||
}
|
||||
|
||||
@@ -15,15 +15,10 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* ScriptData
|
||||
SDName: Boss_Jin'do the Hexxer
|
||||
SD%Complete: 85
|
||||
SDComment: Mind Control not working because of core bug. Shades visible for all.
|
||||
SDCategory: Zul'Gurub
|
||||
EndScriptData */
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "SpellScript.h"
|
||||
#include "TaskScheduler.h"
|
||||
#include "zulgurub.h"
|
||||
|
||||
enum Say
|
||||
@@ -33,269 +28,265 @@ enum Say
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_BRAINWASHTOTEM = 24262,
|
||||
SPELL_POWERFULLHEALINGWARD = 24309,
|
||||
SPELL_BRAIN_WASH_TOTEM = 24262,
|
||||
SPELL_POWERFULL_HEALING_WARD = 24309,
|
||||
SPELL_HEX = 24053,
|
||||
SPELL_DELUSIONSOFJINDO = 24306,
|
||||
SPELL_DELUSIONS_OF_JINDO = 24306,
|
||||
SPELL_SUMMON_SHADE_OF_JINDO = 24308,
|
||||
SPELL_BANISH = 24466,
|
||||
|
||||
//Healing Ward Spell
|
||||
SPELL_HEAL = 24311,
|
||||
|
||||
//Shade of Jindo Spell
|
||||
SPELL_SHADEOFJINDO_PASSIVE = 24307,
|
||||
SPELL_SHADEOFJINDO_VISUAL = 24313,
|
||||
SPELL_SHADOWSHOCK = 19460
|
||||
SPELL_SHADE_OF_JINDO_PASSIVE = 24307,
|
||||
SPELL_SHADE_OF_JINDO_VISUAL = 24313,
|
||||
SPELL_SHADOW_SHOCK = 19460,
|
||||
SPELL_RANDOM_AGGRO = 23878
|
||||
};
|
||||
|
||||
enum Events
|
||||
{
|
||||
EVENT_BRAINWASHTOTEM = 1,
|
||||
EVENT_POWERFULLHEALINGWARD = 2,
|
||||
EVENT_BRAIN_WASH_TOTEM = 1,
|
||||
EVENT_POWERFULL_HEALING_WARD = 2,
|
||||
EVENT_HEX = 3,
|
||||
EVENT_DELUSIONSOFJINDO = 4,
|
||||
EVENT_DELUSIONS_OF_JINDO = 4,
|
||||
EVENT_TELEPORT = 5
|
||||
};
|
||||
|
||||
Position const TeleportLoc = {-11583.7783f, -1249.4278f, 77.5471f, 4.745f};
|
||||
|
||||
class boss_jindo : public CreatureScript
|
||||
struct boss_jindo : public BossAI
|
||||
{
|
||||
public:
|
||||
boss_jindo() : CreatureScript("boss_jindo") { }
|
||||
boss_jindo(Creature* creature) : BossAI(creature, DATA_JINDO) { }
|
||||
|
||||
struct boss_jindoAI : public BossAI
|
||||
void EnterCombat(Unit* who) override
|
||||
{
|
||||
boss_jindoAI(Creature* creature) : BossAI(creature, DATA_JINDO) { }
|
||||
BossAI::EnterCombat(who);
|
||||
events.ScheduleEvent(EVENT_BRAIN_WASH_TOTEM, 20000);
|
||||
events.ScheduleEvent(EVENT_POWERFULL_HEALING_WARD, 16000);
|
||||
events.ScheduleEvent(EVENT_HEX, 8000);
|
||||
events.ScheduleEvent(EVENT_DELUSIONS_OF_JINDO, 10000);
|
||||
events.ScheduleEvent(EVENT_TELEPORT, 5000);
|
||||
|
||||
void Reset() override
|
||||
Talk(SAY_AGGRO);
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* summon) override
|
||||
{
|
||||
BossAI::JustSummoned(summon);
|
||||
|
||||
switch (summon->GetEntry())
|
||||
{
|
||||
_Reset();
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
_JustDied();
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/) override
|
||||
{
|
||||
_EnterCombat();
|
||||
events.ScheduleEvent(EVENT_BRAINWASHTOTEM, 20000);
|
||||
events.ScheduleEvent(EVENT_POWERFULLHEALINGWARD, 16000);
|
||||
events.ScheduleEvent(EVENT_HEX, 8000);
|
||||
events.ScheduleEvent(EVENT_DELUSIONSOFJINDO, 10000);
|
||||
events.ScheduleEvent(EVENT_TELEPORT, 5000);
|
||||
Talk(SAY_AGGRO);
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* summon) override
|
||||
{
|
||||
BossAI::JustSummoned(summon);
|
||||
|
||||
switch (summon->GetEntry())
|
||||
case NPC_BRAIN_WASH_TOTEM:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1))
|
||||
{
|
||||
case NPC_BRAIN_WASH_TOTEM:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1))
|
||||
{
|
||||
summon->CastSpell(target, summon->m_spells[0], true);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
summon->CastSpell(target, summon->m_spells[0], true);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void EnterEvadeMode(EvadeReason evadeReason) override
|
||||
{
|
||||
if (_EnterEvadeMode(evadeReason))
|
||||
{
|
||||
me->AddUnitState(UNIT_STATE_EVADE);
|
||||
Reset();
|
||||
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_DANCE);
|
||||
|
||||
me->m_Events.AddEventAtOffset([&]()
|
||||
{
|
||||
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_NONE);
|
||||
me->GetMotionMaster()->MoveTargetedHome();
|
||||
}, 4s);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_BRAIN_WASH_TOTEM:
|
||||
DoCastSelf(SPELL_BRAIN_WASH_TOTEM);
|
||||
events.ScheduleEvent(EVENT_BRAIN_WASH_TOTEM, urand(18000, 26000));
|
||||
break;
|
||||
case EVENT_POWERFULL_HEALING_WARD:
|
||||
DoCastSelf(SPELL_POWERFULL_HEALING_WARD, true);
|
||||
events.ScheduleEvent(EVENT_POWERFULL_HEALING_WARD, urand(14000, 20000));
|
||||
break;
|
||||
case EVENT_HEX:
|
||||
if (me->GetThreatMgr().getThreatList().size() > 1)
|
||||
DoCastVictim(SPELL_HEX, true);
|
||||
events.ScheduleEvent(EVENT_HEX, urand(12000, 20000));
|
||||
break;
|
||||
case EVENT_DELUSIONS_OF_JINDO:
|
||||
DoCastRandomTarget(SPELL_DELUSIONS_OF_JINDO);
|
||||
events.ScheduleEvent(EVENT_DELUSIONS_OF_JINDO, urand(4000, 12000));
|
||||
break;
|
||||
case EVENT_TELEPORT:
|
||||
DoCastRandomTarget(SPELL_BANISH);
|
||||
events.ScheduleEvent(EVENT_TELEPORT, urand(15000, 23000));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_BRAINWASHTOTEM:
|
||||
DoCast(me, SPELL_BRAINWASHTOTEM);
|
||||
events.ScheduleEvent(EVENT_BRAINWASHTOTEM, urand(18000, 26000));
|
||||
break;
|
||||
case EVENT_POWERFULLHEALINGWARD:
|
||||
DoCastSelf(SPELL_POWERFULLHEALINGWARD, true);
|
||||
events.ScheduleEvent(EVENT_POWERFULLHEALINGWARD, urand(14000, 20000));
|
||||
break;
|
||||
case EVENT_HEX:
|
||||
DoCastVictim(SPELL_HEX, true);
|
||||
events.ScheduleEvent(EVENT_HEX, urand(12000, 20000));
|
||||
break;
|
||||
case EVENT_DELUSIONSOFJINDO: // HACK
|
||||
// Casting the delusion curse with a shade so shade will attack the same target with the curse.
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
|
||||
{
|
||||
DoCast(target, SPELL_DELUSIONSOFJINDO);
|
||||
Creature* Shade = me->SummonCreature(NPC_SHADE_OF_JINDO, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
|
||||
if (Shade)
|
||||
Shade->AI()->AttackStart(target);
|
||||
}
|
||||
events.ScheduleEvent(EVENT_DELUSIONSOFJINDO, urand(4000, 12000));
|
||||
break;
|
||||
case EVENT_TELEPORT: // Possible HACK
|
||||
// Teleports a random player and spawns 9 Sacrificed Trolls to attack player
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
|
||||
{
|
||||
DoTeleportPlayer(target, TeleportLoc.m_positionX, TeleportLoc.m_positionY, TeleportLoc.m_positionZ, TeleportLoc.GetOrientation());
|
||||
if (DoGetThreat(me->GetVictim()))
|
||||
DoModifyThreatPercent(target, -100);
|
||||
Creature* SacrificedTroll;
|
||||
SacrificedTroll = me->SummonCreature(NPC_SACRIFICED_TROLL, TeleportLoc.m_positionX + 2, TeleportLoc.m_positionY, TeleportLoc.m_positionZ, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
|
||||
if (SacrificedTroll)
|
||||
SacrificedTroll->AI()->AttackStart(target);
|
||||
SacrificedTroll = me->SummonCreature(NPC_SACRIFICED_TROLL, TeleportLoc.m_positionX - 2, TeleportLoc.m_positionY, TeleportLoc.m_positionZ, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
|
||||
if (SacrificedTroll)
|
||||
SacrificedTroll->AI()->AttackStart(target);
|
||||
SacrificedTroll = me->SummonCreature(NPC_SACRIFICED_TROLL, TeleportLoc.m_positionX + 4, TeleportLoc.m_positionY, TeleportLoc.m_positionZ, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
|
||||
if (SacrificedTroll)
|
||||
SacrificedTroll->AI()->AttackStart(target);
|
||||
SacrificedTroll = me->SummonCreature(NPC_SACRIFICED_TROLL, TeleportLoc.m_positionX - 4, TeleportLoc.m_positionY, TeleportLoc.m_positionZ, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
|
||||
if (SacrificedTroll)
|
||||
SacrificedTroll->AI()->AttackStart(target);
|
||||
SacrificedTroll = me->SummonCreature(NPC_SACRIFICED_TROLL, TeleportLoc.m_positionX, TeleportLoc.m_positionY + 2, TeleportLoc.m_positionZ, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
|
||||
if (SacrificedTroll)
|
||||
SacrificedTroll->AI()->AttackStart(target);
|
||||
SacrificedTroll = me->SummonCreature(NPC_SACRIFICED_TROLL, TeleportLoc.m_positionX, TeleportLoc.m_positionY - 2, TeleportLoc.m_positionZ, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
|
||||
if (SacrificedTroll)
|
||||
SacrificedTroll->AI()->AttackStart(target);
|
||||
SacrificedTroll = me->SummonCreature(NPC_SACRIFICED_TROLL, TeleportLoc.m_positionX, TeleportLoc.m_positionY + 4, TeleportLoc.m_positionZ, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
|
||||
if (SacrificedTroll)
|
||||
SacrificedTroll->AI()->AttackStart(target);
|
||||
SacrificedTroll = me->SummonCreature(NPC_SACRIFICED_TROLL, TeleportLoc.m_positionX, TeleportLoc.m_positionY - 4, TeleportLoc.m_positionZ, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
|
||||
if (SacrificedTroll)
|
||||
SacrificedTroll->AI()->AttackStart(target);
|
||||
SacrificedTroll = me->SummonCreature(NPC_SACRIFICED_TROLL, TeleportLoc.m_positionX + 3, TeleportLoc.m_positionY, TeleportLoc.m_positionZ, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
|
||||
if (SacrificedTroll)
|
||||
SacrificedTroll->AI()->AttackStart(target);
|
||||
}
|
||||
events.ScheduleEvent(EVENT_TELEPORT, urand(15000, 23000));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
bool CanAIAttack(Unit const* target) const override
|
||||
{
|
||||
bool CanAIAttack(Unit const* target) const override
|
||||
{
|
||||
if (me->GetThreatMgr().getThreatList().size() > 1 && me->GetThreatMgr().getOnlineContainer().getMostHated()->getTarget() == target)
|
||||
return !target->HasAura(SPELL_HEX);
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetZulGurubAI<boss_jindoAI>(creature);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
//Healing Ward
|
||||
class npc_healing_ward : public CreatureScript
|
||||
struct npc_healing_ward : public ScriptedAI
|
||||
{
|
||||
public:
|
||||
npc_healing_ward()
|
||||
: CreatureScript("npc_healing_ward")
|
||||
npc_healing_ward(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
_instance = creature->GetInstanceScript();
|
||||
}
|
||||
|
||||
struct npc_healing_wardAI : public ScriptedAI
|
||||
void Reset() override
|
||||
{
|
||||
npc_healing_wardAI(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
instance = creature->GetInstanceScript();
|
||||
}
|
||||
_scheduler.CancelAll();
|
||||
}
|
||||
|
||||
uint32 Heal_Timer;
|
||||
|
||||
InstanceScript* instance;
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
Heal_Timer = 2000;
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/) override
|
||||
{
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
//Heal_Timer
|
||||
if (Heal_Timer <= diff)
|
||||
void EnterCombat(Unit* /*who*/) override
|
||||
{
|
||||
_scheduler.
|
||||
Schedule(2s, [this](TaskContext context)
|
||||
{
|
||||
Unit* pJindo = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_JINDO));
|
||||
Unit* pJindo = ObjectAccessor::GetUnit(*me, _instance->GetGuidData(DATA_JINDO));
|
||||
if (pJindo)
|
||||
DoCast(pJindo, SPELL_HEAL);
|
||||
Heal_Timer = 3000;
|
||||
}
|
||||
else Heal_Timer -= diff;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetZulGurubAI<npc_healing_wardAI>(creature);
|
||||
context.Repeat(3s);
|
||||
});
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
_scheduler.Update(diff, [this]
|
||||
{
|
||||
DoMeleeAttackIfReady();
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
InstanceScript* _instance;
|
||||
TaskScheduler _scheduler;
|
||||
};
|
||||
|
||||
//Shade of Jindo
|
||||
class npc_shade_of_jindo : public CreatureScript
|
||||
struct npc_shade_of_jindo : public ScriptedAI
|
||||
{
|
||||
public:
|
||||
npc_shade_of_jindo()
|
||||
: CreatureScript("npc_shade_of_jindo")
|
||||
npc_shade_of_jindo(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void IsSummonedBy(Unit* /*summoner*/) override
|
||||
{
|
||||
DoZoneInCombat();
|
||||
DoCastSelf(SPELL_SHADE_OF_JINDO_PASSIVE, true);
|
||||
DoCastSelf(SPELL_SHADE_OF_JINDO_VISUAL, true);
|
||||
DoCastAOE(SPELL_RANDOM_AGGRO, true);
|
||||
}
|
||||
|
||||
struct npc_shade_of_jindoAI : public ScriptedAI
|
||||
void Reset() override
|
||||
{
|
||||
npc_shade_of_jindoAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
_scheduler.CancelAll();
|
||||
|
||||
uint32 ShadowShock_Timer;
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
ShadowShock_Timer = 1000;
|
||||
DoCastSelf(SPELL_SHADEOFJINDO_PASSIVE, true);
|
||||
DoCastSelf(SPELL_SHADEOFJINDO_VISUAL, true);
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/) override { }
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
//ShadowShock_Timer
|
||||
if (ShadowShock_Timer <= diff)
|
||||
_scheduler.
|
||||
Schedule(1s, [this](TaskContext context)
|
||||
{
|
||||
DoCastVictim(SPELL_SHADOWSHOCK);
|
||||
ShadowShock_Timer = 2000;
|
||||
}
|
||||
else ShadowShock_Timer -= diff;
|
||||
DoCastAOE(SPELL_RANDOM_AGGRO, true);
|
||||
context.Repeat();
|
||||
});
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
void EnterCombat(Unit* /*who*/) override
|
||||
{
|
||||
return GetZulGurubAI<npc_shade_of_jindoAI>(creature);
|
||||
_scheduler.
|
||||
Schedule(1s, [this](TaskContext context)
|
||||
{
|
||||
DoCastVictim(SPELL_SHADOW_SHOCK);
|
||||
context.Repeat(2s);
|
||||
});
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
_scheduler.Update(diff, [this]
|
||||
{
|
||||
DoMeleeAttackIfReady();
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
TaskScheduler _scheduler;
|
||||
};
|
||||
|
||||
class spell_random_aggro : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_random_aggro);
|
||||
|
||||
void HandleOnHit()
|
||||
{
|
||||
Unit* caster = GetCaster();
|
||||
Unit* target = GetHitUnit();
|
||||
if (!caster || !target || !caster->GetAI())
|
||||
return;
|
||||
|
||||
caster->GetAI()->AttackStart(target);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnHit += SpellHitFn(spell_random_aggro::HandleOnHit);
|
||||
}
|
||||
};
|
||||
|
||||
class spell_delusions_of_jindo : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_delusions_of_jindo);
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SPELL_SUMMON_SHADE_OF_JINDO });
|
||||
}
|
||||
|
||||
void HandleOnHit()
|
||||
{
|
||||
Unit* caster = GetCaster();
|
||||
if (caster)
|
||||
caster->CastSpell(caster, SPELL_SUMMON_SHADE_OF_JINDO, true);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnHit += SpellHitFn(spell_delusions_of_jindo::HandleOnHit);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_jindo()
|
||||
{
|
||||
new boss_jindo();
|
||||
new npc_healing_ward();
|
||||
new npc_shade_of_jindo();
|
||||
RegisterZulGurubCreatureAI(boss_jindo);
|
||||
RegisterZulGurubCreatureAI(npc_healing_ward);
|
||||
RegisterZulGurubCreatureAI(npc_shade_of_jindo);
|
||||
RegisterSpellScript(spell_random_aggro);
|
||||
RegisterSpellScript(spell_delusions_of_jindo);
|
||||
}
|
||||
|
||||
@@ -71,9 +71,6 @@ public:
|
||||
Initialize();
|
||||
}
|
||||
|
||||
bool Enraged;
|
||||
bool WasDead;
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
Enraged = false;
|
||||
@@ -90,17 +87,16 @@ public:
|
||||
me->SetStandState(UNIT_STAND_STATE_STAND);
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
|
||||
me->LoadEquipment(1, true);
|
||||
|
||||
if (Creature* zealot = instance->GetCreature(DATA_LORKHAN))
|
||||
{
|
||||
zealot->AI()->Reset();
|
||||
zealot->ResetFaction();
|
||||
}
|
||||
|
||||
if (Creature* zealot = instance->GetCreature(DATA_ZATH))
|
||||
{
|
||||
zealot->AI()->Reset();
|
||||
zealot->ResetFaction();
|
||||
}
|
||||
|
||||
_scheduler.SetValidator([this]
|
||||
@@ -148,7 +144,7 @@ public:
|
||||
CheckPhaseTransition();
|
||||
|
||||
_scheduler.Schedule(10s, [this, data](TaskContext /*context*/) {
|
||||
if ((!_lorkhanDied || !_zathDied) && !WasDead)
|
||||
if (!_lorkhanDied || !_zathDied || !WasDead)
|
||||
{
|
||||
ReviveZealot(data);
|
||||
}
|
||||
@@ -157,19 +153,24 @@ public:
|
||||
|
||||
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType, SpellSchoolMask) override
|
||||
{
|
||||
if (!WasDead && damage >= me->GetHealth())
|
||||
if (!me->HasAura(SPELL_TIGER_FORM) && damage >= me->GetHealth())
|
||||
{
|
||||
damage = me->GetHealth() - 1;
|
||||
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->SetStandState(UNIT_STAND_STATE_SLEEP);
|
||||
me->AttackStop();
|
||||
WasDead = true;
|
||||
CheckPhaseTransition();
|
||||
Talk(EMOTE_THEKAL_DIES);
|
||||
|
||||
if (!WasDead)
|
||||
{
|
||||
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->SetStandState(UNIT_STAND_STATE_SLEEP);
|
||||
me->AttackStop();
|
||||
DoResetThreat();
|
||||
WasDead = true;
|
||||
CheckPhaseTransition();
|
||||
Talk(EMOTE_THEKAL_DIES);
|
||||
}
|
||||
}
|
||||
|
||||
if (!Enraged && me->HealthBelowPctDamaged(20, damage) && me->GetEntry() != NPC_HIGH_PRIEST_THEKAL)
|
||||
if (!Enraged && me->HealthBelowPctDamaged(20, damage) && me->HasAura(SPELL_TIGER_FORM))
|
||||
{
|
||||
DoCastSelf(SPELL_ENRAGE);
|
||||
Enraged = true;
|
||||
@@ -182,7 +183,7 @@ public:
|
||||
{
|
||||
me->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
|
||||
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||
me->ResetFaction();
|
||||
me->RestoreFaction();
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
me->SetFullHealth();
|
||||
WasDead = false;
|
||||
@@ -202,11 +203,8 @@ public:
|
||||
{
|
||||
if (Creature* zealot = instance->GetCreature(zealotData))
|
||||
{
|
||||
zealot->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
|
||||
zealot->ResetFaction();
|
||||
zealot->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||
zealot->SetReactState(REACT_AGGRESSIVE);
|
||||
zealot->SetFullHealth();
|
||||
zealot->Respawn(true);
|
||||
zealot->SetInCombatWithZone();
|
||||
UpdateZealotStatus(zealotData, false);
|
||||
}
|
||||
}
|
||||
@@ -231,10 +229,10 @@ public:
|
||||
Talk(SAY_AGGRO);
|
||||
me->SetStandState(UNIT_STAND_STATE_STAND);
|
||||
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||
DoResetThreat();
|
||||
|
||||
_scheduler.Schedule(6s, [this](TaskContext /*context*/) {
|
||||
DoCastSelf(SPELL_TIGER_FORM);
|
||||
me->LoadEquipment(0, true);
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
|
||||
_scheduler.Schedule(30s, [this](TaskContext context) {
|
||||
@@ -261,7 +259,10 @@ public:
|
||||
else
|
||||
{
|
||||
_scheduler.Schedule(10s, [this](TaskContext /*context*/) {
|
||||
DoAction(ACTION_RESSURRECT);
|
||||
if (!(WasDead && _lorkhanDied && _zathDied))
|
||||
{
|
||||
DoAction(ACTION_RESSURRECT);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -271,6 +272,8 @@ public:
|
||||
GuidVector _catGuids;
|
||||
bool _lorkhanDied;
|
||||
bool _zathDied;
|
||||
bool Enraged;
|
||||
bool WasDead;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
@@ -295,10 +298,6 @@ public:
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
me->SetUInt32Value(UNIT_FIELD_BYTES_1, 0);
|
||||
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
|
||||
_scheduler.CancelAll();
|
||||
|
||||
_scheduler.SetValidator([this]
|
||||
@@ -339,24 +338,13 @@ public:
|
||||
});
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType, SpellSchoolMask) override
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
if (damage >= me->GetHealth() && me->HasReactState(REACT_AGGRESSIVE))
|
||||
Talk(EMOTE_ZEALOT_DIES);
|
||||
|
||||
if (Creature* thekal = instance->GetCreature(DATA_THEKAL))
|
||||
{
|
||||
Talk(EMOTE_ZEALOT_DIES);
|
||||
me->RemoveAllAuras();
|
||||
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||
me->SetStandState(UNIT_STAND_STATE_SLEEP);
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->InterruptNonMeleeSpells(false);
|
||||
me->AttackStop();
|
||||
|
||||
damage = 0;
|
||||
|
||||
if (Creature* thekal = instance->GetCreature(DATA_THEKAL))
|
||||
{
|
||||
thekal->AI()->SetData(ACTION_RESSURRECT, DATA_LORKHAN);
|
||||
}
|
||||
thekal->AI()->SetData(ACTION_RESSURRECT, DATA_LORKHAN);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -395,10 +383,6 @@ public:
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
me->SetStandState(UNIT_STAND_STATE_STAND);
|
||||
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
|
||||
_scheduler.CancelAll();
|
||||
|
||||
_scheduler.SetValidator([this]
|
||||
@@ -436,23 +420,13 @@ public:
|
||||
});
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType, SpellSchoolMask) override
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
if (damage >= me->GetHealth() && me->HasReactState(REACT_AGGRESSIVE))
|
||||
Talk(EMOTE_ZEALOT_DIES);
|
||||
|
||||
if (Creature* thekal = instance->GetCreature(DATA_THEKAL))
|
||||
{
|
||||
Talk(EMOTE_ZEALOT_DIES);
|
||||
me->RemoveAllAuras();
|
||||
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||
me->SetStandState(UNIT_STAND_STATE_SLEEP);
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->AttackStop();
|
||||
|
||||
damage = 0;
|
||||
|
||||
if (Creature* thekal = instance->GetCreature(DATA_THEKAL))
|
||||
{
|
||||
thekal->AI()->SetData(ACTION_RESSURRECT, DATA_ZATH);
|
||||
}
|
||||
thekal->AI()->SetData(ACTION_RESSURRECT, DATA_ZATH);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,6 @@ public:
|
||||
instance_zulgurub_InstanceMapScript(Map* map) : InstanceScript(map)
|
||||
{
|
||||
SetBossNumber(EncounterCount);
|
||||
LoadObjectData(creatureData, nullptr);
|
||||
LoadDoorData(doorData);
|
||||
LoadObjectData(creatureData, nullptr);
|
||||
}
|
||||
@@ -83,6 +82,12 @@ public:
|
||||
case NPC_GAHZRANKA:
|
||||
_gahzrankaGUID = creature->GetGUID();
|
||||
break;
|
||||
case NPC_GRILEK:
|
||||
case NPC_HAZZARAH:
|
||||
case NPC_RENATAKI:
|
||||
case NPC_WUSHOOLAY:
|
||||
_edgeOfMadnessGUID = creature->GetGUID();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -120,6 +125,8 @@ public:
|
||||
return _goGongOfBethekkGUID;
|
||||
case DATA_HAKKAR:
|
||||
return _hakkarGUID;
|
||||
case DATA_EDGE_OF_MADNESS:
|
||||
return _edgeOfMadnessGUID;
|
||||
}
|
||||
|
||||
return ObjectGuid::Empty;
|
||||
@@ -135,6 +142,36 @@ public:
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RemoveHakkarPowerStack()
|
||||
{
|
||||
if (Creature* hakkar = instance->GetCreature(_hakkarGUID))
|
||||
{
|
||||
hakkar->CastSpell(hakkar, SPELL_HAKKAR_POWER_DOWN, true);
|
||||
}
|
||||
}
|
||||
|
||||
bool SetBossState(uint32 type, EncounterState state) override
|
||||
{
|
||||
if (!InstanceScript::SetBossState(type, state))
|
||||
return false;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case DATA_JEKLIK:
|
||||
case DATA_VENOXIS:
|
||||
case DATA_MARLI:
|
||||
case DATA_ARLOKK:
|
||||
case DATA_THEKAL:
|
||||
if (state == DONE)
|
||||
RemoveHakkarPowerStack();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string GetSaveData() override
|
||||
{
|
||||
OUT_SAVE_INST_DATA;
|
||||
@@ -187,6 +224,7 @@ public:
|
||||
ObjectGuid _goGongOfBethekkGUID;
|
||||
ObjectGuid _hakkarGUID;
|
||||
ObjectGuid _gahzrankaGUID;
|
||||
ObjectGuid _edgeOfMadnessGUID;
|
||||
};
|
||||
|
||||
InstanceScript* GetInstanceScript(InstanceMap* map) const override
|
||||
@@ -224,6 +262,14 @@ struct go_brazier_of_madness : public GameObjectAI
|
||||
return true;
|
||||
}
|
||||
|
||||
if (InstanceScript* instanceScript = me->GetInstanceScript())
|
||||
{
|
||||
if (instanceScript->GetGuidData(DATA_EDGE_OF_MADNESS))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 bossEntry = 0;
|
||||
for (uint8 i = 0; i < 4; ++i)
|
||||
{
|
||||
|
||||
@@ -76,6 +76,12 @@ enum GameobjectIds
|
||||
GO_GONG_OF_BETHEKK = 180526 // Arlokk Event
|
||||
};
|
||||
|
||||
enum SpellIds
|
||||
{
|
||||
SPELL_HAKKAR_POWER = 24692,
|
||||
SPELL_HAKKAR_POWER_DOWN = 24693
|
||||
};
|
||||
|
||||
template <class AI, class T>
|
||||
inline AI* GetZulGurubAI(T* obj)
|
||||
{
|
||||
|
||||
@@ -453,7 +453,8 @@ enum eJuggle
|
||||
|
||||
SPELL_TORCH_CHECK = 45644,
|
||||
SPELL_GIVE_TORCH = 45280,
|
||||
QUEST_CHECK = 11937,
|
||||
QUEST_TORCH_CATCHING_A = 11657,
|
||||
QUEST_TORCH_CATCHING_H = 11923
|
||||
};
|
||||
|
||||
class spell_midsummer_juggling_torch : public SpellScript
|
||||
@@ -507,6 +508,36 @@ class spell_midsummer_juggling_torch : public SpellScript
|
||||
}
|
||||
};
|
||||
|
||||
// 45644 - Juggle Torch (Catch)
|
||||
class spell_midsummer_torch_catch : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_midsummer_torch_catch);
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SPELL_GIVE_TORCH });
|
||||
}
|
||||
|
||||
void HandleDummy(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
Player* player = GetHitPlayer();
|
||||
if (!player)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (player->GetQuestStatus(QUEST_TORCH_CATCHING_A) == QUEST_STATUS_REWARDED || player->GetQuestStatus(QUEST_TORCH_CATCHING_H) == QUEST_STATUS_REWARDED)
|
||||
{
|
||||
player->CastSpell(player, SPELL_GIVE_TORCH);
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_midsummer_torch_catch::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_event_midsummer_scripts()
|
||||
{
|
||||
// NPCs
|
||||
@@ -520,4 +551,5 @@ void AddSC_event_midsummer_scripts()
|
||||
RegisterSpellScript(spell_midsummer_torch_quest);
|
||||
RegisterSpellScript(spell_midsummer_fling_torch);
|
||||
RegisterSpellScript(spell_midsummer_juggling_torch);
|
||||
RegisterSpellScript(spell_midsummer_torch_catch);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "AreaBoundary.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "azjol_nerub.h"
|
||||
@@ -34,6 +35,13 @@ ObjectData const creatureData[] =
|
||||
{ NPC_HADRONOX, DATA_HADRONOX_EVENT }
|
||||
};
|
||||
|
||||
BossBoundaryData const boundaries =
|
||||
{
|
||||
{ DATA_KRIKTHIR_THE_GATEWATCHER_EVENT, new RectangleBoundary(400.0f, 580.0f, 623.5f, 810.0f) },
|
||||
{ DATA_HADRONOX_EVENT, new ZRangeBoundary(666.0f, 776.0f) },
|
||||
{ DATA_ANUBARAK_EVENT, new CircleBoundary(Position(550.6178f, 253.5917f), 26.0f) }
|
||||
};
|
||||
|
||||
class instance_azjol_nerub : public InstanceMapScript
|
||||
{
|
||||
public:
|
||||
@@ -44,6 +52,7 @@ public:
|
||||
instance_azjol_nerub_InstanceScript(Map* map) : InstanceScript(map)
|
||||
{
|
||||
SetBossNumber(MAX_ENCOUNTERS);
|
||||
LoadBossBoundaries(boundaries);
|
||||
LoadDoorData(doorData);
|
||||
LoadObjectData(creatureData, nullptr);
|
||||
};
|
||||
|
||||
@@ -125,20 +125,27 @@ public:
|
||||
{
|
||||
if (HealthBelowPct(50) && !health50)
|
||||
{
|
||||
WorldObject* summoner = nullptr;
|
||||
if (TempSummon const* tempSummon = me->ToTempSummon())
|
||||
{
|
||||
summoner = tempSummon->GetSummonerUnit();
|
||||
if (WorldObject* summoner = tempSummon->GetSummonerUnit())
|
||||
{
|
||||
Talk(SAY_TURMOIL_HALF_HP, summoner);
|
||||
}
|
||||
}
|
||||
|
||||
Talk(SAY_TURMOIL_HALF_HP, summoner);
|
||||
health50 = true;
|
||||
}
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
Talk(SAY_TURMOIL_DEATH, me->ToTempSummon()->GetSummonerUnit()->ToPlayer());
|
||||
if (TempSummon const* tempSummon = me->ToTempSummon())
|
||||
{
|
||||
if (WorldObject* summoner = tempSummon->GetSummonerUnit())
|
||||
{
|
||||
Talk(SAY_TURMOIL_DEATH, summoner);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setphase(short newPhase)
|
||||
|
||||
@@ -268,7 +268,19 @@ public:
|
||||
{
|
||||
Talk(SAY_YSONDRE_SUMMON_DRUIDS);
|
||||
|
||||
for (uint8 i = 0; i < 10; ++i)
|
||||
auto const& attackers = me->GetThreatMgr().getThreatList();
|
||||
uint8 attackersCount = 0;
|
||||
|
||||
for (const auto attacker : attackers)
|
||||
{
|
||||
if ((*attacker)->ToPlayer() && (*attacker)->IsAlive())
|
||||
++attackersCount;
|
||||
}
|
||||
|
||||
uint8 amount = attackersCount < 30 ? attackersCount * 0.5f : 15;
|
||||
amount = amount < 1 ? 1 : amount;
|
||||
|
||||
for (uint8 i = 0; i < amount; ++i)
|
||||
DoCast(me, SPELL_SUMMON_DRUID_SPIRITS, true);
|
||||
++_stage;
|
||||
}
|
||||
@@ -643,6 +655,12 @@ public:
|
||||
emerald_dragonAI::UpdateAI(diff);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
_JustDied();
|
||||
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE);
|
||||
}
|
||||
|
||||
private:
|
||||
bool _banished; // used for shades activation testing
|
||||
uint32 _banishedTimer; // counter for banishment timeout
|
||||
|
||||
@@ -821,19 +821,19 @@ public:
|
||||
if (!IsHolidayActive(HOLIDAY_FIRE_FESTIVAL))
|
||||
break;
|
||||
|
||||
Map::PlayerList const& players = me->GetMap()->GetPlayers();
|
||||
for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
|
||||
std::list<Player*> targets;
|
||||
Acore::AnyPlayerInObjectRangeCheck check(me, me->GetVisibilityRange(), false);
|
||||
Acore::PlayerListSearcherWithSharedVision<Acore::AnyPlayerInObjectRangeCheck> searcher(me, targets, check);
|
||||
Cell::VisitWorldObjects(me, searcher, me->GetVisibilityRange());
|
||||
for (Player* player : targets)
|
||||
{
|
||||
if (Player* player = itr->GetSource())
|
||||
if (player->GetTeamId() == TEAM_HORDE)
|
||||
{
|
||||
if (player->GetTeamId() == TEAM_HORDE)
|
||||
{
|
||||
me->PlayDirectMusic(EVENTMIDSUMMERFIREFESTIVAL_H, player);
|
||||
}
|
||||
else
|
||||
{
|
||||
me->PlayDirectMusic(EVENTMIDSUMMERFIREFESTIVAL_A, player);
|
||||
}
|
||||
me->PlayDirectMusic(EVENTMIDSUMMERFIREFESTIVAL_H, player);
|
||||
}
|
||||
else
|
||||
{
|
||||
me->PlayDirectMusic(EVENTMIDSUMMERFIREFESTIVAL_A, player);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -769,13 +769,12 @@ public:
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
Active = true;
|
||||
CanIteract = 3500;
|
||||
Active = false;
|
||||
CanIteract = 0;
|
||||
DoCast(me, SPELL_BRAZIER, true);
|
||||
DoCast(me, SPELL_FIERY_AURA, false);
|
||||
me->UpdateHeight(me->GetPositionZ() + 0.94f);
|
||||
me->SetDisableGravity(true);
|
||||
me->HandleEmoteCommand(EMOTE_ONESHOT_DANCE);
|
||||
me->SendMovementFlagUpdate();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user