/* * 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 "GameObjectAI.h" #include "InstanceMapScript.h" #include "InstanceScript.h" #include "Player.h" #include "ScriptedCreature.h" #include "SpellAuras.h" #include "SpellScript.h" #include "SpellScriptLoader.h" #include "scholomance.h" Position KirtonosSpawn = Position(315.028, 70.5385, 102.15, 0.385971); class instance_scholomance : public InstanceMapScript { public: instance_scholomance() : InstanceMapScript(ScholomanceScriptName, MAP_SCHOLOMANCE) { } InstanceScript* GetInstanceScript(InstanceMap* map) const override { return new instance_scholomance_InstanceMapScript(map); } struct instance_scholomance_InstanceMapScript : public InstanceScript { instance_scholomance_InstanceMapScript(Map* map) : InstanceScript(map) { _miniBosses = 0; _kirtonosState = 0; _rasHuman = 0; } void OnCreatureCreate(Creature* cr) override { switch (cr->GetEntry()) { case NPC_DARKMASTER_GANDLING: GandlingGUID = cr->GetGUID(); break; } } void OnGameObjectCreate(GameObject* go) override { switch (go->GetEntry()) { case GO_GATE_KIRTONOS: GateKirtonosGUID = go->GetGUID(); break; case GO_DOOR_OPENED_WITH_KEY: go->AllowSaveToDB(true); break; case GO_GATE_GANDLING_DOWN_NORTH: GandlingGatesGUID[0] = go->GetGUID(); break; case GO_GATE_GANDLING_DOWN_EAST: GandlingGatesGUID[1] = go->GetGUID(); break; case GO_GATE_GANDLING_DOWN_SOUTH: GandlingGatesGUID[2] = go->GetGUID(); break; case GO_GATE_GANDLING_UP_NORTH: GandlingGatesGUID[3] = go->GetGUID(); break; case GO_GATE_GANDLING_UP_EAST: GandlingGatesGUID[4] = go->GetGUID(); break; case GO_GATE_GANDLING_UP_SOUTH: GandlingGatesGUID[5] = go->GetGUID(); break; case GO_GATE_GANDLING_ENTRANCE: GandlingGatesGUID[6] = go->GetGUID(); break; case GO_BRAZIER_KIRTONOS: BrazierKirtonosGUID = go->GetGUID(); break; } } ObjectGuid GetGuidData(uint32 type) const override { switch (type) { case GO_GATE_KIRTONOS: return GateKirtonosGUID; case GO_BRAZIER_KIRTONOS: return BrazierKirtonosGUID; case GO_GATE_GANDLING_DOWN_NORTH: return GandlingGatesGUID[0]; case GO_GATE_GANDLING_DOWN_EAST: return GandlingGatesGUID[1]; case GO_GATE_GANDLING_DOWN_SOUTH: return GandlingGatesGUID[2]; case GO_GATE_GANDLING_UP_NORTH: return GandlingGatesGUID[3]; case GO_GATE_GANDLING_UP_EAST: return GandlingGatesGUID[4]; case GO_GATE_GANDLING_UP_SOUTH: return GandlingGatesGUID[5]; case GO_GATE_GANDLING_ENTRANCE: return GandlingGatesGUID[6]; case NPC_DARKMASTER_GANDLING: return GandlingGUID; } return ObjectGuid::Empty; } void SetData(uint32 type, uint32 data) override { switch (type) { case DATA_KIRTONOS_THE_HERALD: switch (data) { case IN_PROGRESS: // summon kirtonos and close door if (_kirtonosState == NOT_STARTED) { if (Creature* kirtonos = instance->SummonCreature(NPC_KIRTONOS, KirtonosSpawn)) { kirtonos->AI()->DoAction(IN_PROGRESS); } if (GameObject* gate = instance->GetGameObject(GetGuidData(GO_GATE_KIRTONOS))) { gate->SetGoState(GO_STATE_READY); } } _kirtonosState = data; break; case FAIL: // open door and reset brazier if (GameObject* gate = instance->GetGameObject(GetGuidData(GO_GATE_KIRTONOS))) { gate->SetGoState(GO_STATE_ACTIVE); } if (GameObject* brazier = instance->GetGameObject(GetGuidData(GO_BRAZIER_KIRTONOS))) { brazier->SetGoState(GO_STATE_READY); brazier->SetLootState(GO_JUST_DEACTIVATED); brazier->Respawn(); } _kirtonosState = NOT_STARTED; break; case DONE: // open door if (GameObject* gate = instance->GetGameObject(GetGuidData(GO_GATE_KIRTONOS))) { gate->SetGoState(GO_STATE_ACTIVE); } [[fallthrough]]; default: _kirtonosState = data; break; } break; case DATA_MINI_BOSSES: ++_miniBosses; if (_miniBosses == 6) { if (Creature* Gandling = instance->GetCreature(GandlingGUID)) { Gandling->AI()->Talk(0); Gandling->AI()->Reset(); } } break; case DATA_DARKMASTER_GANDLING: switch (data) { case DONE: case NOT_STARTED: case FAIL: HandleGameObject(GandlingGatesGUID[6], true); break; case IN_PROGRESS: HandleGameObject(GandlingGatesGUID[6], false); break; } break; case DATA_RAS_HUMAN: _rasHuman = data; break; } SaveToDB(); } uint32 GetData(uint32 type) const override { switch (type) { case DATA_KIRTONOS_THE_HERALD: return _kirtonosState; case DATA_MINI_BOSSES: return _miniBosses; case DATA_RAS_HUMAN: return _rasHuman; } return 0; } void ReadSaveDataMore(std::istringstream& data) override { data >> _kirtonosState; data >> _miniBosses; } void WriteSaveDataMore(std::ostringstream& data) override { data << _kirtonosState << ' ' << _miniBosses; } protected: ObjectGuid GateKirtonosGUID; ObjectGuid GateMiliciaGUID; ObjectGuid GateTheolenGUID; ObjectGuid GatePolkeltGUID; ObjectGuid GateRavenianGUID; ObjectGuid GateBarovGUID; ObjectGuid GateIlluciaGUID; ObjectGuid BrazierKirtonosGUID; ObjectGuid GandlingGatesGUID[7]; // 6 is the entrance ObjectGuid GandlingGUID; // boss uint32 _kirtonosState; uint32 _miniBosses; uint32 _rasHuman; }; }; class spell_scholomance_fixate_aura : public AuraScript { PrepareAuraScript(spell_scholomance_fixate_aura); void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { Unit* target = GetTarget(); if (Unit* caster = GetCaster()) caster->TauntApply(target); } void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { Unit* target = GetTarget(); if (Unit* caster = GetCaster()) caster->TauntFadeOut(target); } void Register() override { OnEffectApply += AuraEffectApplyFn(spell_scholomance_fixate_aura::HandleEffectApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); OnEffectRemove += AuraEffectRemoveFn(spell_scholomance_fixate_aura::HandleEffectRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); } }; class spell_scholomance_boon_of_life_aura : public AuraScript { PrepareAuraScript(spell_scholomance_boon_of_life_aura); void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { if (Unit* caster = GetCaster()) if (Unit* target = GetTarget()) if (Creature* creature = target->ToCreature()) { creature->AI()->AttackStart(caster); creature->AddThreat(caster, 10000.0f); } } void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { if (Unit* target = GetTarget()) if (Creature* creature = target->ToCreature()) if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_CANCEL) { creature->AI()->Talk(TALK_RAS_HUMAN); creature->SetDisplayId(MODEL_RAS_HUMAN); creature->SetHealth(target->GetMaxHealth()); if (InstanceScript* instance = creature->GetInstanceScript()) instance->SetData(DATA_RAS_HUMAN, 1); } } void Register() override { OnEffectRemove += AuraEffectRemoveFn(spell_scholomance_boon_of_life_aura::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL); AfterEffectApply += AuraEffectApplyFn(spell_scholomance_boon_of_life_aura::OnApply, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL); } }; enum OccultistEntries { CASTER_ENTRY = 10472, DARK_SHADE_ENTRY = 11284 }; enum OccultistSpells { BONE_ARMOR_SPELL = 16431, COUNTER_SPELL = 15122, DRAIN_MANA_SPELL = 17243, SHADOWBOLT_VOLLEY_SPELL = 17228 }; class npc_scholomance_occultist : public CreatureScript { public: npc_scholomance_occultist() : CreatureScript("npc_scholomance_occultist") { } struct npc_scholomance_occultistAI: public ScriptedAI { npc_scholomance_occultistAI(Creature* creature) : ScriptedAI(creature) { instance = me->GetInstanceScript(); } uint32 originalDisplayId; EventMap events; InstanceScript* instance; Unit* SelectUnitCasting() { ThreatContainer::StorageType threatlist = me->GetThreatMgr().GetThreatList(); for (ThreatContainer::StorageType::const_iterator itr = threatlist.begin(); itr != threatlist.end(); ++itr) { if (Unit* unit = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid())) { if (unit->HasUnitState(UNIT_STATE_CASTING)) { return unit; } } } return nullptr; } void JustReachedHome() override { events.Reset(); if (me->GetEntry() != CASTER_ENTRY) { me->UpdateEntry(CASTER_ENTRY, nullptr, false); me->SetDisplayId(originalDisplayId); } } void JustEngagedWith(Unit* /*who*/) override { originalDisplayId = me->GetDisplayId(); events.Reset(); events.RescheduleEvent(1, 1s, 7s); events.RescheduleEvent(2, 400ms); events.RescheduleEvent(3, 6s, 15s); } void UpdateAI(uint32 diff) override { if (!UpdateVictim()) { return; } events.Update(diff); if (me->HealthBelowPct(30) && me->GetEntry() != DARK_SHADE_ENTRY) { events.Reset(); me->InterruptNonMeleeSpells(false); me->UpdateEntry(DARK_SHADE_ENTRY, nullptr, false); events.RescheduleEvent(4, 2s, 10s); } if (me->HasUnitState(UNIT_STATE_CASTING)) { return; } switch (events.ExecuteEvent()) { case 1: me->CastSpell(me, BONE_ARMOR_SPELL, false); events.Repeat(60s); break; case 2: if (Unit* target = SelectUnitCasting()) { me->CastSpell(target, COUNTER_SPELL, false); events.Repeat(10s, 20s); } else { events.Repeat(400ms); } break; case 3: if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, PowerUsersSelector(me, POWER_MANA, 20.0f, false))) { me->CastSpell(target, DRAIN_MANA_SPELL, false); } events.Repeat(13s, 20s); break; case 4: me->CastSpell(me->GetVictim(), SHADOWBOLT_VOLLEY_SPELL, true); events.Repeat(11s, 17s); break; } DoMeleeAttackIfReady(); } }; CreatureAI* GetAI(Creature* creature) const override { return GetScholomanceAI(creature); } }; void AddSC_instance_scholomance() { new instance_scholomance(); RegisterSpellScript(spell_scholomance_fixate_aura); RegisterSpellScript(spell_scholomance_boon_of_life_aura); new npc_scholomance_occultist(); }