diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/bindings/scripts/include/sc_creature.cpp | 45 | ||||
-rw-r--r-- | src/bindings/scripts/include/sc_creature.h | 9 | ||||
-rw-r--r-- | src/bindings/scripts/scripts/zone/black_temple/boss_supremus.cpp | 219 | ||||
-rw-r--r-- | src/bindings/scripts/scripts/zone/black_temple/boss_warlord_najentus.cpp | 127 | ||||
-rw-r--r-- | src/game/CreatureAI.h | 70 |
5 files changed, 253 insertions, 217 deletions
diff --git a/src/bindings/scripts/include/sc_creature.cpp b/src/bindings/scripts/include/sc_creature.cpp index d52e018275e..7c7e12ebe32 100644 --- a/src/bindings/scripts/include/sc_creature.cpp +++ b/src/bindings/scripts/include/sc_creature.cpp @@ -16,52 +16,49 @@ struct TSpellSummary { uint8 Effects; // set of enum SelectEffect } *SpellSummary; -void SummonList::Despawn(Creature *summon) +void SummonList::DoAction(uint32 entry, uint32 info) { - uint64 guid = summon->GetGUID(); - for(iterator i = begin(); i != end(); ++i) + for(iterator i = begin(); i != end();) { - if(*i == guid) - { - erase(i); - return; - } + Creature *summon = Unit::GetCreature(*m_creature, *i); + ++i; + if(summon && summon->IsAIEnabled) + summon->AI()->DoAction(info); } } void SummonList::DespawnEntry(uint32 entry) { - for(iterator i = begin(); i != end(); ++i) + for(iterator i = begin(); i != end();) { - if(Creature *summon = Unit::GetCreature(*m_creature, *i)) + Creature *summon = Unit::GetCreature(*m_creature, *i); + if(!summon) + erase(i++); + else if(summon->GetEntry() == entry) { - if(summon->GetEntry() == entry) - { - summon->setDeathState(JUST_DIED); - summon->RemoveCorpse(); - i = erase(i); - --i; - } + erase(i++); + summon->setDeathState(JUST_DIED); + summon->RemoveCorpse(); } else - { - i = erase(i); - --i; - } + ++i; } } void SummonList::DespawnAll() { - for(iterator i = begin(); i != end(); ++i) + while(!empty()) { - if(Creature *summon = Unit::GetCreature(*m_creature, *i)) + Creature *summon = Unit::GetCreature(*m_creature, *begin()); + if(!summon) + erase(begin()); + else { + erase(begin()); summon->setDeathState(JUST_DIED); summon->RemoveCorpse(); } } - clear(); } void ScriptedAI::AttackStart(Unit* who, bool melee) diff --git a/src/bindings/scripts/include/sc_creature.h b/src/bindings/scripts/include/sc_creature.h index 47850b0d417..72598a40617 100644 --- a/src/bindings/scripts/include/sc_creature.h +++ b/src/bindings/scripts/include/sc_creature.h @@ -13,14 +13,15 @@ float GetSpellMaxRangeForHostile(uint32 id); -class SummonList : std::list<uint64> +class SummonList : private std::list<uint64> { public: - SummonList(Creature* creature) : m_creature(creature) {} - void Summon(Creature *summon) {push_back(summon->GetGUID());} - void Despawn(Creature *summon); + explicit SummonList(Creature* creature) : m_creature(creature) {} + void Summon(Creature *summon) { push_back(summon->GetGUID()); } + void Despawn(Creature *summon) { remove(summon->GetGUID()); } void DespawnEntry(uint32 entry); void DespawnAll(); + void DoAction(uint32 entry, uint32 info); private: Creature *m_creature; }; diff --git a/src/bindings/scripts/scripts/zone/black_temple/boss_supremus.cpp b/src/bindings/scripts/scripts/zone/black_temple/boss_supremus.cpp index 0985e7b61e3..b5ece4cbe68 100644 --- a/src/bindings/scripts/scripts/zone/black_temple/boss_supremus.cpp +++ b/src/bindings/scripts/scripts/zone/black_temple/boss_supremus.cpp @@ -39,6 +39,18 @@ EndScriptData */ #define CREATURE_VOLCANO 23085 #define CREATURE_STALKER 23095 +#define PHASE_STRIKE 1 +#define PHASE_CHASE 2 + +#define EVENT_BERSERK 1 +#define EVENT_SWITCH_PHASE 2 +#define EVENT_FLAME 3 +#define EVENT_VOLCANO 4 +#define EVENT_SWITCH_TARGET 5 +#define EVENT_HATEFUL_STRIKE 6 + +#define GCD_CAST 1 + struct TRINITY_DLL_DECL molten_flameAI : public NullCreatureAI { molten_flameAI(Creature *c) : NullCreatureAI(c) @@ -57,17 +69,9 @@ struct TRINITY_DLL_DECL boss_supremusAI : public ScriptedAI } ScriptedInstance* pInstance; - - uint32 SummonFlameTimer; - uint32 SwitchTargetTimer; - uint32 PhaseSwitchTimer; - uint32 SummonVolcanoTimer; - uint32 HatefulStrikeTimer; - uint32 BerserkTimer; - - bool Phase1; - + EventMap events; SummonList summons; + uint32 phase; void Reset() { @@ -81,26 +85,20 @@ struct TRINITY_DLL_DECL boss_supremusAI : public ScriptedAI //else ToggleDoors(false); } - HatefulStrikeTimer = 5000; - SummonFlameTimer = 20000; - SwitchTargetTimer = 90000; - PhaseSwitchTimer = 60000; - SummonVolcanoTimer = 5000; - BerserkTimer = 900000; // 15 minute enrage + phase = 0; - Phase1 = true; + events.Reset(); summons.DespawnAll(); - - m_creature->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, false); - m_creature->ApplySpellImmune(0, IMMUNITY_EFFECT,SPELL_EFFECT_ATTACK_ME, false); } void Aggro(Unit *who) { - DoZoneInCombat(); - if(pInstance) pInstance->SetData(DATA_SUPREMUSEVENT, IN_PROGRESS); + + ChangePhase(); + events.ScheduleEvent(900000, EVENT_BERSERK, GCD_CAST); + events.ScheduleEvent(20000, EVENT_FLAME, GCD_CAST); } void ToggleDoors(bool close) @@ -112,6 +110,32 @@ struct TRINITY_DLL_DECL boss_supremusAI : public ScriptedAI } } + void ChangePhase() + { + if(!phase || phase == PHASE_CHASE) + { + phase = PHASE_STRIKE; + summons.DoAction(EVENT_VOLCANO, 0); + events.ScheduleEvent(5000, EVENT_HATEFUL_STRIKE, GCD_CAST, PHASE_STRIKE); + m_creature->SetSpeed(MOVE_RUN, 1.2f); + m_creature->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, false); + m_creature->ApplySpellImmune(0, IMMUNITY_EFFECT,SPELL_EFFECT_ATTACK_ME, false); + } + else + { + phase = PHASE_CHASE; + events.ScheduleEvent(5000, EVENT_VOLCANO, GCD_CAST, PHASE_CHASE); + events.ScheduleEvent(10000, EVENT_SWITCH_TARGET, 0, PHASE_CHASE); + m_creature->SetSpeed(MOVE_RUN, 0.9f); + m_creature->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); + m_creature->ApplySpellImmune(0, IMMUNITY_EFFECT,SPELL_EFFECT_ATTACK_ME, true); + } + DoResetThreat(); + DoZoneInCombat(); + events.SetPhase(phase); + events.ScheduleEvent(60000, EVENT_SWITCH_PHASE, GCD_CAST); + } + void JustDied(Unit *killer) { if(pInstance) @@ -153,83 +177,53 @@ struct TRINITY_DLL_DECL boss_supremusAI : public ScriptedAI if (!UpdateVictim()) return; - if(!m_creature->HasAura(SPELL_BERSERK)) - { - if(BerserkTimer < diff) - DoCast(m_creature, SPELL_BERSERK); - else BerserkTimer -= diff; - } - - if(SummonFlameTimer < diff) - { - DoCast(m_creature, SPELL_MOLTEN_PUNCH); - SummonFlameTimer = 20000; - }else SummonFlameTimer -= diff; - - if(Phase1) - { - if(HatefulStrikeTimer < diff) - { - if(Unit* target = CalculateHatefulStrikeTarget()) - { - DoCast(target, SPELL_HATEFUL_STRIKE); - HatefulStrikeTimer = 5000; - } - }else HatefulStrikeTimer -= diff; - } + events.Update(diff); - if(!Phase1) + while(uint32 eventId = events.ExecuteEvent()) { - if(SwitchTargetTimer < diff) + switch(eventId) { - if(Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1, 100, true)) + case EVENT_BERSERK: + m_creature->CastSpell(m_creature, SPELL_BERSERK, true); + break; + case EVENT_FLAME: + DoCast(m_creature, SPELL_MOLTEN_PUNCH); + events.DelayEvents(1500, GCD_CAST); + events.ScheduleEvent(20000, EVENT_FLAME, GCD_CAST); + break; + case EVENT_HATEFUL_STRIKE: + if(Unit* target = CalculateHatefulStrikeTarget()) + DoCast(target, SPELL_HATEFUL_STRIKE); + events.DelayEvents(1000, GCD_CAST); + events.ScheduleEvent(5000, EVENT_HATEFUL_STRIKE, GCD_CAST, PHASE_STRIKE); + break; + case EVENT_SWITCH_TARGET: + if(Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1, 100, true)) + { + DoResetThreat(); + m_creature->AddThreat(target, 5000000.0f); + DoScriptText(EMOTE_NEW_TARGET, m_creature); + } + events.ScheduleEvent(10000, EVENT_SWITCH_TARGET, 0, PHASE_CHASE); + break; + case EVENT_VOLCANO: { - DoResetThreat(); - m_creature->AddThreat(target, 5000000.0f); - DoScriptText(EMOTE_NEW_TARGET, m_creature); - SwitchTargetTimer = 10000; + Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0, 999, true); + if(!target) target = m_creature->getVictim(); + if(target) + { + DoCast(target, SPELL_VOLCANIC_SUMMON); + DoScriptText(EMOTE_GROUND_CRACK, m_creature); + events.DelayEvents(1500, GCD_CAST); + } + events.ScheduleEvent(10000, EVENT_VOLCANO, GCD_CAST, PHASE_CHASE); + return; } - }else SwitchTargetTimer -= diff; - - if(SummonVolcanoTimer < diff) - { - if(Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0, 999, true)) - { - if(!target) - target = m_creature->getVictim(); - - DoCast(target, SPELL_VOLCANIC_SUMMON); - DoScriptText(EMOTE_GROUND_CRACK, m_creature); - SummonVolcanoTimer = 10000; - } - }else SummonVolcanoTimer -= diff; - } - - if(PhaseSwitchTimer < diff) - { - if(!Phase1) - { - Phase1 = true; - DoResetThreat(); - PhaseSwitchTimer = 60000; - m_creature->SetSpeed(MOVE_RUN, 1.2f); - DoZoneInCombat(); - m_creature->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, false); - m_creature->ApplySpellImmune(0, IMMUNITY_EFFECT,SPELL_EFFECT_ATTACK_ME, false); - } - else - { - Phase1 = false; - DoResetThreat(); - SwitchTargetTimer = 10000; - SummonVolcanoTimer = 2000; - PhaseSwitchTimer = 60000; - m_creature->SetSpeed(MOVE_RUN, 0.9f); - DoZoneInCombat(); - m_creature->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true); - m_creature->ApplySpellImmune(0, IMMUNITY_EFFECT,SPELL_EFFECT_ATTACK_ME, true); + case EVENT_SWITCH_PHASE: + ChangePhase(); + break; } - }else PhaseSwitchTimer -= diff; + } DoMeleeAttackIfReady(); } @@ -237,50 +231,25 @@ struct TRINITY_DLL_DECL boss_supremusAI : public ScriptedAI struct TRINITY_DLL_DECL npc_volcanoAI : public ScriptedAI { - npc_volcanoAI(Creature *c) : ScriptedAI(c) - { - pInstance = ((ScriptedInstance*)c->GetInstanceData()); - } - - ScriptedInstance *pInstance; - - uint32 CheckTimer; - bool Eruption; + npc_volcanoAI(Creature *c) : ScriptedAI(c) {} void Reset() { - CheckTimer = 1500; - Eruption = false; - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + DoCast(m_creature, SPELL_VOLCANIC_ERUPTION); } void Aggro(Unit *who) {} - void MoveInLineOfSight(Unit *who) - { - return; // paralyze the npc - } + void MoveInLineOfSight(Unit *who) {} - void UpdateAI(const uint32 diff) + void DoAction(const uint32 info) { - if(CheckTimer < diff) - { - uint64 SupremusGUID = pInstance->GetData64(DATA_SUPREMUS); - Creature* Supremus = (Unit::GetCreature((*m_creature), SupremusGUID)); - if(!Eruption && !((boss_supremusAI*)Supremus->AI())->Phase1) - { - Eruption = true; - DoCast(m_creature, SPELL_VOLCANIC_ERUPTION); - } - else if(Eruption && ((boss_supremusAI*)Supremus->AI())->Phase1) - { - m_creature->RemoveAura(SPELL_VOLCANIC_ERUPTION); - } - CheckTimer = 1500; - }else CheckTimer -= diff; + m_creature->RemoveAura(SPELL_VOLCANIC_ERUPTION); } + + void UpdateAI(const uint32 diff) {} }; CreatureAI* GetAI_boss_supremus(Creature *_Creature) diff --git a/src/bindings/scripts/scripts/zone/black_temple/boss_warlord_najentus.cpp b/src/bindings/scripts/scripts/zone/black_temple/boss_warlord_najentus.cpp index 9233cc53fca..4560ac3699c 100644 --- a/src/bindings/scripts/scripts/zone/black_temple/boss_warlord_najentus.cpp +++ b/src/bindings/scripts/scripts/zone/black_temple/boss_warlord_najentus.cpp @@ -46,6 +46,15 @@ EndScriptData */ #define GOBJECT_SPINE 185584 +#define EVENT_BERSERK 1 +#define EVENT_YELL 2 +#define EVENT_NEEDLE 3 +#define EVENT_SPINE 4 +#define EVENT_SHIELD 5 + +#define GCD_CAST 1 +#define GCD_YELL 2 + struct TRINITY_DLL_DECL boss_najentusAI : public ScriptedAI { boss_najentusAI(Creature *c) : ScriptedAI(c) @@ -54,21 +63,13 @@ struct TRINITY_DLL_DECL boss_najentusAI : public ScriptedAI } ScriptedInstance* pInstance; - - uint32 NeedleSpineTimer; - uint32 EnrageTimer; - uint32 SpecialYellTimer; - uint32 TidalShieldTimer; - uint32 ImpalingSpineTimer; + EventMap events; uint64 SpineTargetGUID; void Reset() { - EnrageTimer = 480000; - SpecialYellTimer = 45000 + (rand()%76)*1000; - - ResetTimer(); + events.Reset(); SpineTargetGUID = 0; @@ -78,11 +79,8 @@ struct TRINITY_DLL_DECL boss_najentusAI : public ScriptedAI void KilledUnit(Unit *victim) { - switch(rand()%2) - { - case 0: DoScriptText(SAY_SLAY1, m_creature); break; - case 1: DoScriptText(SAY_SLAY2, m_creature); break; - } + DoScriptText(rand()%2 ? SAY_SLAY1 : SAY_SLAY2, m_creature); + events.DelayEvents(5000, GCD_YELL); } void JustDied(Unit *victim) @@ -110,6 +108,9 @@ struct TRINITY_DLL_DECL boss_najentusAI : public ScriptedAI DoScriptText(SAY_AGGRO, m_creature); DoZoneInCombat(); + events.ScheduleEvent(480000, EVENT_BERSERK, GCD_CAST); + events.ScheduleEvent(45000 + (rand()%76)*1000, EVENT_YELL, GCD_YELL); + ResetTimer(); } bool RemoveImpalingSpine() @@ -124,9 +125,9 @@ struct TRINITY_DLL_DECL boss_najentusAI : public ScriptedAI void ResetTimer(uint32 inc = 0) { - NeedleSpineTimer = 10000 + inc; - TidalShieldTimer = 60000 + inc; - ImpalingSpineTimer = 20000 + inc; + events.ScheduleEvent(10000 + inc, EVENT_NEEDLE, GCD_CAST); + events.ScheduleEvent(20000 + inc, EVENT_SPINE, GCD_CAST); + events.ScheduleEvent(60000 + inc, EVENT_SHIELD); } void UpdateAI(const uint32 diff) @@ -134,58 +135,56 @@ struct TRINITY_DLL_DECL boss_najentusAI : public ScriptedAI if (!UpdateVictim()) return; - if(TidalShieldTimer < diff) - { - m_creature->CastSpell(m_creature, SPELL_TIDAL_SHIELD, true); - ResetTimer(45000); - }else TidalShieldTimer -= diff; - - if(EnrageTimer < diff) - { - DoScriptText(SAY_ENRAGE2, m_creature); - m_creature->CastSpell(m_creature, SPELL_BERSERK, true); - EnrageTimer = 600000; - }else EnrageTimer -= diff; - - if(NeedleSpineTimer < diff) - { - //m_creature->CastSpell(m_creature, SPELL_NEEDLE_SPINE, true); - std::list<Unit*> target; - SelectUnitList(target, 3, SELECT_TARGET_RANDOM, 80, true); - for(std::list<Unit*>::iterator i = target.begin(); i != target.end(); ++i) - m_creature->CastSpell(*i, 39835, true); - NeedleSpineTimer = 2000+rand()%1000; - }else NeedleSpineTimer -= diff; - - if(SpecialYellTimer < diff) - { - switch(rand()%2) - { - case 0: DoScriptText(SAY_SPECIAL1, m_creature); break; - case 1: DoScriptText(SAY_SPECIAL2, m_creature); break; - } - SpecialYellTimer = 25000 + (rand()%76)*1000; - }else SpecialYellTimer -= diff; + events.Update(diff); - if(ImpalingSpineTimer < diff) + while(uint32 eventId = events.ExecuteEvent()) { - Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1); - if(!target) target = m_creature->getVictim(); - if(target) + switch(eventId) { - m_creature->CastSpell(target, SPELL_IMPALING_SPINE, true); - SpineTargetGUID = target->GetGUID(); - //must let target summon, otherwise you cannot click the spine - target->SummonGameObject(GOBJECT_SPINE, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), m_creature->GetOrientation(), 0, 0, 0, 0, 30); - - switch(rand()%2) + case EVENT_SHIELD: + m_creature->CastSpell(m_creature, SPELL_TIDAL_SHIELD, true); + ResetTimer(45000); + break; + case EVENT_BERSERK: + DoScriptText(SAY_ENRAGE2, m_creature); + m_creature->CastSpell(m_creature, SPELL_BERSERK, true); + events.DelayEvents(15000, GCD_YELL); + break; + case EVENT_SPINE: { - case 0: DoScriptText(SAY_NEEDLE1, m_creature); break; - case 1: DoScriptText(SAY_NEEDLE2, m_creature); break; + Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1); + if(!target) target = m_creature->getVictim(); + if(target) + { + m_creature->CastSpell(target, SPELL_IMPALING_SPINE, true); + SpineTargetGUID = target->GetGUID(); + //must let target summon, otherwise you cannot click the spine + target->SummonGameObject(GOBJECT_SPINE, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), m_creature->GetOrientation(), 0, 0, 0, 0, 30); + DoScriptText(rand()%2 ? SAY_NEEDLE1 : SAY_NEEDLE2, m_creature); + events.DelayEvents(1500, GCD_CAST); + events.DelayEvents(15000, GCD_YELL); + } + events.ScheduleEvent(21000, EVENT_SPINE, GCD_CAST); + return; } - ImpalingSpineTimer = 21000; + case EVENT_NEEDLE: + { + //m_creature->CastSpell(m_creature, SPELL_NEEDLE_SPINE, true); + std::list<Unit*> target; + SelectUnitList(target, 3, SELECT_TARGET_RANDOM, 80, true); + for(std::list<Unit*>::iterator i = target.begin(); i != target.end(); ++i) + m_creature->CastSpell(*i, 39835, true); + events.ScheduleEvent(15000+rand()%10000, EVENT_NEEDLE, GCD_CAST); + events.DelayEvents(1500, GCD_CAST); + return; + } + case EVENT_YELL: + DoScriptText(rand()%2 ? SAY_SPECIAL1 : SAY_SPECIAL2, m_creature); + events.ScheduleEvent(25000 + (rand()%76)*1000, EVENT_YELL, GCD_YELL); + events.DelayEvents(15000, GCD_YELL); + break; } - }else ImpalingSpineTimer -= diff; + } DoMeleeAttackIfReady(); } diff --git a/src/game/CreatureAI.h b/src/game/CreatureAI.h index c61a410d9b6..695dae447c3 100644 --- a/src/game/CreatureAI.h +++ b/src/game/CreatureAI.h @@ -77,6 +77,76 @@ enum SCEquip EQUIP_UNEQUIP = 0 }; +class EventMap : private std::map<uint32, uint32> +{ + private: + uint32 m_time, m_phase; + public: + explicit EventMap() : m_phase(0), m_time(0) {} + + void Reset() { clear(); m_time = 0; m_phase = 0; } + + void Update(uint32 time) { m_time += time; } + + void SetPhase(uint32 phase) + { + if(phase && phase < 9) + m_phase = (1 << (phase + 24)); + } + + void ScheduleEvent(uint32 time, uint32 eventId, uint32 gcd = 0, uint32 phase = 0) + { + time += m_time; + if(gcd && gcd < 9) + eventId |= (1 << (gcd + 16)); + if(phase && phase < 9) + eventId |= (1 << (phase + 24)); + iterator itr = find(time); + while(itr != end()) + { + ++time; + itr = find(time); + } + insert(std::make_pair(time, eventId)); + } + + uint32 ExecuteEvent() + { + while(!empty()) + { + if(begin()->first > m_time) + return 0; + else if(m_phase && (begin()->second & 0xFF000000) && !(begin()->second & m_phase)) + erase(begin()); + else + { + uint32 eventId = (begin()->second & 0x0000FFFF); + erase(begin()); + return eventId; + } + } + return 0; + } + + void DelayEvents(uint32 time, uint32 gcd) + { + time += m_time; + gcd = (1 << (gcd + 16)); + for(iterator itr = begin(); itr != end();) + { + if(itr->first >= time) + break; + if(itr->second & gcd) + { + ScheduleEvent(time, itr->second); + erase(itr++); + } + else + ++itr; + } + } +}; + class TRINITY_DLL_SPEC UnitAI { protected: |