Merge branch 'master' into Playerbot

This commit is contained in:
Yunfan Li
2023-06-22 09:53:06 +08:00
15 changed files with 488 additions and 360 deletions

View File

@@ -0,0 +1,12 @@
-- DB update 2023_06_18_00 -> 2023_06_18_01
--
UPDATE `creature_template` SET `minlevel` = 72, `maxlevel` = 72 WHERE `entry` IN (
20738, -- Chrono Lord Deja (1)
20745, -- Temporus (1)
21558, -- High Botanist Freywinn (1)
21559, -- Laj (1)
21581, -- Thorngrin the Tender (1)
21582, -- Warp Splinter (1)
21712, -- Infinite Chrono-Lord (1)
22167 -- Infinite Timereaver (1)
);

View File

@@ -0,0 +1,5 @@
-- DB update 2023_06_18_01 -> 2023_06_18_02
--
DELETE FROM `spell_script_names` WHERE `ScriptName` = 'spell_gargolmar_retalliation' AND `spell_id` = 22857;
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
(22857, 'spell_gargolmar_retalliation');

View File

@@ -0,0 +1,4 @@
-- DB update 2023_06_18_02 -> 2023_06_18_03
--
DELETE FROM `item_enchantment_template` WHERE `entry` = 5173 AND `ench` IN (29,33,91,197,231,927,1399,1913,1952,2067,2068,2069);

View File

