A from-scratch World of Warcraft 1.12.1 client in Rust + Bevy. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
266 lines
12 KiB
XML
266 lines
12 KiB
XML
<Ui xmlns="http://www.blizzard.com/wow/ui/">
|
||
<!--
|
||
The death arc's UI (decision 0308 slices 1/3): the reference's death dialogs registered on
|
||
the shared StaticPopup engine (UiPanels.xml), and the UIParent death-event driver,
|
||
transcribed from the patch-chain FrameXML (mpqx extraction, decision 0246):
|
||
StaticPopup.lua l.375-505 (DEATH + RESURRECT×3), l.1134-1201 (XP_LOSS×2 + RECOVER_CORPSE*),
|
||
UIParent.lua l.237-262 + l.399-436 (the event arms). Strings verbatim from
|
||
GlobalStrings.lua. The engine-side events feeding this: PLAYER_DEAD/ALIVE/UNGHOST +
|
||
RESURRECT_REQUEST + CONFIRM_XP_LOSS fire from `death.rs`'s state machine;
|
||
CORPSE_IN_RANGE/OUT_OF_RANGE/IN_INSTANCE join with the slice-2 corpse-run range gate
|
||
(registered now — they simply don't fire yet). Deferred with 0308 §8: the SKINNED/
|
||
SKINNED_REPOP pair (battleground insignia) and UseSoulstone (HasSoulstone() is nil).
|
||
-->
|
||
<Script><![CDATA[
|
||
-- ── Strings (GlobalStrings.lua, verbatim; %% escapes as shipped) ─────────────────────────
|
||
local DEATH_RELEASE_TIMER = "%d %s until release"
|
||
local DEATH_RELEASE_NOTIMER = "You have died. Release to the nearest graveyard?"
|
||
local DEATH_RELEASE = "Release Spirit"
|
||
local USE_SOULSTONE = "Reincarnate" -- the shaman default; OnShow overrides with HasSoulstone()'s text
|
||
local RECOVER_CORPSE_TEXT = "Resurrect now?"
|
||
local RECOVER_CORPSE_TIMER = "%d %s until resurrection"
|
||
local RECOVER_CORPSE_INSTANCE_TEXT = "You must enter the instance to recover your corpse"
|
||
local RESURRECT_REQUEST_TEXT = "%s wants to resurrect you. You will be afflicted with resurrection sickness."
|
||
local RESURRECT_REQUEST_TIMER = "%s wants to resurrect you and will be able to in %d %s. You will be afflicted with resurrection sickness."
|
||
local RESURRECT_REQUEST_NO_SICKNESS = "%s wants to resurrect you"
|
||
local RESURRECT_REQUEST_NO_SICKNESS_TIMER = "%s wants to resurrect you and will be able to in %d %s"
|
||
local CONFIRM_XP_LOSS = "If you find your corpse, you can resurrect for no penalty. If I resurrect you all of your items will take 25%% durability damage (equipped and inventory) and you will be afflicted by %s of Resurrection Sickness."
|
||
local CONFIRM_XP_LOSS_AGAIN = "Remember, if you find your corpse there is no penalty. Are you sure you want to incur %s of Resurrection Sickness and have all your items take 25%% durability damage?"
|
||
local CONFIRM_XP_LOSS_NO_SICKNESS = "If you find your corpse, you can resurrect for no penalty. If I resurrect you all of your items will take 25%% durability damage (equipped and inventory)."
|
||
local CONFIRM_XP_LOSS_AGAIN_NO_SICKNESS = "Remember, if you find your corpse there is no penalty. Are you sure you want to have all your items take 25% durability damage?"
|
||
local ACCEPT = "Accept"
|
||
local DECLINE = "Decline"
|
||
local CANCEL = "Cancel"
|
||
|
||
-- ── The DEATH (release) dialog — StaticPopup.lua l.375-414, verbatim behavior ────────────
|
||
-- OnShow seeds timeleft from GetReleaseTimeRemaining(): >0 counts down through the engine's
|
||
-- per-tick DEATH text; −1 swaps in the no-timer text (no countdown). Timeout expiry is a
|
||
-- silent hide — the SERVER force-releases at 6:00 (0308 §1). No hideOnEscape: ESC never
|
||
-- dismisses it. Button2 is soulstone-only (HasSoulstone() is nil in v1 → hidden, and the
|
||
-- OnCancel clicked-branch falls through to RepopMe()).
|
||
StaticPopupDialogs["DEATH"] = {
|
||
text = DEATH_RELEASE_TIMER,
|
||
button1 = DEATH_RELEASE,
|
||
button2 = USE_SOULSTONE,
|
||
OnShow = function()
|
||
this.timeleft = GetReleaseTimeRemaining()
|
||
local text = HasSoulstone()
|
||
if text then
|
||
getglobal(this:GetName() .. "Button2"):SetText(text)
|
||
end
|
||
if this.timeleft == -1 then
|
||
getglobal(this:GetName() .. "Text"):SetText(DEATH_RELEASE_NOTIMER)
|
||
end
|
||
end,
|
||
OnAccept = function()
|
||
RepopMe()
|
||
end,
|
||
OnCancel = function(data, reason)
|
||
if reason == "override" then
|
||
return
|
||
end
|
||
if reason == "timeout" then
|
||
return
|
||
end
|
||
if reason == "clicked" then
|
||
if HasSoulstone() then
|
||
UseSoulstone()
|
||
else
|
||
RepopMe()
|
||
end
|
||
end
|
||
end,
|
||
DisplayButton2 = function()
|
||
return HasSoulstone()
|
||
end,
|
||
timeout = 0,
|
||
whileDead = 1,
|
||
interruptCinematic = 1,
|
||
notClosableByLogout = 1,
|
||
cancels = "RECOVER_CORPSE",
|
||
}
|
||
|
||
-- ── RECOVER_CORPSE — StaticPopup.lua l.1182-1202 (slice 2's range gate shows it) ─────────
|
||
StaticPopupDialogs["RECOVER_CORPSE"] = {
|
||
StartDelay = GetCorpseRecoveryDelay,
|
||
delayText = RECOVER_CORPSE_TIMER,
|
||
text = RECOVER_CORPSE_TEXT,
|
||
button1 = ACCEPT,
|
||
OnAccept = function()
|
||
RetrieveCorpse()
|
||
return 1
|
||
end,
|
||
timeout = 0,
|
||
whileDead = 1,
|
||
interruptCinematic = 1,
|
||
notClosableByLogout = 1,
|
||
}
|
||
StaticPopupDialogs["RECOVER_CORPSE_INSTANCE"] = {
|
||
text = RECOVER_CORPSE_INSTANCE_TEXT,
|
||
timeout = 0,
|
||
whileDead = 1,
|
||
interruptCinematic = 1,
|
||
notClosableByLogout = 1,
|
||
}
|
||
|
||
-- ── The RESURRECT trio — StaticPopup.lua l.416-505: sickness / no-sickness / no-timer.
|
||
-- Decline (or the 60 s timeout) answers the offer and re-shows DEATH if still unreleased.
|
||
local function resurrect_entry(text, delayText)
|
||
return {
|
||
StartDelay = delayText and GetCorpseRecoveryDelay or nil,
|
||
delayText = delayText,
|
||
text = text,
|
||
button1 = ACCEPT,
|
||
button2 = DECLINE,
|
||
OnShow = function()
|
||
this.timeleft = GetCorpseRecoveryDelay() + 60
|
||
end,
|
||
OnAccept = function()
|
||
AcceptResurrect()
|
||
end,
|
||
OnCancel = function()
|
||
DeclineResurrect()
|
||
if UnitIsDead("player") then
|
||
StaticPopup_Show("DEATH")
|
||
end
|
||
end,
|
||
timeout = 60,
|
||
whileDead = 1,
|
||
cancels = "DEATH",
|
||
interruptCinematic = 1,
|
||
notClosableByLogout = 1,
|
||
hideOnEscape = 1,
|
||
}
|
||
end
|
||
StaticPopupDialogs["RESURRECT"] = resurrect_entry(RESURRECT_REQUEST_TEXT, RESURRECT_REQUEST_TIMER)
|
||
StaticPopupDialogs["RESURRECT_NO_SICKNESS"] =
|
||
resurrect_entry(RESURRECT_REQUEST_NO_SICKNESS, RESURRECT_REQUEST_NO_SICKNESS_TIMER)
|
||
StaticPopupDialogs["RESURRECT_NO_TIMER"] = resurrect_entry(RESURRECT_REQUEST_NO_SICKNESS, nil)
|
||
|
||
-- ── The spirit healer's XP_LOSS two-step — StaticPopup.lua l.1134-1180: the first Accept
|
||
-- rewrites to the "Are you sure" text (data cleared, dialog stays via return 1), the second
|
||
-- sends AcceptXPLoss(); walking out of range auto-hides (the entry's own OnUpdate poll).
|
||
StaticPopupDialogs["XP_LOSS"] = {
|
||
text = CONFIRM_XP_LOSS,
|
||
button1 = ACCEPT,
|
||
button2 = CANCEL,
|
||
OnAccept = function(data)
|
||
if data then
|
||
getglobal(this:GetParent():GetName() .. "Text"):SetText(
|
||
format(CONFIRM_XP_LOSS_AGAIN, data))
|
||
this:GetParent().data = nil
|
||
return 1
|
||
else
|
||
AcceptXPLoss()
|
||
end
|
||
end,
|
||
OnUpdate = function(elapsed, dialog)
|
||
if not CheckSpiritHealerDist() then
|
||
dialog:Hide()
|
||
end
|
||
end,
|
||
timeout = 0,
|
||
exclusive = 1,
|
||
whileDead = 1,
|
||
showAlert = 1,
|
||
hideOnEscape = 1,
|
||
}
|
||
StaticPopupDialogs["XP_LOSS_NO_SICKNESS"] = {
|
||
text = CONFIRM_XP_LOSS_NO_SICKNESS,
|
||
button1 = ACCEPT,
|
||
button2 = CANCEL,
|
||
OnAccept = function(data)
|
||
if data then
|
||
getglobal(this:GetParent():GetName() .. "Text"):SetText(
|
||
CONFIRM_XP_LOSS_AGAIN_NO_SICKNESS)
|
||
this:GetParent().data = nil
|
||
return 1
|
||
else
|
||
AcceptXPLoss()
|
||
end
|
||
end,
|
||
OnUpdate = function(elapsed, dialog)
|
||
if not CheckSpiritHealerDist() then
|
||
dialog:Hide()
|
||
end
|
||
end,
|
||
timeout = 0,
|
||
exclusive = 1,
|
||
whileDead = 1,
|
||
showAlert = 1,
|
||
hideOnEscape = 1,
|
||
}
|
||
|
||
-- ── The death-event driver — UIParent.lua l.237-262 + l.399-436, transcribed ─────────────
|
||
function BenillaDeathDriver_OnEvent()
|
||
if event == "PLAYER_DEAD" then
|
||
if not StaticPopup_Visible("DEATH") then
|
||
CloseAllWindows(1)
|
||
if GetReleaseTimeRemaining() > 0 or GetReleaseTimeRemaining() == -1 then
|
||
StaticPopup_Show("DEATH")
|
||
end
|
||
end
|
||
elseif event == "PLAYER_ALIVE" then
|
||
StaticPopup_Hide("DEATH")
|
||
StaticPopup_Hide("RESURRECT_NO_SICKNESS")
|
||
elseif event == "PLAYER_UNGHOST" then
|
||
StaticPopup_Hide("RESURRECT")
|
||
StaticPopup_Hide("RESURRECT_NO_SICKNESS")
|
||
StaticPopup_Hide("RESURRECT_NO_TIMER")
|
||
elseif event == "RESURRECT_REQUEST" then
|
||
if ResurrectHasSickness() then
|
||
StaticPopup_Show("RESURRECT", arg1)
|
||
elseif ResurrectHasTimer() then
|
||
StaticPopup_Show("RESURRECT_NO_SICKNESS", arg1)
|
||
else
|
||
StaticPopup_Show("RESURRECT_NO_TIMER", arg1)
|
||
end
|
||
elseif event == "CONFIRM_XP_LOSS" then
|
||
local resSicknessTime = GetResSicknessDuration()
|
||
if resSicknessTime then
|
||
local dialog = StaticPopup_Show("XP_LOSS", resSicknessTime)
|
||
if dialog then
|
||
dialog.data = resSicknessTime
|
||
end
|
||
else
|
||
local dialog = StaticPopup_Show("XP_LOSS_NO_SICKNESS")
|
||
if dialog then
|
||
dialog.data = 1
|
||
end
|
||
end
|
||
-- The ref hides the gossip window under the confirm (UIParent.lua l.412).
|
||
local gossip = getglobal("BenillaGossipFrame")
|
||
if gossip and gossip:IsVisible() then
|
||
HideUIPanel(gossip)
|
||
end
|
||
elseif event == "CORPSE_IN_RANGE" then
|
||
StaticPopup_Show("RECOVER_CORPSE")
|
||
elseif event == "CORPSE_IN_INSTANCE" then
|
||
StaticPopup_Show("RECOVER_CORPSE_INSTANCE")
|
||
elseif event == "CORPSE_OUT_OF_RANGE" then
|
||
StaticPopup_Hide("RECOVER_CORPSE")
|
||
StaticPopup_Hide("RECOVER_CORPSE_INSTANCE")
|
||
StaticPopup_Hide("XP_LOSS")
|
||
end
|
||
end
|
||
]]></Script>
|
||
|
||
<Frame name="BenillaDeathDriver" hidden="true">
|
||
<Size><AbsDimension x="1" y="1"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT"/></Anchors>
|
||
<Scripts>
|
||
<OnLoad>
|
||
self:RegisterEvent("PLAYER_DEAD")
|
||
self:RegisterEvent("PLAYER_ALIVE")
|
||
self:RegisterEvent("PLAYER_UNGHOST")
|
||
self:RegisterEvent("RESURRECT_REQUEST")
|
||
self:RegisterEvent("CONFIRM_XP_LOSS")
|
||
self:RegisterEvent("CORPSE_IN_RANGE")
|
||
self:RegisterEvent("CORPSE_IN_INSTANCE")
|
||
self:RegisterEvent("CORPSE_OUT_OF_RANGE")
|
||
</OnLoad>
|
||
<OnEvent>BenillaDeathDriver_OnEvent()</OnEvent>
|
||
</Scripts>
|
||
</Frame>
|
||
</Ui>
|