mirror of
https://gitcode.com/GitHub_Trending/az/azerothcore-wotlk.git
synced 2026-10-10 07:06:38 +08:00
fix(DB/Quest): Summon Lord Kragaru from the Serpent Statue (#27611)
Co-authored-by: Aokromes <[email protected]> Co-authored-by: Dr-J <[email protected]> Co-authored-by: Gultask <[email protected]>
This commit is contained in:
co-authored by
Aokromes
Dr-J
Gultask
parent
c3e3d216bf
commit
83ad15d755
@@ -0,0 +1,21 @@
|
||||
--
|
||||
-- Quest 6027 'Book of the Ancients': using the Gem of the Serpent lights the Naga Beam but
|
||||
-- often summons nothing, leaving Lord Kragaru (12369) unreachable. The beam is a temporary
|
||||
-- gameobject whose lifetime is rounded to whole seconds, so it frequently expires before its
|
||||
-- own 3500ms summon timer fires, depending on when inside a second the player clicked.
|
||||
-- Drive the summon from the statue instead - a permanent spawn whose SmartAI cannot despawn.
|
||||
--
|
||||
DELETE FROM `smart_scripts` WHERE (`source_type` = 1 AND `entryorguid` IN (177673, 177705)) OR (`source_type` = 9 AND `entryorguid` = 17767300);
|
||||
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
|
||||
(177673, 1, 0, 1, 70, 0, 100, 0, 2, 0, 0, 0, 0, 0, 80, 17767300, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Serpent Statue - On Loot State Changed (Activated) - Call Timed Actionlist'),
|
||||
(177673, 1, 1, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 241, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Serpent Statue - On Link - Summon Gameobject Group 0 \'Naga Beam\''),
|
||||
(17767300, 9, 0, 0, 0, 0, 100, 0, 3500, 3500, 0, 0, 0, 0, 12, 12369, 1, 180000, 0, 0, 0, 8, 0, 0, 0, 0, 252.57, 2963.7, 1.72356, 1.29154, 'Serpent Statue - On Script - Summon Creature \'Lord Kragaru\'');
|
||||
|
||||
-- The beam is summoned through a gameobject summon group so that its sniffed rotation survives:
|
||||
-- SMART_ACTION_SUMMON_GO hands SummonGameObject an identity quaternion and cannot carry one.
|
||||
DELETE FROM `gameobject_summon_groups` WHERE (`summonerId` = 177673 AND `summonerType` = 1 AND `groupId` = 0);
|
||||
INSERT INTO `gameobject_summon_groups` (`summonerId`, `summonerType`, `groupId`, `entry`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `respawnTime`, `Comment`) VALUES
|
||||
(177673, 1, 0, 177705, 252.547, 2963.69, 1.64267, 5.58505, 0, 0, -0.34202, 0.939693, 4, 'Serpent Statue - Naga Beam');
|
||||
|
||||
-- The Naga Beam is purely cosmetic now; it carries no script.
|
||||
UPDATE `gameobject_template` SET `AIName` = '' WHERE (`entry` = 177705);
|
||||
@@ -157,6 +157,7 @@ go test -tags=e2e ./local/... -count=1 -v -timeout 30m -parallel 1
|
||||
| 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 |
|
||||
| quests/objectives | a mob that drops a quest item advertises it, so the client shows the objective on hover (`creature_questitem` -> `SMSG_CREATURE_QUERY_RESPONSE.questItems`) | P2 | covered (`TestAC_27553_*`), decoding the response through a raw packet hook since the harness has no dispatch case for it | #27553 |
|
||||
| quests/summons | using the Serpent Statue on Ranazjar Isle summons Lord Kragaru, the only source of the Book of the Ancients (quest 6027). Beam and summon are asserted separately so a failure names which script broke, and the activation is repeated because the regression it guards was probabilistic, not absolute | P2 | covered (`TestQuest6027_*`) | — |
|
||||
| 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,140 @@
|
||||
//go:build e2e
|
||||
|
||||
package summons_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"
|
||||
)
|
||||
|
||||
const (
|
||||
serpentStatue uint32 = 177673 // GO, type BUTTON, Ranazjar Isle
|
||||
serpentStatueGUID = 12609 // its single gameobject.guid spawn
|
||||
nagaBeam uint32 = 177705 // GO summoned by the statue, cosmetic
|
||||
lordKragaru uint32 = 12369 // drops Book of the Ancients (15803)
|
||||
|
||||
statueX float32 = 252.513
|
||||
statueY float32 = 2963.7
|
||||
statueZ float32 = 1.64204
|
||||
kalimdor uint32 = 1
|
||||
|
||||
// The statue summons the beam, then Lord Kragaru 3500ms later.
|
||||
summonWindow = 10 * time.Second
|
||||
|
||||
// Long enough for the gameobject to tick once and drop the finished action list.
|
||||
settleBetweenActivations = 500 * time.Millisecond
|
||||
|
||||
// One activation is not a regression test: the bug this guards against was
|
||||
// probabilistic (measured 4/16 on unfixed data), so a single success proves
|
||||
// nothing. Six consecutive successes put a regression under ~2%.
|
||||
activations = 6
|
||||
)
|
||||
|
||||
// Quest 6027 "Book of the Ancients" hands out a Gem of the Serpent to place on the
|
||||
// Serpent Statue on Ranazjar Isle. That must summon Lord Kragaru, who carries the
|
||||
// book; without him the quest cannot be completed.
|
||||
//
|
||||
// The summon used to hang off the Naga Beam, a gameobject the statue summons for
|
||||
// four seconds. SMART_ACTION_SUMMON_GO's despawn parameter is in whole seconds and
|
||||
// lands in GameObject::SetRespawnTime, which adds it to the second-granular
|
||||
// GameTime clock, so the beam's real lifetime was anywhere in (3.0s, 4.0s] and it
|
||||
// was frequently deleted before its own 3500ms summon timer fired.
|
||||
//
|
||||
// Both halves are asserted: the beam is the visual the player reports seeing, so
|
||||
// separating "beam appeared" from "Kragaru appeared" tells a failing run which of
|
||||
// the two scripts broke.
|
||||
func TestQuest6027_SerpentStatueSummonsKragaru(t *testing.T) {
|
||||
meta.Begin(t, meta.TestMeta{
|
||||
Tags: []string{"med", "quests", "serial"},
|
||||
Runtime: "med",
|
||||
Category: "quests/summons",
|
||||
})
|
||||
|
||||
bot := e2eharness.NewSolo(t, e2eharness.ScenarioOpts{Prefix: "Serp"})
|
||||
e2eharness.TeleportGo(t, bot.World, statueX, statueY+6, statueZ, kalimdor)
|
||||
|
||||
statue := bot.WaitGameObject(t, serpentStatue, 15*time.Second)
|
||||
|
||||
// Any use leaves the statue in GO_ACTIVATED for button.autoCloseTime (60s), and
|
||||
// UseDoorOrButton is a no-op until it resets — so a previous run, or a player who
|
||||
// just clicked it, would make the real click below silently do nothing.
|
||||
// .gobject activate forces GO_READY and re-uses it with a 10s autoclose instead,
|
||||
// which bounds the wait to that rather than a minute.
|
||||
e2eharness.MustGM(t, bot.World, fmt.Sprintf(".gobject activate %d", serpentStatueGUID))
|
||||
time.Sleep(12 * time.Second)
|
||||
|
||||
// Every successful summon is a new ObjectGuid. Counting distinct guids rather
|
||||
// than "is a Kragaru nearby" keeps earlier summons from satisfying later
|
||||
// activations — on unfixed data that would mask exactly the failures we hunt.
|
||||
seen := map[uint64]bool{}
|
||||
for _, u := range bot.World.GetNearbyUnits(100) {
|
||||
if u.Entry == lordKragaru {
|
||||
seen[u.GUID] = true
|
||||
}
|
||||
}
|
||||
|
||||
for i := 1; i <= activations; i++ {
|
||||
prevBeam := bot.World.FindGameObjectByEntry(nagaBeam, 0)
|
||||
|
||||
if i == 1 {
|
||||
// The player path: CMSG_GAMEOBJ_USE reaches GameObject::Use, which for a
|
||||
// BUTTON calls UseDoorOrButton -- the same call the gem's OpenLock effect
|
||||
// makes through Spell::SendLoot. Only the first activation can afford it:
|
||||
// it leaves the full 60s autoclose behind.
|
||||
bot.GameObjectUse(t, statue)
|
||||
} else {
|
||||
// Same UseDoorOrButton call, reached past that autoclose.
|
||||
e2eharness.MustGM(t, bot.World, fmt.Sprintf(".gobject activate %d", serpentStatueGUID))
|
||||
}
|
||||
|
||||
beam, summoned := uint64(0), uint64(0)
|
||||
deadline := time.Now().Add(summonWindow)
|
||||
for time.Now().Before(deadline) {
|
||||
// Require a beam this activation did not inherit. Its lifetime overlaps the
|
||||
// next activation, so matching on entry alone would let the previous one
|
||||
// stand in and hide an intermittent break of the summon-GO row.
|
||||
if beam == 0 {
|
||||
if g := bot.World.FindGameObjectByEntry(nagaBeam, 0); g != 0 && g != prevBeam {
|
||||
beam = g
|
||||
}
|
||||
}
|
||||
for _, u := range bot.World.GetNearbyUnits(100) {
|
||||
if u.Entry == lordKragaru && !seen[u.GUID] {
|
||||
seen[u.GUID] = true
|
||||
summoned = u.GUID
|
||||
}
|
||||
}
|
||||
if summoned != 0 {
|
||||
break
|
||||
}
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
}
|
||||
|
||||
if beam == 0 {
|
||||
e2eharness.Assertf(t, "activation %d/%d: Serpent Statue (%d) did not summon the Naga Beam (%d); "+
|
||||
"the statue's own script is broken, before any Kragaru summon can run",
|
||||
i, activations, serpentStatue, nagaBeam)
|
||||
}
|
||||
if summoned == 0 {
|
||||
e2eharness.Assertf(t, "activation %d/%d: Serpent Statue (%d) did not summon Lord Kragaru (%d) within %s; "+
|
||||
"without him the Book of the Ancients (15803) never drops and quest 6027 cannot be completed",
|
||||
i, activations, serpentStatue, lordKragaru, summonWindow)
|
||||
}
|
||||
t.Logf("activation %d/%d: beam 0x%X lit, Lord Kragaru summoned guid=0x%X",
|
||||
i, activations, beam, summoned)
|
||||
|
||||
// SetScript9 refuses a new action list while one is still registered
|
||||
// (allowOverride = 0), and the finished list is only dropped on the
|
||||
// gameobject's next update tick. Re-activating inside that tick would be
|
||||
// ignored — a beam, since that hangs off the link, but no Kragaru. A player
|
||||
// cannot reach this: the 60s autoclose forbids back-to-back use, and only a
|
||||
// GM force-reset gets here. Give the statue its tick.
|
||||
time.Sleep(settleBetweenActivations)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user