@@ -0,0 +1,8 @@
-- DB update 2023_06_18_03 -> 2023_06_21_00
DELETE FROM `creature_template_movement` WHERE (`CreatureId` = 22355);
INSERT INTO `creature_template_movement` (`CreatureId`, `Ground`, `Swim`, `Flight`, `Rooted`, `Chase`, `Random`, `InteractionPauseTimer`) VALUES
(22355, 1, 0, 0, 1, 0, 0, 0);
DELETE FROM `smart_scripts` WHERE `entryorguid` = 22355 AND `id` IN (8);
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
(22355, 0, 8, 0, 11, 0, 100, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Netherweb Victim - On Respawn - Set Reactstate Passive');

View File

@@ -729,6 +729,7 @@ bool Player::UpdateGatherSkill(uint32 SkillId, uint32 SkillValue,
uint32 gathering_skill_gain =
sWorld->getIntConfig(CONFIG_SKILL_GAIN_GATHERING);
sScriptMgr->OnUpdateGatheringSkill(this, SkillId, SkillValue, RedLevel + 100, RedLevel + 50, RedLevel + 25, gathering_skill_gain);
// For skinning and Mining chance decrease with level. 1-74 - no decrease,
// 75-149 - 2 times, 225-299 - 8 times
@@ -806,6 +807,7 @@ bool Player::UpdateCraftSkill(uint32 spellid)
uint32 craft_skill_gain =
sWorld->getIntConfig(CONFIG_SKILL_GAIN_CRAFTING);
sScriptMgr->OnUpdateCraftingSkill(this, _spell_idx->second, SkillValue, craft_skill_gain);
return UpdateSkillPro(
_spell_idx->second->SkillLine,

View File

@@ -983,6 +983,20 @@ void ScriptMgr::OnGetMaxSkillValue(Player* player, uint32 skill, int32& result,
});
}
void ScriptMgr::OnUpdateGatheringSkill(Player *player, uint32 skillId, uint32 currentLevel, uint32 gray, uint32 green, uint32 yellow, uint32 &gain) {
ExecuteScript<PlayerScript>([&](PlayerScript* script)
{
script->OnUpdateGatheringSkill(player, skillId, gray, green, yellow, currentLevel, gain);
});
}
void ScriptMgr::OnUpdateCraftingSkill(Player *player, SkillLineAbilityEntry const* skill, uint32 currentLevel, uint32& gain) {
ExecuteScript<PlayerScript>([&](PlayerScript* script)
{
script->OnUpdateCraftingSkill(player, skill, currentLevel, gain);
});
}
bool ScriptMgr::OnUpdateFishingSkill(Player* player, int32 skill, int32 zone_skill, int32 chance, int32 roll)
{
auto ret = IsValidBoolScript<PlayerScript>([&](PlayerScript* script)

View File

@@ -1276,6 +1276,29 @@ public:
virtual void OnGetMaxSkillValue(Player* /*player*/, uint32 /*skill*/, int32& /*result*/, bool /*IsPure*/) { }
/**
* @brief This hook called before gathering skill gain is applied to the character.
*
* @param player Contains information about the Player sender
* @param skill_id Contains information about the skill line
* @param current Contains the current skill level for skill
* @param gray Contains the gray skill level for current application
* @param green Contains the green skill level for current application
* @param yellow Contains the yellow skill level for current application
* @param gain Contains the amount of points that should be added to the Player
*/
virtual void OnUpdateGatheringSkill(Player* /*player*/, uint32 /*skill_id*/, uint32 /*current*/, uint32 /*gray*/, uint32 /*green*/, uint32 /*yellow*/, uint32& /*gain*/) { }
/**
* @brief This hook is called before crafting skill gain is applied to the character.
*
* @param player Contains information about the Player sender
* @param skill Contains information about the skill line
* @param current_level Contains the current skill level for skill
* @param gain Contains the amount of points that should be added to the Player
*/
virtual void OnUpdateCraftingSkill(Player* /*player*/, SkillLineAbilityEntry const* /*skill*/, uint32 /*current_level*/, uint32& /*gain*/) { }
[[nodiscard]] virtual bool OnUpdateFishingSkill(Player* /*player*/, int32 /*skill*/, int32 /*zone_skill*/, int32 /*chance*/, int32 /*roll*/) { return true; }
[[nodiscard]] virtual bool CanAreaExploreAndOutdoor(Player* /*player*/) { return true; }
@@ -2375,6 +2398,8 @@ public: /* PlayerScript */
void OnDeleteFromDB(CharacterDatabaseTransaction trans, uint32 guid);
bool CanRepopAtGraveyard(Player* player);
void OnGetMaxSkillValue(Player* player, uint32 skill, int32& result, bool IsPure);
void OnUpdateGatheringSkill(Player* player, uint32 skillId, uint32 currentLevel, uint32 gray, uint32 green, uint32 yellow, uint32& gain);
void OnUpdateCraftingSkill(Player* player, SkillLineAbilityEntry const* skill, uint32 currentLevel, uint32& gain);
bool OnUpdateFishingSkill(Player* player, int32 skill, int32 zone_skill, int32 chance, int32 roll);
bool CanAreaExploreAndOutdoor(Player* player);
void OnVictimRewardBefore(Player* player, Player* victim, uint32& killer_title, uint32& victim_title);

View File

@@ -119,6 +119,47 @@ struct boss_malchezaar : public BossAI
{
Initialize();
_Reset();
ScheduleHealthCheckEvent(60, [&] {
me->InterruptNonMeleeSpells(false);
_phase = 2;
DoCastSelf(SPELL_EQUIP_AXES);
Talk(SAY_AXE_TOSS1);
DoCastSelf(SPELL_THRASH_AURA, true);
SetEquipmentSlots(false, EQUIP_ID_AXE, EQUIP_ID_AXE, EQUIP_NO_CHANGE);
me->SetCanDualWield(true);
me->SetAttackTime(OFF_ATTACK, (me->GetAttackTime(BASE_ATTACK) * 150) / 100);
scheduler.Schedule(5s, 10s, [this](TaskContext context)
{
DoCastVictim(SPELL_SUNDER_ARMOR);
context.Repeat();
});
scheduler.CancelGroup(GROUP_SHADOW_WORD_PAIN);
});
ScheduleHealthCheckEvent(30, [&] {
me->RemoveAurasDueToSpell(SPELL_THRASH_AURA);
Talk(SAY_AXE_TOSS2);
_phase = PHASE_THREE;
clearweapons();
me->SummonCreature(NPC_MALCHEZARS_AXE, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000);
scheduler.Schedule(20s, 30s, [this](TaskContext context)
{
DoCastRandomTarget(SPELL_AMPLIFY_DAMAGE, 1);
context.Repeat();
}).Schedule(20s, [this](TaskContext context)
{
DoCastRandomTarget(SPELL_SHADOW_WORD_PAIN);
context.SetGroup(GROUP_SHADOW_WORD_PAIN);
context.Repeat();
});
scheduler.CancelGroup(GROUP_ENFEEBLE);
});
}
void KilledUnit(Unit* /*victim*/) override
@@ -183,49 +224,6 @@ struct boss_malchezaar : public BossAI
});
}
void DamageTaken(Unit* /*done_by*/, uint32& damage, DamageEffectType, SpellSchoolMask) override
{
if (me->HealthBelowPctDamaged(60, damage) && _phase == PHASE_ONE)
{
me->InterruptNonMeleeSpells(false);
_phase = 2;
DoCastSelf( SPELL_EQUIP_AXES);
Talk(SAY_AXE_TOSS1);
DoCastSelf( SPELL_THRASH_AURA, true);
SetEquipmentSlots(false, EQUIP_ID_AXE, EQUIP_ID_AXE, EQUIP_NO_CHANGE);
me->SetCanDualWield(true);
me->SetAttackTime(OFF_ATTACK, (me->GetAttackTime(BASE_ATTACK) * 150) / 100);
scheduler.Schedule(5s, 10s, [this](TaskContext context)
{
DoCastVictim(SPELL_SUNDER_ARMOR);
context.Repeat();
});
scheduler.CancelGroup(GROUP_SHADOW_WORD_PAIN);
}
else if (me->HealthBelowPctDamaged(30, damage) && _phase == PHASE_TWO)
{
me->RemoveAurasDueToSpell(SPELL_THRASH_AURA);
Talk(SAY_AXE_TOSS2);
_phase = PHASE_THREE;
clearweapons();
me->SummonCreature(NPC_MALCHEZARS_AXE, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000);
scheduler.Schedule(20s, 30s, [this](TaskContext context)
{
DoCastRandomTarget(SPELL_AMPLIFY_DAMAGE, 1);
context.Repeat();
}).Schedule(20s, [this](TaskContext context)
{
DoCastRandomTarget(SPELL_SHADOW_WORD_PAIN);
context.SetGroup(GROUP_SHADOW_WORD_PAIN);
context.Repeat();
});;
}
}
void EnfeebleHealthEffect()
{
std::list<Unit*> targetList;

View File

@@ -56,7 +56,8 @@ public:
_currentRift = 0;
_shieldPercent = 100;
_encounterNPCs.clear();
_canSpawnPortal = true; // Delay after bosses
_noBossSpawnDelay = true; // Delay after bosses
_eventStatus = EVENT_PREPARE;
}
void CleanupInstance()
@@ -72,10 +73,24 @@ public:
_availableRiftPositions.push_back(pos);
}
// prevent getting stuck if event fails during boss break
_noBossSpawnDelay = true;
instance->LoadGrid(-2023.0f, 7121.0f);
if (Creature* medivh = GetCreature(DATA_MEDIVH))
{
medivh->DespawnOrUnsummon(0ms, 3s);
medivh->Respawn();
}
for (ObjectGuid const& guid : _encounterNPCs)
{
if (guid.GetEntry() == NPC_DP_BEAM_STALKER)
{
if (Creature* creature = instance->GetCreature(guid))
{
creature->Respawn();
}
break;
}
}
}
@@ -121,8 +136,8 @@ public:
case NPC_RIFT_LORD:
case NPC_RIFT_LORD_2:
case NPC_TIME_RIFT:
case NPC_INFINITE_ASSASIN:
case NPC_INFINITE_ASSASIN_2:
case NPC_INFINITE_ASSASSIN:
case NPC_INFINITE_ASSASSIN_2:
case NPC_INFINITE_WHELP:
case NPC_INFINITE_CHRONOMANCER:
case NPC_INFINITE_CHRONOMANCER_2:
@@ -143,14 +158,14 @@ public:
case DATA_CHRONO_LORD_DEJA:
case DATA_TEMPORUS:
{
_canSpawnPortal = false;
_noBossSpawnDelay = false;
_scheduler.Schedule(2min + 30s, [this](TaskContext)
{
_canSpawnPortal = true;
_noBossSpawnDelay = true;
ScheduleNextPortal(0s, Position(0.0f, 0.0f, 0.0f, 0.0f));
});
ScheduleNextPortal(2min + 30s, Position(0.0f, 0.0f, 0.0f, 0.0f));
break;
}
default:
@@ -163,26 +178,27 @@ public:
void OnPlayerEnter(Player* player) override
{
if (instance->GetPlayersCountExceptGMs() <= 1 && GetBossState(DATA_AEONUS) != DONE)
if (instance->GetPlayersCountExceptGMs() <= 1 && GetBossState(DATA_AEONUS) != DONE && _eventStatus != EVENT_IN_PROGRESS)
{
CleanupInstance();
}
player->SendUpdateWorldState(WORLD_STATE_BM, _currentRift > 0 ? 1 : 0);
player->SendUpdateWorldState(WORLD_STATE_BM, _eventStatus);
player->SendUpdateWorldState(WORLD_STATE_BM_SHIELD, _shieldPercent);
player->SendUpdateWorldState(WORLD_STATE_BM_RIFT, _currentRift);
}
void ScheduleNextPortal(Milliseconds time, Position lastPosition)
{
// only one rift can be scheduled at any time
_scheduler.CancelGroup(CONTEXT_GROUP_RIFTS);
_scheduler.Schedule(time, [this, lastPosition](TaskContext context)
{
if (GetCreature(DATA_MEDIVH))
{
// Spawning prevented - there's a 150s delay after a boss dies.
if (!_canSpawnPortal)
// Spawning prevented: after-boss-delay or event failed/not started or last portal spawned
if (!_noBossSpawnDelay || _eventStatus == EVENT_PREPARE || _currentRift >= 18)
{
return;
}
@@ -208,19 +224,10 @@ public:
instance->SummonCreature(NPC_TIME_RIFT, spawnPos);
// Here we check if we have available rift spots.
if (_currentRift < 18)
{
if (!_availableRiftPositions.empty())
{
context.Repeat((_currentRift >= 13 ? 2min : 90s));
}
else
{
context.Repeat(4s);
}
}
// queue next portal if group doesn't kill keepers fast enough
context.Repeat((_currentRift >= 13 ? 2min : 90s));
}
// if no rift positions are available, the next rift will be scheduled in OnCreatureRemove
}
context.SetGroup(CONTEXT_GROUP_RIFTS);
@@ -241,8 +248,8 @@ public:
case NPC_RIFT_KEEPER_MAGE:
case NPC_RIFT_LORD:
case NPC_RIFT_LORD_2:
case NPC_INFINITE_ASSASIN:
case NPC_INFINITE_ASSASIN_2:
case NPC_INFINITE_ASSASSIN:
case NPC_INFINITE_ASSASSIN_2:
case NPC_INFINITE_WHELP:
case NPC_INFINITE_CHRONOMANCER:
case NPC_INFINITE_CHRONOMANCER_2:
@@ -251,6 +258,7 @@ public:
case NPC_INFINITE_VANQUISHER:
case NPC_INFINITE_VANQUISHER_2:
case NPC_DP_BEAM_STALKER:
case NPC_DP_EMITTER_STALKER:
_encounterNPCs.insert(creature->GetGUID());
break;
}
@@ -263,7 +271,7 @@ public:
switch (creature->GetEntry())
{
case NPC_TIME_RIFT:
if (_currentRift < 18)
if (_currentRift < 18 && _noBossSpawnDelay && _eventStatus == EVENT_IN_PROGRESS)
{
if (_availableRiftPositions.size() < 3)
{
@@ -286,8 +294,8 @@ public:
case NPC_RIFT_KEEPER_MAGE:
case NPC_RIFT_LORD:
case NPC_RIFT_LORD_2:
case NPC_INFINITE_ASSASIN:
case NPC_INFINITE_ASSASIN_2:
case NPC_INFINITE_ASSASSIN:
case NPC_INFINITE_ASSASSIN_2:
case NPC_INFINITE_WHELP:
case NPC_INFINITE_CHRONOMANCER:
case NPC_INFINITE_CHRONOMANCER_2:
@@ -295,6 +303,7 @@ public:
case NPC_INFINITE_EXECUTIONER_2:
case NPC_INFINITE_VANQUISHER:
case NPC_INFINITE_VANQUISHER_2:
case NPC_DP_EMITTER_STALKER:
_encounterNPCs.erase(creature->GetGUID());
break;
}
@@ -308,27 +317,14 @@ public:
{
case DATA_MEDIVH:
{
DoUpdateWorldState(WORLD_STATE_BM, 1);
_eventStatus = EVENT_IN_PROGRESS;
DoUpdateWorldState(WORLD_STATE_BM, _eventStatus);
DoUpdateWorldState(WORLD_STATE_BM_SHIELD, _shieldPercent);
DoUpdateWorldState(WORLD_STATE_BM_RIFT, _currentRift);
ScheduleNextPortal(3s, Position(0.0f, 0.0f, 0.0f, 0.0f));
for (ObjectGuid const& guid : _encounterNPCs)
{
if (guid.GetEntry() == NPC_DP_BEAM_STALKER)
{
if (Creature* creature = instance->GetCreature(guid))
{
if (!creature->IsAlive())
{
creature->Respawn(true);
}
}
break;
}
}
break;
}
case DATA_DAMAGE_SHIELD:
@@ -348,6 +344,8 @@ public:
if (!_shieldPercent)
{
_eventStatus = EVENT_PREPARE;
if (Creature* medivh = GetCreature(DATA_MEDIVH))
{
if (medivh->IsAlive() && medivh->IsAIEnabled)
@@ -404,6 +402,12 @@ public:
GuidSet encounterNPCSCopy = _encounterNPCs;
for (ObjectGuid const& guid : encounterNPCSCopy)
{
// Don't despawn permanent visual effect NPC twice or it won't respawn correctly
if (guid.GetEntry() == NPC_DP_BEAM_STALKER)
{
continue;
}
if (Creature* creature = instance->GetCreature(guid))
{
creature->CastSpell(creature, SPELL_TELEPORT_VISUAL, true);
@@ -412,6 +416,16 @@ public:
}
_scheduler.CancelAll();
// Step 4 - Schedule instance cleanup without player interaction
_scheduler.Schedule(300s, [this](TaskContext)
{
CleanupInstance();
DoUpdateWorldState(WORLD_STATE_BM, _eventStatus);
DoUpdateWorldState(WORLD_STATE_BM_SHIELD, _shieldPercent);
DoUpdateWorldState(WORLD_STATE_BM_RIFT, _currentRift);
});
});
});
});
@@ -447,7 +461,8 @@ public:
GuidSet _encounterNPCs;
uint8 _currentRift;
int8 _shieldPercent;
bool _canSpawnPortal;
bool _noBossSpawnDelay;
EventStatus _eventStatus;
TaskScheduler _scheduler;
};
};

