Merge branch 'master' into Playerbot

This commit is contained in:
Yunfan Li
2023-08-27 00:42:24 +08:00
25 changed files with 339 additions and 219 deletions

View File

@@ -6880,7 +6880,13 @@ bool Player::Satisfy(DungeonProgressionRequirements const* ar, uint32 target_map
}
else if (missingPlayerItems.size())
{
GetSession()->SendAreaTriggerMessage(GetSession()->GetAcoreString(LANG_LEVEL_MINREQUIRED_AND_ITEM), LevelMin, sObjectMgr->GetItemTemplate(missingPlayerItems[0]->id)->Name1.c_str());
LocaleConstant loc_idx = GetSession()->GetSessionDbLocaleIndex();
std::string name = sObjectMgr->GetItemTemplate(missingPlayerItems[0]->id)->Name1;
if (ItemLocale const* il = sObjectMgr->GetItemLocale(missingPlayerItems[0]->id))
{
ObjectMgr::GetLocaleString(il->Name, loc_idx, name);
}
GetSession()->SendAreaTriggerMessage(GetSession()->GetAcoreString(LANG_LEVEL_MINREQUIRED_AND_ITEM), ar->levelMin, name.c_str());
}
else if (LevelMin)
{

View File

@@ -1412,16 +1412,16 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici
uint32 mapid = m_caster->GetMapId();
uint32 phasemask = m_caster->GetPhaseMask();
float collisionHeight = m_caster->GetCollisionHeight();
float destx = 0.0f, desty = 0.0f, destz = 0.0f, ground = 0.0f, startx = 0.0f, starty = 0.0f, startz = 0.0f, starto = 0.0f;
float destz = 0.0f, startx = 0.0f, starty = 0.0f, startz = 0.0f, starto = 0.0f;
Position pos;
Position lastpos;
m_caster->GetPosition(startx, starty, startz, starto);
pos.Relocate(startx, starty, startz, starto);
destx = pos.GetPositionX() + distance * cos(pos.GetOrientation());
desty = pos.GetPositionY() + distance * sin(pos.GetOrientation());
float destx = pos.GetPositionX() + distance * cos(pos.GetOrientation());
float desty = pos.GetPositionY() + distance * sin(pos.GetOrientation());
ground = map->GetHeight(phasemask, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ());
float ground = map->GetHeight(phasemask, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ());
bool isCasterInWater = m_caster->IsInWater();
if (!m_caster->HasUnitMovementFlag(MOVEMENTFLAG_FALLING) || (pos.GetPositionZ() - ground < distance))
@@ -1586,6 +1586,15 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici
destz = prevZ;
//LOG_ERROR("spells", "(collision) destZ rewrited in prevZ");
// Don't make the player move backward from the xy adjustments by collisions.
if ((DELTA_X > 0 && startx > destx) || (DELTA_X < 0 && startx < destx) ||
(DELTA_Y > 0 && starty > desty) || (DELTA_Y < 0 && starty < desty))
{
destx = startx;
desty = starty;
destz = startz;
}
break;
}
// we have correct destz now
@@ -1597,9 +1606,9 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici
else
{
float z = pos.GetPositionZ();
bool col = VMAP::VMapFactory::createOrGetVMapMgr()->GetObjectHitPos(mapid, pos.GetPositionX(), pos.GetPositionY(), z + 0.5f, destx, desty, z + 0.5f, destx, desty, z, -0.5f);
bool col = VMAP::VMapFactory::createOrGetVMapMgr()->GetObjectHitPos(mapid, pos.GetPositionX(), pos.GetPositionY(), z, destx, desty, z, destx, desty, z, -0.5f);
// check dynamic collision
bool dcol = m_caster->GetMap()->GetObjectHitPos(phasemask, pos.GetPositionX(), pos.GetPositionY(), z + 0.5f, destx, desty, z + 0.5f, destx, desty, z, -0.5f);
bool dcol = m_caster->GetMap()->GetObjectHitPos(phasemask, pos.GetPositionX(), pos.GetPositionY(), z, destx, desty, z, destx, desty, z, -0.5f);
// collision occured
if (col || dcol)

View File

@@ -57,6 +57,12 @@ void SpellMgr::LoadSpellInfoCorrections()
spellInfo->AttributesEx3 |= SPELL_ATTR3_ALWAYS_HIT;
});
// Has Brewfest Mug
ApplySpellFix({ 42533 }, [](SpellInfo* spellInfo)
{
spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(347); // 15 min
});
// Elixir of Minor Fortitude
ApplySpellFix({ 2378 }, [](SpellInfo* spellInfo)
{
@@ -592,6 +598,14 @@ void SpellMgr::LoadSpellInfoCorrections()
spellInfo->Effects[EFFECT_1].ApplyAuraName = SPELL_AURA_DUMMY; // just a marker
});
ApplySpellFix({
6940, // Hand of Sacrifice
64205 // Divine Sacrifice
}, [](SpellInfo* spellInfo)
{
spellInfo->AttributesEx7 |= SPELL_ATTR7_DONT_CAUSE_SPELL_PUSHBACK;
});
// Seal of Command trigger
ApplySpellFix({ 20424 }, [](SpellInfo* spellInfo)
{
@@ -4566,6 +4580,12 @@ void SpellMgr::LoadSpellInfoCorrections()
spellInfo->AuraInterruptFlags |= AURA_INTERRUPT_FLAG_TAKE_DAMAGE;
});
// Torment of the Worgen
ApplySpellFix({ 30567 }, [](SpellInfo* spellInfo)
{
spellInfo->ProcChance = 3;
});
for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
{
SpellInfo* spellInfo = mSpellInfoMap[i];

View File

@@ -47,6 +47,7 @@ ObjectData const creatureData[] =
{ NPC_NEFARIAN_TROOPS, DATA_NEFARIAN_TROOPS },
{ NPC_VICTOR_NEFARIUS, DATA_LORD_VICTOR_NEFARIUS },
{ NPC_CHROMAGGUS, DATA_CHROMAGGUS },
{ 0, 0 }
};
ObjectData const objectData[] =

