Merge branch 'azerothcore:master' into Playerbot

This commit is contained in:
ZhengPeiRu21
2023-04-18 09:28:55 -06:00
committed by GitHub
21 changed files with 434 additions and 220 deletions

View File

@@ -597,15 +597,15 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
if (caster && caster != me) // Areatrigger cast
{
caster->CastSpell(target->ToUnit(), e.action.cast.spell, (e.action.cast.flags & SMARTCAST_TRIGGERED));
caster->CastSpell(target->ToUnit(), e.action.cast.spell, (e.action.cast.castFlags & SMARTCAST_TRIGGERED));
}
else if (me && (!(e.action.cast.flags & SMARTCAST_AURA_NOT_PRESENT) || !target->ToUnit()->HasAura(e.action.cast.spell)))
else if (me && (!(e.action.cast.castFlags & SMARTCAST_AURA_NOT_PRESENT) || !target->ToUnit()->HasAura(e.action.cast.spell)))
{
if (e.action.cast.flags & SMARTCAST_INTERRUPT_PREVIOUS)
if (e.action.cast.castFlags & SMARTCAST_INTERRUPT_PREVIOUS)
me->InterruptNonMeleeSpells(false);
// Xinef: flag usable only if caster has max dist set
if ((e.action.cast.flags & SMARTCAST_COMBAT_MOVE) && GetCasterMaxDist() > 0.0f && me->GetMaxPower(GetCasterPowerType()) > 0)
if ((e.action.cast.castFlags & SMARTCAST_COMBAT_MOVE) && GetCasterMaxDist() > 0.0f && me->GetMaxPower(GetCasterPowerType()) > 0)
{
// Xinef: check mana case only and operate movement accordingly, LoS and range is checked in targetet movement generator
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(e.action.cast.spell);
@@ -623,12 +623,45 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
}
}
me->CastSpell(target->ToUnit(), e.action.cast.spell, (e.action.cast.flags & SMARTCAST_TRIGGERED));
me->CastSpell(target->ToUnit(), e.action.cast.spell, (e.action.cast.castFlags & SMARTCAST_TRIGGERED));
}
}
break;
}
case SMART_ACTION_SELF_CAST:
{
if (targets.empty())
break;
if (e.action.cast.targetsLimit)
Acore::Containers::RandomResize(targets, e.action.cast.targetsLimit);
TriggerCastFlags triggerFlags = TRIGGERED_NONE;
if (e.action.cast.castFlags & SMARTCAST_TRIGGERED)
{
if (e.action.cast.triggerFlags)
triggerFlags = TriggerCastFlags(e.action.cast.triggerFlags);
else
triggerFlags = TRIGGERED_FULL_MASK;
}
for (WorldObject* target : targets)
{
Unit* uTarget = target->ToUnit();
if (!uTarget)
continue;
if (!(e.action.cast.castFlags & SMARTCAST_AURA_NOT_PRESENT) || !uTarget->HasAura(e.action.cast.spell))
{
if (e.action.cast.castFlags & SMARTCAST_INTERRUPT_PREVIOUS)
uTarget->InterruptNonMeleeSpells(false);
uTarget->CastSpell(uTarget, e.action.cast.spell, triggerFlags);
}
}
break;
}
case SMART_ACTION_INVOKER_CAST:
{
Unit* tempLastInvoker = GetLastInvoker(unit); // xinef: can be used for area triggers cast
@@ -638,7 +671,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
if (targets.empty())
break;
if (e.action.cast.targetsLimit > 0 && targets.size() > e.action.cast.targetsLimit)
if (e.action.cast.targetsLimit)
Acore::Containers::RandomResize(targets, e.action.cast.targetsLimit);
for (WorldObject* target : targets)
@@ -646,12 +679,12 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
if (!IsUnit(target))
continue;
if (!(e.action.cast.flags & SMARTCAST_AURA_NOT_PRESENT) || !target->ToUnit()->HasAura(e.action.cast.spell))
if (!(e.action.cast.castFlags & SMARTCAST_AURA_NOT_PRESENT) || !target->ToUnit()->HasAura(e.action.cast.spell))
{
if (e.action.cast.flags & SMARTCAST_INTERRUPT_PREVIOUS)
if (e.action.cast.castFlags & SMARTCAST_INTERRUPT_PREVIOUS)
tempLastInvoker->InterruptNonMeleeSpells(false);
tempLastInvoker->CastSpell(target->ToUnit(), e.action.cast.spell, (e.action.cast.flags & SMARTCAST_TRIGGERED));
tempLastInvoker->CastSpell(target->ToUnit(), e.action.cast.spell, (e.action.cast.castFlags & SMARTCAST_TRIGGERED));
}
}
@@ -4143,7 +4176,7 @@ void SmartScript::UpdateTimer(SmartScriptHolder& e, uint32 const diff)
// delay spell cast event if another spell is being casted
if (e.GetActionType() == SMART_ACTION_CAST)
{
if (!(e.action.cast.flags & (SMARTCAST_INTERRUPT_PREVIOUS | SMARTCAST_TRIGGERED)))
if (!(e.action.cast.castFlags & (SMARTCAST_INTERRUPT_PREVIOUS | SMARTCAST_TRIGGERED)))
{
if (me && me->HasUnitState(UNIT_STATE_CASTING))
{
@@ -4402,7 +4435,7 @@ void SmartScript::OnInitialize(WorldObject* obj, AreaTrigger const* at)
}
// Xinef: if smartcast combat move flag is present
if (i->GetActionType() == SMART_ACTION_CAST && (i->action.cast.flags & SMARTCAST_COMBAT_MOVE))
if (i->GetActionType() == SMART_ACTION_CAST && (i->action.cast.castFlags & SMARTCAST_COMBAT_MOVE))
{
if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(i->action.cast.spell))
{

View File

@@ -409,7 +409,7 @@ bool SmartAIMgr::IsTargetValid(SmartScriptHolder const& e)
case SMART_TARGET_INVOKER_PARTY:
if (e.GetScriptType() != SMART_SCRIPT_TYPE_TIMED_ACTIONLIST && e.GetEventType() != SMART_EVENT_LINK && !EventHasInvoker(e.event.type))
{
LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} has invoker target, but action does not provide any invoker!", e.entryOrGuid, e.GetScriptType(), e.GetEventType(), e.GetActionType());
LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} has invoker target, but event does not provide any invoker!", e.entryOrGuid, e.GetScriptType(), e.GetEventType(), e.GetActionType());
return false;
}
break;
@@ -620,7 +620,7 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e)
case SMART_ACTION_THREAT_SINGLE_PCT: return sizeof(SmartAction::threatPCT);
case SMART_ACTION_THREAT_ALL_PCT: return sizeof(SmartAction::threatPCT);
case SMART_ACTION_CALL_AREAEXPLOREDOREVENTHAPPENS: return sizeof(SmartAction::quest);
//case SMART_ACTION_RESERVED_16: return sizeof(SmartAction::raw);
case SMART_ACTION_RESERVED_16: return sizeof(SmartAction::raw);
case SMART_ACTION_SET_EMOTE_STATE: return sizeof(SmartAction::emote);
case SMART_ACTION_SET_UNIT_FLAG: return sizeof(SmartAction::unitFlag);
case SMART_ACTION_REMOVE_UNIT_FLAG: return sizeof(SmartAction::unitFlag);
@@ -690,6 +690,7 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e)
case SMART_ACTION_ADD_NPC_FLAG: return sizeof(SmartAction::flag);
case SMART_ACTION_REMOVE_NPC_FLAG: return sizeof(SmartAction::flag);
case SMART_ACTION_SIMPLE_TALK: return sizeof(SmartAction::simpleTalk);
case SMART_ACTION_SELF_CAST: return sizeof(SmartAction::cast);
case SMART_ACTION_INVOKER_CAST: return sizeof(SmartAction::cast);
case SMART_ACTION_CROSS_CAST: return sizeof(SmartAction::crossCast);
case SMART_ACTION_CALL_RANDOM_TIMED_ACTIONLIST: return sizeof(SmartAction::randTimedActionList);
@@ -733,22 +734,21 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e)
case SMART_ACTION_TRIGGER_RANDOM_TIMED_EVENT: return sizeof(SmartAction::randomTimedEvent);
case SMART_ACTION_REMOVE_ALL_GAMEOBJECTS: return NO_PARAMS;
// case SMART_ACTION_PAUSE_MOVEMENT: return sizeof(SmartAction::pauseMovement);
//case SMART_ACTION_PLAY_ANIMKIT: return sizeof(SmartAction::raw);
//case SMART_ACTION_SCENE_PLAY: return sizeof(SmartAction::raw);
//case SMART_ACTION_SCENE_CANCEL: return sizeof(SmartAction::raw);
case SMART_ACTION_PLAY_ANIMKIT: return sizeof(SmartAction::raw);
case SMART_ACTION_SCENE_PLAY: return sizeof(SmartAction::raw);
case SMART_ACTION_SCENE_CANCEL: return sizeof(SmartAction::raw);
// case SMART_ACTION_SPAWN_SPAWNGROUP: return sizeof(SmartAction::groupSpawn);
// case SMART_ACTION_DESPAWN_SPAWNGROUP: return sizeof(SmartAction::groupSpawn);
// case SMART_ACTION_RESPAWN_BY_SPAWNID: return sizeof(SmartAction::respawnData);
// case SMART_ACTION_INVOKER_CAST: return sizeof(SmartAction::cast);
case SMART_ACTION_PLAY_CINEMATIC: return sizeof(SmartAction::cinematic);
case SMART_ACTION_SET_MOVEMENT_SPEED: return sizeof(SmartAction::movementSpeed);
//case SMART_ACTION_PLAY_SPELL_VISUAL_KIT: return sizeof(SmartAction::raw);
// case SMART_ACTION_PLAY_SPELL_VISUAL_KIT: return sizeof(SmartAction::raw);
// case SMART_ACTION_OVERRIDE_LIGHT: return sizeof(SmartAction::overrideLight);
// case SMART_ACTION_OVERRIDE_WEATHER: return sizeof(SmartAction::overrideWeather);
//case SMART_ACTION_SET_AI_ANIM_KIT: return sizeof(SmartAction::raw);
// case SMART_ACTION_SET_AI_ANIM_KIT: return sizeof(SmartAction::raw);
case SMART_ACTION_SET_HOVER: return sizeof(SmartAction::setHover);
case SMART_ACTION_SET_HEALTH_PCT: return sizeof(SmartAction::setHealthPct);
//case SMART_ACTION_CREATE_CONVERSATION: return sizeof(SmartAction::raw);
// case SMART_ACTION_CREATE_CONVERSATION: return sizeof(SmartAction::raw);
case SMART_ACTION_MOVE_TO_POS_TARGET: return sizeof(SmartAction::moveToPos);
case SMART_ACTION_EXIT_VEHICLE: return NO_PARAMS;
case SMART_ACTION_SET_UNIT_MOVEMENT_FLAGS: return sizeof(SmartAction::movementFlag);
@@ -1438,11 +1438,14 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
}
break;
}
case SMART_ACTION_CAST:
case SMART_ACTION_INVOKER_CAST:
if (!IsSpellValid(e, e.action.cast.spell))
if (e.GetScriptType() != SMART_SCRIPT_TYPE_TIMED_ACTIONLIST && e.GetEventType() != SMART_EVENT_LINK && !EventHasInvoker(e.event.type))
{
LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} has invoker cast action, but event does not provide any invoker!", e.entryOrGuid, e.GetScriptType(), e.GetEventType(), e.GetActionType());
return false;
}
break;
case SMART_ACTION_CAST:
case SMART_ACTION_CROSS_CAST:
if (!IsSpellValid(e, e.action.crossCast.spell))
return false;