View File

@@ -43,9 +43,9 @@ enum medivhMisc
EVENT_OUTRO_8 = 17
};
static std::vector<uint32> firstWave = { NPC_INFINITE_ASSASIN, NPC_INFINITE_WHELP, NPC_INFINITE_CHRONOMANCER };
static std::vector<uint32> secondWave = { NPC_INFINITE_EXECUTIONER, NPC_INFINITE_CHRONOMANCER, NPC_INFINITE_WHELP, NPC_INFINITE_ASSASIN };
static std::vector<uint32> thirdWave = { NPC_INFINITE_EXECUTIONER, NPC_INFINITE_VANQUISHER, NPC_INFINITE_CHRONOMANCER, NPC_INFINITE_ASSASIN };
static std::vector<uint32> firstWave = { NPC_INFINITE_ASSASSIN, NPC_INFINITE_WHELP, NPC_INFINITE_CHRONOMANCER };
static std::vector<uint32> secondWave = { NPC_INFINITE_EXECUTIONER, NPC_INFINITE_CHRONOMANCER, NPC_INFINITE_WHELP, NPC_INFINITE_ASSASSIN };
static std::vector<uint32> thirdWave = { NPC_INFINITE_EXECUTIONER, NPC_INFINITE_VANQUISHER, NPC_INFINITE_CHRONOMANCER, NPC_INFINITE_ASSASSIN };
class NpcRunToHome : public BasicEvent
{
@@ -323,8 +323,8 @@ struct npc_time_rift : public NullCreatureAI
{
switch (entry)
{
case NPC_INFINITE_ASSASIN:
entry = NPC_INFINITE_ASSASIN_2;
case NPC_INFINITE_ASSASSIN:
entry = NPC_INFINITE_ASSASSIN_2;
break;
case NPC_INFINITE_CHRONOMANCER:
entry = NPC_INFINITE_CHRONOMANCER_2;

View File

@@ -36,13 +36,10 @@ enum DataTypes
MAX_ENCOUNTER = 3,
DATA_MEDIVH = 10,
DATA_RIFT_KILLED = 11,
DATA_DAMAGE_SHIELD = 12,
DATA_SHIELD_PERCENT = 13,
DATA_RIFT_NUMBER = 14,
DATA_SUMMONED_NPC = 20,
DATA_DELETED_NPC = 21
DATA_RIFT_NUMBER = 14
};
enum WorldStateIds
@@ -52,6 +49,12 @@ enum WorldStateIds
WORLD_STATE_BM_RIFT = 2784
};
enum EventStatus
{
EVENT_PREPARE = 0,
EVENT_IN_PROGRESS = 1
};
enum QuestIds
{
QUEST_OPENING_PORTAL = 10297,
@@ -75,13 +78,13 @@ enum CreatureIds
NPC_INFINITE_TIMEREAVER = 21698,
NPC_AEONUS = 17881,
NPC_INFINITE_ASSASIN = 17835,
NPC_INFINITE_ASSASSIN = 17835,
NPC_INFINITE_WHELP = 21818,
NPC_INFINITE_CHRONOMANCER = 17892,
NPC_INFINITE_EXECUTIONER = 18994,
NPC_INFINITE_VANQUISHER = 18995,
NPC_INFINITE_ASSASIN_2 = 21137,
NPC_INFINITE_ASSASSIN_2 = 21137,
NPC_INFINITE_CHRONOMANCER_2 = 21136,
NPC_INFINITE_EXECUTIONER_2 = 21138,
NPC_INFINITE_VANQUISHER_2 = 21139,

View File

@@ -44,6 +44,7 @@ enum blySays
enum blySpells
{
SPELL_BLYS_BAND_ESCAPE = 11365,
SPELL_SHIELD_BASH = 11972,
SPELL_REVENGE = 12170
};
@@ -64,6 +65,7 @@ public:
void InitializeAI() override
{
ableToPortHome = false;
startedFight = false;
me->SetFaction(FACTION_FRIENDLY);
postGossipStep = 0;
@@ -74,16 +76,33 @@ public:
InstanceScript* instance;
bool startedFight;
bool ableToPortHome;
uint32 postGossipStep;
uint32 Text_Timer;
uint32 ShieldBash_Timer;
uint32 Revenge_Timer; //this is wrong, spell should never be used unless me->GetVictim() dodge, parry or block attack. Trinity support required.
uint32 Revenge_Timer; //this is wrong, spell should never be used unless me->GetVictim() dodge, parry or block attack. Trinity support required.
uint32 Porthome_Timer;
ObjectGuid PlayerGUID;
void Reset() override
{
ShieldBash_Timer = 5000;
Revenge_Timer = 8000;
Porthome_Timer = 156000;
ableToPortHome = false;
startedFight = false;
}
void EnterEvadeMode(EvadeReason /*reason*/) override
{
if (ableToPortHome)
return;
if (instance->GetData(DATA_PYRAMID) == PYRAMID_KILLED_ALL_TROLLS)
{
ableToPortHome = true;
Porthome_Timer = 156000;
}
}
void MovementInform(uint32 type, uint32 /*id*/) override
@@ -112,6 +131,7 @@ public:
switch (postGossipStep)
{
case 1:
startedFight = true;
//weegli doesn't fight - he goes & blows up the door
if (Creature* pWeegli = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_WEEGLI)))
{
@@ -128,6 +148,7 @@ public:
me->SetFaction(FACTION_MONSTER);
Player* target = ObjectAccessor::GetPlayer(*me, PlayerGUID);
switchFactionIfAlive(NPC_WEEGLI, target);
switchFactionIfAlive(NPC_RAVEN, target);
switchFactionIfAlive(NPC_ORO, target);
switchFactionIfAlive(NPC_MURTA, target);
@@ -146,6 +167,37 @@ public:
}
}
if (Porthome_Timer <= diff && ableToPortHome == true)
{
if (Creature* weegli = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_WEEGLI)))
{
weegli->CastSpell(weegli, SPELL_BLYS_BAND_ESCAPE);
weegli->DespawnOrUnsummon(10000);
}
if (Creature* raven = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_RAVEN)))
{
raven->CastSpell(raven, SPELL_BLYS_BAND_ESCAPE);
raven->DespawnOrUnsummon(10000);
}
if (Creature* oro = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_ORO)))
{
oro->CastSpell(oro, SPELL_BLYS_BAND_ESCAPE);
oro->DespawnOrUnsummon(10000);
}
if (Creature* murta = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_MURTA)))
{
murta->CastSpell(murta, SPELL_BLYS_BAND_ESCAPE);
murta->DespawnOrUnsummon(10000);
}
DoCastSelf(SPELL_BLYS_BAND_ESCAPE);
me->DespawnOrUnsummon(10000);
Porthome_Timer = 156000; //set timer back so that the event doesn't keep triggering
}
else
{
Porthome_Timer -= diff;
}
if (!UpdateVictim())
{
return;
@@ -176,6 +228,7 @@ public:
void DoAction(int32 /*param*/) override
{
ableToPortHome = false;
postGossipStep = 1;
Text_Timer = 0;
}
@@ -211,9 +264,8 @@ public:
void sGossipHello(Player* player) override
{
if (instance->GetData(DATA_PYRAMID) >= PYRAMID_DESTROY_GATES && !startedFight)
if (instance->GetData(DATA_PYRAMID) >= PYRAMID_MOVED_DOWNSTAIRS && !startedFight)
{
startedFight = true;
AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_BLY, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
SendGossipMenuFor(player, 1517, me->GetGUID());
}
@@ -261,6 +313,17 @@ public:
instance->SetData(DATA_PYRAMID, PYRAMID_CAGES_OPEN);
//setting gossip option as soon as the cages open
if(Creature* bly = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_BLY)))
{
bly->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP);
}
if(Creature* weegli = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_WEEGLI)))
{
weegli->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP);
}
//set bly & co to aggressive & start moving to top of stairs
initBlyCrewMember(NPC_BLY, 1884.99f, 1263, 41.52f);
initBlyCrewMember(NPC_RAVEN, 1882.5f, 1263, 41.52f);
@@ -281,15 +344,6 @@ public:
crew->GetMotionMaster()->MovePoint(1, { x, y, z, 4.78f });
crew->SetFaction(FACTION_ESCORT_N_NEUTRAL_ACTIVE);
switch (entry)
{
case NPC_BLY:
case NPC_WEEGLI:
crew->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP);
break;
default:
break;
}
}
}
};
@@ -429,13 +483,13 @@ public:
{
if (instance->GetData(DATA_PYRAMID) == PYRAMID_CAGES_OPEN)
{
me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP);
instance->SetData(DATA_PYRAMID, PYRAMID_ARRIVED_AT_STAIR);
Talk(SAY_WEEGLI_OHNO);
}
else if (instance->GetData(DATA_PYRAMID) == PYRAMID_KILLED_ALL_TROLLS)
else if (instance->GetData(DATA_PYRAMID) >= PYRAMID_KILLED_ALL_TROLLS && instance->GetData(DATA_PYRAMID) < PYRAMID_DESTROY_GATES)
{
instance->SetData(DATA_PYRAMID, PYRAMID_MOVED_DOWNSTAIRS);
me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP);
}
else if (instance->GetData(DATA_PYRAMID) == PYRAMID_DESTROY_GATES)
{
@@ -452,13 +506,13 @@ public:
if (instance->GetData(DATA_PYRAMID) == PYRAMID_CAGES_OPEN)
{
me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP);
instance->SetData(DATA_PYRAMID, PYRAMID_ARRIVED_AT_STAIR);
Talk(SAY_WEEGLI_OHNO);
}
else if (instance->GetData(DATA_PYRAMID) == PYRAMID_KILLED_ALL_TROLLS)
else if (instance->GetData(DATA_PYRAMID) >= PYRAMID_KILLED_ALL_TROLLS && instance->GetData(DATA_PYRAMID) < PYRAMID_DESTROY_GATES)
{
instance->SetData(DATA_PYRAMID, PYRAMID_MOVED_DOWNSTAIRS);
me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP);
}
else if (instance->GetData(DATA_PYRAMID) == PYRAMID_DESTROY_GATES)
{
@@ -476,10 +530,6 @@ public:
me->SetHomePosition(1858.57f, 1146.35f, 14.745f, 3.85f);
Talk(SAY_WEEGLI_OK_I_GO);
instance->SetData(DATA_PYRAMID, PYRAMID_DESTROY_GATES);
if (Creature* sergeantBly = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_BLY)))
{
sergeantBly->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP);
}
}
}
@@ -501,6 +551,7 @@ public:
switch (instance->GetData(DATA_PYRAMID))
{
case PYRAMID_MOVED_DOWNSTAIRS:
case PYRAMID_KILLED_ALL_TROLLS:
AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_WEEGLI, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
SendGossipMenuFor(player, 1514, me->GetGUID()); //if event can proceed to end
break;
@@ -508,7 +559,7 @@ public:
SendGossipMenuFor(player, 1511, me->GetGUID()); //if event not started
break;
default:
SendGossipMenuFor(player, 1513, me->GetGUID()); //if event are in progress
SendGossipMenuFor(player, 1513, me->GetGUID()); //if event is in progress
}
}
};

