Scripts/Shadowfang Keep: dropped deprecated scripts and updated instance script and definitions to Cataclysm

This commit is contained in:
Ovahlord
2023-12-22 14:29:48 +01:00
parent 50a2166fb1
commit 06917b6c43
5 changed files with 71 additions and 551 deletions

View File

@@ -0,0 +1 @@
UPDATE `creature_template` SET `ScriptName`= '' WHERE `ScriptName` IN ('npc_shadowfang_prisoner', 'npc_arugal_voidwalker', 'boss_archmage_arugal');

View File

@@ -94,7 +94,7 @@ Position const FryeMovePos = { -196.2483f, 2197.224f, 79.9315f, 0.0f };
struct boss_apothecary_hummel : public BossAI
{
boss_apothecary_hummel(Creature* creature) : BossAI(creature, DATA_APOTHECARY_HUMMEL), _deadCount(0), _isDead(false) { }
boss_apothecary_hummel(Creature* creature) : BossAI(creature, BOSS_APOTHECARY_HUMMEL), _deadCount(0), _isDead(false) { }
bool OnGossipSelect(Player* player, uint32 menuId, uint32 gossipListId) override
{
@@ -171,7 +171,7 @@ struct boss_apothecary_hummel : public BossAI
events.Reset();
me->SetUninteractible(false);
instance->SetBossState(DATA_APOTHECARY_HUMMEL, DONE);
instance->SetBossState(BOSS_APOTHECARY_HUMMEL, DONE);
Map::PlayerList const& players = me->GetMap()->GetPlayers();
if (!players.isEmpty())

View File

@@ -15,229 +15,50 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* ScriptData
SDName: Instance_Shadowfang_Keep
SD%Complete: 90
SDComment:
SDCategory: Shadowfang Keep
EndScriptData */
#include "ScriptMgr.h"
#include "shadowfang_keep.h"
#include "GameObject.h"
#include "InstanceScript.h"
#include "Log.h"
#include "Map.h"
#include "ScriptedCreature.h"
#include "TemporarySummon.h"
#define MAX_ENCOUNTER 4
enum Yells
ObjectData const creatureData[] =
{
SAY_BOSS_DIE_AD = 4,
SAY_BOSS_DIE_AS = 3,
SAY_ARCHMAGE = 0
{ NPC_BARON_ASHBURY, BOSS_BARON_ASHBURY },
{ NPC_BARON_SILVERLAINE, BOSS_BARON_SILVERLAINE },
{ NPC_COMMANDER_SPRINGVALE, BOSS_COMMANDER_SPRINGVALE },
{ NPC_LORD_WALDEN, BOSS_LORD_WALDEN },
{ NPC_LORD_GODFREY, BOSS_LORD_GODFREY },
{ 0, 0 } // END
};
enum Creatures
DungeonEncounterData const encounters[] =
{
NPC_ASH = 3850,
NPC_ADA = 3849,
NPC_ARCHMAGE_ARUGAL = 4275,
NPC_ARUGAL_VOIDWALKER = 4627
{ BOSS_BARON_ASHBURY, {{ 1069 }} },
{ BOSS_BARON_SILVERLAINE, {{ 1070 }} },
{ BOSS_COMMANDER_SPRINGVALE, {{ 1071 }} },
{ BOSS_LORD_WALDEN, {{ 1073 }} },
{ BOSS_LORD_GODFREY, {{ 1072 }} },
{ BOSS_APOTHECARY_HUMMEL, {{ 2879 }} }
};
enum GameObjects
{
GO_COURTYARD_DOOR = 18895, //door to open when talking to NPC's
GO_SORCERER_DOOR = 18972, //door to open when Fenrus the Devourer
GO_ARUGAL_DOOR = 18971 //door to open when Wolf Master Nandos
};
enum Spells
{
SPELL_ASHCROMBE_TELEPORT = 15742
};
const Position SpawnLocation[] =
{
{-148.199f, 2165.647f, 128.448f, 1.026f},
{-153.110f, 2168.620f, 128.448f, 1.026f},
{-145.905f, 2180.520f, 128.448f, 4.183f},
{-140.794f, 2178.037f, 128.448f, 4.090f},
{-138.640f, 2170.159f, 136.577f, 2.737f}
};
class instance_shadowfang_keep : public InstanceMapScript
{
public:
instance_shadowfang_keep() : InstanceMapScript(SFKScriptName, 33) { }
InstanceScript* GetInstanceScript(InstanceMap* map) const override
{
return new instance_shadowfang_keep_InstanceMapScript(map);
}
struct instance_shadowfang_keep_InstanceMapScript : public InstanceScript
{
instance_shadowfang_keep_InstanceMapScript(InstanceMap* map) : InstanceScript(map)
{
SetHeaders(DataHeader);
SetBossNumber(MAX_ENCOUNTER);
uiPhase = 0;
uiTimer = 0;
}
ObjectGuid uiAshGUID;
ObjectGuid uiAdaGUID;
ObjectGuid uiArchmageArugalGUID;
ObjectGuid DoorCourtyardGUID;
ObjectGuid DoorSorcererGUID;
ObjectGuid DoorArugalGUID;
uint8 uiPhase;
uint16 uiTimer;
void OnCreatureCreate(Creature* creature) override
{
switch (creature->GetEntry())
{
case NPC_ASH: uiAshGUID = creature->GetGUID(); break;
case NPC_ADA: uiAdaGUID = creature->GetGUID(); break;
case NPC_ARCHMAGE_ARUGAL: uiArchmageArugalGUID = creature->GetGUID(); break;
}
}
void OnGameObjectCreate(GameObject* go) override
{
switch (go->GetEntry())
{
case GO_COURTYARD_DOOR:
DoorCourtyardGUID = go->GetGUID();
if (GetBossState(0) == DONE)
HandleGameObject(ObjectGuid::Empty, true, go);
break;
case GO_SORCERER_DOOR:
DoorSorcererGUID = go->GetGUID();
if (GetBossState(2) == DONE)
HandleGameObject(ObjectGuid::Empty, true, go);
break;
case GO_ARUGAL_DOOR:
DoorArugalGUID = go->GetGUID();
if (GetBossState(3) == DONE)
HandleGameObject(ObjectGuid::Empty, true, go);
break;
}
}
void DoSpeech()
{
Creature* pAda = instance->GetCreature(uiAdaGUID);
Creature* pAsh = instance->GetCreature(uiAshGUID);
if (pAda && pAda->IsAlive() && pAsh && pAsh->IsAlive())
{
pAda->AI()->Talk(SAY_BOSS_DIE_AD);
pAsh->AI()->Talk(SAY_BOSS_DIE_AS);
}
}
void SetData(uint32 type, uint32 data) override
{
switch (type)
{
case TYPE_FREE_NPC:
if (data == DONE)
DoUseDoorOrButton(DoorCourtyardGUID);
SetBossState(0, EncounterState(data));
break;
case TYPE_RETHILGORE:
if (data == DONE)
DoSpeech();
SetBossState(1, EncounterState(data));
break;
case TYPE_FENRUS:
switch (data)
{
case DONE:
uiTimer = 1000;
uiPhase = 1;
break;
case 7:
DoUseDoorOrButton(DoorSorcererGUID);
break;
}
SetBossState(2, EncounterState(data));
break;
case TYPE_NANDOS:
if (data == DONE)
DoUseDoorOrButton(DoorArugalGUID);
SetBossState(3, EncounterState(data));
break;
}
}
uint32 GetData(uint32 type) const override
{
switch (type)
{
case TYPE_FREE_NPC:
return GetBossState(0);
case TYPE_RETHILGORE:
return GetBossState(1);
case TYPE_FENRUS:
return GetBossState(2);
case TYPE_NANDOS:
return GetBossState(3);
}
return 0;
}
void Update(uint32 uiDiff) override
{
if (GetData(TYPE_FENRUS) != DONE)
return;
Creature* pArchmage = instance->GetCreature(uiArchmageArugalGUID);
if (!pArchmage || !pArchmage->IsAlive())
return;
if (uiPhase)
{
if (uiTimer <= uiDiff)
{
switch (uiPhase)
{
case 1:
{
Creature* summon = pArchmage->SummonCreature(pArchmage->GetEntry(), SpawnLocation[4], TEMPSUMMON_TIMED_DESPAWN, 10s);
summon->SetImmuneToPC(true);
summon->SetReactState(REACT_DEFENSIVE);
summon->CastSpell(summon, SPELL_ASHCROMBE_TELEPORT, true);
summon->AI()->Talk(SAY_ARCHMAGE);
uiTimer = 2000;
uiPhase = 2;
break;
}
case 2:
{
pArchmage->SummonCreature(NPC_ARUGAL_VOIDWALKER, SpawnLocation[0], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 1min);
pArchmage->SummonCreature(NPC_ARUGAL_VOIDWALKER, SpawnLocation[1], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 1min);
pArchmage->SummonCreature(NPC_ARUGAL_VOIDWALKER, SpawnLocation[2], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 1min);
pArchmage->SummonCreature(NPC_ARUGAL_VOIDWALKER, SpawnLocation[3], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 1min);
uiPhase = 0;
break;
}
}
} else uiTimer -= uiDiff;
}
SetBossNumber(EncounterCount);
LoadObjectData(creatureData, nullptr);
LoadDungeonEncounterData(encounters);
}
};
InstanceScript* GetInstanceScript(InstanceMap* map) const override
{
return new instance_shadowfang_keep_InstanceMapScript(map);
}
};
void AddSC_instance_shadowfang_keep()

View File

@@ -15,354 +15,39 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* ScriptData
SDName: Shadowfang_Keep
SD%Complete: 75
SDComment: npc_shadowfang_prisoner using escortAI for movement to door. Might need additional code in case being attacked. Add proper texts/say().
SDCategory: Shadowfang Keep
EndScriptData */
/* ContentData
npc_shadowfang_prisoner
EndContentData */
#include "ScriptMgr.h"
#include "shadowfang_keep.h"
#include "InstanceScript.h"
#include "Player.h"
#include "ScriptedEscortAI.h"
#include "ScriptedGossip.h"
#include "SpellAuraEffects.h"
#include "SpellScript.h"
/*######
## npc_shadowfang_prisoner
######*/
enum Yells
{
SAY_FREE_AS = 0,
SAY_OPEN_DOOR_AS = 1,
SAY_POST_DOOR_AS = 2,
SAY_FREE_AD = 0,
SAY_OPEN_DOOR_AD = 1,
SAY_POST1_DOOR_AD = 2,
SAY_POST2_DOOR_AD = 3
};
enum Spells
{
SPELL_UNLOCK = 6421,
SPELL_DARK_OFFERING = 7154
};
enum Creatures
{
NPC_ASH = 3850
};
class npc_shadowfang_prisoner : public CreatureScript
{
public:
npc_shadowfang_prisoner() : CreatureScript("npc_shadowfang_prisoner") { }
struct npc_shadowfang_prisonerAI : public EscortAI
{
npc_shadowfang_prisonerAI(Creature* creature) : EscortAI(creature)
{
instance = creature->GetInstanceScript();
}
InstanceScript* instance;
void WaypointReached(uint32 waypointId, uint32 /*pathId*/) override
{
if (Player* player = GetPlayerForEscort())
{
switch (waypointId)
{
case 0:
if (me->GetEntry() == NPC_ASH)
Talk(SAY_FREE_AS, player);
else
Talk(SAY_FREE_AD, player);
break;
case 10:
if (me->GetEntry() == NPC_ASH)
Talk(SAY_OPEN_DOOR_AS, player);
else
Talk(SAY_OPEN_DOOR_AD, player);
break;
case 11:
if (me->GetEntry() == NPC_ASH)
DoCast(me, SPELL_UNLOCK);
break;
case 12:
if (me->GetEntry() == NPC_ASH)
Talk(SAY_POST_DOOR_AS, player);
else
Talk(SAY_POST1_DOOR_AD, player);
instance->SetData(TYPE_FREE_NPC, DONE);
break;
case 13:
if (me->GetEntry() != NPC_ASH)
Talk(SAY_POST2_DOOR_AD, player);
break;
}
}
}
void Reset() override { }
void JustEngagedWith(Unit* /*who*/) override { }
bool OnGossipSelect(Player* player, uint32 /*menuId*/, uint32 gossipListId) override
{
uint32 const action = player->PlayerTalkClass->GetGossipOptionAction(gossipListId);
ClearGossipMenuFor(player);
if (action == GOSSIP_ACTION_INFO_DEF + 1)
{
CloseGossipMenuFor(player);
LoadPath((me->GetEntry() << 3) | 2);
Start(false, player->GetGUID());
}
return true;
}
bool OnGossipHello(Player* player) override
{
uint32 gossipMenuId = player->GetGossipMenuForSource(me);
InitGossipMenuFor(player, gossipMenuId);
if (instance->GetData(TYPE_FREE_NPC) != DONE && instance->GetData(TYPE_RETHILGORE) == DONE)
AddGossipItemFor(player, gossipMenuId, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
SendGossipMenuFor(player, player->GetGossipTextId(me), me->GetGUID());
return true;
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetShadowfangKeepAI<npc_shadowfang_prisonerAI>(creature);
}
};
class npc_arugal_voidwalker : public CreatureScript
{
public:
npc_arugal_voidwalker() : CreatureScript("npc_arugal_voidwalker") { }
CreatureAI* GetAI(Creature* creature) const override
{
return GetShadowfangKeepAI<npc_arugal_voidwalkerAI>(creature);
}
struct npc_arugal_voidwalkerAI : public ScriptedAI
{
npc_arugal_voidwalkerAI(Creature* creature) : ScriptedAI(creature)
{
Initialize();
instance = creature->GetInstanceScript();
}
void Initialize()
{
uiDarkOffering = urand(200, 1000);
}
InstanceScript* instance;
uint32 uiDarkOffering;
void Reset() override
{
Initialize();
}
void UpdateAI(uint32 uiDiff) override
{
if (!UpdateVictim())
return;
if (uiDarkOffering <= uiDiff)
{
if (Creature* pFriend = me->FindNearestCreature(me->GetEntry(), 25.0f, true))
DoCast(pFriend, SPELL_DARK_OFFERING);
else
DoCast(me, SPELL_DARK_OFFERING);
uiDarkOffering = urand(4400, 12500);
} else uiDarkOffering -= uiDiff;
DoMeleeAttackIfReady();
}
void JustDied(Unit* /*killer*/) override
{
instance->SetData(TYPE_FENRUS, instance->GetData(TYPE_FENRUS) + 1);
}
};
};
enum ArugalSpells
{
SPELL_TELE_UPPER = 7587,
SPELL_TELE_SPAWN = 7586,
SPELL_TELE_STAIRS = 7136,
NUM_TELEPORT_SPELLS = 3,
SPELL_ARUGAL_CURSE = 7621,
SPELL_THUNDERSHOCK = 7803,
SPELL_VOIDBOLT = 7588
};
enum ArugalTexts
{
SAY_AGGRO = 1, // You, too, shall serve!
SAY_TRANSFORM = 2, // Release your rage!
SAY_SLAY = 3 // Another falls!
};
enum ArugalEvents
{
EVENT_VOID_BOLT = 1,
EVENT_TELEPORT,
EVENT_THUNDERSHOCK,
EVENT_CURSE
};
class boss_archmage_arugal : public CreatureScript
{
public:
boss_archmage_arugal() : CreatureScript("boss_archmage_arugal") { }
struct boss_archmage_arugalAI : public BossAI
{
boss_archmage_arugalAI(Creature* creature) : BossAI(creature, BOSS_ARUGAL) { }
uint32 teleportSpells[NUM_TELEPORT_SPELLS] =
{
SPELL_TELE_SPAWN,
SPELL_TELE_UPPER,
SPELL_TELE_STAIRS
};
void KilledUnit(Unit* who) override
{
if (who->GetTypeId() == TYPEID_PLAYER)
Talk(SAY_SLAY);
}
void SpellHitTarget(WorldObject* /*target*/, SpellInfo const* spellInfo) override
{
if (spellInfo->Id == SPELL_ARUGAL_CURSE)
Talk(SAY_TRANSFORM);
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
Talk(SAY_AGGRO);
events.ScheduleEvent(EVENT_CURSE, 7s);
events.ScheduleEvent(EVENT_TELEPORT, 15s);
events.ScheduleEvent(EVENT_VOID_BOLT, 1s);
events.ScheduleEvent(EVENT_THUNDERSHOCK, 10s);
}
void AttackStart(Unit* who) override
{
AttackStartCaster(who, 100.0f); // void bolt range is 100.f
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_CURSE:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 30.0f, true))
DoCast(target, SPELL_ARUGAL_CURSE);
events.Repeat(Seconds(15));
break;
case EVENT_TELEPORT:
{
// ensure we never cast the same teleport twice in a row
uint8 spellIndex = urand(1, NUM_TELEPORT_SPELLS-1);
std::swap(teleportSpells[0], teleportSpells[spellIndex]);
DoCast(teleportSpells[0]);
events.Repeat(Seconds(20));
break;
}
case EVENT_THUNDERSHOCK:
DoCastAOE(SPELL_THUNDERSHOCK);
events.Repeat(Seconds(30));
break;
case EVENT_VOID_BOLT:
DoCastVictim(SPELL_VOIDBOLT);
events.Repeat(Seconds(5));
break;
}
}
DoMeleeAttackIfReady();
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetShadowfangKeepAI<boss_archmage_arugalAI>(creature);
}
};
#include "Unit.h"
// 7057 - Haunting Spirits
class spell_shadowfang_keep_haunting_spirits : public SpellScriptLoader
class spell_shadowfang_keep_haunting_spirits : public AuraScript
{
public:
spell_shadowfang_keep_haunting_spirits() : SpellScriptLoader("spell_shadowfang_keep_haunting_spirits") { }
void CalcPeriodic(AuraEffect const* /*aurEff*/, bool& isPeriodic, int32& amplitude)
{
isPeriodic = true;
amplitude = (irand(0, 60) + 30) * IN_MILLISECONDS;
}
class spell_shadowfang_keep_haunting_spirits_AuraScript : public AuraScript
{
void CalcPeriodic(AuraEffect const* /*aurEff*/, bool& isPeriodic, int32& amplitude)
{
isPeriodic = true;
amplitude = (irand(0, 60) + 30) * IN_MILLISECONDS;
}
void HandleDummyTick(AuraEffect const* aurEff)
{
GetTarget()->CastSpell(nullptr, aurEff->GetAmount(), true);
}
void HandleDummyTick(AuraEffect const* aurEff)
{
GetTarget()->CastSpell(nullptr, aurEff->GetAmount(), true);
}
void HandleUpdatePeriodic(AuraEffect* aurEff)
{
aurEff->CalculatePeriodic(GetCaster());
}
void HandleUpdatePeriodic(AuraEffect* aurEff)
{
aurEff->CalculatePeriodic(GetCaster());
}
void Register() override
{
DoEffectCalcPeriodic += AuraEffectCalcPeriodicFn(spell_shadowfang_keep_haunting_spirits_AuraScript::CalcPeriodic, EFFECT_0, SPELL_AURA_DUMMY);
OnEffectPeriodic += AuraEffectPeriodicFn(spell_shadowfang_keep_haunting_spirits_AuraScript::HandleDummyTick, EFFECT_0, SPELL_AURA_DUMMY);
OnEffectUpdatePeriodic += AuraEffectUpdatePeriodicFn(spell_shadowfang_keep_haunting_spirits_AuraScript::HandleUpdatePeriodic, EFFECT_0, SPELL_AURA_DUMMY);
}
};
AuraScript* GetAuraScript() const override
{
return new spell_shadowfang_keep_haunting_spirits_AuraScript();
}
void Register() override
{
DoEffectCalcPeriodic += AuraEffectCalcPeriodicFn(spell_shadowfang_keep_haunting_spirits::CalcPeriodic, EFFECT_0, SPELL_AURA_DUMMY);
OnEffectPeriodic += AuraEffectPeriodicFn(spell_shadowfang_keep_haunting_spirits::HandleDummyTick, EFFECT_0, SPELL_AURA_DUMMY);
OnEffectUpdatePeriodic += AuraEffectUpdatePeriodicFn(spell_shadowfang_keep_haunting_spirits::HandleUpdatePeriodic, EFFECT_0, SPELL_AURA_DUMMY);
}
};
void AddSC_shadowfang_keep()
{
new npc_shadowfang_prisoner();
new npc_arugal_voidwalker();
new boss_archmage_arugal();
new spell_shadowfang_keep_haunting_spirits();
RegisterSpellScript(spell_shadowfang_keep_haunting_spirits);
}

View File

@@ -15,22 +15,35 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DEF_SHADOWFANG_H
#define DEF_SHADOWFANG_H
#ifndef _Shadownfang_Keep_h__
#define _Shadownfang_Keep_h__
#include "CreatureAIImpl.h"
#define SFKScriptName "instance_shadowfang_keep"
#define DataHeader "SK"
constexpr char const* SFKScriptName = "instance_shadowfang_keep";
constexpr char const* DataHeader = "SFK";
enum SKDataTypes
constexpr uint32 const EncounterCount = 6;
enum SFKDataTypes
{
TYPE_FREE_NPC = 1,
TYPE_RETHILGORE = 2,
TYPE_FENRUS = 3,
TYPE_NANDOS = 4,
BOSS_ARUGAL = 5,
DATA_APOTHECARY_HUMMEL = 6
// Encounters
BOSS_BARON_ASHBURY = 0,
BOSS_BARON_SILVERLAINE = 1,
BOSS_COMMANDER_SPRINGVALE = 2,
BOSS_LORD_WALDEN = 3,
BOSS_LORD_GODFREY = 4,
BOSS_APOTHECARY_HUMMEL = 5
};
enum SFKCreatureIds
{
// Bosses
NPC_BARON_ASHBURY = 46962,
NPC_BARON_SILVERLAINE = 3887,
NPC_COMMANDER_SPRINGVALE = 4278,
NPC_LORD_WALDEN = 46963,
NPC_LORD_GODFREY = 46964
};
template <class AI, class T>
@@ -41,4 +54,4 @@ inline AI* GetShadowfangKeepAI(T* obj)
#define RegisterShadowfangKeepCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetShadowfangKeepAI)
#endif
#endif // _Shadownfang_Keep_h__