/* * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #include "CreatureScript.h" #include "PassiveAI.h" #include "Player.h" #include "ScriptedCreature.h" #include "ScriptedGossip.h" #include "SpellAuraEffects.h" #include "SpellInfo.h" #include "SpellScript.h" #include "SpellScriptLoader.h" #include "zulaman.h" /*###### ## npc_forest_frog ######*/ enum ForestFrog { // Spells SPELL_REMOVE_AMANI_CURSE = 43732, SPELL_PUSH_MOJO = 43923, SPELL_SUMMON_AMANI_CHARM_CHEST_1 = 43835, // Amani Treasure Box (186744) SPELL_SUMMON_AMANI_CHARM_CHEST_2 = 43756, // Amani Charm Box (186734) SPELL_SUMMON_MONEY_BAG = 43774, // Money Bag (186736) SPELL_STEALTH_ = 34189, SPELL_FIXATE = 43360, // Creatures NPC_FOREST_FROG = 24396, NPC_MANNUTH = 24397, NPC_DEEZ = 24403, NPC_GALATHRYN = 24404, NPC_ADARRAH = 24405, NPC_FUDGERICK = 24406, NPC_DARWEN = 24407, NPC_GUNTER = 24408, NPC_KYREN = 24409, NPC_MITZI = 24445, NPC_CHRISTIAN = 24448, NPC_BRENNAN = 24453, NPC_HOLLEE = 24455, // Adarrah is spawned elsewhere. // So her text 0 isn't used in this instance. SAY_THANKS_FREED = 0, SAY_CHEST_SPAWN = 1, SAY_CHEST_TALK = 2, SAY_GOODBYE = 3, POINT_DESPAWN = 1, }; struct npc_forest_frog : public ScriptedAI { npc_forest_frog(Creature* creature) : ScriptedAI(creature) { instance = creature->GetInstanceScript(); } void JustEngagedWith(Unit* /*who*/) override { } void MovementInform(uint32 type, uint32 data) override { if (type == POINT_MOTION_TYPE && data == POINT_DESPAWN) me->DespawnOrUnsummon(1s); } void UpdateAI(uint32 diff) override { events.Update(diff); if (eventTimer) { Player* player = ObjectAccessor::GetPlayer(me->GetMap(), PlayerGUID); if (!player) { events.CancelEvent(eventTimer); eventTimer = 0; return; } switch (events.ExecuteEvent()) { case 1: if (me->GetEntry() == NPC_ADARRAH) Talk(SAY_THANKS_FREED + 1, player); else Talk(SAY_THANKS_FREED, player); eventTimer = 2; events.ScheduleEvent(eventTimer, 4s, 5s); break; case 2: if (me->GetEntry() != NPC_GUNTER && me->GetEntry() != NPC_KYREN) // vendors don't kneel? me->SetStandState(UNIT_STAND_STATE_KNEEL); switch (me->GetEntry()) { case NPC_MANNUTH: case NPC_DEEZ: case NPC_GALATHRYN: DoCastSelf(SPELL_SUMMON_AMANI_CHARM_CHEST_2, true); Talk(SAY_CHEST_SPAWN, player); break; case NPC_ADARRAH: DoCastSelf(SPELL_SUMMON_AMANI_CHARM_CHEST_2, true); Talk(SAY_CHEST_SPAWN + 1, player); break; case NPC_DARWEN: case NPC_FUDGERICK: DoCastSelf(SPELL_SUMMON_MONEY_BAG, true); me->LoadEquipment(0, true); Talk(SAY_CHEST_SPAWN, player); break; case NPC_KYREN: case NPC_GUNTER: Talk(SAY_CHEST_SPAWN, player); break; case NPC_MITZI: case NPC_CHRISTIAN: case NPC_BRENNAN: case NPC_HOLLEE: DoCastSelf(SPELL_SUMMON_AMANI_CHARM_CHEST_1, true); Talk(SAY_CHEST_SPAWN, player); break; } eventTimer = 3; events.ScheduleEvent(eventTimer, 6s, 7s); break; case 3: me->SetStandState(EMOTE_ONESHOT_NONE); if (me->GetEntry() == NPC_ADARRAH) Talk(SAY_CHEST_TALK + 1, player); else Talk(SAY_CHEST_TALK, player); eventTimer = 4; if (me->GetEntry() == NPC_GUNTER || me->GetEntry() == NPC_KYREN) events.ScheduleEvent(eventTimer, 300s); // vendors wait for 5 minutes before running away and despawning else events.ScheduleEvent(eventTimer, 6s); break; case 4: me->HandleEmoteCommand(EMOTE_ONESHOT_WAVE); if (me->GetEntry() == NPC_ADARRAH) Talk(SAY_GOODBYE + 1, player); else Talk(SAY_GOODBYE, player); eventTimer = 5; events.ScheduleEvent(eventTimer, 2s); break; case 5: if (me->GetEntry() == NPC_ADARRAH) DoCastSelf(SPELL_STEALTH_, true); if (me->GetPositionY() > 1290.0f) me->GetMotionMaster()->MovePoint(POINT_DESPAWN, 118.2742f, 1400.657f, -9.118711f); else me->GetMotionMaster()->MovePoint(POINT_DESPAWN, 114.3155f, 1244.244f, -20.97606f); eventTimer = 0; break; } } } void DoSpawnRandom() { auto const& entries = { NPC_MANNUTH, NPC_DEEZ, NPC_GALATHRYN, NPC_ADARRAH, NPC_FUDGERICK, NPC_DARWEN, NPC_MITZI, NPC_CHRISTIAN, NPC_BRENNAN, NPC_HOLLEE }; uint32 cEntry = Acore::Containers::SelectRandomContainerElement(entries); if (!instance->GetData(TYPE_RAND_VENDOR_1) && roll_chance_i(10)) { cEntry = NPC_GUNTER; instance->SetData(TYPE_RAND_VENDOR_1, DONE); } else if (!instance->GetData(TYPE_RAND_VENDOR_2) && roll_chance_i(10)) { cEntry = NPC_KYREN; instance->SetData(TYPE_RAND_VENDOR_2, DONE); } // start generic rp eventTimer = 1; events.ScheduleEvent(eventTimer, 3s); me->UpdateEntry(cEntry); if (Player* player = ObjectAccessor::GetPlayer(me->GetMap(), PlayerGUID)) me->SetFacingToObject(player); } void SpellHit(Unit* caster, SpellInfo const* spell) override { if (spell->Id == SPELL_REMOVE_AMANI_CURSE && caster->IsPlayer() && me->GetEntry() == NPC_FOREST_FROG) { me->GetMotionMaster()->MoveIdle(); PlayerGUID = caster->GetGUID(); if (roll_chance_i(2)) { DoCast(caster, SPELL_PUSH_MOJO, true); me->GetMotionMaster()->MovePoint(POINT_DESPAWN, caster->GetPosition()); } else DoSpawnRandom(); } } private: InstanceScript* instance; uint8 eventTimer; ObjectGuid PlayerGUID; }; /*###### ## npc_zulaman_hostage ######*/ #define GOSSIP_HOSTAGE1 "I am glad to help you." static uint32 HostageEntry[] = {23790, 23999, 24024, 24001}; static uint32 ChestEntry[] = {186648, 187021, 186667, 186672}; class npc_zulaman_hostage : public CreatureScript { public: npc_zulaman_hostage() : CreatureScript("npc_zulaman_hostage") { } struct npc_zulaman_hostageAI : public ScriptedAI { npc_zulaman_hostageAI(Creature* creature) : ScriptedAI(creature) { IsLoot = false; } bool IsLoot; ObjectGuid PlayerGUID; void JustEngagedWith(Unit* /*who*/) override { } void JustDied(Unit* /*killer*/) override { if (Player* player = ObjectAccessor::GetPlayer(*me, PlayerGUID)) player->SendLoot(me->GetGUID(), LOOT_CORPSE); } void UpdateAI(uint32 /*diff*/) override { if (IsLoot) DoCast(me, 7, false); } }; CreatureAI* GetAI(Creature* creature) const override { return GetZulAmanAI(creature); } bool OnGossipHello(Player* player, Creature* creature) override { AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_HOSTAGE1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); SendGossipMenuFor(player, player->GetGossipTextId(creature), creature->GetGUID()); return true; } bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override { ClearGossipMenuFor(player); if (action == GOSSIP_ACTION_INFO_DEF + 1) CloseGossipMenuFor(player); if (!creature->HasNpcFlag(UNIT_NPC_FLAG_GOSSIP)) return true; creature->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP); creature->GetInstanceScript()->SetData(DATA_CHEST_LOOTED, 0); float x, y, z; creature->GetPosition(x, y, z); for (uint8 i = 0; i < 4; ++i) { if (HostageEntry[i] == creature->GetEntry()) { GameObject* obj = creature->SummonGameObject(ChestEntry[i], x - 2, y, z, 0, 0, 0, 0, 0, 0); if (obj) obj->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED); break; } } return true; } }; /*###### ## npc_harrison_jones ######*/ enum Says { SAY_HARRISON_0 = 0, SAY_HARRISON_1 = 1, SAY_HARRISON_2 = 0, SAY_HARRISON_3 = 1 }; enum Spells { SPELL_BANGING_THE_GONG = 45225, SPELL_STEALTH = 34189, SPELL_COSMETIC_SPEAR_THROW = 43647 }; enum Phases { PHASE_GONG = 0, PHASE_GATE_CLOSED = 1, PHASE_GATE_OPENED = 2 }; enum Actions { ACTION_COMPLETE_GONG_RITUAL = 0 }; enum Waypoints { HARRISON_MOVE_1 = 2435800, HARRISON_MOVE_2 = 2435801, HARRISON_MOVE_3 = 2435802 }; enum DisplayIds { MODEL_HARRISON_JONES_0 = 22340, MODEL_HARRISON_JONES_1 = 22354, MODEL_HARRISON_JONES_2 = 22347 }; enum EntryIds { NPC_HARRISON_JONES_1 = 24375, NPC_HARRISON_JONES_2 = 24365 }; enum Weapons { WEAPON_MACE = 5301, WEAPON_SPEAR = 13631 }; struct npc_harrison_jones : public ScriptedAI { npc_harrison_jones(Creature* creature) : ScriptedAI(creature) { _instance = creature->GetInstanceScript(); } void Reset() override { _phase = PHASE_GONG; me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); } void JustEngagedWith(Unit* /*who*/) override { } void sGossipSelect(Player* player, uint32 sender, uint32 action) override { if (me->GetCreatureTemplate()->GossipMenuId == sender && !action) { CloseGossipMenuFor(player); me->SetFacingToObject(player); me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP); Talk(SAY_HARRISON_0); scheduler.Schedule(2s, [this](TaskContext /*task*/) { me->GetMotionMaster()->MoveWaypoint(HARRISON_MOVE_1, false); }); } } void SpellHit(Unit*, SpellInfo const* spell) override { if (spell->Id == SPELL_COSMETIC_SPEAR_THROW) { me->RemoveAllAuras(); // remove stealth me->SetEntry(NPC_HARRISON_JONES_2); me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); me->PlayDistanceSound(1332); // human male death me->HandleEmoteCommand(EMOTE_ONESHOT_WOUND_CRITICAL); me->StopMoving(); scheduler.Schedule(1s, [this](TaskContext /*task*/) { me->SetStandState(UNIT_STAND_STATE_DEAD); }).Schedule(2s, [this](TaskContext /*task*/) { // Send savages to attack players std::list creatures; me->GetCreatureListWithEntryInGrid(creatures, NPC_AMANISHI_SAVAGE, 100.0f); for (Creature* creature : creatures) { creature->SetImmuneToAll(false); creature->SetInCombatWithZone(); } }); _instance->StorePersistentData(DATA_TIMED_RUN, 21); _instance->DoAction(ACTION_START_TIMED_RUN); me->DespawnOrUnsummon(3min+30s, 0s); } } void DoAction(int32 action) override { if (action == ACTION_COMPLETE_GONG_RITUAL) { me->GetMap()->ToInstanceMap()->PermBindAllPlayers(); _phase = PHASE_GATE_CLOSED; me->RemoveAura(SPELL_BANGING_THE_GONG); me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, uint32(0)); if (GameObject* gong = _instance->GetGameObject(DATA_STRANGE_GONG)) gong->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE); // Players are Now Saved to instance at SPECIAL (Player should be notified?) scheduler.Schedule(500ms, [this](TaskContext /*task*/) { me->GetMotionMaster()->MoveWaypoint(HARRISON_MOVE_2, false); }); } } void OpenMassiveGateAndCallGuards() { if (GameObject* gate = _instance->GetGameObject(DATA_MASSIVE_GATE)) { gate->AllowSaveToDB(true); gate->SetGoState(GO_STATE_ACTIVE); } std::list targetList; GetCreatureListWithEntryInGrid(targetList, me, NPC_AMANISHI_GUARDIAN, 26.0f); if (!targetList.empty()) { for (auto const& creature : targetList) { if (creature) { creature->SetImmuneToPC(true); creature->SetReactState(REACT_PASSIVE); if (creature->GetPositionX() > 120) { creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, uint32(WEAPON_SPEAR)); creature->AI()->SetData(0, 1); } else creature->AI()->SetData(0, 2); } } } } void MovementInform(uint32 type, uint32 id) override { // at gong if (type == WAYPOINT_MOTION_TYPE && id == 3 && _phase == PHASE_GONG) { if (GameObject* gong = _instance->GetGameObject(DATA_STRANGE_GONG)) me->SetFacingToObject(gong); scheduler.Schedule(2s, [this](TaskContext /*task*/) { Talk(SAY_HARRISON_1); }).Schedule(7s, [this](TaskContext /*task*/) { DoCastSelf(SPELL_BANGING_THE_GONG); me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, uint32(WEAPON_MACE)); me->SetFacingTo(5.9696f); if (GameObject* gong = _instance->GetGameObject(DATA_STRANGE_GONG)) gong->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE); }); } // to the massive gate else if (type == WAYPOINT_MOTION_TYPE && id == 2 && _phase == PHASE_GATE_CLOSED) { me->SetEntry(NPC_HARRISON_JONES_1); Talk(SAY_HARRISON_2); } // at massive gate else if (type == WAYPOINT_MOTION_TYPE && id == 3 && _phase == PHASE_GATE_CLOSED) { me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_USE_STANDING); Talk(SAY_HARRISON_3); scheduler.Schedule(8s, [this](TaskContext /*task*/) { OpenMassiveGateAndCallGuards(); _phase = PHASE_GATE_OPENED; }).Schedule(10s, [this](TaskContext /*task*/) { DoCastSelf(SPELL_STEALTH); me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); me->GetMotionMaster()->MoveWaypoint(HARRISON_MOVE_3, false); }); } } void UpdateAI(uint32 diff) override { scheduler.Update(diff); } private: InstanceScript* _instance; uint32 _phase; }; class spell_ritual_of_power : public SpellScript { PrepareSpellScript(spell_ritual_of_power); void OnEffect(SpellEffIndex /*effIndex*/) { if (InstanceScript* instance = GetCaster()->GetInstanceScript()) if (Creature* creature = instance->GetCreature(DATA_HARRISON_JONES)) creature->AI()->DoAction(ACTION_COMPLETE_GONG_RITUAL); } void Register() override { OnEffectLaunch += SpellEffectFn(spell_ritual_of_power::OnEffect, EFFECT_0, SPELL_EFFECT_SEND_EVENT); } }; enum AmanishiLookout { PATH_LOOKOUT = 2417500, SAY_INVADERS = 0, }; struct npc_amanishi_lookout : public NullCreatureAI { npc_amanishi_lookout(Creature* creature) : NullCreatureAI(creature), _instance(creature->GetInstanceScript()) {} void Reset() override { me->RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_PC); me->RemoveUnitFlag(UNIT_FLAG_RENAME); } void MoveInLineOfSight(Unit* who) override { if (!me->IsWithinDist(who, me->GetAggroRange(who), false)) return; Player* player = who->GetCharmerOrOwnerPlayerOrPlayerItself(); if (!player || player->IsGameMaster()) return; if (!who->IsWithinLOSInMap(me)) return; if (_instance->GetData(TYPE_AKILZON_GAUNTLET) == NOT_STARTED) _instance->SetData(TYPE_AKILZON_GAUNTLET, IN_PROGRESS); } void DoAction(int32 action) override { if (action == ACTION_START_AKILZON_GAUNTLET) { Talk(SAY_INVADERS); me->SetUnitFlag(UNIT_FLAG_IMMUNE_TO_PC); me->SetUnitFlag(UNIT_FLAG_RENAME); me->GetMotionMaster()->MoveWaypoint(PATH_LOOKOUT, false); } } void MovementInform(uint32 type, uint32 id) override { // at boss if (type == WAYPOINT_MOTION_TYPE && id == 9) // should despawn with waypoint script me->DespawnOrUnsummon(0s, 0s); } private: InstanceScript* _instance; }; struct npc_eagle_trash_aggro_trigger : public ScriptedAI { npc_eagle_trash_aggro_trigger(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) {} void MoveInLineOfSight(Unit* who) override { if (who->GetLevel() > 70) return; if (!me->IsWithinDist(who, me->GetAggroRange(who), false)) return; Player* player = who->GetCharmerOrOwnerPlayerOrPlayerItself(); if (!player || player->IsGameMaster()) return; if (_instance->GetData(TYPE_AKILZON_GAUNTLET) == NOT_STARTED) _instance->SetData(TYPE_AKILZON_GAUNTLET, IN_PROGRESS); } private: InstanceScript* _instance; }; enum AmanishiTempest { GROUP_AKILZON_GAUNTLET = 1, SPELL_SUMMON_EAGLE = 43487, SPELL_SUMMON_WARRIOR = 43486, SPELL_THUNDERCLAP = 44033, }; struct npc_amanishi_tempest : public ScriptedAI { npc_amanishi_tempest(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()), _summons(creature) { } void Reset() override { _summons.DespawnAll(); scheduler.CancelAll(); } void JustEngagedWith(Unit* /*who*/) override { scheduler.CancelGroup(GROUP_AKILZON_GAUNTLET); scheduler.Schedule(9s, 11s, [this](TaskContext context) { DoCastVictim(SPELL_THUNDERCLAP); context.Repeat(); }); } void JustSummoned(Creature* summon) override { _summons.Summon(summon); summon->SetNoCallAssistance(true); // prevent eagles from pulling boss summon->SetInCombatWithZone(); } void JustDied(Unit* killer) override { ScriptedAI::JustDied(killer); _instance->SetData(TYPE_AKILZON_GAUNTLET, DONE); } void DoAction(int32 action) override { if (action == ACTION_START_AKILZON_GAUNTLET) ScheduleEvents(); else if (action == ACTION_RESET_AKILZON_GAUNTLET) Reset(); } void SummonedCreatureEvade(Creature* /*summon*/) override { EnterEvadeMode(EVADE_REASON_OTHER); } void EnterEvadeMode(EvadeReason why) override { ScriptedAI::EnterEvadeMode(why); scheduler.CancelAll(); } void ScheduleEvents() { scheduler.Schedule(29s, 53s, GROUP_AKILZON_GAUNTLET, [this](TaskContext context) { for (uint8 i = 0; i < 5; ++i) DoCastAOE(SPELL_SUMMON_EAGLE, true); context.Repeat(); }).Schedule(40s, GROUP_AKILZON_GAUNTLET, [this](TaskContext context) { for (uint8 i = 0; i < 2; ++i) DoCastAOE(SPELL_SUMMON_WARRIOR, true); context.Repeat(); }); } void UpdateAI(uint32 diff) override { scheduler.Update(diff); ScriptedAI::UpdateAI(diff); } private: InstanceScript* _instance; SummonList _summons; }; enum AmanishiScout { NPC_WORLD_TRIGGER = 22515, SAY_AGGRO = 0, SPELL_ALERT_DRUMS = 42177, SPELL_MULTI_SHOT = 43205, SPELL_SHOOT = 16496 }; inline bool IsHut(Creature* trigger) { return trigger->GetPositionX() < -90.0f // South of Jan'alai area && ((trigger->GetOrientation() > 2.7f) || (trigger->GetOrientation() < 2.7f && 1270.0f < trigger->GetPositionY() && trigger->GetPositionY() < 1280.0f)); } inline bool IsDrum(Creature* trigger) { return trigger->GetPositionX() < -90.0f // South of Jan'alai area && !IsHut(trigger); } struct npc_amanishi_scout : public ScriptedAI { npc_amanishi_scout(Creature* creature) : ScriptedAI(creature) { } void Reset() override { scheduler.CancelAll(); me->SetCombatMovement(false); me->SetReactState(REACT_AGGRESSIVE); _drumGUID.Clear(); } void JustEngagedWith(Unit* /*who*/) override { me->SetInCombatWithZone(); Talk(SAY_AGGRO); // Move to Drum std::list triggers; GetCreatureListWithEntryInGrid(triggers, me, NPC_WORLD_TRIGGER, 50.0f); triggers.remove_if([](Creature* trigger) {return !IsDrum(trigger);}); triggers.sort(Acore::ObjectDistanceOrderPred(me)); if (triggers.empty()) { ScheduleCombat(); return; } Creature* closestDrum = triggers.front(); me->GetMotionMaster()->MoveFollow(closestDrum, 0.0f, 0.0f); _drumGUID = closestDrum->GetGUID(); me->ClearTarget(); me->SetReactState(REACT_PASSIVE); scheduler.Schedule(1s, [this](TaskContext context) { if (_drumGUID) if (Creature* drum = ObjectAccessor::GetCreature(*me, _drumGUID)) { if (me->IsWithinRange(drum, INTERACTION_DISTANCE)) { me->SetFacingToObject(drum); DoCastSelf(SPELL_ALERT_DRUMS); scheduler.Schedule(5s, [this](TaskContext /*context*/) { ScheduleCombat(); }); return; } context.Repeat(1s); return; } ScheduleCombat(); }); } void ScheduleCombat() { me->SetReactState(REACT_AGGRESSIVE); me->SetCombatMovement(true); if (Unit* victim = me->GetVictim()) me->GetMotionMaster()->MoveChase(victim); scheduler.Schedule(2s, [this](TaskContext context) { DoCastVictim(SPELL_SHOOT); context.Repeat(4s, 5s); }).Schedule(6s, [this](TaskContext context) { DoCastAOE(SPELL_MULTI_SHOT); context.Repeat(20s, 24s); }); } void UpdateAI(uint32 diff) override { scheduler.Update(diff); if (!me->IsCombatMovementAllowed() || !UpdateVictim()) return; DoMeleeAttackIfReady(); } private: ObjectGuid _drumGUID; }; enum SpellAlertDrums { SPELL_SUMMON_AMANISHI_SENTRIES = 42179 }; class spell_alert_drums : public AuraScript { PrepareAuraScript(spell_alert_drums); bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo({ SPELL_SUMMON_AMANISHI_SENTRIES }); } void HandleTriggerSpell(AuraEffect const* aurEff) { PreventDefaultAction(); if (aurEff->GetTickNumber() == 1) GetCaster()->CastSpell(GetCaster(), SPELL_SUMMON_AMANISHI_SENTRIES, true); } void Register() override { OnEffectPeriodic += AuraEffectPeriodicFn(spell_alert_drums::HandleTriggerSpell, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); } }; enum AmanishiSentries { SUMMON_AMANISHI_SENTRIES_1 = 42180, SUMMON_AMANISHI_SENTRIES_2 = 42181, SUMMON_AMANISHI_SENTRIES_3 = 42182, SUMMON_AMANISHI_SENTRIES_4 = 42183, }; class spell_summon_amanishi_sentries : public SpellScript { PrepareSpellScript(spell_summon_amanishi_sentries); constexpr static uint32 spells[4] = { SUMMON_AMANISHI_SENTRIES_1, SUMMON_AMANISHI_SENTRIES_2, SUMMON_AMANISHI_SENTRIES_3, SUMMON_AMANISHI_SENTRIES_4 }; bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo(spells); } void HandleScriptEffect(SpellEffIndex /*effIndex*/) { std::list triggers; GetCreatureListWithEntryInGrid(triggers, GetHitUnit(), NPC_WORLD_TRIGGER, 50.0f); triggers.remove_if([](Creature* trigger) {return !IsHut(trigger);}); if (triggers.empty()) return; Creature* trigger = Acore::Containers::SelectRandomContainerElement(triggers); uint8 index_1 = urand(0, 3); uint8 index_2 = (index_1 + 1) % 4; trigger->CastSpell(trigger, spells[index_1], true); trigger->CastSpell(trigger, spells[index_2], true); } void Register() override { OnEffectHitTarget += SpellEffectFn(spell_summon_amanishi_sentries::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); } }; class spell_call_of_the_beast : public SpellScript { PrepareSpellScript(spell_call_of_the_beast); bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo({ SPELL_FIXATE }); } void HandleEffect(SpellEffIndex /*effIndex*/) { GetHitUnit()->CastSpell(GetHitUnit(), SPELL_FIXATE, true); } void Register() override { OnEffectHitTarget += SpellEffectFn(spell_call_of_the_beast::HandleEffect, EFFECT_0, SPELL_EFFECT_APPLY_AURA); } }; void AddSC_zulaman() { RegisterZulAmanCreatureAI(npc_forest_frog); new npc_zulaman_hostage(); RegisterZulAmanCreatureAI(npc_harrison_jones); RegisterSpellScript(spell_ritual_of_power); RegisterZulAmanCreatureAI(npc_amanishi_lookout); RegisterZulAmanCreatureAI(npc_eagle_trash_aggro_trigger); RegisterZulAmanCreatureAI(npc_amanishi_tempest); RegisterZulAmanCreatureAI(npc_amanishi_scout); RegisterSpellScript(spell_alert_drums); RegisterSpellScript(spell_summon_amanishi_sentries); RegisterSpellScript(spell_call_of_the_beast); }