diff --git a/data/sql/updates/pending_db_world/rev_1715986644313348181.sql b/data/sql/updates/pending_db_world/rev_1715986644313348181.sql new file mode 100644 index 000000000..466919755 --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1715986644313348181.sql @@ -0,0 +1,13 @@ +-- +-- Razuvious +DELETE FROM `creature_text` WHERE `CreatureID` = 16061 AND `GroupID` IN (4, 5); +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(16061, 4, 0, 'Pathetic...', 12, 0, 100, 5, 0, 0, 27865, 0, 'Razuvious SAY_PATHETIC'), +(16061, 5, 0, 'Start doing something before I replace that target dummy with you and begin a warm up session of my own!', 12, 0, 100, 5, 0, 0, 13136, 0, 'Razuvious SAY_TARGET_DUMMY'); + +-- Death Knight Understudy +DELETE FROM `creature_text` WHERE `CreatureID` = 16803; +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(16803, 0, 0, 'Sir, student requests that you beat him for his lack of understanding!', 12, 0, 100, 1, 0, 0, 13140, 0, 'Death Knight Understudy SAY_BEAT_ME'), +(16803, 0, 1, 'I am unworthy, master!', 12, 0, 100, 1, 0, 0, 13138, 0, 'Death Knight Understudy SAY_UNWORTHY'), +(16803, 0, 2, 'Student is worthless, master! Student apologizes for his deficiency!', 12, 0, 100, 1, 0, 0, 13137, 0, 'Death Knight Understudy SAY_WORTHLESS'); diff --git a/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp b/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp index 9264e851f..eed3cd6cf 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp @@ -24,7 +24,10 @@ enum Says SAY_AGGRO = 0, SAY_SLAY = 1, SAY_TAUNTED = 2, - SAY_DEATH = 3 + SAY_DEATH = 3, + SAY_PATHETIC = 4, + SAY_TARGET_DUMMY = 5, + SAY_DEATH_KNIGHT_UNDERSTUDY = 0, }; enum Spells @@ -34,7 +37,6 @@ enum Spells SPELL_DISRUPTING_SHOUT_25 = 29107, SPELL_JAGGED_KNIFE = 55550, SPELL_HOPELESS = 29125, - SPELL_TAUNT = 29060 }; @@ -45,10 +47,25 @@ enum Events EVENT_JAGGED_KNIFE = 3 }; -enum Misc +enum NPCs { NPC_DEATH_KNIGHT_UNDERSTUDY = 16803, - NPC_RAZUVIOUS = 16061 + NPC_TARGET_DUMMY = 16211, +}; + +enum Actions +{ + ACTION_FACE_ME = 0, + ACTION_TALK = 1, + ACTION_EMOTE = 2, + ACTION_SALUTE = 3, + ACTION_BACK_TO_TRAINING = 4, +}; + +enum Misc +{ + GROUP_OOC_RP = 0, + POINT_DEATH_KNIGHT = 0, }; class boss_razuvious : public CreatureScript @@ -94,6 +111,99 @@ public: summons.DespawnAll(); events.Reset(); SpawnHelpers(); + ScheduleRP(); + } + + void ScheduleInteractWithDeathKnight() + { + if (_rpBuddyGUID) + if (Creature* understudy = ObjectAccessor::GetCreature(*me, _rpBuddyGUID)) + me->SetFacingToObject(understudy); + + scheduler.Schedule(2s, GROUP_OOC_RP, [this](TaskContext /*context*/) + { + if (roll_chance_i(75)) + { + bool longText = roll_chance_i(50); + Talk(longText ? SAY_TARGET_DUMMY : SAY_PATHETIC); + scheduler.Schedule(4s, GROUP_OOC_RP, [this](TaskContext /*context*/) + { + if (_rpBuddyGUID) + if (Creature* understudy = ObjectAccessor::GetCreature(*me, _rpBuddyGUID)) + understudy->AI()->DoAction(ACTION_TALK); + }); + if (longText) + scheduler.DelayGroup(GROUP_OOC_RP, 5s); + } + else + { + me->HandleEmoteCommand(EMOTE_ONESHOT_EXCLAMATION); + scheduler.Schedule(4s, GROUP_OOC_RP, [this](TaskContext /*context*/) + { + if (_rpBuddyGUID) + if (Creature* understudy = ObjectAccessor::GetCreature(*me, _rpBuddyGUID)) + { + if (roll_chance_i(25)) + understudy->AI()->DoAction(ACTION_EMOTE); + else + understudy->AI()->DoAction(ACTION_TALK); + } + }); + } + }).Schedule(4s, GROUP_OOC_RP, [this](TaskContext /*context*/) + { + if (_rpBuddyGUID) + if (Creature* understudy = ObjectAccessor::GetCreature(*me, _rpBuddyGUID)) + understudy->AI()->DoAction(ACTION_FACE_ME); + }).Schedule(10s, GROUP_OOC_RP, [this](TaskContext /*context*/) + { + if (_rpBuddyGUID) + if (Creature* understudy = ObjectAccessor::GetCreature(*me, _rpBuddyGUID)) + understudy->AI()->DoAction(ACTION_SALUTE); + }).Schedule(13s, GROUP_OOC_RP, [this](TaskContext /*context*/) + { + me->ResumeMovement(); + }).Schedule(16s, GROUP_OOC_RP, [this](TaskContext /*context*/) + { + if (_rpBuddyGUID) + if (Creature* understudy = ObjectAccessor::GetCreature(*me, _rpBuddyGUID)) + understudy->AI()->DoAction(ACTION_BACK_TO_TRAINING); + ScheduleRP(); + }); + } + + void MovementInform(uint32 type, uint32 id) override + { + if (type == POINT_MOTION_TYPE && id == POINT_DEATH_KNIGHT) + { + ScheduleInteractWithDeathKnight(); + } + } + + void ScheduleRP() + { + _rpBuddyGUID = Acore::Containers::SelectRandomContainerElement(summons); + scheduler.Schedule(60s, 80s, GROUP_OOC_RP, [this](TaskContext context) + { + if (_rpBuddyGUID) + { + if (Creature* understudy = ObjectAccessor::GetCreature(*me, _rpBuddyGUID)) + { + if (me->GetDistance2d(understudy) <= 6.0f) + { + me->PauseMovement(); + scheduler.Schedule(500ms, GROUP_OOC_RP, [this](TaskContext /*context*/) + { + if (_rpBuddyGUID) + if (Creature* understudy = ObjectAccessor::GetCreature(*me, _rpBuddyGUID)) + me->GetMotionMaster()->MovePoint(POINT_DEATH_KNIGHT, understudy->GetNearPosition(3.2f, understudy->GetRelativeAngle(me))); + }); + return; + } + } + } + context.Repeat(2s); + }); } void KilledUnit(Unit* who) override @@ -135,6 +245,7 @@ public: void JustEngagedWith(Unit* who) override { BossAI::JustEngagedWith(who); + scheduler.CancelGroup(GROUP_OOC_RP); Talk(SAY_AGGRO); events.ScheduleEvent(EVENT_UNBALANCING_STRIKE, 20s); events.ScheduleEvent(EVENT_DISRUPTING_SHOUT, 15s); @@ -144,6 +255,9 @@ public: void UpdateAI(uint32 diff) override { + if (!me->IsInCombat()) + scheduler.Update(diff); + if (!UpdateVictim()) return; @@ -171,6 +285,9 @@ public: } DoMeleeAttackIfReady(); } + + private: + ObjectGuid _rpBuddyGUID; }; }; @@ -179,20 +296,65 @@ class boss_razuvious_minion : public CreatureScript public: boss_razuvious_minion() : CreatureScript("boss_razuvious_minion") { } - CreatureAI* GetAI(Creature* pCreature) const override + CreatureAI* GetAI(Creature* creature) const override { - return GetNaxxramasAI(pCreature); + return GetNaxxramasAI(creature); } struct boss_razuvious_minionAI : public ScriptedAI { - explicit boss_razuvious_minionAI(Creature* c) : ScriptedAI(c) { } - - EventMap events; + explicit boss_razuvious_minionAI(Creature* creature) : ScriptedAI(creature) { } void Reset() override { - events.Reset(); + scheduler.CancelAll(); + ScheduleAttackDummy(); + } + + void ScheduleAttackDummy() + { + me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_READY1H); + if (Creature* targetDummy = me->FindNearestCreature(NPC_TARGET_DUMMY, 10.0f)) + { + me->SetFacingToObject(targetDummy); + } + scheduler.Schedule(6s, 9s, GROUP_OOC_RP, [this](TaskContext context) + { + me->HandleEmoteCommand(EMOTE_ONESHOT_ATTACK1H); + context.Repeat(6s, 9s); + }); + } + + void DoAction(int32 action) override + { + switch (action) + { + case ACTION_FACE_ME: + scheduler.CancelGroup(GROUP_OOC_RP); + me->SetSheath(SHEATH_STATE_UNARMED); + me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_NONE); + if (InstanceScript* instance = me->GetInstanceScript()) + { + if (Creature* creature = instance->GetCreature(DATA_RAZUVIOUS)) + { + me->SetFacingToObject(creature); + } + } + break; + case ACTION_TALK: + Talk(SAY_DEATH_KNIGHT_UNDERSTUDY); + break; + case ACTION_EMOTE: + me->HandleEmoteCommand(EMOTE_ONESHOT_TALK); + break; + case ACTION_SALUTE: + me->HandleEmoteCommand(EMOTE_ONESHOT_SALUTE); + break; + case ACTION_BACK_TO_TRAINING: + me->SetSheath(SHEATH_STATE_MELEE); + ScheduleAttackDummy(); + break; + } } void KilledUnit(Unit* who) override @@ -205,18 +367,23 @@ public: void JustEngagedWith(Unit* who) override { - if (Creature* cr = me->FindNearestCreature(NPC_RAZUVIOUS, 100.0f)) + scheduler.CancelGroup(GROUP_OOC_RP); + if (InstanceScript* instance = me->GetInstanceScript()) { - cr->SetInCombatWithZone(); - cr->AI()->AttackStart(who); + if (Creature* creature = instance->GetCreature(DATA_RAZUVIOUS)) + { + creature->SetInCombatWithZone(); + creature->AI()->AttackStart(who); + } } } void UpdateAI(uint32 diff) override { + scheduler.Update(diff); + if (UpdateVictim()) { - events.Update(diff); if (!me->HasUnitState(UNIT_STATE_CASTING) || !me->IsCharmed()) { DoMeleeAttackIfReady(); diff --git a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp index 2f45192b7..431e5ae55 100644 --- a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp +++ b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp @@ -52,6 +52,17 @@ inline uint8 GetEruptionSection(float x, float y) return 3; } +ObjectData const creatureData[] = +{ + { NPC_RAZUVIOUS, DATA_RAZUVIOUS }, + { 0, 0 } +}; + +ObjectData const gameObjectData[] = +{ + { 0, 0 } +}; + class instance_naxxramas : public InstanceMapScript { public: @@ -68,6 +79,7 @@ public: { SetHeaders(DataHeader); SetBossNumber(MAX_ENCOUNTERS); + LoadObjectData(creatureData, gameObjectData); for (auto& i : HeiganEruption) i.clear(); @@ -253,6 +265,8 @@ public: _lichkingGUID = creature->GetGUID(); return; } + + InstanceScript::OnCreatureCreate(creature); } void OnGameObjectCreate(GameObject* pGo) override @@ -498,6 +512,8 @@ public: } break; } + + InstanceScript::OnGameObjectCreate(pGo); } void OnGameObjectRemove(GameObject* pGo) override diff --git a/src/server/scripts/Northrend/Naxxramas/naxxramas.h b/src/server/scripts/Northrend/Naxxramas/naxxramas.h index 256ca8633..5c237d784 100644 --- a/src/server/scripts/Northrend/Naxxramas/naxxramas.h +++ b/src/server/scripts/Northrend/Naxxramas/naxxramas.h @@ -58,26 +58,27 @@ enum NXData DATA_STALAGG_BOSS = 108, DATA_FEUGEN_BOSS = 109, DATA_THADDIUS_GATE = 110, - DATA_GOTHIK_BOSS = 111, - DATA_GOTHIK_ENTER_GATE = 112, - DATA_GOTHIK_INNER_GATE = 113, - DATA_GOTHIK_EXIT_GATE = 114, - DATA_HORSEMEN_GATE = 115, - DATA_LICH_KING_BOSS = 116, - DATA_KELTHUZAD_FLOOR = 117, - DATA_ABOMINATION_KILLED = 118, - DATA_FRENZY_REMOVED = 119, - DATA_CHARGES_CROSSED = 120, - DATA_SPORE_KILLED = 121, - DATA_HUNDRED_CLUB = 122, - DATA_DANCE_FAIL = 123, - DATA_IMMORTAL_FAIL = 124, - DATA_KELTHUZAD_GATE = 125, - DATA_HAD_THADDIUS_GREET = 126, - DATA_KELTHUZAD_PORTAL_1 = 127, - DATA_KELTHUZAD_PORTAL_2 = 128, - DATA_KELTHUZAD_PORTAL_3 = 129, - DATA_KELTHUZAD_PORTAL_4 = 130 + DATA_RAZUVIOUS = 111, + DATA_GOTHIK_BOSS = 112, + DATA_GOTHIK_ENTER_GATE = 113, + DATA_GOTHIK_INNER_GATE = 114, + DATA_GOTHIK_EXIT_GATE = 115, + DATA_HORSEMEN_GATE = 116, + DATA_LICH_KING_BOSS = 117, + DATA_KELTHUZAD_FLOOR = 118, + DATA_ABOMINATION_KILLED = 119, + DATA_FRENZY_REMOVED = 120, + DATA_CHARGES_CROSSED = 121, + DATA_SPORE_KILLED = 122, + DATA_HUNDRED_CLUB = 123, + DATA_DANCE_FAIL = 124, + DATA_IMMORTAL_FAIL = 125, + DATA_KELTHUZAD_GATE = 126, + DATA_HAD_THADDIUS_GREET = 127, + DATA_KELTHUZAD_PORTAL_1 = 128, + DATA_KELTHUZAD_PORTAL_2 = 129, + DATA_KELTHUZAD_PORTAL_3 = 130, + DATA_KELTHUZAD_PORTAL_4 = 131 }; enum NXGOs @@ -137,6 +138,9 @@ enum NXNPCs NPC_STALAGG = 15929, NPC_FEUGEN = 15930, + // Razuvious + NPC_RAZUVIOUS = 16061, + // Four horseman NPC_BARON_RIVENDARE = 30549, NPC_SIR_ZELIEK = 16063,