refactor(Scripts/BloodFurnace): Modernize Broggok script (#14982)

This commit is contained in:
Skjalf
2023-02-12 23:43:33 -03:00
committed by GitHub
parent 10daa206c6
commit 65f031c340
4 changed files with 160 additions and 246 deletions

View File

@@ -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 <class AI, class T>
inline AI* GetBloodFurnaceAI(T* obj)
{
return GetInstanceAI<AI>(obj, BloodFurnaceScriptName);
}
#define RegisterBloodFurnaceCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetBloodFurnaceAI)
#endif

View File

@@ -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<boss_broggokAI>(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);
}

View File

@@ -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;
}

View File

@@ -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;
}
}