View File

@@ -97,6 +97,11 @@ enum Creatures
CREATURE_CRONE = 18168,
};
enum OZActions
{
ACTION_RELEASE = 1,
};
void SummonCroneIfReady(InstanceScript* instance, Creature* creature)
{
instance->SetData(DATA_OPERA_OZ_DEATHCOUNT, SPECIAL); // Increment DeathCount
@@ -137,13 +142,26 @@ void DespawnAll(InstanceScript* instance)
}
}
void DoActions(InstanceScript* instance)
{
uint32 datas[4] = {DATA_DOROTHEE, DATA_ROAR, DATA_STRAWMAN, DATA_TINHEAD};
for (uint32 data : datas)
{
if (Creature* actionCreature = instance->GetCreature(data))
{
actionCreature->AI()->DoAction(ACTION_RELEASE);
}
}
}
struct boss_dorothee : public ScriptedAI
{
boss_dorothee(Creature* creature) : ScriptedAI(creature)
{
SetCombatMovement(false);
//this is kinda a big no-no. but it will prevent her from moving to chase targets. she should just cast her spells. in this case, since there is not really something to LOS her with or get out of range this would work. but a more elegant solution would be better
Initialize();
instance = creature->GetInstanceScript();
_scheduler.SetValidator([this]
@@ -152,47 +170,26 @@ struct boss_dorothee : public ScriptedAI
});
}
void ScheduleActivation()
{
_scheduler.Schedule(16670ms, [this](TaskContext)
{
if (Creature* roar = instance->GetCreature(DATA_ROAR))
{
roar->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
roar->SetImmuneToPC(false);
roar->SetInCombatWithZone();
}
}).Schedule(26300ms, [this](TaskContext)
{
if (Creature* strawman = instance->GetCreature(DATA_STRAWMAN))
{
strawman->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
strawman->SetImmuneToPC(false);
strawman->SetInCombatWithZone();
}
}).Schedule(34470ms, [this](TaskContext)
{
if (Creature* tinhead = instance->GetCreature(DATA_TINHEAD))
{
tinhead->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
tinhead->SetImmuneToPC(false);
tinhead->SetInCombatWithZone();
}
});
}
void Initialize()
{
titoDied = false;
_startIntro = false;
}
InstanceScript* instance;
bool titoDied;
void DoAction(int32 action) override
{
if (action == ACTION_RELEASE)
{
_scheduler.Schedule(11700ms, [this](TaskContext)
{
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->SetImmuneToPC(false);
me->SetInCombatWithZone();
});
}
}
void Reset() override
{
Initialize();
titoDied = false;
_startIntro = false;
}
void JustEngagedWith(Unit* /*who*/) override
@@ -270,13 +267,7 @@ struct boss_dorothee : public ScriptedAI
if (!_startIntro)
{
ScheduleActivation();
_scheduler.Schedule(12s, [this](TaskContext)
{
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->SetImmuneToPC(false);
me->SetInCombatWithZone();
});
DoActions(instance);
_startIntro = true;
}
DoMeleeAttackIfReady();
@@ -347,6 +338,19 @@ struct boss_roar : public ScriptedAI
InstanceScript* instance;
void DoAction(int32 action) override
{
if (action == ACTION_RELEASE)
{
_scheduler.Schedule(16670ms, [this](TaskContext)
{
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->SetImmuneToPC(false);
me->SetInCombatWithZone();
});
}
}
void Reset() override { }
void MoveInLineOfSight(Unit* who) override
@@ -441,6 +445,19 @@ struct boss_strawman : public ScriptedAI
InstanceScript* instance;
void DoAction(int32 action) override
{
if (action == ACTION_RELEASE)
{
_scheduler.Schedule(26300ms, [this](TaskContext)
{
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->SetImmuneToPC(false);
me->SetInCombatWithZone();
});
}
}
void Reset() override { }
void AttackStart(Unit* who) override
@@ -516,11 +533,11 @@ struct boss_strawman : public ScriptedAI
void UpdateAI(uint32 diff) override
{
_scheduler.Update(diff);
if (!UpdateVictim())
return;
_scheduler.Update(diff);
DoMeleeAttackIfReady();
}
private:
@@ -541,6 +558,19 @@ struct boss_tinhead : public ScriptedAI
InstanceScript* instance;
void DoAction(int32 action) override
{
if (action == ACTION_RELEASE)
{
_scheduler.Schedule(34470ms, [this](TaskContext)
{
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->SetImmuneToPC(false);
me->SetInCombatWithZone();
});
}
}
void Reset() override
{
_rustCount = 0;

View File

@@ -43,6 +43,7 @@ ObjectData const creatureData[] =
{ NPC_TINHEAD, DATA_TINHEAD },
{ NPC_ROMULO, DATA_ROMULO },
{ NPC_JULIANNE, DATA_JULIANNE },
{ 0, 0 }
};
class instance_karazhan : public InstanceMapScript

