Scripts/HallsOfStone: Sjonnir, some improvements

- rewritten to BossAI
- added spawn ordered by percent, according to official data

Closes #10702

Signed-off-by: joschiwald <joschiwald@online.de>
This commit is contained in:
MitchesD
2013-09-02 18:55:52 +02:00
committed by joschiwald
parent 3722fcb850
commit 5e03230f3d
2 changed files with 187 additions and 222 deletions

View File

@@ -0,0 +1,7 @@
DELETE FROM `spelldifficulty_dbc` WHERE `id` IN (51849, 50840, 50834, 50830, 50831);
INSERT INTO `spelldifficulty_dbc`(`id`,`spellid0`,`spellid1`) VALUES
(51849, 51849, 59861),
(50840, 50840, 59848),
(50834, 50834, 59846),
(50830, 50830, 59844),
(50831, 50831, 59845);

View File

@@ -15,280 +15,238 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* Script Data Start
SDName: Boss sjonnir
SDAuthor: LordVanMartin
SD%Complete:
SDComment:
SDCategory:
Script Data End */
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "halls_of_stone.h"
enum Spells
{
SPELL_LIGHTING_RING = 51849, //Periodic Trigger (interval 2s) spell = 50841
H_SPELL_LIGHTING_RING = 59861, //Periodic Trigger (interval 2s) spell = 59849
SPELL_LIGHTING_RING_1 = 50840, //Periodic Trigger (interval 2s) spell = 50841
H_SPELL_LIGHTING_RING_1 = 59848, //Periodic Trigger (interval 2s) spell = 59849
SPELL_STATIC_CHARGE = 50834, //Periodic Trigger 2s interval, spell =50835
H_SPELL_STATIC_CHARGE = 59846, //Periodic Trigger 2s interval, spell =50847
SPELL_CHAIN_LIGHTING = 50830,
H_SPELL_CHAIN_LIGHTING = 59844,
SPELL_LIGHTING_SHIELD = 50831,
H_SPELL_LIGHTING_SHIELD = 59845,
SPELL_FRENZY = 28747
SPELL_LIGHTING_RING = 51849, // Periodic Trigger (interval 2s) spell = 50841
SPELL_LIGHTING_RING_1 = 50840, // Periodic Trigger (interval 2s) spell = 50841
SPELL_STATIC_CHARGE = 50834, // Periodic Trigger 2s interval, spell =50835
SPELL_CHAIN_LIGHTING = 50830,
SPELL_LIGHTING_SHIELD = 50831,
SPELL_FRENZY = 28747
};
enum Yells
{
SAY_AGGRO = 0,
SAY_SLAY = 1,
SAY_DEATH = 2
SAY_AGGRO = 0,
SAY_SLAY = 1,
SAY_DEATH = 2
};
#define EMOTE_GENERIC_FRENZY -1000002
enum SjonnirCreatures
{
CREATURE_FORGED_IRON_TROGG = 27979,
CREATURE_MALFORMED_OOZE = 27981,
CREATURE_FORGED_IRON_DWARF = 27982,
CREATURE_IRON_SLUDGE = 28165
NPC_FORGED_IRON_TROGG = 27979,
NPC_MALFORMED_OOZE = 27981,
NPC_FORGED_IRON_DWARF = 27982,
NPC_IRON_SLUDGE = 28165,
NPC_EARTHEN_DWARF = 27980
};
enum Misc
{
DATA_TIME_BEFORE_OOZE = 150000, // 2min 30 secs
ACTION_OOZE_DEAD = 1,
DATA_ABUSE_THE_OOZE = 2
ACTION_OOZE_DEAD = 1,
DATA_ABUSE_THE_OOZE = 2
};
struct Locations
enum Events
{
float x, y, z;
EVENT_CHAIN_LIGHTNING = 1,
EVENT_LIGHTNING_SHIELD,
EVENT_STATIC_CHARGE,
EVENT_LIGHTNING_RING,
EVENT_SUMMON,
EVENT_FRENZY,
};
static Locations PipeLocations[] =
Position const PipeLocations[] =
{
{1295.44f, 734.07f, 200.3f}, //left
{1297.7f, 595.6f, 199.9f} //right
{ 1295.44f, 734.07f, 200.3f, 0.0f }, // left
{ 1297.7f, 595.6f, 199.9f, 0.0f } // right
};
static Locations CenterPoint = {1295.21f, 667.157f, 189.691f};
Position const CenterPoint = { 1295.21f, 667.157f, 189.691f, 0.0f };
class boss_sjonnir : public CreatureScript
{
public:
boss_sjonnir() : CreatureScript("boss_sjonnir") { }
public:
boss_sjonnir() : CreatureScript("boss_sjonnir") { }
struct boss_sjonnirAI : public ScriptedAI
{
boss_sjonnirAI(Creature* creature) : ScriptedAI(creature), lSummons(me)
struct boss_sjonnirAI : public BossAI
{
instance = creature->GetInstanceScript();
}
boss_sjonnirAI(Creature* creature) : BossAI(creature, DATA_SJONNIR) { }
bool bIsFrenzy;
uint32 uiChainLightningTimer;
uint32 uiLightningShieldTimer;
uint32 uiStaticChargeTimer;
uint32 uiLightningRingTimer;
uint32 uiSummonTimer;
uint32 uiFrenzyTimer;
uint32 uiEncounterTimer;
uint8 abuseTheOoze;
SummonList lSummons;
InstanceScript* instance;
void Reset() OVERRIDE
{
bIsFrenzy = false;
uiEncounterTimer = 0;
uiChainLightningTimer = urand(3000, 8000);
uiLightningShieldTimer = urand(20000, 25000);
uiStaticChargeTimer = urand(20000, 25000);
uiLightningRingTimer = urand(30000, 35000);
uiSummonTimer = 5000;
uiFrenzyTimer = 300000; //5 minutes
abuseTheOoze = 0;
lSummons.DespawnAll();
if (instance)
instance->SetBossState(DATA_SJONNIR, NOT_STARTED);
}
void EnterCombat(Unit* /*who*/) OVERRIDE
{
Talk(SAY_AGGRO);
uiEncounterTimer = 0;
if (instance)
void Reset() OVERRIDE
{
/*
if (GameObject* pDoor = instance->instance->GetGameObject(instance->GetData64(DATA_SJONNIR_DOOR)))
if (pDoor->GetGoState() == GO_STATE_READY)
_Reset();
abuseTheOoze = 0;
}
void EnterCombat(Unit* who) OVERRIDE
{
if (!instance->CheckRequiredBosses(DATA_SJONNIR, who->ToPlayer()))
{
EnterEvadeMode();
return;
}
_EnterCombat();
Talk(SAY_AGGRO);
events.ScheduleEvent(EVENT_CHAIN_LIGHTNING, urand(3000, 8000));
events.ScheduleEvent(EVENT_LIGHTNING_SHIELD, urand(20000, 25000));
events.ScheduleEvent(EVENT_STATIC_CHARGE, urand(20000, 25000));
events.ScheduleEvent(EVENT_LIGHTNING_RING, urand(30000, 35000));
events.ScheduleEvent(EVENT_SUMMON, 5000);
events.ScheduleEvent(EVENT_FRENZY, 300000);
}
void JustSummoned(Creature* summon) OVERRIDE
{
summon->GetMotionMaster()->MovePoint(0, CenterPoint);
/*if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
summon->AI()->AttackStart(target);*/
summons.Summon(summon);
}
void JustDied(Unit* /*killer*/) OVERRIDE
{
_JustDied();
Talk(SAY_DEATH);
}
void KilledUnit(Unit* who) OVERRIDE
{
if (who->GetTypeId() == TYPEID_PLAYER)
Talk(SAY_SLAY);
}
void DoAction(int32 action) OVERRIDE
{
if (action == ACTION_OOZE_DEAD)
++abuseTheOoze;
}
uint32 GetData(uint32 type) const OVERRIDE
{
if (type == DATA_ABUSE_THE_OOZE)
return abuseTheOoze;
return 0;
}
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)
{
EnterEvadeMode();
return;
case EVENT_CHAIN_LIGHTNING:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
DoCast(target, SPELL_CHAIN_LIGHTING);
events.ScheduleEvent(EVENT_CHAIN_LIGHTNING, urand(10000, 15000));
break;
case EVENT_LIGHTNING_SHIELD:
DoCast(me, SPELL_LIGHTING_SHIELD);
break;
case EVENT_STATIC_CHARGE:
DoCastVictim(SPELL_STATIC_CHARGE);
events.ScheduleEvent(EVENT_STATIC_CHARGE, urand(20000, 25000));
break;
case EVENT_LIGHTNING_RING:
DoCast(me, SPELL_LIGHTING_RING);
events.ScheduleEvent(EVENT_LIGHTNING_RING, urand(30000, 35000));
break;
case EVENT_SUMMON:
{
uint8 summonPipe = urand(0, 1);
if (HealthAbovePct(75))
me->SummonCreature(NPC_FORGED_IRON_DWARF, PipeLocations[summonPipe], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 30000);
else if (HealthAbovePct(50))
me->SummonCreature(NPC_FORGED_IRON_TROGG, PipeLocations[summonPipe], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 30000);
else if (HealthAbovePct(25))
me->SummonCreature(NPC_MALFORMED_OOZE, PipeLocations[summonPipe], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 30000);
else
me->SummonCreature(NPC_EARTHEN_DWARF, PipeLocations[summonPipe], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 30000);
events.ScheduleEvent(EVENT_SUMMON, 20000);
break;
}
case EVENT_FRENZY:
/// @todo: add emote
DoCast(me, SPELL_FRENZY, true);
break;
default:
break;
}
*/
instance->SetBossState(DATA_SJONNIR, IN_PROGRESS);
}
}
}
void UpdateAI(uint32 diff) OVERRIDE
{
//Return since we have no target
if (!UpdateVictim())
return;
if (uiChainLightningTimer <= diff)
{
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
DoCast(target, SPELL_CHAIN_LIGHTING);
uiChainLightningTimer = urand(10000, 15000);
} else uiChainLightningTimer -= diff;
if (uiLightningShieldTimer <= diff)
{
DoCast(me, SPELL_LIGHTING_SHIELD);
uiLightningShieldTimer -= diff;
DoMeleeAttackIfReady();
}
if (uiStaticChargeTimer <= diff)
{
DoCastVictim(SPELL_STATIC_CHARGE);
uiStaticChargeTimer = urand(20000, 25000);
} uiStaticChargeTimer -= diff;
private:
uint8 abuseTheOoze;
};
if (uiLightningRingTimer <= diff)
{
if (me->IsNonMeleeSpellCasted(false))
me->InterruptNonMeleeSpells(false);
DoCast(me, SPELL_LIGHTING_RING);
uiLightningRingTimer = urand(30000, 35000);
} else uiLightningRingTimer -= diff;
if (uiSummonTimer <= diff)
{
uint32 uiSummonPipe = rand()%2;
me->SummonCreature(uiEncounterTimer > DATA_TIME_BEFORE_OOZE ? CREATURE_MALFORMED_OOZE :
RAND(CREATURE_FORGED_IRON_DWARF, CREATURE_FORGED_IRON_TROGG),
PipeLocations[uiSummonPipe].x, PipeLocations[uiSummonPipe].y, PipeLocations[uiSummonPipe].z, 0.0f,
TEMPSUMMON_CORPSE_TIMED_DESPAWN, 30000);
uiSummonTimer = 20000;
} else uiSummonTimer -= diff;
if (!bIsFrenzy)
{
if (uiFrenzyTimer <= diff)
{
DoCast(me, SPELL_FRENZY);
bIsFrenzy = true;
}
else uiFrenzyTimer -= diff;
}
uiEncounterTimer +=diff;
DoMeleeAttackIfReady();
}
void JustSummoned(Creature* summon) OVERRIDE
CreatureAI* GetAI(Creature* creature) const OVERRIDE
{
summon->GetMotionMaster()->MovePoint(0, CenterPoint.x, CenterPoint.y, CenterPoint.z);
/*if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
summon->AI()->AttackStart(target);*/
lSummons.Summon(summon);
return GetHallsOfStoneAI<boss_sjonnirAI>(creature);
}
void JustDied(Unit* /*killer*/) OVERRIDE
{
Talk(SAY_DEATH);
lSummons.DespawnAll();
if (instance)
instance->SetBossState(DATA_SJONNIR, DONE);
}
void KilledUnit(Unit* victim) OVERRIDE
{
if (victim->GetTypeId() != TYPEID_PLAYER)
return;
Talk(SAY_SLAY);
}
void DoAction(int32 action) OVERRIDE
{
if (action == ACTION_OOZE_DEAD)
++abuseTheOoze;
}
uint32 GetData(uint32 type) const OVERRIDE
{
if (type == DATA_ABUSE_THE_OOZE)
return abuseTheOoze;
return 0;
}
};
CreatureAI* GetAI(Creature* creature) const OVERRIDE
{
return GetHallsOfStoneAI<boss_sjonnirAI>(creature);
}
};
class npc_malformed_ooze : public CreatureScript
{
public:
npc_malformed_ooze() : CreatureScript("npc_malformed_ooze") { }
public:
npc_malformed_ooze() : CreatureScript("npc_malformed_ooze") { }
struct npc_malformed_oozeAI : public ScriptedAI
{
npc_malformed_oozeAI(Creature* creature) : ScriptedAI(creature) {}
uint32 uiMergeTimer;
void Reset() OVERRIDE
struct npc_malformed_oozeAI : public ScriptedAI
{
uiMergeTimer = 10000;
}
npc_malformed_oozeAI(Creature* creature) : ScriptedAI(creature) { }
void UpdateAI(uint32 diff) OVERRIDE
{
if (uiMergeTimer <= diff)
void Reset() OVERRIDE
{
if (Creature* temp = me->FindNearestCreature(CREATURE_MALFORMED_OOZE, 3.0f, true))
_mergeTimer = 10000;
}
void UpdateAI(uint32 diff) OVERRIDE
{
if (_mergeTimer <= diff)
{
DoSpawnCreature(CREATURE_IRON_SLUDGE, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 20000);
temp->DisappearAndDie();
me->DisappearAndDie();
if (Creature* temp = me->FindNearestCreature(NPC_MALFORMED_OOZE, 3.0f, true))
{
DoSpawnCreature(NPC_IRON_SLUDGE, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 20000);
temp->DisappearAndDie();
me->DisappearAndDie();
}
_mergeTimer = 3000;
}
uiMergeTimer = 3000;
} else uiMergeTimer -= diff;
else
_mergeTimer -= diff;
if (!UpdateVictim())
return;
if (!UpdateVictim())
return;
DoMeleeAttackIfReady();
DoMeleeAttackIfReady();
}
private:
uint32 _mergeTimer;
};
CreatureAI* GetAI(Creature* creature) const OVERRIDE
{
return GetHallsOfStoneAI<npc_malformed_oozeAI>(creature);
}
};
CreatureAI* GetAI(Creature* creature) const OVERRIDE
{
return GetHallsOfStoneAI<npc_malformed_oozeAI>(creature);
}
};
class npc_iron_sludge : public CreatureScript
@@ -307,8 +265,8 @@ class npc_iron_sludge : public CreatureScript
void JustDied(Unit* /*killer*/) OVERRIDE
{
if (Creature* Sjonnir = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_SJONNIR)))
Sjonnir->AI()->DoAction(ACTION_OOZE_DEAD);
if (Creature* sjonnir = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_SJONNIR)))
sjonnir->AI()->DoAction(ACTION_OOZE_DEAD);
}
};