void UpdateAI(const uint32 diff) { if(!UpdateVictim()) return; if(((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 60) && (Phase == 1)) { Phase = 2; m_creature->AddUnitMovementFlag(MOVEMENTFLAG_LEVITATING); m_creature->SetHover(true); m_creature->GetMotionMaster()->Clear(false); m_creature->GetMotionMaster()->MoveIdle(); DoScriptText(SAY_PHASE_2_TRANS, m_creature); } if(((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 40) && (Phase == 2)) { Phase = 3; m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING); m_creature->SetHover(false); m_creature->GetMotionMaster()->MovePoint(0, -10.6155, -219.357, -87.7344); DoStartMovement(m_creature->getVictim()); m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE); DoScriptText(SAY_PHASE_3_TRANS, m_creature); } if(Phase == 1 || Phase == 3) { if(FlameBreathTimer < diff) { DoCast(m_creature->getVictim(), SPELL_FLAMEBREATH); FlameBreathTimer = 15000; }else FlameBreathTimer -= diff; if(TailSweepTimer < diff) { Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1); if(target && !m_creature->HasInArc(M_PI, target)) DoCast(target, SPELL_TAILSWEEP); TailSweepTimer = 10000; }else TailSweepTimer -= diff; if(CleaveTimer < diff) { DoCast(m_creature->getVictim(), SPELL_CLEAVE); CleaveTimer = 10000; }else CleaveTimer -= diff; if(WingBuffetTimer < diff) { DoCast(m_creature->getVictim(), SPELL_WINGBUFFET); WingBuffetTimer = 7000 + ((rand()%8)*1000); }else WingBuffetTimer -= diff; if(KnockAwayTimer < diff) { if(rand() <= 30) { DoCast(m_creature->getVictim(), SPELL_KNOCK_AWAY); } KnockAwayTimer = 15000; }else KnockAwayTimer -= diff; if(Phase == 3) { if(BellowingRoarTimer < diff) { DoCast(m_creature->getVictim(), SPELL_BELLOWINGROAR); BellowingRoarTimer = 30000; }else BellowingRoarTimer -= diff; if(SummonWhelpsTimer < diff) { SummonWhelps(Phase); SummonWhelpsTimer = 45000; }else SummonWhelpsTimer -= diff; } DoMeleeAttackIfReady(); } if(Phase == 2) { if(InitialSpawn) { InitialSpawn = false; for(uint32 i = 0; i < 10; ++i) { uint32 random = rand()%4; Creature* Whelp = m_creature->SummonCreature(CREATURE_WHELP, SpawnLocations[random][0], SpawnLocations[random][1], SpawnLocations[random][2], 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30000); if(Whelp) Whelp->AI()->AttackStart(SelectUnit(SELECT_TARGET_RANDOM, 0)); } } if(EngulfingFlamesTimer < diff) { DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_ENGULFINGFLAMES); m_creature->HandleEmoteCommand(ANIM_FLY); EngulfingFlamesTimer = 10000; } else EngulfingFlamesTimer -= diff; if(FireballTimer < diff) { DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0), SPELL_FIREBALL); FireballTimer = 18000; } else FireballTimer -= diff; if(MovementTimer < diff) { if(rand()%100 < 30) { DoScriptText(EMOTE_BREATH, m_creature); DoCast(m_creature->getVictim(), SPELL_DEEPBREATH); } else ChangePosition(); MovementTimer = 25000; }else MovementTimer -= diff; if(SummonWhelpsTimer < diff) { SummonWhelps(Phase); SummonWhelpsTimer = 45000; } else SummonWhelpsTimer -= diff; } }
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; } }