View File

@@ -58,17 +58,6 @@ enum Spells
SPELL_STONED = 33652,
};
enum Events
{
EVENT_GROWTH = 1,
EVENT_CAVE_IN = 2,
EVENT_GROUND_SLAM = 3,
EVENT_HURTFUL_STRIKE = 4,
EVENT_REVERBERATION = 5,
EVENT_SHATTER = 6,
EVENT_RECENTLY_SPOKEN = 7
};
struct boss_gruul : public BossAI
{
boss_gruul(Creature* creature) : BossAI(creature, DATA_GRUUL) { }
@@ -76,7 +65,8 @@ struct boss_gruul : public BossAI
void Reset() override
{
_Reset();
_caveInTimer = 29000;
_recentlySpoken = false;
_caveInTimer = 29000ms;
}
void JustEngagedWith(Unit* /*who*/) override
@@ -84,20 +74,61 @@ struct boss_gruul : public BossAI
_JustEngagedWith();
Talk(SAY_AGGRO);
events.ScheduleEvent(EVENT_GROWTH, 30000);
events.ScheduleEvent(EVENT_CAVE_IN, _caveInTimer);
events.ScheduleEvent(EVENT_REVERBERATION, 20000);
events.ScheduleEvent(EVENT_HURTFUL_STRIKE, 10000);
events.ScheduleEvent(EVENT_GROUND_SLAM, 35000);
scheduler.Schedule(30300ms, [this](TaskContext context)
{
Talk(EMOTE_GROW);
DoCastSelf(SPELL_GROWTH);
context.Repeat(30300ms);
}).Schedule(_caveInTimer, [this](TaskContext context)
{
DoCastRandomTarget(SPELL_CAVE_IN);
if (_caveInTimer > 4000ms)
{
_caveInTimer = _caveInTimer - 1500ms;
}
context.Repeat(_caveInTimer);
}).Schedule(20s, [this](TaskContext context)
{
DoCastSelf(SPELL_REVERBERATION);
context.Repeat(22s);
}).Schedule(10s, [this](TaskContext context)
{
if (Unit* target = SelectTarget(SelectTargetMethod::MaxThreat, 1, 5.0f))
{
DoCast(target, SPELL_HURTFUL_STRIKE);
}
else
{
DoCastVictim(SPELL_HURTFUL_STRIKE);
}
context.Repeat(15s);
}).Schedule(35s, [this](TaskContext context)
{
Talk(SAY_SLAM);
DoCastSelf(SPELL_GROUND_SLAM);
scheduler.DelayAll(9701ms);
scheduler.Schedule(9700ms, [this](TaskContext)
{
Talk(SAY_SHATTER);
me->RemoveAurasDueToSpell(SPELL_LOOK_AROUND);
DoCastSelf(SPELL_SHATTER);
});
context.Repeat(60s);
});
}
void KilledUnit(Unit* /*who*/) override
{
if (events.GetNextEventTime(EVENT_RECENTLY_SPOKEN) == 0)
if (!_recentlySpoken)
{
events.ScheduleEvent(EVENT_RECENTLY_SPOKEN, 5000);
Talk(SAY_SLAY);
_recentlySpoken = true;
}
scheduler.Schedule(5s, [this](TaskContext)
{
_recentlySpoken = false;
});
}
void JustDied(Unit* /*killer*/) override
@@ -111,52 +142,7 @@ struct boss_gruul : public BossAI
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case EVENT_GROWTH:
Talk(EMOTE_GROW);
DoCast(me, SPELL_GROWTH);
events.ScheduleEvent(EVENT_GROWTH, 30000);
break;
case EVENT_CAVE_IN:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
me->CastSpell(target, SPELL_CAVE_IN, false);
if (_caveInTimer >= 4000)
_caveInTimer -= 1500;
events.ScheduleEvent(EVENT_CAVE_IN, _caveInTimer);
break;
case EVENT_REVERBERATION:
me->CastSpell(me, SPELL_REVERBERATION, false);
events.ScheduleEvent(EVENT_REVERBERATION, 22000);
break;
case EVENT_HURTFUL_STRIKE:
if (Unit* target = SelectTarget(SelectTargetMethod::MaxThreat, 1, 5.0f))
{
me->CastSpell(target, SPELL_HURTFUL_STRIKE, false);
}
else
{
me->CastSpell(me->GetVictim(), SPELL_HURTFUL_STRIKE, false);
}
events.ScheduleEvent(EVENT_HURTFUL_STRIKE, 15000);
break;
case EVENT_GROUND_SLAM:
Talk(SAY_SLAM);
me->CastSpell(me, SPELL_GROUND_SLAM, false);
events.DelayEvents(8001);
events.ScheduleEvent(EVENT_GROUND_SLAM, 60000);
events.ScheduleEvent(EVENT_SHATTER, 8000);
break;
case EVENT_SHATTER:
Talk(SAY_SHATTER);
me->RemoveAurasDueToSpell(SPELL_LOOK_AROUND);
me->CastSpell(me, SPELL_SHATTER, false);
break;
}
scheduler.Update(diff);
if (!me->HasUnitState(UNIT_STATE_ROOT))
{
@@ -165,7 +151,8 @@ struct boss_gruul : public BossAI
}
private:
uint32 _caveInTimer;
std::chrono::milliseconds _caveInTimer;
bool _recentlySpoken;
};
struct npc_invisible_tractor_beam_source : public NullCreatureAI