View File

@@ -38,7 +38,8 @@ ObjectData const creatureData[] =
{ NPC_HIGH_PRIEST_THEKAL, DATA_THEKAL },
{ NPC_ZEALOT_LORKHAN, DATA_LORKHAN },
{ NPC_ZEALOT_ZATH, DATA_ZATH },
{ NPC_PRIESTESS_MARLI, DATA_MARLI }
{ NPC_PRIESTESS_MARLI, DATA_MARLI },
{ 0, 0 }
};
class instance_zulgurub : public InstanceMapScript

View File

@@ -31,9 +31,10 @@ const Position PortalLocation[4] =
{ -1930.9106f, 7183.5970f, 23.007639f, 3.59537f }
};
ObjectData const creatureData[1] =
ObjectData const creatureData[] =
{
{ NPC_MEDIVH, DATA_MEDIVH }
{ NPC_MEDIVH, DATA_MEDIVH },
{ 0, 0 }
};
class instance_the_black_morass : public InstanceMapScript

View File

@@ -21,7 +21,8 @@
ObjectData const creatureData[] =
{
{ NPC_ONYXIA, DATA_ONYXIA }
{ NPC_ONYXIA, DATA_ONYXIA },
{ 0, 0 }
};
class instance_onyxias_lair : public InstanceMapScript

View File