View File

@@ -607,7 +607,7 @@ enum SMART_ACTION
SMART_ACTION_ADD_NPC_FLAG = 82, // Flags
SMART_ACTION_REMOVE_NPC_FLAG = 83, // Flags
SMART_ACTION_SIMPLE_TALK = 84, // groupID, can be used to make players say groupID, Text_over event is not triggered, whisper can not be used (Target units will say the text)
SMART_ACTION_INVOKER_CAST = 85, // spellID, castFlags, if avaliable, last used invoker will cast spellId with castFlags on targets
SMART_ACTION_SELF_CAST = 85, // spellID, castFlags
SMART_ACTION_CROSS_CAST = 86, // spellID, castFlags, CasterTargetType, CasterTarget param1, CasterTarget param2, CasterTarget param3, ( + the origonal target fields as Destination target), CasterTargets will cast spellID on all Targets (use with caution if targeting multiple * multiple units)
SMART_ACTION_CALL_RANDOM_TIMED_ACTIONLIST = 87, // script9 ids 1-9
SMART_ACTION_CALL_RANDOM_RANGE_TIMED_ACTIONLIST = 88, // script9 id min, max
@@ -656,8 +656,8 @@ enum SMART_ACTION
SMART_ACTION_SPAWN_SPAWNGROUP = 131, /// @todo: NOT SUPPORTED YET
SMART_ACTION_DESPAWN_SPAWNGROUP = 132, /// @todo: NOT SUPPORTED YET
SMART_ACTION_RESPAWN_BY_SPAWNID = 133, /// @todo: NOT SUPPORTED YET
// SMART_ACTION_INVOKER_CAST = 134, /// @todo: solve name conflicts
SMART_ACTION_PLAY_CINEMATIC = 135, // entry
SMART_ACTION_INVOKER_CAST = 134, // spellID, castFlags
SMART_ACTION_PLAY_CINEMATIC = 135, // entry, cinematic
SMART_ACTION_SET_MOVEMENT_SPEED = 136, // movementType, speedInteger, speedFraction
SMART_ACTION_SET_HEALTH_PCT = 142, // percent
@@ -801,7 +801,8 @@ struct SmartAction
struct
{
uint32 spell;
uint32 flags;
uint32 castFlags;
uint32 triggerFlags;
uint32 targetsLimit;
} cast;

