From a9f2fde270e4153c2e6479665368933dd924e410 Mon Sep 17 00:00:00 2001 From: BlaMacfly Date: Fri, 4 Sep 2026 23:54:16 +0200 Subject: [PATCH] Rivage brise : la mort de Tirion, et les renforts qui tombaient sur le joueur MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SIGNALE EN JEU : « p7 c'est Krosus qui plonge Tirion dans le fiel normalement, et la pas de script de scenario ». Le script se contentait d'invoquer Krosus douze secondes apres avoir pose Tirion agenouille. La sequence officielle est relevee sur Warcraft Wiki, et ses huit repliques existent dans nos donnees avec leur BroadcastTextId ET leur Sound -- de 99237 a 99247. Elle est desormais jouee en trente-trois secondes : Tirion comprend le piege, Gul'dan lui repond depuis le tombeau, Krosus surgit de la lave, Gul'dan ordonne, Krosus souffle, Tirion sombre, le chef de faction riposte, Gul'dan raille puis lance l'assaut. Krosus n'est attaquable qu'a ce dernier signal. Gul'dan est invoque des cette scene, au sommet du tombeau, et y reste jusqu'a la fin -- c'est de la qu'il domine le champ de bataille. La finale le reutilise au lieu d'en invoquer un second. RENFORTS DE LA CITE : « en phase 6 j'ai des invocations de demon sur ma tronche ». Ils naissaient au point de ralliement, c'est-a-dire au milieu du combat. Ils arrivent desormais de la peripherie, sur un cercle de 45 a 60 metres dont l'orientation change a chaque vague, puis chargent. Ces vagues restent une addition de ma part, pas une donnee du jeu : la cite ne compte que 273 points de defenseurs pour une barre qui en demande 300. Si la correspondance des poids se revele fausse, elles n'auront plus lieu d'etre. Co-Authored-By: Claude Opus 5 --- sql/sylvania/mort_tirion.sql | 36 ++++ .../Scenario/scenario_broken_shore_intro.cpp | 161 +++++++++++++++++- 2 files changed, 191 insertions(+), 6 deletions(-) create mode 100644 sql/sylvania/mort_tirion.sql diff --git a/sql/sylvania/mort_tirion.sql b/sql/sylvania/mort_tirion.sql new file mode 100644 index 0000000..779e534 --- /dev/null +++ b/sql/sylvania/mort_tirion.sql @@ -0,0 +1,36 @@ +-- ===================================================================== +-- Rivage brisé — la mort de Tirion, mise en scène +-- +-- SIGNALÉ EN JEU : « p7 c'est Krosus qui plonge Tirion dans le fiel +-- normalement, et là pas de script de scénario ». +-- +-- Séquence officielle, relevée sur Warcraft Wiki : +-- Tirion « Stay back... it's a trap... the Light will protect me... » +-- Gul'dan « Ha, you fool! You stand before the temple of a GOD... » +-- Krosus surgit de la lave. +-- Gul'dan « Destroy him. » +-- Krosus souffle sur Tirion. +-- Tirion « The Light... will... ahh! Aahhhh!! » puis il sombre. +-- Thrall « Fordring! » +-- Gul'dan « All you have worked for... » puis « Destroy them! » +-- +-- Les huit répliques portent leur BroadcastTextId et leur Sound +-- d'origine : le client jouera la voix française et affichera son +-- propre texte. Le texte anglais porté ici n'est qu'un repère. +-- +-- Groupes 20 et au-delà, pour ne rien écraser. +-- ===================================================================== + +DELETE FROM `creature_text` WHERE `GroupID` BETWEEN 20 AND 29 + AND `CreatureID` IN (90367, 90413, 90711, 90713); + +INSERT INTO `creature_text` + (`CreatureID`,`GroupID`,`ID`,`Text`,`Type`,`Language`,`Probability`,`Emote`,`Duration`,`Sound`,`BroadcastTextId`,`TextRange`,`comment`) VALUES + (90367,20,0,'Stay back... it''s a trap... the Light will protect me...',14,0,100,0,0,53452,99237,0,'mort de Tirion 1'), + (90367,21,0,'The Light... will... ahh! Aahhhh!!',14,0,100,0,0,53455,99240,0,'mort de Tirion 5'), + (90413,20,0,'Ha, you fool! You stand before the temple of a GOD. Your pitiful Light cannot reach you here.',14,0,100,0,0,53453,99238,0,'mort de Tirion 2'), + (90413,21,0,'Destroy him.',14,0,100,0,0,53454,99239,0,'mort de Tirion 4'), + (90413,22,0,'All you have worked for, all you have sacrificed, just to see your champions fall to ash one by one.',14,0,100,0,0,53458,99243,0,'mort de Tirion 7'), + (90413,23,0,'Destroy them!',14,0,100,0,0,53462,99247,0,'mort de Tirion 8'), + (90711,20,0,'Fordring!',14,0,100,0,0,53456,99241,0,'mort de Tirion 6'), + (90713,20,0,'We will never give in to hopelessness!',14,0,100,0,0,53459,99244,0,'mort de Tirion, riposte'); diff --git a/src/server/scripts/BrokenIsles/Scenario/scenario_broken_shore_intro.cpp b/src/server/scripts/BrokenIsles/Scenario/scenario_broken_shore_intro.cpp index 09c224c..f37b910 100644 --- a/src/server/scripts/BrokenIsles/Scenario/scenario_broken_shore_intro.cpp +++ b/src/server/scripts/BrokenIsles/Scenario/scenario_broken_shore_intro.cpp @@ -562,8 +562,13 @@ struct scenario_broken_shore_intro : public InstanceScript // Des vagues continuent d'affluer tant que la cite tient : // sans cela la barre ne pourrait pas se remplir, la zone ne // comptant pas assez de defenseurs pour ses 300 points. + // + // SIGNALE EN JEU : « en phase 6 j'ai des invocations de + // demon sur ma tronche ». Elles naissaient au point de + // ralliement, c'est-a-dire au milieu du combat. Elles + // arrivent desormais de la peripherie et chargent. if ((cityKills % 6) == 0) - SummonWave(Anchors().city, 5); + SummonWaveLoin(); // FILET DE SECURITE, pas un mecanisme. Si la barre restait // bloquee pour une raison qui nous echappe, le joueur ne @@ -585,6 +590,34 @@ struct scenario_broken_shore_intro : public InstanceScript } } + // Renforts de la cite : ils surgissent en peripherie, a une + // cinquantaine de metres, sur un cercle dont l'orientation change a + // chaque vague -- puis ils chargent. Aucun demon ne se materialise + // dans le dos du joueur. + void SummonWaveLoin() + { + static uint32 const demons[5] = + { NPC_CHAOS_MINION, NPC_FELBLOOD_PACKHOUND, NPC_FELBLADE_DESTROYER, + NPC_EREDAR_SUMMONER, NPC_INFERNAL_DESTROYER }; + + FactionAnchors const& a = Anchors(); + float const depart = frand(0.0f, float(M_PI) * 2.0f); + + for (uint8 i = 0; i < 5; ++i) + { + float const angle = depart + float(i) * (float(M_PI) * 2.0f / 5.0f); + float const rayon = frand(45.0f, 60.0f); + + if (TempSummon* demon = SummonAt(demons[i], a.city, + std::cos(angle) * rayon, + std::sin(angle) * rayon)) + { + demon->SetReactState(REACT_AGGRESSIVE); + demon->SetInCombatWithZone(); + } + } + } + void StartFindLeader() { FactionAnchors const& a = Anchors(); @@ -687,22 +720,137 @@ struct scenario_broken_shore_intro : public InstanceScript DoSendEventScenario(EVENT_TIRION_REACHED); stage = STAGE_KROSUS; - tirion->DespawnOrUnsummon(20000); + SceneMortTirion(); + }); + } + // ================================================================= + // SylvaniaCore : la mort de Tirion, mise en scene. + // + // SIGNALE EN JEU : « p7 c'est Krosus qui plonge Tirion dans le fiel + // normalement, et la pas de script de scenario ». Le script se + // contentait d'invoquer Krosus douze secondes plus tard. + // + // Sequence officielle, relevee sur Warcraft Wiki : + // Tirion « Stay back... it's a trap... » + // Gul'dan « Ha, you fool! You stand before the temple of a GOD... » + // Krosus surgit de la lave. + // Gul'dan « Destroy him. » + // Krosus souffle sur Tirion, qui sombre sous la lave. + // Thrall « Fordring! » + // Gul'dan « All you have worked for... » puis « Destroy them! » + // + // Les huit repliques portent leur BroadcastTextId et leur Sound + // d'origine : le client joue la voix et affiche sa propre langue. + // + // Gul'dan est invoque des maintenant, au sommet du tombeau. Il y + // domine toute la fin du scenario -- c'est de la qu'il parle, et la + // finale le reutilise au lieu d'en invoquer un second. + // ================================================================= + void SceneMortTirion() + { + FactionAnchors const& a = Anchors(); + + if (Creature* guldan = Summon(NPC_GULDAN, a.tomb)) + { + guldanGUID = guldan->GetGUID(); + guldan->SetReactState(REACT_PASSIVE); + guldan->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC | UNIT_FLAG_IMMUNE_TO_PC); + } + + auto dire = [this](ObjectGuid const& guid, uint8 groupe) + { + if (Creature* qui = instance->GetCreature(guid)) + qui->AI()->Talk(groupe); + }; + + // 0 s -- Tirion comprend le piege + dire(tirionGUID, 20); + + scheduler.Schedule(Seconds(5), [this, dire](TaskContext /*c*/) + { + dire(guldanGUID, 20); // « Ha, you fool!... » + }); + + scheduler.Schedule(Seconds(11), [this](TaskContext /*c*/) + { + // Krosus surgit de la lave, encore passif if (Creature* krosus = Summon(NPC_KROSUS, Anchors().crevasse)) + { + krosusGUID = krosus->GetGUID(); + krosus->SetReactState(REACT_PASSIVE); + krosus->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC | UNIT_FLAG_IMMUNE_TO_PC); + } + }); + + scheduler.Schedule(Seconds(14), [this, dire](TaskContext /*c*/) + { + dire(guldanGUID, 21); // « Destroy him. » + }); + + scheduler.Schedule(Seconds(17), [this, dire](TaskContext /*c*/) + { + // Le souffle de Krosus emporte Tirion + Creature* krosus = instance->GetCreature(krosusGUID); + Creature* tirion = instance->GetCreature(tirionGUID); + if (krosus && tirion) + krosus->SetFacingToObject(tirion); + + dire(tirionGUID, 21); // « The Light... ahh! » + }); + + scheduler.Schedule(Seconds(20), [this](TaskContext /*c*/) + { + // Il sombre sous la lave + if (Creature* tirion = instance->GetCreature(tirionGUID)) + { + tirion->SetStandState(UNIT_STAND_STATE_DEAD); + tirion->DespawnOrUnsummon(4000); + } + }); + + scheduler.Schedule(Seconds(23), [this, dire](TaskContext /*c*/) + { + dire(leaderGUID, 20); // riposte du chef + DoOnPlayers([](Player* /*player*/) { }); + }); + + scheduler.Schedule(Seconds(27), [this, dire](TaskContext /*c*/) + { + dire(guldanGUID, 22); // « All you have worked for... » + }); + + scheduler.Schedule(Seconds(33), [this, dire](TaskContext /*c*/) + { + dire(guldanGUID, 23); // « Destroy them! » + + if (Creature* krosus = instance->GetCreature(krosusGUID)) + { + krosus->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC | UNIT_FLAG_IMMUNE_TO_PC); + krosus->SetReactState(REACT_AGGRESSIVE); krosus->SetInCombatWithZone(); + } }); } void StartFinale() { FactionAnchors const& a = Anchors(); - if (Creature* guldan = Summon(NPC_GULDAN, a.tomb)) + + // Gul'dan est deja au sommet du tombeau depuis la mort de + // Tirion : on ne l'invoque une seconde fois que s'il a disparu. + Creature* guldan = instance->GetCreature(guldanGUID); + if (!guldan) { - guldanGUID = guldan->GetGUID(); - guldan->SetReactState(REACT_PASSIVE); - guldan->AI()->Talk(0); + guldan = Summon(NPC_GULDAN, a.tomb); + if (guldan) + { + guldanGUID = guldan->GetGUID(); + guldan->SetReactState(REACT_PASSIVE); + } } + if (guldan) + guldan->AI()->Talk(0); SummonWave(a.tomb, 4); scheduler.Schedule(Seconds(20), [this](TaskContext /*context*/) { @@ -761,6 +909,7 @@ private: ObjectGuid placedVarianGUID; ObjectGuid placedVoljinGUID; ObjectGuid tirionGUID; + ObjectGuid krosusGUID; ObjectGuid guldanGUID; TaskScheduler scheduler; };