@@ -36,6 +36,7 @@ ObjectData const creatureData[] =
{ NPC_YEGGETH, DATA_YEGGETH },
{ NPC_PAKKON, DATA_PAKKON },
{ NPC_ZERRAN, DATA_ZERRAN },
{ 0, 0 }
};
enum RajaxxWaveEvent

View File

@@ -35,7 +35,8 @@ ObjectData const creatureData[] =
{ NPC_MASTERS_EYE, DATA_MASTERS_EYE },
{ NPC_VEKLOR, DATA_VEKLOR },
{ NPC_VEKNILASH, DATA_VEKNILASH },
{ NPC_VISCIDUS, DATA_VISCIDUS }
{ NPC_VISCIDUS, DATA_VISCIDUS },
{ 0, 0 }
};
DoorData const doorData[] =

View File

@@ -37,7 +37,7 @@ EndContentData */
## npc_shenthul
######*/
enum Shenthul
enum Shenthul : uint32
{
QUEST_SHATTERED_SALUTE = 2460
};
@@ -134,10 +134,8 @@ public:
## npc_thrall_warchief
######*/
enum ThrallWarchief
enum ThrallWarchief : uint32
{
QUEST_6566 = 6566,
SPELL_CHAIN_LIGHTNING = 16033,
SPELL_SHOCK = 16034,
@@ -153,19 +151,17 @@ enum ThrallWarchief
AREA_ORGRIMMAR = 1637,
AREA_RAZOR_HILL = 362,
AREA_CAMP_TAURAJO = 378,
AREA_CROSSROADS = 380
AREA_CROSSROADS = 380,
// What the Wind Carries (ID: 6566)
QUEST_WHAT_THE_WIND_CARRIES = 6566,
GOSSIP_MENU_THRALL = 3664,
GOSSIP_RESPONSE_THRALL_FIRST = 5733,
GOSSIP_OPTION_DEFAULT = 0
};
const Position heraldOfThrallPos = { -462.404f, -2637.68f, 96.0656f, 5.8606f };
#define GOSSIP_HTW "Please share your wisdom with me, Warchief."
#define GOSSIP_STW1 "What discoveries?"
#define GOSSIP_STW2 "Usurper?"
#define GOSSIP_STW3 "With all due respect, Warchief - why not allow them to be destroyed? Does this not strengthen our position?"
#define GOSSIP_STW4 "I... I did not think of it that way, Warchief."
#define GOSSIP_STW5 "I live only to serve, Warchief! My life is empty and meaningless without your guidance."
#define GOSSIP_STW6 "Of course, Warchief!"
/// @todo verify abilities/timers
class npc_thrall_warchief : public CreatureScript
{
@@ -175,47 +171,37 @@ public:
bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override
{
ClearGossipMenuFor(player);
switch (action)
uint32 DiscussionOrder = action - GOSSIP_ACTION_INFO_DEF;
if (DiscussionOrder>= 1 && DiscussionOrder <= 6)
{
case GOSSIP_ACTION_INFO_DEF+1:
AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_STW1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2);
SendGossipMenuFor(player, 5733, creature->GetGUID());
break;
case GOSSIP_ACTION_INFO_DEF+2:
AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_STW2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3);
SendGossipMenuFor(player, 5734, creature->GetGUID());
break;
case GOSSIP_ACTION_INFO_DEF+3:
AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_STW3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4);
SendGossipMenuFor(player, 5735, creature->GetGUID());
break;
case GOSSIP_ACTION_INFO_DEF+4:
AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_STW4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5);
SendGossipMenuFor(player, 5736, creature->GetGUID());
break;
case GOSSIP_ACTION_INFO_DEF+5:
AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_STW5, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6);
SendGossipMenuFor(player, 5737, creature->GetGUID());
break;
case GOSSIP_ACTION_INFO_DEF+6:
AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_STW6, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7);
SendGossipMenuFor(player, 5738, creature->GetGUID());
break;
case GOSSIP_ACTION_INFO_DEF+7:
CloseGossipMenuFor(player);
player->AreaExploredOrEventHappens(QUEST_6566);
break;
uint32 NextAction = GOSSIP_ACTION_INFO_DEF + DiscussionOrder + 1;
uint32 GossipResponse = GOSSIP_RESPONSE_THRALL_FIRST + DiscussionOrder - 1;
AddGossipItemFor(player, GOSSIP_MENU_THRALL + DiscussionOrder, GOSSIP_OPTION_DEFAULT, GOSSIP_SENDER_MAIN, NextAction);
SendGossipMenuFor(player, GossipResponse, creature->GetGUID());
}
else if (DiscussionOrder == 7)
{
CloseGossipMenuFor(player);
player->AreaExploredOrEventHappens(QUEST_WHAT_THE_WIND_CARRIES);
}
return true;
}
bool OnGossipHello(Player* player, Creature* creature) override
{
if (creature->IsQuestGiver())
{
player->PrepareQuestMenu(creature->GetGUID());
}
if (player->GetQuestStatus(QUEST_6566) == QUEST_STATUS_INCOMPLETE)
AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_HTW, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
if (player->GetQuestStatus(QUEST_WHAT_THE_WIND_CARRIES) == QUEST_STATUS_INCOMPLETE)
{
AddGossipItemFor(player, GOSSIP_MENU_THRALL, GOSSIP_OPTION_DEFAULT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
}
SendGossipMenuFor(player, player->GetGossipTextId(creature), creature->GetGUID());
return true;

View File

@@ -32,7 +32,8 @@ DoorData const doorData[] =
ObjectData const creatureData[] =
{
{ NPC_KRIKTHIR_THE_GATEWATCHER, DATA_KRIKTHIR_THE_GATEWATCHER_EVENT },
{ NPC_HADRONOX, DATA_HADRONOX_EVENT }
{ NPC_HADRONOX, DATA_HADRONOX_EVENT },
{ 0, 0 }
};
BossBoundaryData const boundaries =

View File

@@ -118,7 +118,8 @@ DoorData const doorData[] =
ObjectData const creatureData[] =
{
{ NPC_SINDRAGOSA, DATA_SINDRAGOSA }
{ NPC_SINDRAGOSA, DATA_SINDRAGOSA },
{ 0, 0 }
};
// this doesnt have to only store questgivers, also can be used for related quest spawns

View File

@@ -27,7 +27,8 @@ DoorData const doorData[] =
ObjectData const gameObjectData[] =
{
{ GO_THE_TALON_KINGS_COFFER, DATA_GO_TALON_KING_COFFER }
{ GO_THE_TALON_KINGS_COFFER, DATA_GO_TALON_KING_COFFER },
{ 0, 0 }
};
class instance_sethekk_halls : public InstanceMapScript

View File

@@ -23,7 +23,7 @@ enum Yells
{
SAY_AGGRO = 0,
SAY_SUMMON = 1,
SAY_SUMMON_BUBLE = 2,
SAY_SUMMON_BUBBLE = 2,
SAY_SLAY = 3,
SAY_DEATH = 4,
EMOTE_WATERY_GRAVE = 5,
@@ -47,120 +47,95 @@ enum Spells
SPELL_SUMMON_WATER_GLOBULE_4 = 37861
};
enum Misc
const uint32 wateryGraveIds[4] = {SPELL_WATERY_GRAVE_1, SPELL_WATERY_GRAVE_2, SPELL_WATERY_GRAVE_3, SPELL_WATERY_GRAVE_4};
const uint32 waterGlobuleIds[4] = {SPELL_SUMMON_WATER_GLOBULE_1, SPELL_SUMMON_WATER_GLOBULE_2, SPELL_SUMMON_WATER_GLOBULE_3, SPELL_SUMMON_WATER_GLOBULE_4};
struct boss_morogrim_tidewalker : public BossAI
{
// Creatures
NPC_WATER_GLOBULE = 21913,
NPC_TIDEWALKER_LURKER = 21920,
EVENT_SPELL_TIDAL_WAVE = 1,
EVENT_SPELL_WATERY_GRAVE = 2,
EVENT_SPELL_EARTHQUAKE = 3,
EVENT_SUMMON_MURLOCS = 4,
EVENT_KILL_TALK = 5
};
const uint32 wateryGraveId[4] = {SPELL_WATERY_GRAVE_1, SPELL_WATERY_GRAVE_2, SPELL_WATERY_GRAVE_3, SPELL_WATERY_GRAVE_4};
const uint32 waterGlobuleId[4] = {SPELL_SUMMON_WATER_GLOBULE_1, SPELL_SUMMON_WATER_GLOBULE_2, SPELL_SUMMON_WATER_GLOBULE_3, SPELL_SUMMON_WATER_GLOBULE_4};
class boss_morogrim_tidewalker : public CreatureScript
{
public:
boss_morogrim_tidewalker() : CreatureScript("boss_morogrim_tidewalker") { }
CreatureAI* GetAI(Creature* creature) const override
boss_morogrim_tidewalker(Creature* creature) : BossAI(creature, DATA_MOROGRIM_TIDEWALKER)
{
return GetSerpentShrineAI<boss_morogrim_tidewalkerAI>(creature);
scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
struct boss_morogrim_tidewalkerAI : public BossAI
void Reset() override
{
boss_morogrim_tidewalkerAI(Creature* creature) : BossAI(creature, DATA_MOROGRIM_TIDEWALKER)
BossAI::Reset();
_recentlySpoken = false;
}
void KilledUnit(Unit*) override
{
if (!_recentlySpoken)
{
Talk(SAY_SLAY);
_recentlySpoken = true;
}
void Reset() override
scheduler.Schedule(6s, [this](TaskContext)
{
BossAI::Reset();
}
_recentlySpoken = false;
});
}
void KilledUnit(Unit*) override
void JustSummoned(Creature* summon) override
{
summons.Summon(summon);
summon->SetInCombatWithZone();
}
void JustDied(Unit* killer) override
{
Talk(SAY_DEATH);
BossAI::JustDied(killer);
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
Talk(SAY_AGGRO);
scheduler.Schedule(10s, [this](TaskContext context)
{
if (events.GetNextEventTime(EVENT_KILL_TALK) == 0)
DoCastVictim(SPELL_TIDAL_WAVE);
context.Repeat(20s);
}).Schedule(20s, [this](TaskContext context)
{
Talk(SAY_SUMMON_BUBBLE);
if (me->HealthAbovePct(25))
{
Talk(SAY_SLAY);
events.ScheduleEvent(EVENT_KILL_TALK, 6000);
Talk(EMOTE_WATERY_GRAVE);
me->CastCustomSpell(SPELL_WATERY_GRAVE, SPELLVALUE_MAX_TARGETS, 4, me, false);
}
}
void JustSummoned(Creature* summon) override
{
summons.Summon(summon);
summon->SetInCombatWithZone();
}
void JustDied(Unit* killer) override
{
Talk(SAY_DEATH);
BossAI::JustDied(killer);
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
Talk(SAY_AGGRO);
events.ScheduleEvent(EVENT_SPELL_TIDAL_WAVE, 10000);
events.ScheduleEvent(EVENT_SPELL_WATERY_GRAVE, 28000);
events.ScheduleEvent(EVENT_SPELL_EARTHQUAKE, 40000);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
else
{
case EVENT_SPELL_TIDAL_WAVE:
me->CastSpell(me->GetVictim(), SPELL_TIDAL_WAVE, false);
events.ScheduleEvent(EVENT_SPELL_TIDAL_WAVE, 20000);
break;
case EVENT_SPELL_WATERY_GRAVE:
Talk(SAY_SUMMON_BUBLE);
if (me->HealthAbovePct(25))
{
Talk(EMOTE_WATERY_GRAVE);
me->CastCustomSpell(SPELL_WATERY_GRAVE, SPELLVALUE_MAX_TARGETS, 4, me, false);
}
else
{
Talk(EMOTE_WATERY_GLOBULES);
for (uint8 i = 0; i < 4; ++i)
me->CastSpell(me, waterGlobuleId[i], true);
}
events.ScheduleEvent(EVENT_SPELL_WATERY_GRAVE, 25000);
break;
case EVENT_SPELL_EARTHQUAKE:
Talk(EMOTE_EARTHQUAKE);
me->CastSpell(me, SPELL_EARTHQUAKE, false);
events.ScheduleEvent(EVENT_SPELL_EARTHQUAKE, urand(45000, 60000));
events.ScheduleEvent(EVENT_SUMMON_MURLOCS, 8000);
break;
case EVENT_SUMMON_MURLOCS:
Talk(SAY_SUMMON);
for (uint32 i = SPELL_SUMMON_MURLOC1; i < SPELL_SUMMON_MURLOC1 + 11; ++i)
me->CastSpell(me, i, true);
break;
Talk(EMOTE_WATERY_GLOBULES);
for (uint8 waterGlobuleId : waterGlobuleIds)
{
DoCastSelf(waterGlobuleId, true);
}
}
context.Repeat(25s);
}).Schedule(40s, [this](TaskContext context)
{
Talk(EMOTE_EARTHQUAKE);
DoMeleeAttackIfReady();
}
};
DoCastSelf(SPELL_EARTHQUAKE);
scheduler.Schedule(8s, [this](TaskContext)
{
Talk(SAY_SUMMON);
for (uint32 murlocSpellId = SPELL_SUMMON_MURLOC1; murlocSpellId < SPELL_SUMMON_MURLOC1 + 11; ++murlocSpellId)
{
DoCastSelf(murlocSpellId, true);
}
});
context.Repeat(45s, 60s);
});
}
private:
bool _recentlySpoken;
};
class spell_morogrim_tidewalker_watery_grave : public SpellScriptLoader
@@ -174,7 +149,7 @@ public:
bool Load() override
{
targetNumber = 0;
_targetNumber = 0;
return true;
}
@@ -182,8 +157,8 @@ public:
{
PreventHitDefaultEffect(effIndex);
if (Unit* target = GetHitUnit())
if (targetNumber < 4)
GetCaster()->CastSpell(target, wateryGraveId[targetNumber++], true);
if (_targetNumber < 4)
GetCaster()->CastSpell(target, wateryGraveIds[_targetNumber++], true);
}
void Register() override
@@ -192,7 +167,7 @@ public:
}
private:
uint8 targetNumber;
uint8 _targetNumber;
};
SpellScript* GetSpellScript() const override
@@ -225,6 +200,7 @@ public:
return;
// Xinef: acquire new target
// TODO: sniffs to see how this actually happens
if (Unit* target = GetHitUnit())
GetCaster()->AddThreat(target, 1000000.0f);
}
@@ -244,7 +220,7 @@ public:
void AddSC_boss_morogrim_tidewalker()
{
new boss_morogrim_tidewalker();
RegisterSerpentShrineAI(boss_morogrim_tidewalker);
new spell_morogrim_tidewalker_watery_grave();
new spell_morogrim_tidewalker_water_globule_new_target();
}