View File

@@ -4575,6 +4575,8 @@ void Unit::_UnapplyAura(AuraApplicationMap::iterator& i, AuraRemoveMode removeMo
// only way correctly remove all auras from list
//if (removedAuras != m_removedAurasCount) new aura may be added
i = m_appliedAuras.begin();
sScriptMgr->OnAuraRemove(this, aurApp, removeMode);
}
void Unit::_UnapplyAura(AuraApplication* aurApp, AuraRemoveMode removeMode)
@@ -4718,8 +4720,6 @@ void Unit::RemoveAura(AuraApplicationMap::iterator& i, AuraRemoveMode mode)
// Remove aura - for Area and Target auras
if (aura->GetOwner() == this)
aura->Remove(mode);
sScriptMgr->OnAuraRemove(this, aurApp, mode);
}
void Unit::RemoveAura(uint32 spellId, ObjectGuid caster, uint8 reqEffMask, AuraRemoveMode removeMode)

View File

@@ -422,6 +422,12 @@ void WorldSession::HandleAuctionPlaceBid(WorldPacket& recvData)
AuctionEntry* auction = auctionHouse->GetAuction(auctionId);
Player* player = GetPlayer();
if (!sScriptMgr->CanPlaceAuctionBid(player, auction))
{
SendAuctionCommandResult(0, AUCTION_PLACE_BID, ERR_AUCTION_RESTRICTED_ACCOUNT);
return;
}
if (!auction || auction->owner == player->GetGUID())
{
//you cannot bid your own auction:

View File

@@ -614,6 +614,21 @@ void ScriptMgr::OnQuestRewardItem(Player* player, Item* item, uint32 count)
});
}
bool ScriptMgr::CanPlaceAuctionBid(Player* player, AuctionEntry* auction)
{
auto ret = IsValidBoolScript<PlayerScript>([&](PlayerScript *script)
{
return !script->CanPlaceAuctionBid(player, auction);
});
if (ret && *ret)
{
return false;
}
return true;
}
void ScriptMgr::OnGroupRollRewardItem(Player* player, Item* item, uint32 count, RollVote voteType, Roll* roll)
{
ExecuteScript<PlayerScript>([&](PlayerScript* script)

View File

@@ -1192,6 +1192,9 @@ public:
// After receiving item as a quest reward
virtual void OnQuestRewardItem(Player* /*player*/, Item* /*item*/, uint32 /*count*/) { }
// When placing a bid or buying out an auction
[[nodiscard]] virtual bool CanPlaceAuctionBid(Player* /*player*/, AuctionEntry* /*auction*/) { return true; }
// After receiving item as a group roll reward
virtual void OnGroupRollRewardItem(Player* /*player*/, Item* /*item*/, uint32 /*count*/, RollVote /*voteType*/, Roll* /*roll*/) { }
@@ -2331,6 +2334,7 @@ public: /* PlayerScript */
void OnStoreNewItem(Player* player, Item* item, uint32 count);
void OnCreateItem(Player* player, Item* item, uint32 count);
void OnQuestRewardItem(Player* player, Item* item, uint32 count);
bool CanPlaceAuctionBid(Player* player, AuctionEntry* auction);
void OnGroupRollRewardItem(Player* player, Item* item, uint32 count, RollVote voteType, Roll* roll);
bool OnBeforeOpenItem(Player* player, Item* item);
bool OnBeforePlayerQuestComplete(Player* player, uint32 quest_id);

View File

@@ -98,21 +98,21 @@ struct boss_ambassador_hellmaw : public BossAI
}
Talk(SAY_AGGRO);
events.ScheduleEvent(EVENT_SPELL_CORROSIVE, urand(5000, 10000));
events.ScheduleEvent(EVENT_SPELL_CORROSIVE, urand(23050, 30350));
scheduler.Schedule(5s, 10s, [this](TaskContext context)
scheduler.Schedule(23050ms, 30350ms, [this](TaskContext context)
{
DoCastVictim(SPELL_CORROSIVE_ACID);
context.Repeat(15s, 25s);
}).Schedule(15s, 20s, [this](TaskContext context)
context.Repeat(23050ms, 30350ms);
}).Schedule(23s, 33s, [this](TaskContext context)
{
DoCastAOE(SPELL_FEAR);
context.Repeat(20s, 35s);
context.Repeat(23s, 33s);
});
if (IsHeroic())
{
scheduler.Schedule(5min, [this](TaskContext)
scheduler.Schedule(3min, [this](TaskContext)
{
DoCastSelf(SPELL_ENRAGE, true);
});

View File

@@ -85,10 +85,10 @@ public:
void JustEngagedWith(Unit* /*who*/) override
{
Talk(SAY_AGGRO);
events.ScheduleEvent(EVENT_SPELL_INCITE, 20000);
events.ScheduleEvent(EVENT_SPELL_INCITE, 24000);
events.ScheduleEvent(EVENT_INCITE_WAIT, 15000);
events.ScheduleEvent(EVENT_SPELL_CHARGE, 0);
events.ScheduleEvent(EVENT_SPELL_KNOCKBACK, 15000);
events.ScheduleEvent(EVENT_SPELL_KNOCKBACK, urand(16950, 26350));
if (instance)
instance->SetData(DATA_BLACKHEARTTHEINCITEREVENT, IN_PROGRESS);
@@ -127,18 +127,18 @@ public:
DoResetThreatList();
InciteChaos = true;
events.DelayEvents(15000);
events.RepeatEvent(40000);
events.RepeatEvent(urand(50000, 70000));
events.ScheduleEvent(EVENT_INCITE_WAIT, 15000);
break;
}
case EVENT_SPELL_CHARGE:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
me->CastSpell(target, SPELL_CHARGE, false);
events.RepeatEvent(urand(15000, 25000));
events.RepeatEvent(urand(30000, 50000));
break;
case EVENT_SPELL_KNOCKBACK:
me->CastSpell(me, SPELL_WAR_STOMP, false);
events.RepeatEvent(urand(18000, 24000));
events.RepeatEvent(urand(16950, 26350));
break;
}

View File

@@ -47,18 +47,20 @@ enum GrandmasterVorpil
EVENT_SPELL_SHADOWBOLT = 1,
EVENT_SPELL_DRAWSHADOWS = 2,
EVENT_SUMMON_TRAVELER = 3,
EVENT_SPELL_BANISH = 4
EVENT_SPELL_BANISH = 4,
EVENT_SPELL_RAIN_OF_FIRE = 5
};
float VorpilPosition[3] = {-252.8820f, -264.3030f, 17.1f};
float VorpilPosition[3] = {-253.548f, -263.646f, 17.0864f};
float VoidPortalCoords[5][3] =
//x, y, z, and orientation
float VoidPortalCoords[5][4] =
{
{-283.5894f, -239.5718f, 12.7f},
{-306.5853f, -258.4539f, 12.7f},
{-295.8789f, -269.0899f, 12.7f},
{-209.3401f, -262.7564f, 17.1f},
{-261.4533f, -297.3298f, 17.1f}
{-208.411f, -263.652f, 17.086313f, 3.121870040893554687f}, //portal A 33566
{-261.676f, -297.69f, 17.087011f, 1.360249996185302734f}, //portal B 33614
{-282.272f, -240.432f, 12.683899f, 5.580170154571533203f}, //portal C 33615
{-291.833f, -268.595f, 12.682545f, 0.047733999788761138f}, //portal D 33567
{-303.966f, -255.759f, 12.683404f, 6.012829780578613281f} //portal E 33616
};
class boss_grandmaster_vorpil : public CreatureScript
@@ -85,6 +87,8 @@ public:
bool sayIntro, sayHelp;
int count = 0;
void Reset() override
{
sayHelp = false;
@@ -98,13 +102,13 @@ public:
void summonPortals()
{
for (uint8 i = 0; i < 5; ++i)
me->SummonCreature(NPC_VOID_PORTAL, VoidPortalCoords[i][0], VoidPortalCoords[i][1], VoidPortalCoords[i][2], 0, TEMPSUMMON_CORPSE_DESPAWN, 3000000);
me->SummonCreature(NPC_VOID_PORTAL, VoidPortalCoords[i][0], VoidPortalCoords[i][1], VoidPortalCoords[i][2], VoidPortalCoords[i][3], TEMPSUMMON_CORPSE_DESPAWN, 3000000);
}
void spawnVoidTraveler()
{
uint8 pos = urand(0, 4);
me->SummonCreature(NPC_VOID_TRAVELER, VoidPortalCoords[pos][0], VoidPortalCoords[pos][1], VoidPortalCoords[pos][2], 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000);
me->SummonCreature(NPC_VOID_TRAVELER, VoidPortalCoords[pos][0], VoidPortalCoords[pos][1], VoidPortalCoords[pos][2], VoidPortalCoords[pos][3], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000);
if (!sayHelp)
{
Talk(SAY_HELP);
@@ -112,6 +116,38 @@ public:
}
}
int counterVoidSpawns(int count)
{
int timer = 0;
switch(count)
{
case 1:
case 2:
timer = 13300;
break;
case 3:
timer = 12100;
break;
case 4:
timer = 10900;
break;
case 5:
case 6:
timer = 9700;
break;
case 7:
case 8:
timer = 7200;
break;
case 9:
timer = 6000;
break;
default:
timer = 4800;
}
return timer;
}
void JustSummoned(Creature* summon) override
{
summons.Summon(summon);
@@ -141,14 +177,17 @@ public:
Talk(SAY_AGGRO);
summonPortals();
events.ScheduleEvent(EVENT_SPELL_SHADOWBOLT, urand(7000, 14000));
events.ScheduleEvent(EVENT_SPELL_DRAWSHADOWS, 45000);
events.ScheduleEvent(EVENT_SUMMON_TRAVELER, 5000);
events.ScheduleEvent(EVENT_SPELL_SHADOWBOLT, urand(9700, 20000));
events.ScheduleEvent(EVENT_SPELL_DRAWSHADOWS, 36400);
events.ScheduleEvent(EVENT_SUMMON_TRAVELER, 10900);
if (IsHeroic())
events.ScheduleEvent(EVENT_SPELL_BANISH, 17000);
{
events.ScheduleEvent(EVENT_SPELL_BANISH, urand(17000, 28000));
}
if (instance)
{
instance->SetData(DATA_GRANDMASTERVORPILEVENT, IN_PROGRESS);
}
}
void MoveInLineOfSight(Unit* who) override
@@ -172,19 +211,21 @@ public:
{
case EVENT_SPELL_SHADOWBOLT:
me->CastSpell(me, SPELL_SHADOWBOLT_VOLLEY, false);
events.RepeatEvent(urand(15000, 30000));
events.RepeatEvent(urand(9700, 20000));
break;
case EVENT_SPELL_BANISH:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 30, false))
me->CastSpell(target, SPELL_BANISH, false);
events.RepeatEvent(16000);
events.RepeatEvent(urand(17000, 28000));
break;
case EVENT_SUMMON_TRAVELER:
spawnVoidTraveler();
events.RepeatEvent(HealthBelowPct(20) ? 5000 : 10000);
count++;
events.RepeatEvent(counterVoidSpawns(count));
break;
case EVENT_SPELL_DRAWSHADOWS:
{
me->CastSpell(me, SPELL_DRAW_SHADOWS, true);
Map* map = me->GetMap();
Map::PlayerList const& PlayerList = map->GetPlayers();
for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i)
@@ -193,15 +234,15 @@ public:
player->TeleportTo(me->GetMapId(), VorpilPosition[0], VorpilPosition[1], VorpilPosition[2], 0, TELE_TO_NOT_LEAVE_COMBAT);
me->NearTeleportTo(VorpilPosition[0], VorpilPosition[1], VorpilPosition[2], 0.0f);
me->CastSpell(me, SPELL_DRAW_SHADOWS, true);
me->CastSpell(me, SPELL_RAIN_OF_FIRE_N);
events.RepeatEvent(24000);
events.DelayEvents(6000);
events.ScheduleEvent(EVENT_SPELL_RAIN_OF_FIRE, 1000);
events.RepeatEvent(urand(36400, 44950));
break;
}
case EVENT_SPELL_RAIN_OF_FIRE:
me->CastSpell(me, DUNGEON_MODE(SPELL_RAIN_OF_FIRE_N, SPELL_RAIN_OF_FIRE_H));
events.DelayEvents(6000);
break;
}
DoMeleeAttackIfReady();
}
};

