diff --git a/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/blood_furnace.h b/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/blood_furnace.h index af0ef54fb..985cb7618 100644 --- a/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/blood_furnace.h +++ b/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/blood_furnace.h @@ -21,6 +21,10 @@ #include "CreatureAIImpl.h" #include "Player.h" +#define DataHeader "BF" + +constexpr uint32 EncounterCount = 4; + #define BloodFurnaceScriptName "instance_blood_furnace" enum bloodFurnace @@ -33,8 +37,8 @@ enum bloodFurnace DATA_DOOR1 = 10, DATA_DOOR2 = 11, DATA_DOOR3 = 12, - DATA_DOOR4 = 13, - DATA_DOOR5 = 14, + DATA_BROGGOK_REAR_DOOR = 13, + DATA_BROGGOK_LEVER = 14, DATA_DOOR6 = 15, DATA_PRISON_CELL1 = 20, @@ -55,10 +59,19 @@ enum bloodFurnaceNPC NPC_CHANNELER = 17653 }; +enum BloodFurnaceGO +{ + GO_BROGGOK_DOOR_FRONT = 181822, + GO_BROGGOK_DOOR_REAR = 181819, + GO_BROGGOK_LEVER = 181982 +}; + template inline AI* GetBloodFurnaceAI(T* obj) { return GetInstanceAI(obj, BloodFurnaceScriptName); } +#define RegisterBloodFurnaceCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetBloodFurnaceAI) + #endif diff --git a/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_broggok.cpp b/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_broggok.cpp index 3cc1a18f5..da6ff8e70 100644 --- a/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_broggok.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_broggok.cpp @@ -29,126 +29,63 @@ enum eEnums SPELL_POISON_CLOUD = 30916, SPELL_POISON_BOLT = 30917, SPELL_POISON = 30914, - - EVENT_SPELL_SLIME = 1, - EVENT_SPELL_POISON = 2, - EVENT_SPELL_BOLT = 3 }; -class boss_broggok : public CreatureScript +struct boss_broggok : public BossAI { -public: - boss_broggok() : CreatureScript("boss_broggok") + boss_broggok(Creature* creature) : BossAI(creature, DATA_BROGGOK) { } + + void Reset() override { + _Reset(); + me->SetReactState(REACT_PASSIVE); + me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + me->SetImmuneToAll(true); } - struct boss_broggokAI : public ScriptedAI + void EnterCombat(Unit* /*who*/) override { - boss_broggokAI(Creature* creature) : ScriptedAI(creature), summons(me) - { - instance = creature->GetInstanceScript(); - } + Talk(SAY_AGGRO); + _EnterCombat(); + } - InstanceScript* instance; - SummonList summons; - bool canAttack; - - void Reset() override - { - events.Reset(); - summons.DespawnAll(); - - me->SetReactState(REACT_PASSIVE); - me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - me->SetImmuneToAll(true); - canAttack = false; - - if (instance) - instance->SetData(DATA_BROGGOK, NOT_STARTED); - } - - void EnterCombat(Unit* /*who*/) override - { - Talk(SAY_AGGRO); - } - - void JustSummoned(Creature* summoned) override - { - summons.Summon(summoned); - - summoned->SetFaction(FACTION_MONSTER_2); - summoned->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); - summoned->CastSpell(summoned, SPELL_POISON, true, 0, 0, me->GetGUID()); - } - - void SummonedCreatureDespawn(Creature* summon) override - { - summons.Despawn(summon); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim() || !canAttack) - return; - - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case EVENT_SPELL_SLIME: - me->CastSpell(me->GetVictim(), SPELL_SLIME_SPRAY, false); - events.RepeatEvent(urand(7000, 12000)); - break; - case EVENT_SPELL_BOLT: - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) - me->CastSpell(target, SPELL_POISON_BOLT, false); - events.RepeatEvent(urand(6000, 11000)); - break; - case EVENT_SPELL_POISON: - me->CastSpell(me, SPELL_POISON_CLOUD, false); - events.RepeatEvent(20000); - break; - } - - DoMeleeAttackIfReady(); - } - - void JustDied(Unit* /*killer*/) override - { - if (instance) - { - instance->HandleGameObject(instance->GetGuidData(DATA_DOOR4), true); - instance->HandleGameObject(instance->GetGuidData(DATA_DOOR5), true); - instance->SetData(DATA_BROGGOK, DONE); - } - } - - void DoAction(int32 action) override - { - switch (action) - { - case ACTION_PREPARE_BROGGOK: - me->SetInCombatWithZone(); - break; - case ACTION_ACTIVATE_BROGGOK: - events.ScheduleEvent(EVENT_SPELL_SLIME, 10000); - events.ScheduleEvent(EVENT_SPELL_POISON, 5000); - events.ScheduleEvent(EVENT_SPELL_BOLT, 7000); - - me->SetReactState(REACT_AGGRESSIVE); - me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - me->SetImmuneToAll(false); - canAttack = true; - break; - } - } - }; - - CreatureAI* GetAI(Creature* creature) const override + void JustSummoned(Creature* summoned) override { - return GetBloodFurnaceAI(creature); + summons.Summon(summoned); + + summoned->SetFaction(FACTION_MONSTER_2); + summoned->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + summoned->CastSpell(summoned, SPELL_POISON, true, 0, 0, me->GetGUID()); + } + + void DoAction(int32 action) override + { + switch (action) + { + case ACTION_PREPARE_BROGGOK: + me->SetInCombatWithZone(); + instance->SetBossState(DATA_BROGGOK, IN_PROGRESS); + break; + case ACTION_ACTIVATE_BROGGOK: + scheduler.Schedule(10s, [this](TaskContext context) + { + DoCastVictim(SPELL_SLIME_SPRAY); + context.Repeat(7s, 12s); + }).Schedule(5s, [this](TaskContext context) + { + DoCastRandomTarget(SPELL_POISON_BOLT); + context.Repeat(6s, 11s); + }).Schedule(7s, [this](TaskContext context) + { + DoCastSelf(SPELL_POISON_CLOUD); + context.Repeat(20s); + }); + + me->SetReactState(REACT_AGGRESSIVE); + me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + me->SetImmuneToAll(false); + break; + } } }; @@ -160,12 +97,16 @@ public: bool OnGossipHello(Player* /*player*/, GameObject* go) override { if (InstanceScript* instance = go->GetInstanceScript()) - if (instance->GetData(DATA_BROGGOK) != DONE && instance->GetData(DATA_BROGGOK) != IN_PROGRESS) - if (Creature* broggok = ObjectAccessor::GetCreature(*go, instance->GetGuidData(DATA_BROGGOK))) + { + if (instance->GetBossState(DATA_BROGGOK) == NOT_STARTED) + { + if (Creature* broggok = instance->GetCreature(DATA_BROGGOK)) { instance->SetData(DATA_BROGGOK, IN_PROGRESS); broggok->AI()->DoAction(ACTION_PREPARE_BROGGOK); } + } + } go->UseDoorOrButton(); return false; @@ -173,46 +114,35 @@ public: }; // 30914, 38462 - Poison (Broggok) -class spell_broggok_poison_cloud : public SpellScriptLoader +class spell_broggok_poison_cloud : public AuraScript { -public: - spell_broggok_poison_cloud() : SpellScriptLoader("spell_broggok_poison_cloud") { } + PrepareAuraScript(spell_broggok_poison_cloud); - class spell_broggok_poison_cloud_AuraScript : public AuraScript + bool Validate(SpellInfo const* spellInfo) override { - PrepareAuraScript(spell_broggok_poison_cloud_AuraScript); + if (!sSpellMgr->GetSpellInfo(spellInfo->Effects[EFFECT_0].TriggerSpell)) + return false; + return true; + } - bool Validate(SpellInfo const* spellInfo) override - { - if (!sSpellMgr->GetSpellInfo(spellInfo->Effects[EFFECT_0].TriggerSpell)) - return false; - return true; - } - - void PeriodicTick(AuraEffect const* aurEff) - { - PreventDefaultAction(); - - uint32 triggerSpell = GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell; - int32 mod = int32(((float(aurEff->GetTickNumber()) / aurEff->GetTotalTicks()) * 0.9f + 0.1f) * 10000 * 2 / 3); - GetTarget()->CastCustomSpell(triggerSpell, SPELLVALUE_RADIUS_MOD, mod, (Unit*)nullptr, TRIGGERED_FULL_MASK, nullptr, aurEff); - } - - void Register() override - { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_broggok_poison_cloud_AuraScript::PeriodicTick, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); - } - }; - - AuraScript* GetAuraScript() const override + void PeriodicTick(AuraEffect const* aurEff) { - return new spell_broggok_poison_cloud_AuraScript(); + PreventDefaultAction(); + + uint32 triggerSpell = GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell; + int32 mod = int32(((float(aurEff->GetTickNumber()) / aurEff->GetTotalTicks()) * 0.9f + 0.1f) * 10000 * 2 / 3); + GetTarget()->CastCustomSpell(triggerSpell, SPELLVALUE_RADIUS_MOD, mod, (Unit*)nullptr, TRIGGERED_FULL_MASK, nullptr, aurEff); + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_broggok_poison_cloud::PeriodicTick, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); } }; void AddSC_boss_broggok() { - new boss_broggok(); + RegisterBloodFurnaceCreatureAI(boss_broggok); new go_broggok_lever(); - new spell_broggok_poison_cloud(); + RegisterSpellScript(spell_broggok_poison_cloud); } diff --git a/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_kelidan_the_breaker.cpp b/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_kelidan_the_breaker.cpp index e2191c837..8f5741c63 100644 --- a/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_kelidan_the_breaker.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_kelidan_the_breaker.cpp @@ -301,8 +301,9 @@ public: Creature* GetKelidan() { - if (me->GetInstanceScript()) - return ObjectAccessor::GetCreature(*me, me->GetInstanceScript()->GetGuidData(DATA_KELIDAN)); + if (InstanceScript* instance = me->GetInstanceScript()) + return instance->GetCreature(DATA_KELIDAN); + return nullptr; } diff --git a/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/instance_blood_furnace.cpp b/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/instance_blood_furnace.cpp index 3fe7b4bb8..ba5b2a8b0 100644 --- a/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/instance_blood_furnace.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/instance_blood_furnace.cpp @@ -20,6 +20,25 @@ #include "ScriptMgr.h" #include "blood_furnace.h" +DoorData const doorData[] = +{ + { GO_BROGGOK_DOOR_FRONT, DATA_BROGGOK, DOOR_TYPE_ROOM }, + { GO_BROGGOK_DOOR_REAR, DATA_BROGGOK, DOOR_TYPE_PASSAGE }, + { 0, 0, DOOR_TYPE_ROOM } // END +}; + +ObjectData const gameobjectData[] = +{ + { GO_BROGGOK_DOOR_REAR, DATA_BROGGOK_REAR_DOOR }, + { GO_BROGGOK_LEVER, DATA_BROGGOK_LEVER } +}; + +ObjectData const creatureData[] = +{ + { NPC_BROGGOK, DATA_BROGGOK }, + { NPC_KELIDAN, DATA_KELIDAN } +}; + class instance_blood_furnace : public InstanceMapScript { public: @@ -27,10 +46,15 @@ public: struct instance_blood_furnace_InstanceMapScript : public InstanceScript { - instance_blood_furnace_InstanceMapScript(Map* map) : InstanceScript(map) {} + instance_blood_furnace_InstanceMapScript(Map* map) : InstanceScript(map) + { + SetHeaders(DataHeader); + SetBossNumber(EncounterCount); + LoadDoorData(doorData); + LoadObjectData(creatureData, gameobjectData); + } uint32 _auiEncounter[MAX_ENCOUNTER]; - ObjectGuid _bossGUIDs[3]; ObjectGuid _doorGUIDs[6]; ObjectGuid _prisonGUIDs[4]; @@ -38,8 +62,6 @@ public: uint8 _prisonerCounter[4]; - ObjectGuid _broggokLeverGUID; - void Initialize() override { memset(&_auiEncounter, 0, sizeof(_auiEncounter)); @@ -48,21 +70,12 @@ public: void OnCreatureCreate(Creature* creature) override { - switch (creature->GetEntry()) + if (creature->GetEntry() == NPC_NASCENT_FEL_ORC) { - case NPC_THE_MAKER: - _bossGUIDs[DATA_THE_MAKER] = creature->GetGUID(); - break; - case NPC_BROGGOK: - _bossGUIDs[DATA_BROGGOK] = creature->GetGUID(); - break; - case NPC_KELIDAN: - _bossGUIDs[DATA_KELIDAN] = creature->GetGUID(); - break; - case NPC_NASCENT_FEL_ORC: - StorePrisoner(creature); - break; + StorePrisoner(creature); } + + InstanceScript::OnCreatureCreate(creature); } void OnUnitDeath(Unit* unit) override @@ -83,14 +96,7 @@ public: if (GetData(DATA_THE_MAKER) == DONE) HandleGameObject(go->GetGUID(), true); } - if (go->GetEntry() == 181822) //Broggok Front door - _doorGUIDs[3] = go->GetGUID(); - if (go->GetEntry() == 181819) //Broggok Rear door - { - _doorGUIDs[4] = go->GetGUID(); - if (GetData(DATA_BROGGOK) == DONE) - HandleGameObject(go->GetGUID(), true); - } + if (go->GetEntry() == 181823) //Kelidan exit door _doorGUIDs[5] = go->GetGUID(); @@ -103,24 +109,16 @@ public: if (go->GetEntry() == 181817) //Broggok prison cell back left _prisonGUIDs[3] = go->GetGUID(); - if (go->GetEntry() == 181982) - _broggokLeverGUID = go->GetGUID(); //Broggok lever + InstanceScript::OnGameObjectCreate(go); } ObjectGuid GetGuidData(uint32 data) const override { switch (data) { - case DATA_THE_MAKER: - case DATA_BROGGOK: - case DATA_KELIDAN: - return _bossGUIDs[data]; - case DATA_DOOR1: case DATA_DOOR2: case DATA_DOOR3: - case DATA_DOOR4: - case DATA_DOOR5: case DATA_DOOR6: return _doorGUIDs[data - DATA_DOOR1]; @@ -134,16 +132,40 @@ public: return ObjectGuid::Empty; } + bool SetBossState(uint32 type, EncounterState state) override + { + if (!InstanceScript::SetBossState(type, state)) + return false; + + if (type == DATA_BROGGOK) + { + if (state == IN_PROGRESS) + { + ActivateCell(DATA_PRISON_CELL1); + HandleGameObject(_doorGUIDs[3], false); + } + else if (state == NOT_STARTED) + { + ResetPrisons(); + HandleGameObject(_doorGUIDs[4], false); + HandleGameObject(_doorGUIDs[3], true); + if (GameObject* lever = GetGameObject(DATA_BROGGOK_LEVER)) + { + lever->Respawn(); + } + } + } + + return true; + } + void SetData(uint32 type, uint32 data) override { switch (type) { case DATA_THE_MAKER: - case DATA_BROGGOK: case DATA_KELIDAN: _auiEncounter[type] = data; - if (type == DATA_BROGGOK) - UpdateBroggokEvent(data); break; } @@ -151,74 +173,17 @@ public: SaveToDB(); } - std::string GetSaveData() override - { - OUT_SAVE_INST_DATA; - - std::ostringstream saveStream; - saveStream << "B F " << _auiEncounter[0] << ' ' << _auiEncounter[1] << ' ' << _auiEncounter[2]; - - OUT_SAVE_INST_DATA_COMPLETE; - return saveStream.str(); - } - uint32 GetData(uint32 type) const override { switch (type) { case DATA_THE_MAKER: - case DATA_BROGGOK: case DATA_KELIDAN: return _auiEncounter[type]; } return 0; } - void Load(const char* strIn) override - { - if (!strIn) - { - OUT_LOAD_INST_DATA_FAIL; - return; - } - - OUT_LOAD_INST_DATA(strIn); - - char dataHead1, dataHead2; - - std::istringstream loadStream(strIn); - loadStream >> dataHead1 >> dataHead2; - - if (dataHead1 == 'B' && dataHead2 == 'F') - { - loadStream >> _auiEncounter[0] >> _auiEncounter[1] >> _auiEncounter[2]; - - for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) - if (_auiEncounter[i] == IN_PROGRESS || _auiEncounter[i] == FAIL) - _auiEncounter[i] = NOT_STARTED; - } - - OUT_LOAD_INST_DATA_COMPLETE; - } - - void UpdateBroggokEvent(uint32 data) - { - switch (data) - { - case IN_PROGRESS: - ActivateCell(DATA_PRISON_CELL1); - HandleGameObject(_doorGUIDs[3], false); - break; - case NOT_STARTED: - ResetPrisons(); - HandleGameObject(_doorGUIDs[4], false); - HandleGameObject(_doorGUIDs[3], true); - if (GameObject* lever = instance->GetGameObject(_broggokLeverGUID)) - lever->Respawn(); - break; - } - } - void ResetPrisons() { for (uint8 i = 0; i < 4; ++i) @@ -290,7 +255,7 @@ public: else if (_prisonersCell[2].find(guid) != _prisonersCell[2].end() && --_prisonerCounter[2] <= 0) ActivateCell(DATA_PRISON_CELL4); else if (_prisonersCell[3].find(guid) != _prisonersCell[3].end() && --_prisonerCounter[3] <= 0) - ActivateCell(DATA_DOOR5); + ActivateCell(DATA_BROGGOK_REAR_DOOR); } void ActivateCell(uint8 id) @@ -304,10 +269,15 @@ public: HandleGameObject(_prisonGUIDs[id - DATA_PRISON_CELL1], true); ActivatePrisoners(_prisonersCell[id - DATA_PRISON_CELL1]); break; - case DATA_DOOR5: - HandleGameObject(_doorGUIDs[4], true); - if (Creature* broggok = instance->GetCreature(GetGuidData(DATA_BROGGOK))) + case DATA_BROGGOK_REAR_DOOR: + if (GameObject* go = GetGameObject(DATA_BROGGOK_REAR_DOOR)) + { + HandleGameObject(ObjectGuid::Empty, true, go); + } + if (Creature* broggok = GetCreature(DATA_BROGGOK)) + { broggok->AI()->DoAction(ACTION_ACTIVATE_BROGGOK); + } break; } }