Merge branch 'master' into Playerbot
This commit is contained in:
@@ -38,13 +38,14 @@ public:
|
||||
{
|
||||
static ChatCommandTable gmCommandTable =
|
||||
{
|
||||
{ "chat", HandleGMChatCommand, SEC_GAMEMASTER, Console::No },
|
||||
{ "fly", HandleGMFlyCommand, SEC_GAMEMASTER, Console::No },
|
||||
{ "ingame", HandleGMListIngameCommand, SEC_PLAYER, Console::Yes },
|
||||
{ "list", HandleGMListFullCommand, SEC_ADMINISTRATOR, Console::Yes },
|
||||
{ "visible", HandleGMVisibleCommand, SEC_GAMEMASTER, Console::No },
|
||||
{ "on", HandleGMOnCommand, SEC_MODERATOR, Console::No },
|
||||
{ "off", HandleGMOffCommand, SEC_MODERATOR, Console::No }
|
||||
{ "chat", HandleGMChatCommand, SEC_GAMEMASTER, Console::No },
|
||||
{ "fly", HandleGMFlyCommand, SEC_GAMEMASTER, Console::No },
|
||||
{ "ingame", HandleGMListIngameCommand, SEC_PLAYER, Console::Yes },
|
||||
{ "list", HandleGMListFullCommand, SEC_ADMINISTRATOR, Console::Yes },
|
||||
{ "visible", HandleGMVisibleCommand, SEC_GAMEMASTER, Console::No },
|
||||
{ "on", HandleGMOnCommand, SEC_MODERATOR, Console::No },
|
||||
{ "off", HandleGMOffCommand, SEC_MODERATOR, Console::No },
|
||||
{ "spectator", HandleGMSpectatorCommand, SEC_GAMEMASTER, Console::No },
|
||||
};
|
||||
static ChatCommandTable commandTable =
|
||||
{
|
||||
@@ -236,6 +237,19 @@ public:
|
||||
handler->SendNotification(LANG_GM_OFF);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleGMSpectatorCommand(ChatHandler* handler, Optional<bool> enable)
|
||||
{
|
||||
Player* player = handler->GetSession()->GetPlayer();
|
||||
|
||||
if (enable.has_value())
|
||||
player->SetGMSpectator(*enable);
|
||||
else
|
||||
player->SetGMSpectator(!player->IsGMSpectator());
|
||||
handler->SendNotification(player->IsGMSpectator() ? LANG_GM_SPECTATOR_ON : LANG_GM_SPECTATOR_OFF);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_gm_commandscript()
|
||||
|
||||
@@ -74,7 +74,7 @@ public:
|
||||
|
||||
if (sGuildMgr->GetGuildByName(guildName))
|
||||
{
|
||||
handler->SendErrorMessage(LANG_GUILD_RENAME_ALREADY_EXISTS);
|
||||
handler->SendErrorMessage(LANG_GUILD_RENAME_ALREADY_EXISTS, guildName);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -249,6 +249,20 @@ public:
|
||||
handler->PSendSysMessage(LANG_GUILD_INFO_BANK_GOLD, guild->GetTotalBankMoney() / 100 / 100); // Bank Gold (in gold coins)
|
||||
handler->PSendSysMessage(LANG_GUILD_INFO_MOTD, guild->GetMOTD()); // Message of the Day
|
||||
handler->PSendSysMessage(LANG_GUILD_INFO_EXTRA_INFO, guild->GetInfo()); // Extra Information
|
||||
|
||||
QueryResult result = CharacterDatabase.Query("SELECT rid, rname FROM guild_rank WHERE guildid = {}", guild->GetId());
|
||||
if (result)
|
||||
{
|
||||
handler->PSendSysMessage(LANG_GUILD_INFO_RANKS);
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
uint32 rid = fields[0].Get<uint32>();
|
||||
std::string rname = fields[1].Get<std::string>();
|
||||
|
||||
handler->PSendSysMessage(LANG_GUILD_INFO_RANKS_LIST, rid, rname);
|
||||
} while (result->NextRow());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -24,6 +24,9 @@
|
||||
#include "ScriptedEscortAI.h"
|
||||
#include "SpellInfo.h"
|
||||
#include "SpellScript.h"
|
||||
#include "MotionMaster.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include <limits>
|
||||
|
||||
//How to win friends and influence enemies
|
||||
// texts signed for creature 28939 but used for 28939, 28940, 28610
|
||||
@@ -701,10 +704,406 @@ public:
|
||||
};
|
||||
};
|
||||
|
||||
// Spell and NPC IDs for Scourge Assault event
|
||||
enum NecroSpells
|
||||
{
|
||||
SPELL_SCARLET_GHOUL = 52683, // Raises a Scarlet Ghoul from a humanoid corpse
|
||||
SPELL_SCOURGE_GRYPHON = 52685, // Raises a Scourge Gryphon from a gryphon corpse
|
||||
SPELL_GHOULPLOSION = 52672 // Causes a Gluttonous Geist to explode (kill)
|
||||
};
|
||||
|
||||
enum NecroNPCs
|
||||
{
|
||||
NPC_GLUTTONOUS_GEIST = 28905,
|
||||
NPC_DEAD_SCARLET_MEDIC = 28895,
|
||||
NPC_DEAD_SCARLET_INFANTRYMAN = 28896,
|
||||
NPC_DEAD_SCARLET_CAPTAIN = 28898,
|
||||
NPC_DEAD_SCARLET_PEASANT = 28892,
|
||||
NPC_DEAD_SCARLET_MINER = 28891,
|
||||
NPC_DEAD_SCARLET_FLEET_DEFENDER = 28886,
|
||||
NPC_DEAD_SCARLET_GRYPHON = 28893
|
||||
};
|
||||
|
||||
/*######
|
||||
## npc_acherus_necromancer (Entry 28889)
|
||||
######*/
|
||||
class npc_acherus_necromancer : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_acherus_necromancer() : CreatureScript("npc_acherus_necromancer") { }
|
||||
|
||||
struct npc_acherus_necromancerAI : public ScriptedAI
|
||||
{
|
||||
npc_acherus_necromancerAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
EventMap events;
|
||||
ObjectGuid targetCorpseGUID;
|
||||
ObjectGuid geistGUID;
|
||||
bool isOnRitual;
|
||||
|
||||
// Event timers (IDs)
|
||||
enum Events
|
||||
{
|
||||
EVENT_START_RITUAL = 1,
|
||||
EVENT_GHOULPLOSION,
|
||||
EVENT_RAISE_GHOUL,
|
||||
EVENT_RESUME_WP
|
||||
};
|
||||
|
||||
// Point ID for movement
|
||||
enum Points
|
||||
{
|
||||
POINT_CORPSE_REACHED = 1
|
||||
};
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
events.Reset();
|
||||
targetCorpseGUID.Clear();
|
||||
geistGUID.Clear();
|
||||
isOnRitual = false;
|
||||
// Start waypoint movement using WaypointMovementGenerator
|
||||
if (uint32 pathId = me->GetWaypointPath())
|
||||
{
|
||||
me->GetMotionMaster()->MovePath(pathId, true); // true = repeatable
|
||||
}
|
||||
// Schedule the first ritual after 20-30s
|
||||
events.ScheduleEvent(EVENT_START_RITUAL, urand(20000, 30000));
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
events.Update(diff);
|
||||
|
||||
if (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_START_RITUAL:
|
||||
{
|
||||
if (isOnRitual) // Already performing ritual
|
||||
{
|
||||
events.ScheduleEvent(EVENT_START_RITUAL, urand(5000, 10000));
|
||||
break;
|
||||
}
|
||||
|
||||
// Find nearest dead Scarlet humanoid (exclude gryphon)
|
||||
Creature* nearestCorpse = nullptr;
|
||||
float nearestDist = std::numeric_limits<float>::max();
|
||||
static const uint32 corpseEntries[] = {
|
||||
NPC_DEAD_SCARLET_MEDIC, NPC_DEAD_SCARLET_INFANTRYMAN, NPC_DEAD_SCARLET_CAPTAIN,
|
||||
NPC_DEAD_SCARLET_PEASANT, NPC_DEAD_SCARLET_MINER, NPC_DEAD_SCARLET_FLEET_DEFENDER
|
||||
};
|
||||
for (uint32 entry : corpseEntries)
|
||||
{
|
||||
// Search up to 60 yards for each type
|
||||
if (Creature* corpse = me->FindNearestCreature(entry, 60.0f, true))
|
||||
{
|
||||
float dist = me->GetDistance(corpse);
|
||||
if (dist < nearestDist)
|
||||
{
|
||||
nearestDist = dist;
|
||||
nearestCorpse = corpse;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!nearestCorpse)
|
||||
{
|
||||
// No corpse found nearby: try again later
|
||||
events.ScheduleEvent(EVENT_START_RITUAL, urand(5000, 10000));
|
||||
break;
|
||||
}
|
||||
// Start ritual
|
||||
isOnRitual = true;
|
||||
targetCorpseGUID = nearestCorpse->GetGUID();
|
||||
geistGUID.Clear();
|
||||
// Pause waypoint movement and move to the corpse
|
||||
me->PauseMovement();
|
||||
float x, y, z;
|
||||
// Keep it at a distance from the corpse
|
||||
nearestCorpse->GetClosePoint(x, y, z, me->GetObjectSize());
|
||||
me->GetMotionMaster()->MovePoint(POINT_CORPSE_REACHED, x, y, z);
|
||||
break;
|
||||
}
|
||||
|
||||
case EVENT_GHOULPLOSION:
|
||||
{
|
||||
if (Creature* geist = ObjectAccessor::GetCreature(*me, geistGUID))
|
||||
{
|
||||
me->SetFacingToObject(geist);
|
||||
DoCast(geist, SPELL_GHOULPLOSION);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case EVENT_RAISE_GHOUL:
|
||||
{
|
||||
if (Creature* corpse = ObjectAccessor::GetCreature(*me, targetCorpseGUID))
|
||||
{
|
||||
// Cast Scarlet Ghoul on the corpse (always a humanoid for necromancer)
|
||||
me->SetFacingToObject(corpse);
|
||||
DoCast(corpse, SPELL_SCARLET_GHOUL);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case EVENT_RESUME_WP:
|
||||
{
|
||||
// Resume waypoint movement
|
||||
isOnRitual = false;
|
||||
|
||||
targetCorpseGUID.Clear();
|
||||
|
||||
// Resume paused waypoint movement
|
||||
me->ResumeMovement();
|
||||
// Schedule next ritual in 20-30s
|
||||
events.ScheduleEvent(EVENT_START_RITUAL, urand(20000, 30000));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Necromancers are not expected to engage in combat; no melee UpdateAI needed beyond events.
|
||||
}
|
||||
|
||||
void MovementInform(uint32 type, uint32 id) override
|
||||
{
|
||||
if (type == POINT_MOTION_TYPE && id == POINT_CORPSE_REACHED)
|
||||
{
|
||||
// Reached the corpse
|
||||
// Check for nearby Gluttonous Geist within ~3 yards
|
||||
Creature* geist = me->FindNearestCreature(NPC_GLUTTONOUS_GEIST, 3.0f, true);
|
||||
if (geist)
|
||||
{
|
||||
me->SetFacingToObject(geist);
|
||||
geistGUID = geist->GetGUID();
|
||||
// Geist found: schedule Ghoulplosion at +3s, then raising at +6s, then resume at +9s
|
||||
events.ScheduleEvent(EVENT_GHOULPLOSION, 3000);
|
||||
events.ScheduleEvent(EVENT_RAISE_GHOUL, 6000);
|
||||
events.ScheduleEvent(EVENT_RESUME_WP, 9000);
|
||||
}
|
||||
else
|
||||
{
|
||||
// No Geist: just raise after 3s, resume 3s later
|
||||
|
||||
Creature* corpse = ObjectAccessor::GetCreature(*me, targetCorpseGUID);
|
||||
if (corpse)
|
||||
{
|
||||
me->SetFacingToObject(corpse);
|
||||
}
|
||||
|
||||
events.ScheduleEvent(EVENT_RAISE_GHOUL, 3000);
|
||||
events.ScheduleEvent(EVENT_RESUME_WP, 6000);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return new npc_acherus_necromancerAI(creature);
|
||||
}
|
||||
};
|
||||
|
||||
/*######
|
||||
## npc_gothik_the_harvester (Entry 28890)
|
||||
######*/
|
||||
class npc_gothik_the_harvester : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_gothik_the_harvester() : CreatureScript("npc_gothik_the_harvester") { }
|
||||
|
||||
struct npc_gothik_the_harvesterAI : public ScriptedAI
|
||||
{
|
||||
npc_gothik_the_harvesterAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
EventMap events;
|
||||
ObjectGuid targetCorpseGUID;
|
||||
ObjectGuid geistGUID;
|
||||
bool isOnRitual;
|
||||
|
||||
enum Events
|
||||
{
|
||||
EVENT_START_RITUAL = 1,
|
||||
EVENT_GHOULPLOSION,
|
||||
EVENT_RAISE_DEAD,
|
||||
EVENT_RESUME_WP
|
||||
};
|
||||
|
||||
enum Points
|
||||
{
|
||||
POINT_CORPSE_REACHED = 1
|
||||
};
|
||||
|
||||
// Text identifiers for creature_text (see SQL below)
|
||||
enum Says
|
||||
{
|
||||
SAY_GRYPHON = 0, // "You will fly again, beast..."
|
||||
SAY_GHOUL = 1, // "Surprise, surprise! Another ghoul!"
|
||||
SAY_GEIST = 2 // "Is Gothik the Harvester going to have to choke a geist?"
|
||||
};
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
events.Reset();
|
||||
targetCorpseGUID.Clear();
|
||||
geistGUID.Clear();
|
||||
isOnRitual = false;
|
||||
// Start waypoint movement using WaypointMovementGenerator
|
||||
if (uint32 pathId = me->GetWaypointPath())
|
||||
{
|
||||
me->GetMotionMaster()->MovePath(pathId, true); // true = repeatable
|
||||
}
|
||||
// Schedule the first ritual after 50-60s
|
||||
events.ScheduleEvent(EVENT_START_RITUAL, urand(50000, 60000));
|
||||
}
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
events.Update(diff);
|
||||
|
||||
if (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_START_RITUAL:
|
||||
{
|
||||
if (isOnRitual) // Already performing ritual
|
||||
{
|
||||
events.ScheduleEvent(EVENT_START_RITUAL, urand(5000, 10000));
|
||||
break;
|
||||
}
|
||||
|
||||
// Find nearest dead Scarlet NPC (including gryphon)
|
||||
Creature* nearestCorpse = nullptr;
|
||||
float nearestDist = std::numeric_limits<float>::max();
|
||||
static const uint32 corpseEntries[] = {
|
||||
NPC_DEAD_SCARLET_MEDIC, NPC_DEAD_SCARLET_INFANTRYMAN, NPC_DEAD_SCARLET_CAPTAIN,
|
||||
NPC_DEAD_SCARLET_PEASANT, NPC_DEAD_SCARLET_MINER, NPC_DEAD_SCARLET_FLEET_DEFENDER,
|
||||
NPC_DEAD_SCARLET_GRYPHON
|
||||
};
|
||||
for (uint32 entry : corpseEntries)
|
||||
{
|
||||
// Search up to 60 yards for each type
|
||||
if (Creature* corpse = me->FindNearestCreature(entry, 60.0f, true))
|
||||
{
|
||||
float dist = me->GetDistance(corpse);
|
||||
if (dist < nearestDist)
|
||||
{
|
||||
nearestDist = dist;
|
||||
nearestCorpse = corpse;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!nearestCorpse)
|
||||
{
|
||||
events.ScheduleEvent(EVENT_START_RITUAL, urand(5000, 10000));
|
||||
break;
|
||||
}
|
||||
// Start ritual
|
||||
isOnRitual = true;
|
||||
targetCorpseGUID = nearestCorpse->GetGUID();
|
||||
geistGUID.Clear();
|
||||
// Pause waypoint movement and move to the corpse
|
||||
me->PauseMovement();
|
||||
float x, y, z;
|
||||
// Keep it at a distance from the corpse
|
||||
nearestCorpse->GetClosePoint(x, y, z, me->GetObjectSize());
|
||||
me->GetMotionMaster()->MovePoint(POINT_CORPSE_REACHED, x, y, z);
|
||||
break;
|
||||
}
|
||||
case EVENT_GHOULPLOSION:
|
||||
{
|
||||
// Cast Ghoulplosion on the Geist and say the Geist line
|
||||
if (Creature* geist = ObjectAccessor::GetCreature(*me, geistGUID))
|
||||
{
|
||||
Talk(SAY_GEIST);
|
||||
me->SetFacingToObject(geist);
|
||||
DoCast(geist, SPELL_GHOULPLOSION);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case EVENT_RAISE_DEAD:
|
||||
{
|
||||
// Cast the appropriate raise spell on the corpse (griffon or ghoul)
|
||||
if (Creature* corpse = ObjectAccessor::GetCreature(*me, targetCorpseGUID))
|
||||
{
|
||||
me->SetFacingToObject(corpse);
|
||||
uint32 entry = corpse->GetEntry();
|
||||
if (entry == NPC_DEAD_SCARLET_GRYPHON)
|
||||
{
|
||||
DoCast(corpse, SPELL_SCOURGE_GRYPHON);
|
||||
}
|
||||
else
|
||||
{
|
||||
DoCast(corpse, SPELL_SCARLET_GHOUL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EVENT_RESUME_WP:
|
||||
{
|
||||
// Resume waypoint movement
|
||||
isOnRitual = false;
|
||||
targetCorpseGUID.Clear();
|
||||
// Resume paused waypoint movement
|
||||
me->ResumeMovement();
|
||||
// Schedule next ritual in 50-60s
|
||||
events.ScheduleEvent(EVENT_START_RITUAL, urand(50000, 60000));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MovementInform(uint32 type, uint32 id) override
|
||||
{
|
||||
if (type == POINT_MOTION_TYPE && id == POINT_CORPSE_REACHED)
|
||||
{
|
||||
// Reached the target corpse
|
||||
Creature* corpse = ObjectAccessor::GetCreature(*me, targetCorpseGUID);
|
||||
if (corpse)
|
||||
{
|
||||
me->SetFacingToObject(corpse);
|
||||
// Say line depending on corpse type (gryphon or humanoid)
|
||||
if (corpse->GetEntry() == NPC_DEAD_SCARLET_GRYPHON)
|
||||
Talk(SAY_GRYPHON);
|
||||
else
|
||||
Talk(SAY_GHOUL);
|
||||
}
|
||||
// Check for Geist nearby
|
||||
Creature* geist = me->FindNearestCreature(NPC_GLUTTONOUS_GEIST, 3.0f, true);
|
||||
if (geist)
|
||||
{
|
||||
me->SetFacingToObject(geist);
|
||||
geistGUID = geist->GetGUID();
|
||||
// Geist present: Ghoulplosion in 3s (with SAY_GEIST), raise in 6s, resume in 9s
|
||||
events.ScheduleEvent(EVENT_GHOULPLOSION, 3000);
|
||||
events.ScheduleEvent(EVENT_RAISE_DEAD, 6000);
|
||||
events.ScheduleEvent(EVENT_RESUME_WP, 9000);
|
||||
}
|
||||
else
|
||||
{
|
||||
// No Geist: raise in 3s, resume in 6s
|
||||
events.ScheduleEvent(EVENT_RAISE_DEAD, 3000);
|
||||
events.ScheduleEvent(EVENT_RESUME_WP, 6000);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return new npc_gothik_the_harvesterAI(creature);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_the_scarlet_enclave_c2()
|
||||
{
|
||||
new npc_crusade_persuaded();
|
||||
new npc_scarlet_courier();
|
||||
new npc_koltira_deathweaver();
|
||||
new npc_a_special_surprise();
|
||||
new npc_acherus_necromancer();
|
||||
new npc_gothik_the_harvester();
|
||||
}
|
||||
|
||||
@@ -280,14 +280,14 @@ const Position LightOfDawnPos[] =
|
||||
{2289.259f, -5280.355f, 86.112f, 4.41f}, // 3 Koltira Loc1
|
||||
{2273.289f, -5273.675f, 86.701f, 5.01f}, // 4 Thassarian Loc1
|
||||
{2280.81f, -5284.09f, 86.608f, 4.76f}, // 5 Morgraine Loc1
|
||||
{2281.335f, -5300.409f, 85.170f, 1.528f}, // 6 Tirion Summon loc
|
||||
{2165.711f, -5266.1235f, 95.5025f, 0.13962634f }, // 6 Tirion Summon loc
|
||||
{2281.198f, -5257.397f, 80.224f, 4.66f}, // 7 Alexandros loc1
|
||||
{2281.156f, -5259.934f, 80.647f, 0}, // 8 Alexandros loc2
|
||||
{2281.294f, -5281.895f, 82.445f, 1.35f}, // 9 Darion loc1
|
||||
{2281.093f, -5263.013f, 81.125f, 0}, // 10 Darion loc2
|
||||
{2283.896f, -5287.914f, 83.066f, 1.55f}, // 11 Tirion Fordring loc2
|
||||
{2281.313f, -5250.282f, 79.322f, 4.69f}, // 12 Lich King spawns
|
||||
{2281.523f, -5261.058f, 80.877f, 0}, // 13 Lich king moves forward
|
||||
{2280.304f, -5257.205f, 80.09781f, 4.6251f },// 12 Lich King spawns
|
||||
{2280.687f, -5262.276f, 81.082634f, 0.0f },// 13 Lich king moves forward
|
||||
{2264.27f, -5267.29f, 80.16f, 0}, // 14 Tirion Fordring loc3
|
||||
{2270.99f, -5278.00f, 81.89f, 0} // 15 Tirion Fordring loc4
|
||||
};
|
||||
@@ -501,7 +501,12 @@ public:
|
||||
if (Creature* tirion = me->SummonCreature(NPC_HIGHLORD_TIRION_FORDRING, LightOfDawnPos[6], TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 600000))
|
||||
{
|
||||
tirion->LoadEquipment(0, true);
|
||||
tirion->AI()->Talk(SAY_LIGHT_OF_DAWN25);
|
||||
tirion->AI()->Talk(SAY_LIGHT_OF_DAWN25, 4s);
|
||||
|
||||
tirion->m_Events.AddEventAtOffset([&, tirion] {
|
||||
tirion->GetMotionMaster()->MovePath(NPC_HIGHLORD_TIRION_FORDRING * 10, false);
|
||||
}, 14s);
|
||||
|
||||
events.Reset();
|
||||
events.ScheduleEvent(EVENT_FINISH_FIGHT_1, 10s);
|
||||
events.ScheduleEvent(EVENT_FINISH_FIGHT_2, 20s);
|
||||
@@ -898,7 +903,12 @@ public:
|
||||
if (Creature* lk = GetEntryFromSummons(NPC_THE_LICH_KING))
|
||||
{
|
||||
lk->AI()->Talk(SAY_LIGHT_OF_DAWN46);
|
||||
lk->CastSpell(me, SPELL_REBUKE, false);
|
||||
// Mograine's charge puts him inside the Lich King's collision, so we need to teleport him out
|
||||
// Otherwise, Rebuke will kick him the wrong direction
|
||||
me->NearTeleportTo(2279.7493f, -5258.1f, 80.065f, 4.3419204f);
|
||||
lk->m_Events.AddEventAtOffset([&, lk] {
|
||||
lk->CastSpell(me, SPELL_REBUKE, false);
|
||||
}, 1s);
|
||||
}
|
||||
break;
|
||||
case EVENT_OUTRO_SCENE_28:
|
||||
@@ -1200,23 +1210,6 @@ class spell_chapter5_light_of_dawn_aura : public AuraScript
|
||||
}
|
||||
};
|
||||
|
||||
class spell_chapter5_rebuke : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_chapter5_rebuke);
|
||||
|
||||
void HandleLeapBack(SpellEffIndex effIndex)
|
||||
{
|
||||
PreventHitEffect(effIndex);
|
||||
if (Unit* unitTarget = GetHitUnit())
|
||||
unitTarget->KnockbackFrom(2282.86f, -5263.45f, 40.0f, 8.0f);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectLaunchTarget += SpellEffectFn(spell_chapter5_rebuke::HandleLeapBack, EFFECT_0, SPELL_EFFECT_LEAP_BACK);
|
||||
}
|
||||
};
|
||||
|
||||
// 58552 - Return to Orgrimmar
|
||||
// 58533 - Return to Stormwind
|
||||
enum ReturnToCapital
|
||||
@@ -1317,6 +1310,5 @@ void AddSC_the_scarlet_enclave_c5()
|
||||
{
|
||||
new npc_highlord_darion_mograine();
|
||||
RegisterSpellScript(spell_chapter5_light_of_dawn_aura);
|
||||
RegisterSpellScript(spell_chapter5_rebuke);
|
||||
RegisterSpellScript(spell_chapter5_return_to_capital);
|
||||
}
|
||||
|
||||
+186
-254
@@ -49,292 +49,228 @@ enum DeathKnightSpells
|
||||
SPELL_GHOUL_FRENZY = 62218,
|
||||
};
|
||||
|
||||
class npc_pet_dk_ebon_gargoyle : public CreatureScript
|
||||
struct npc_pet_dk_ebon_gargoyle : ScriptedAI
|
||||
{
|
||||
public:
|
||||
npc_pet_dk_ebon_gargoyle() : CreatureScript("npc_pet_dk_ebon_gargoyle") { }
|
||||
|
||||
struct npc_pet_dk_ebon_gargoyleAI : ScriptedAI
|
||||
npc_pet_dk_ebon_gargoyle(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
npc_pet_dk_ebon_gargoyleAI(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
_despawnTimer = 36000; // 30 secs + 4 fly out + 2 initial attack timer
|
||||
_despawning = false;
|
||||
_initialSelection = true;
|
||||
_targetGUID.Clear();
|
||||
}
|
||||
_despawnTimer = 36000; // 30 secs + 4 fly out + 2 initial attack timer
|
||||
_despawning = false;
|
||||
_initialSelection = true;
|
||||
_targetGUID.Clear();
|
||||
}
|
||||
|
||||
void MovementInform(uint32 type, uint32 point) override
|
||||
void MovementInform(uint32 type, uint32 point) override
|
||||
{
|
||||
if (type == POINT_MOTION_TYPE && point == 1)
|
||||
{
|
||||
if (type == POINT_MOTION_TYPE && point == 1)
|
||||
me->SetCanFly(false);
|
||||
me->SetDisableGravity(false);
|
||||
}
|
||||
}
|
||||
|
||||
void InitializeAI() override
|
||||
{
|
||||
ScriptedAI::InitializeAI();
|
||||
Unit* owner = me->GetOwner();
|
||||
if (!owner)
|
||||
return;
|
||||
|
||||
// Xinef: Night of the Dead avoidance
|
||||
if (Aura* aur = me->GetAura(SPELL_DK_NIGHT_OF_THE_DEAD))
|
||||
if (AuraEffect* aurEff = owner->GetAuraEffect(SPELL_AURA_ADD_FLAT_MODIFIER, SPELLFAMILY_DEATHKNIGHT, 2718, 0))
|
||||
if (aur->GetEffect(0))
|
||||
aur->GetEffect(0)->SetAmount(-aurEff->GetSpellInfo()->Effects[EFFECT_2].CalcValue());
|
||||
|
||||
me->SetCanFly(true);
|
||||
me->SetDisableGravity(true);
|
||||
|
||||
float tz = me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), true, MAX_FALL_DISTANCE);
|
||||
me->GetMotionMaster()->MoveCharge(me->GetPositionX(), me->GetPositionY(), tz, 7.0f, 1);
|
||||
me->AddUnitState(UNIT_STATE_NO_ENVIRONMENT_UPD);
|
||||
_selectionTimer = 2000;
|
||||
_initialCastTimer = 0;
|
||||
}
|
||||
|
||||
void MySelectNextTarget()
|
||||
{
|
||||
Unit* owner = me->GetOwner();
|
||||
if (owner && owner->IsPlayer() && (!me->GetVictim() || me->GetVictim()->IsImmunedToSpell(sSpellMgr->GetSpellInfo(51963)) || !me->IsValidAttackTarget(me->GetVictim()) || !owner->CanSeeOrDetect(me->GetVictim())))
|
||||
{
|
||||
Unit* selection = owner->ToPlayer()->GetSelectedUnit();
|
||||
if (selection && selection != me->GetVictim() && me->IsValidAttackTarget(selection))
|
||||
{
|
||||
me->SetCanFly(false);
|
||||
me->SetDisableGravity(false);
|
||||
me->GetMotionMaster()->Clear(false);
|
||||
SetGazeOn(selection);
|
||||
}
|
||||
|
||||
else if (!me->GetVictim() || !owner->CanSeeOrDetect(me->GetVictim()))
|
||||
{
|
||||
me->CombatStop(true);
|
||||
me->GetMotionMaster()->Clear(false);
|
||||
me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, 0.0f);
|
||||
RemoveTargetAura();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InitializeAI() override
|
||||
void AttackStart(Unit* who) override
|
||||
{
|
||||
RemoveTargetAura();
|
||||
_targetGUID = who->GetGUID();
|
||||
me->AddAura(SPELL_DK_SUMMON_GARGOYLE_1, who);
|
||||
ScriptedAI::AttackStart(who);
|
||||
}
|
||||
|
||||
void RemoveTargetAura()
|
||||
{
|
||||
if (Unit* target = ObjectAccessor::GetUnit(*me, _targetGUID))
|
||||
target->RemoveAura(SPELL_DK_SUMMON_GARGOYLE_1, me->GetGUID());
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
_selectionTimer = 0;
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
MySelectNextTarget();
|
||||
}
|
||||
|
||||
// Fly away when dismissed
|
||||
void FlyAway()
|
||||
{
|
||||
RemoveTargetAura();
|
||||
|
||||
// Stop Fighting
|
||||
me->CombatStop(true);
|
||||
me->ApplyModFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE, true);
|
||||
|
||||
// Sanctuary
|
||||
me->CastSpell(me, SPELL_DK_SANCTUARY, true);
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
|
||||
me->SetSpeed(MOVE_FLIGHT, 1.0f, true);
|
||||
me->SetSpeed(MOVE_RUN, 1.0f, true);
|
||||
float x = me->GetPositionX() + 20 * cos(me->GetOrientation());
|
||||
float y = me->GetPositionY() + 20 * std::sin(me->GetOrientation());
|
||||
float z = me->GetPositionZ() + 40;
|
||||
me->DisableSpline();
|
||||
me->GetMotionMaster()->Clear(false);
|
||||
|
||||
me->GetMotionMaster()->MoveCharge(x, y, z, 7.0f, 1);
|
||||
me->SetCanFly(true);
|
||||
me->SetDisableGravity(true);
|
||||
|
||||
_despawning = true;
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (_initialSelection)
|
||||
{
|
||||
ScriptedAI::InitializeAI();
|
||||
Unit* owner = me->GetOwner();
|
||||
if (!owner)
|
||||
_initialSelection = false;
|
||||
// Find victim of Summon Gargoyle spell
|
||||
std::list<Unit*> targets;
|
||||
Acore::AnyUnfriendlyUnitInObjectRangeCheck u_check(me, me, 50.0f);
|
||||
Acore::UnitListSearcher<Acore::AnyUnfriendlyUnitInObjectRangeCheck> searcher(me, targets, u_check);
|
||||
Cell::VisitAllObjects(me, searcher, 50.0f);
|
||||
for (auto const& target : targets)
|
||||
if (target->GetAura(SPELL_DK_SUMMON_GARGOYLE_1, me->GetOwnerGUID()))
|
||||
{
|
||||
target->RemoveAura(SPELL_DK_SUMMON_GARGOYLE_1, me->GetOwnerGUID());
|
||||
SetGazeOn(target);
|
||||
_targetGUID = target->GetGUID();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (_despawnTimer > 4000)
|
||||
{
|
||||
_despawnTimer -= diff;
|
||||
if (!UpdateVictimWithGaze())
|
||||
{
|
||||
MySelectNextTarget();
|
||||
return;
|
||||
|
||||
// Xinef: Night of the Dead avoidance
|
||||
if (Aura* aur = me->GetAura(SPELL_DK_NIGHT_OF_THE_DEAD))
|
||||
if (AuraEffect* aurEff = owner->GetAuraEffect(SPELL_AURA_ADD_FLAT_MODIFIER, SPELLFAMILY_DEATHKNIGHT, 2718, 0))
|
||||
{
|
||||
if (aur->GetEffect(0))
|
||||
{
|
||||
aur->GetEffect(0)->SetAmount(-aurEff->GetSpellInfo()->Effects[EFFECT_2].CalcValue());
|
||||
}
|
||||
}
|
||||
|
||||
me->SetCanFly(true);
|
||||
me->SetDisableGravity(true);
|
||||
|
||||
float tz = me->GetMapHeight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), true, MAX_FALL_DISTANCE);
|
||||
me->GetMotionMaster()->MoveCharge(me->GetPositionX(), me->GetPositionY(), tz, 7.0f, 1);
|
||||
me->AddUnitState(UNIT_STATE_NO_ENVIRONMENT_UPD);
|
||||
_selectionTimer = 2000;
|
||||
_initialCastTimer = 0;
|
||||
}
|
||||
|
||||
void MySelectNextTarget()
|
||||
{
|
||||
Unit* owner = me->GetOwner();
|
||||
if (owner && owner->IsPlayer() && (!me->GetVictim() || me->GetVictim()->IsImmunedToSpell(sSpellMgr->GetSpellInfo(51963)) || !me->IsValidAttackTarget(me->GetVictim()) || !owner->CanSeeOrDetect(me->GetVictim())))
|
||||
{
|
||||
Unit* selection = owner->ToPlayer()->GetSelectedUnit();
|
||||
if (selection && selection != me->GetVictim() && me->IsValidAttackTarget(selection))
|
||||
{
|
||||
me->GetMotionMaster()->Clear(false);
|
||||
SetGazeOn(selection);
|
||||
}
|
||||
|
||||
else if (!me->GetVictim() || !owner->CanSeeOrDetect(me->GetVictim()))
|
||||
{
|
||||
me->CombatStop(true);
|
||||
me->GetMotionMaster()->Clear(false);
|
||||
me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, 0.0f);
|
||||
RemoveTargetAura();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AttackStart(Unit* who) override
|
||||
{
|
||||
RemoveTargetAura();
|
||||
_targetGUID = who->GetGUID();
|
||||
me->AddAura(SPELL_DK_SUMMON_GARGOYLE_1, who);
|
||||
ScriptedAI::AttackStart(who);
|
||||
}
|
||||
|
||||
void RemoveTargetAura()
|
||||
{
|
||||
if (Unit* target = ObjectAccessor::GetUnit(*me, _targetGUID))
|
||||
target->RemoveAura(SPELL_DK_SUMMON_GARGOYLE_1, me->GetGUID());
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
_selectionTimer = 0;
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
MySelectNextTarget();
|
||||
}
|
||||
|
||||
// Fly away when dismissed
|
||||
void FlyAway()
|
||||
{
|
||||
RemoveTargetAura();
|
||||
|
||||
// Stop Fighting
|
||||
me->CombatStop(true);
|
||||
me->ApplyModFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE, true);
|
||||
|
||||
// Sanctuary
|
||||
me->CastSpell(me, SPELL_DK_SANCTUARY, true);
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
|
||||
me->SetSpeed(MOVE_FLIGHT, 1.0f, true);
|
||||
me->SetSpeed(MOVE_RUN, 1.0f, true);
|
||||
float x = me->GetPositionX() + 20 * cos(me->GetOrientation());
|
||||
float y = me->GetPositionY() + 20 * std::sin(me->GetOrientation());
|
||||
float z = me->GetPositionZ() + 40;
|
||||
me->DisableSpline();
|
||||
me->GetMotionMaster()->Clear(false);
|
||||
|
||||
me->GetMotionMaster()->MoveCharge(x, y, z, 7.0f, 1);
|
||||
me->SetCanFly(true);
|
||||
me->SetDisableGravity(true);
|
||||
|
||||
_despawning = true;
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (_initialSelection)
|
||||
_initialCastTimer += diff;
|
||||
_selectionTimer += diff;
|
||||
if (_selectionTimer >= 1000)
|
||||
{
|
||||
_initialSelection = false;
|
||||
// Find victim of Summon Gargoyle spell
|
||||
std::list<Unit*> targets;
|
||||
Acore::AnyUnfriendlyUnitInObjectRangeCheck u_check(me, me, 50.0f);
|
||||
Acore::UnitListSearcher<Acore::AnyUnfriendlyUnitInObjectRangeCheck> searcher(me, targets, u_check);
|
||||
Cell::VisitAllObjects(me, searcher, 50.0f);
|
||||
for (std::list<Unit*>::const_iterator iter = targets.begin(); iter != targets.end(); ++iter)
|
||||
if ((*iter)->GetAura(SPELL_DK_SUMMON_GARGOYLE_1, me->GetOwnerGUID()))
|
||||
{
|
||||
(*iter)->RemoveAura(SPELL_DK_SUMMON_GARGOYLE_1, me->GetOwnerGUID());
|
||||
SetGazeOn(*iter);
|
||||
_targetGUID = (*iter)->GetGUID();
|
||||
break;
|
||||
}
|
||||
MySelectNextTarget();
|
||||
_selectionTimer = 0;
|
||||
}
|
||||
if (_despawnTimer > 4000)
|
||||
{
|
||||
if (_initialCastTimer >= 2000 && !me->HasUnitState(UNIT_STATE_CASTING | UNIT_STATE_LOST_CONTROL) && me->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_CONTROLLED) == NULL_MOTION_TYPE)
|
||||
me->CastSpell(me->GetVictim(), 51963, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!_despawning)
|
||||
FlyAway();
|
||||
|
||||
if (_despawnTimer > diff)
|
||||
_despawnTimer -= diff;
|
||||
if (!UpdateVictimWithGaze())
|
||||
{
|
||||
MySelectNextTarget();
|
||||
return;
|
||||
}
|
||||
|
||||
_initialCastTimer += diff;
|
||||
_selectionTimer += diff;
|
||||
if (_selectionTimer >= 1000)
|
||||
{
|
||||
MySelectNextTarget();
|
||||
_selectionTimer = 0;
|
||||
}
|
||||
if (_initialCastTimer >= 2000 && !me->HasUnitState(UNIT_STATE_CASTING | UNIT_STATE_LOST_CONTROL) && me->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_CONTROLLED) == NULL_MOTION_TYPE)
|
||||
me->CastSpell(me->GetVictim(), 51963, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!_despawning)
|
||||
FlyAway();
|
||||
|
||||
if (_despawnTimer > diff)
|
||||
_despawnTimer -= diff;
|
||||
else
|
||||
me->DespawnOrUnsummon();
|
||||
}
|
||||
me->DespawnOrUnsummon();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
ObjectGuid _targetGUID;
|
||||
uint32 _despawnTimer;
|
||||
uint32 _selectionTimer;
|
||||
uint32 _initialCastTimer;
|
||||
bool _despawning;
|
||||
bool _initialSelection;
|
||||
};
|
||||
private:
|
||||
ObjectGuid _targetGUID;
|
||||
uint32 _despawnTimer;
|
||||
uint32 _selectionTimer;
|
||||
uint32 _initialCastTimer;
|
||||
bool _despawning;
|
||||
bool _initialSelection;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
struct npc_pet_dk_ghoul : public CombatAI
|
||||
{
|
||||
npc_pet_dk_ghoul(Creature* c) : CombatAI(c) { }
|
||||
|
||||
void JustDied(Unit* /*who*/) override
|
||||
{
|
||||
return new npc_pet_dk_ebon_gargoyleAI(creature);
|
||||
if (me->IsGuardian() || me->IsSummon())
|
||||
me->ToTempSummon()->UnSummon();
|
||||
}
|
||||
};
|
||||
|
||||
class npc_pet_dk_ghoul : public CreatureScript
|
||||
struct npc_pet_dk_risen_ally : public PossessedAI
|
||||
{
|
||||
public:
|
||||
npc_pet_dk_ghoul() : CreatureScript("npc_pet_dk_ghoul") { }
|
||||
npc_pet_dk_risen_ally(Creature* c) : PossessedAI(c) { }
|
||||
|
||||
struct npc_pet_dk_ghoulAI : public CombatAI
|
||||
void OnCharmed(bool apply) override
|
||||
{
|
||||
npc_pet_dk_ghoulAI(Creature* c) : CombatAI(c) { }
|
||||
|
||||
void JustDied(Unit* /*who*/) override
|
||||
{
|
||||
if (me->IsGuardian() || me->IsSummon())
|
||||
me->ToTempSummon()->UnSummon();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* pCreature) const override
|
||||
{
|
||||
return new npc_pet_dk_ghoulAI (pCreature);
|
||||
}
|
||||
};
|
||||
|
||||
class npc_pet_dk_risen_ally : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_pet_dk_risen_ally() : CreatureScript("npc_pet_dk_risen_ally") { }
|
||||
|
||||
struct npc_pet_dk_risen_allyAI : public PossessedAI
|
||||
{
|
||||
npc_pet_dk_risen_allyAI(Creature* c) : PossessedAI(c) { }
|
||||
|
||||
void OnCharmed(bool apply) override
|
||||
{
|
||||
if (!apply)
|
||||
{
|
||||
if (Unit* owner = me->GetCharmerOrOwner())
|
||||
if (!apply)
|
||||
if (Unit* owner = me->GetCharmerOrOwner())
|
||||
if (Player* player = owner->ToPlayer())
|
||||
{
|
||||
if (Player* player = owner->ToPlayer())
|
||||
{
|
||||
player->RemoveAurasDueToSpell(SPELL_DK_RAISE_ALLY); // Remove Raise Ally aura
|
||||
player->RemoveAurasDueToSpell(SPELL_GHOUL_FRENZY); // Remove Frenzy aura
|
||||
//player->ClearResurrectRequestData();
|
||||
}
|
||||
player->RemoveAurasDueToSpell(SPELL_DK_RAISE_ALLY); // Remove Raise Ally aura
|
||||
player->RemoveAurasDueToSpell(SPELL_GHOUL_FRENZY); // Remove Frenzy aura
|
||||
//player->ClearResurrectRequestData();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* pCreature) const override
|
||||
{
|
||||
return new npc_pet_dk_risen_allyAI (pCreature);
|
||||
}
|
||||
};
|
||||
|
||||
class npc_pet_dk_army_of_the_dead : public CreatureScript
|
||||
struct npc_pet_dk_army_of_the_dead : public CombatAI
|
||||
{
|
||||
public:
|
||||
npc_pet_dk_army_of_the_dead() : CreatureScript("npc_pet_dk_army_of_the_dead") { }
|
||||
npc_pet_dk_army_of_the_dead(Creature* creature) : CombatAI(creature) { }
|
||||
|
||||
struct npc_pet_dk_army_of_the_deadAI : public CombatAI
|
||||
void InitializeAI() override
|
||||
{
|
||||
npc_pet_dk_army_of_the_deadAI(Creature* creature) : CombatAI(creature) { }
|
||||
|
||||
void InitializeAI() override
|
||||
{
|
||||
CombatAI::InitializeAI();
|
||||
((Minion*)me)->SetFollowAngle(rand_norm() * 2 * M_PI);
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return new npc_pet_dk_army_of_the_deadAI (creature);
|
||||
CombatAI::InitializeAI();
|
||||
((Minion*)me)->SetFollowAngle(rand_norm() * 2 * M_PI);
|
||||
}
|
||||
};
|
||||
|
||||
class npc_pet_dk_dancing_rune_weapon : public CreatureScript
|
||||
struct npc_pet_dk_dancing_rune_weapon : public NullCreatureAI
|
||||
{
|
||||
public:
|
||||
npc_pet_dk_dancing_rune_weapon() : CreatureScript("npc_pet_dk_dancing_rune_weapon") { }
|
||||
npc_pet_dk_dancing_rune_weapon(Creature* creature) : NullCreatureAI(creature) { }
|
||||
|
||||
struct npc_pet_dk_dancing_rune_weaponAI : public NullCreatureAI
|
||||
void InitializeAI() override
|
||||
{
|
||||
npc_pet_dk_dancing_rune_weaponAI(Creature* creature) : NullCreatureAI(creature) { }
|
||||
me->AddAura(SPELL_HUNTER_PET_SCALING_04, me);
|
||||
if (Unit* owner = me->GetOwner())
|
||||
me->GetMotionMaster()->MoveFollow(owner, 0.01f, me->GetFollowAngle(), MOTION_SLOT_CONTROLLED);
|
||||
|
||||
void InitializeAI() override
|
||||
{
|
||||
// Xinef: Hit / Expertise scaling
|
||||
me->AddAura(61017, me);
|
||||
if (Unit* owner = me->GetOwner())
|
||||
me->GetMotionMaster()->MoveFollow(owner, 0.01f, me->GetFollowAngle(), MOTION_SLOT_CONTROLLED);
|
||||
|
||||
NullCreatureAI::InitializeAI();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return new npc_pet_dk_dancing_rune_weaponAI (creature);
|
||||
NullCreatureAI::InitializeAI();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -346,12 +282,8 @@ class spell_pet_dk_gargoyle_strike : public SpellScript
|
||||
{
|
||||
int32 damage = 60;
|
||||
if (Unit* caster = GetCaster())
|
||||
{
|
||||
if (caster->GetLevel() >= 60)
|
||||
{
|
||||
damage += (caster->GetLevel() - 60) * 4;
|
||||
}
|
||||
}
|
||||
|
||||
SetEffectValue(damage);
|
||||
}
|
||||
@@ -364,10 +296,10 @@ class spell_pet_dk_gargoyle_strike : public SpellScript
|
||||
|
||||
void AddSC_deathknight_pet_scripts()
|
||||
{
|
||||
new npc_pet_dk_ebon_gargoyle();
|
||||
new npc_pet_dk_ghoul();
|
||||
new npc_pet_dk_risen_ally();
|
||||
new npc_pet_dk_army_of_the_dead();
|
||||
new npc_pet_dk_dancing_rune_weapon();
|
||||
RegisterCreatureAI(npc_pet_dk_ebon_gargoyle);
|
||||
RegisterCreatureAI(npc_pet_dk_ghoul);
|
||||
RegisterCreatureAI(npc_pet_dk_risen_ally);
|
||||
RegisterCreatureAI(npc_pet_dk_army_of_the_dead);
|
||||
RegisterCreatureAI(npc_pet_dk_dancing_rune_weapon);
|
||||
RegisterSpellScript(spell_pet_dk_gargoyle_strike);
|
||||
}
|
||||
|
||||
@@ -530,11 +530,21 @@ class spell_dk_bone_shield : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_dk_bone_shield);
|
||||
|
||||
uint32 lastChargeUsedTime = 0;
|
||||
|
||||
void HandleProc(ProcEventInfo& eventInfo)
|
||||
{
|
||||
PreventDefaultAction();
|
||||
uint32 currentTime = getMSTime();
|
||||
// Checks for 2 seconds between uses of bone shield charges
|
||||
if ((currentTime - lastChargeUsedTime) < 2000)
|
||||
return;
|
||||
|
||||
if (!eventInfo.GetSpellInfo() || !eventInfo.GetSpellInfo()->IsTargetingArea())
|
||||
{
|
||||
DropCharge();
|
||||
lastChargeUsedTime = currentTime;
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
|
||||
@@ -5431,6 +5431,22 @@ private:
|
||||
uint32 _spellId;
|
||||
};
|
||||
|
||||
class spell_gen_cooldown_all : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_gen_cooldown_all);
|
||||
|
||||
void HandleScript(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
if (Player* player = GetHitPlayer())
|
||||
player->RemoveAllSpellCooldown();
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_gen_cooldown_all::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_generic_spell_scripts()
|
||||
{
|
||||
RegisterSpellScript(spell_silithyst);
|
||||
@@ -5593,4 +5609,5 @@ void AddSC_generic_spell_scripts()
|
||||
RegisterSpellScript(spell_gen_proc_on_victim);
|
||||
RegisterSpellScriptWithArgs(spell_gen_translocate, "spell_gen_translocate_down", SPELL_TRANSLOCATION_DOWN);
|
||||
RegisterSpellScriptWithArgs(spell_gen_translocate, "spell_gen_translocate_up", SPELL_TRANSLOCATION_UP);
|
||||
RegisterSpellScript(spell_gen_cooldown_all);
|
||||
}
|
||||
|
||||
@@ -887,8 +887,9 @@ class spell_hun_misdirection : public AuraScript
|
||||
bool CheckProc(ProcEventInfo& eventInfo)
|
||||
{
|
||||
// Do not trigger from Mend Pet
|
||||
if (eventInfo.GetProcSpell() && (eventInfo.GetProcSpell()->GetSpellInfo()->SpellFamilyFlags[0] & 0x800000))
|
||||
if ((eventInfo.GetProcSpell() && (eventInfo.GetProcSpell()->GetSpellInfo()->SpellFamilyFlags[0] & 0x800000)) || (eventInfo.GetHealInfo() && (eventInfo.GetHealInfo()->GetSpellInfo()->SpellFamilyFlags[0] & 0x800000)))
|
||||
return false;
|
||||
|
||||
return GetTarget()->GetRedirectThreatTarget();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user