Module:GameInfo/Skills: Difference between revisions
From SpiritVale Wiki
More actions
No edit summary Tags: Mobile edit Mobile web edit |
No edit summary Tags: Mobile edit Mobile web edit |
||
| Line 1: | Line 1: | ||
-- Module:GameInfo/Skills | -- Module:GameInfo/Skills | ||
-- Phase 4.1 — | -- Phase 4.1 — Final native-first rendering (schema 1 + schema 2) | ||
-- | -- | ||
-- | -- Notes: | ||
-- - | -- - JSON Definition tokens must be plain strings that decode to Domain|Key. | ||
-- - Interactivity is provided by sitewide popup systems in Common.js. | |||
-- - Schema 2 is the primary layout target; schema 1 remains supported. | |||
-- - | |||
-- - | |||
local p = {} | local p = {} | ||
| Line 86: | Line 55: | ||
local _CORE_ORDER = { | local _CORE_ORDER = { | ||
{ field = "cost", label = "Cost" }, | { field = "cost", label = "Cost", def_tok = "Cast|Cost" }, | ||
{ field = "cast_time", label = "Cast Time" }, | { field = "cast_time", label = "Cast Time", def_tok = "Cast|Cast Time" }, | ||
{ field = "cooldown", label = "Cooldown" }, | { field = "cooldown", label = "Cooldown", def_tok = "Cast|Cooldown" }, | ||
{ field = "range", label = "Range" }, | { field = "range", label = "Range", def_tok = "Cast|Range" }, | ||
{ field = "area", label = "Area" }, | { field = "area", label = "Area", def_tok = "Cast|Area" }, | ||
{ field = "duration", label = "Duration" }, | { field = "duration", label = "Duration", def_tok = "Cast|Duration" }, | ||
} | } | ||
| Line 101: | Line 70: | ||
end | end | ||
local function _safe_tbl(t) return type(t) == "table" and t or {} end | local function _safe_tbl(t) | ||
return type(t) == "table" and t or {} | |||
end | |||
local function _safe_str(s, fallback) | local function _safe_str(s, fallback) | ||
| Line 244: | Line 215: | ||
end | end | ||
local function | local function _split_def_token(s) | ||
s = _trim(s) | s = _trim(s) | ||
if s == "" then return nil end | if s == "" then return nil, nil end | ||
local bar = s:find("|", 1, true) | local bar = s:find("|", 1, true) | ||
if not bar then | if not bar then return nil, nil end | ||
local domain = _trim(s:sub(1, bar - 1)) | local domain = _trim(s:sub(1, bar - 1)) | ||
local key | local key = _trim(s:sub(bar + 1)) | ||
if domain == "" or key == "" then | if domain == "" or key == "" then return nil, nil end | ||
return domain, key | |||
end | |||
local function _render_def_token(frame, s, noicon, extra_args) | |||
s = _trim(s) | |||
if s == "" then return nil end | |||
local domain, key = _split_def_token(s) | |||
if not domain or not key then | |||
return mw.text.nowiki(s) | return mw.text.nowiki(s) | ||
end | end | ||
| Line 274: | Line 253: | ||
end | end | ||
local function _meta_lines_def(frame, lines) | local function _display_text_from_token(s) | ||
lines = _safe_tbl(lines) | s = _trim(s) | ||
if s == "" then return "" end | |||
local _, key = _split_def_token(s) | |||
if key then return key end | |||
return s | |||
end | |||
local function _meta_lines_def(frame, lines) | |||
lines = _safe_tbl(lines) | |||
local wrap = mw.html.create("span"):addClass("sv-meta-lines") | local wrap = mw.html.create("span"):addClass("sv-meta-lines") | ||
local any = false | local any = false | ||
| Line 292: | Line 280: | ||
end | end | ||
local function | local function _build_hitbox(parent, class_name, frame, token) | ||
token = _safe_str(token, "") | |||
if | if not _has_pipe(token) then return false end | ||
local | local wt = _render_def_token(frame, token, true, { pill = "1", fill = "1" }) | ||
if not | if not wt then return false end | ||
parent:tag("span") | |||
:addClass(class_name) | |||
:attr("aria-hidden", "true") | |||
:wikitext(wt) | |||
return | return true | ||
end | end | ||
local function | local function _is_blankish(v) | ||
if v == nil then return true end | |||
if | local s = _trim(v) | ||
return s == "" or s == "—" or s == "-" or s == "--" | |||
local | |||
end | end | ||
local function _value_has_content(val) | |||
if val == nil then return false end | |||
local function _value_has_content(val) | |||
if val == nil then return false end | |||
if type(val) ~= "table" then | if type(val) ~= "table" then | ||
| Line 857: | Line 807: | ||
end | end | ||
_build_hitbox(card, "sv-meta-hit", frame, spec.hit_tok) | |||
end | end | ||
| Line 1,114: | Line 1,055: | ||
pill:addClass(active and "is-active" or "is-inactive") | pill:addClass(active and "is-active" or "is-inactive") | ||
if active then pill:addClass("sv-hover-lift") end | |||
local main = pill:tag("div"):addClass("sv_skill_scaling__stat-main") | local main = pill:tag("div"):addClass("sv_skill_scaling__stat-main") | ||
| Line 1,131: | Line 1,073: | ||
if active then | if active then | ||
_build_hitbox(pill, "sv_skill_scaling__stat-hit", frame, def_tok) | |||
end | end | ||
end | end | ||
local function _build_skill_scaling_core_pill(parent, spec, fld, level) | local function _build_skill_scaling_core_pill(frame, parent, spec, fld, level) | ||
fld = _safe_tbl(fld) | fld = _safe_tbl(fld) | ||
local active = _value_has_content(fld.value) | local active = _value_has_content(fld.value) | ||
| Line 1,151: | Line 1,087: | ||
:addClass("sv_skill_scaling__core-pill") | :addClass("sv_skill_scaling__core-pill") | ||
:addClass("sv_skill_scaling__core-pill--" .. spec.field) | :addClass("sv_skill_scaling__core-pill--" .. spec.field) | ||
:addClass("sv-hover-lift") | |||
:attr("data-core-key", spec.field) | :attr("data-core-key", spec.field) | ||
:attr("aria-label", spec.label) | |||
pill:addClass(active and "is-active" or "is-inactive") | pill:addClass(active and "is-active" or "is-inactive") | ||
local top = pill:tag("div"):addClass("sv_skill_scaling__core-main") | local top = pill:tag("div"):addClass("sv_skill_scaling__core-main") | ||
local value = top:tag("span"):addClass("sv_skill_scaling__core-value") | local value = top:tag("span"):addClass("sv_skill_scaling__core-value") | ||
_apply_value(value, fld.value, level) | _apply_value(value, fld.value, level) | ||
| Line 1,170: | Line 1,107: | ||
:addClass("sv_skill_scaling__core-label") | :addClass("sv_skill_scaling__core-label") | ||
:wikitext(mw.text.nowiki(spec.label)) | :wikitext(mw.text.nowiki(spec.label)) | ||
_build_hitbox(pill, "sv_skill_scaling__core-hit", frame, spec.def_tok) | |||
end | end | ||
| Line 1,230: | Line 1,169: | ||
end | end | ||
end | end | ||
do | do | ||
local core_group = body:tag("div") | local core_group = body:tag("div") | ||
:addClass("sv_skill_scaling__group") | :addClass("sv_skill_scaling__group") | ||
:addClass("sv_skill_scaling__group--core") | :addClass("sv_skill_scaling__group--core") | ||
local core_col = core_group:tag("div") | local core_col = core_group:tag("div") | ||
:addClass("sv_skill_scaling__column") | :addClass("sv_skill_scaling__column") | ||
:addClass("sv_skill_scaling__column--core") | :addClass("sv_skill_scaling__column--core") | ||
:addClass("sv_skill_scaling__core") | :addClass("sv_skill_scaling__core") | ||
local core_grid = core_col:tag("div"):addClass("sv_skill_scaling__core-grid") | local core_grid = core_col:tag("div"):addClass("sv_skill_scaling__core-grid") | ||
for _, spec in ipairs(_CORE_ORDER) do | for _, spec in ipairs(_CORE_ORDER) do | ||
_build_skill_scaling_core_pill(core_grid, spec, skill_scaling[spec.field], actual_default) | _build_skill_scaling_core_pill(frame, core_grid, spec, skill_scaling[spec.field], actual_default) | ||
end | end | ||
end | |||
return root, actual_default | |||
end | |||
local function _normalize_modifier_spec(item) | |||
item = _safe_tbl(item) | |||
local label_tok = _safe_str(item.label_wt or item.label or item.key or "", "") | |||
return { | |||
label_tok = label_tok, | |||
label_text = _display_text_from_token(label_tok), | |||
value = item.value, | |||
} | |||
end | |||
local function _build_modifier_pill(frame, parent, item, level) | |||
local spec = _normalize_modifier_spec(item) | |||
if spec.label_text == "" then return end | |||
local has_def = _has_pipe(spec.label_tok) | |||
local pill = parent:tag("div") | |||
:addClass("sv-tile") | |||
:addClass("sv-mech-mod-pill") | |||
if has_def then pill:addClass("sv-hover-lift") end | |||
pill:tag("div") | |||
:addClass("sv-mech-mod-pill__label") | |||
:wikitext(mw.text.nowiki(spec.label_text)) | |||
local value = pill:tag("div"):addClass("sv-mech-mod-pill__value") | |||
_apply_value(value, spec.value, level) | |||
if has_def then | |||
_build_hitbox(pill, "sv-mech-mod-pill__hit", frame, spec.label_tok) | |||
end | |||
end | |||
local function _build_keyword_pill(frame, parent, pill_text) | |||
pill_text = _trim(pill_text) | |||
if pill_text == "" then return end | |||
local has_def = _has_pipe(pill_text) | |||
local pill = parent:tag("span") | |||
:addClass("sv-pill") | |||
:addClass("sv-pill--value") | |||
:addClass("sv-mech-keyword-pill") | |||
if has_def then pill:addClass("sv-hover-lift") end | |||
pill:tag("span") | |||
:addClass("sv-mech-keyword-pill__label") | |||
:wikitext(mw.text.nowiki(_display_text_from_token(pill_text))) | |||
if has_def then | |||
_build_hitbox(pill, "sv-mech-keyword-pill__hit", frame, pill_text) | |||
end | end | ||
end | end | ||
| Line 1,336: | Line 1,329: | ||
if kind == "event" then | if kind == "event" then | ||
local sub = parent:tag("div"):addClass("sv-ref-sub") | local sub = parent:tag("div"):addClass("sv-ref-sub") | ||
if stats.text ~= nil then | if stats.text ~= nil then | ||
_apply_value(sub, stats, level) | _apply_value(sub, stats, level) | ||
| Line 1,390: | Line 1,382: | ||
local text = container:tag("div"):addClass("sv-ref-text") | local text = container:tag("div"):addClass("sv-ref-text") | ||
local title_div = text:tag("div"):addClass("sv-ref-title") | local title_div = text:tag("div"):addClass("sv-ref-title") | ||
if page ~= "" then | if page ~= "" then | ||
| Line 1,423: | Line 1,414: | ||
mods_wrap:tag("div"):addClass("sv-tab-section-title"):wikitext("Modifiers") | mods_wrap:tag("div"):addClass("sv-tab-section-title"):wikitext("Modifiers") | ||
local gridwrap = mods_wrap:tag("div"):addClass("sv- | local gridwrap = mods_wrap:tag("div"):addClass("sv-mech-mod-grid") | ||
for _, item in ipairs(mechanics_mods) do | for _, item in ipairs(mechanics_mods) do | ||
_build_modifier_pill(frame, gridwrap, item, level) | |||
end | end | ||
end | end | ||
| Line 1,635: | Line 1,616: | ||
local reqrow = _build_req_users(root_id, payload.requirements, payload.users) | local reqrow = _build_req_users(root_id, payload.requirements, payload.users) | ||
local meta_req_block = _build_meta_req_block(meta_block, reqrow) | local meta_req_block = _build_meta_req_block(meta_block, reqrow) | ||
if meta_req_block then box.top:node(meta_req_block) end | |||
if meta_req_block then | |||
local level_panel, actual_default = _build_level(root_id, default_level, max_level, 1, nil) | local level_panel, actual_default = _build_level(root_id, default_level, max_level, 1, nil) | ||
box.bottom:node(level_panel) | box.bottom:node(level_panel) | ||
box.bottom:node(_build_scaling_top(frame, payload.scaling_top, actual_default)) | box.bottom:node(_build_scaling_top(frame, payload.scaling_top, actual_default)) | ||
| Line 1,689: | Line 1,666: | ||
local reqrow = _build_req_users_native(root_id, payload.requirements, payload.users) | local reqrow = _build_req_users_native(root_id, payload.requirements, payload.users) | ||
local meta_req_block = _build_meta_req_block(meta_block, reqrow) | local meta_req_block = _build_meta_req_block(meta_block, reqrow) | ||
if meta_req_block then box.top:node(meta_req_block) end | |||
if meta_req_block then | |||
local scaling_block, actual_default = _build_skill_scaling_native( | local scaling_block, actual_default = _build_skill_scaling_native( | ||