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

@@ -0,0 +1,26 @@
-- DB update 2023_04_15_00 -> 2023_04_17_00
--
DELETE FROM `creature_template_movement` WHERE `CreatureId` IN (18708, 20657);
INSERT INTO `creature_template_movement` (`CreatureId`, `Ground`, `Rooted`, `Flight`) VALUES
(18708, 1, 1, 1),
(20657, 1, 1, 1);
DELETE FROM `spell_script_names` WHERE `spell_id` = 33711;
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
(33711, 'spell_murmur_touch');
DELETE FROM `smart_scripts` WHERE (`entryorguid` = -146210) AND (`source_type` = 0) AND (`id` IN (1));
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
(-146210, 0, 1, 0, 58, 0, 100, 0, 8, 1863400, 0, 0, 0, 225, 0, 1, 0, 0, 0, 0, 10, 146104, 18708, 0, 0, 0, 0, 0, 0, 'Cabal Summoner - On Waypoint Finished - Send GUID to Murmur');
DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = -146209 AND `id` = 4);
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
(-146209, 0, 4, 0, 34, 0, 100, 0, 8, 1, 0, 0, 0, 225, 0, 1, 0, 0, 0, 0, 10, 146104, 18708, 0, 0, 0, 0, 0, 0, 'Cabal Summoner - On Reached Point 1 - Send GUID to Murmur'); -- This is a hack as it will trigger spell 33331 instead of 33329
DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 13) AND (`SourceEntry` = 33329);
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(13, 1, 33329, 0, 0, 31, 0, 3, 18639, 146225, 0, 0, 0, '', 'Murmur\'s Wrath (33329) only targets a set of guids'),
(13, 1, 33329, 0, 1, 31, 0, 3, 18634, 146226, 0, 0, 0, '', 'Murmur\'s Wrath (33329) only targets a set of guids'),
(13, 1, 33329, 0, 2, 31, 0, 3, 18639, 146227, 0, 0, 0, '', 'Murmur\'s Wrath (33329) only targets a set of guids'),
(13, 1, 33329, 0, 3, 31, 0, 3, 18634, 146228, 0, 0, 0, '', 'Murmur\'s Wrath (33329) only targets a set of guids'),
(13, 1, 33329, 0, 4, 31, 0, 3, 18639, 146229, 0, 0, 0, '', 'Murmur\'s Wrath (33329) only targets a set of guids');

View File

@@ -0,0 +1,7 @@
-- DB update 2023_04_17_00 -> 2023_04_17_01
--
DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 13) AND (`SourceGroup` = 1) AND (`SourceEntry` = 33332);
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(13, 1, 33332, 0, 1, 31, 0, 3, 18639, 0, 0, 0, 0, '', 'Suppression Blast (33332) can only target a set of Entries'),
(13, 1, 33332, 0, 2, 31, 0, 3, 18634, 0, 0, 0, 0, '', 'Suppression Blast (33332) can only target a set of Entries'),
(13, 1, 33332, 0, 3, 31, 0, 3, 18632, 0, 0, 0, 0, '', 'Suppression Blast (33332) can only target a set of Entries');

View File

@@ -0,0 +1,7 @@
-- DB update 2023_04_17_01 -> 2023_04_17_02
-- 184906 (Power Converter)
UPDATE `gameobject_template` SET `AIName` = 'SmartGameObjectAI' WHERE `entry` = 184906;
DELETE FROM `smart_scripts` WHERE (`source_type` = 1 AND `entryorguid` = 184906);
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
(184906, 1, 0, 0, 70, 0, 100, 0, 2, 0, 0, 0, 0, 41, 1000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Power Converter - On Gameobject State Changed - Despawn In 1000 ms');

View File

@@ -0,0 +1,7 @@
-- DB update 2023_04_17_02 -> 2023_04_18_00
--
DELETE FROM `smart_scripts` WHERE (`entryorguid` = 21694) AND (`source_type` = 0) AND (`id` IN (2, 3, 4, 5));
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
(21694, 0, 2, 0, 0, 0, 100, 0, 7000, 9500, 12000, 15000, 0, 11, 40340, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Bog Overlord - In Combat - Cast \'Trample\''),
(21694, 0, 3, 4, 2, 0, 100, 1, 0, 20, 0, 0, 0, 11, 8599, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Bog Overlord - Between 0-20% Health - Cast \'Enrage\' (No Repeat)'),
(21694, 0, 4, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Bog Overlord - Between 0-20% Health - Say Line 0 (No Repeat)');

View File

@@ -0,0 +1,6 @@
-- DB update 2023_04_18_00 -> 2023_04_18_01
--
UPDATE `smart_scripts` SET `action_type`=134 WHERE `action_type` = 85;
DELETE FROM `smart_scripts` WHERE `entryorguid`=25418 AND `source_type`=0 AND `id`=4 AND `link`=5;
DELETE FROM `smart_scripts` WHERE `entryorguid`=25416 AND `source_type`=0 AND `id`=4 AND `link`=5;
DELETE FROM `smart_scripts` WHERE `entryorguid`=33518 AND `source_type`=0 AND `id`=3 AND `link`=0;

View File

@@ -0,0 +1,3 @@
-- DB update 2023_04_18_01 -> 2023_04_18_02
--
UPDATE `creature_template` SET `dmgschool` = 0 WHERE (`entry` IN (21695, 21696, 21916, 21917));

View File

@@ -107,6 +107,11 @@ void TaskScheduler::Dispatch(success_t const& callback)
callback();
}
bool TaskScheduler::IsGroupScheduled(group_t const group)
{
return _task_holder.IsGroupQueued(group);
}
void TaskScheduler::TaskQueue::Push(TaskContainer&& task)
{
container.insert(task);
@@ -159,6 +164,19 @@ void TaskScheduler::TaskQueue::ModifyIf(std::function<bool(TaskContainer const&)
container.insert(cache.begin(), cache.end());
}
bool TaskScheduler::TaskQueue::IsGroupQueued(group_t const group)
{
for (auto const& task : container)
{
if (task->IsInGroup(group))
{
return true;
}
}
return false;
}
bool TaskScheduler::TaskQueue::IsEmpty() const
{
return container.empty();

View File

@@ -136,6 +136,9 @@ class TaskScheduler
void ModifyIf(std::function<bool(TaskContainer const&)> const& filter);
/// Check if the group exists and is currently scheduled.
bool IsGroupQueued(group_t const group);
bool IsEmpty() const;
};
@@ -260,6 +263,9 @@ public:
/// Hint: Use std::initializer_list for this: "{1, 2, 3, 4}"
TaskScheduler& CancelGroupsOf(std::vector<group_t> const& groups);
/// Check if the group exists and is currently scheduled.
bool IsGroupScheduled(group_t const group);
/// Delays all tasks with the given duration.
template<class _Rep, class _Period>
TaskScheduler& DelayAll(std::chrono::duration<_Rep, _Period> const& duration)

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)