Files
YataiDONNijiiro/Scripts/dan_select/dan_select_base.lua
T
TaikoZhongandClaude Opus 5.5 01e2d72afe dan select: carry the parent's pre-2026-10-15 dan select as this skin's base
Upstream removed the exam grid, value centring, rank plate and total-notes options from PyTaikoGreen's dan_select.lua and moved its numbers into the script, so this skin fell back to the parent's plain exam rows with the parent's offsets (its own SKIN table never reached the parent's local one). dan_select_base.lua is the parent's script as of 4d325135 with those options fixed to this skin's values and the dropped keys given this skin's own numbers from before the migration; dan_select.lua loads it instead of the parent's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 21:58:32 +08:00

619 lines
27 KiB
Lua

-- Nijiiro's dan select base: PyTaikoGreen's dan_select.lua as of 4d325135, before upstream
-- (2026-10-15) dropped the exam grid, value centring, rank plate and total-notes options and
-- moved their numbers into its own script. Nijiiro still uses all of them, so it carries this
-- copy (loaded by dan_select.lua in place of the parent's). The options are fixed to Nijiiro's
-- values; keys upstream dropped have Nijiiro's own values from before the migration.
-- Generated by make_nj_dan_select_base.py; edit that, not this.
local LEGACY = {
dan_chip_name = { ["x"] = 0, ["y"] = 89, ["height"] = 88, ["font_size"] = 42 },
dan_exam_gauge_box = { ["x"] = 436, ["y"] = 610 },
dan_exam_info = { ["x"] = 40, ["y"] = 140, ["width"] = 984 },
dan_exam_label_pill = { ["x"] = 28, ["y"] = -1 },
dan_exam_score_box = { ["x"] = 769, ["y"] = 610, ["height"] = 132 },
dan_exam_seg = { ["x"] = 11, ["y"] = 47, ["width"] = 327 },
dan_exam_value = { ["x"] = 185, ["y"] = 40 },
dan_exam_value_center = { ["x"] = 633.0, ["width"] = -6.0 }, -- PyTaikoGreen's x 1.5
dan_hori_name = { ["x"] = 257, ["y"] = 380, ["width"] = 240 },
dan_level_counter_margin = { ["x"] = 34 },
dan_select_exam_border_text = { ["x"] = 309, ["y"] = 55, ["font_size"] = 25, ["outline"] = 2.6 },
dan_select_gauge_border_text = { ["x"] = 291, ["y"] = 67, ["font_size"] = 32, ["outline"] = 3.1 },
dan_select_total_notes = { ["x"] = 0 },
dan_subtitle = { ["x"] = 632, ["y"] = 262, ["height"] = 40, ["font_size"] = 22 },
dan_title = { ["x"] = 632, ["y"] = 262, ["height"] = 60, ["font_size"] = 36, ["outline"] = 2.6 },
dan_yellow_box_offset = { ["x"] = 0, ["y"] = 110 },
exam_counter_margin = { ["x"] = 44 },
exam_gauge_offset = { ["x"] = 0 },
song_box_name = { ["x"] = 0, ["y"] = 0, ["height"] = 120, ["font_size"] = 42 },
total_notes_counter_margin = { ["x"] = 44 },
yellow_box_bottom = { ["y"] = 974 },
}
local RENAMED = { dan_title = "dan_select_title", dan_subtitle = "dan_select_subtitle", dan_chip_name = "dan_select_chip_name", song_box_name = "song_select_box_name", dan_exam_info = "dan_select_exam_info" }
local OPTS = { dan_confirm_yes_left = false, dan_exam_grid = true, dan_exam_value_center = true, dan_select_rank_plate = true }
DanSelect = {}
DanSelect.__index = DanSelect
local _tex = {}
local function T(subset, name)
local key = subset .. "/" .. name
local id = _tex[key]
if id == nil then
id = tex.get_texture("dan_select/" .. subset .. "/" .. name)
_tex[key] = id
end
return id
end
local function cfg(name)
return (RENAMED[name] and tex.get_skin_config(RENAMED[name])) or tex.get_skin_config(name) or LEGACY[name]
end
local function opt(name)
return OPTS[name]
end
-- Texture draw-offset at index 0 (TextureObject::x[0] / y[0] / x2[0]).
local function tex_x0(subset, name)
local info = tex.get_texture_info(subset, name)
if info and info.x and info.x[1] then return info.x[1] end
return 0
end
local function tex_y0(subset, name)
local info = tex.get_texture_info(subset, name)
if info and info.y and info.y[1] then return info.y[1] end
return 0
end
local function tex_x2(subset, name)
local info = tex.get_texture_info(subset, name)
if info and info.x2 and info.x2[1] then return info.x2[1] end
return 0
end
-- exam.type -> icon texture name (exam_icon_id in box_dan.cpp). "renda" resolves to
-- exam_roll, falling back to exam_drumroll in older skins. Returns the resolved name.
local EXAM_ICON = {
gauge = "exam_gauge", combo = "exam_combo",
hit = "exam_hit", judgebad = "exam_judgebad",
judgegood = "exam_judgegood", judgeperfect = "exam_judgeperfect",
score = "exam_score", renda = "exam_roll",
}
local function exam_icon_name(type)
local name = EXAM_ICON[type]
if not name then return nil end
if T("yellow_box", name) then return name end
if T("yellow_box", "exam_drumroll") then return "exam_drumroll" end
return nil
end
local yb_box = { path = nil, state = "closed" }
function DanSelect.new()
local self = setmetatable({ now = 0 }, DanSelect)
yb_box.path, yb_box.state = nil, "closed"
return self
end
local YB_DIFF_ANIMS = { 13, 14, 15, 16, 17, 18 }
local function draw_dan_yellow_box(is_diff, fade)
local right_x = tex.get_animation(is_diff and 14 or 10).attribute
local left_x = tex.get_animation(is_diff and 13 or 9).attribute
local center_width = tex.get_animation(is_diff and 15 or 11).attribute
local top_y = tex.get_animation(16).attribute
local center_height = tex.get_animation(17).attribute
local bottom_y = (cfg("yellow_box_bottom") or { y = 0 }).y
local info = tex.get_texture_info("yellow_box", "yellow_box_bottom_right")
local eh = (info and info.height) or 0
tex.draw_texture(T("yellow_box", "yellow_box_bottom_right"), { x = right_x, y = bottom_y, fade = fade })
tex.draw_texture(T("yellow_box", "yellow_box_bottom_left"), { x = left_x, y = bottom_y, fade = fade })
tex.draw_texture(T("yellow_box", "yellow_box_top_right"), { x = right_x, y = top_y, fade = fade })
tex.draw_texture(T("yellow_box", "yellow_box_top_left"), { x = left_x, y = top_y, fade = fade })
tex.draw_texture(T("yellow_box", "yellow_box_bottom"), { x = left_x + eh, y = bottom_y, x2 = center_width, fade = fade })
tex.draw_texture(T("yellow_box", "yellow_box_right"), { x = right_x, y = top_y + eh, y2 = center_height, fade = fade })
tex.draw_texture(T("yellow_box", "yellow_box_left"), { x = left_x, y = top_y + eh, y2 = center_height, fade = fade })
tex.draw_texture(T("yellow_box", "yellow_box_top"), { x = left_x + eh, y = top_y, x2 = center_width, fade = fade })
tex.draw_texture(T("yellow_box", "yellow_box_center"), { x = left_x + eh, y = top_y + eh, x2 = center_width, y2 = center_height, fade = fade })
end
-- Track the open box and start the diff-select expansion on the closed -> diff_select
-- transition (the dan box never passes through the "open" draw_state).
local function track_dan_yellow_box(box)
local state = box:draw_state()
local path = box:path()
if state == "closed" then
if yb_box.path == path then
yb_box.path, yb_box.state = nil, "closed"
end
return
end
if yb_box.path ~= path then
yb_box.path, yb_box.state = path, state
for _, id in ipairs(YB_DIFF_ANIMS) do tex.get_animation(id):reset() end
for _, id in ipairs(YB_DIFF_ANIMS) do tex.get_animation(id):start() end
end
end
local function update_dan_yellow_box(ms)
for _, id in ipairs(YB_DIFF_ANIMS) do tex.get_animation(id):update(ms) end
end
function DanSelect:update(ms)
self.now = ms
update_dan_yellow_box(ms)
end
local function draw_tex(subset, name, params)
local id = T(subset, name)
if id then tex.draw_texture(id, params) end
end
function DanSelect:draw_back()
draw_tex("global", "bg", {})
draw_tex("global", "bg_header", {})
draw_tex("global", "bg_footer", {})
draw_tex("global", "footer", {})
end
function DanSelect:draw_cursor(pos, now, since_move)
if since_move < 0 or since_move >= 967 then return true end
local p = since_move / 967
local drift = 30 * p
local fade = 0.984 * (1 - p)
draw_tex("global", "arrow", { index = 0, x = -drift, fade = fade })
draw_tex("global", "arrow", { index = 1, x = drift, fade = fade, mirror = "horizontal" })
return true
end
function DanSelect:draw_title()
draw_tex("global", "dan_select", {})
end
local CONFIRM_OPTION, CONFIRM_YES = 0, 1
-- fade: confirm_fade attribute; index: 0 option / 1 yes / 2 no
function DanSelect:draw_confirm(f, index)
if f <= 0 then return end
tex.draw_rect(0, 0, tex.get_screen_width(), tex.get_screen_height(), 0, 0, 0, math.min(0.5, f) * 255)
draw_tex("confirm_box", "bg", { fade = f })
draw_tex("confirm_box", "confirmation_text", { fade = f })
for i = 0, 1 do
draw_tex("confirm_box", "selection_box", { fade = f, index = i })
end
if index ~= CONFIRM_OPTION then
-- selection_box slots are screen-left / screen-right; yes sits right of no unless swapped
local yes_info = tex.get_texture_info("confirm_box", "yes")
local no_info = tex.get_texture_info("confirm_box", "no")
local yes_right = yes_info and no_info and yes_info.x[1] > no_info.x[1]
local side = ((index == CONFIRM_YES) == (yes_right and true or false)) and 1 or 0
draw_tex("confirm_box", "selection_box_highlight", { fade = f, index = side })
draw_tex("confirm_box", "selection_box_outline", { fade = f, index = side })
end
local swap_dx = 0
if opt("dan_confirm_yes_left") then
local info = tex.get_texture_info("confirm_box", "selection_box")
if info and info.x and #info.x >= 2 then swap_dx = info.x[2] - info.x[1] end
end
draw_tex("confirm_box", "yes", { x = -swap_dx, fade = f })
draw_tex("confirm_box", "no", { x = swap_dx, fade = f })
if T("confirm_box", "option") then
if index == CONFIRM_OPTION then draw_tex("confirm_box", "option_highlight", { fade = f }) end
draw_tex("confirm_box", "option", { fade = f })
end
end
-- Draw a texture at an absolute position, ignoring its own x[0]/y[0] anchor (draw_abs).
local function draw_abs(subset, name, X, Y, fade, frame)
local id = T(subset, name)
if not id then return end
tex.draw_texture(id, {
frame = frame or 0,
x = X - tex_x0(subset, name),
y = Y - tex_y0(subset, name),
fade = fade,
})
end
local BACK_CX, BACK_BOTTOM, BACK_HALF0, BACK_HALF1 = 642, 539, 44.4, 191
local BACK_TOP0, BACK_TOP1, BACK_GROW_MS = 338 - 228, 338 - 231, 150
function DanSelect:draw_back_box(box)
local bx = box:box_x()
local fade = box.fade.attribute
tex.draw_texture(T("back", "folder"), { x = bx, fade = fade })
if box:draw_state() == "closed" then
self.back_open_at = nil
tex.draw_texture(T("back", "chip"), { x = bx, fade = fade })
return
end
self.back_open_at = self.back_open_at or self.now
local ms = self.now - self.back_open_at
local u = math.min(math.max(ms / BACK_GROW_MS, 0), 1)
local half = BACK_HALF0 + (BACK_HALF1 - BACK_HALF0) * u
local top = BACK_TOP0 + (BACK_TOP1 - BACK_TOP0) * u
local l, r = BACK_CX - half, BACK_CX + half - 32
local w, h = r - l - 32, BACK_BOTTOM - top - 32
local function piece(name, x, y, x2, y2)
tex.draw_texture(T("back", name), { x = x, y = y, x2 = x2 and x2 - 32 or 0, y2 = y2 and y2 - 32 or 0 })
end
piece("board_tl", l, top); piece("board_t", l + 32, top, w)
piece("board_tr", r, top); piece("board_r", r, top + 32, nil, h)
piece("board_br", r, BACK_BOTTOM); piece("board_b", l + 32, BACK_BOTTOM, w)
piece("board_bl", l, BACK_BOTTOM); piece("board_l", l, top + 32, nil, h)
piece("board_c", l + 32, top + 32, w, h)
local f = math.min(math.max((ms - 33) / 117, 0), 1)
for _, name in ipairs({ "graphic", "text", "pill" }) do tex.draw_texture(T("back", name), { fade = f }) end
end
function DanSelect:draw_box(box)
if box.is_back then return self:draw_back_box(box) end
track_dan_yellow_box(box)
local state = box:draw_state()
if state == "closed" then
self:draw_dan_closed(box)
else
self:draw_dan_open(box)
end
end
-- ---------------------------------------------------------------------------
-- draw_chip (closed): folder board + vertical chip name.
-- ---------------------------------------------------------------------------
function DanSelect:draw_dan_closed(box)
local bx = box:box_x()
local fade = box.fade.attribute
tex.draw_texture(T("box", "folder"), { frame = box.dan_color, x = bx, fade = fade })
if box.clear_mark > 0 and T("box", "clear_mark") then
tex.draw_texture(T("box", "clear_mark"), { frame = box.clear_mark - 1, x = bx, fade = fade })
end
local name = box:chip_name()
if name then
local nb = cfg("dan_chip_name") or cfg("song_box_name") or { x = 0, y = 0, height = 0 }
name:draw({
x = bx + nb.x - name.width / 2,
y = nb.y,
y2 = math.min(name.height, nb.height or name.height) - name.height,
fade = fade,
})
end
end
-- ---------------------------------------------------------------------------
-- draw_open: chip + song ribbon + total notes + rank + exam box.
-- ---------------------------------------------------------------------------
function DanSelect:draw_dan_open(box)
self:draw_dan_closed(box)
local f = box.open_fade.attribute
-- The yellow box board the course details sit on (opaque; its growth is driven by
-- the diff-select animations, matching the song-select wheel).
draw_dan_yellow_box(true, 1.0)
local off = cfg("dan_yellow_box_offset") or { x = 0, y = 0 }
local offset_x = off.x or 0
local offset_y = off.y or 0
local n = box:song_count()
for i = 0, n - 1 do
local x = i * offset_x
local y = i * offset_y
tex.draw_texture(T("yellow_box", "genre_banner"), { frame = box:song_genre(i), x = x, y = y, fade = f })
local song_label = T("yellow_box", "song_label")
if song_label then
tex.draw_texture(song_label, { frame = math.min(i, 2), x = x, y = y, fade = f })
end
tex.draw_texture(T("yellow_box", "difficulty"), { frame = box:song_difficulty(i), x = x, y = y, fade = f })
if box:song_difficulty(i) == 4 and T("yellow_box", "difficulty_ura") then
tex.draw_texture(T("yellow_box", "difficulty_ura"), { x = x, y = y, fade = f })
end
tex.draw_texture(T("yellow_box", "difficulty_x"), { x = x, y = y, fade = f })
tex.draw_texture(T("yellow_box", "difficulty_star"), { x = x, y = y, fade = f })
-- Level counter
local lvl = tostring(box:song_level(i))
local margin = (cfg("dan_level_counter_margin") or { x = 0 }).x
local total_w = #lvl * margin
for j = 1, #lvl do
local digit = string.byte(lvl, j) - 48
tex.draw_texture(T("yellow_box", "difficulty_num"), {
frame = digit, x = x - total_w / 2 + (j - 1) * margin, y = y, fade = f })
end
-- Song title + subtitle
local title_text = box:song_title_text(i)
local sub_text = box:song_subtitle_text(i)
local td = cfg("dan_title") or { x = 0, y = 0, height = 0 }
local sd = cfg("dan_subtitle") or { x = 0, y = 0, height = 0 }
if box:song_masked(i) and T("yellow_box", "hidden_title") then
tex.draw_texture(T("yellow_box", "hidden_title"), { x = x, y = y, fade = f })
elseif title_text then
title_text:draw({
x = td.x + x, y = td.y + y,
y2 = math.min(title_text.height, td.height or title_text.height) - title_text.height,
fade = f })
end
if sub_text then
sub_text:draw({
x = sd.x + x,
y = sd.y + y - math.min(sub_text.height, sd.height or sub_text.height),
y2 = math.min(sub_text.height, sd.height or sub_text.height) - sub_text.height,
fade = f })
end
end
if box.clear_mark > 0 and T("yellow_box", "clear_mark") then
tex.draw_texture(T("yellow_box", "clear_mark"), { frame = box.clear_mark - 1, fade = f })
end
-- Total notes
tex.draw_texture(T("yellow_box", "total_notes_bg"), { fade = f })
local tn_slot = cfg("dan_select_total_notes")
if not tn_slot or tn_slot.x >= 1.0 then
tex.draw_texture(T("yellow_box", "total_notes"), { fade = f })
local tn = tostring(box.total_notes)
local tn_margin = (cfg("total_notes_counter_margin") or { x = 0 }).x
for i = 1, #tn do
local digit = string.byte(tn, i) - 48
-- Lumen centres the counter on its 4-digit width
tex.draw_texture(T("yellow_box", "total_notes_counter"), { frame = digit, x = (i - 1 + (4 - #tn) / 2) * tn_margin, fade = f })
end
end
-- Rank plate / frame
if box.dan_rank >= 0 and opt("dan_select_rank_plate") then
tex.draw_texture(T("yellow_box", "rank_plate"), { frame = box.dan_rank, fade = f })
else
tex.draw_texture(T("yellow_box", "frame"), { frame = box.dan_color, fade = f })
local hori = box:hori_name()
if hori then
local hn = cfg("dan_hori_name") or { x = 0, y = 0, width = 0 }
hori:draw({
x = hn.x - hori.width / 2,
y = hn.y,
x2 = math.min(hori.width, hn.width or hori.width) - hori.width,
fade = f })
end
end
self:draw_exam_box(box, f)
end
-- ---------------------------------------------------------------------------
-- Exam board (the default "condition rows" layout).
-- ---------------------------------------------------------------------------
function DanSelect:draw_exam_box(box, f)
if opt("dan_exam_grid") then
self:draw_exam_grid(box, f)
return
end
local offset_y = (cfg("dan_exam_info") or { y = 0 }).y
local margin = (cfg("exam_counter_margin") or { x = 0 }).x
-- Four or more conditions do not fit the board: drop the soul-gauge row.
local exam_count = box:exam_count()
local shown = {}
for i = 0, exam_count - 1 do
if not (exam_count >= 4 and box:exam_type(i) == "gauge") then
shown[#shown + 1] = i
end
end
if #shown > 3 then
while #shown > 3 do shown[#shown] = nil end
end
local L = ({ { dt = 38, row0 = 90, pitch = 0 }, { dt = 18, row0 = 37, pitch = 106 } })[#shown]
or { dt = 0, row0 = 0, pitch = offset_y }
local dt = L.dt
local function part(name, p)
p.fade = f
tex.draw_texture(T("yellow_box", name), p)
end
part("exam_box_bottom_right", { y = -dt })
part("exam_box_bottom_left", { y = -dt })
part("exam_box_top_right", { y = dt })
part("exam_box_top_left", { y = dt })
part("exam_box_bottom", { y = -dt })
part("exam_box_right", { y = dt, y2 = -2 * dt })
part("exam_box_left", { y = dt, y2 = -2 * dt })
part("exam_box_top", { y = dt })
part("exam_box_center", { y = dt, y2 = -2 * dt })
part("exam_header", { y = dt })
for idx = 1, #shown do
local i = shown[idx]
local y = L.row0 + (idx - 1) * L.pitch
local etype = box:exam_type(i)
local range = box:exam_range(i)
tex.draw_texture(T("yellow_box", "judge_box"), { y = y, fade = f })
local icon_name = exam_icon_name(etype)
if icon_name then tex.draw_texture(T("yellow_box", icon_name), { y = y, fade = f }) end
if opt("dan_exam_value_center") then
-- Centre the whole value (digits, %, suffix) on dan_exam_value_center.x.
local vc = cfg("dan_exam_value_center") or { x = 0, width = 0 }
local digits = tostring(box:exam_red(i))
local pct = (etype == "gauge") and T("yellow_box", "exam_percent") or nil
local suf = (range == "more") and T("yellow_box", "exam_more")
or (range == "less") and T("yellow_box", "exam_less") or nil
local digits_w = (#digits - 1) * margin + tex_x2("yellow_box", "judge_num")
local pct_w = pct and tex_x2("yellow_box", "exam_percent") or 0
local suf_w = suf and tex_x2("yellow_box", (range == "more") and "exam_more" or "exam_less") or 0
local gap = vc.width or 0
local parts = 1 + (pct and 1 or 0) + (suf and 1 or 0)
local total = digits_w + pct_w + suf_w + gap * (parts - 1)
local cx = (vc.x or 0) - total / 2
for j = 1, #digits do
local digit = string.byte(digits, j) - 48
tex.draw_texture(T("yellow_box", "judge_num"),
{ frame = digit, x = cx + (j - 1) * margin - tex_x0("yellow_box", "judge_num"), y = y, fade = f })
end
cx = cx + digits_w + gap
if pct then
tex.draw_texture(pct, { x = cx - tex_x0("yellow_box", "exam_percent"), y = y, fade = f })
cx = cx + pct_w + gap
end
if suf then
local suf_name = (range == "more") and "exam_more" or "exam_less"
tex.draw_texture(suf, { x = cx - tex_x0("yellow_box", suf_name), y = y, fade = f })
end
else
local x_offset = 0
if etype == "gauge" then
tex.draw_texture(T("yellow_box", "exam_percent"), { y = y, fade = f })
x_offset = (cfg("exam_gauge_offset") or { x = 0 }).x
end
local counter = tostring(box:exam_red(i))
for j = 1, #counter do
local digit = string.byte(counter, j) - 48
local x = x_offset - (#counter - j + 1) * margin
tex.draw_texture(T("yellow_box", "judge_num"), { frame = digit, x = x, y = y, fade = f })
end
if range == "more" then
tex.draw_texture(T("yellow_box", "exam_more"), { x = -x_offset * 1.7, y = y, fade = f })
elseif range == "less" then
tex.draw_texture(T("yellow_box", "exam_less"), { x = -x_offset * 1.7, y = y, fade = f })
end
end
end
end
-- ---------------------------------------------------------------------------
-- Exam board grid mode (dan_exam_grid option): a two-column gauge/score layout.
-- ---------------------------------------------------------------------------
local function caption(self, str, font_size, outline)
self._captions = self._captions or {}
local key = str .. "\0" .. tostring(font_size) .. "\0" .. tostring(outline)
local cap = self._captions[key]
if cap == nil then
cap = text.create_raw_text(str, font_size, { 255, 255, 255, 255 }, { 0, 0, 0, 255 }, false, outline)
self._captions[key] = cap
end
return cap
end
local function draw_value_text(self, cap_str, bt, right_x, top_y, f)
if not bt then return false end
local ol = (bt.outline and bt.outline >= 0) and bt.outline or (3.0 / tex.get_screen_scale())
local size = (bt.font_size and bt.font_size > 0) and bt.font_size or 28
local cap = caption(self, cap_str, size, ol)
if not cap then return false end
local pad = math.floor(ol * tex.get_screen_scale()) + 2
cap:draw({ x = right_x - cap.width + pad, y = top_y - pad, fade = f })
return true
end
-- draw_value (grid mode): centred digits + optional percent/suffix, absolute anchors.
local function draw_value(self, red, etype, range, centre_x, top_y, f)
local digits = tostring(red)
local margin = (cfg("exam_counter_margin") or { x = 0 }).x
local pct_w = 0
if etype == "gauge" and T("yellow_box", "exam_percent") then
pct_w = tex_x2("yellow_box", "exam_percent")
end
local suffix = (range == "less") and "exam_less" or (range == "more") and "exam_more" or nil
local suf_w = 0
if suffix and T("yellow_box", suffix) then
suf_w = tex_x2("yellow_box", suffix)
end
local total = #digits * margin + pct_w + suf_w
local cx = centre_x - total * 0.5
for j = 1, #digits do
local digit = string.byte(digits, j) - 48
draw_abs("yellow_box", "judge_num", cx, top_y, f, digit)
cx = cx + margin
end
if pct_w > 0 then
draw_abs("yellow_box", "exam_percent", cx, top_y + 8, f)
cx = cx + pct_w
end
if suf_w > 0 then
draw_abs("yellow_box", suffix, cx, top_y + 6, f)
end
end
function DanSelect:draw_exam_grid(box, f)
local exam_frame = T("yellow_box", "exam_frame")
if exam_frame then tex.draw_texture(exam_frame, { fade = f }) end
tex.draw_texture(T("yellow_box", "exam_header"), { fade = f })
local gb = cfg("dan_exam_gauge_box")
local sb = cfg("dan_exam_score_box")
local gx = (gb and gb.x) or 436.0
local gy = (gb and gb.y) or 615.0
local sx = (sb and sb.x) or 769.0
local sy = (sb and sb.y) or 615.0
local pitch = (sb and sb.height and sb.height > 0) and sb.height or 132.0
local sg = cfg("dan_exam_seg")
local seg_x = (sg and sg.x) or 14.0
local seg_y = (sg and sg.y) or 48.0
local seg_dx = (sg and sg.width and sg.width > 0) and sg.width or 327.0
local vp = cfg("dan_exam_value")
local val_x = (vp and vp.x) or 185.0
local val_y = (vp and vp.y) or 40.0
local pp = cfg("dan_exam_label_pill")
local pill_x = (pp and pp.x) or 26.0
local pill_y = (pp and pp.y) or 2.0
local seg_bt = cfg("dan_select_exam_border_text")
local gauge_bt = cfg("dan_select_gauge_border_text")
local right_row = 0
local gauge_used = false
local exam_count = box:exam_count()
for i = 0, exam_count - 1 do
local etype = box:exam_type(i)
local range = box:exam_range(i)
local left = (etype == "gauge" and not gauge_used)
if left then gauge_used = true end
-- The cabinet has three right-side slots; skip (don't stop) further right rows.
if left or right_row < 3 then
local BX = left and gx or sx
local BY = left and gy or (sy + pitch * right_row)
draw_abs("yellow_box", left and "exam_gauge_box" or "judge_box",
BX - (left and 0 or 3), BY - (left and 0 or 2), f)
local icon_name = exam_icon_name(etype)
if icon_name then draw_abs("yellow_box", icon_name, BX + pill_x, BY + pill_y, f) end
if left then
if not draw_value_text(self, box:exam_caption(i), gauge_bt,
BX + ((gauge_bt and gauge_bt.x) or 0),
BY + ((gauge_bt and gauge_bt.y) or 0), f) then
draw_value(self, box:exam_red(i), etype, range, BX + 181.0, BY + 45.0, f)
end
else
local gothrough = box:exam_gothrough(i)
local segs = gothrough and 1 or math.min(box:song_count(), 3)
for k = 0, segs - 1 do
local frame = gothrough and 0 or (k + 1)
draw_abs("yellow_box", "exam_seg_label", BX + seg_x + seg_dx * k, BY + seg_y, f, frame)
local red = gothrough and box:exam_red(i) or box:exam_song_red(i, k)
if not draw_value_text(self, box:exam_song_caption(i, k), seg_bt,
BX + ((seg_bt and seg_bt.x) or 0) + seg_dx * k,
BY + ((seg_bt and seg_bt.y) or 0), f) then
draw_value(self, red, etype, range, BX + val_x + seg_dx * k, BY + val_y, f)
end
end
end
if not left then right_row = right_row + 1 end
end
end
end