From fd8db4143c3f8f0b2a0b6de6fec67b3d599ad988 Mon Sep 17 00:00:00 2001 From: Charles A Edwards Date: Fri, 9 Sep 2016 14:12:06 +0100 Subject: [PATCH] Core updated to use the latest version of ScriptDev3 Core updated to use the latest version of ScriptDev3 --- .../blackrock_depths/blackrock_depths.cpp | 946 ++++++++++++-- .../blackrock_depths/blackrock_depths.h | 170 ++- .../boss_emperor_dagran_thaurissan.cpp | 49 +- .../boss_high_interrogator_gerstahn.cpp | 10 +- .../instance_blackrock_depths.cpp | 1130 +++++++++++------ 5 files changed, 1796 insertions(+), 509 deletions(-) diff --git a/src/modules/SD3/scripts/eastern_kingdoms/blackrock_mountain/blackrock_depths/blackrock_depths.cpp b/src/modules/SD3/scripts/eastern_kingdoms/blackrock_mountain/blackrock_depths/blackrock_depths.cpp index eb65c3b93..876e2f461 100644 --- a/src/modules/SD3/scripts/eastern_kingdoms/blackrock_mountain/blackrock_depths/blackrock_depths.cpp +++ b/src/modules/SD3/scripts/eastern_kingdoms/blackrock_mountain/blackrock_depths/blackrock_depths.cpp @@ -28,22 +28,30 @@ * ScriptData * SDName: Blackrock_Depths * SD%Complete: 80 - * SDComment: Quest support: 4001, 4322, 4342, 7604, 9015. + * SDComment: Quest support: 4001, 4134, 4201, 4322, 4342, 7604, 9015. * SDCategory: Blackrock Depths * EndScriptData */ /** * ContentData + * go_bar_beer_keg * go_shadowforge_brazier * go_relic_coffer_door * at_ring_of_law * npc_grimstone * npc_kharan_mighthammer + * npc_phalanx + * npc_mistress_nagmara + * npc_rocknot * npc_marshal_windsor * npc_dughal_stormwing * npc_tobias_seecher - * boss_doomrel + * npc_hurley_blackbreath + * boss_doomrel + * boss_plugger_spazzring + * go_bar_ale_mug + * npc_ironhand_guardian * EndContentData */ @@ -51,6 +59,28 @@ #include "blackrock_depths.h" #include "escort_ai.h" +/*###### +## go_bar_beer_keg +######*/ + +struct go_bar_beer_keg : public GameObjectScript +{ + go_bar_beer_keg() : GameObjectScript("go_bar_beer_keg") {} + + bool OnUse(Player* /*pPlayer*/, GameObject* pGo) override + { + if (ScriptedInstance* pInstance = (ScriptedInstance*)pGo->GetInstanceData()) + { + if (pInstance->GetData(TYPE_HURLEY) == IN_PROGRESS || pInstance->GetData(TYPE_HURLEY) == DONE) // GOs despawning on use, this check should never be true but this is proper to have it there + return false; + else + // Every time we set the event to SPECIAL, the instance script increments the number of broken kegs, capping at 3 + pInstance->SetData(TYPE_HURLEY, SPECIAL); + } + return false; + } +}; + /*###### ## go_shadowforge_brazier ######*/ @@ -99,6 +129,24 @@ struct go_relic_coffer_door : public GameObjectScript } }; + /*###### +## at_shadowforge_bridge +######*/ + +static const float aGuardSpawnPositions[2][4] = +{ + {642.3660f, -274.5155f, -43.10918f, 0.4712389f}, // First guard spawn position + {740.1137f, -283.3448f, -42.75082f, 2.8623400f} // Second guard spawn position +}; + +enum +{ + SAY_GUARD_AGGRO = -1230043 +}; + +// this needs adding - see cmangos commit + + /*###### ## npc_grimstone ######*/ @@ -123,17 +171,17 @@ enum DATA_BANNER_BEFORE_EVENT = 5, // 4 or 6 in total? 1+2+1 / 2+2+2 / 3+3. Depending on this, code should be changed. - MAX_MOB_AMOUNT = 4, MAX_THELDREN_ADDS = 4, MAX_POSSIBLE_THELDREN_ADDS = 8, SPELL_SUMMON_THELRIN_DND = 27517, - /* Other spells used by Grimstone - SPELL_ASHCROMBES_TELEPORT_A = 15742 + // Other spells used by Grimstone + SPELL_ASHCROMBES_TELEPORT_A = 15742, SPELL_ASHCROMBES_TELEPORT_B = 6422, SPELL_ARENA_FLASH_A = 15737, SPELL_ARENA_FLASH_B = 15739, - */ + SPELL_ARENA_FLASH_C = 15740, + SPELL_ARENA_FLASH_D = 15741, QUEST_THE_CHALLENGE = 9015, NPC_THELDREN_QUEST_CREDIT = 16166, @@ -154,7 +202,10 @@ static const float aSpawnPositions[3][4] = }; static const uint32 aGladiator[MAX_POSSIBLE_THELDREN_ADDS] = {NPC_LEFTY, NPC_ROTFANG, NPC_SNOKH, NPC_MALGEN, NPC_KORV, NPC_REZZNIK, NPC_VAJASHNI, NPC_VOLIDA}; -static const uint32 aRingMob[] = {NPC_WORM, NPC_STINGER, NPC_SCREECHER, NPC_THUNDERSNOUT, NPC_CREEPER, NPC_BEETLE}; +static const uint32 aRingMob[2][6] = { + {NPC_WORM, NPC_STINGER, NPC_SCREECHER, NPC_THUNDERSNOUT, NPC_CREEPER, NPC_BEETLE}, // NPC template entry + {4, 2, 5, 3, 3, 7} // Number of NPCs per wave (two waves) +}; static const uint32 aRingBoss[] = {NPC_GOROSH, NPC_GRIZZLE, NPC_EVISCERATOR, NPC_OKTHOR, NPC_ANUBSHIAH, NPC_HEDRUM}; enum Phases @@ -206,7 +257,7 @@ struct npc_grimstone : public CreatureScript { npc_grimstoneAI(Creature* pCreature) : npc_escortAI(pCreature) { - m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + m_pInstance = (instance_blackrock_depths*)pCreature->GetInstanceData(); m_uiMobSpawnId = urand(0, 5); // Select MAX_THELDREN_ADDS(4) random adds for Theldren encounter uint8 uiCount = 0; @@ -222,19 +273,20 @@ struct npc_grimstone : public CreatureScript Reset(); } - ScriptedInstance* m_pInstance; + instance_blackrock_depths* m_pInstance; uint8 m_uiEventPhase; uint32 m_uiEventTimer; uint8 m_uiMobSpawnId; - uint8 m_uiMobDeadCount; + uint8 m_uiAliveSummonedMob; Phases m_uiPhase; uint32 m_uiGladiatorId[MAX_THELDREN_ADDS]; GuidList m_lSummonedGUIDList; + GuidSet m_lArenaCrowd; void Reset() override { @@ -242,7 +294,7 @@ struct npc_grimstone : public CreatureScript m_uiEventTimer = 1000; m_uiEventPhase = 0; - m_uiMobDeadCount = 0; + m_uiAliveSummonedMob = 0; m_uiPhase = PHASE_MOBS; } @@ -250,20 +302,16 @@ struct npc_grimstone : public CreatureScript void JustSummoned(Creature* pSummoned) override { if (!m_pInstance) - { return; - } // Ring mob or boss summoned + float fX, fY, fZ; float fcX, fcY, fcZ; - //m_pInstance->GetArenaCenterCoords(fX, fY, fZ); - AreaTriggerEntry const *at = sAreaTriggerStore.LookupEntry(m_pInstance->GetData(TYPE_SIGNAL)); - if (at) - { - m_creature->GetRandomPoint(at->x, at->y, at->z, 10.0f, fcX, fcY, fcZ); - pSummoned->GetMotionMaster()->MovePoint(1, fcX, fcY, fcZ); - } + m_pInstance->GetArenaCenterCoords(fX, fY, fZ); + m_creature->GetRandomPoint(fX, fY, fZ, 10.0f, fcX, fcY, fcZ); + pSummoned->GetMotionMaster()->MovePoint(1, fcX, fcY, fcZ); + ++m_uiAliveSummonedMob; m_lSummonedGUIDList.push_back(pSummoned->GetObjectGuid()); } @@ -275,50 +323,41 @@ struct npc_grimstone : public CreatureScript { Player* pPlayer = itr->getSource(); if (pPlayer && pPlayer->GetQuestStatus(QUEST_THE_CHALLENGE) == QUEST_STATUS_INCOMPLETE) - { pPlayer->KilledMonsterCredit(NPC_THELDREN_QUEST_CREDIT); - } } } void SummonedCreatureJustDied(Creature* /*pSummoned*/) override { - ++m_uiMobDeadCount; + --m_uiAliveSummonedMob; switch (m_uiPhase) { case PHASE_MOBS: // Ring mob killed - if (m_uiMobDeadCount == MAX_MOB_AMOUNT) - { - m_uiEventTimer = 5000; - m_uiMobDeadCount = 0; - } - break; case PHASE_BOSS: // Ring boss killed // One Boss - if (m_uiMobDeadCount == 1) - { + if (m_uiAliveSummonedMob == 0) m_uiEventTimer = 5000; - m_uiMobDeadCount = 0; - } break; case PHASE_GLADIATORS: // Theldren and his band killed // Adds + Theldren - if (m_uiMobDeadCount == MAX_THELDREN_ADDS + 1) + if (m_uiAliveSummonedMob == 0) { m_uiEventTimer = 5000; - m_uiMobDeadCount = 0; DoChallengeQuestCredit(); } break; } } - void SummonRingMob(uint32 uiEntry, SpawnPosition uiPosition) + void SummonRingMob(uint32 uiEntry, uint8 uiNpcPerWave, SpawnPosition uiPosition) { float fX, fY, fZ; - m_creature->GetRandomPoint(aSpawnPositions[uiPosition][0], aSpawnPositions[uiPosition][1], aSpawnPositions[uiPosition][2], 2.0f, fX, fY, fZ); - m_creature->SummonCreature(uiEntry, fX, fY, fZ, 0, TEMPSUMMON_DEAD_DESPAWN, 0); + for (uint8 i = 0; i < uiNpcPerWave; ++i) + { + m_creature->GetRandomPoint(aSpawnPositions[uiPosition][0], aSpawnPositions[uiPosition][1], aSpawnPositions[uiPosition][2], 2.0f, fX, fY, fZ); + m_creature->SummonCreature(uiEntry, fX, fY, fZ, 0, TEMPSUMMON_DEAD_DESPAWN, 0); + } } void WaypointReached(uint32 uiPointId) override @@ -326,7 +365,7 @@ struct npc_grimstone : public CreatureScript switch (uiPointId) { case 0: // Middle reached first time - DoScriptText(urand(0, 1) ? SAY_START_1 : SAY_START_2, m_creature); + DoScriptText(SAY_START_1, m_creature); SetEscortPaused(true); m_uiEventTimer = 5000; break; @@ -339,7 +378,7 @@ struct npc_grimstone : public CreatureScript SetEscortPaused(true); break; case 3: // Middle reached second time - DoScriptText(urand(0, 1) ? SAY_SUMMON_BOSS_1 : SAY_SUMMON_BOSS_2, m_creature); + DoScriptText(SAY_SUMMON_BOSS_1, m_creature); break; case 4: // Reached North Gate DoScriptText(SAY_OPEN_NORTH_GATE, m_creature); @@ -350,7 +389,7 @@ struct npc_grimstone : public CreatureScript if (m_pInstance) { m_pInstance->SetData(TYPE_RING_OF_LAW, DONE); - debug_log("SD3: npc_grimstone: event reached end and set complete."); + // debug_log("SD2: npc_grimstone: event reached end and set complete."); } break; } @@ -359,14 +398,12 @@ struct npc_grimstone : public CreatureScript void UpdateEscortAI(const uint32 uiDiff) override { if (!m_pInstance) - { return; - } if (m_pInstance->GetData(TYPE_RING_OF_LAW) == FAIL) { // Reset Doors - if (m_uiEventPhase >= 9) // North Gate is opened + if (m_uiEventPhase >= 10) // North Gate is opened { m_pInstance->DoUseDoorOrButton(GO_ARENA_2); m_pInstance->DoUseDoorOrButton(GO_ARENA_4); @@ -381,9 +418,7 @@ struct npc_grimstone : public CreatureScript for (GuidList::const_iterator itr = m_lSummonedGUIDList.begin(); itr != m_lSummonedGUIDList.end(); ++itr) { if (Creature* pSummoned = m_creature->GetMap()->GetCreature(*itr)) - { pSummoned->ForcedDespawn(); - } } m_lSummonedGUIDList.clear(); @@ -400,8 +435,20 @@ struct npc_grimstone : public CreatureScript { case 0: // Shortly after spawn, start walking - // DoScriptText(-1000000, m_creature); // no more text on spawn + DoCastSpellIfCan(m_creature, SPELL_ASHCROMBES_TELEPORT_A, CAST_TRIGGERED); + DoScriptText(SAY_START_2, m_creature); m_pInstance->DoUseDoorOrButton(GO_ARENA_4); + // Some of the NPCs in the crowd do cheer emote at event start + // we randomly select 25% of the NPCs to do this + m_pInstance->GetArenaCrowdGuid(m_lArenaCrowd); + for (GuidSet::const_iterator itr = m_lArenaCrowd.begin(); itr != m_lArenaCrowd.end(); ++itr) + { + if (Creature* pSpectator = m_creature->GetMap()->GetCreature(*itr)) + { + if (urand(0, 3) < 1) + pSpectator->HandleEmote(EMOTE_ONESHOT_CHEER); + } + } Start(false); SetEscortPaused(false); m_uiEventTimer = 0; @@ -416,61 +463,68 @@ struct npc_grimstone : public CreatureScript break; case 3: // Open East Gate + DoCastSpellIfCan(m_creature, SPELL_ARENA_FLASH_A, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_ARENA_FLASH_B, CAST_TRIGGERED); m_pInstance->DoUseDoorOrButton(GO_ARENA_1); m_uiEventTimer = 3000; break; case 4: - SetEscortPaused(false); - m_creature->SetVisibility(VISIBILITY_OFF); - // Summon Ring Mob(s) - SummonRingMob(aRingMob[m_uiMobSpawnId], POS_EAST); - m_uiEventTimer = 8000; + // timer for teleport out spell which has 2000 ms cast time + DoCastSpellIfCan(m_creature, SPELL_ASHCROMBES_TELEPORT_B, CAST_TRIGGERED); + m_uiEventTimer = 2500; break; case 5: + m_creature->SetVisibility(VISIBILITY_OFF); + SetEscortPaused(false); // Summon Ring Mob(s) - SummonRingMob(aRingMob[m_uiMobSpawnId], POS_EAST); - SummonRingMob(aRingMob[m_uiMobSpawnId], POS_EAST); - m_uiEventTimer = 8000; - break; - case 6: - // Summon Ring Mob(s) - SummonRingMob(aRingMob[m_uiMobSpawnId], POS_EAST); - m_uiEventTimer = 0; + SummonRingMob(aRingMob[0][m_uiMobSpawnId], aRingMob[1][m_uiMobSpawnId], POS_EAST); + m_uiEventTimer = 16000; break; case 7: - // Summoned Mobs are dead, continue event - m_creature->SetVisibility(VISIBILITY_ON); - m_pInstance->DoUseDoorOrButton(GO_ARENA_1); - // DoScriptText(-1000000, m_creature); // after killed the mobs, no say here - SetEscortPaused(false); + // Summon Ring Mob(s) + SummonRingMob(aRingMob[0][m_uiMobSpawnId], aRingMob[1][m_uiMobSpawnId], POS_EAST); m_uiEventTimer = 0; break; case 8: + // Summoned Mobs are dead, continue event + DoScriptText(SAY_SUMMON_BOSS_2, m_creature); + m_creature->SetVisibility(VISIBILITY_ON); + DoCastSpellIfCan(m_creature, SPELL_ASHCROMBES_TELEPORT_A, CAST_TRIGGERED); + m_pInstance->DoUseDoorOrButton(GO_ARENA_1); + SetEscortPaused(false); + m_uiEventTimer = 0; + break; + case 9: // Open North Gate + DoCastSpellIfCan(m_creature, SPELL_ARENA_FLASH_C, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_ARENA_FLASH_D, CAST_TRIGGERED); m_pInstance->DoUseDoorOrButton(GO_ARENA_2); m_uiEventTimer = 5000; break; - case 9: + case 10: + // timer for teleport out spell which has 2000 ms cast time + DoCastSpellIfCan(m_creature, SPELL_ASHCROMBES_TELEPORT_B, CAST_TRIGGERED); + m_uiEventTimer = 2500; + break; + case 11: // Summon Boss m_creature->SetVisibility(VISIBILITY_OFF); // If banner summoned after start, then summon Thelden after the creatures are dead if (m_pInstance->GetData(TYPE_RING_OF_LAW) == SPECIAL && m_uiPhase == PHASE_MOBS) { m_uiPhase = PHASE_GLADIATORS; - SummonRingMob(NPC_THELDREN, POS_NORTH); + SummonRingMob(NPC_THELDREN, 1, POS_NORTH); for (uint8 i = 0; i < MAX_THELDREN_ADDS; ++i) - { - SummonRingMob(m_uiGladiatorId[i], POS_NORTH); - } + SummonRingMob(m_uiGladiatorId[i], 1, POS_NORTH); } else { m_uiPhase = PHASE_BOSS; - SummonRingMob(aRingBoss[urand(0, 5)], POS_NORTH); + SummonRingMob(aRingBoss[urand(0, 5)], 1, POS_NORTH); } m_uiEventTimer = 0; break; - case 10: + case 12: // Boss dead m_lSummonedGUIDList.clear(); m_pInstance->DoUseDoorOrButton(GO_ARENA_2); @@ -483,9 +537,7 @@ struct npc_grimstone : public CreatureScript ++m_uiEventPhase; } else - { m_uiEventTimer -= uiDiff; - } } } }; @@ -516,6 +568,334 @@ struct spell_banner_of_provocation : public SpellScript } }; + +/*###### ++## npc_phalanx ++######*/ + +enum +{ + YELL_PHALANX_AGGRO = -1230040, + + SPELL_THUNDERCLAP = 15588, + SPELL_MIGHTY_BLOW = 14099, + SPELL_FIREBALL_VOLLEY = 15285, +}; + +struct npc_phalanxAI : public npc_escortAI +{ + npc_phalanxAI(Creature* pCreature) : npc_escortAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + + Reset(); + } + + ScriptedInstance* m_pInstance; + + float m_fKeepDoorOrientation; + uint32 uiThunderclapTimer; + uint32 uiMightyBlowTimer; + uint32 uiFireballVolleyTimer; + uint32 uiCallPatrolTimer; + + void Reset() override + { + // If reset after an fight, it means Phalanx has already started moving (if not already reached door) + // so we made him restart right before reaching the door to guard it (again) + if (HasEscortState(STATE_ESCORT_ESCORTING) || HasEscortState(STATE_ESCORT_PAUSED)) + { + SetCurrentWaypoint(1); + SetEscortPaused(false); + } + + m_fKeepDoorOrientation = 2.06059f; + uiThunderclapTimer = 0; + uiMightyBlowTimer = 0; + uiFireballVolleyTimer = 0; + uiCallPatrolTimer = 0; + } + + void Aggro(Unit* /*pWho*/) override + { + uiThunderclapTimer = 12000; + uiMightyBlowTimer = 15000; + uiFireballVolleyTimer = 1; + } + + void WaypointReached(uint32 uiPointId) override + { + if (!m_pInstance) + return; + + switch (uiPointId) + { + case 0: + DoScriptText(YELL_PHALANX_AGGRO, m_creature); + break; + case 1: + SetEscortPaused(true); + // There are two ways of activating Phalanx: completing Rocknot event, making Phalanx hostile to anyone + // killing Plugger making Phalanx hostile to Horde (do not ask why) + // In the later case, Phalanx should also spawn the bar patrol with some delay and only then set the Plugger + // event to DONE. In the weird case where Plugger was previously killed (event == DONE) but Phalanx is reactivated + // (like on reset after a wipe), do not spawn the patrol again + if (m_pInstance->GetData(TYPE_PLUGGER) == DONE || m_pInstance->GetData(TYPE_PLUGGER) == IN_PROGRESS) + { + m_creature->SetFactionTemporary(FACTION_IRONFORGE, TEMPFACTION_NONE); + if (m_pInstance->GetData(TYPE_PLUGGER) == IN_PROGRESS) + { + uiCallPatrolTimer = 10000; + m_pInstance->SetData(TYPE_PLUGGER, DONE); + } + } + else + m_creature->SetFactionTemporary(FACTION_DARK_IRON, TEMPFACTION_NONE); + + m_creature->SetFacingTo(m_fKeepDoorOrientation); + break; + } + } + + void UpdateEscortAI(const uint32 uiDiff) override + { + if (!m_pInstance) + return; + + if (uiCallPatrolTimer) + { + if (uiCallPatrolTimer < uiDiff && m_pInstance->GetData(TYPE_BAR) != DONE) + { + m_pInstance->SetData(TYPE_BAR, IN_PROGRESS); + uiCallPatrolTimer = 0; + } + else + uiCallPatrolTimer -= uiDiff; + } + + // Combat check + if (m_creature->SelectHostileTarget() && m_creature->getVictim()) + { + if (uiThunderclapTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_THUNDERCLAP) == CAST_OK) + uiThunderclapTimer = 10000; + } + else + uiThunderclapTimer -= uiDiff; + + if (uiMightyBlowTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_MIGHTY_BLOW) == CAST_OK) + uiMightyBlowTimer = 10000; + } + else + uiMightyBlowTimer -= uiDiff; + + if (m_creature->GetHealthPercent() < 51.0f) + { + if (uiFireballVolleyTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_FIREBALL_VOLLEY) == CAST_OK) + uiFireballVolleyTimer = 15000; + } + else + uiFireballVolleyTimer -= uiDiff; + } + + DoMeleeAttackIfReady(); + } + } +}; + +struct npc_phalanx : public CreatureScript +{ + npc_phalanx() : CreatureScript("npc_phalanx") {} + + + CreatureAI* GetAI(Creature* pCreature) override + { + return new npc_phalanxAI(pCreature); + } +}; + + +/*###### +## npc_mistress_nagmara +######*/ + +enum +{ + GOSSIP_ITEM_NAGMARA = -3230003, + GOSSIP_ID_NAGMARA = 2727, + GOSSIP_ID_NAGMARA_2 = 2729, + SPELL_POTION_LOVE = 14928, + SPELL_NAGMARA_ROCKNOT = 15064, + + SAY_NAGMARA_1 = -1230066, + SAY_NAGMARA_2 = -1230067, + TEXTEMOTE_NAGMARA = -1230068, + TEXTEMOTE_ROCKNOT = -1230069, + + QUEST_POTION_LOVE = 4201 +}; + +struct npc_mistress_nagmaraAI : public ScriptedAI +{ + npc_mistress_nagmaraAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + Creature* pRocknot; + + uint8 m_uiPhase; + uint32 m_uiPhaseTimer; + + void Reset() override + { + m_uiPhase = 0; + m_uiPhaseTimer = 0; + } + + void DoPotionOfLoveIfCan() + { + if (!m_pInstance) + return; + + pRocknot = m_pInstance->GetSingleCreatureFromStorage(NPC_PRIVATE_ROCKNOT); + if (!pRocknot) + return; + + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + m_creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + pRocknot->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); + + m_creature->GetMotionMaster()->MoveIdle(); + m_creature->GetMotionMaster()->MoveFollow(pRocknot, 2.0f, 0); + m_uiPhase = 1; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (m_uiPhaseTimer) + { + if (m_uiPhaseTimer <= uiDiff) + m_uiPhaseTimer = 0; + else + { + m_uiPhaseTimer -= uiDiff; + return; + } + } + + if (!pRocknot) + return; + + switch (m_uiPhase) + { + case 0: // Phase 0 : Nagmara patrols in the bar to serve patrons or is following Rocknot passively + break; + case 1: // Phase 1 : Nagmara is moving towards Rocknot + if (m_creature->IsWithinDist2d(pRocknot->GetPositionX(), pRocknot->GetPositionY(), 5.0f)) + { + m_creature->GetMotionMaster()->MoveIdle(); + m_creature->SetFacingToObject(pRocknot); + pRocknot->SetFacingToObject(m_creature); + DoScriptText(SAY_NAGMARA_1, m_creature); + m_uiPhase++; + m_uiPhaseTimer = 5000; + } + else + m_creature->GetMotionMaster()->MoveFollow(pRocknot, 2.0f, 0); + break; + case 2: // Phase 2 : Nagmara is "seducing" Rocknot + DoScriptText(SAY_NAGMARA_2, m_creature); + m_uiPhaseTimer = 4000; + m_uiPhase++; + break; + case 3: // Phase 3: Nagmara give potion to Rocknot and Rocknot escort AI will handle the next part of the event + if (DoCastSpellIfCan(m_creature, SPELL_POTION_LOVE) == CAST_OK) + { + m_uiPhase = 0; + m_pInstance->SetData(TYPE_NAGMARA, SPECIAL); + } + break; + case 4: // Phase 4 : make the lovers face each other + m_creature->SetFacingToObject(pRocknot); + pRocknot->SetFacingToObject(m_creature); + m_uiPhaseTimer = 4000; + m_uiPhase++; + m_pInstance->SetData(TYPE_NAGMARA, DONE); + break; + case 5: // Phase 5 : Nagmara and Rocknot are under the stair kissing (this phase repeats endlessly) + DoScriptText(TEXTEMOTE_NAGMARA, m_creature); + DoScriptText(TEXTEMOTE_ROCKNOT, pRocknot); + DoCastSpellIfCan(m_creature, SPELL_NAGMARA_ROCKNOT); + pRocknot->CastSpell(pRocknot, SPELL_NAGMARA_ROCKNOT, false); + m_uiPhaseTimer = 12000; + break; + } + } +}; + +struct npc_mistress_nagmara : public CreatureScript +{ + npc_mistress_nagmara() : CreatureScript("npc_mistress_nagmara") {} + + CreatureAI* GetAI(Creature* pCreature) override + { + return new npc_mistress_nagmaraAI(pCreature); + } + + bool OnGossipHello(Player* pPlayer, Creature* pCreature) override + { + if (pCreature->IsQuestGiver()) + pPlayer->PrepareQuestMenu(pCreature->GetObjectGuid()); + + if (pPlayer->GetQuestStatus(QUEST_POTION_LOVE) == QUEST_STATUS_COMPLETE) + { + pPlayer->ADD_GOSSIP_ITEM_ID(GOSSIP_ICON_CHAT, GOSSIP_ITEM_NAGMARA, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + pPlayer->SEND_GOSSIP_MENU(GOSSIP_ID_NAGMARA_2, pCreature->GetObjectGuid()); + } + else + pPlayer->SEND_GOSSIP_MENU(GOSSIP_ID_NAGMARA, pCreature->GetObjectGuid()); + + return true; + } + + bool OnGossipSelect(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction) override + { + switch (uiAction) + { + case GOSSIP_ACTION_INFO_DEF+1: + pPlayer->CLOSE_GOSSIP_MENU(); + if (npc_mistress_nagmaraAI* pNagmaraAI = dynamic_cast(pCreature->AI())) + pNagmaraAI->DoPotionOfLoveIfCan(); + break; + } + return true; + } + + bool OnQuestRewarded(Player* /*pPlayer*/, Creature* pCreature, Quest const* pQuest) override + { + ScriptedInstance* pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + + if (!pInstance) + return true; + + if (pQuest->GetQuestId() == QUEST_POTION_LOVE) + { + if (npc_mistress_nagmaraAI* pNagmaraAI = dynamic_cast(pCreature->AI())) + pNagmaraAI->DoPotionOfLoveIfCan(); + } + + return true; + } +}; + /*###### ## npc_rocknot ######*/ @@ -686,6 +1066,7 @@ struct npc_rocknot : public CreatureScript } }; + /*###### ## npc_marshal_windsor ######*/ @@ -1081,6 +1462,143 @@ struct npc_tobias_seecher : public CreatureScript } }; + +/*###### + ## npc_hurley_blackbreath + ######*/ + +enum +{ + YELL_HURLEY_SPAWN = -1230041, + SAY_HURLEY_AGGRO = -1230042, + + // SPELL_DRUNKEN_RAGE = 14872, + SPELL_FLAME_BREATH = 9573, + + NPC_RIBBLY_SCREWSPIGOT = 9543, + NPC_RIBBLY_CRONY = 10043, +}; + +struct npc_hurley_blackbreath : public CreatureScript +{ + npc_hurley_blackbreath() : CreatureScript("npc_hurley_blackbreath") {} + + struct npc_hurley_blackbreathAI : public npc_escortAI + { + npc_hurley_blackbreathAI(Creature* pCreature) : npc_escortAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 uiFlameBreathTimer; + uint32 m_uiEventTimer; + bool bIsEnraged; + + void Reset() override + { + // If reset after an fight, we made him move to the keg room (end of the path) + if (HasEscortState(STATE_ESCORT_ESCORTING) || HasEscortState(STATE_ESCORT_PAUSED)) + { + SetCurrentWaypoint(5); + SetEscortPaused(false); + } + else + m_uiEventTimer = 1000; + + bIsEnraged = false; + } + + // We want to prevent Hurley to go rampage on Ribbly and his friends. + // Everybody loves Ribbly. Except his family. They want him dead. + void AttackStart(Unit* pWho) override + { + if (pWho) + { + if (pWho->GetEntry() == NPC_RIBBLY_SCREWSPIGOT || pWho->GetEntry() == NPC_RIBBLY_CRONY) + return; + else + ScriptedAI::AttackStart(pWho); + } + } + + void Aggro(Unit* /*pWho*/) override + { + uiFlameBreathTimer = 7000; + bIsEnraged = false; + DoScriptText(SAY_HURLEY_AGGRO, m_creature); + } + + void WaypointReached(uint32 uiPointId) override + { + if (!m_pInstance) + return; + + switch (uiPointId) + { + case 1: + DoScriptText(YELL_HURLEY_SPAWN, m_creature); + SetRun(true); + break; + case 5: + SetEscortPaused(true); + break; + default: + break; + } + } + + void UpdateEscortAI(const uint32 uiDiff) override + { + if (!m_pInstance) + return; + + // Combat check + if (m_creature->SelectHostileTarget() && m_creature->getVictim()) + { + if (uiFlameBreathTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_FLAME_BREATH) == CAST_OK) + uiFlameBreathTimer = 10000; + } + else + uiFlameBreathTimer -= uiDiff; + + if (m_creature->GetHealthPercent() < 31.0f && !bIsEnraged) + { + if (DoCastSpellIfCan(m_creature, SPELL_DRUNKEN_RAGE) == CAST_OK) + bIsEnraged = true; + } + + DoMeleeAttackIfReady(); + } + else + { + if (m_uiEventTimer) + { + if (m_uiEventTimer < uiDiff) + { + Start(false); + SetEscortPaused(false); + m_uiEventTimer = 0; + } + else + m_uiEventTimer -= uiDiff; + } + } + } + }; + + CreatureAI* GetAI(Creature* pCreature) override + { + return new npc_hurley_blackbreathAI(pCreature); + } +}; + + /*###### ## boss_doomrel ######*/ @@ -1131,6 +1649,206 @@ struct boss_doomrel : public CreatureScript }; +/*###### +## boss_plugger_spazzring +######*/ + +enum +{ + SAY_OOC_1 = -1230050, + SAY_OOC_2 = -1230051, + SAY_OOC_3 = -1230052, + SAY_OOC_4 = -1230053, + + YELL_STOLEN_1 = -1230054, + YELL_STOLEN_2 = -1230055, + YELL_STOLEN_3 = -1230056, + YELL_AGRRO_1 = -1230057, + YELL_AGRRO_2 = -1230058, + YELL_PICKPOCKETED = -1230059, + + // spells + SPELL_BANISH = 8994, + SPELL_CURSE_OF_TONGUES = 13338, + SPELL_DEMON_ARMOR = 13787, + SPELL_IMMOLATE = 12742, + SPELL_SHADOW_BOLT = 12739, + SPELL_PICKPOCKET = 921, +}; + +static const int aRandomSays[] = { SAY_OOC_1, SAY_OOC_2, SAY_OOC_3, SAY_OOC_4 }; + +static const int aRandomYells[] = { YELL_STOLEN_1, YELL_STOLEN_2, YELL_STOLEN_3 }; + +struct boss_plugger_spazzringAI : public ScriptedAI +{ + boss_plugger_spazzringAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (instance_blackrock_depths*)pCreature->GetInstanceData(); + Reset(); + } + + instance_blackrock_depths* m_pInstance; + + uint32 m_uiOocSayTimer; + uint32 m_uiDemonArmorTimer; + uint32 m_uiBanishTimer; + uint32 m_uiImmolateTimer; + uint32 m_uiShadowBoltTimer; + uint32 m_uiCurseOfTonguesTimer; + uint32 m_uiPickpocketTimer; + + void Reset() override + { + m_uiOocSayTimer = 10000; + m_uiDemonArmorTimer = 1000; + m_uiBanishTimer = 0; + m_uiImmolateTimer = 0; + m_uiShadowBoltTimer = 0; + m_uiCurseOfTonguesTimer = 0; + m_uiPickpocketTimer = 0; + } + + void Aggro(Unit* /*pWho*/) override + { + m_uiBanishTimer = urand(8, 12) * 1000; + m_uiImmolateTimer = urand(18, 20) * 1000; + m_uiShadowBoltTimer = 1000; + m_uiCurseOfTonguesTimer = 17000; + } + + void JustDied(Unit* pKiller) override + { + if (!m_pInstance) + return; + + // Activate Phalanx and handle patrons faction + if (Creature* pPhalanx = m_pInstance->GetSingleCreatureFromStorage(NPC_PHALANX)) + { + if (!m_pInstance) + return; + + // Activate Phalanx and handle patrons faction + if (Creature* pPhalanx = m_pInstance->GetSingleCreatureFromStorage(NPC_PHALANX)) + { + if (npc_phalanxAI* pEscortAI = dynamic_cast(pPhalanx->AI())) + pEscortAI->Start(false, NULL, NULL, true); + } + m_pInstance->HandleBarPatrons(PATRON_HOSTILE); + m_pInstance->SetData(TYPE_PLUGGER, IN_PROGRESS); // The event is set IN_PROGRESS even if Plugger is dead because his death triggers more actions that are part of the event + } + } + + // Players stole one of the ale mug/roasted boar: warn them + void WarnThief(Player* pPlayer) + { + DoScriptText(aRandomYells[urand(0, 2)], m_creature); + m_creature->SetFacingToObject(pPlayer); + } + + // Players stole too much of the ale mug/roasted boar: attack them + void AttackThief(Player* pPlayer) + { + if (pPlayer) + { + DoScriptText(urand(0, 1) < 1 ? YELL_AGRRO_1 : YELL_AGRRO_2, m_creature); + m_creature->SetFacingToObject(pPlayer); + m_creature->SetFactionTemporary(FACTION_DARK_IRON, TEMPFACTION_RESTORE_RESPAWN); + AttackStart(pPlayer); + } + } + + void UpdateAI(const uint32 uiDiff) override + { + // Combat check + if (m_creature->SelectHostileTarget() && m_creature->getVictim()) + { + if (m_uiBanishTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) + { + if (DoCastSpellIfCan(pTarget, SPELL_BANISH) == CAST_OK) + m_uiBanishTimer = urand(26, 28) * 1000; + } + } + else + m_uiBanishTimer -= uiDiff; + + if (m_uiImmolateTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_IMMOLATE) == CAST_OK) + m_uiImmolateTimer = 25000; + } + else + m_uiImmolateTimer -= uiDiff; + + if (m_uiShadowBoltTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_SHADOW_BOLT) == CAST_OK) + m_uiShadowBoltTimer = urand(36, 63) * 100; + } + else + m_uiShadowBoltTimer -= uiDiff; + + if (m_uiCurseOfTonguesTimer < uiDiff) + { + if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_CURSE_OF_TONGUES, SELECT_FLAG_POWER_MANA)) + { + if (DoCastSpellIfCan(pTarget, SPELL_CURSE_OF_TONGUES) == CAST_OK) + m_uiCurseOfTonguesTimer = urand(19, 31) * 1000; + } + } + else + m_uiCurseOfTonguesTimer -= uiDiff; + + DoMeleeAttackIfReady(); + } + // Out of Combat (OOC) + else + { + if (m_uiOocSayTimer < uiDiff) + { + DoScriptText(aRandomSays[urand(0, 3)], m_creature); + m_uiOocSayTimer = urand(10, 20) * 1000; + } + else + m_uiOocSayTimer -= uiDiff; + + if (m_uiPickpocketTimer) + { + if (m_uiPickpocketTimer < uiDiff) + { + DoScriptText(YELL_PICKPOCKETED, m_creature); + m_creature->SetFactionTemporary(FACTION_DARK_IRON, TEMPFACTION_RESTORE_RESPAWN); + m_uiPickpocketTimer = 0; + } + else + m_uiPickpocketTimer -= uiDiff; + } + + if (m_uiDemonArmorTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_DEMON_ARMOR) == CAST_OK) + m_uiDemonArmorTimer = 30 * MINUTE * IN_MILLISECONDS; + } + else + m_uiDemonArmorTimer -= uiDiff; + } + } +}; + +struct boss_plugger_spazzring : public CreatureScript +{ + boss_plugger_spazzring() : CreatureScript("boss_plugger_spazzring") {} + + + CreatureAI* GetAI(Creature* pCreature) override + { + return new boss_plugger_spazzringAI(pCreature); + } +}; + + /*###### ## npc_kharan_mighthammer ######*/ @@ -1224,11 +1942,83 @@ struct npc_kharan_mighthammer : public CreatureScript } }; + +/*###### +## npc_ironhand_guardian +######*/ + +enum +{ + SPELL_GOUT_OF_FLAME = 15529, + SPELL_STONED_VISUAL = 15533, +}; + +struct npc_ironhand_guardian : public CreatureScript +{ + npc_ironhand_guardian() : CreatureScript("npc_ironhand_guardian") {} + + struct npc_ironhand_guardianAI : public ScriptedAI + { + npc_ironhand_guardianAI(Creature* pCreature) : ScriptedAI(pCreature) + { + m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); + } + + ScriptedInstance* m_pInstance; + + uint32 m_uiGoutOfFlameTimer; + uint8 m_uiPhase; + + void Reset() override + { + m_uiGoutOfFlameTimer = urand(4, 8) * 1000; + } + + void UpdateAI(const uint32 uiDiff) override + { + if (!m_pInstance) + return; + + if (m_pInstance->GetData(TYPE_IRON_HALL) == NOT_STARTED) + { + m_uiPhase = 0; + return; + } + + switch (m_uiPhase) + { + case 0: + m_creature->RemoveAurasDueToSpell(SPELL_STONED); + if (DoCastSpellIfCan(m_creature, SPELL_STONED_VISUAL) == CAST_OK) + m_uiPhase = 1; + break; + case 1: + if (m_uiGoutOfFlameTimer < uiDiff) + { + if (DoCastSpellIfCan(m_creature, SPELL_GOUT_OF_FLAME) == CAST_OK) + m_uiGoutOfFlameTimer = urand(13, 18) * 1000; + } + else + m_uiGoutOfFlameTimer -= uiDiff; + break; + } + } + }; + + CreatureAI* GetAI(Creature* pCreature) override + { + return new npc_ironhand_guardianAI(pCreature); + } +}; + void AddSC_blackrock_depths() { Script *s; s = new go_shadowforge_brazier(); s->RegisterSelf(); + s = new go_shadowforge_brazier(); + s->RegisterSelf(); s = new go_relic_coffer_door(); s->RegisterSelf(); @@ -1242,16 +2032,24 @@ void AddSC_blackrock_depths() s->RegisterSelf(); s = new npc_rocknot(); s->RegisterSelf(); + s = new npc_phalanx(); + s->RegisterSelf(); + s = new npc_mistress_nagmara(); + s->RegisterSelf(); s = new npc_marshal_windsor(); s->RegisterSelf(); s = new npc_tobias_seecher(); s->RegisterSelf(); s = new npc_dughal_stormwing(); s->RegisterSelf(); + s = new npc_hurley_blackbreath(); + s->RegisterSelf(); s = new boss_doomrel(); s->RegisterSelf(); s = new npc_kharan_mighthammer(); s->RegisterSelf(); + s = new npc_ironhand_guardian(); + s->RegisterSelf(); //pNewScript = new Script; //pNewScript->Name = "go_shadowforge_brazier"; diff --git a/src/modules/SD3/scripts/eastern_kingdoms/blackrock_mountain/blackrock_depths/blackrock_depths.h b/src/modules/SD3/scripts/eastern_kingdoms/blackrock_mountain/blackrock_depths/blackrock_depths.h index 16f0ce7e6..564ab0f80 100644 --- a/src/modules/SD3/scripts/eastern_kingdoms/blackrock_mountain/blackrock_depths/blackrock_depths.h +++ b/src/modules/SD3/scripts/eastern_kingdoms/blackrock_mountain/blackrock_depths/blackrock_depths.h @@ -27,24 +27,37 @@ #ifndef DEF_BRD_H #define DEF_BRD_H +#include "precompiled.h" + enum { - MAX_ENCOUNTER = 7, + MAX_ENCOUNTER = 13, TYPE_SIGNAL = MAX_ENCOUNTER + 1, MAX_RELIC_DOORS = 12, MAX_DWARFS = 7, + MAX_DWARF_RUNES = 7, + MAX_CRONIES = 3, TYPE_RING_OF_LAW = 1, TYPE_VAULT = 2, - TYPE_BAR = 3, + TYPE_ROCKNOT = 3, TYPE_TOMB_OF_SEVEN = 4, TYPE_LYCEUM = 5, TYPE_IRON_HALL = 6, TYPE_QUEST_JAIL_BREAK = 7, + TYPE_FLAMELASH = 8, + TYPE_HURLEY = 9, + TYPE_BRIDGE = 10, + TYPE_BAR = 11, + TYPE_PLUGGER = 12, + TYPE_NAGMARA = 13, + TYPE_BAR_DOOR = 15, + TYPE_ARENA_COORDS = 16, + TYPE_ARENA_CROWD = 17, NPC_EMPEROR = 9019, NPC_PRINCESS = 8929, - NPC_PHALANX = 9502, + NPC_PRIESTESS = 10076, NPC_HATEREL = 9034, NPC_ANGERREL = 9035, NPC_VILEREL = 9036, @@ -55,6 +68,8 @@ enum NPC_MAGMUS = 9938, NPC_WATCHER_DOOMGRIP = 9476, NPC_WARBRINGER_CONST = 8905, // Four of them in Relict Vault are related to Doomgrip summon event + NPC_LOREGRAIN = 9024, + NPC_FIREGUARD_DESTROYER = 8911, // Four of them in Relict Vault are related to Doomgrip summon event // Jail Break event related NPC_OGRABISI = 9677, @@ -64,6 +79,30 @@ enum NPC_TOBIAS = 9679, NPC_DUGHAL = 9022, + // Arena crowd + NPC_ARENA_SPECTATOR = 8916, + NPC_SHADOWFORGE_PEASANT = 8896, + NPC_SHADOWFORGE_CITIZEN = 8902, + NPC_SHADOWFORGE_SENATOR = 8904, + NPC_ANVILRAGE_SOLDIER = 8893, + NPC_ANVILRAGE_MEDIC = 8894, + NPC_ANVILRAGE_OFFICER = 8895, + + // Spawned on Shadowforge bridge + NPC_ANVILRAGE_GUARDMAN = 8891, + + // Grim Guzzler bar events + NPC_PHALANX = 9502, + NPC_GRIM_PATRON = 9545, + NPC_GUZZLING_PATRON = 9547, + NPC_HAMMERED_PATRON = 9554, + NPC_HURLEY_BLACKBREATH = 9537, + NPC_BLACKBREATH_CRONY = 9541, + NPC_PLUGGER_SPAZZRING = 9499, + NPC_PRIVATE_ROCKNOT = 9503, + NPC_MISTRESS_NAGMARA = 9500, + NPC_RIBBLY_SCREWSPIGGOT = 9543, + GO_ARENA_1 = 161525, GO_ARENA_2 = 161522, GO_ARENA_3 = 161524, @@ -87,16 +126,64 @@ enum GO_CHEST_SEVEN = 169243, GO_ARENA_SPOILS = 181074, GO_SECRET_DOOR = 174553, + GO_SECRET_SAFE = 161495, // Jail break event related GO_JAIL_DOOR_SUPPLY = 170561, GO_JAIL_SUPPLY_CRATE = 166872, + GO_DWARFRUNE_A01 = 170578, + GO_DWARFRUNE_B01 = 170579, + GO_DWARFRUNE_C01 = 170580, + GO_DWARFRUNE_D01 = 170581, + GO_DWARFRUNE_E01 = 170582, + GO_DWARFRUNE_F01 = 170583, + GO_DWARFRUNE_G01 = 170584, + SPELL_STONED = 10255, // Aura of Warbringer Constructs in Relict Vault FACTION_DWARF_HOSTILE = 754, // Hostile faction for the Tomb of the Seven dwarfs + FACTION_ARENA_NEUTRAL = 15, // Neutral faction for NPC in top of Arena after event complete + FACTION_DARK_IRON = 54, // Hostile faction for the Grim Guzzler + FACTION_IRONFORGE = 122, + + // enum used to handle the various Grim Guzzler bar patron's reaction + // depending on the actions and events triggered by players + PATRON_EMOTE = 0, + PATRON_PISSED = 1, + PATRON_HOSTILE = 2, + SAY_PISSED_PATRON_1 = -1230037, + SAY_PISSED_PATRON_2 = -1230038, + SAY_PISSED_PATRON_3 = -1230039, + SAY_ROCKNOT_DESPAWN = -1230047, + YELL_PATROL_1 = -1230048, + YELL_PATROL_2 = -1230049, + SPELL_NAGMARA_VANISH = 15341, + + // Emperor Dagran Thaurissan + YELL_SENATOR_1 = -1230060, + YELL_SENATOR_2 = -1230061, + YELL_SENATOR_3 = -1230062, + YELL_SENATOR_4 = -1230063 }; +// Random emotes for Grim Guzzler patrons +static const uint32 aPatronsEmotes[] = +{ + EMOTE_ONESHOT_EXCLAMATION, EMOTE_ONESHOT_CHEER, EMOTE_ONESHOT_CHEER, EMOTE_ONESHOT_LAUGH, EMOTE_ONESHOT_LAUGH, EMOTE_ONESHOT_LAUGH +}; + +struct ArenaCylinder +{ + float m_fCenterX; + float m_fCenterY; + float m_fCenterZ; + uint32 m_uiRadius; + uint32 m_uiHeight; +}; + +static const ArenaCylinder aArenaCrowdVolume[] = {595.78f, -188.65f, -38.63f, 69, 10}; + enum ArenaNPCs { // Gladiators @@ -138,7 +225,84 @@ static const uint32 aArenaNPCs[] = // Used to summon Watcher Doomgrip static const float aVaultPositions[4] = {821.905f, -338.382f, -50.134f, 3.78736f}; +// Used to summon Hurley Blackbreath +static const float aHurleyPositions[4] = {856.0867f, -149.7469f, -49.6719f, 0.05949629f}; + +// Used to summon the patrol in Grim Guzzler +static const float aBarPatrolPositions[2][4] = { + {872.7059f, -232.5491f, -43.7525f, 2.069044f}, + {865.5645f, -219.7471f, -43.7033f, 2.033881f} +}; + +static const uint32 aBarPatrolId[3] = {NPC_FIREGUARD_DESTROYER, NPC_ANVILRAGE_OFFICER, NPC_ANVILRAGE_OFFICER}; + // Tomb of the Seven dwarfs static const uint32 aTombDwarfes[MAX_DWARFS] = {NPC_ANGERREL, NPC_SEETHREL, NPC_DOPEREL, NPC_GLOOMREL, NPC_VILEREL, NPC_HATEREL, NPC_DOOMREL}; + + +class instance_blackrock_depths : public ScriptedInstance +{ + public: + instance_blackrock_depths(Map* pMap); + ~instance_blackrock_depths() {} + + void Initialize() override; + + void OnCreatureCreate(Creature* pCreature) override; + void OnCreatureEnterCombat(Creature* pCreature) override; + void OnCreatureDeath(Creature* pCreature) override; + void OnCreatureEvade(Creature* pCreature); + void OnObjectCreate(GameObject* pGo) override; + + void SetData(uint32 uiType, uint32 uiData) override; + uint32 GetData(uint32 uiType) const override; + + const char* Save() const override { return m_strInstData.c_str(); } + void Load(const char* chrIn) override; + + void Update(uint32 uiDiff) override; + + // Arena Event + void SetArenaCenterCoords(float fX, float fY, float fZ) { m_fArenaCenterX = fX; m_fArenaCenterY = fY; m_fArenaCenterZ = fZ; } + void GetArenaCenterCoords(float& fX, float& fY, float& fZ) { fX = m_fArenaCenterX; fY = m_fArenaCenterY; fZ = m_fArenaCenterZ; } + void GetArenaCrowdGuid(GuidSet& sCrowdSet) { sCrowdSet = m_sArenaCrowdNpcGuids; } + + // Bar events + void SetBarDoorIsOpen() { m_bIsBarDoorOpen = true; } + void GetBarDoorIsOpen(bool& bIsOpen) { bIsOpen = m_bIsBarDoorOpen; } + void HandleBarPatrons(uint8 uiEventType); + void HandleBarPatrol(uint8 uiStep); + + private: + void DoCallNextDwarf(); + + uint32 m_auiEncounter[MAX_ENCOUNTER]; + std::string m_strInstData; + + // Grim Guzzler bar events + bool m_bIsBarDoorOpen; + uint32 m_uiBarAleCount; + uint32 m_uiPatronEmoteTimer; + uint8 m_uiBrokenKegs; + uint32 m_uiPatrolTimer; + uint8 m_uiStolenAles; + uint32 m_uiDagranTimer; + + uint8 m_uiCofferDoorsOpened; + + uint32 m_uiDwarfFightTimer; + uint32 m_uiArenaCenterAT; + uint8 m_uiDwarfRound; + + float m_fArenaCenterX, m_fArenaCenterY, m_fArenaCenterZ; + + GuidSet m_sVaultNpcGuids; + GuidSet m_sArenaCrowdNpcGuids; + GuidSet m_sBarPatronNpcGuids; + GuidSet m_sBarPatrolGuids; + +}; + + #endif diff --git a/src/modules/SD3/scripts/eastern_kingdoms/blackrock_mountain/blackrock_depths/boss_emperor_dagran_thaurissan.cpp b/src/modules/SD3/scripts/eastern_kingdoms/blackrock_mountain/blackrock_depths/boss_emperor_dagran_thaurissan.cpp index 50825ecce..55d7c3df5 100644 --- a/src/modules/SD3/scripts/eastern_kingdoms/blackrock_mountain/blackrock_depths/boss_emperor_dagran_thaurissan.cpp +++ b/src/modules/SD3/scripts/eastern_kingdoms/blackrock_mountain/blackrock_depths/boss_emperor_dagran_thaurissan.cpp @@ -39,8 +39,10 @@ enum eEmperor { FACTION_NEUTRAL = 734, - SAY_AGGRO = -1230001, - SAY_SLAY = -1230002, + YELL_AGGRO_1 = -1230001, + YELL_AGGRO_2 = -1230064, + YELL_AGGRO_3 = -1230065, + YELL_SLAY = -1230002, SPELL_HANDOFTHAURISSAN = 17492, SPELL_AVATAROFFLAME = 15636 @@ -55,6 +57,7 @@ struct boss_emperor_dagran_thaurissan : public CreatureScript boss_emperor_dagran_thaurissanAI(Creature* pCreature) : ScriptedAI(pCreature) { m_pInstance = (ScriptedInstance*)pCreature->GetInstanceData(); + Reset(); } ScriptedInstance* m_pInstance; @@ -72,19 +75,28 @@ struct boss_emperor_dagran_thaurissan : public CreatureScript void Aggro(Unit* /*pWho*/) override { - DoScriptText(SAY_AGGRO, m_creature); + uint32 uiTextId; + switch (urand(0, 2)) + { + case 0: uiTextId = YELL_AGGRO_1; break; + case 1: uiTextId = YELL_AGGRO_2; break; + case 2: uiTextId = YELL_AGGRO_3; break; + } + DoScriptText(uiTextId, m_creature); m_creature->CallForHelp(VISIBLE_RANGE); } void JustDied(Unit* /*pVictim*/) override { if (!m_pInstance) - { return; - } if (Creature* pPrincess = m_pInstance->GetSingleCreatureFromStorage(NPC_PRINCESS)) { + // check if we didn't update the entry + if (pPrincess->GetEntry() != NPC_PRINCESS) + return; + if (pPrincess->IsAlive()) { pPrincess->SetFactionTemporary(FACTION_NEUTRAL, TEMPFACTION_NONE); @@ -95,50 +107,33 @@ struct boss_emperor_dagran_thaurissan : public CreatureScript void KilledUnit(Unit* /*pVictim*/) override { - DoScriptText(SAY_SLAY, m_creature); + DoScriptText(YELL_SLAY, m_creature); } void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) - { return; - } if (m_uiHandOfThaurissan_Timer < uiDiff) { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - DoCastSpellIfCan(pTarget, SPELL_HANDOFTHAURISSAN); + if (DoCastSpellIfCan(pTarget, SPELL_HANDOFTHAURISSAN) == CAST_OK) + m_uiHandOfThaurissan_Timer = urand(5, 10) * 1000; } - - // 3 Hands of Thaurissan will be casted - // if (m_uiCounter < 3) - //{ - // m_uiHandOfThaurissan_Timer = 1000; - // ++m_uiCounter; - //} - // else - //{ - m_uiHandOfThaurissan_Timer = 5000; - // m_uiCounter = 0; - //} } else - { m_uiHandOfThaurissan_Timer -= uiDiff; - } // AvatarOfFlame_Timer if (m_uiAvatarOfFlame_Timer < uiDiff) { - DoCastSpellIfCan(m_creature->getVictim(), SPELL_AVATAROFFLAME); - m_uiAvatarOfFlame_Timer = 18000; + if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_AVATAROFFLAME) == CAST_OK) + m_uiAvatarOfFlame_Timer = 18000; } else - { m_uiAvatarOfFlame_Timer -= uiDiff; - } DoMeleeAttackIfReady(); } diff --git a/src/modules/SD3/scripts/eastern_kingdoms/blackrock_mountain/blackrock_depths/boss_high_interrogator_gerstahn.cpp b/src/modules/SD3/scripts/eastern_kingdoms/blackrock_mountain/blackrock_depths/boss_high_interrogator_gerstahn.cpp index 5dcfcd723..04689fa13 100644 --- a/src/modules/SD3/scripts/eastern_kingdoms/blackrock_mountain/blackrock_depths/boss_high_interrogator_gerstahn.cpp +++ b/src/modules/SD3/scripts/eastern_kingdoms/blackrock_mountain/blackrock_depths/boss_high_interrogator_gerstahn.cpp @@ -77,10 +77,9 @@ struct boss_high_interrogator_gerstahn : public CreatureScript { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { - DoCastSpellIfCan(pTarget, SPELL_SHADOWWORDPAIN); + if (DoCastSpellIfCan(pTarget, SPELL_SHADOWWORDPAIN) == CAST_OK) + m_uiShadowWordPainTimer = 7000; } - - m_uiShadowWordPainTimer = 7000; } else { @@ -92,10 +91,9 @@ struct boss_high_interrogator_gerstahn : public CreatureScript { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, SPELL_MANABURN, SELECT_FLAG_POWER_MANA)) { - DoCastSpellIfCan(pTarget, SPELL_MANABURN); + if (DoCastSpellIfCan(pTarget, SPELL_MANABURN) == CAST_OK) + m_uiManaBurnTimer = 10000; } - - m_uiManaBurnTimer = 10000; } else { diff --git a/src/modules/SD3/scripts/eastern_kingdoms/blackrock_mountain/blackrock_depths/instance_blackrock_depths.cpp b/src/modules/SD3/scripts/eastern_kingdoms/blackrock_mountain/blackrock_depths/instance_blackrock_depths.cpp index a309e06ba..8d5f23ff3 100644 --- a/src/modules/SD3/scripts/eastern_kingdoms/blackrock_mountain/blackrock_depths/instance_blackrock_depths.cpp +++ b/src/modules/SD3/scripts/eastern_kingdoms/blackrock_mountain/blackrock_depths/instance_blackrock_depths.cpp @@ -36,462 +36,794 @@ #include "precompiled.h" #include "blackrock_depths.h" -struct is_blackrock_depths : public InstanceScript + +struct is_blackrock_spire : public InstanceScript { - is_blackrock_depths() : InstanceScript("instance_blackrock_depths") {} + is_blackrock_spire() : InstanceScript("instance_blackrock_spire") {} - class instance_blackrock_depths : public ScriptedInstance +}; + +instance_blackrock_depths::instance_blackrock_depths(Map* pMap) : ScriptedInstance(pMap), + m_uiBarAleCount(0), + m_uiBrokenKegs(0), + m_uiCofferDoorsOpened(0), + m_uiDwarfRound(0), + m_uiDwarfFightTimer(0), + m_uiPatronEmoteTimer(2000), + m_uiPatrolTimer(0), + m_uiStolenAles(0), + m_uiDagranTimer(0), + + m_fArenaCenterX(0.0f), + m_fArenaCenterY(0.0f), + m_fArenaCenterZ(0.0f), + m_bIsBarDoorOpen(false) +{ + Initialize(); +} + +void instance_blackrock_depths::Initialize() +{ + memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + +}; + +void instance_blackrock_depths::OnCreatureCreate(Creature* pCreature) +{ + switch (pCreature->GetEntry()) { - public: - instance_blackrock_depths(Map* pMap) : ScriptedInstance(pMap), - m_uiBarAleCount(0), - m_uiCofferDoorsOpened(0), - m_uiDwarfFightTimer(0), - m_uiArenaCenterAT(0), - m_uiDwarfRound(0) + case NPC_EMPEROR: + case NPC_PRINCESS: + case NPC_PHALANX: + case NPC_PLUGGER_SPAZZRING: + case NPC_HATEREL: + case NPC_ANGERREL: + case NPC_VILEREL: + case NPC_GLOOMREL: + case NPC_SEETHREL: + case NPC_DOOMREL: + case NPC_DOPEREL: + case NPC_SHILL: + case NPC_CREST: + case NPC_JAZ: + case NPC_TOBIAS: + case NPC_DUGHAL: + case NPC_LOREGRAIN: + case NPC_RIBBLY_SCREWSPIGGOT: + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); + break; + + case NPC_WARBRINGER_CONST: + // Golems not in the Relict Vault? + if (std::abs(pCreature->GetPositionZ() - aVaultPositions[2]) > 1.0f || !pCreature->IsWithinDist2d(aVaultPositions[0], aVaultPositions[1], 20.0f)) { - Initialize(); + break; } + // Golems in Relict Vault need to have a stoned aura, set manually to prevent reapply when reached home + pCreature->CastSpell(pCreature, SPELL_STONED, true); + // Store the Relict Vault Golems into m_sVaultNpcGuids + case NPC_WATCHER_DOOMGRIP: + m_sVaultNpcGuids.insert(pCreature->GetObjectGuid()); + break; + // Arena crowd + case NPC_ARENA_SPECTATOR: + case NPC_SHADOWFORGE_PEASANT: + case NPC_SHADOWFORGE_CITIZEN: + case NPC_SHADOWFORGE_SENATOR: + case NPC_ANVILRAGE_SOLDIER: + case NPC_ANVILRAGE_MEDIC: + case NPC_ANVILRAGE_OFFICER: + if (pCreature->GetPositionZ() < aArenaCrowdVolume->m_fCenterZ || pCreature->GetPositionZ() > aArenaCrowdVolume->m_fCenterZ + aArenaCrowdVolume->m_uiHeight || + !pCreature->IsWithinDist2d(aArenaCrowdVolume->m_fCenterX, aArenaCrowdVolume->m_fCenterY, aArenaCrowdVolume->m_uiRadius)) + break; + m_sArenaCrowdNpcGuids.insert(pCreature->GetObjectGuid()); + if (m_auiEncounter[0] == DONE) + pCreature->SetFactionTemporary(FACTION_ARENA_NEUTRAL, TEMPFACTION_RESTORE_RESPAWN); + break; + // Grim Guzzler bar crowd + case NPC_GRIM_PATRON: + case NPC_GUZZLING_PATRON: + case NPC_HAMMERED_PATRON: + m_sBarPatronNpcGuids.insert(pCreature->GetObjectGuid()); + if (m_auiEncounter[11] == DONE) + pCreature->SetFactionTemporary(FACTION_DARK_IRON, TEMPFACTION_RESTORE_RESPAWN); + pCreature->SetStandState(UNIT_STAND_STATE_STAND); + break; + case NPC_PRIVATE_ROCKNOT: + case NPC_MISTRESS_NAGMARA: + if (m_auiEncounter[11] == DONE) + pCreature->ForcedDespawn(); + else + m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); + break; + } +} - ~instance_blackrock_depths() {} +void instance_blackrock_depths::OnCreatureEnterCombat(Creature* pCreature) +{ + if (pCreature->GetEntry() == NPC_MAGMUS) + { + SetData(TYPE_IRON_HALL, IN_PROGRESS); + } +} - void Initialize() override - { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - } - - void OnCreatureCreate(Creature* pCreature) override - { - switch (pCreature->GetEntry()) +void instance_blackrock_depths::OnCreatureDeath(Creature* pCreature) +{ + switch (pCreature->GetEntry()) + { + case NPC_WARBRINGER_CONST: + case NPC_WATCHER_DOOMGRIP: + if (GetData(TYPE_VAULT) == IN_PROGRESS) { - case NPC_EMPEROR: - case NPC_PRINCESS: - case NPC_PHALANX: - case NPC_HATEREL: - case NPC_ANGERREL: - case NPC_VILEREL: - case NPC_GLOOMREL: - case NPC_SEETHREL: - case NPC_DOOMREL: - case NPC_DOPEREL: - case NPC_SHILL: - case NPC_CREST: - case NPC_JAZ: - case NPC_TOBIAS: - case NPC_DUGHAL: - m_mNpcEntryGuidStore[pCreature->GetEntry()] = pCreature->GetObjectGuid(); - break; + m_sVaultNpcGuids.erase(pCreature->GetObjectGuid()); - case NPC_WARBRINGER_CONST: - // Golems not in the Relict Vault? - if (std::abs(pCreature->GetPositionZ() - aVaultPositions[2]) > 1.0f || !pCreature->IsWithinDist2d(aVaultPositions[0], aVaultPositions[1], 20.0f)) + // If all event npcs dead then set event to done + if (m_sVaultNpcGuids.empty()) + SetData(TYPE_VAULT, DONE); + } + break; + case NPC_OGRABISI: + case NPC_SHILL: + case NPC_CREST: + case NPC_JAZ: + if (GetData(TYPE_QUEST_JAIL_BREAK) == IN_PROGRESS) + SetData(TYPE_QUEST_JAIL_BREAK, SPECIAL); + break; + // Handle Tomb of the Seven dwarf death event + case NPC_HATEREL: + case NPC_ANGERREL: + case NPC_VILEREL: + case NPC_GLOOMREL: + case NPC_SEETHREL: + case NPC_DOPEREL: + // Only handle the event when event is in progress + if (GetData(TYPE_TOMB_OF_SEVEN) != IN_PROGRESS) + return; + // Call the next dwarf only if it's the last one which joined the fight + if (pCreature->GetEntry() == aTombDwarfes[m_uiDwarfRound - 1]) + DoCallNextDwarf(); + break; + case NPC_DOOMREL: + SetData(TYPE_TOMB_OF_SEVEN, DONE); + break; + case NPC_MAGMUS: + SetData(TYPE_IRON_HALL, DONE); + break; + case NPC_HURLEY_BLACKBREATH: + SetData(TYPE_HURLEY, DONE); + break; + case NPC_RIBBLY_SCREWSPIGGOT: + // Do nothing if the patrol was already spawned or is about to: + // Plugger has made the bar hostile + if (GetData(TYPE_BAR) == IN_PROGRESS || GetData(TYPE_PLUGGER) == IN_PROGRESS || GetData(TYPE_BAR) == DONE || GetData(TYPE_PLUGGER) == DONE) + return; + else + SetData(TYPE_BAR, IN_PROGRESS); + break; + case NPC_SHADOWFORGE_SENATOR: + // Emperor Dagran Thaurissan performs a random yell upon the death + // of Shadowforge Senators in the Throne Room + if (Creature* pDagran = GetSingleCreatureFromStorage(NPC_EMPEROR)) + { + uint32 uiTextId; + + if (!pDagran->IsAlive()) + return; + + if (m_uiDagranTimer > 0) + return; + + switch (urand(0, 3)) { - break; + case 0: uiTextId = YELL_SENATOR_1; break; + case 1: uiTextId = YELL_SENATOR_2; break; + case 2: uiTextId = YELL_SENATOR_3; break; + case 3: uiTextId = YELL_SENATOR_4; break; } - // Golems in Relict Vault need to have a stoned aura, set manually to prevent reapply when reached home - pCreature->CastSpell(pCreature, SPELL_STONED, true); - // Store the Relict Vault Golems into m_sVaultNpcGuids - case NPC_WATCHER_DOOMGRIP: - m_sVaultNpcGuids.insert(pCreature->GetObjectGuid()); - break; + DoScriptText(uiTextId, pDagran); + m_uiDagranTimer = 30000; // set a timer of 30 sec to avoid Emperor Thaurissan to spam yells in case many senators are killed in a short amount of time + } + break; + + } +} + +void instance_blackrock_depths::OnCreatureEvade(Creature* pCreature) +{ + if (GetData(TYPE_RING_OF_LAW) == IN_PROGRESS || GetData(TYPE_RING_OF_LAW) == SPECIAL) + { + for (uint8 i = 0; i < countof(aArenaNPCs); ++i) + { + if (pCreature->GetEntry() == aArenaNPCs[i]) + { + SetData(TYPE_RING_OF_LAW, FAIL); + return; } } + } - void OnCreatureEnterCombat(Creature* pCreature) override + switch (pCreature->GetEntry()) + { + // Handle Tomb of the Seven reset in case of wipe + case NPC_HATEREL: + case NPC_ANGERREL: + case NPC_VILEREL: + case NPC_GLOOMREL: + case NPC_SEETHREL: + case NPC_DOPEREL: + case NPC_DOOMREL: + SetData(TYPE_TOMB_OF_SEVEN, FAIL); + break; + case NPC_MAGMUS: + SetData(TYPE_IRON_HALL, FAIL); + break; + } +} + +void instance_blackrock_depths::OnObjectCreate(GameObject* pGo) +{ + switch (pGo->GetEntry()) + { + case GO_ARENA_1: + case GO_ARENA_2: + case GO_ARENA_3: + case GO_ARENA_4: + case GO_SHADOW_LOCK: + case GO_SHADOW_MECHANISM: + case GO_SHADOW_GIANT_DOOR: + case GO_SHADOW_DUMMY: + case GO_BAR_KEG_SHOT: + case GO_BAR_KEG_TRAP: + case GO_TOMB_ENTER: + case GO_TOMB_EXIT: + case GO_LYCEUM: + case GO_GOLEM_ROOM_N: + case GO_GOLEM_ROOM_S: + case GO_THRONE_ROOM: + case GO_SPECTRAL_CHALICE: + case GO_CHEST_SEVEN: + case GO_ARENA_SPOILS: + case GO_SECRET_DOOR: + case GO_JAIL_DOOR_SUPPLY: + case GO_JAIL_SUPPLY_CRATE: + case GO_DWARFRUNE_A01: + case GO_DWARFRUNE_B01: + case GO_DWARFRUNE_C01: + case GO_DWARFRUNE_D01: + case GO_DWARFRUNE_E01: + case GO_DWARFRUNE_F01: + case GO_DWARFRUNE_G01: + break; + case GO_BAR_DOOR: + if (GetData(TYPE_ROCKNOT) == DONE) { - if (pCreature->GetEntry() == NPC_MAGMUS) - { - SetData(TYPE_IRON_HALL, IN_PROGRESS); - } + // Rocknot event done: set the Grim Guzzler door animation to "broken" + // tell the instance script it is open to prevent some of the other events + pGo->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); + SetBarDoorIsOpen(); } - - void OnCreatureDeath(Creature* pCreature) override + else if (m_auiEncounter[10] == DONE || m_auiEncounter[11] == DONE) { - switch (pCreature->GetEntry()) + // bar or Plugger event done: open the Grim Guzzler door + // tell the instance script it is open to prevent some of the other events + DoUseDoorOrButton(GO_BAR_DOOR); + SetBarDoorIsOpen(); + } + break; + + default: + return; + } + m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); +} + +void instance_blackrock_depths::SetData(uint32 uiType, uint32 uiData) +{ + switch (uiType) + { + case TYPE_RING_OF_LAW: + // If finished the arena event after theldren fight + if (uiData == DONE && m_auiEncounter[0] == SPECIAL) + { + DoRespawnGameObject(GO_ARENA_SPOILS, HOUR); + } + m_auiEncounter[0] = uiData; + break; + case TYPE_VAULT: + if (uiData == SPECIAL) + { + ++m_uiCofferDoorsOpened; + + if (m_uiCofferDoorsOpened == MAX_RELIC_DOORS) { - case NPC_WARBRINGER_CONST: - case NPC_WATCHER_DOOMGRIP: - if (GetData(TYPE_VAULT) == IN_PROGRESS) + SetData(TYPE_VAULT, IN_PROGRESS); + + Creature* pConstruct = NULL; + + // Activate vault constructs + for (GuidSet::const_iterator itr = m_sVaultNpcGuids.begin(); itr != m_sVaultNpcGuids.end(); ++itr) { - m_sVaultNpcGuids.erase(pCreature->GetObjectGuid()); - - // If all event npcs dead then set event to done - if (m_sVaultNpcGuids.empty()) + pConstruct = instance->GetCreature(*itr); + if (pConstruct) { - SetData(TYPE_VAULT, DONE); + pConstruct->RemoveAurasDueToSpell(SPELL_STONED); } } - break; - case NPC_OGRABISI: - case NPC_SHILL: - case NPC_CREST: - case NPC_JAZ: - if (GetData(TYPE_QUEST_JAIL_BREAK) == IN_PROGRESS) - { - SetData(TYPE_QUEST_JAIL_BREAK, SPECIAL); - } - break; - // Handle Tomb of the Seven dwarf death event - case NPC_HATEREL: - case NPC_ANGERREL: - case NPC_VILEREL: - case NPC_GLOOMREL: - case NPC_SEETHREL: - case NPC_DOPEREL: - // Only handle the event when event is in progress - if (GetData(TYPE_TOMB_OF_SEVEN) != IN_PROGRESS) + + if (!pConstruct) { return; } - // Call the next dwarf only if it's the last one which joined the fight - if (pCreature->GetEntry() == aTombDwarfes[m_uiDwarfRound - 1]) - { - DoCallNextDwarf(); - } - break; - case NPC_DOOMREL: - SetData(TYPE_TOMB_OF_SEVEN, DONE); - break; - case NPC_MAGMUS: - SetData(TYPE_IRON_HALL, DONE); - break; + + // Summon doomgrip + pConstruct->SummonCreature(NPC_WATCHER_DOOMGRIP, aVaultPositions[0], aVaultPositions[1], aVaultPositions[2], aVaultPositions[3], TEMPSUMMON_DEAD_DESPAWN, 0); } + // No need to store in this case + return; } - - void OnCreatureEvade(Creature* pCreature) override + if (uiData == DONE) { - if (GetData(TYPE_RING_OF_LAW) == IN_PROGRESS || GetData(TYPE_RING_OF_LAW) == SPECIAL) - { - for (uint8 i = 0; i < countof(aArenaNPCs); ++i) - { - if (pCreature->GetEntry() == aArenaNPCs[i]) - { - SetData(TYPE_RING_OF_LAW, FAIL); - return; - } - } - } - - switch (pCreature->GetEntry()) - { - // Handle Tomb of the Seven reset in case of wipe - case NPC_HATEREL: - case NPC_ANGERREL: - case NPC_VILEREL: - case NPC_GLOOMREL: - case NPC_SEETHREL: - case NPC_DOPEREL: - case NPC_DOOMREL: - SetData(TYPE_TOMB_OF_SEVEN, FAIL); - break; - case NPC_MAGMUS: - SetData(TYPE_IRON_HALL, FAIL); - break; - } + DoUseDoorOrButton(GO_SECRET_DOOR); } - - void OnObjectCreate(GameObject* pGo) override + m_auiEncounter[1] = uiData; + break; + case TYPE_ROCKNOT: + if (uiData == SPECIAL) + ++m_uiBarAleCount; + else { - switch (pGo->GetEntry()) - { - case GO_ARENA_1: - case GO_ARENA_2: - case GO_ARENA_3: - case GO_ARENA_4: - case GO_SHADOW_LOCK: - case GO_SHADOW_MECHANISM: - case GO_SHADOW_GIANT_DOOR: - case GO_SHADOW_DUMMY: - case GO_BAR_KEG_SHOT: - case GO_BAR_KEG_TRAP: - case GO_BAR_DOOR: - case GO_TOMB_ENTER: - case GO_TOMB_EXIT: - case GO_LYCEUM: - case GO_GOLEM_ROOM_N: - case GO_GOLEM_ROOM_S: - case GO_THRONE_ROOM: - case GO_SPECTRAL_CHALICE: - case GO_CHEST_SEVEN: - case GO_ARENA_SPOILS: - case GO_SECRET_DOOR: - case GO_JAIL_DOOR_SUPPLY: - case GO_JAIL_SUPPLY_CRATE: - break; - - default: - return; - } - m_mGoEntryGuidStore[pGo->GetEntry()] = pGo->GetObjectGuid(); - } - - void SetData(uint32 uiType, uint32 uiData) override - { - switch (uiType) - { - case TYPE_RING_OF_LAW: - // If finished the arena event after theldren fight - if (uiData == DONE && m_auiEncounter[0] == SPECIAL) - { - DoRespawnGameObject(GO_ARENA_SPOILS, HOUR); - } - m_auiEncounter[0] = uiData; - break; - case TYPE_VAULT: - if (uiData == SPECIAL) - { - ++m_uiCofferDoorsOpened; - - if (m_uiCofferDoorsOpened == MAX_RELIC_DOORS) - { - SetData(TYPE_VAULT, IN_PROGRESS); - - Creature* pConstruct = NULL; - - // Activate vault constructs - for (GuidSet::const_iterator itr = m_sVaultNpcGuids.begin(); itr != m_sVaultNpcGuids.end(); ++itr) - { - pConstruct = instance->GetCreature(*itr); - if (pConstruct) - { - pConstruct->RemoveAurasDueToSpell(SPELL_STONED); - } - } - - if (!pConstruct) - { - return; - } - - // Summon doomgrip - pConstruct->SummonCreature(NPC_WATCHER_DOOMGRIP, aVaultPositions[0], aVaultPositions[1], aVaultPositions[2], aVaultPositions[3], TEMPSUMMON_DEAD_DESPAWN, 0); - } - // No need to store in this case - return; - } - if (uiData == DONE) - { - DoUseDoorOrButton(GO_SECRET_DOOR); - } - m_auiEncounter[1] = uiData; - break; - case TYPE_BAR: - if (uiData == SPECIAL) - { - ++m_uiBarAleCount; - } - else - { - m_auiEncounter[2] = uiData; - } - break; - case TYPE_TOMB_OF_SEVEN: - // Don't set the same data twice - if (uiData == m_auiEncounter[3]) - { - break; - } - // Combat door - DoUseDoorOrButton(GO_TOMB_ENTER); - // Start the event - if (uiData == IN_PROGRESS) - { - DoCallNextDwarf(); - } - if (uiData == FAIL) - { - // Reset dwarfes - for (uint8 i = 0; i < MAX_DWARFS; ++i) - { - if (Creature* pDwarf = GetSingleCreatureFromStorage(aTombDwarfes[i])) - { - if (!pDwarf->IsAlive()) - { - pDwarf->Respawn(); - } - } - } - - m_uiDwarfRound = 0; - m_uiDwarfFightTimer = 0; - } - if (uiData == DONE) - { - DoRespawnGameObject(GO_CHEST_SEVEN, HOUR); - DoUseDoorOrButton(GO_TOMB_EXIT); - } - m_auiEncounter[3] = uiData; - break; - case TYPE_LYCEUM: - if (uiData == DONE) - { - DoUseDoorOrButton(GO_GOLEM_ROOM_N); - DoUseDoorOrButton(GO_GOLEM_ROOM_S); - } - m_auiEncounter[4] = uiData; - break; - case TYPE_IRON_HALL: - switch (uiData) - { - case IN_PROGRESS: - DoUseDoorOrButton(GO_GOLEM_ROOM_N); - DoUseDoorOrButton(GO_GOLEM_ROOM_S); - break; - case FAIL: - DoUseDoorOrButton(GO_GOLEM_ROOM_N); - DoUseDoorOrButton(GO_GOLEM_ROOM_S); - break; - case DONE: - DoUseDoorOrButton(GO_GOLEM_ROOM_N); - DoUseDoorOrButton(GO_GOLEM_ROOM_S); - DoUseDoorOrButton(GO_THRONE_ROOM); - break; - } - m_auiEncounter[5] = uiData; - break; - case TYPE_QUEST_JAIL_BREAK: - m_auiEncounter[6] = uiData; - return; - case TYPE_SIGNAL: - if (AreaTriggerEntry const *at = sAreaTriggerStore.LookupEntry(uiData)) - m_uiArenaCenterAT = uiData; - return; - } - if (uiData == DONE) { - OUT_SAVE_INST_DATA; - - std::ostringstream saveStream; - saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " - << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5] << " " << m_auiEncounter[6]; - - m_strInstData = saveStream.str(); - - SaveToDB(); - OUT_SAVE_INST_DATA_COMPLETE; + HandleBarPatrons(PATRON_PISSED); + SetBarDoorIsOpen(); } + m_auiEncounter[2] = uiData; } - - uint32 GetData(uint32 uiType) const override + break; + case TYPE_TOMB_OF_SEVEN: + // Don't set the same data twice + if (uiData == m_auiEncounter[3]) { - switch (uiType) - { - case TYPE_RING_OF_LAW: - return m_auiEncounter[0]; - case TYPE_VAULT: - return m_auiEncounter[1]; - case TYPE_BAR: - if (m_auiEncounter[2] == IN_PROGRESS && m_uiBarAleCount == 3) - { - return SPECIAL; - } - else - { - return m_auiEncounter[2]; - } - case TYPE_TOMB_OF_SEVEN: - return m_auiEncounter[3]; - case TYPE_LYCEUM: - return m_auiEncounter[4]; - case TYPE_IRON_HALL: - return m_auiEncounter[5]; - case TYPE_QUEST_JAIL_BREAK: - return m_auiEncounter[6]; - case TYPE_SIGNAL: - return m_uiArenaCenterAT; - default: - return 0; - } + break; } - - const char* Save() const override { return m_strInstData.c_str(); } - void Load(const char* chrIn) override + // Combat door + DoUseDoorOrButton(GO_TOMB_ENTER); + // Start the event + if (uiData == IN_PROGRESS) { - if (!chrIn) - { - OUT_LOAD_INST_DATA_FAIL; - return; - } - - OUT_LOAD_INST_DATA(chrIn); - - std::istringstream loadStream(chrIn); - loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3] - >> m_auiEncounter[4] >> m_auiEncounter[5] >> m_auiEncounter[6]; - - for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) - if (m_auiEncounter[i] == IN_PROGRESS) - { - m_auiEncounter[i] = NOT_STARTED; - } - - OUT_LOAD_INST_DATA_COMPLETE; + DoCallNextDwarf(); } - - void Update(uint32 uiDiff) override + if (uiData == FAIL) { - if (m_uiDwarfFightTimer) + // Reset dwarfes + for (uint8 i = 0; i < MAX_DWARFS; ++i) { - if (m_uiDwarfFightTimer <= uiDiff) + if (Creature* pDwarf = GetSingleCreatureFromStorage(aTombDwarfes[i])) { - if (m_uiDwarfRound < MAX_DWARFS) + if (!pDwarf->IsAlive()) { - DoCallNextDwarf(); - m_uiDwarfFightTimer = 30000; - } - else - { - m_uiDwarfFightTimer = 0; + pDwarf->Respawn(); } } - else - { - m_uiDwarfFightTimer -= uiDiff; - } } - } - private: - void DoCallNextDwarf() + m_uiDwarfRound = 0; + m_uiDwarfFightTimer = 0; + } + if (uiData == DONE) { - if (Creature* pDwarf = GetSingleCreatureFromStorage(aTombDwarfes[m_uiDwarfRound])) + DoRespawnGameObject(GO_CHEST_SEVEN, HOUR); + DoUseDoorOrButton(GO_TOMB_EXIT); + } + m_auiEncounter[3] = uiData; + break; + case TYPE_LYCEUM: + if (uiData == DONE) + { + DoUseDoorOrButton(GO_GOLEM_ROOM_N); + DoUseDoorOrButton(GO_GOLEM_ROOM_S); + } + m_auiEncounter[4] = uiData; + break; + case TYPE_IRON_HALL: + switch (uiData) + { + case IN_PROGRESS: + DoUseDoorOrButton(GO_GOLEM_ROOM_N); + DoUseDoorOrButton(GO_GOLEM_ROOM_S); + break; + case FAIL: + DoUseDoorOrButton(GO_GOLEM_ROOM_N); + DoUseDoorOrButton(GO_GOLEM_ROOM_S); + break; + case DONE: + DoUseDoorOrButton(GO_GOLEM_ROOM_N); + DoUseDoorOrButton(GO_GOLEM_ROOM_S); + DoUseDoorOrButton(GO_THRONE_ROOM); + break; + } + m_auiEncounter[5] = uiData; + break; + case TYPE_QUEST_JAIL_BREAK: + m_auiEncounter[6] = uiData; + return; + case TYPE_SIGNAL: + if (AreaTriggerEntry const *at = sAreaTriggerStore.LookupEntry(uiData)) + m_uiArenaCenterAT = uiData; + return; + case TYPE_FLAMELASH: + for (int i = 0; i < MAX_DWARF_RUNES; ++i) + DoUseDoorOrButton(GO_DWARFRUNE_A01 + i); + return; + case TYPE_HURLEY: + if (uiData == SPECIAL) + { + ++m_uiBrokenKegs; + + if (m_uiBrokenKegs == 3) { - if (Player* pPlayer = GetPlayerInMap()) + if (Creature* pPlugger = GetSingleCreatureFromStorage(NPC_PLUGGER_SPAZZRING)) { - pDwarf->SetFactionTemporary(FACTION_DWARF_HOSTILE, TEMPFACTION_RESTORE_RESPAWN | TEMPFACTION_RESTORE_REACH_HOME); - pDwarf->AI()->AttackStart(pPlayer); + // Summon Hurley Blackbreath + Creature* pHurley = pPlugger->SummonCreature(NPC_HURLEY_BLACKBREATH, aHurleyPositions[0], aHurleyPositions[1], aHurleyPositions[2], aHurleyPositions[3], TEMPSUMMON_DEAD_DESPAWN, 0); + + if (!pHurley) + return; + + // Summon cronies around Hurley + for (uint8 i = 0; i < MAX_CRONIES; ++i) + { + float fX, fY, fZ; + pPlugger->GetRandomPoint(aHurleyPositions[0], aHurleyPositions[1], aHurleyPositions[2], 2.0f, fX, fY, fZ); + Creature* pSummoned = pPlugger->SummonCreature(NPC_BLACKBREATH_CRONY, fX, fY, fZ, aHurleyPositions[3], TEMPSUMMON_DEAD_DESPAWN, 0); + pSummoned->SetWalk(false); + // The cronies should not engage anyone until their boss does so + // the linking is done by DB + pSummoned->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); + // The movement toward the kegs is handled by Hurley EscortAI + // and we want the cronies to follow him there + pSummoned->GetMotionMaster()->MoveFollow(pHurley, 1.0f, 0); + } + SetData(TYPE_HURLEY, IN_PROGRESS); } } - m_uiDwarfFightTimer = 30000; - ++m_uiDwarfRound; } - - uint32 m_auiEncounter[MAX_ENCOUNTER]; - std::string m_strInstData; - - uint32 m_uiBarAleCount; - uint8 m_uiCofferDoorsOpened; - - uint32 m_uiDwarfFightTimer; - uint32 m_uiArenaCenterAT; - uint8 m_uiDwarfRound; - - float m_fArenaCenterX, m_fArenaCenterY, m_fArenaCenterZ; - - GuidSet m_sVaultNpcGuids; - }; - - InstanceData* GetInstanceData(Map* pMap) override - { - return new instance_blackrock_depths(pMap); + else + m_auiEncounter[8] = uiData; + break; + case TYPE_BRIDGE: + m_auiEncounter[9] = uiData; + return; + case TYPE_BAR: + if (uiData == IN_PROGRESS) + HandleBarPatrol(0); + m_auiEncounter[10] = uiData; + break; + case TYPE_PLUGGER: + if (uiData == SPECIAL) + { + if (Creature* pPlugger = GetSingleCreatureFromStorage(NPC_PLUGGER_SPAZZRING)) + { + ++m_uiStolenAles; + if (m_uiStolenAles == 3) + uiData = IN_PROGRESS; + } + } + m_auiEncounter[11] = uiData; + break; + case TYPE_NAGMARA: + m_auiEncounter[12] = uiData; + break; } -}; + + if (uiData == DONE) + { + OUT_SAVE_INST_DATA; + + std::ostringstream saveStream; + saveStream << m_auiEncounter[0] << " " << m_auiEncounter[1] << " " << m_auiEncounter[2] << " " + << m_auiEncounter[3] << " " << m_auiEncounter[4] << " " << m_auiEncounter[5] << " " + << m_auiEncounter[6] << " " << m_auiEncounter[7] << " " << m_auiEncounter[8] << " " + << m_auiEncounter[9] << " " << m_auiEncounter[10] << " " << m_auiEncounter[11] << " " + << m_auiEncounter[12]; + + m_strInstData = saveStream.str(); + + SaveToDB(); + OUT_SAVE_INST_DATA_COMPLETE; + } +} + +uint32 instance_blackrock_depths::GetData(uint32 uiType) const +{ + switch (uiType) + { + case TYPE_RING_OF_LAW: + return m_auiEncounter[0]; + case TYPE_VAULT: + return m_auiEncounter[1]; + case TYPE_ROCKNOT: + if (m_auiEncounter[2] == IN_PROGRESS && m_uiBarAleCount == 3) + return SPECIAL; + else + return m_auiEncounter[2]; + case TYPE_TOMB_OF_SEVEN: + return m_auiEncounter[3]; + case TYPE_LYCEUM: + return m_auiEncounter[4]; + case TYPE_IRON_HALL: + return m_auiEncounter[5]; + case TYPE_QUEST_JAIL_BREAK: + return m_auiEncounter[6]; + case TYPE_SIGNAL: + return m_uiArenaCenterAT; + case TYPE_FLAMELASH: + return m_auiEncounter[7]; + case TYPE_HURLEY: + return m_auiEncounter[8]; + case TYPE_BRIDGE: + return m_auiEncounter[9]; + case TYPE_BAR: + return m_auiEncounter[10]; + case TYPE_PLUGGER: + return m_auiEncounter[11]; + case TYPE_NAGMARA: + return m_auiEncounter[12]; + default: + return 0; + } +} + +void instance_blackrock_depths::Load(const char* chrIn) +{ + if (!chrIn) + { + OUT_LOAD_INST_DATA_FAIL; + return; + } + + OUT_LOAD_INST_DATA(chrIn); + + std::istringstream loadStream(chrIn); + loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3] + >> m_auiEncounter[4] >> m_auiEncounter[5] >> m_auiEncounter[6] >> m_auiEncounter[7] + >> m_auiEncounter[8] >> m_auiEncounter[9] >> m_auiEncounter[10] >> m_auiEncounter[11] + >> m_auiEncounter[12]; + + for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) + if (m_auiEncounter[i] == IN_PROGRESS && i != TYPE_IRON_HALL) // specific check for Iron Hall event: once started, it never stops, the Ironhall Guardians switch to flamethrower mode and never stop even after event completion, i.e. the event remains started if Magmus resets + m_auiEncounter[i] = NOT_STARTED; + + OUT_LOAD_INST_DATA_COMPLETE; +} + +void instance_blackrock_depths::HandleBarPatrons(uint8 uiEventType) +{ + switch (uiEventType) + { + // case for periodical handle of random emotes + case PATRON_EMOTE: + for (GuidSet::const_iterator itr = m_sBarPatronNpcGuids.begin(); itr != m_sBarPatronNpcGuids.end(); ++itr) + { + // About 5% of patrons do emote at a given time + // So avoid executing follow up code for the 95% others + if (urand(0, 100) < 4) + { + // Only three emotes are seen in data: laugh, cheer and exclamation + // the last one appearing the least and the first one appearing the most + // emotes are stored in a table and frequency is handled there + if (Creature* pPatron = instance->GetCreature(*itr)) + pPatron->HandleEmote(aPatronsEmotes[urand(0, 5)]); + } + } + return; + // case for Rocknot event when breaking the barrel + case PATRON_PISSED: + // Three texts are said, one less often than the two others + // Only by patrons near the broken barrel react to Rocknot's rampage + if (GameObject* pGo = GetSingleGameObjectFromStorage(GO_BAR_KEG_SHOT)) + { + for (GuidSet::const_iterator itr = m_sBarPatronNpcGuids.begin(); itr != m_sBarPatronNpcGuids.end(); ++itr) + { + if (Creature* pPatron = instance->GetCreature(*itr)) + { + if (pPatron->GetPositionZ() > pGo->GetPositionZ() - 1 && pPatron->IsWithinDist2d(pGo->GetPositionX(), pGo->GetPositionY(), 18.0f)) + { + uint32 uiTextId = 0; + switch (urand(0, 4)) + { + case 0: uiTextId = SAY_PISSED_PATRON_3; break; + case 1: // case is double to give this text twice the chance of the previous one do be displayed + case 2: uiTextId = SAY_PISSED_PATRON_2; break; + // covers the two remaining cases + default: uiTextId = SAY_PISSED_PATRON_1; break; + } + DoScriptText(uiTextId, pPatron); + } + } + } + } + return; + // case when Plugger is aggroed/pickpocketed + case PATRON_HOSTILE: + for (GuidSet::const_iterator itr = m_sBarPatronNpcGuids.begin(); itr != m_sBarPatronNpcGuids.end(); ++itr) + { + if (Creature* pPatron = instance->GetCreature(*itr)) + { + pPatron->SetFactionTemporary(FACTION_DARK_IRON, TEMPFACTION_RESTORE_RESPAWN); + pPatron->SetStandState(UNIT_STAND_STATE_STAND); + // Patron should also start random movement around their current position (= home) + } + } + // Mistress Nagmara and Private Rocknot despawn if the bar turns hostile + if (Creature* pRocknot = GetSingleCreatureFromStorage(NPC_PRIVATE_ROCKNOT)) + { + DoScriptText(SAY_ROCKNOT_DESPAWN, pRocknot); + pRocknot->ForcedDespawn(); + } + if (Creature* pNagmara = GetSingleCreatureFromStorage(NPC_MISTRESS_NAGMARA)) + { + pNagmara->CastSpell(pNagmara, SPELL_NAGMARA_VANISH, true); + pNagmara->ForcedDespawn(); + } + return; + default: + return; + } +} + +void instance_blackrock_depths::HandleBarPatrol(uint8 uiStep) +{ + if (GetData(TYPE_BAR) == DONE) + return; + + switch (uiStep) + { + case 0: + if (Creature* pPlugger = GetSingleCreatureFromStorage(NPC_PLUGGER_SPAZZRING)) + { + // if relevant, open the bar door and tell the instance it is open + if (!m_bIsBarDoorOpen) + { + DoUseDoorOrButton(GO_BAR_DOOR); + SetBarDoorIsOpen(); + } + + // One Fireguard Destroyer and two Anvilrage Officers are spawned + for (uint8 i = 0; i < 3; ++i) + { + float fX, fY, fZ; + // spawn them behind the bar door + pPlugger->GetRandomPoint(aBarPatrolPositions[0][0], aBarPatrolPositions[0][1], aBarPatrolPositions[0][2], 2.0f, fX, fY, fZ); + if (Creature* pSummoned = pPlugger->SummonCreature(aBarPatrolId[i], fX, fY, fZ, aBarPatrolPositions[0][3], TEMPSUMMON_DEAD_DESPAWN, 0)) + { + m_sBarPatrolGuids.insert(pSummoned->GetObjectGuid()); + // move them to the Grim Guzzler + pPlugger->GetRandomPoint(aBarPatrolPositions[1][0], aBarPatrolPositions[1][1], aBarPatrolPositions[1][2], 2.0f, fX, fY, fZ); + pSummoned->GetMotionMaster()->MoveIdle(); + pSummoned->GetMotionMaster()->MovePoint(0,fX, fY, fZ); + } + } + // start timer to handle the yells + m_uiPatrolTimer = 4000; + break; + } + case 1: + for (GuidSet::const_iterator itr = m_sBarPatrolGuids.begin(); itr != m_sBarPatrolGuids.end(); ++itr) + { + if (Creature* pTmp = instance->GetCreature(*itr)) + { + if (pTmp->GetEntry() == NPC_FIREGUARD_DESTROYER) + { + DoScriptText(YELL_PATROL_1, pTmp); + SetData(TYPE_BAR, SPECIAL); // temporary set the status to special before the next yell: event will then be complete + m_uiPatrolTimer = 2000; + break; + } + } + } + break; + case 2: + for (GuidSet::const_iterator itr = m_sBarPatrolGuids.begin(); itr != m_sBarPatrolGuids.end(); ++itr) + { + if (Creature* pTmp = instance->GetCreature(*itr)) + { + if (pTmp->GetEntry() == NPC_FIREGUARD_DESTROYER) + { + DoScriptText(YELL_PATROL_2, pTmp); + SetData(TYPE_BAR, DONE); + m_uiPatrolTimer = 0; + break; + } + } + } + break; + } +} + +void instance_blackrock_depths::Update(uint32 uiDiff) +{ + if (m_uiDwarfFightTimer) + { + if (m_uiDwarfFightTimer <= uiDiff) + { + if (m_uiDwarfRound < MAX_DWARFS) + { + DoCallNextDwarf(); + m_uiDwarfFightTimer = 30000; + } + else + m_uiDwarfFightTimer = 0; + } + else + m_uiDwarfFightTimer -= uiDiff; + } + + if (m_uiDagranTimer) + { + if (m_uiDagranTimer <= uiDiff) + m_uiDagranTimer = 0; + else + m_uiDagranTimer -= uiDiff; + } + + // Every second some of the patrons will do one random emote if they are not hostile (i.e. Plugger event is not done/in progress) + if (m_uiPatronEmoteTimer) + { + if (m_uiPatronEmoteTimer <= uiDiff) + { + HandleBarPatrons(PATRON_EMOTE); + m_uiPatronEmoteTimer = 1000; + } + else + m_uiPatronEmoteTimer -= uiDiff; + } + + if (m_uiPatrolTimer) + { + if (m_uiPatrolTimer <= uiDiff) + { + switch(GetData(TYPE_BAR)) + { + case IN_PROGRESS: + HandleBarPatrol(1); + break; + case SPECIAL: + HandleBarPatrol(2); + break; + default: + break; + } + } + else + m_uiPatrolTimer -= uiDiff; + } +} + +void instance_blackrock_depths::DoCallNextDwarf() +{ + if (Creature* pDwarf = GetSingleCreatureFromStorage(aTombDwarfes[m_uiDwarfRound])) + { + if (Player* pPlayer = GetPlayerInMap()) + { + pDwarf->SetFactionTemporary(FACTION_DWARF_HOSTILE, TEMPFACTION_RESTORE_RESPAWN | TEMPFACTION_RESTORE_REACH_HOME); + pDwarf->AI()->AttackStart(pPlayer); + } + } + m_uiDwarfFightTimer = 30000; + ++m_uiDwarfRound; +} + + +InstanceData* GetInstanceData_instance_blackrock_depths(Map* pMap) +{ + return new instance_blackrock_depths(pMap); +} void AddSC_instance_blackrock_depths() { Script* s; - s = new is_blackrock_depths(); + s = new is_blackrock_spire(); s->RegisterSelf(); //pNewScript = new Script;