From 82254cf6275cc92af46897d745ce9087a7612caa Mon Sep 17 00:00:00 2001 From: BlaMacfly Date: Fri, 4 Sep 2026 23:33:12 +0200 Subject: [PATCH] Rivage brise : les neuf etapes ont enfin leurs criteres officiels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Suite du parcours joue de bout en bout avec l'exploitant. ETAPE 6, LA BARRE RESTAIT A 0 %. Son arbre 42770 porte l'operateur 9, SUM_CHILDREN_WEIGHT : la barre vaut 300 points et chaque enfant y contribue selon son poids -- 44384 vaut 1, 53062 vaut 2, 53063 vaut 5, 53064 vaut 10. Le script n'envoyait aucun des quatre : il comptait dix morts dans son coin et forcait le passage, laissant la barre morte. Les demons ordinaires alimentent desormais le poids 2, les elites le poids 5, et des vagues affluent pour que la barre puisse se remplir -- la zone ne compte pas assez de defenseurs pour ses 300 points. LES CAGES DE LA LEGION ne comptaient pour rien : aucun critere ne les mentionne, et elles n'avaient aucun script. Signale en jeu, puis confirme par l'observation (« la barre bouge de 1 % »). Elles portent le quatrieme poids, le seul qui restait libre. Les 39 exemplaires sont rattaches a go_legion_cage. ETAPE 7, TIRION se validait par une minuterie de douze secondes, sans le joueur, et disparaissait au bout de vingt -- impossible a atteindre meme en courant. Meme defaut que « Trouver Varian ». Il faut desormais le rejoindre, il reste en place, et Krosus n'apparait qu'ensuite. ETAPES 8 ET 9 cablees dans la foulee : 44669 a la mort de Krosus, 44826 quand Gul'dan est arrete. Plus aucune etape ne se valide par forcage. DOUBLONS DE PLACEMENT : neuf creatures de la 1460 et trente-huit de la 1666 occupaient une position strictement identique a une autre, au centimetre pres. L'import n'est pas en cause -- la reference les porte deja en double, guids 294825 et 294827 pour l'entree 92564. Ecart assume avec elle, au benefice du rendu. RESERVE : la correspondance des quatre poids de l'etape 6 reste une deduction. La cite ne contient que deux categories d'ennemis la ou les poids en supposent quatre. A verifier en jeu, chiffres en main. Co-Authored-By: Claude Opus 5 --- sql/sylvania/rivage_doublons.sql | 33 ++++ .../Scenario/scenario_broken_shore_intro.cpp | 144 ++++++++++++++++-- 2 files changed, 168 insertions(+), 9 deletions(-) create mode 100644 sql/sylvania/rivage_doublons.sql diff --git a/sql/sylvania/rivage_doublons.sql b/sql/sylvania/rivage_doublons.sql new file mode 100644 index 0000000..c9c60ae --- /dev/null +++ b/sql/sylvania/rivage_doublons.sql @@ -0,0 +1,33 @@ +-- ===================================================================== +-- Rivage brisé — créatures posées deux fois au même endroit +-- +-- SIGNALÉ EN JEU : « il est spawn 2 fois au même endroit » (entrée +-- 92564, guid 290200360). +-- +-- Neuf créatures de la carte 1460 occupent une position strictement +-- identique à une autre — même entrée, mêmes coordonnées au centimètre. +-- En jeu, deux modèles se superposent exactement. +-- +-- L'IMPORT N'EST PAS EN CAUSE. La référence les porte déjà en double : +-- (294825,92564,1460,…,1254.48,2438.92,47.0961,…) +-- (294827,92564,1460,…,1254.48,2438.92,47.0961,…) +-- La transposition était fidèle ; c'est la donnée d'origine qui l'est +-- moins. Écart assumé avec la référence, au bénéfice du rendu. +-- +-- On conserve le plus petit guid de chaque paire. +-- ===================================================================== + +DELETE c FROM `creature` c + JOIN ( + SELECT `id`, ROUND(`position_x`,1) AS px, ROUND(`position_y`,1) AS py, + MIN(`guid`) AS garder + FROM `creature` + WHERE `map` IN (1460, 1666) + GROUP BY `id`, px, py + HAVING COUNT(*) > 1 + ) AS d + ON c.`id` = d.`id` + AND ROUND(c.`position_x`,1) = d.px + AND ROUND(c.`position_y`,1) = d.py + AND c.`guid` <> d.garder + WHERE c.`map` IN (1460, 1666); 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 7db2f4a..09c224c 100644 --- a/src/server/scripts/BrokenIsles/Scenario/scenario_broken_shore_intro.cpp +++ b/src/server/scripts/BrokenIsles/Scenario/scenario_broken_shore_intro.cpp @@ -125,6 +125,52 @@ enum BrokenShoreMisc EVENT_LEADER_FOUND = 45228, EVENT_ANCHOR_DESTROYED = 45288, + // ============================================================== + // Etape 6, « Raser la cite noire ». Son arbre 42770 porte + // l'operateur 9, CRITERIA_TREE_OPERATOR_SUM_CHILDREN_WEIGHT : la + // barre vaut 300 points et chaque enfant y contribue selon SON + // poids, releve dans les DB2 du build 7.3.5.26972 : + // + // asset 44384 poids 1 -> 0,33 % par activation + // asset 53062 poids 2 -> 0,67 % + // asset 53063 poids 5 -> 1,67 % + // asset 53064 poids 10 -> 3,33 % + // + // SIGNALE EN JEU : « la phase 6 ne progresse pas en tuant, la + // progression reste a 0 % ». Le script n'envoyait aucun de ces + // quatre evenements : il comptait dix morts dans son coin et + // forcait le passage, laissant la barre morte. + // + // DEDUCTION ASSUMEE, ET NON DONNEE : rien n'indique quel ennemi + // porte quel poids. La cite ne contient que DEUX categories -- + // 94 demons ordinaires et 17 elites -- la ou les poids en + // supposent quatre. On attribue donc le poids 2 aux ordinaires et + // le poids 5 aux elites, ce qui fait progresser la barre a + // proportion de la difficulte. Les poids 1 et 10 restent + // inemployes faute de savoir ce qu'ils designent. + // ============================================================== + EVENT_CITY_TRASH = 53062, // poids 2 + EVENT_CITY_ELITE = 53063, // poids 5 + + // Etapes 7 a 9, criteres releves dans les memes DB2 : + // etape 7 arbre 42772 critere 29715 asset 50027 x1 + // etape 8 arbre 43765 critere 28055 asset 44669 x1 + // etape 9 arbre 47225 critere 29714 asset 44826 x1 + // Le quatrieme poids de la barre de l'etape 6, longtemps inemploye. + // SIGNALE EN JEU : « les gameobject Legion Cage ne comptent pas », + // puis « oui la barre bouge de 1 % » -- les cages alimentent donc + // bien la barre. Le poids 1 est le seul des quatre qui restait + // libre, et il correspond a une action mineure : 1 point sur 300, + // soit 0,33 %, ce qui s'affiche comme 1 % des la deuxieme cage. + EVENT_CITY_CAGE = 44384, + GO_LEGION_CAGE = 240535, + GO_LEGION_CAGE_2 = 248819, + DATA_CAGE_OPENED = 9002, + + EVENT_TIRION_REACHED = 50027, + EVENT_KROSUS_SLAIN = 44669, + EVENT_GULDAN_STOPPED = 44826, + KILLS_CITY = 10, KILLS_FINALE = 8, ANCHORS_PORTAL = 4, // etait 2, valeur inventee @@ -379,7 +425,7 @@ struct scenario_broken_shore_intro : public InstanceScript case NPC_FELBLADE_DESTROYER: case NPC_EREDAR_SUMMONER: case NPC_INFERNAL_DESTROYER: - OnDemonDied(); + OnDemonDied(creature); break; // Les treize Seigneurs gangrebois places sur la carte. L'etape // en exige trois ; on les enumere explicitement plutot que de @@ -421,8 +467,8 @@ struct scenario_broken_shore_intro : public InstanceScript case NPC_KROSUS: if (stage == STAGE_KROSUS) { + DoSendEventScenario(EVENT_KROSUS_SLAIN); stage = STAGE_STOP_GULDAN; - CompleteStep(); StartFinale(); } break; @@ -447,7 +493,7 @@ struct scenario_broken_shore_intro : public InstanceScript // arrivent jamais ici : ils ont leurs propres criteres. // ===================================================== if (creature->GetCreatureTemplate()->type == CREATURE_TYPE_DEMON) - OnDemonDied(); + OnDemonDied(creature); break; } } @@ -457,6 +503,14 @@ struct scenario_broken_shore_intro : public InstanceScript // d'instance ne rapporte cette utilisation. void SetData(uint32 type, uint32 /*data*/) override { + if (type == DATA_CAGE_OPENED) + { + // Une cage ne vaut que pendant l'assaut de la cite. + if (stage == STAGE_RAZE_CITY) + DoSendEventScenario(EVENT_CITY_CAGE); + return; + } + if (type != DATA_SPIRE_USED || stage != STAGE_STORM_BEACH) return; @@ -489,7 +543,7 @@ struct scenario_broken_shore_intro : public InstanceScript } } - void OnDemonDied() + void OnDemonDied(Creature* mort) { switch (stage) { @@ -499,13 +553,29 @@ struct scenario_broken_shore_intro : public InstanceScript TryFinishBeach(); break; case STAGE_RAZE_CITY: - if (++cityKills >= KILLS_CITY) + { + // La barre officielle avance selon la valeur de l'ennemi. + bool const elite = mort && mort->GetCreatureTemplate()->rank > 0; + DoSendEventScenario(elite ? EVENT_CITY_ELITE : EVENT_CITY_TRASH); + ++cityKills; + + // 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. + if ((cityKills % 6) == 0) + SummonWave(Anchors().city, 5); + + // FILET DE SECURITE, pas un mecanisme. Si la barre restait + // bloquee pour une raison qui nous echappe, le joueur ne + // doit pas rester prisonnier de l'etape. + if (cityKills >= 90) { stage = STAGE_HIGHLORD; CompleteStep(); StartHighlord(); } break; + } case STAGE_STOP_GULDAN: if (++finaleKills >= KILLS_FINALE) FinishScenario(); @@ -570,17 +640,55 @@ struct scenario_broken_shore_intro : public InstanceScript void StartHighlord() { + // ============================================================= + // SylvaniaCore : l'etape s'intitule « Atteindre Tirion ». + // + // SIGNALE EN JEU : « la 7 c'est Tirion, il est passe + // automatiquement et ca me passe en 8 ». + // + // La minuterie de douze secondes validait l'etape SANS LE + // JOUEUR, et Tirion disparaissait au bout de vingt secondes -- + // impossible de l'atteindre meme en courant. Meme defaut que + // « Trouver Varian » : le script decidait a la place du joueur. + // + // On attend desormais qu'un joueur le rejoigne, et on alimente + // le critere officiel 50027. Tirion reste en place : il agonise + // dans la crevasse, il n'a aucune raison de s'evaporer. + // ============================================================= FactionAnchors const& a = Anchors(); if (Creature* tirion = Summon(NPC_TIRION, a.crevasse)) { + tirionGUID = tirion->GetGUID(); tirion->AI()->Talk(0); tirion->SetStandState(UNIT_STAND_STATE_KNEEL); - tirion->DespawnOrUnsummon(20000); } - scheduler.Schedule(Seconds(12), [this](TaskContext /*context*/) + + scheduler.Schedule(Seconds(2), [this](TaskContext context) { + if (stage != STAGE_HIGHLORD) + return; + + Creature* tirion = instance->GetCreature(tirionGUID); + if (!tirion) + return; + + bool atteint = false; + DoOnPlayers([&atteint, tirion](Player* player) + { + if (player->IsWithinDist(tirion, 25.0f, false)) + atteint = true; + }); + + if (!atteint) + { + context.Repeat(Seconds(2)); + return; + } + + DoSendEventScenario(EVENT_TIRION_REACHED); stage = STAGE_KROSUS; - CompleteStep(); + tirion->DespawnOrUnsummon(20000); + if (Creature* krosus = Summon(NPC_KROSUS, Anchors().crevasse)) krosus->SetInCombatWithZone(); }); @@ -608,7 +716,7 @@ struct scenario_broken_shore_intro : public InstanceScript void FinishScenario() { stage = STAGE_DONE; - CompleteStep(); + DoSendEventScenario(EVENT_GULDAN_STOPPED); if (Scenario* scenario = instance->GetInstanceScenario()) scenario->CompleteScenario(); @@ -652,6 +760,7 @@ private: ObjectGuid sylvanasGUID; ObjectGuid placedVarianGUID; ObjectGuid placedVoljinGUID; + ObjectGuid tirionGUID; ObjectGuid guldanGUID; TaskScheduler scheduler; }; @@ -660,6 +769,22 @@ private: // appelle sScriptMgr->OnGossipHello avant tout traitement specifique, ce // qui nous donne le seul point d'accroche disponible. On renvoie false // pour laisser le comportement normal se poursuivre. +// Les cages de la Legion, disseminees dans la cite. Les liberer fait +// avancer la barre de l'etape 6. +class go_legion_cage : public GameObjectScript +{ +public: + go_legion_cage() : GameObjectScript("go_legion_cage") { } + + bool OnGossipHello(Player* /*player*/, GameObject* go) override + { + if (InstanceScript* instance = go->GetInstanceScript()) + instance->SetData(DATA_CAGE_OPENED, 1); + + return false; // on laisse le comportement normal se poursuivre + } +}; + class go_spire_of_woe : public GameObjectScript { public: @@ -678,4 +803,5 @@ void AddSC_scenario_broken_shore_intro() { RegisterInstanceScript(scenario_broken_shore_intro, 1460); new go_spire_of_woe(); + new go_legion_cage(); }