diff --git a/sql/scriptdev2/scriptdev2.sql b/sql/scriptdev2/scriptdev2.sql index 73adcda1c4..427d944764 100644 --- a/sql/scriptdev2/scriptdev2.sql +++ b/sql/scriptdev2/scriptdev2.sql @@ -1919,17 +1919,6 @@ INSERT INTO script_texts (entry,content_default,sound,type,language,emote,broadc ('-1000499','Puny $r wanna fight Overlord Mok''Morokk? Me beat you! Me boss here!','0','0','1','0','1515','morokk SAY_MOR_CHALLENGE'), ('-1000500','Me scared! Me run now!','0','1','0','0','1523','morokk SAY_MOR_SCARED'), -('-1000501','Are you sure that you are ready? If we do not have a group of your allies to aid us, we will surely fail.','0','0','1','0','8566','muglash SAY_MUG_START1'), -('-1000502','This will be a tough fight, $N. Follow me closely!','0','0','1','0','8555','muglash SAY_MUG_START2'), -('-1000503','This is the brazier, $N. Put it out. Vorsha is a beast, worthy of praise from no one!','0','0','1','0','8556','muglash SAY_MUG_BRAZIER'), -('-1000504','Now we must wait, $N. It won''t be long before the naga realize what we have done.','0','0','1','0','8410','muglash SAY_MUG_BRAZIER_WAIT'), -('-1000505','Be on your guard, $N!','0','0','1','0','8412','muglash SAY_MUG_ON_GUARD'), -('-1000506','Perhaps we will get a moment to rest. But I will not give up until we have faced off against Vorsha!','0','0','1','0','8413','muglash SAY_MUG_REST'), -('-1000507','We have done it, $N!','0','0','1','0','8569','muglash SAY_MUG_DONE'), -('-1000508','You have my deepest gratitude, $N. I thank you.','0','0','1','0','8558','muglash SAY_MUG_GRATITUDE'), -('-1000509','I am going to patrol the area for a while longer and ensure that things are truly safe.','0','0','1','0','8564','muglash SAY_MUG_PATROL'), -('-1000510','Please return to Zoram''gar and report our success to the Warsong Runner.','0','0','1','0','8565','muglash SAY_MUG_RETURN'), - ('-1000511','Aright, listen up! Form a circle around me and move out!','0','0','0','0','20314','letoll SAY_LE_START'), ('-1000512','Aright, $r, just keep us safe from harm while we work. We''ll pay you when we return.','0','0','0','0','20328','letoll SAY_LE_KEEP_SAFE'), ('-1000513','The dig site is just north of here.','0','0','0','0','20329','letoll SAY_LE_NORTH'), @@ -6052,36 +6041,6 @@ INSERT INTO script_waypoint (Entry, PathId, Point, PositionX, PositionY, Positio (12580,0,25,-8455.95,351.225,120.88,0,0,0,''), (12580,0,26,-8446.87,339.904,121.33,5.3737,1000,0,'SAY_WINDSOR_KEEP_1'), (12580,0,27,-8446.87,339.904,121.33,0,10000,0,''), -(12717,0,1,3346.25,1007.88,3.59,0,0,0,'SAY_MUG_START2'), -(12717,0,2,3367.39,1011.51,3.72,0,0,0,''), -(12717,0,3,3418.64,1013.96,2.905,0,0,0,''), -(12717,0,4,3426.84,1015.1,3.449,0,0,0,''), -(12717,0,5,3437.03,1020.79,2.742,0,0,0,''), -(12717,0,6,3460.56,1024.26,1.353,0,0,0,''), -(12717,0,7,3479.87,1037.96,1.023,0,0,0,''), -(12717,0,8,3490.53,1043.35,3.338,0,0,0,''), -(12717,0,9,3504.28,1047.77,8.205,0,0,0,''), -(12717,0,10,3510.73,1049.79,12.143,0,0,0,''), -(12717,0,11,3514.41,1051.17,13.235,0,0,0,''), -(12717,0,12,3516.94,1052.91,12.918,0,0,0,''), -(12717,0,13,3523.64,1056.3,7.563,0,0,0,''), -(12717,0,14,3531.94,1059.86,6.175,0,0,0,''), -(12717,0,15,3535.48,1069.96,1.697,0,0,0,''), -(12717,0,16,3546.98,1093.49,0.68,0,0,0,''), -(12717,0,17,3549.73,1101.88,-1.123,0,0,0,''), -(12717,0,18,3555.14,1116.99,-4.326,0,0,0,''), -(12717,0,19,3571.94,1132.18,-0.634,0,0,0,''), -(12717,0,20,3574.28,1137.58,3.684,0,0,0,''), -(12717,0,21,3579.31,1137.25,8.205,0,0,0,''), -(12717,0,22,3590.22,1143.65,8.291,0,0,0,''), -(12717,0,23,3595.97,1145.83,6.773,0,0,0,''), -(12717,0,24,3603.65,1146.92,9.763,0,0,0,''), -(12717,0,25,3607.08,1146.01,10.692,0,5000,0,'SAY_MUG_BRAZIER'), -(12717,0,26,3614.52,1142.63,10.248,0,0,0,''), -(12717,0,27,3616.66,1140.84,10.682,0,3000,0,'SAY_MUG_PATROL'), -(12717,0,28,3621.08,1138.11,10.369,0,0,0,'SAY_MUG_RETURN'), -(12717,0,29,3615.48,1145.53,9.614,0,0,0,''), -(12717,0,30,3607.19,1152.72,8.871,0,0,0,''), (12818,0,1,3347.25,-694.701,159.926,0,0,0,''), (12818,0,2,3341.53,-694.726,161.125,0,1000,0,''), (12818,0,3,3338.35,-686.088,163.444,0,0,0,''), diff --git a/src/game/AI/ScriptDevAI/scripts/kalimdor/ashenvale.cpp b/src/game/AI/ScriptDevAI/scripts/kalimdor/ashenvale.cpp index b8b0a5c88e..d9e0ef5249 100644 --- a/src/game/AI/ScriptDevAI/scripts/kalimdor/ashenvale.cpp +++ b/src/game/AI/ScriptDevAI/scripts/kalimdor/ashenvale.cpp @@ -37,71 +37,97 @@ EndContentData */ enum { - SAY_MUG_START1 = -1000501, - SAY_MUG_START2 = -1000502, - SAY_MUG_BRAZIER = -1000503, - SAY_MUG_BRAZIER_WAIT = -1000504, - SAY_MUG_ON_GUARD = -1000505, - SAY_MUG_REST = -1000506, - SAY_MUG_DONE = -1000507, - SAY_MUG_GRATITUDE = -1000508, - SAY_MUG_PATROL = -1000509, - SAY_MUG_RETURN = -1000510, - + MUGLASH_ESCORT_PATH = 12717, + + SAY_MUGLASH_START = 8555, + SAY_MUGLASH_BRAZIER = 8556, + SAY_MUGLASH_FAIL = 8409, + SAY_MUGLASH_AGGRO = 8412, + SAY_MUGLASH_EVENT_01 = 8410, + SAY_MUGLASH_EVENT_02 = 8413, + SAY_MUGLASH_EVENT_03 = 8567, + SAY_MUGLASH_EVENT_04 = 8568, + SAY_MUGLASH_SUCCESS = 8569, + SAY_MUGLASH_SUCCESS_02 = 8558, + SAY_MUGLASH_SUCCESS_03 = 8564, + SAY_MUGLASH_SUCCESS_04 = 8565, + + SPELL_MUGLASH_WAITING = 20861, QUEST_VORSHA = 6641, GO_NAGA_BRAZIER = 178247, + NPC_MUGLASH = 12717, + // First Wave NPC_WRATH_RIDER = 3713, NPC_WRATH_SORCERESS = 3717, NPC_WRATH_RAZORTAIL = 3712, + // 2nd Wave NPC_WRATH_PRIESTESS = 3944, NPC_WRATH_MYRMIDON = 3711, NPC_WRATH_SEAWITCH = 3715, - NPC_VORSHA = 12940 + // 3rd Wave + NPC_VORSHA = 12940, }; -static float m_afFirstNagaCoord[3][3] = +enum MuglashActions { - {3603.504150f, 1122.631104f, 1.635f}, // rider - {3589.293945f, 1148.664063f, 5.565f}, // sorceress - {3609.925537f, 1168.759521f, -1.168f} // razortail + NETHEKURSE_ACTION_MAX, + MUGLASH_FAIL, + MUGLASH_EVENT }; -static float m_afSecondNagaCoord[3][3] = +struct firstWaveLocations +{ + uint32 uiEntry; + float fX, fY, fZ; +}; +// First Wave Data +static const firstWaveLocations nagaLocations[3] = { - {3609.925537f, 1168.759521f, -1.168f}, // witch - {3645.652100f, 1139.425415f, 1.322f}, // priest - {3583.602051f, 1128.405762f, 2.347f} // myrmidon + { NPC_WRATH_RAZORTAIL, 3629.9194f, 1169.9987f, -3.4472558f}, + { NPC_WRATH_RIDER, 3617.8516f, 1097.7166f, -4.0877485f}, + { NPC_WRATH_SORCERESS, 3583.1497f, 1165.5658f, -5.3660164f} }; -static float m_fVorshaCoord[] = {3633.056885f, 1172.924072f, -5.388f}; +// 2nd Wave Data +struct secondWaveLocations +{ + uint32 uiEntry; + float fX, fY, fZ; +}; +static const secondWaveLocations secondnagaLocations[3] = +{ + { NPC_WRATH_MYRMIDON, 3575.009f, 1119.8704f, -4.2547455f}, + { NPC_WRATH_SEAWITCH, 3606.9448f, 1176.3822f, -2.9632108f}, + { NPC_WRATH_PRIESTESS, 3651.5383f, 1155.5522f, -3.9628646f} +}; struct npc_muglashAI : public npc_escortAI { npc_muglashAI(Creature* pCreature) : npc_escortAI(pCreature) { - m_uiWaveId = 0; - m_bIsBrazierExtinguished = false; Reset(); + AddCustomAction(MUGLASH_FAIL, true, [&]() { DoFailEscort(); }, TIMER_COMBAT_OOC); + AddCustomAction(MUGLASH_EVENT, true, [&]() { DoStartEvent(); }, TIMER_ALWAYS); + m_uiEventId = 0; } - bool m_bIsBrazierExtinguished; - - uint32 m_uiWaveId; - uint32 m_uiEventTimer; + uint32 m_uiEventId; + uint8 m_uiWaveOneAlive; + uint8 m_uiWaveTwoAlive; + bool m_Wave; void Reset() override { - m_uiEventTimer = 10000; - if (!HasEscortState(STATE_ESCORT_ESCORTING)) { - m_uiWaveId = 0; - m_bIsBrazierExtinguished = false; + m_uiEventId = 0; + m_uiWaveOneAlive = 0; + m_uiWaveTwoAlive = 0; } } @@ -112,8 +138,8 @@ struct npc_muglashAI : public npc_escortAI if (urand(0, 1)) return; - if (Player* pPlayer = GetPlayerForEscort()) - DoScriptText(SAY_MUG_ON_GUARD, m_creature, pPlayer); + if (Player* player = GetPlayerForEscort()) + DoBroadcastText(SAY_MUGLASH_AGGRO, m_creature, player); } } @@ -121,101 +147,218 @@ struct npc_muglashAI : public npc_escortAI { switch (uiPointId) { - case 1: - if (Player* pPlayer = GetPlayerForEscort()) - DoScriptText(SAY_MUG_START2, m_creature, pPlayer); + case 3: + if (Player* player = GetPlayerForEscort()) + { + DoBroadcastText(SAY_MUGLASH_START, m_creature, player); + m_creature->HandleEmote(EMOTE_ONESHOT_TALK); + } break; - case 25: - if (Player* pPlayer = GetPlayerForEscort()) - DoScriptText(SAY_MUG_BRAZIER, m_creature, pPlayer); - - if (GameObject* pGo = GetClosestGameObjectWithEntry(m_creature, GO_NAGA_BRAZIER, INTERACTION_DISTANCE * 2)) + case 9: + // Before entering Water ignore mmaps to get better pathing + m_creature->SetIgnoreMMAP(true); + break; + case 15: + // First point after Water + m_creature->SetIgnoreMMAP(false); + break; + case 18: + // Last waypoint Reached + if (Player* player = GetPlayerForEscort()) { - // some kind of event flag? Update to player/group only? - pGo->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); - SetEscortPaused(true); + DoBroadcastText(SAY_MUGLASH_BRAZIER, m_creature, player); + m_creature->HandleEmote(EMOTE_ONESHOT_TALK); } + // Let Escort fail after 5 minutes if players dont use Naga Brazier object + ResetTimer(MUGLASH_FAIL, 300000); break; - case 26: - DoScriptText(SAY_MUG_GRATITUDE, m_creature); - - if (Player* pPlayer = GetPlayerForEscort()) - pPlayer->RewardPlayerAndGroupAtEventExplored(QUEST_VORSHA, m_creature); + case 19: + // Using custom point to get a 2 seconds delay after last text + // Make Naga Brazier object usable + if (GameObject* go = GetClosestGameObjectWithEntry(m_creature, GO_NAGA_BRAZIER, INTERACTION_DISTANCE * 2)) + { + go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); + } + // Stop waypoints at this point + SetEscortPaused(true); break; - case 27: - DoScriptText(SAY_MUG_PATROL, m_creature); + case 20: + // First Wave spawned disable waypoints for now + SetEscortPaused(true); break; - case 28: - DoScriptText(SAY_MUG_RETURN, m_creature); + case 21: + SetEscortPaused(true); + ResetTimer(MUGLASH_EVENT, 2000); + m_uiEventId = 4; break; } } - void DoWaveSummon() + void JustSummoned(Creature* summoned) override { - switch (m_uiWaveId) + // Ignore mmap so they can get out of water without strange movement + summoned->SetIgnoreMMAP(true); + summoned->GetMotionMaster()->MovePath(1); + + switch (summoned->GetEntry()) { - case 1: - m_creature->SummonCreature(NPC_WRATH_RIDER, m_afFirstNagaCoord[0][0], m_afFirstNagaCoord[0][1], m_afFirstNagaCoord[0][2], 0.0f, TEMPSPAWN_TIMED_OOC_DESPAWN, 60000); - m_creature->SummonCreature(NPC_WRATH_SORCERESS, m_afFirstNagaCoord[1][0], m_afFirstNagaCoord[1][1], m_afFirstNagaCoord[1][2], 0.0f, TEMPSPAWN_TIMED_OOC_DESPAWN, 60000); - m_creature->SummonCreature(NPC_WRATH_RAZORTAIL, m_afFirstNagaCoord[2][0], m_afFirstNagaCoord[2][1], m_afFirstNagaCoord[2][2], 0.0f, TEMPSPAWN_TIMED_OOC_DESPAWN, 60000); + case NPC_WRATH_RAZORTAIL: + case NPC_WRATH_RIDER: + case NPC_WRATH_SORCERESS: + ++m_uiWaveOneAlive; break; - case 2: - m_creature->SummonCreature(NPC_WRATH_PRIESTESS, m_afSecondNagaCoord[0][0], m_afSecondNagaCoord[0][1], m_afSecondNagaCoord[0][2], 0.0f, TEMPSPAWN_TIMED_OOC_DESPAWN, 60000); - m_creature->SummonCreature(NPC_WRATH_MYRMIDON, m_afSecondNagaCoord[1][0], m_afSecondNagaCoord[1][1], m_afSecondNagaCoord[1][2], 0.0f, TEMPSPAWN_TIMED_OOC_DESPAWN, 60000); - m_creature->SummonCreature(NPC_WRATH_SEAWITCH, m_afSecondNagaCoord[2][0], m_afSecondNagaCoord[2][1], m_afSecondNagaCoord[2][2], 0.0f, TEMPSPAWN_TIMED_OOC_DESPAWN, 60000); + case NPC_WRATH_MYRMIDON: + case NPC_WRATH_SEAWITCH: + case NPC_WRATH_PRIESTESS: + ++m_uiWaveTwoAlive; break; - case 3: - m_creature->SummonCreature(NPC_VORSHA, m_fVorshaCoord[0], m_fVorshaCoord[1], m_fVorshaCoord[2], 0.0f, TEMPSPAWN_TIMED_OOC_DESPAWN, 60000); + } + } + + void SummonedCreatureJustDied(Creature* summoned) override + { + switch (summoned->GetEntry()) + { + // First Wave + case NPC_WRATH_RAZORTAIL: + case NPC_WRATH_RIDER: + case NPC_WRATH_SORCERESS: + --m_uiWaveOneAlive; + // Continue Event if all are dead and spawn 2nd wave already + if (m_uiWaveOneAlive == 0) + { + for (auto& i : secondnagaLocations) + m_creature->SummonCreature(i.uiEntry, i.fX, i.fY, i.fZ, 0.0f, TEMPSPAWN_TIMED_OOC_DESPAWN, 60000, true, true); + m_uiEventId = 2; + ResetTimer(MUGLASH_EVENT, 5000); + } break; - case 4: - SetEscortPaused(false); - DoScriptText(SAY_MUG_DONE, m_creature); + case NPC_WRATH_MYRMIDON: + case NPC_WRATH_SEAWITCH: + case NPC_WRATH_PRIESTESS: + --m_uiWaveTwoAlive; + // If 2nd Wave is Dead go to next waypoint and spawn Vorsha + if (m_uiWaveTwoAlive == 0) + { + m_creature->SummonCreature(NPC_VORSHA, 3630.2092f, 1190.3536f, -16.624332f, 0.0f, TEMPSPAWN_TIMED_OOC_DESPAWN, 60000, true, false); + SetEscortPaused(false); // go to next waypoint + } break; + case NPC_VORSHA: + ResetTimer(MUGLASH_EVENT, 2000); + m_uiEventId = 6; + break; + } } - void JustSummoned(Creature* pSummoned) override + // Failed cause players didnt use Naga Brazier object + void DoFailEscort() { - pSummoned->AI()->AttackStart(m_creature); + if (Player* player = GetPlayerForEscort()) + { + DoBroadcastText(SAY_MUGLASH_FAIL, m_creature, player); + m_creature->HandleEmote(EMOTE_ONESHOT_TALK); + } + // Make Object not interactable when it quest failed + if (GameObject* go = GetClosestGameObjectWithEntry(m_creature, GO_NAGA_BRAZIER, INTERACTION_DISTANCE * 2)) + { + go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); + } + m_creature->ForcedDespawn(1000); } - void UpdateEscortAI(const uint32 uiDiff) override - { - if (!m_creature->SelectHostileTarget() || !m_creature->GetVictim()) + // When Player activates object start Event + void DoStartEvent() + { + switch(m_uiEventId) { - if (HasEscortState(STATE_ESCORT_PAUSED) && m_bIsBrazierExtinguished) - { - if (m_uiEventTimer < uiDiff) + case 0: + // Disable Fail timer, player used object + DisableTimer(MUGLASH_FAIL); + ++m_uiEventId; + ResetTimer(MUGLASH_EVENT, 2000); + break; + case 1: + if (Player* player = GetPlayerForEscort()) + DoBroadcastText(SAY_MUGLASH_EVENT_01, m_creature, player); + // Summon first wave of adds + for (auto& i : nagaLocations) + m_creature->SummonCreature(i.uiEntry, i.fX, i.fY, i.fZ, 0.0f, TEMPSPAWN_TIMED_OOC_DESPAWN, 60000, true, true); + SetEscortPaused(false); // go to next waypoint + break; + case 2: + // First Wave is Dead rest now + DoBroadcastText(SAY_MUGLASH_EVENT_02, m_creature); + m_creature->SetStandState(UNIT_STAND_STATE_SIT); + ResetTimer(MUGLASH_EVENT, 9000); + ++m_uiEventId; + break; + case 3: + // 2nd wave comes to muglash + m_creature->SetStandState(UNIT_STAND_STATE_SIT); + ++m_uiEventId; + break; + case 4: + // 2nd wave is dead + DoBroadcastText(SAY_MUGLASH_EVENT_03, m_creature); + ++m_uiEventId; + ResetTimer(MUGLASH_EVENT, 3000); + break; + case 5: + m_creature->HandleEmote(EMOTE_ONESHOT_POINT); + DoBroadcastText(SAY_MUGLASH_EVENT_04, m_creature); + break; + case 6: + m_creature->HandleEmote(EMOTE_ONESHOT_CHEER); + if (Player* player = GetPlayerForEscort()) + DoBroadcastText(SAY_MUGLASH_SUCCESS, m_creature, player); + ++m_uiEventId; + ResetTimer(MUGLASH_EVENT, 8000); + break; + case 7: + if (Player* player = GetPlayerForEscort()) { - ++m_uiWaveId; - DoWaveSummon(); - m_uiEventTimer = 10000; + // Award quest credit + player->RewardPlayerAndGroupAtEventExplored(QUEST_VORSHA, m_creature); } - else - m_uiEventTimer -= uiDiff; - } - - return; + m_creature->HandleEmote(EMOTE_ONESHOT_BOW); + if (Player* player = GetPlayerForEscort()) + DoBroadcastText(SAY_MUGLASH_SUCCESS_02, m_creature, player); + ++m_uiEventId; + ResetTimer(MUGLASH_EVENT, 3000); + break; + case 8: + m_creature->HandleEmote(EMOTE_ONESHOT_TALK); + DoBroadcastText(SAY_MUGLASH_SUCCESS_03, m_creature); + ++m_uiEventId; + ResetTimer(MUGLASH_EVENT, 5000); + break; + case 9: + DoBroadcastText(SAY_MUGLASH_SUCCESS_04, m_creature); + ++m_uiEventId; + ResetTimer(MUGLASH_EVENT, 5000); + break; + case 10: + // Escort Finished, move random around point before despawning + m_creature->GetMotionMaster()->MoveRandomAroundPoint(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), 5.0f); + End(); + m_creature->ForcedDespawn(14000); // Despawn after 14 + break; } - - DoMeleeAttackIfReady(); } }; -bool QuestAccept_npc_muglash(Player* pPlayer, Creature* pCreature, const Quest* pQuest) +bool QuestAccept_npc_muglash(Player* player, Creature* creature, const Quest* quest) { - if (pQuest->GetQuestId() == QUEST_VORSHA) + if (quest->GetQuestId() == QUEST_VORSHA) { - if (npc_muglashAI* pEscortAI = dynamic_cast(pCreature->AI())) + if (npc_muglashAI* pEscortAI = dynamic_cast(creature->AI())) { - DoScriptText(SAY_MUG_START1, pCreature); - pCreature->SetFactionTemporary(FACTION_ESCORT_H_PASSIVE, TEMPFACTION_RESTORE_RESPAWN | TEMPFACTION_TOGGLE_IMMUNE_TO_NPC); - - pEscortAI->Start(false, pPlayer, pQuest); + creature->SetFactionTemporary(FACTION_ESCORT_H_NEUTRAL_PASSIVE, TEMPFACTION_RESTORE_RESPAWN); + pEscortAI->Start(false, player, quest, false, false, MUGLASH_ESCORT_PATH); } } - return true; } @@ -224,19 +367,21 @@ UnitAI* GetAI_npc_muglash(Creature* pCreature) return new npc_muglashAI(pCreature); } -bool GOUse_go_naga_brazier(Player* /*pPlayer*/, GameObject* pGo) +bool GOUse_go_naga_brazier(Player* /*pPlayer*/, GameObject* go) { - if (Creature* pCreature = GetClosestCreatureWithEntry(pGo, NPC_MUGLASH, INTERACTION_DISTANCE * 2)) + // When player finishs cast inform npc muglash + if (Creature* creature = GetClosestCreatureWithEntry(go, NPC_MUGLASH, INTERACTION_DISTANCE * 2)) { - if (npc_muglashAI* pEscortAI = dynamic_cast(pCreature->AI())) + if (npc_muglashAI* pEscortAI = dynamic_cast(creature->AI())) { - DoScriptText(SAY_MUG_BRAZIER_WAIT, pCreature); - - pEscortAI->m_bIsBrazierExtinguished = true; + // Start Event with 2 seconds delay + pEscortAI->DoStartEvent(); return false; } } - + // Make Object not interactable again and remove flames visual + go->SetGoState(GO_STATE_READY); + go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT); return true; }