View File

@@ -89,4 +89,6 @@ inline AI* GetSerpentShrineAI(T* obj)
return GetInstanceAI<AI>(obj, SerpentShrineScriptName);
}
#define RegisterSerpentShrineAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetSerpentShrineAI)
#endif

View File

@@ -30,7 +30,8 @@
ObjectData const creatureData[] =
{
{ NPC_QUAGMIRRAN, DATA_QUAGMIRRAN }
{ NPC_QUAGMIRRAN, DATA_QUAGMIRRAN },
{ 0, 0 }
};
class instance_the_slave_pens : public InstanceMapScript

View File

@@ -23,7 +23,8 @@
ObjectData const creatureData[] =
{
{ NPC_HUNGARFEN, DATA_HUNGARFEN },
{ NPC_GHAZAN, DATA_GHAZAN }
{ NPC_GHAZAN, DATA_GHAZAN },
{ 0, 0 }
};
class instance_the_underbog : public InstanceMapScript

View File

@@ -30,7 +30,8 @@ ObjectData const creatureData[] =
{
{ NPC_DALLIAH, DATA_DALLIAH },
{ NPC_SOCCOTHRATES, DATA_SOCCOTHRATES },
{ NPC_MELLICHAR, DATA_WARDEN_MELLICHAR }
{ NPC_MELLICHAR, DATA_WARDEN_MELLICHAR },
{ 0, 0 }
};
class instance_arcatraz : public InstanceMapScript