void MovementInform(uint32 uiMoveType, uint32 uiPointId) override { if (uiMoveType != POINT_MOTION_TYPE || !m_pInstance) return; switch (uiPointId) { case POINT_ID_IN_AIR: // sort of a hack, it is unclear how this really work but the values are valid m_creature->SetByteValue(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_FLY_ANIM); m_creature->SetLevitate(true); m_uiPhaseTimer = 1000; // Movement to Initial North Position is delayed return; case POINT_ID_LAND: // undo flying m_creature->SetByteValue(UNIT_FIELD_BYTES_1, 3, 0); m_creature->SetLevitate(false); m_creature->HandleEmote(EMOTE_ONESHOT_LAND); m_uiPhaseTimer = 500; // Start PHASE_END shortly delayed return; case POINT_ID_LIFTOFF: m_uiPhaseTimer = 500; // Start Flying shortly delayed m_creature->HandleEmote(EMOTE_ONESHOT_LIFTOFF); break; case POINT_ID_INIT_NORTH: // Start PHASE_BREATH m_uiPhase = PHASE_BREATH; break; } if (Creature* pTrigger = m_pInstance->GetSingleCreatureFromStorage(NPC_ONYXIA_TRIGGER)) m_creature->SetFacingToObject(pTrigger); }
void Aggro(Unit* /*pWho*/) override { DoScriptText(SAY_AGGRO, m_creature); if (m_pInstance) m_pInstance->SetData(TYPE_ONYXIA, IN_PROGRESS); }
void JustDied(Unit* /*pKiller*/) override { if (m_pInstance) { m_pInstance->SetData(TYPE_ONYXIA, DONE); } }
void JustReachedHome() override { // in case evade in phase 2, see comments for hack where phase 2 is set m_creature->SetLevitate(false); m_creature->SetByteFlag(UNIT_FIELD_BYTES_1, 3, 0); if (m_pInstance) m_pInstance->SetData(TYPE_ONYXIA, FAIL); }
void JustSummoned(Creature* pSummoned) override { if (!m_pInstance) return; if (Creature* pTrigger = m_pInstance->GetSingleCreatureFromStorage(NPC_ONYXIA_TRIGGER)) { // Get some random point near the center float fX, fY, fZ; pSummoned->GetRandomPoint(pTrigger->GetPositionX(), pTrigger->GetPositionY(), pTrigger->GetPositionZ(), 20.0f, fX, fY, fZ); pSummoned->GetMotionMaster()->MovePoint(1, fX, fY, fZ); } else pSummoned->SetInCombatWithZone(); if (pSummoned->GetEntry() == NPC_ONYXIA_WHELP) ++m_uiSummonCount; }
void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; // Whelps summoning timer, outside encounter phase switch because the summoning spans across several sub-parts of phase 2 if (m_uiSummonWhelpsTimer) { if (m_uiSummonWhelpsTimer < uiDiff) { SummonWhelps(); // no update of timer: handled in SummonWhelps() } else { m_uiSummonWhelpsTimer -= uiDiff; if (m_uiSummonWhelpsTimer == 0) // check needed for the rare but possible case where (m_uiSummonWhelpsTimer - uiDiff == 0) SummonWhelps(); } } switch (m_uiPhase) { case PHASE_END: if (m_uiBellowingRoarTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_BELLOWINGROAR) == CAST_OK) m_uiBellowingRoarTimer = urand(15000, 45000); } else m_uiBellowingRoarTimer -= uiDiff; // no break, phase 3 will use same abilities as in 1 case PHASE_START: { if (m_uiFlameBreathTimer < uiDiff) { if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_FLAMEBREATH) == CAST_OK) m_uiFlameBreathTimer = urand(10000, 20000); } else m_uiFlameBreathTimer -= uiDiff; if (m_uiTailSweepTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_TAILSWEEP) == CAST_OK) m_uiTailSweepTimer = urand(15000, 20000); } else m_uiTailSweepTimer -= uiDiff; if (m_uiCleaveTimer < uiDiff) { if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE) == CAST_OK) m_uiCleaveTimer = urand(2000, 5000); } else m_uiCleaveTimer -= uiDiff; if (m_uiWingBuffetTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_WINGBUFFET) == CAST_OK) m_uiWingBuffetTimer = urand(15000, 30000); } else m_uiWingBuffetTimer -= uiDiff; if (m_uiCheckInLairTimer < uiDiff) { if (m_pInstance) { Creature* pOnyTrigger = m_pInstance->GetSingleCreatureFromStorage(NPC_ONYXIA_TRIGGER); if (pOnyTrigger && !m_creature->IsWithinDistInMap(pOnyTrigger, 90.0f, false)) { if (!m_bHasYelledLured) { m_bHasYelledLured = true; DoScriptText(SAY_KITE, m_creature); } DoCastSpellIfCan(m_creature, SPELL_BREATH_ENTRANCE); } else m_bHasYelledLured = false; } m_uiCheckInLairTimer = 3000; } else m_uiCheckInLairTimer -= uiDiff; if (m_uiPhase == PHASE_START && m_creature->GetHealthPercent() < 65.0f) { m_uiPhase = PHASE_TO_LIFTOFF; DoScriptText(SAY_PHASE_2_TRANS, m_creature); SetCombatMovement(false); m_creature->GetMotionMaster()->MoveIdle(); m_creature->SetTarget(nullptr); float fGroundZ = m_creature->GetMap()->GetHeight(aMoveData[POINT_ID_SOUTH].fX, aMoveData[POINT_ID_SOUTH].fY, aMoveData[POINT_ID_SOUTH].fZ); m_creature->GetMotionMaster()->MovePoint(POINT_ID_LIFTOFF, aMoveData[POINT_ID_SOUTH].fX, aMoveData[POINT_ID_SOUTH].fY, fGroundZ); return; } DoMeleeAttackIfReady(); break; } case PHASE_BREATH: { if (m_creature->GetHealthPercent() < 40.0f) { m_uiPhase = PHASE_BREATH_POST; DoScriptText(SAY_PHASE_3_TRANS, m_creature); m_uiSummonWhelpsTimer = 0; // End of Onyxian Whelps summoning float fGroundZ = m_creature->GetMap()->GetHeight(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()); m_creature->GetMotionMaster()->MoveFlyOrLand(POINT_ID_LAND, m_creature->GetPositionX(), m_creature->GetPositionY(), fGroundZ, false); return; } if (m_uiMovementTimer < uiDiff) { // 3 possible actions switch (urand(0, 2)) { case 0: // breath DoScriptText(EMOTE_BREATH, m_creature); DoCastSpellIfCan(m_creature, aMoveData[m_uiMovePoint].uiSpellId, CAST_INTERRUPT_PREVIOUS); m_uiMovePoint += NUM_MOVE_POINT / 2; m_uiMovePoint %= NUM_MOVE_POINT; m_uiMovementTimer = 25000; return; case 1: // a point on the left side { // C++ is stupid, so add -1 with +7 m_uiMovePoint += NUM_MOVE_POINT - 1; m_uiMovePoint %= NUM_MOVE_POINT; break; } case 2: // a point on the right side ++m_uiMovePoint %= NUM_MOVE_POINT; break; } m_uiMovementTimer = urand(15000, 25000); m_creature->GetMotionMaster()->MovePoint(m_uiMovePoint, aMoveData[m_uiMovePoint].fX, aMoveData[m_uiMovePoint].fY, aMoveData[m_uiMovePoint].fZ); } else m_uiMovementTimer -= uiDiff; if (m_uiFireballTimer < uiDiff) { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { if (DoCastSpellIfCan(pTarget, SPELL_FIREBALL) == CAST_OK) m_uiFireballTimer = urand(3000, 5000); } } else m_uiFireballTimer -= uiDiff; // engulfingflames is supposed to be activated by a fireball but haven't come by break; } default: // Phase-switching phases if (!m_uiPhaseTimer) break; if (m_uiPhaseTimer <= uiDiff) { switch (m_uiPhase) { case PHASE_TO_LIFTOFF: m_uiPhase = PHASE_BREATH_PRE; // Initial Onyxian Whelps spawn m_uiSummonWhelpsTimer = 3000; if (m_pInstance) m_pInstance->SetData(TYPE_ONYXIA, DATA_LIFTOFF); m_creature->GetMotionMaster()->MoveFlyOrLand(POINT_ID_IN_AIR, aMoveData[POINT_ID_SOUTH].fX, aMoveData[POINT_ID_SOUTH].fY, aMoveData[POINT_ID_SOUTH].fZ, true); break; case PHASE_BREATH_PRE: m_creature->GetMotionMaster()->MovePoint(POINT_ID_INIT_NORTH, aMoveData[POINT_ID_NORTH].fX, aMoveData[POINT_ID_NORTH].fY, aMoveData[POINT_ID_NORTH].fZ); break; case PHASE_BREATH_POST: m_uiPhase = PHASE_END; m_creature->SetTarget(m_creature->getVictim()); SetCombatMovement(true, true); DoCastSpellIfCan(m_creature, SPELL_BELLOWINGROAR); break; } m_uiPhaseTimer = 0; } else m_uiPhaseTimer -= uiDiff; break; } }
void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) { return; } switch (m_uiPhase) { case PHASE_END: // Here is room for additional summoned whelps and Erruption if (m_uiBellowingRoarTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_BELLOWINGROAR) == CAST_OK) { m_uiBellowingRoarTimer = 30000; } } else { m_uiBellowingRoarTimer -= uiDiff; } // no break, phase 3 will use same abilities as in 1 case PHASE_START: { if (m_uiFlameBreathTimer < uiDiff) { if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_FLAMEBREATH) == CAST_OK) { m_uiFlameBreathTimer = urand(10000, 20000); } } else { m_uiFlameBreathTimer -= uiDiff; } if (m_uiTailSweepTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_TAILSWEEP) == CAST_OK) { m_uiTailSweepTimer = urand(15000, 20000); } } else { m_uiTailSweepTimer -= uiDiff; } if (m_uiCleaveTimer < uiDiff) { if (DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE) == CAST_OK) { m_uiCleaveTimer = urand(2000, 5000); } } else { m_uiCleaveTimer -= uiDiff; } if (m_uiWingBuffetTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_WINGBUFFET) == CAST_OK) { m_uiWingBuffetTimer = urand(15000, 30000); } } else { m_uiWingBuffetTimer -= uiDiff; } if (m_uiCheckInLairTimer < uiDiff) { if (m_pInstance) { Creature* pOnyTrigger = m_pInstance->GetSingleCreatureFromStorage(NPC_ONYXIA_TRIGGER); if (pOnyTrigger && !m_creature->IsWithinDistInMap(pOnyTrigger, 90.0f, false)) { DoCastSpellIfCan(m_creature, SPELL_BREATH_ENTRANCE); } } m_uiCheckInLairTimer = 3000; } else { m_uiCheckInLairTimer -= uiDiff; } if (m_uiPhase == PHASE_START && m_creature->GetHealthPercent() < 65.0f) { m_uiPhase = PHASE_TO_LIFTOFF; DoScriptText(SAY_PHASE_2_TRANS, m_creature); SetCombatMovement(false); m_creature->GetMotionMaster()->MoveIdle(); m_creature->SetTargetGuid(ObjectGuid()); float fGroundZ = m_creature->GetMap()->GetHeight(aMoveData[POINT_ID_SOUTH].fX, aMoveData[POINT_ID_SOUTH].fY, aMoveData[POINT_ID_SOUTH].fZ); m_creature->GetMotionMaster()->MovePoint(POINT_ID_LIFTOFF, aMoveData[POINT_ID_SOUTH].fX, aMoveData[POINT_ID_SOUTH].fY, fGroundZ); return; } DoMeleeAttackIfReady(); break; } case PHASE_BREATH: { if (m_creature->GetHealthPercent() < 40.0f) { m_uiPhase = PHASE_BREATH_POST; DoScriptText(SAY_PHASE_3_TRANS, m_creature); float fGroundZ = m_creature->GetMap()->GetHeight(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()); m_creature->GetMotionMaster()->MoveFlyOrLand(POINT_ID_LAND, m_creature->GetPositionX(), m_creature->GetPositionY(), fGroundZ, false); return; } if (m_uiMovementTimer < uiDiff) { // 3 possible actions switch (urand(0, 2)) { case 0: // breath DoScriptText(EMOTE_BREATH, m_creature); DoCastSpellIfCan(m_creature, aMoveData[m_uiMovePoint].uiSpellId, CAST_INTERRUPT_PREVIOUS); m_uiMovePoint += NUM_MOVE_POINT / 2; m_uiMovePoint %= NUM_MOVE_POINT; m_uiMovementTimer = 25000; return; case 1: // a point on the left side { // C++ is stupid, so add -1 with +7 m_uiMovePoint += NUM_MOVE_POINT - 1; m_uiMovePoint %= NUM_MOVE_POINT; break; } case 2: // a point on the right side ++m_uiMovePoint %= NUM_MOVE_POINT; break; } m_uiMovementTimer = urand(15000, 25000); m_creature->GetMotionMaster()->MovePoint(m_uiMovePoint, aMoveData[m_uiMovePoint].fX, aMoveData[m_uiMovePoint].fY, aMoveData[m_uiMovePoint].fZ); } else { m_uiMovementTimer -= uiDiff; } if (m_uiFireballTimer < uiDiff) { if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) { if (DoCastSpellIfCan(pTarget, SPELL_FIREBALL) == CAST_OK) { m_uiFireballTimer = urand(3000, 5000); } } } else { m_uiFireballTimer -= uiDiff; // engulfingflames is supposed to be activated by a fireball but haven't come by } if (m_bIsSummoningWhelps) { if (DidSummonWhelps(uiDiff)) { m_bIsSummoningWhelps = false; m_uiSummonCount = 0; m_uiSummonWhelpsTimer = 80000; // 90s - 10s for summoning } } else { if (m_uiSummonWhelpsTimer < uiDiff) { m_bIsSummoningWhelps = true; } else { m_uiSummonWhelpsTimer -= uiDiff; } } break; } case PHASE_BREATH_PRE: // Summon first rounds of whelps DidSummonWhelps(uiDiff); // no break here default: // Phase-switching phases if (!m_uiPhaseTimer) { break; } if (m_uiPhaseTimer <= uiDiff) { switch (m_uiPhase) { case PHASE_TO_LIFTOFF: m_uiPhase = PHASE_BREATH_PRE; if (m_pInstance) { m_pInstance->SetData(TYPE_ONYXIA, DATA_LIFTOFF); } m_creature->GetMotionMaster()->MoveFlyOrLand(POINT_ID_IN_AIR, aMoveData[POINT_ID_SOUTH].fX, aMoveData[POINT_ID_SOUTH].fY, aMoveData[POINT_ID_SOUTH].fZ, true); break; case PHASE_BREATH_PRE: m_creature->GetMotionMaster()->MovePoint(POINT_ID_INIT_NORTH, aMoveData[POINT_ID_NORTH].fX, aMoveData[POINT_ID_NORTH].fY, aMoveData[POINT_ID_NORTH].fZ); break; case PHASE_BREATH_POST: m_uiPhase = PHASE_END; m_creature->SetTargetGuid(m_creature->getVictim()->GetObjectGuid()); SetCombatMovement(true, true); DoCastSpellIfCan(m_creature, SPELL_BELLOWINGROAR); break; } m_uiPhaseTimer = 0; } else { m_uiPhaseTimer -= uiDiff; } break; } }