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 |
||
| (4 intermediate revisions by the same user not shown) | |||
| Line 1: | Line 1: | ||
-- Module:GameInfo/Skills | -- Module:GameInfo/Skills | ||
-- Phase 4. | -- Phase 4.2 — 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. | |||
-- - Mechanics / keywords are JSON-driven; the renderer does not infer future | |||
-- mechanic definition tokens from labels. | |||
-- - | |||
-- - | |||
-- - | |||
-- | |||
local p = {} | local p = {} | ||
| Line 86: | Line 57: | ||
local _CORE_ORDER = { | local _CORE_ORDER = { | ||
{ field = "cost", label = "Cost" }, | { field = "cost", label = "Cost", def_tok = "Skill|Cost" }, | ||
{ field = "cast_time", label = "Cast Time" }, | { field = "cast_time", label = "Cast Time", def_tok = "Skill|CastTime" }, | ||
{ field = "cooldown", label = "Cooldown" }, | { field = "cooldown", label = "Cooldown", def_tok = "Skill|Cooldown" }, | ||
{ field = "range", label = "Range" }, | { field = "range", label = "Range", def_tok = "Skill|Range" }, | ||
{ field = "area", label = "Area" }, | { field = "area", label = "Area", def_tok = "Skill|Area" }, | ||
{ field = "duration", label = "Duration" }, | { field = "duration", label = "Duration", def_tok = "Skill|Duration" }, | ||
} | } | ||
| Line 101: | Line 72: | ||
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 119: | Line 92: | ||
s = s:gsub("[^%w]+", "-"):gsub("%-+", "-"):gsub("^%-", ""):gsub("%-$", "") | s = s:gsub("[^%w]+", "-"):gsub("%-+", "-"):gsub("^%-", ""):gsub("%-$", "") | ||
if s == "" then s = "item" end | if s == "" then s = "item" end | ||
return s | |||
end | |||
local function _humanize_key(s) | |||
s = _trim(s) | |||
if s == "" then return "" end | |||
if s:find("%s") then return s end | |||
s = s:gsub("([A-Z]+)([A-Z][a-z])", "%1 %2") | |||
s = s:gsub("([a-z0-9])([A-Z])", "%1 %2") | |||
return s | return s | ||
end | end | ||
| Line 244: | Line 226: | ||
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 272: | Line 262: | ||
return frame:expandTemplate{ title = "def", args = args } | return frame:expandTemplate{ title = "def", args = args } | ||
end | |||
local function _display_text_from_token(s) | |||
s = _trim(s) | |||
if s == "" then return "" end | |||
local _, key = _split_def_token(s) | |||
if key then return _humanize_key(key) end | |||
return s | |||
end | end | ||
| Line 292: | Line 291: | ||
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 | local function _value_has_content(val) | ||
if val == nil then return false end | |||
if | |||
if type(val) ~= "table" then | |||
return not _is_blankish(val) | |||
if type(val) ~= "table" then | |||
return not _is_blankish(val) | |||
end | end | ||
| Line 656: | Line 617: | ||
local s = _trim(it) | local s = _trim(it) | ||
if s == "" then return nil end | if s == "" then return nil end | ||
return { text = s } | return { text = s, page = s } | ||
end | end | ||
| Line 665: | Line 626: | ||
if text == "" then return nil end | if text == "" then return nil end | ||
local page = _safe_str(it.page or "", "") | local page = _safe_str(it.page or "", "") | ||
if page == "" then page = text end | |||
local suffix = _safe_str(it.suffix or "", "") | local suffix = _safe_str(it.suffix or "", "") | ||
return { text = text, page = (page ~= "" and page or nil), suffix = (suffix ~= "" and suffix or nil) } | return { text = text, page = (page ~= "" and page or nil), suffix = (suffix ~= "" and suffix or nil) } | ||
| Line 827: | Line 789: | ||
end | end | ||
local function | local function _build_meta_card(frame, parent, spec) | ||
spec = _safe_tbl(spec) | |||
local | local card = parent:tag("div") | ||
:addClass("sv-tile") | |||
:addClass("sv-meta-card") | |||
:addClass("sv-hover-lift") | |||
local icon_div = card:tag("div") | |||
:addClass("sv-meta-icon") | |||
:addClass("sv-tile") | |||
local icon_page = _safe_str(spec.icon_page, "") | |||
local icon_alt = _safe_str(spec.icon_alt, "") | |||
if icon_page ~= "" then | |||
icon_div:node(_render_file_image(icon_page, icon_alt, 24)) | |||
else | |||
icon_div:node(_question_badge()) | |||
end | |||
local wrap = card:tag("div"):addClass("sv-meta-textwrap") | |||
local text = wrap:tag("div"):addClass("sv-meta-text") | |||
local lines = _safe_tbl(spec.lines) | |||
if #lines > 0 then | |||
text:node(_meta_lines_def(frame, lines)) | |||
else | |||
text:wikitext("—") | |||
end | |||
_build_hitbox(card, "sv-meta-hit", frame, spec.hit_tok) | |||
end | |||
local function _build_meta_row(frame, meta_row) | |||
meta_row = _safe_tbl(meta_row) | |||
local hit_tok = "" | local meta = mw.html.create("div"):addClass("sv-skill-meta") | ||
for _, ln in ipairs(lines) do | for i = 1, 4 do | ||
local cell = _safe_tbl(meta_row[i]) | |||
local icon = _safe_tbl(cell.icon) | |||
local lines = _safe_tbl(cell.label_lines) | |||
local hit_tok = "" | |||
for _, ln in ipairs(lines) do | |||
local s = _safe_str(ln, "") | local s = _safe_str(ln, "") | ||
if _has_pipe(s) then | if _has_pipe(s) then | ||
| Line 870: | Line 839: | ||
end | end | ||
end | end | ||
_build_meta_card(frame, meta, { | |||
icon_page = _safe_str(icon.page, ""), | |||
icon_alt = _safe_str(icon.alt, ""), | |||
lines = lines, | |||
hit_tok = hit_tok, | |||
}) | |||
end | end | ||
| Line 890: | Line 857: | ||
for i = 1, 4 do | for i = 1, 4 do | ||
local cell = _safe_tbl(skill_meta[i]) | local cell = _safe_tbl(skill_meta[i]) | ||
local | local lines = _safe_tbl(cell.label_lines) | ||
local hit_tok = _safe_str(cell.label_wt, "") | |||
if #lines == 0 and hit_tok ~= "" then | |||
lines = { hit_tok } | |||
end | end | ||
_build_meta_card(frame, meta, { | |||
icon_page = _safe_str(cell.icon, ""), | |||
icon_alt = "", | |||
lines = lines, | |||
hit_tok = hit_tok, | |||
}) | |||
end | end | ||
| Line 1,128: | Line 1,067: | ||
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,145: | Line 1,085: | ||
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) | ||
local resolved_label = _safe_str(fld.label or fld.key, spec.label) | |||
local resolved_tok = _safe_str(fld.label_wt or fld.def_wt, spec.def_tok) | |||
local pill = parent:tag("div") | local pill = parent:tag("div") | ||
| Line 1,165: | Line 1,101: | ||
: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", resolved_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,183: | Line 1,120: | ||
pill:tag("div") | pill:tag("div") | ||
:addClass("sv_skill_scaling__core-label") | :addClass("sv_skill_scaling__core-label") | ||
:wikitext(mw.text.nowiki( | :wikitext(mw.text.nowiki(resolved_label)) | ||
_build_hitbox(pill, "sv_skill_scaling__core-hit", frame, resolved_tok) | |||
end | end | ||
| Line 1,258: | Line 1,197: | ||
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 | end | ||
| Line 1,265: | Line 1,204: | ||
end | end | ||
local function | local function _normalize_modifier_spec(item) | ||
item = _safe_tbl(item) | |||
local explicit_tok = _safe_str(item.label_wt or item.def_wt, "") | |||
local label_text = _safe_str(item.label or item.key or item.text, "") | |||
if label_text == "" and explicit_tok ~= "" then | |||
label_text = _display_text_from_token(explicit_tok) | |||
end | |||
return { | |||
label_tok = explicit_tok, | |||
label_text = label_text, | |||
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 | local has_def = _has_pipe(spec.label_tok) | ||
local | local has_value = _value_has_content(spec.value) | ||
local | local pill = parent:tag("div") | ||
:addClass("sv-tile") | |||
:addClass("sv-mech-mod-pill") | |||
:attr("aria-label", spec.label_text) | |||
if | if has_value then | ||
pill:addClass("is-active") | |||
else | |||
pill:addClass("is-inactive") | |||
end | end | ||
if | |||
if has_def or has_value then | |||
pill:addClass("sv-hover-lift") | |||
end | 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 _normalize_keyword_spec(item) | |||
if type(item) == "string" then | |||
local tok = _safe_str(item, "") | |||
local label = tok | |||
if _has_pipe(tok) then | |||
label = _display_text_from_token(tok) | |||
end | end | ||
return { | |||
label_tok = (_has_pipe(tok) and tok or ""), | |||
label_text = label, | |||
} | |||
end | |||
item = _safe_tbl(item) | |||
local tok = _safe_str(item.label_wt or item.def_wt, "") | |||
local label = _safe_str(item.label or item.text or item.key, "") | |||
if label == "" and tok ~= "" then | |||
label = _display_text_from_token(tok) | |||
end | end | ||
return { | |||
label_tok = tok, | |||
label_text = label, | |||
} | |||
end | |||
local | local function _build_keyword_pill(frame, parent, item) | ||
local spec = _normalize_keyword_spec(item) | |||
local display_text = _safe_str(spec.label_text, "") | |||
local hit_tok = _safe_str(spec.label_tok, "") | |||
if display_text == "" then return end | |||
local | local has_def = _has_pipe(hit_tok) | ||
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)) | |||
if has_def then | |||
_build_hitbox(pill, "sv-mech-keyword-pill__hit", frame, hit_tok) | |||
end | |||
end | |||
local function _build_tabs(frame, root_id, tabs_obj, level) | |||
tabs_obj = _safe_tbl(tabs_obj) | |||
local mechanics = _safe_tbl(tabs_obj.mechanics) | |||
local effects = _safe_tbl(tabs_obj.effects) | |||
local mechanics_mods = _safe_tbl(mechanics.mods) | |||
local mechanics_keywords = _safe_tbl(mechanics.keywords) | |||
local effects_cards = _safe_tbl(effects.cards) | |||
if #mechanics_mods == 0 then | |||
mechanics_mods = _safe_tbl(mechanics.grid) | |||
end | end | ||
if #mechanics_keywords == 0 then | |||
local old_keywords = _safe_tbl(tabs_obj.keywords) | |||
mechanics_keywords = _safe_tbl(old_keywords.pills) | |||
local | |||
end | end | ||
if #effects_cards == 0 then | |||
local old_events = _safe_tbl(tabs_obj.events) | |||
local merged = {} | |||
for _, card in ipairs(_safe_tbl(effects.cards)) do | |||
table.insert(merged, card) | |||
end | |||
for _, card in ipairs(_safe_tbl(old_events.cards)) do | |||
table.insert(merged, card) | |||
end | |||
effects_cards = merged | |||
end | |||
local mechanics_count = _to_int( | |||
mechanics.count, | |||
#mechanics_mods + #mechanics_keywords | |||
) | |||
local d = srow:tag("span") | local effects_count = _to_int( | ||
:addClass("sv-pill") | effects.count, | ||
:addClass("sv-pill--value") | #effects_cards | ||
:addClass("sv-ref-stat") | ) | ||
_apply_value(d, stats.duration, level) | |||
local tab_specs = { | |||
{ key = "mechanics", title = "Mechanics (" .. tostring(mechanics_count) .. ")" }, | |||
{ key = "effects", title = "Effects (" .. tostring(effects_count) .. ")" }, | |||
} | |||
local root = mw.html.create("div"):addClass("sv-skill-tabs") | |||
local tabs = root:tag("div") | |||
:addClass("sv-tabs") | |||
:attr("data-tabs", "1") | |||
:attr("data-tabs-root", root_id) | |||
local list = tabs:tag("div"):addClass("sv-tabs-list"):attr("role", "tablist") | |||
local panels = tabs:tag("div"):addClass("sv-tabs-panels") | |||
for i, spec in ipairs(tab_specs) do | |||
local active = (i == 1) | |||
list:tag("span") | |||
:addClass("sv-tab") | |||
:attr("role", "tab") | |||
:attr("tabindex", active and "0" or "-1") | |||
:attr("data-tab", spec.key) | |||
:attr("aria-selected", active and "true" or "false") | |||
:wikitext(mw.text.nowiki(spec.title)) | |||
end | |||
local function render_ref_icon(parent, icon) | |||
icon = _safe_tbl(icon) | |||
local page = _safe_str(icon.page, "") | |||
local alt = _safe_str(icon.alt, "") | |||
if page ~= "" then | |||
parent:node(_render_file_image(page, alt, 52)) | |||
else | |||
parent:node(_question_badge()) | |||
end | |||
end | |||
local function render_effect_stats(parent, stats, kind) | |||
stats = _safe_tbl(stats) | |||
kind = _safe_str(kind, ""):lower() | |||
if kind == "event" then | |||
local sub = parent:tag("div"):addClass("sv-ref-sub") | |||
if stats.text ~= nil then | |||
_apply_value(sub, stats, level) | |||
else | |||
_apply_value(sub, { text = "—" }, level) | |||
end | |||
return | |||
end | |||
if next(stats) ~= nil then | |||
local srow = parent:tag("div"):addClass("sv-ref-stats") | |||
local d = srow:tag("span") | |||
:addClass("sv-pill") | |||
:addClass("sv-pill--value") | |||
:addClass("sv-ref-stat") | |||
_apply_value(d, stats.duration, level) | |||
local c = srow:tag("span") | |||
:addClass("sv-pill") | |||
:addClass("sv-pill--value") | |||
:addClass("sv-ref-stat") | |||
_apply_value(c, stats.chance, level) | |||
local st = srow:tag("span") | |||
:addClass("sv-pill") | |||
:addClass("sv-pill--value") | |||
:addClass("sv-ref-stat") | |||
_apply_value(st, stats.stacks, level) | |||
end | |||
end | |||
local function render_ref_card(parent, card) | |||
card = _safe_tbl(card) | |||
local kind = _safe_str(card.kind, "") | |||
local title = _safe_str(card.title, "—") | |||
local page = _safe_str(card.page, "") | |||
local icon = _safe_tbl(card.icon) | |||
local container = parent:tag("div") | |||
:addClass("sv-tile") | |||
:addClass("sv-hover-lift") | |||
:addClass("sv-ref-card") | |||
if kind ~= "" then | |||
container:addClass("sv-ref-card--" .. _slugify(kind)) | |||
end | |||
local ico = container:tag("div") | |||
:addClass("sv-ref-ico") | |||
:addClass("sv-tile") | |||
render_ref_icon(ico, icon) | |||
local text = container:tag("div"):addClass("sv-ref-text") | |||
local title_div = text:tag("div"):addClass("sv-ref-title") | |||
if page ~= "" then | |||
title_div:wikitext(string.format("[[%s|%s]]", page, mw.text.nowiki(title))) | |||
else | |||
title_div:wikitext(mw.text.nowiki(title)) | |||
end | |||
render_effect_stats(text, card.stats, kind) | |||
end | end | ||
local | do | ||
local panel = panels:tag("div") | |||
:addClass("sv-tabpanel") | |||
:addClass("sv-mech-panel") | |||
:attr("role", "tabpanel") | |||
:attr("data-panel", "mechanics") | |||
local | local mods_wrap = panel:tag("div") | ||
local | :addClass("sv-mech-panel__group") | ||
:addClass("sv-mech-panel__group--mods") | |||
:addClass("sv-mech-panel__mods") | |||
local keys_wrap = panel:tag("div") | |||
:addClass("sv-mech-panel__group") | |||
:addClass("sv-mech-panel__group--keywords") | |||
:addClass("sv-mech-panel__keywords") | |||
if #mechanics_mods > 0 then | |||
mods_wrap:tag("div"):addClass("sv-tab-section-title"):wikitext("Modifiers") | |||
local gridwrap = mods_wrap:tag("div"):addClass("sv-mech-mod-grid") | |||
for _, item in ipairs(mechanics_mods) do | |||
_build_modifier_pill(frame, gridwrap, item, level) | |||
end | |||
end | end | ||
if #mechanics_keywords > 0 then | |||
keys_wrap:tag("div"):addClass("sv-tab-section-title"):wikitext("Keywords") | |||
local pills = keys_wrap:tag("div"):addClass("sv-tab-pills") | |||
for _, kw in ipairs(mechanics_keywords) do | |||
_build_keyword_pill(frame, pills, kw) | |||
end | |||
end | |||
if #mechanics_mods == 0 and #mechanics_keywords == 0 then | |||
panel:tag("div") | |||
:addClass("sv-tile") | |||
:addClass("sv-tab-empty") | |||
:wikitext("—") | |||
end | end | ||
end | end | ||
| Line 1,418: | Line 1,494: | ||
local panel = panels:tag("div") | local panel = panels:tag("div") | ||
:addClass("sv-tabpanel") | :addClass("sv-tabpanel") | ||
:addClass("sv- | :addClass("sv-hidden") | ||
:attr("role", "tabpanel") | :attr("role", "tabpanel") | ||
:attr("data-panel", " | :attr("data-panel", "effects") | ||
:attr("hidden", "hidden") | |||
local | if #effects_cards > 0 then | ||
local grid = panel:tag("div"):addClass("sv-ref-grid") | |||
:addClass("sv- | for _, card in ipairs(effects_cards) do | ||
render_ref_card(grid, card) | |||
end | |||
else | |||
panel:tag("div") | |||
:addClass("sv-tile") | |||
:addClass("sv-tab-empty") | |||
:wikitext("—") | |||
end | |||
end | |||
return root | |||
end | |||
local function _map_to_groups(map_tbl, preferred_order) | |||
local m = _safe_tbl(map_tbl) | |||
local function normalize_items(v) | |||
if type(v) == "table" then | |||
return v | |||
end | |||
if v == nil then | |||
return {} | |||
end | end | ||
return { v } | |||
end | |||
local used = {} | |||
local group_keys = {} | |||
local function push_key(k) | |||
k = tostring(k) | |||
if k ~= "" and not used[k] and m[k] ~= nil then | |||
used[k] = true | |||
table.insert(group_keys, k) | |||
end | end | ||
end | |||
local explicit = m.__order or m.order | |||
if type(explicit) == "table" then | |||
for _, k in ipairs(explicit) do | |||
push_key(k) | |||
end | end | ||
end | end | ||
if type(preferred_order) == "table" then | |||
for _, k in ipairs(preferred_order) do | |||
push_key(k) | |||
end | end | ||
end | end | ||
local rest = {} | |||
for k, _ in pairs(m) do | |||
k = tostring(k) | |||
local | if k ~= "__order" and k ~= "order" and not used[k] then | ||
table.insert(rest, k) | |||
if | |||
end | end | ||
end | |||
table.sort(rest) | |||
for _, k in ipairs(rest) do | |||
table.insert(group_keys, k) | |||
end | end | ||
local | local out_groups = {} | ||
local | for _, title in ipairs(group_keys) do | ||
local items = normalize_items(m[title]) | |||
local out_items = {} | |||
for _, it in ipairs(_safe_tbl(items)) do | |||
table.insert(out_items, it) | |||
table.insert( | |||
end | end | ||
table.insert(out_groups, { title = title, items = out_items }) | |||
end | end | ||
return out_groups | |||
end | |||
local function _build_req_users_native(root_id, requirements_map, users_map) | |||
local req_groups = _map_to_groups(requirements_map, { "Skills", "Weapon Types", "Stances" }) | |||
local usr_groups = _map_to_groups(users_map, { "Classes", "Monsters", "Summons" }) | |||
local | local req_box, req_n = _build_grouped_disclose(root_id, "req", "Requirements", req_groups) | ||
local usr_box, usr_n = _build_grouped_disclose(root_id, "usr", "Users", usr_groups) | |||
if req_n == 0 and usr_n == 0 then return nil end | |||
local row = mw.html.create("div"):addClass("sv-reqrow") | |||
if req_box then row:node(req_box) end | |||
if usr_box then row:node(usr_box) end | |||
return row | |||
end | |||
local function _build_req_users(root_id, requirements, users) | |||
requirements = _safe_tbl(requirements) | |||
users = _safe_tbl(users) | |||
local req_box, req_n = _build_grouped_disclose( | |||
root_id, "req", "Requirements", _safe_tbl(requirements.groups) | |||
) | |||
local usr_box, usr_n = _build_grouped_disclose( | |||
root_id, "usr", "Users", _safe_tbl(users.groups) | |||
) | |||
local req_box, req_n = _build_grouped_disclose(root_id, "req", "Requirements", | |||
local usr_box, usr_n = _build_grouped_disclose(root_id, "usr", "Users", | |||
if req_n == 0 and usr_n == 0 then return nil end | if req_n == 0 and usr_n == 0 then return nil end | ||
| Line 1,572: | Line 1,613: | ||
end | end | ||
local function | local function _append_meta_req_bubble(wrap, mod, node) | ||
if not node then return false end | |||
wrap:tag("div") | |||
:addClass("sv-skill-meta-block__bubble") | |||
:addClass("sv-skill-meta-block__bubble--" .. mod) | |||
:node(node) | |||
return true | |||
return | |||
end | end | ||
| Line 1,598: | Line 1,631: | ||
local count = 0 | local count = 0 | ||
if _append_meta_req_bubble(wrap, "meta", meta_node) then count = count + 1 end | |||
if | if _append_meta_req_bubble(wrap, "req", req_node) then count = count + 1 end | ||
if count == 1 then | if count == 1 then | ||
| Line 1,652: | Line 1,671: | ||
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,706: | Line 1,721: | ||
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( | ||