mirror of
https://github.com/Nighthawk42/wow_bejeweled.git
synced 2026-08-30 04:30:22 +00:00
feat: add backdrop foundation
This commit is contained in:
@@ -15,3 +15,4 @@ Engine\Grid.lua
|
||||
Engine\Matches.lua
|
||||
Engine\Cascade.lua
|
||||
Engine\Scoring.lua
|
||||
UI\Backdrops.lua
|
||||
|
||||
@@ -15,10 +15,12 @@ function addon:Initialize(accountData, profileData)
|
||||
assert(self.SavedVariables, "SavedVariables module is not loaded")
|
||||
assert(self.Grid, "Grid module is not loaded")
|
||||
assert(self.Audio, "Audio module is not loaded")
|
||||
assert(self.Backdrops, "Backdrops module is not loaded")
|
||||
|
||||
self.accountData, self.profileData = self.SavedVariables:Initialize(accountData, profileData)
|
||||
self.grid = self.Grid:New()
|
||||
self.audio = self.Audio:New(self.profileData.settings)
|
||||
self.backdrops = self.Backdrops
|
||||
self.initialized = true
|
||||
|
||||
return self
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
local _, addon = ...
|
||||
|
||||
local Constants = assert(addon.Constants, "Constants module is not loaded")
|
||||
|
||||
local Backdrops = {}
|
||||
|
||||
local PRESETS = {
|
||||
tooltip = {
|
||||
bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
|
||||
tileSize = 16,
|
||||
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
|
||||
tile = 1,
|
||||
edgeSize = 16,
|
||||
insets = { top = 5, right = 5, left = 5, bottom = 5 },
|
||||
},
|
||||
window = {
|
||||
bgFile = Constants.IMAGE_ROOT .. "windowBackground",
|
||||
tileSize = 64,
|
||||
edgeFile = Constants.IMAGE_ROOT .. "windowBorder",
|
||||
tile = 1,
|
||||
edgeSize = 32,
|
||||
insets = { top = 5, right = 3, left = 5, bottom = 5 },
|
||||
},
|
||||
panel = {
|
||||
bgFile = Constants.IMAGE_ROOT .. "windowBackground",
|
||||
tileSize = 128,
|
||||
edgeFile = "Interface\\Glues\\Common\\TextPanel-Border",
|
||||
tile = 1,
|
||||
edgeSize = 32,
|
||||
insets = { top = 3, right = 5, left = 5, bottom = 5 },
|
||||
},
|
||||
slider = {
|
||||
bgFile = Constants.IMAGE_ROOT .. "windowBackground",
|
||||
tileSize = 64,
|
||||
edgeFile = "Interface\\Buttons\\UI-SliderBar-Border",
|
||||
tile = 1,
|
||||
edgeSize = 8,
|
||||
insets = { top = 5, right = 2, left = 2, bottom = 5 },
|
||||
},
|
||||
level = {
|
||||
bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
|
||||
tileSize = 16,
|
||||
edgeFile = Constants.IMAGE_ROOT .. "levelBorder",
|
||||
tile = 1,
|
||||
edgeSize = 32,
|
||||
insets = { top = 5, right = 2, left = 2, bottom = 5 },
|
||||
},
|
||||
}
|
||||
|
||||
local function CopyInsets(insets)
|
||||
return {
|
||||
top = insets.top,
|
||||
right = insets.right,
|
||||
left = insets.left,
|
||||
bottom = insets.bottom,
|
||||
}
|
||||
end
|
||||
|
||||
local function CopyDescriptor(descriptor)
|
||||
local copy = {}
|
||||
for key, value in pairs(descriptor) do
|
||||
if key == "insets" then
|
||||
copy.insets = CopyInsets(value)
|
||||
else
|
||||
copy[key] = value
|
||||
end
|
||||
end
|
||||
return copy
|
||||
end
|
||||
|
||||
local function AddBackdropTemplate(template)
|
||||
if not template or template == "" then
|
||||
return "BackdropTemplate"
|
||||
end
|
||||
if string.find(template, "BackdropTemplate", 1, true) then
|
||||
return template
|
||||
end
|
||||
return template .. ",BackdropTemplate"
|
||||
end
|
||||
|
||||
local function ApplyColor(frame, methodName, color)
|
||||
if not color then
|
||||
return
|
||||
end
|
||||
assert(type(color) == "table", methodName .. " color must be a table")
|
||||
assert(type(frame[methodName]) == "function", "frame does not support " .. methodName)
|
||||
if color[4] == nil then
|
||||
frame[methodName](frame, color[1], color[2], color[3])
|
||||
else
|
||||
frame[methodName](frame, color[1], color[2], color[3], color[4])
|
||||
end
|
||||
end
|
||||
|
||||
function Backdrops:CreateDescriptor(presetName, overrides)
|
||||
presetName = presetName or "tooltip"
|
||||
local preset = PRESETS[presetName]
|
||||
assert(preset, "unknown backdrop preset: " .. tostring(presetName))
|
||||
assert(overrides == nil or type(overrides) == "table", "backdrop overrides must be a table")
|
||||
|
||||
local descriptor = CopyDescriptor(preset)
|
||||
if overrides then
|
||||
for key, value in pairs(overrides) do
|
||||
if key == "insets" then
|
||||
assert(type(value) == "table", "backdrop inset overrides must be a table")
|
||||
for insetName, insetValue in pairs(value) do
|
||||
descriptor.insets[insetName] = insetValue
|
||||
end
|
||||
else
|
||||
descriptor[key] = value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return descriptor
|
||||
end
|
||||
|
||||
function Backdrops:Apply(frame, descriptor, backgroundColor, borderColor)
|
||||
assert(frame ~= nil, "backdrop frame is required")
|
||||
assert(type(frame.SetBackdrop) == "function", "frame does not support SetBackdrop")
|
||||
assert(type(descriptor) == "table", "backdrop descriptor must be a table")
|
||||
|
||||
frame:SetBackdrop(descriptor)
|
||||
ApplyColor(frame, "SetBackdropColor", backgroundColor)
|
||||
ApplyColor(frame, "SetBackdropBorderColor", borderColor)
|
||||
return frame
|
||||
end
|
||||
|
||||
function Backdrops:CreateFrame(options)
|
||||
options = options or {}
|
||||
assert(type(options) == "table", "backdrop frame options must be a table")
|
||||
|
||||
local createFrame = options.createFrame or CreateFrame
|
||||
assert(type(createFrame) == "function", "CreateFrame is unavailable")
|
||||
local descriptor = options.descriptor or self:CreateDescriptor(options.preset, options.overrides)
|
||||
local frame = createFrame(
|
||||
options.frameType or "Frame",
|
||||
options.name,
|
||||
options.parent,
|
||||
AddBackdropTemplate(options.template)
|
||||
)
|
||||
|
||||
self:Apply(frame, descriptor, options.backgroundColor, options.borderColor)
|
||||
return frame, descriptor
|
||||
end
|
||||
|
||||
Backdrops.PresetNames = {
|
||||
"tooltip",
|
||||
"window",
|
||||
"panel",
|
||||
"slider",
|
||||
"level",
|
||||
}
|
||||
|
||||
addon.Backdrops = Backdrops
|
||||
@@ -6,7 +6,7 @@ This branch contains the analysis-complete, Mainline-first modernization of the
|
||||
|
||||
The preserved 8,401-line Mainline source must be analyzed sequentially, in evidence-backed batches, before runtime work begins. All behavior-critical shortened symbols must be resolved and all batches must be complete before any public Lua API, runtime module, modern TOC, packaging, or release work is added.
|
||||
|
||||
All 17 batches (lines 1–8,401) are documented, the cross-batch identifier audit has no remaining `working` or `unresolved` declarations, and the retained Retail API contracts are pinned in `docs/api-baseline.md`. The analysis phase gate is closed. Runtime implementation now includes wire-compatible SavedVariables initialization, deterministic grid/match/cascade/scoring transitions, skills, levels, and legacy-compatible audio cue scheduling.
|
||||
All 17 batches (lines 1–8,401) are documented, the cross-batch identifier audit has no remaining `working` or `unresolved` declarations, and the retained Retail API contracts are pinned in `docs/api-baseline.md`. The analysis phase gate is closed. Runtime implementation now includes wire-compatible SavedVariables initialization, deterministic grid/match/cascade/scoring transitions, skills, levels, legacy-compatible audio cue scheduling, and BackdropTemplate-safe UI chrome construction.
|
||||
|
||||
## Goal
|
||||
|
||||
@@ -19,11 +19,13 @@ The eventual addon will target current Retail/Mainline World of Warcraft while p
|
||||
- `Bejeweled/sounds/` — immutable legacy sounds.
|
||||
- `Bejeweled/Core/` — private addon initialization, constants, supported audio playback, and non-destructive SavedVariables defaulting.
|
||||
- `Bejeweled/Engine/` — deterministic gameplay state; currently the 8×8 grid, swaps, legal moves, legacy cell encoding, stable cascade resolution, legacy score formulas, statistics, skill gains, achievements, and level thresholds.
|
||||
- `Bejeweled/UI/` — Retail-safe frame/rendering boundaries; currently shared backdrop descriptors and construction.
|
||||
- `docs/analysis/` — sequential batch reports, identifier ledger, and exact coverage schedule.
|
||||
- `docs/architecture.md` — module ownership and authoritative runtime data flow.
|
||||
- `docs/api-baseline.md` — verified Retail API constraints for implementation.
|
||||
- `tools/test-runtime.lua` and `tools/verify-runtime.ps1` — Lua 5.1-compatible engine tests and TOC verification.
|
||||
- `plan.md` — the bootstrap specification executed by the root commit.
|
||||
- `todo.md` — the running implementation roadmap and completed runtime slices.
|
||||
|
||||
## Contributing
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Target architecture (post-analysis)
|
||||
|
||||
The analysis phase gate is satisfied. This ownership map now governs runtime implementation; currently implemented modules are `Core/Init.lua`, `Core/Constants.lua`, `Core/Audio.lua`, `Core/SavedVariables.lua`, `Engine/Grid.lua`, `Engine/Matches.lua`, `Engine/Cascade.lua`, and `Engine/Scoring.lua`.
|
||||
The analysis phase gate is satisfied. This ownership map now governs runtime implementation; currently implemented modules are `Core/Init.lua`, `Core/Constants.lua`, `Core/Audio.lua`, `Core/SavedVariables.lua`, `Engine/Grid.lua`, `Engine/Matches.lua`, `Engine/Cascade.lua`, `Engine/Scoring.lua`, and `UI/Backdrops.lua`.
|
||||
|
||||
## Load order and ownership
|
||||
|
||||
@@ -12,7 +12,7 @@ The analysis phase gate is satisfied. This ownership map now governs runtime imp
|
||||
6. `Engine/Matches.lua` — pure legacy-order match detection, axis-overlap reporting, and power/hyper-gem classification; clearing and scoring remain downstream responsibilities.
|
||||
7. `Engine/Cascade.lua` — transactional clears, matched power-gem expansion, spawned-special preservation, fixed-cell gravity, bounded refill, and repeated transitions to a stable board. It emits logical movement/refill records but owns no animation or scoring.
|
||||
8. `Engine/Scoring.lua` — legacy score arithmetic, combo/mode/level multipliers, wire-compatible statistics, probabilistic skill gains, one-time achievements, rank advancement, and pending/explicit level transitions. It emits presentation events and owns no frames, text, sound, or chat publishing.
|
||||
9. `UI/Backdrops.lua` — backdrop-compatible frame construction and shared chrome.
|
||||
9. `UI/Backdrops.lua` — backdrop-compatible frame construction and fresh-copy presets for tooltip, window, panel, slider, and level-border chrome. Every constructed frame explicitly inherits `BackdropTemplate`.
|
||||
10. `UI/GemPool.lua` — gem-frame allocation, reuse, and grid-to-frame projection.
|
||||
11. `UI/Animations.lua` — animation groups, transition timing, and visual effect orchestration.
|
||||
12. `UI/HUD.lua` — score, timer, level, status, hint, and achievement presentation.
|
||||
|
||||
+64
-1
@@ -47,12 +47,72 @@ LoadAddonFile("Bejeweled/Engine/Grid.lua", addon)
|
||||
LoadAddonFile("Bejeweled/Engine/Matches.lua", addon)
|
||||
LoadAddonFile("Bejeweled/Engine/Cascade.lua", addon)
|
||||
LoadAddonFile("Bejeweled/Engine/Scoring.lua", addon)
|
||||
LoadAddonFile("Bejeweled/UI/Backdrops.lua", addon)
|
||||
|
||||
AssertEqual(eventFrame.registeredEvent, "ADDON_LOADED", "initializer event registration")
|
||||
AssertEqual(addon.Constants.GRID_WIDTH, 8, "grid width")
|
||||
AssertEqual(addon.Constants.GRID_HEIGHT, 8, "grid height")
|
||||
AssertEqual(addon.Constants.GEM_COLOR_COUNT, 7, "gem color count")
|
||||
|
||||
local windowBackdrop = addon.Backdrops:CreateDescriptor("window")
|
||||
AssertEqual(windowBackdrop.bgFile, addon.Constants.IMAGE_ROOT .. "windowBackground", "window backdrop texture")
|
||||
AssertEqual(windowBackdrop.edgeFile, addon.Constants.IMAGE_ROOT .. "windowBorder", "window backdrop border")
|
||||
AssertEqual(windowBackdrop.insets.right, 3, "window backdrop right inset")
|
||||
windowBackdrop.insets.right = 99
|
||||
AssertEqual(addon.Backdrops:CreateDescriptor("window").insets.right, 3, "backdrop preset shared mutable insets")
|
||||
|
||||
local customPanelBackdrop = addon.Backdrops:CreateDescriptor("panel", {
|
||||
edgeSize = 24,
|
||||
insets = { left = 7 },
|
||||
})
|
||||
AssertEqual(customPanelBackdrop.edgeSize, 24, "backdrop scalar override")
|
||||
AssertEqual(customPanelBackdrop.insets.left, 7, "backdrop inset override")
|
||||
AssertEqual(customPanelBackdrop.insets.top, 3, "backdrop inset default preservation")
|
||||
|
||||
local createdBackdropFrame
|
||||
local backdropCreateArguments
|
||||
local function CreateBackdropFrame(frameType, name, parent, template)
|
||||
backdropCreateArguments = { frameType, name, parent, template }
|
||||
createdBackdropFrame = {}
|
||||
function createdBackdropFrame:SetBackdrop(descriptor)
|
||||
self.descriptor = descriptor
|
||||
end
|
||||
function createdBackdropFrame:SetBackdropColor(red, green, blue, alpha)
|
||||
self.backgroundColor = { red, green, blue, alpha }
|
||||
end
|
||||
function createdBackdropFrame:SetBackdropBorderColor(red, green, blue, alpha)
|
||||
self.borderColor = { red, green, blue, alpha }
|
||||
end
|
||||
return createdBackdropFrame
|
||||
end
|
||||
|
||||
local backdropParent = {}
|
||||
local appliedBackdropFrame, appliedDescriptor = addon.Backdrops:CreateFrame({
|
||||
name = "BejeweledBackdropTest",
|
||||
parent = backdropParent,
|
||||
template = "UIPanelButtonTemplate",
|
||||
preset = "panel",
|
||||
backgroundColor = { 0.6, 0.6, 0.6, 1 },
|
||||
borderColor = { 1, 0.8, 0.45 },
|
||||
createFrame = CreateBackdropFrame,
|
||||
})
|
||||
assert(appliedBackdropFrame == createdBackdropFrame, "backdrop frame identity changed")
|
||||
assert(appliedDescriptor == createdBackdropFrame.descriptor, "created backdrop descriptor was not applied")
|
||||
AssertEqual(backdropCreateArguments[1], "Frame", "default backdrop frame type")
|
||||
AssertEqual(backdropCreateArguments[2], "BejeweledBackdropTest", "backdrop frame name")
|
||||
assert(backdropCreateArguments[3] == backdropParent, "backdrop frame parent changed")
|
||||
AssertEqual(backdropCreateArguments[4], "UIPanelButtonTemplate,BackdropTemplate", "backdrop template composition")
|
||||
AssertEqual(createdBackdropFrame.backgroundColor[4], 1, "backdrop background alpha")
|
||||
AssertEqual(createdBackdropFrame.borderColor[3], 0.45, "backdrop border blue")
|
||||
assert(createdBackdropFrame.borderColor[4] == nil, "three-channel border color gained an alpha")
|
||||
|
||||
local existingTemplateFrame = addon.Backdrops:CreateFrame({
|
||||
template = "BackdropTemplate",
|
||||
createFrame = CreateBackdropFrame,
|
||||
})
|
||||
assert(existingTemplateFrame, "existing BackdropTemplate frame was not created")
|
||||
AssertEqual(backdropCreateArguments[4], "BackdropTemplate", "BackdropTemplate was duplicated")
|
||||
|
||||
local playedFiles = {}
|
||||
local playedSoundKits = {}
|
||||
local audioSettings = {}
|
||||
@@ -535,11 +595,14 @@ eventFrame.scripts.OnEvent(eventFrame, "ADDON_LOADED", "Bejeweled", false)
|
||||
assert(addon.initialized, "addon initialization did not complete")
|
||||
assert(addon.grid, "addon initialization did not create a grid")
|
||||
assert(addon.audio, "addon initialization did not create audio")
|
||||
assert(addon.backdrops == addon.Backdrops, "addon initialization did not install backdrops")
|
||||
assert(eventFrame.registeredEvent == nil, "initializer event was not unregistered")
|
||||
local initializedGrid = addon.grid
|
||||
local initializedAudio = addon.audio
|
||||
local initializedBackdrops = addon.backdrops
|
||||
addon:Initialize({}, {})
|
||||
assert(addon.grid == initializedGrid, "addon initialization is not idempotent")
|
||||
assert(addon.audio == initializedAudio, "audio initialization is not idempotent")
|
||||
assert(addon.backdrops == initializedBackdrops, "backdrop initialization is not idempotent")
|
||||
|
||||
print("Runtime verification passed: audio, SavedVariables, and deterministic gameplay engine.")
|
||||
print("Runtime verification passed: UI backdrops, audio, SavedVariables, and deterministic gameplay engine.")
|
||||
|
||||
@@ -26,7 +26,8 @@ try {
|
||||
"Engine\Grid.lua",
|
||||
"Engine\Matches.lua",
|
||||
"Engine\Cascade.lua",
|
||||
"Engine\Scoring.lua"
|
||||
"Engine\Scoring.lua",
|
||||
"UI\Backdrops.lua"
|
||||
)
|
||||
$actualFiles = @($toc | Where-Object { $_ -match "\.lua$" })
|
||||
if (Compare-Object -ReferenceObject $expectedFiles -DifferenceObject $actualFiles -SyncWindow 0) {
|
||||
|
||||
Reference in New Issue
Block a user