View File

@@ -17,6 +17,7 @@
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "TaskScheduler.h"
#include "gruuls_lair.h"
enum HighKingMaulgar
@@ -59,39 +60,49 @@ enum HighKingMaulgar
ACTION_ADD_DEATH = 1
};
enum HKMEvents
{
EVENT_RECENTLY_SPOKEN = 1,
EVENT_ARCING_SMASH = 2,
EVENT_MIGHTY_BLOW = 3,
EVENT_WHIRLWIND = 4,
EVENT_CHARGING = 5,
EVENT_ROAR = 6,
EVENT_CHECK_HEALTH = 7,
EVENT_ADD_ABILITY1 = 10,
EVENT_ADD_ABILITY2 = 11,
EVENT_ADD_ABILITY3 = 12,
EVENT_ADD_ABILITY4 = 13
};
struct boss_high_king_maulgar : public BossAI
{
boss_high_king_maulgar(Creature* creature) : BossAI(creature, DATA_MAULGAR) { }
boss_high_king_maulgar(Creature* creature) : BossAI(creature, DATA_MAULGAR)
{
scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
void Reset() override
{
_Reset();
_recentlySpoken = false;
me->SetLootMode(0);
ScheduleHealthCheckEvent(50, [&]{
Talk(SAY_ENRAGE);
DoCastSelf(SPELL_FLURRY);
scheduler.Schedule(0ms, [this](TaskContext context)
{
DoCastRandomTarget(SPELL_BERSERKER_C);
context.Repeat(35s);
}).Schedule(0ms, [this](TaskContext context)
{
DoCastSelf(SPELL_ROAR);
context.Repeat(20600ms, 29100ms);
});
});
}
void KilledUnit(Unit* /*victim*/) override
{
if (events.GetNextEventTime(EVENT_RECENTLY_SPOKEN) == 0)
if(!_recentlySpoken)
{
events.ScheduleEvent(EVENT_RECENTLY_SPOKEN, 5s);
Talk(SAY_SLAY);
_recentlySpoken = true;
}
scheduler.Schedule(5s, [this](TaskContext)
{
_recentlySpoken = false;
});
}
void JustDied(Unit* /*killer*/) override
@@ -126,10 +137,20 @@ struct boss_high_king_maulgar : public BossAI
_JustEngagedWith();
Talk(SAY_AGGRO);
events.ScheduleEvent(EVENT_ARCING_SMASH, 10s);
events.ScheduleEvent(EVENT_MIGHTY_BLOW, 15s);
events.ScheduleEvent(EVENT_WHIRLWIND, 54s);
events.ScheduleEvent(EVENT_CHECK_HEALTH, 500ms);
scheduler.Schedule(9500ms, [this](TaskContext context)
{
DoCastVictim(SPELL_ARCING_SMASH);
context.Repeat(9500ms, 12s);
}).Schedule(15700ms, [this](TaskContext context)
{
DoCastVictim(SPELL_MIGHTY_BLOW);
context.Repeat(16200ms, 19s);
}).Schedule(67000ms, [this](TaskContext context)
{
scheduler.DelayAll(15s);
DoCastSelf(SPELL_WHIRLWIND);
context.Repeat(45s, 60s);
});
}
void UpdateAI(uint32 diff) override
@@ -137,49 +158,12 @@ struct boss_high_king_maulgar : public BossAI
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case EVENT_ARCING_SMASH:
me->CastSpell(me->GetVictim(), SPELL_ARCING_SMASH, false);
events.ScheduleEvent(EVENT_ARCING_SMASH, 10s);
break;
case EVENT_MIGHTY_BLOW:
me->CastSpell(me->GetVictim(), SPELL_MIGHTY_BLOW, false);
events.ScheduleEvent(EVENT_MIGHTY_BLOW, 15s);
break;
case EVENT_WHIRLWIND:
events.DelayEvents(15s);
me->CastSpell(me, SPELL_WHIRLWIND, false);
events.ScheduleEvent(EVENT_WHIRLWIND, 54s);
break;
case EVENT_CHECK_HEALTH:
if (me->HealthBelowPct(50))
{
Talk(SAY_ENRAGE);
me->CastSpell(me, SPELL_FLURRY, true);
events.ScheduleEvent(EVENT_CHARGING, 0s);
events.ScheduleEvent(EVENT_ROAR, 30s);
break;
}
events.ScheduleEvent(EVENT_CHECK_HEALTH, 500ms);
break;
case EVENT_ROAR:
me->CastSpell(me, SPELL_ROAR, false);
events.ScheduleEvent(EVENT_ROAR, 40s);
break;
case EVENT_CHARGING:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1))
me->CastSpell(target, SPELL_BERSERKER_C, false);
events.ScheduleEvent(EVENT_CHARGING, 35s);
break;
}
scheduler.Update(diff);
DoMeleeAttackIfReady();
}
private:
bool _recentlySpoken;
};
struct boss_olm_the_summoner : public ScriptedAI
@@ -187,15 +171,18 @@ struct boss_olm_the_summoner : public ScriptedAI
boss_olm_the_summoner(Creature* creature) : ScriptedAI(creature), summons(me)
{
instance = creature->GetInstanceScript();
_scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
EventMap events;
SummonList summons;
InstanceScript* instance;
void Reset() override
{
events.Reset();
_scheduler.CancelAll();
summons.DespawnAll();
instance->SetBossState(DATA_MAULGAR, NOT_STARTED);
}
@@ -214,9 +201,22 @@ struct boss_olm_the_summoner : public ScriptedAI
me->SetInCombatWithZone();
instance->SetBossState(DATA_MAULGAR, IN_PROGRESS);
events.ScheduleEvent(EVENT_ADD_ABILITY1, 500ms);
events.ScheduleEvent(EVENT_ADD_ABILITY2, 5s);
events.ScheduleEvent(EVENT_ADD_ABILITY3, 6500ms);
_scheduler.Schedule(1200ms, [this](TaskContext context)
{
DoCastSelf(SPELL_SUMMON_WFH);
context.Repeat(48500ms);
}).Schedule(6050ms, [this](TaskContext context)
{
DoCastVictim(SPELL_DARK_DECAY);
context.Repeat(6050ms);
}).Schedule(6500ms, [this](TaskContext context)
{
if (me->HealthBelowPct(90))
{
DoCastRandomTarget(SPELL_DEATH_COIL);
}
context.Repeat(6s, 13500ms);
});
}
void JustDied(Unit* /*killer*/) override
@@ -234,27 +234,12 @@ struct boss_olm_the_summoner : public ScriptedAI
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
_scheduler.Update(diff);
switch (events.ExecuteEvent())
{
case EVENT_ADD_ABILITY1:
me->CastSpell(me, SPELL_SUMMON_WFH, false);
events.ScheduleEvent(EVENT_ADD_ABILITY1, 50s);
break;
case EVENT_ADD_ABILITY2:
DoCastVictim(SPELL_DARK_DECAY);
events.ScheduleEvent(EVENT_ADD_ABILITY2, 6500ms);
break;
case EVENT_ADD_ABILITY3:
DoCastRandomTarget(SPELL_DEATH_COIL);
events.ScheduleEvent(EVENT_ADD_ABILITY3, 7s);
break;
}
DoMeleeAttackIfReady();
}
private:
TaskScheduler _scheduler;
};
struct boss_kiggler_the_crazed : public ScriptedAI
@@ -262,14 +247,17 @@ struct boss_kiggler_the_crazed : public ScriptedAI
boss_kiggler_the_crazed(Creature* creature) : ScriptedAI(creature)
{
instance = creature->GetInstanceScript();
_scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
EventMap events;
InstanceScript* instance;
void Reset() override
{
events.Reset();
_scheduler.CancelAll();
instance->SetBossState(DATA_MAULGAR, NOT_STARTED);
}
@@ -278,10 +266,35 @@ struct boss_kiggler_the_crazed : public ScriptedAI
me->SetInCombatWithZone();
instance->SetBossState(DATA_MAULGAR, IN_PROGRESS);
events.ScheduleEvent(EVENT_ADD_ABILITY1, 1500ms);
events.ScheduleEvent(EVENT_ADD_ABILITY2, 5s);
events.ScheduleEvent(EVENT_ADD_ABILITY3, 25s);
events.ScheduleEvent(EVENT_ADD_ABILITY4, 30s);
_scheduler.Schedule(1200ms, [this](TaskContext context)
{
DoCastVictim(SPELL_LIGHTNING_BOLT);
context.Repeat(2400ms);
}).Schedule(29s, [this](TaskContext context)
{
DoCastVictim(SPELL_ARCANE_SHOCK);
context.Repeat(7200ms, 20600ms);
}).Schedule(23s, [this](TaskContext context)
{
//changed to work similarly to Ikiss poly
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(SPELL_GREATER_POLYMORPH);
if (Unit* target = SelectTarget(SelectTargetMethod::MaxThreat, 1, [&]
(Unit* target) -> bool
{
return target && !target->IsImmunedToSpell(spellInfo);
}))
{
DoCast(target, SPELL_GREATER_POLYMORPH);
}
context.Repeat(10900ms);
}).Schedule(30s, [this](TaskContext context)
{
if (me->SelectNearestPlayer(30.0f))
{
DoCastAOE(SPELL_ARCANE_EXPLOSION);
}
context.Repeat(30s);
});
}
void JustDied(Unit* /*killer*/) override
@@ -294,36 +307,12 @@ struct boss_kiggler_the_crazed : public ScriptedAI
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case EVENT_ADD_ABILITY1:
DoCastVictim(SPELL_LIGHTNING_BOLT);
events.ScheduleEvent(EVENT_ADD_ABILITY1, 1500ms);
break;
case EVENT_ADD_ABILITY2:
DoCastVictim(SPELL_ARCANE_SHOCK);
events.ScheduleEvent(EVENT_ADD_ABILITY2, 5s);
break;
case EVENT_ADD_ABILITY3:
if (Unit* target = SelectTarget(SelectTargetMethod::MaxThreat, 1)) //target method should perhaps change
me->CastSpell(target, SPELL_GREATER_POLYMORPH, false);
events.ScheduleEvent(EVENT_ADD_ABILITY3, 11s);
break;
case EVENT_ADD_ABILITY4:
if (me->SelectNearestPlayer(30.0f))
{
DoCastAOE(SPELL_ARCANE_EXPLOSION);
}
events.ScheduleEvent(EVENT_ADD_ABILITY4, 30s);
break;
}
_scheduler.Update(diff);
DoMeleeAttackIfReady();
}
private:
TaskScheduler _scheduler;
};
struct boss_blindeye_the_seer : public ScriptedAI
@@ -331,14 +320,17 @@ struct boss_blindeye_the_seer : public ScriptedAI
boss_blindeye_the_seer(Creature* creature) : ScriptedAI(creature)
{
instance = creature->GetInstanceScript();
_scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
EventMap events;
InstanceScript* instance;
void Reset() override
{
events.Reset();
_scheduler.CancelAll();
instance->SetBossState(DATA_MAULGAR, NOT_STARTED);
}
@@ -347,9 +339,22 @@ struct boss_blindeye_the_seer : public ScriptedAI
me->SetInCombatWithZone();
instance->SetBossState(DATA_MAULGAR, IN_PROGRESS);
events.ScheduleEvent(EVENT_ADD_ABILITY1, 11s);
events.ScheduleEvent(EVENT_ADD_ABILITY2, 30s);
events.ScheduleEvent(EVENT_ADD_ABILITY3, 31s);
_scheduler.Schedule(7200ms, [this](TaskContext context)
{
if (Unit* target = DoSelectLowestHpFriendly(60.0f, 50000))
{
DoCast(target, SPELL_HEAL);
}
context.Repeat(7200ms);
}).Schedule(37500s, [this](TaskContext context)
{
DoCastSelf(SPELL_GREATER_PW_SHIELD);
_scheduler.Schedule(1200ms, [this](TaskContext)
{
DoCastSelf(SPELL_PRAYER_OH);
});
context.Repeat(54500ms, 63s);
});
}
void JustDied(Unit* /*killer*/) override
@@ -362,31 +367,12 @@ struct boss_blindeye_the_seer : public ScriptedAI
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case EVENT_ADD_ABILITY1:
if (Unit* target = DoSelectLowestHpFriendly(60.0f, 50000))
{
DoCast(target, SPELL_HEAL);
}
events.ScheduleEvent(EVENT_ADD_ABILITY1, 6s);
break;
case EVENT_ADD_ABILITY2:
DoCastSelf(SPELL_GREATER_PW_SHIELD);
events.ScheduleEvent(EVENT_ADD_ABILITY2, 30s);
break;
case EVENT_ADD_ABILITY3:
me->CastSpell(me, SPELL_PRAYER_OH, false);
events.ScheduleEvent(EVENT_ADD_ABILITY3, 30s);
break;
}
_scheduler.Update(diff);
DoMeleeAttackIfReady();
}
private:
TaskScheduler _scheduler;
};
struct boss_krosh_firehand : public ScriptedAI
@@ -394,14 +380,17 @@ struct boss_krosh_firehand : public ScriptedAI
boss_krosh_firehand(Creature* creature) : ScriptedAI(creature)
{
instance = creature->GetInstanceScript();
_scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
EventMap events;
InstanceScript* instance;
void Reset() override
{
events.Reset();
_scheduler.CancelAll();
instance->SetBossState(DATA_MAULGAR, NOT_STARTED);
}
@@ -419,9 +408,22 @@ struct boss_krosh_firehand : public ScriptedAI
me->SetInCombatWithZone();
instance->SetBossState(DATA_MAULGAR, IN_PROGRESS);
events.ScheduleEvent(EVENT_ADD_ABILITY1, 1500ms); //spellshield
events.ScheduleEvent(EVENT_ADD_ABILITY2, 3500ms); //greater fireball
events.ScheduleEvent(EVENT_ADD_ABILITY3, 8s); //blast wave (needs to check for players in range)
_scheduler.Schedule(1200ms, [this](TaskContext context)
{
DoCastSelf(SPELL_SPELLSHIELD);
context.Repeat(30300ms);
}).Schedule(3600ms, [this](TaskContext context)
{
DoCastVictim(SPELL_GREATER_FIREBALL);
context.Repeat(3600ms);
}).Schedule(7200ms, [this](TaskContext context)
{
if (me->SelectNearestPlayer(15.0f))
{
DoCastAOE(SPELL_BLAST_WAVE);
}
context.Repeat(7200ms);
});
}
void JustDied(Unit* /*killer*/) override
@@ -434,31 +436,12 @@ struct boss_krosh_firehand : public ScriptedAI
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case EVENT_ADD_ABILITY1:
DoCastSelf(SPELL_SPELLSHIELD);
events.ScheduleEvent(EVENT_ADD_ABILITY1, 30s);
break;
case EVENT_ADD_ABILITY2:
DoCastVictim(SPELL_GREATER_FIREBALL);
events.ScheduleEvent(EVENT_ADD_ABILITY2, 1s);
break;
case EVENT_ADD_ABILITY3:
if (me->SelectNearestPlayer(15.0f))
{
DoCastAOE(SPELL_BLAST_WAVE);
}
events.ScheduleEvent(EVENT_ADD_ABILITY3, 8s);
break;
}
_scheduler.Update(diff);
DoMeleeAttackIfReady();
}
private:
TaskScheduler _scheduler;
};
void AddSC_boss_high_king_maulgar()

View File

@@ -144,7 +144,28 @@ private:
};
class spell_gargolmar_retalliation : public AuraScript
{
PrepareAuraScript(spell_gargolmar_retalliation);
bool CheckProc(ProcEventInfo& eventInfo)
{
if (!eventInfo.GetActor() || !eventInfo.GetProcTarget())
{
return false;
}
return GetTarget()->isInFront(eventInfo.GetActor(), M_PI);
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_gargolmar_retalliation::CheckProc);
}
};
void AddSC_boss_watchkeeper_gargolmar()
{
RegisterHellfireRampartsCreatureAI(boss_watchkeeper_gargolmar);
RegisterSpellScript(spell_gargolmar_retalliation);
}