Merge branch 'master' into Playerbot

This commit is contained in:
Yunfan Li
2025-06-28 10:46:23 +08:00
63 changed files with 998 additions and 449 deletions
+6 -1
View File
@@ -271,10 +271,15 @@ public:
///- %Parse the command line arguments
char* accountName = strtok((char*)args, " ");
char* password = strtok(nullptr, " ");
char* email = strtok(nullptr, " ");
if (!accountName || !password)
return false;
AccountOpResult result = AccountMgr::CreateAccount(std::string(accountName), std::string(password));
// if email is not specified, use empty string
std::string emailStr = email ? email : "";
AccountOpResult result = AccountMgr::CreateAccount(std::string(accountName), std::string(password), emailStr);
switch (result)
{
case AOR_OK:
+76 -6
View File
@@ -86,16 +86,35 @@ public:
return true;
}
static bool HandleGoCreatureCIdCommand(ChatHandler* handler, Variant<Hyperlink<creature_entry>, uint32> cId)
static bool HandleGoCreatureCIdCommand(ChatHandler* handler, Variant<Hyperlink<creature_entry>, uint32> cId, Optional<uint32> _pos)
{
CreatureData const* spawnpoint = GetCreatureData(handler, *cId);
uint32 pos = 1;
if (_pos)
{
pos = *_pos;
if (pos < 1)
{
handler->SendErrorMessage(LANG_COMMAND_FACTION_INVPARAM, pos);
return false;
}
}
if (!spawnpoint)
std::vector<CreatureData const*> spawnpoints = GetCreatureDataList(*cId);
if (spawnpoints.empty())
{
handler->SendErrorMessage(LANG_COMMAND_GOCREATNOTFOUND);
return false;
}
if (spawnpoints.size() < pos)
{
handler->SendErrorMessage(LANG_COMMAND_GONOTENOUGHSPAWNS, pos, spawnpoints.size());
return false;
}
CreatureData const* spawnpoint = spawnpoints[--pos];
return DoTeleport(handler, { spawnpoint->posX, spawnpoint->posY, spawnpoint->posZ }, spawnpoint->mapid);
}
@@ -153,16 +172,35 @@ public:
return DoTeleport(handler, { spawnpoint->posX, spawnpoint->posY, spawnpoint->posZ }, spawnpoint->mapid);
}
static bool HandleGoGameObjectGOIdCommand(ChatHandler* handler, uint32 goId)
static bool HandleGoGameObjectGOIdCommand(ChatHandler* handler, uint32 goId, Optional<uint32> _pos)
{
GameObjectData const* spawnpoint = GetGameObjectData(handler, goId);
uint32 pos = 1;
if (_pos)
{
pos = *_pos;
if (pos < 1)
{
handler->SendErrorMessage(LANG_COMMAND_FACTION_INVPARAM, pos);
return false;
}
}
if (!spawnpoint)
std::vector<GameObjectData const*> spawnpoints = GetGameObjectDataList(goId);
if (spawnpoints.empty())
{
handler->SendErrorMessage(LANG_COMMAND_GOOBJNOTFOUND);
return false;
}
if (spawnpoints.size() < pos)
{
handler->SendErrorMessage(LANG_COMMAND_GONOTENOUGHSPAWNS, pos, spawnpoints.size());
return false;
}
GameObjectData const* spawnpoint = spawnpoints[--pos];
return DoTeleport(handler, { spawnpoint->posX, spawnpoint->posY, spawnpoint->posZ }, spawnpoint->mapid);
}
@@ -509,6 +547,22 @@ public:
return spawnpoint;
}
static std::vector<CreatureData const*> GetCreatureDataList(uint32 entry)
{
std::vector<CreatureData const*> spawnpoints;
for (auto const& pair : sObjectMgr->GetAllCreatureData())
{
if (pair.second.id1 != entry)
{
continue;
}
spawnpoints.emplace_back(&pair.second);
}
return spawnpoints;
}
static GameObjectData const* GetGameObjectData(ChatHandler* handler, uint32 entry)
{
GameObjectData const* spawnpoint = nullptr;
@@ -532,6 +586,22 @@ public:
return spawnpoint;
}
static std::vector<GameObjectData const*> GetGameObjectDataList(uint32 entry)
{
std::vector<GameObjectData const*> spawnpoints;
for (auto const& pair : sObjectMgr->GetAllGOData())
{
if (pair.second.id != entry)
{
continue;
}
spawnpoints.emplace_back(&pair.second);
}
return spawnpoints;
}
};
void AddSC_go_commandscript()
@@ -74,7 +74,7 @@ struct boss_servant_quarters : public BossAI
context.Repeat(12s, 18s);
}).Schedule(10s, [this](TaskContext context)
{
if (Unit* target = SelectTarget(SelectTargetMethod::MinDistance, 0, FarthestTargetSelector(me, 40.0f, false, true)))
if (Unit* target = SelectTarget(SelectTargetMethod::MinDistance, 0, RangeSelector(me, 40.0f, false, true)))
{
me->CastSpell(target, SPELL_DIVE);
}
@@ -18,6 +18,7 @@
#include "CombatAI.h"
#include "CreatureScript.h"
#include "CreatureTextMgr.h"
#include "ScriptedGossip.h"
#include "Player.h"
#include "ScriptedCreature.h"
#include "ScriptedEscortAI.h"
@@ -185,16 +186,23 @@ public:
enum Koltira
{
SAY_BREAKOUT1 = 0,
SAY_BREAKOUT2 = 1,
SAY_BREAKOUT3 = 2,
SAY_BREAKOUT4 = 3,
SAY_BREAKOUT5 = 4,
SAY_BREAKOUT6 = 5,
SAY_BREAKOUT7 = 6,
SAY_BREAKOUT8 = 7,
SAY_BREAKOUT9 = 8,
SAY_BREAKOUT10 = 9,
SAY_BREAKOUT0 = 0,
SAY_BREAKOUT1 = 1,
SAY_BREAKOUT2 = 2,
SAY_BREAKOUT3 = 3,
SAY_BREAKOUT4 = 4,
SAY_BREAKOUT5 = 5,
SAY_BREAKOUT6 = 6,
SAY_BREAKOUT7 = 7,
SAY_BREAKOUT8 = 8,
SAY_BREAKOUT9 = 9,
SAY_BREAKOUT10 = 10,
EMOTE_KOLTIRA_COLLAPSES = 11,
SAY_VALROTH_WAVE3 = 0,
SAY_VALROTH_AGGRO = 1,
SAY_VALROTH_WAVE1 = 4,
SAY_VALROTH_WAVE2 = 5,
SPELL_KOLTIRA_TRANSFORM = 52899,
SPELL_ANTI_MAGIC_ZONE = 52894,
@@ -206,7 +214,14 @@ enum Koltira
//not sure about this id
//NPC_DEATH_KNIGHT_MOUNT = 29201,
MODEL_DEATH_KNIGHT_MOUNT = 25278
MODEL_DEATH_KNIGHT_MOUNT = 25278,
POINT_STAND_UP = 0,
POINT_BOX = 1,
POINT_ANTI_MAGIC_ZONE = 2,
POINT_MOUNT = 0,
POINT_DESPAWN = 1
};
class npc_koltira_deathweaver : public CreatureScript
@@ -214,205 +229,203 @@ class npc_koltira_deathweaver : public CreatureScript
public:
npc_koltira_deathweaver() : CreatureScript("npc_koltira_deathweaver") { }
bool OnQuestAccept(Player* player, Creature* creature, const Quest* quest) override
{
if (quest->GetQuestId() == QUEST_BREAKOUT)
{
creature->SetStandState(UNIT_STAND_STATE_STAND);
creature->setActive(true);
if (npc_escortAI* pEscortAI = CAST_AI(npc_koltira_deathweaver::npc_koltira_deathweaverAI, creature->AI()))
pEscortAI->Start(false, false, player->GetGUID());
}
return true;
}
CreatureAI* GetAI(Creature* creature) const override
{
return new npc_koltira_deathweaverAI(creature);
}
struct npc_koltira_deathweaverAI : public npc_escortAI
struct npc_koltira_deathweaverAI : public ScriptedAI
{
npc_koltira_deathweaverAI(Creature* creature) : npc_escortAI(creature), summons(me)
{
me->SetReactState(REACT_DEFENSIVE);
}
uint32 m_uiWave;
uint32 m_uiWave_Timer;
ObjectGuid m_uiValrothGUID;
SummonList summons;
npc_koltira_deathweaverAI(Creature* creature) : ScriptedAI(creature) { }
void Reset() override
{
if (!HasEscortState(STATE_ESCORT_ESCORTING))
{
m_uiWave = 0;
m_uiWave_Timer = 3000;
m_uiValrothGUID.Clear();
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->LoadEquipment(0, true);
me->RemoveAllAuras();
summons.DespawnAll();
}
scheduler.CancelAll();
me->m_Events.KillAllEvents(false);
me->SetUnitFlag(UNIT_FLAG_IMMUNE_TO_NPC);
me->setActive(false);
}
void EnterEvadeMode(EvadeReason /*why*/) override
void StartEvent()
{
me->GetThreatMgr().ClearAllThreat();
me->CombatStop(false);
me->SetLootRecipient(nullptr);
if (HasEscortState(STATE_ESCORT_ESCORTING))
{
AddEscortState(STATE_ESCORT_RETURNING);
ReturnToLastPoint();
LOG_DEBUG("scripts.ai", "EscortAI has left combat and is now returning to last point");
}
else
{
me->GetMotionMaster()->MoveTargetedHome();
me->SetImmuneToNPC(true);
Reset();
}
}
void AttackStart(Unit* who) override
{
if (HasEscortState(STATE_ESCORT_PAUSED))
if (!me->HasNpcFlag(UNIT_NPC_FLAG_GOSSIP)) // Already in progress
return;
npc_escortAI::AttackStart(who);
me->SetStandState(UNIT_STAND_STATE_SIT);
me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP);
me->setActive(true);
Talk(SAY_BREAKOUT0);
me->m_Events.AddEventAtOffset([&] {
me->GetMotionMaster()->MovePath(me->GetEntry() * 10, false);
}, 5s);
}
void WaypointReached(uint32 waypointId) override
void sQuestAccept(Player* /*player*/, Quest const* quest) override
{
switch (waypointId)
if (quest->GetQuestId() == QUEST_BREAKOUT)
StartEvent();
}
void sGossipSelect(Player* player, uint32 /*menuId*/, uint32 /*gossipListId*/) override
{
if (player->GetQuestStatus(QUEST_BREAKOUT) == QUEST_STATUS_INCOMPLETE)
{
case 0:
Talk(SAY_BREAKOUT1);
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
break;
case 1:
me->SetStandState(UNIT_STAND_STATE_KNEEL);
break;
case 2:
me->SetStandState(UNIT_STAND_STATE_STAND);
//me->UpdateEntry(NPC_KOLTIRA_ALT); //unclear if we must update or not
DoCast(me, SPELL_KOLTIRA_TRANSFORM);
me->LoadEquipment();
break;
case 3:
SetEscortPaused(true);
me->SetStandState(UNIT_STAND_STATE_KNEEL);
Talk(SAY_BREAKOUT2);
DoCast(me, SPELL_ANTI_MAGIC_ZONE); // cast again that makes bubble up
break;
case 4:
me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_ALL, false);
SetRun(true);
break;
case 9:
me->Mount(MODEL_DEATH_KNIGHT_MOUNT);
break;
case 10:
me->Dismount();
break;
CloseGossipMenuFor(player);
StartEvent();
}
}
void JustSummoned(Creature* summoned) override
void MovementInform(uint32 type, uint32 id) override
{
if (Player* player = GetPlayerForEscort())
summoned->AI()->AttackStart(player);
if (type != WAYPOINT_MOTION_TYPE)
return;
if (summoned->GetEntry() == NPC_HIGH_INQUISITOR_VALROTH)
m_uiValrothGUID = summoned->GetGUID();
summoned->AddThreat(me, 0.0f);
summoned->SetImmuneToPC(false);
summons.Summon(summoned);
}
void SummonAcolyte(uint32 uiAmount)
{
for (uint32 i = 0; i < uiAmount; ++i)
me->SummonCreature(NPC_CRIMSON_ACOLYTE, 1642.329f, -6045.818f, 127.583f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000);
}
void UpdateAI(uint32 uiDiff) override
{
npc_escortAI::UpdateAI(uiDiff);
if (HasEscortState(STATE_ESCORT_PAUSED))
if (!me->HasUnitFlag(UNIT_FLAG_IMMUNE_TO_NPC))
{
if (m_uiWave_Timer <= uiDiff)
if (id == POINT_MOUNT)
me->Mount(MODEL_DEATH_KNIGHT_MOUNT);
else if (id == POINT_DESPAWN)
{
switch (m_uiWave)
me->Dismount();
me->DespawnOrUnsummon();
}
return;
}
switch (id)
{
case POINT_STAND_UP:
Talk(SAY_BREAKOUT1);
break;
case POINT_BOX:
me->SetStandState(UNIT_STAND_STATE_KNEEL);
scheduler.Schedule(5s, [this](TaskContext context)
{
switch (context.GetRepeatCounter())
{
case 0:
Talk(SAY_BREAKOUT3);
SummonAcolyte(3);
m_uiWave_Timer = 20000;
// Shouldn't actually be spawned at this point, but no way to send his yells otherwise?
if (Creature* valroth = me->SummonCreature(NPC_HIGH_INQUISITOR_VALROTH, 1640.8596f, -6030.834f, 134.82211f, 4.606426715850830078f, TEMPSUMMON_MANUAL_DESPAWN))
{
_valrothGUID = valroth->GetGUID();
valroth->AI()->Talk(SAY_VALROTH_WAVE1);
valroth->SetReactState(REACT_PASSIVE);
}
if (Creature* acolyte = me->SummonCreature(NPC_CRIMSON_ACOLYTE, 1640.6724f, -6032.0527f, 134.82213f, 4.654973506927490234f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000))
acolyte->GetMotionMaster()->MovePath(NPC_CRIMSON_ACOLYTE * 10, false);
if (Creature* acolyte = me->SummonCreature(NPC_CRIMSON_ACOLYTE, 1641.0055f, -6031.893f, 134.82211f, 0.401425719261169433f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000))
acolyte->GetMotionMaster()->MovePath((NPC_CRIMSON_ACOLYTE + 1) * 10, false);
if (Creature* acolyte = me->SummonCreature(NPC_CRIMSON_ACOLYTE, 1639.7053f, -6031.7373f, 134.82213f, 2.443460941314697265f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000))
acolyte->GetMotionMaster()->MovePath((NPC_CRIMSON_ACOLYTE + 2) * 10, false);
break;
case 1:
Talk(SAY_BREAKOUT4);
SummonAcolyte(3);
m_uiWave_Timer = 20000;
if (Creature* valroth = ObjectAccessor::GetCreature(*me, _valrothGUID))
valroth->AI()->Talk(SAY_VALROTH_WAVE2);
if (Creature* acolyte = me->SummonCreature(NPC_CRIMSON_ACOLYTE, 1640.7958f, -6030.307f, 134.82211f, 4.65355682373046875f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000))
acolyte->GetMotionMaster()->MovePath((NPC_CRIMSON_ACOLYTE + 3) * 10, false);
if (Creature* acolyte = me->SummonCreature(NPC_CRIMSON_ACOLYTE, 1641.7305f, -6030.751f, 134.82211f, 6.143558979034423828f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000))
acolyte->GetMotionMaster()->MovePath((NPC_CRIMSON_ACOLYTE + 4) * 10, false);
if (Creature* acolyte = me->SummonCreature(NPC_CRIMSON_ACOLYTE, 1639.4657f, -6030.404f, 134.82211f, 4.502949237823486328f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000))
acolyte->GetMotionMaster()->MovePath((NPC_CRIMSON_ACOLYTE + 5) * 10, false);
break;
case 2:
Talk(SAY_BREAKOUT5);
SummonAcolyte(4);
m_uiWave_Timer = 20000;
if (Creature* valroth = ObjectAccessor::GetCreature(*me, _valrothGUID))
valroth->AI()->Talk(SAY_VALROTH_WAVE3);
if (Creature* acolyte = me->SummonCreature(NPC_CRIMSON_ACOLYTE, 1641.3405f, -6031.436f, 134.82211f, 4.612849712371826171f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000))
acolyte->GetMotionMaster()->MovePath((NPC_CRIMSON_ACOLYTE + 6) * 10, false);
if (Creature* acolyte = me->SummonCreature(NPC_CRIMSON_ACOLYTE, 1642.0404f, -6030.3843f, 134.82211f, 1.378810048103332519f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000))
acolyte->GetMotionMaster()->MovePath((NPC_CRIMSON_ACOLYTE + 7) * 10, false);
if (Creature* acolyte = me->SummonCreature(NPC_CRIMSON_ACOLYTE, 1640.1162f, -6029.7817f, 134.82211f, 5.707226753234863281f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000))
acolyte->GetMotionMaster()->MovePath((NPC_CRIMSON_ACOLYTE + 8) * 10, false);
if (Creature* acolyte = me->SummonCreature(NPC_CRIMSON_ACOLYTE, 1640.9948f, -6029.8027f, 134.82211f, 1.605702877044677734f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000))
acolyte->GetMotionMaster()->MovePath((NPC_CRIMSON_ACOLYTE + 9) * 10, false);
break;
case 3:
Talk(SAY_BREAKOUT6);
me->SummonCreature(NPC_HIGH_INQUISITOR_VALROTH, 1642.329f, -6045.818f, 127.583f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 1000);
m_uiWave_Timer = 1000;
break;
case 4:
me->m_Events.AddEventAtOffset([this]
{
Creature* temp = ObjectAccessor::GetCreature(*me, m_uiValrothGUID);
Talk(EMOTE_KOLTIRA_COLLAPSES, me);
me->KillSelf();
if (!temp || !temp->IsAlive())
{
Talk(SAY_BREAKOUT8);
m_uiWave_Timer = 5000;
}
else
{
// xinef: despawn check
Player* player = GetPlayerForEscort();
if (!player || me->GetDistance(player) > 60.0f)
{
me->DespawnOrUnsummon();
return;
}
if (Creature* valroth = ObjectAccessor::GetCreature(*me, _valrothGUID))
valroth->DespawnOrUnsummon();
}, 2min);
m_uiWave_Timer = 2500;
return; //return, we don't want m_uiWave to increment now
}
break;
if (Creature* valroth = ObjectAccessor::GetCreature(*me, _valrothGUID))
{
valroth->AI()->Talk(SAY_VALROTH_AGGRO);
valroth->SetReactState(REACT_AGGRESSIVE);
valroth->GetMotionMaster()->MovePath(NPC_HIGH_INQUISITOR_VALROTH * 10, false);
}
case 5:
Talk(SAY_BREAKOUT9);
me->RemoveAurasDueToSpell(SPELL_ANTI_MAGIC_ZONE);
// i do not know why the armor will also be removed
m_uiWave_Timer = 2500;
return;
default:
break;
case 6:
Talk(SAY_BREAKOUT10);
SetEscortPaused(false);
break;
}
}
++m_uiWave;
}
else
m_uiWave_Timer -= uiDiff;
context.Repeat(20s);
});
scheduler.Schedule(3s, [this](TaskContext)
{
DoCastSelf(SPELL_KOLTIRA_TRANSFORM);
me->LoadEquipment();
});
break;
case POINT_ANTI_MAGIC_ZONE:
me->SetStandState(UNIT_STAND_STATE_KNEEL);
Talk(SAY_BREAKOUT2);
DoCastSelf(SPELL_ANTI_MAGIC_ZONE);
break;
}
}
void SummonedCreatureDies(Creature* summon, Unit*) override
{
if (summon->GetEntry() == NPC_HIGH_INQUISITOR_VALROTH)
{
me->m_Events.KillAllEvents(false);
me->RemoveAurasDueToSpell(SPELL_ANTI_MAGIC_ZONE);
me->SetStandState(UNIT_STAND_STATE_STAND);
Talk(SAY_BREAKOUT8, 3s);
Talk(SAY_BREAKOUT9, 8s);
scheduler.Schedule(11s, [this](TaskContext)
{
Talk(SAY_BREAKOUT10);
SetInvincibility(true);
me->SetReactState(REACT_PASSIVE);
me->RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_NPC);
me->GetMotionMaster()->MovePath((me->GetEntry() + 1) * 10, false);
});
}
}
void UpdateAI(uint32 diff) override
{
scheduler.Update(diff);
}
private:
ObjectGuid _valrothGUID;
};
};
@@ -504,98 +517,6 @@ public:
};
};
//Koltira & Valroth- Breakout
enum valroth
{
//SAY_VALROTH1 = 0, Unused
SAY_VALROTH_AGGRO = 1,
SAY_VALROTH_RAND = 2,
SAY_VALROTH_DEATH = 3,
SPELL_RENEW = 38210,
SPELL_INQUISITOR_PENANCE = 52922,
SPELL_VALROTH_SMITE = 52926,
SPELL_SUMMON_VALROTH_REMAINS = 52929
};
class npc_high_inquisitor_valroth : public CreatureScript
{
public:
npc_high_inquisitor_valroth() : CreatureScript("npc_high_inquisitor_valroth") { }
CreatureAI* GetAI(Creature* creature) const override
{
return new npc_high_inquisitor_valrothAI(creature);
}
struct npc_high_inquisitor_valrothAI : public ScriptedAI
{
npc_high_inquisitor_valrothAI(Creature* creature) : ScriptedAI(creature) { }
uint32 uiRenew_timer;
uint32 uiInquisitor_Penance_timer;
uint32 uiValroth_Smite_timer;
void Reset() override
{
uiRenew_timer = 1000;
uiInquisitor_Penance_timer = 2000;
uiValroth_Smite_timer = 1000;
}
void JustEngagedWith(Unit* who) override
{
Talk(SAY_VALROTH_AGGRO);
DoCast(who, SPELL_VALROTH_SMITE);
}
void UpdateAI(uint32 diff) override
{
if (uiRenew_timer <= diff)
{
Shout();
DoCast(me, SPELL_RENEW);
uiRenew_timer = urand(1000, 6000);
}
else uiRenew_timer -= diff;
if (uiInquisitor_Penance_timer <= diff)
{
Shout();
DoCastVictim(SPELL_INQUISITOR_PENANCE);
uiInquisitor_Penance_timer = urand(2000, 7000);
}
else uiInquisitor_Penance_timer -= diff;
if (uiValroth_Smite_timer <= diff)
{
Shout();
DoCastVictim(SPELL_VALROTH_SMITE);
uiValroth_Smite_timer = urand(1000, 6000);
}
else uiValroth_Smite_timer -= diff;
DoMeleeAttackIfReady();
}
void Shout()
{
if (rand() % 100 < 15)
Talk(SAY_VALROTH_RAND);
}
void JustDied(Unit* killer) override
{
Talk(SAY_VALROTH_DEATH);
if (killer)
{
killer->CastSpell(me, SPELL_SUMMON_VALROTH_REMAINS, true);
}
}
};
};
/*######
## npc_a_special_surprise
######*/
@@ -785,6 +706,5 @@ void AddSC_the_scarlet_enclave_c2()
new npc_crusade_persuaded();
new npc_scarlet_courier();
new npc_koltira_deathweaver();
new npc_high_inquisitor_valroth();
new npc_a_special_surprise();
}
@@ -121,7 +121,7 @@ enum LightOfDawnEncounter
EVENT_SPELL_DEATH_STRIKE,
EVENT_SPELL_DEATH_EMBRACE,
EVENT_SPELL_UNHOLY_BLIGHT,
EVENT_SPELL_TALK,
EVENT_SPELL_DARION_MOD_DAMAGE,
// Positioning
EVENT_FINISH_FIGHT_1,
EVENT_FINISH_FIGHT_2,
@@ -253,6 +253,7 @@ enum LightOfDawnSpells
SPELL_DEATH_EMBRACE = 53635,
SPELL_ICY_TOUCH1 = 49723,
SPELL_UNHOLY_BLIGHT = 53640,
SPELL_DARION_MOD_DAMAGE = 53645,
// Outro
SPELL_THE_LIGHT_OF_DAWN = 53658,
@@ -524,7 +525,7 @@ public:
events.RescheduleEvent(EVENT_SPELL_DEATH_STRIKE, 8000);
events.RescheduleEvent(EVENT_SPELL_DEATH_EMBRACE, 5000);
events.RescheduleEvent(EVENT_SPELL_UNHOLY_BLIGHT, 10000);
events.RescheduleEvent(EVENT_SPELL_TALK, 10000);
events.RescheduleEvent(EVENT_SPELL_DARION_MOD_DAMAGE, 500);
}
void Reset() override
@@ -661,7 +662,7 @@ public:
me->SetHomePosition(pos);
me->SetWalk(false);
me->GetMotionMaster()->MovePoint(1, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), true, true);
me->CastSpell(me, SPELL_THE_MIGHT_OF_MOGRAINE, true);
DoCastSelf(SPELL_THE_MIGHT_OF_MOGRAINE, true);
break;
}
case EVENT_START_COUNTDOWN_14:
@@ -1146,23 +1147,24 @@ public:
{
case EVENT_SPELL_ANTI_MAGIC_ZONE:
DoCast(me, SPELL_ANTI_MAGIC_ZONE1);
events.RescheduleEvent(eventId, 25s, 30s);
events.RescheduleEvent(eventId, 30s, 45s);
break;
case EVENT_SPELL_DEATH_STRIKE:
DoCastVictim(SPELL_DEATH_STRIKE);
events.RescheduleEvent(eventId, 5s, 10s);
events.RescheduleEvent(eventId, 5s, 35s);
break;
case EVENT_SPELL_DEATH_EMBRACE:
DoCastVictim(SPELL_DEATH_EMBRACE);
events.RescheduleEvent(eventId, 15s, 20s);
events.RescheduleEvent(eventId, 45s, 60s);
break;
case EVENT_SPELL_UNHOLY_BLIGHT:
DoCast(me, SPELL_UNHOLY_BLIGHT);
events.RescheduleEvent(eventId, 60s);
break;
case EVENT_SPELL_TALK:
case EVENT_SPELL_DARION_MOD_DAMAGE:
DoCast(me, SPELL_DARION_MOD_DAMAGE);
Talk(SAY_LIGHT_OF_DAWN09);
events.RescheduleEvent(eventId, 15s, 20s);
events.RescheduleEvent(eventId, 15s, 25s);
break;
}
@@ -1215,9 +1217,106 @@ class spell_chapter5_rebuke : public SpellScript
}
};
// 58552 - Return to Orgrimmar
// 58533 - Return to Stormwind
enum ReturnToCapital
{
SPELL_RETURN_TO_ORGRIMMAR_APPLE = 58509,
SPELL_RETURN_TO_ORGRIMMAR_BANANA = 58513,
SPELL_RETURN_TO_ORGRIMMAR_SPIT = 58520,
EMOTE_THROW_APPLE = 2,
EMOTE_THROW_BANANA = 3,
EMOTE_THROW_SPIT = 4,
SAY_INSULT_TO_DK = 5,
NPC_SW_GUARD = 68,
NPC_ROYAL_GUARD = 1756,
NPC_CITY_PATROLLER = 1976,
NPC_OG_GUARD = 3296,
NPC_KOR_ELITE = 14304,
TEXT_BROADCAST_COWER = 31670 // "%s cowers in fear."
};
uint32 ReturnToCapitalSpells[3] =
{
58509, // Apple
58513, // Banana
58520 // Spit
};
class spell_chapter5_return_to_capital : public SpellScript
{
PrepareSpellScript(spell_chapter5_return_to_capital);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_RETURN_TO_ORGRIMMAR_APPLE, SPELL_RETURN_TO_ORGRIMMAR_BANANA, SPELL_RETURN_TO_ORGRIMMAR_SPIT});
}
void HandleHit(SpellEffIndex /*effIndex*/)
{
Creature* creature = GetHitUnit()->ToCreature();
Player* player = GetCaster()->ToPlayer();
uint32 spellId = GetSpellInfo()->Id;
if (!spellId || !creature || !player || player->IsGameMaster() || !player->IsAlive() || !creature->IsAlive() || creature->IsInCombat())
return;
if (creature->HasSpellCooldown(spellId))
return;
if (creature->GetEntry() == NPC_SW_GUARD || creature->GetEntry() == NPC_ROYAL_GUARD || creature->GetEntry() == NPC_CITY_PATROLLER || creature->GetEntry() == NPC_OG_GUARD || creature->GetEntry() == NPC_KOR_ELITE)
{
_emote = urand(2,4);
if (creature)
{
creature->PauseMovement(5000);
creature->SetTimedFacingToObject(player, 30000);
if (roll_chance_i(30))
{
creature->AI()->Talk(_emote, player);
creature->CastSpell(player, ReturnToCapitalSpells[_emote - 2]);
}
else
{
creature->AI()->Talk(SAY_INSULT_TO_DK, player);
creature->HandleEmoteCommand(RAND(EMOTE_ONESHOT_POINT,EMOTE_ONESHOT_RUDE));
}
}
}
/*/// @todo: This needs to be further investigated as there are some "guard" npcs, that have civilian flags and non guard npcs should also insult the dk.
else
if (creature->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_CIVILIAN)
{
creature->HandleEmoteCommand(EMOTE_STATE_COWER); // from sniff, emote 431 for a while, then reset (with "%s cowers in fear." text)
creature->PlayDirectSound(14556); // from sniff
if (player)
{
LocaleConstant loc_idx = player->GetSession()->GetSessionDbLocaleIndex();
if (BroadcastText const* bct = sObjectMgr->GetBroadcastText(TEXT_BROADCAST_COWER))
creature->TextEmote(bct->GetText(loc_idx, creature->getGender()), creature);
}
}
*/
creature->AddSpellCooldown(spellId, 0, 30000);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_chapter5_return_to_capital::HandleHit, EFFECT_0, SPELL_EFFECT_DUMMY);
}
private:
uint8 _emote;
};
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);
}
@@ -381,14 +381,8 @@ struct boss_kiljaeden : public BossAI
if (Creature* anveena = instance->GetCreature(DATA_ANVEENA))
{
anveena->RemoveAllAuras();
anveena->DespawnOrUnsummon(3500);
}
}, 34s);
me->m_Events.AddEventAtOffset([&] {
if (Creature* anveena = instance->GetCreature(DATA_ANVEENA))
{
anveena->CastSpell(anveena, SPELL_SACRIFICE_OF_ANVEENA, true);
anveena->DespawnOrUnsummon(1500);
DoCastSelf(SPELL_CUSTOM_08_STATE, true);
me->SetUnitFlag(UNIT_FLAG_PACIFIED);
scheduler.CancelAll();
@@ -213,7 +213,7 @@ struct npc_dark_fiend : public ScriptedAI
Unit* target = nullptr;
if (InstanceScript* instance = me->GetInstanceScript())
if (Creature* muru = instance->GetCreature(DATA_MURU))
target = muru->GetAI()->SelectTarget(SelectTargetMethod::Random, 0, FarthestTargetSelector(me, 50.0f, true, true));
target = muru->GetAI()->SelectTarget(SelectTargetMethod::Random, 0, RangeSelector(me, 50.0f, true, true));
if (target)
{
@@ -18,6 +18,8 @@
#include "CreatureScript.h"
#include "Player.h"
#include "ScriptedCreature.h"
#include "SpellScript.h"
#include "SpellScriptLoader.h"
#include "SpellInfo.h"
#include "halls_of_lightning.h"
@@ -27,6 +29,7 @@ enum IonarSpells
SPELL_BALL_LIGHTNING_H = 59800,
SPELL_STATIC_OVERLOAD_N = 52658,
SPELL_STATIC_OVERLOAD_H = 59795,
SPELL_STATIC_OVERLOAD_KNOCK = 53337,
SPELL_DISPERSE = 52770,
SPELL_SUMMON_SPARK = 52746,
@@ -272,8 +275,34 @@ public:
};
};
// 52658, 59795 - Static Overload
class spell_ionar_static_overload : public AuraScript
{
PrepareAuraScript(spell_ionar_static_overload);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_STATIC_OVERLOAD_KNOCK });
}
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_EXPIRE)
return;
if (Unit* target = GetTarget())
target->CastSpell(target, SPELL_STATIC_OVERLOAD_KNOCK, true);
}
void Register() override
{
OnEffectRemove += AuraEffectRemoveFn(spell_ionar_static_overload::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL);
}
};
void AddSC_boss_ionar()
{
new boss_ionar();
new npc_spark_of_ionar();
RegisterSpellScript(spell_ionar_static_overload);
}
@@ -819,54 +819,6 @@ public:
}
};
enum StormCloud
{
STORM_COULD = 29939,
HEALING_WINDS = 55549,
STORM_VISUAL = 55708,
GYMERS_GRAB = 55516,
RIDE_VEHICLE = 43671
};
class npc_storm_cloud : public CreatureScript
{
public:
npc_storm_cloud() : CreatureScript("npc_storm_cloud") { }
struct npc_storm_cloudAI : public ScriptedAI
{
npc_storm_cloudAI(Creature* creature) : ScriptedAI(creature) { }
void Reset() override
{
me->CastSpell(me, STORM_VISUAL, true);
}
void JustRespawned() override
{
Reset();
}
void SpellHit(Unit* caster, SpellInfo const* spell) override
{
if (spell->Id != GYMERS_GRAB)
return;
if (Vehicle* veh = caster->GetVehicleKit())
if (veh->GetAvailableSeatCount() != 0)
{
me->CastSpell(caster, RIDE_VEHICLE, true);
me->CastSpell(caster, HEALING_WINDS, true);
}
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return new npc_storm_cloudAI(creature);
}
};
enum ScourgeDisguiseInstability
{
SCOURGE_DISGUISE_FAILING_MESSAGE_1 = 28552, // Scourge Disguise Failing! Find a safe place!
@@ -922,7 +874,6 @@ void AddSC_zuldrak()
new npc_released_offspring_harkoa();
new npc_crusade_recruit();
new go_scourge_enclosure();
new npc_storm_cloud();
RegisterSpellScript(spell_scourge_disguise_instability);
}
+41 -4
View File
@@ -1727,6 +1727,16 @@ class spell_dk_pestilence : public SpellScript
{
PrepareSpellScript(spell_dk_pestilence);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo(
{
SPELL_DK_GLYPH_OF_DISEASE,
SPELL_DK_BLOOD_PLAGUE,
SPELL_DK_FROST_FEVER
});
}
void HandleScriptEffect(SpellEffIndex /*effIndex*/)
{
Unit* caster = GetCaster();
@@ -1743,11 +1753,38 @@ class spell_dk_pestilence : public SpellScript
// And spread them on target
// Blood Plague
if (target->GetAura(SPELL_DK_BLOOD_PLAGUE, caster->GetGUID()))
caster->CastSpell(hitUnit, SPELL_DK_BLOOD_PLAGUE, true);
if (Aura* disOld = target->GetAura(SPELL_DK_BLOOD_PLAGUE, caster->GetGUID()))
if (AuraEffect* effOld = disOld->GetEffect(EFFECT_0))
{
float pctMods = effOld->GetPctMods();
float crit = effOld->GetCritChance();
caster->CastSpell(hitUnit, SPELL_DK_BLOOD_PLAGUE, true);
if (Aura* disNew = hitUnit->GetAura(SPELL_DK_BLOOD_PLAGUE, caster->GetGUID()))
if (AuraEffect* effNew = disNew->GetEffect(EFFECT_0))
{
effNew->SetPctMods(pctMods);
effNew->SetCritChance(crit);
effNew->SetAmount(effNew->CalculateAmount(effNew->GetCaster()));
}
}
// Frost Fever
if (target->GetAura(SPELL_DK_FROST_FEVER, caster->GetGUID()))
caster->CastSpell(hitUnit, SPELL_DK_FROST_FEVER, true);
if (Aura* disOld = target->GetAura(SPELL_DK_FROST_FEVER, caster->GetGUID()))
if (AuraEffect* effOld = disOld->GetEffect(EFFECT_0))
{
float pctMods = effOld->GetPctMods();
float crit = effOld->GetCritChance();
caster->CastSpell(hitUnit, SPELL_DK_FROST_FEVER, true);
if (Aura* disNew = hitUnit->GetAura(SPELL_DK_FROST_FEVER, caster->GetGUID()))
if (AuraEffect* effNew = disNew->GetEffect(EFFECT_0))
{
effNew->SetPctMods(pctMods);
effNew->SetCritChance(crit);
effNew->SetAmount(effNew->CalculateAmount(effNew->GetCaster()));
}
}
}
}
+1 -1
View File
@@ -606,7 +606,6 @@ class spell_gen_black_magic_enchant : public AuraScript
}
};
// 53642 - The Might of Mograine
// 64174 - Protective Gaze
class spell_gen_area_aura_select_players : public AuraScript
{
@@ -622,6 +621,7 @@ class spell_gen_area_aura_select_players : public AuraScript
}
};
// 53642 - The Might of Mograine
// 62650 - Fortitude of Frost
// 62670 - Resilience of Nature
// 62671 - Speed of Invention
+23
View File
@@ -4187,6 +4187,28 @@ class spell_item_multiphase_goggles : public AuraScript
}
};
// 60244 - Blood Parrot Despawn Aura (Item: 12185 - Bloodsail Admiral's Hat)
enum BloodsailAdmiralHat
{
NPC_ADMIRAL_HAT_PARROT = 11236, // Blood Parrot
};
class spell_item_bloodsail_admiral_hat : public AuraScript
{
PrepareAuraScript(spell_item_bloodsail_admiral_hat);
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (Player* player = GetCaster()->ToPlayer())
player->RemoveAllMinionsByEntry(NPC_ADMIRAL_HAT_PARROT);
}
void Register() override
{
OnEffectRemove += AuraEffectRemoveFn(spell_item_bloodsail_admiral_hat::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
}
};
void AddSC_item_spell_scripts()
{
RegisterSpellScript(spell_item_massive_seaforium_charge);
@@ -4315,4 +4337,5 @@ void AddSC_item_spell_scripts()
RegisterSpellScript(spell_item_luffa);
RegisterSpellScript(spell_item_spell_reflectors);
RegisterSpellScript(spell_item_multiphase_goggles);
RegisterSpellScript(spell_item_bloodsail_admiral_hat);
}
+12 -5
View File
@@ -2269,7 +2269,10 @@ class spell_q12619_emblazon_runeblade_effect : public SpellScript
enum Quest_The_Storm_King
{
SPELL_RIDE_GYMER = 43671,
SPELL_GRABBED = 55424
SPELL_GRABBED = 55424,
SPELL_HEALING_WINDS = 55549,
NPC_STORM_CLOUD = 29939
};
class spell_q12919_gymers_grab : public SpellScript
@@ -2284,10 +2287,14 @@ class spell_q12919_gymers_grab : public SpellScript
void HandleScript(SpellEffIndex /*effIndex*/)
{
int8 seatId = 2;
if (!GetHitCreature())
return;
GetHitCreature()->CastCustomSpell(SPELL_RIDE_GYMER, SPELLVALUE_BASE_POINT0, seatId, GetCaster(), true);
GetHitCreature()->CastSpell(GetHitCreature(), SPELL_GRABBED, true);
if (Creature* creature = GetHitCreature())
{
creature->CastCustomSpell(SPELL_RIDE_GYMER, SPELLVALUE_BASE_POINT0, seatId, GetCaster(), true);
creature->CastSpell(creature, SPELL_GRABBED, true);
if (creature->GetEntry() == NPC_STORM_CLOUD)
creature->CastSpell(GetCaster(), SPELL_HEALING_WINDS, true);
}
}
void Register() override