View File

@@ -24,10 +24,15 @@ enum Murmur
{
EMOTE_SONIC_BOOM = 0,
SPELL_SUPPRESSION = 33332,
SPELL_SHOCKWAVE = 33686,
SPELL_SHOCKWAVE_SERVERSIDE = 33673,
SPELL_RESONANCE = 33657,
SPELL_MAGNETIC_PULL = 33689,
SPELL_SONIC_SHOCK = 38797,
SPELL_THUNDERING_STORM = 39365,
SPELL_MURMUR_WRATH_AOE = 33329,
SPELL_MURMUR_WRATH = 33331,
SPELL_SONIC_BOOM_CAST_N = 33923,
SPELL_SONIC_BOOM_CAST_H = 38796,
@@ -36,194 +41,217 @@ enum Murmur
SPELL_MURMURS_TOUCH_N = 33711,
SPELL_MURMURS_TOUCH_H = 38794,
EVENT_SPELL_SONIC_BOOM = 1,
EVENT_SPELL_SONIC_BOOM_EFFECT = 2,
EVENT_SPELL_MURMURS_TOUCH = 3,
EVENT_SPELL_RESONANCE = 4,
EVENT_SPELL_MAGNETIC = 5,
EVENT_SPELL_THUNDERING = 6,
EVENT_SPELL_SONIC_SHOCK = 7
GROUP_RESONANCE = 1,
GROUP_OOC_CAST = 2,
GUID_MURMUR_NPCS = 1
};
class boss_murmur : public CreatureScript
enum Creatures
{
public:
boss_murmur() : CreatureScript("boss_murmur") { }
NPC_CABAL_SPELLBINDER = 18639
};
CreatureAI* GetAI(Creature* creature) const override
struct boss_murmur : public BossAI
{
boss_murmur(Creature* creature) : BossAI(creature, DATA_MURMUR)
{
return GetShadowLabyrinthAI<boss_murmurAI>(creature);
SetCombatMovement(false);
scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
struct boss_murmurAI : public ScriptedAI
void Reset() override
{
boss_murmurAI(Creature* creature) : ScriptedAI(creature)
{
SetCombatMovement(false);
instance = creature->GetInstanceScript();
}
_Reset();
me->SetHealth(me->CountPctFromMaxHealth(40));
me->ResetPlayerDamageReq();
CastSupressionOOC();
}
InstanceScript* instance;
EventMap events;
void Reset() override
{
events.Reset();
me->SetHealth(me->CountPctFromMaxHealth(40));
me->ResetPlayerDamageReq();
if (instance)
instance->SetData(DATA_MURMUREVENT, NOT_STARTED);
}
void JustEngagedWith(Unit* /*who*/) override
{
events.ScheduleEvent(EVENT_SPELL_SONIC_BOOM, 30000);
events.ScheduleEvent(EVENT_SPELL_MURMURS_TOUCH, urand(8000, 20000));
events.ScheduleEvent(EVENT_SPELL_RESONANCE, 5000);
events.ScheduleEvent(EVENT_SPELL_MAGNETIC, urand(15000, 30000));
if (IsHeroic())
void CastSupressionOOC()
{
me->m_Events.AddEventAtOffset([this] {
if (me->FindNearestCreature(NPC_CABAL_SPELLBINDER, 35.0f))
{
events.ScheduleEvent(EVENT_SPELL_THUNDERING, 15000);
events.ScheduleEvent(EVENT_SPELL_SONIC_SHOCK, 10000);
me->CastCustomSpell(SPELL_SUPPRESSION, SPELLVALUE_MAX_TARGETS, 5, (Unit*)nullptr, false);
CastSupressionOOC();
}
}, 3600ms, 10900ms, GROUP_OOC_CAST);
}
bool CanAIAttack(Unit const* victim) const override
{
return me->IsWithinMeleeRange(victim);
}
void EnterEvadeMode(EvadeReason why) override
{
if (me->GetThreatMgr().GetThreatList().empty())
{
BossAI::EnterEvadeMode(why);
}
}
bool ShouldCastResonance()
{
if (Unit* victim = me->GetVictim())
{
if (!me->IsWithinMeleeRange(victim))
{
return true;
}
if (instance)
instance->SetData(DATA_MURMUREVENT, IN_PROGRESS);
}
void JustDied(Unit*) override
{
if (instance)
instance->SetData(DATA_MURMUREVENT, DONE);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim() || me->HasUnitState(UNIT_STATE_CASTING))
return;
events.Update(diff);
switch (events.ExecuteEvent())
if (Unit* victimTarget = victim->GetVictim())
{
case EVENT_SPELL_SONIC_BOOM:
Talk(EMOTE_SONIC_BOOM);
me->CastSpell(me, DUNGEON_MODE(SPELL_SONIC_BOOM_CAST_N, SPELL_SONIC_BOOM_CAST_H), false);
events.RepeatEvent(28500);
events.DelayEvents(1500);
events.ScheduleEvent(EVENT_SPELL_SONIC_BOOM_EFFECT, 0);
return;
case EVENT_SPELL_SONIC_BOOM_EFFECT:
me->CastSpell(me, DUNGEON_MODE(SPELL_SONIC_BOOM_EFFECT_N, SPELL_SONIC_BOOM_EFFECT_H), true);
break;
case EVENT_SPELL_MURMURS_TOUCH:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 80.0f, true))
me->CastSpell(target, DUNGEON_MODE(SPELL_MURMURS_TOUCH_N, SPELL_MURMURS_TOUCH_H), false);
events.RepeatEvent(urand(25000, 35000));
break;
case EVENT_SPELL_RESONANCE:
if (!me->IsWithinMeleeRange(me->GetVictim()))
me->CastSpell(me, SPELL_RESONANCE, false);
events.RepeatEvent(5000);
break;
case EVENT_SPELL_MAGNETIC:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 80.0f, true))
return victimTarget != me;
}
}
return true;
}
void SetGUID(ObjectGuid guid, int32 index) override
{
if (index == GUID_MURMUR_NPCS)
{
if (Creature* creature = ObjectAccessor::GetCreature(*me, guid))
{
DoCast(creature, SPELL_MURMUR_WRATH, true);
}
}
}
void JustEngagedWith(Unit* /*who*/) override
{
_JustEngagedWith();
scheduler.Schedule(28s, [this](TaskContext context)
{
Talk(EMOTE_SONIC_BOOM);
DoCastAOE(DUNGEON_MODE(SPELL_SONIC_BOOM_CAST_N, SPELL_SONIC_BOOM_CAST_H));
scheduler.Schedule(1500ms, [this](TaskContext)
{
DoCastAOE(DUNGEON_MODE(SPELL_SONIC_BOOM_EFFECT_N, SPELL_SONIC_BOOM_EFFECT_H), true);
});
context.Repeat(34s, 40s);
}).Schedule(14600ms, 25500ms, [this](TaskContext context)
{
DoCastRandomTarget(DUNGEON_MODE(SPELL_MURMURS_TOUCH_N, SPELL_MURMURS_TOUCH_H));
context.Repeat(14600ms, 25500ms);
}).Schedule(15s, 30s, [this](TaskContext context)
{
if (DoCastRandomTarget(SPELL_MAGNETIC_PULL, 0, 80.0f) == SPELL_CAST_OK)
{
context.Repeat(15s, 30s);
}
else
{
context.Repeat(500ms);
}
}).Schedule(3s, [this](TaskContext context)
{
if (ShouldCastResonance())
{
if (!scheduler.IsGroupScheduled(GROUP_RESONANCE))
{
scheduler.Schedule(5s, 5s, GROUP_RESONANCE, [this](TaskContext context)
{
me->CastSpell(target, SPELL_MAGNETIC_PULL, false);
events.RepeatEvent(urand(15000, 30000));
return;
}
events.RepeatEvent(500);
break;
case EVENT_SPELL_THUNDERING:
me->CastSpell(me, SPELL_THUNDERING_STORM, true);
events.RepeatEvent(15000);
break;
case EVENT_SPELL_SONIC_SHOCK:
me->CastSpell(me->GetVictim(), SPELL_SONIC_SHOCK, false);
events.RepeatEvent(urand(10000, 20000));
break;
}
if (!me->isAttackReady())
return;
if (!me->IsWithinMeleeRange(me->GetVictim()))
{
ThreatContainer::StorageType threatlist = me->GetThreatMgr().GetThreatList();
for (ThreatContainer::StorageType::const_iterator i = threatlist.begin(); i != threatlist.end(); ++i)
if (Unit* target = ObjectAccessor::GetUnit(*me, (*i)->getUnitGuid()))
if (target->IsAlive() && me->IsWithinMeleeRange(target))
if (ShouldCastResonance())
{
me->TauntApply(target);
break;
DoCastAOE(SPELL_RESONANCE);
context.Repeat(6s, 18s);
}
});
}
}
DoMeleeAttackIfReady();
}
};
};
context.Repeat();
});
class spell_murmur_sonic_boom_effect : public SpellScriptLoader
{
public:
spell_murmur_sonic_boom_effect() : SpellScriptLoader("spell_murmur_sonic_boom_effect") { }
class spell_murmur_sonic_boom_effect_SpellScript : public SpellScript
{
PrepareSpellScript(spell_murmur_sonic_boom_effect_SpellScript)
public:
spell_murmur_sonic_boom_effect_SpellScript() : SpellScript() { }
void RecalculateDamage()
if (IsHeroic())
{
SetHitDamage(GetHitUnit()->CountPctFromMaxHealth(90));
scheduler.Schedule(5s, [this](TaskContext context)
{
DoCastAOE(SPELL_THUNDERING_STORM);
context.Repeat(6050ms, 10s);
}).Schedule(3650ms, 9150ms, [this](TaskContext context)
{
DoCastVictim(SPELL_SONIC_SHOCK);
context.Repeat(9150ms, 10s);
});
}
void Register() override
{
OnHit += SpellHitFn(spell_murmur_sonic_boom_effect_SpellScript::RecalculateDamage);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_murmur_sonic_boom_effect_SpellScript();
me->m_Events.CancelEventGroup(GROUP_OOC_CAST);
}
};
class spell_murmur_thundering_storm : public SpellScriptLoader
class spell_murmur_thundering_storm : public SpellScript
{
PrepareSpellScript(spell_murmur_thundering_storm);
void SelectTarget(std::list<WorldObject*>& targets)
{
targets.remove_if(Acore::AllWorldObjectsInExactRange(GetCaster(), 100.0f, true));
targets.remove_if(Acore::AllWorldObjectsInExactRange(GetCaster(), 25.0f, false));
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_murmur_thundering_storm::SelectTarget, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
}
};
// 33711/38794 - Murmur's Touch
class spell_murmur_touch : public AuraScript
{
PrepareAuraScript(spell_murmur_touch);
void HandleAfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE)
{
if (GetTarget())
{
GetTarget()->CastSpell(GetTarget(), SPELL_SHOCKWAVE, true);
GetTarget()->CastSpell(GetTarget(), SPELL_SHOCKWAVE_SERVERSIDE, true);
}
}
}
void Register() override
{
AfterEffectRemove += AuraEffectRemoveFn(spell_murmur_touch::HandleAfterRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL);
}
};
class spell_murmur_sonic_boom_effect : public SpellScript
{
PrepareSpellScript(spell_murmur_sonic_boom_effect)
public:
spell_murmur_thundering_storm() : SpellScriptLoader("spell_murmur_thundering_storm") { }
spell_murmur_sonic_boom_effect() : SpellScript() { }
class spell_murmur_thundering_storm_SpellScript : public SpellScript
void RecalculateDamage()
{
PrepareSpellScript(spell_murmur_thundering_storm_SpellScript);
SetHitDamage(GetHitUnit()->CountPctFromCurHealth(80));
}
void SelectTarget(std::list<WorldObject*>& targets)
{
targets.remove_if(Acore::AllWorldObjectsInExactRange(GetCaster(), 100.0f, true));
targets.remove_if(Acore::AllWorldObjectsInExactRange(GetCaster(), 25.0f, false));
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_murmur_thundering_storm_SpellScript::SelectTarget, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
}
};
SpellScript* GetSpellScript() const override
void Register() override
{
return new spell_murmur_thundering_storm_SpellScript();
OnHit += SpellHitFn(spell_murmur_sonic_boom_effect::RecalculateDamage);
}
};
void AddSC_boss_murmur()
{
new boss_murmur();
new spell_murmur_sonic_boom_effect();
new spell_murmur_thundering_storm();
RegisterShadowLabyrinthCreatureAI(boss_murmur);
RegisterSpellScript(spell_murmur_thundering_storm);
RegisterSpellScript(spell_murmur_touch);
RegisterSpellScript(spell_murmur_sonic_boom_effect);
}

View File

@@ -31,8 +31,9 @@ enum slData
TYPE_HELLMAW = 1,
DATA_BLACKHEARTTHEINCITEREVENT = 2,
DATA_GRANDMASTERVORPILEVENT = 3,
DATA_MURMUREVENT = 4,
MAX_ENCOUNTER = 5
DATA_MURMUR = 4,
DATA_MURMUREVENT = 5,
MAX_ENCOUNTER = 6
};
enum slNPCandGO

View File

@@ -3663,7 +3663,9 @@ class spell_gen_ds_flush_knockback : public SpellScript
60864 - Jaws of Death (spell_gen_default_count_pct_from_max_hp)
38441 - Cataclysmic Bolt (spell_gen_50pct_count_pct_from_max_hp)
66316, 67100, 67101, 67102 - Spinning Pain Spike (spell_gen_50pct_count_pct_from_max_hp)
41360 - L5 Arcane Charge (spell_gen_100pct_count_pct_from_max_hp) */
41360 - L5 Arcane Charge (spell_gen_100pct_count_pct_from_max_hp)
33711/38794 - Murmur's Touch
*/
class spell_gen_count_pct_from_max_hp : public SpellScript
{
PrepareSpellScript(spell_gen_count_pct_from_max_hp)