fix(DB/SAI): Correct Frostmourne Cavern text and RP progression(#27522)

This commit is contained in:
llupa
2026-09-08 15:38:16 -03:00
committed by GitHub
parent db533ad753
commit b0796ebda4
3 changed files with 199 additions and 0 deletions
@@ -0,0 +1,55 @@
--
-- Quest 12478 "Frostmourne Cavern": Arthas (27455) spoke his opening line before he was
-- visible, his replies overtook their cues, he repeated his last line, and Muradin (27480)
-- vanished on the spot instead of leaving. Retimed against the quest cinematic.
--
DELETE FROM `smart_scripts` WHERE (`source_type` = 9) AND (`entryorguid` = 2745500);
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
(2745500,9,0,0,0,0,100,0,7000,7000,0,0,0,0,47,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,'Script9 - Set Visible'),
(2745500,9,1,0,0,0,100,0,0,0,0,0,0,0,118,0,0,0,0,0,0,15,190332,20,0,0,0,0,0,0,'Script9 - Set GO State'),
(2745500,9,2,0,0,0,100,0,0,0,0,0,0,0,12,27480,8,0,0,0,0,8,0,0,0,0,4816.75,-580.34,162.99,5.37,'Script9 - Summon Creature'),
(2745500,9,3,0,0,0,100,0,2000,2000,0,0,0,0,1,4,0,0,0,0,0,1,0,0,0,0,0,0,0,0,'Script9 - Talk'),
(2745500,9,4,0,0,0,100,0,40000,40000,0,0,0,0,1,5,0,0,0,0,0,1,0,0,0,0,0,0,0,0,'Script9 - Talk'),
(2745500,9,5,0,0,0,100,0,13000,13000,0,0,0,0,1,6,0,0,0,0,0,1,0,0,0,0,0,0,0,0,'Script9 - Talk'),
(2745500,9,6,0,0,0,100,0,8000,8000,0,0,0,0,1,7,0,0,0,0,0,1,0,0,0,0,0,0,0,0,'Script9 - Talk'),
(2745500,9,8,0,0,0,100,0,0,0,0,0,0,0,69,0,0,0,0,0,0,8,0,0,0,0,4820.36,-582.3,163.8,4,'Script9 - Move Point'),
(2745500,9,9,0,0,0,100,0,5000,5000,0,0,0,0,11,49824,0,0,0,0,0,1,0,0,0,0,0,0,0,0,'Script9 - Cast Spell'),
(2745500,9,10,0,0,0,100,0,11000,11000,0,0,0,0,118,1,0,0,0,0,0,15,190332,20,0,0,0,0,0,0,'Script9 - Set GO State'),
(2745500,9,11,0,0,0,100,0,0,0,0,0,0,0,71,0,1,36942,0,0,0,1,0,0,0,0,0,0,0,0,'Script9 - Set Equip'),
(2745500,9,12,0,0,0,100,0,500,500,0,0,0,0,5,25,0,0,0,0,0,1,0,0,0,0,0,0,0,0,'Script9 - Play Emote'),
(2745500,9,13,0,0,0,100,0,0,0,0,0,0,0,59,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,'Script9 - Set Run'),
(2745500,9,14,0,0,0,100,0,4000,4000,0,0,0,0,69,0,0,0,0,0,0,8,0,0,0,0,4809.08,-574.8,160.91,2.9,'Script9 - Move Point'),
(2745500,9,15,0,0,0,100,0,4000,4000,0,0,0,0,5,15,0,0,0,0,0,1,0,0,0,0,0,0,0,0,'Script9 - Play Emote'),
(2745500,9,16,0,0,0,100,0,4000,4000,0,0,0,0,69,0,0,0,0,0,0,8,0,0,0,0,4767,-567,163,3,'Script9 - Move Point'),
(2745500,9,17,0,0,0,100,0,7000,7000,0,0,0,0,41,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,'Script9 - Despawn');
DELETE FROM `smart_scripts` WHERE (`source_type` = 9) AND (`entryorguid` = 2748000);
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
(2748000,9,0,0,0,0,100,0,8000,8000,0,0,0,0,69,0,0,0,0,0,0,8,0,0,0,0,4818.63,-582.84,163.54,5.2,'Script9 - Move Point'),
(2748000,9,1,0,0,0,100,0,5000,5000,0,0,0,0,1,2,0,0,0,0,0,1,0,0,0,0,0,0,0,0,'Script9 - Talk'),
(2748000,9,2,0,0,0,100,0,0,0,0,0,0,0,11,68442,0,0,0,0,0,1,0,0,0,0,0,0,0,0,'Script9 - Cast Spell'),
(2748000,9,3,0,0,0,100,0,16000,16000,0,0,0,0,28,68442,0,0,0,0,0,1,0,0,0,0,0,0,0,0,'Script9 - Remove Aura'),
(2748000,9,4,0,0,0,100,0,0,0,0,0,0,0,66,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0.7,'Script9 - Set Orientation'),
(2748000,9,5,0,0,0,100,0,5000,5000,0,0,0,0,5,5,0,0,0,0,0,1,0,0,0,0,0,0,0,0,'Script9 - Play Emote'),
(2748000,9,6,0,0,0,100,0,2000,2000,0,0,0,0,69,0,0,0,0,0,0,8,0,0,0,0,4816.75,-580.34,162.99,5.37,'Script9 - Move Point'),
(2748000,9,7,0,0,0,100,0,2000,2000,0,0,0,0,66,0,0,0,0,0,0,8,0,0,0,0,0,0,0,6.13,'Script9 - Set Orientation'),
(2748000,9,8,0,0,0,100,0,9000,9000,0,0,0,0,1,3,0,0,0,0,0,1,0,0,0,0,0,0,0,0,'Script9 - Talk'),
(2748000,9,9,0,0,0,100,0,32000,32000,0,0,0,0,40,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,'Muradin - On Script - Set Sheath Unarmed'),
(2748000,9,10,0,0,0,100,0,0,0,0,0,0,0,90,7,0,0,0,0,0,1,0,0,0,0,0,0,0,0,'Muradin - On Script - Set Stand State Dead'),
(2748000,9,11,0,0,0,100,0,13000,13000,0,0,0,0,91,7,0,0,0,0,0,1,0,0,0,0,0,0,0,0,'Muradin - On Script - Remove Stand State Dead'),
(2748000,9,12,0,0,0,100,0,500,500,0,0,0,0,17,64,0,0,0,0,0,1,0,0,0,0,0,0,0,0,'Muradin - On Script - Set Emote State 64'),
(2748000,9,13,0,0,0,100,0,5000,5000,0,0,0,0,1,4,0,0,0,0,0,1,0,0,0,0,0,0,0,0,'Muradin - On Script - Say Line 4'),
(2748000,9,14,0,0,0,100,0,3000,3000,0,0,0,0,1,5,0,0,0,0,0,1,0,0,0,0,0,0,0,0,'Muradin - On Script - Say Line 5'),
(2748000,9,15,0,0,0,100,0,4000,4000,0,0,0,0,17,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,'Muradin - On Script - Set Emote State 0'),
(2748000,9,16,0,0,0,100,0,1000,1000,0,0,0,0,11,49829,3,0,0,0,0,1,0,0,0,0,0,0,0,0,'Muradin - On Script - Cast \'Frostmourne Cavern Quest Credit\''),
(2748000,9,17,0,0,0,100,0,0,0,0,0,0,0,59,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,'Muradin - On Script - Set Run'),
(2748000,9,18,0,0,0,100,0,0,0,0,0,0,0,69,0,0,0,0,0,0,8,0,0,0,0,4809.08,-574.8,160.91,2.9,'Muradin - On Script - Move Point'),
(2748000,9,19,0,0,0,100,0,1000,1000,0,0,0,0,69,0,0,0,0,0,0,8,0,0,0,0,4767,-567,163,3,'Muradin - On Script - Move Point'),
(2748000,9,20,0,0,0,100,0,7000,7000,0,0,0,0,41,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,'Muradin - On Script - Despawn');
DELETE FROM `smart_scripts` WHERE (`source_type` = 9) AND (`entryorguid` = 2748001);
DELETE FROM `waypoints` WHERE (`entry` = 27480);
-- Group 8 is a duplicate of group 7, unreferenced once the repeated line is gone.
DELETE FROM `creature_text_locale` WHERE (`CreatureID` = 27455) AND (`GroupID` = 8);
DELETE FROM `creature_text` WHERE (`CreatureID` = 27455) AND (`GroupID` = 8);
+9
View File
@@ -21,6 +21,14 @@ Authoring rules for new tests live in the harness:
1. Running AzerothCore **3.3.5a** authserver + worldserver.
2. MySQL with `acore_auth`, `acore_characters`, and `acore_world` (world DB is required for spawn cleanup and many fixtures).
3. Go **1.26+** and network reachability to auth (default `127.0.0.1:3724`).
4. `Warden.Enabled = 0` on the worldserver, until the harness bug below is fixed upstream.
Symptom: every login fails with `attempted to log in using invalid client OS ()`.
`WorldSocket::HandleAuthSession` reads `account.os` from the database and, when Warden is
active, rejects anything that is not `Win` or `OSX`. That column is written by the
*authserver* from the AUTH_LOGON_CHALLENGE FourCC, and AzerothGhost sends it leading-NUL
first (`client/auth.go`: `os := [4]byte{0, 'n', 'i', 'W'}`), so AC's `_os = os.data()`
builds an empty string and stores it. Docker stacks can set `AC_WARDEN_ENABLED=0` on the
worldserver service.
Accounts are created by the harness (GM level 3, password `test`). Do not reuse real player accounts.
@@ -150,6 +158,7 @@ If the scenario should stay as a regression, **move** it into `suites/` next to
| social/trade | item+gold accept; cancel; walk-OOR TARGET_TO_FAR | P1 | covered | #25723 |
| quests/lifecycle | STAY_ALIVE fail on death; status after save/relog | P1 | covered (`TestAC_26549_*`) | #26549 |
| quests/escort | find spawned unit; follow-NPC despawns on logout | P2 | covered (`TestAC_24450_*`) | #24450 |
| quests/frostmourne | scrying-orb vision runs; Muradin leaves the cavern and despawns; quest 12478 COMPLETE | P2 | covered (`TestAC_25760_*`); dialogue order and duplicate line `blocked-harness` (no monster-say capture) | #25760 |
| items/equip | visible-item slot after EquipEntry; additem; survives relog | P2 | covered | — |
| protocol/session | pos; item/quest load; money save/relog | P1 | covered; GM vis persist `blocked-harness` (extra_flags after relog) | #25793 |
| protocol/teleport | cross-map; named; GoCreatureID | P1 | covered | — |
@@ -0,0 +1,135 @@
//go:build e2e
package frostmourne_test
import (
"fmt"
"testing"
"time"
_ "github.com/go-sql-driver/mysql"
"github.com/azerothcore/AzerothGhost/e2e/e2eharness"
"github.com/azerothcore/azerothcore-wotlk/e2e/internal/meta"
)
// Issue: https://github.com/azerothcore/azerothcore-wotlk/issues/25760
//
// Quest 12478 "Frostmourne Cavern": Zelig's Scrying Orb (item 37933, spell 49817,
// spell_q12478_frostmourne_cavern) summons Prince Arthas (27455). His SmartAI
// actionlist 2745500 reveals him, summons Muradin (27480) and plays the vision;
// Muradin's list 2748000 ends by taking quest credit and leaving the cavern.
//
// The dialogue itself is monster say, which this harness cannot observe, so the
// line ordering and the removal of the duplicated line are not asserted here — see
// the gap noted in e2e/README.md. What this covers is the half with a
// protocol-visible oracle, and it is the half a single manual playthrough is worst
// at checking:
//
// - the vision starts at all, and Arthas summons Muradin;
// - Muradin leaves the cavern under his own movement instead of vanishing where
// he was knocked down, which is what the reworked ending added;
// - quest 12478 reaches COMPLETE, guarding the credit cast (spell 49829) that
// moved six and a half seconds later and now sits shortly before his despawn;
// - neither actor is leaked afterwards. Both are TEMPSUMMON_MANUAL_DESPAWN, so
// their only despawn is the last step of a long timed chain.
func TestAC_25760_FrostmourneCavernVisionCompletes(t *testing.T) {
meta.Begin(t, meta.TestMeta{
Tags: []string{"med", "quests", "ai", "issue", "serial"},
Runtime: "med",
Issue: 25760,
Category: "quests/frostmourne",
})
const (
questFrostmourneCavern = uint32(12478)
spellScryingOrb = uint32(49817)
npcArthas = uint32(27455)
npcMuradin = uint32(27480)
mapNorthrend = uint32(571)
)
const (
// Arthas's summon position, hardcoded in spell_q12478_frostmourne_cavern, so the
// bot stands exactly where he materialises and distances below start there.
orbX, orbY, orbZ = float32(4821.3), float32(-580.14), float32(163.541)
// Muradin is knocked down beside the dais; his exit ends ~56 yd away,
// mostly south with a westward drift.
// "Still loaded but no longer beside us" is what distinguishes leaving
// from despawning on the spot.
nearRadius = float32(30)
farRadius = float32(250)
)
bot := e2eharness.NewSolo(t, e2eharness.ScenarioOpts{Prefix: "Frost", Level: 80})
bot.AddQuest(t, questFrostmourneCavern)
bot.Teleport(t, orbX, orbY, orbZ, mapNorthrend)
// Leftovers from an earlier run would satisfy the presence checks below.
bot.DespawnNearbyEntry(t, npcArthas, farRadius)
bot.DespawnNearbyEntry(t, npcMuradin, farRadius)
// The orb's effect is SPELL_EFFECT_SEND_EVENT; casting it via GM avoids
// needing a real item-use packet.
bot.GM(t, fmt.Sprintf(".cast %d", spellScryingOrb))
arthas := bot.WaitUnit(t, npcArthas, 30*time.Second)
if arthas == 0 {
e2eharness.Preconditionf(t, "orb spell %d summoned no Arthas %d", spellScryingOrb, npcArthas)
}
muradin := bot.WaitUnit(t, npcMuradin, 30*time.Second)
if muradin == 0 {
e2eharness.Assertf(t, "Arthas %d never summoned Muradin %d", npcArthas, npcMuradin)
}
t.Logf("vision started arthas=0x%X muradin=0x%X", arthas, muradin)
// Muradin is knocked down at ~86s, back on his feet at ~99s, speaks at ~104s
// and ~107s, then takes credit and runs out at ~112s, despawning at ~120s.
// He is only loaded-but-distant for about four seconds of that, so poll well
// inside the window: the loop body is two in-memory object-cache lookups and
// is not rate limited.
var (
leftTheCavern bool
muradinGone bool
)
deadline := time.Now().Add(160 * time.Second)
for time.Now().Before(deadline) {
near := bot.FindUnit(npcMuradin, nearRadius)
far := bot.FindUnit(npcMuradin, farRadius)
if far != 0 && near == 0 {
leftTheCavern = true
}
if far == 0 && leftTheCavern {
muradinGone = true
break
}
time.Sleep(400 * time.Millisecond)
}
if !leftTheCavern {
e2eharness.Assertf(t,
"Muradin %d never moved away before despawning - the ending should walk him out of the cavern",
npcMuradin)
}
if !muradinGone {
e2eharness.Assertf(t,
"Muradin %d still loaded after the vision - TEMPSUMMON_MANUAL_DESPAWN summon was leaked",
npcMuradin)
}
if bot.FindUnit(npcArthas, farRadius) != 0 {
e2eharness.Assertf(t, "Arthas %d still loaded after the vision", npcArthas)
}
st, ok := bot.QuestStatusAfterSave(t, questFrostmourneCavern)
if !ok {
e2eharness.Assertf(t, "quest %d not in the character's log after the vision", questFrostmourneCavern)
}
if st != e2eharness.QuestStatusComplete {
e2eharness.Assertf(t,
"quest %d status %d, want %d COMPLETE - the credit cast did not land",
questFrostmourneCavern, st, e2eharness.QuestStatusComplete)
}
bot.AssertWorldAlive(t)
t.Logf("PASS vision completed, Muradin left and despawned, quest %d COMPLETE", questFrostmourneCavern)
}