dan select: back chip, chip names, cursor and course rows #63

Merged
GanYiZhong merged 1 commits from GanYiZhong/YataiDONNijiiro:feat/dan-select-back-chip into main 2026-10-14 09:13:50 +02:00
16 changed files with 231 additions and 9 deletions

No files matched your search

Binary file not shown.
+6
View File
@@ -0,0 +1,6 @@
{
"folder": {
"x": -44,
"y": 16
}
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+6 -2
View File
@@ -190,7 +190,7 @@
}, },
"song_label": { "song_label": {
"x": 430, "x": 430,
"y": 230 "y": 246
}, },
"exam_seg_label": { "exam_seg_label": {
"x": 0, "x": 0,
@@ -204,5 +204,9 @@
"x": 100, "x": 100,
"y": 505 "y": 505
}, },
"difficulty_ura": {} "difficulty_ura": {},
"difficulty_level": {
"x": 538,
"y": 287
}
} }
+14
View File
@@ -45,6 +45,7 @@
"combo_color_tiers": true, "combo_color_tiers": true,
"gauge_cell_fade_in": true, "gauge_cell_fade_in": true,
"dan_exam_grid": true, "dan_exam_grid": true,
"dan_chip_name_black": true,
"disable_chara_3d": false "disable_chara_3d": false
} }
}, },
@@ -833,6 +834,19 @@
"height": 88, "height": 88,
"font_size": 42 "font_size": 42
}, },
"dan_back_label": {
"x": 0,
"y": 89,
"width": 60,
"height": 88,
"font_size": 42,
"text": {
"en": "Back",
"ja": "戻る",
"zh": "返回",
"ko": "뒤로"
}
},
"dan_result_chara": { "dan_result_chara": {
"x": 187, "x": 187,
"y": 934 "y": 934
+169 -7
View File
@@ -47,12 +47,14 @@ function DanSelect.new()
end end
-- pos: selected chip x (the textures' own json positions carry the rest); -- pos: selected chip x (the textures' own json positions carry the rest);
-- now_ms: engine clock; moved_ms: ms since the last ribbon step (-1 = never). -- now_ms: engine clock; moved_ms: ms since the last ribbon step (-1 = never);
local function draw_cursor(self, pos, now_ms, moved_ms) -- y: how far the selected chip has dropped (see draw_box below).
local function draw_cursor(self, pos, now_ms, moved_ms, y)
y = y or 0
if self.t_cursor then if self.t_cursor then
local f = (now_ms * 0.06) % 60 local f = (now_ms * 0.06) % 60
local a = CUR:get("#259@0", f, "a") or 1 local a = CUR:get("#259@0", f, "a") or 1
tex.draw_texture(self.t_cursor, { x = pos, fade = a }) tex.draw_texture(self.t_cursor, { x = pos, y = y, fade = a })
end end
if moved_ms and moved_ms >= 0 then if moved_ms and moved_ms >= 0 then
local f = moved_ms * 0.06 local f = moved_ms * 0.06
@@ -61,10 +63,10 @@ local function draw_cursor(self, pos, now_ms, moved_ms)
local a = ARW:get("#261@0", f, "a") or 0 local a = ARW:get("#261@0", f, "a") or 0
if a > 0 then if a > 0 then
if self.t_arrow_r then if self.t_arrow_r then
tex.draw_texture(self.t_arrow_r, { x = pos + drift, fade = a }) tex.draw_texture(self.t_arrow_r, { x = pos + drift, y = y, fade = a })
end end
if self.t_arrow_l then if self.t_arrow_l then
tex.draw_texture(self.t_arrow_l, { x = pos - drift, fade = a }) tex.draw_texture(self.t_arrow_l, { x = pos - drift, y = y, fade = a })
end end
end end
end end
@@ -73,6 +75,15 @@ end
if HAS_CLIPS then DanSelect.draw_cursor = draw_cursor end if HAS_CLIPS then DanSelect.draw_cursor = draw_cursor end
-- The level is the cabinet's own art, one "star + number" image per level
-- (yellow_box/difficulty_level, frames 1..10 and 10+), in place of the parent's star and
-- level digits, which are held back.
local function draw_level(level, x, y, f)
local id = tex.get_texture("dan_select/yellow_box/difficulty_level")
if not id or level < 1 then return end
tex.draw_texture(id, { frame = math.min(level, 11) - 1, x = x, y = y, fade = f })
end
-- The course's clear stamp (yellow_box/clear_mark) sits over the dan plate and Don, as the -- The course's clear stamp (yellow_box/clear_mark) sits over the dan plate and Don, as the
-- cabinet's stamp_detail does (it is above don_1p). The parent draws it with the box, under -- cabinet's stamp_detail does (it is above don_1p). The parent draws it with the box, under
-- both, so it is held back there and drawn with the title, which the engine draws after -- both, so it is held back there and drawn with the title, which the engine draws after
@@ -82,16 +93,35 @@ local held_stamp -- shared: the boxes and the title can be drawn through diffe
if parent_open then if parent_open then
function DanSelect:draw_dan_open(box) function DanSelect:draw_dan_open(box)
local stamp = tex.get_texture("dan_select/yellow_box/clear_mark") local stamp = tex.get_texture("dan_select/yellow_box/clear_mark")
if not stamp or box.clear_mark <= 0 then return parent_open(self, box) end local level = tex.get_texture("dan_select/yellow_box/difficulty_level")
local hide = {}
if level then
for _, n in ipairs({ "difficulty_star", "difficulty_num", "difficulty_x" }) do
local t = tex.get_texture("dan_select/yellow_box/" .. n)
if t then hide[#hide + 1] = t end
end
end
local draw = tex.draw_texture local draw = tex.draw_texture
tex.draw_texture = function(id, p) tex.draw_texture = function(id, p)
if id == stamp then return end if id == stamp then return end
for _, t in ipairs(hide) do -- handles compare with ==, not as table keys
if id == t then return end
end
return draw(id, p) return draw(id, p)
end end
local ok, err = pcall(parent_open, self, box) local ok, err = pcall(parent_open, self, box)
tex.draw_texture = draw tex.draw_texture = draw
if not ok then error(err, 0) end if not ok then error(err, 0) end
held_stamp = { id = stamp, frame = box.clear_mark - 1, fade = box.open_fade.attribute } local f = box.open_fade.attribute
local off = tex.get_skin_config("dan_yellow_box_offset") or { x = 0, y = 0 }
if level then
for i = 0, box:song_count() - 1 do
draw_level(box:song_level(i), i * (off.x or 0), i * (off.y or 0), f)
end
end
if stamp and box.clear_mark > 0 then
held_stamp = { id = stamp, frame = box.clear_mark - 1, fade = f }
end
end end
function DanSelect:draw_title() function DanSelect:draw_title()
@@ -101,3 +131,135 @@ if parent_open then
if s then tex.draw_texture(s.id, { frame = s.frame, fade = s.fade }) end if s then tex.draw_texture(s.id, { frame = s.frame, fade = s.fade }) end
end end
end end
-- The back entry is one more chip in the top strip (back/folder, laid out like box/folder);
-- the parent's opening board is its own layout, so nothing opens under it here.
-- Its label comes from skin_config dan_back_label, so it follows the language setting. It is set
-- like the dan chip names (black, no outline: dan_chip_name_black), vertical for CJK and
-- across, squeezed to the chip, for other languages.
local CJK = { ja = true, zh = true, ko = true, tw = true, cn = true }
local back_label
local function get_back_label()
if back_label == nil then
local cfg = tex.get_skin_config("dan_back_label")
if not cfg then back_label = false; return false end
local lang = tex.language()
local vertical = CJK[lang] or CJK[lang:sub(1, 2)] or false
back_label = {
cfg = cfg,
vertical = vertical,
main = text.create_raw_text(tex.skin_text("dan_back_label"), cfg.font_size,
{ 0, 0, 0, 255 }, { 0, 0, 0, 255 }, vertical, 0, 2),
}
end
return back_label
end
local function draw_back_label(bx, fade, y)
local label = get_back_label()
if not label then return end
local cfg, main = label.cfg, label.main
local sx, sy = 1, 1
if label.vertical then
sy = math.min(1, cfg.height / main.height)
else
sx = math.min(1, cfg.width / main.width) -- width: chip face less the border
end
local w, h = main.width * sx, main.height * sy
main:draw({ x = bx + cfg.x - w / 2, y = cfg.y + (cfg.height - h) / 2 + y,
x2 = w - main.width, y2 = h - main.height, fade = fade })
end
-- The selected chip drops below the strip, as the cabinet's does, easing there and back.
-- Only draw_cursor (called after every box) is told where the cursor is, so the boxes are
-- held back in draw_box and drawn from draw_cursor.
local SELECTED_DROP = 22
local DROP_MS = 60 -- time constant of the ease
local drop = {} -- chip key -> current drop
local held_boxes = {}
local last_ms
local function chip_key(box)
return box.is_back and "\0back" or box.text_name
end
local function chip_drop(box)
return drop[chip_key(box)] or 0
end
local function draw_chip_name(box, bx, y, fade)
local name = box:chip_name()
if not name then return end
local nb = tex.get_skin_config("dan_chip_name") or { x = 0, y = 0 }
name:draw({
x = bx + nb.x - name.width / 2,
y = nb.y + y,
y2 = math.min(name.height, nb.height or name.height) - name.height,
fade = fade,
})
end
-- the chip as the parent draws it (folder, stamp, name), at its drop
function DanSelect:draw_dan_closed(box)
local bx, fade, y = box:box_x(), box.fade.attribute, chip_drop(box)
local id = tex.get_texture("dan_select/box/folder")
if id then tex.draw_texture(id, { frame = box.dan_color, x = bx, y = y, fade = fade }) end
local mark = box.clear_mark > 0 and tex.get_texture("dan_select/box/clear_mark")
if mark then tex.draw_texture(mark, { frame = box.clear_mark - 1, x = bx, y = y, fade = fade }) end
draw_chip_name(box, bx, y, fade)
end
function DanSelect:draw_back_box(box)
local bx, fade, y = box:box_x(), box.fade.attribute, chip_drop(box)
local id = tex.get_texture("dan_select/back/folder")
if id then tex.draw_texture(id, { x = bx, y = y, fade = fade }) end
draw_back_label(bx, fade, y)
end
-- The cursor's glow goes over the chip, its emblem and name (they grey under it, as on the
-- cabinet) but not over the clear stamp, which is drawn again on top of it.
local function draw_chip_front(box)
if box.is_back or box.clear_mark <= 0 then return end
local mark = tex.get_texture("dan_select/box/clear_mark")
if mark then
tex.draw_texture(mark, { frame = box.clear_mark - 1, x = box:box_x(), y = chip_drop(box),
fade = box.fade.attribute })
end
end
local parent_draw_box = DanSelect.draw_box
function DanSelect:draw_box(box)
held_boxes[#held_boxes + 1] = box
end
local cursor_parent = DanSelect.draw_cursor
function DanSelect:draw_cursor(pos, now_ms, moved_ms)
local boxes = held_boxes
held_boxes = {}
local k = last_ms and math.min(1, math.max(0, now_ms - last_ms) / DROP_MS) or 1
last_ms = now_ms
local selected
for _, box in ipairs(boxes) do
local key = chip_key(box)
local is_sel = math.abs(box:box_x() - pos) < 1
if is_sel then selected = box end
local d = drop[key] or 0
d = d + ((is_sel and SELECTED_DROP or 0) - d) * k
drop[key] = (math.abs(d) >= 0.05) and d or nil
end
-- draw every box even if one fails, then report the first failure
local err
for _, box in ipairs(boxes) do
local ok, e = pcall(parent_draw_box, self, box)
if not ok and not err then err = e end
end
if err then error(err, 0) end
local y = selected and chip_drop(selected) or 0
if cursor_parent then
cursor_parent(self, pos, now_ms, moved_ms, y)
elseif self.t_cursor then
tex.draw_texture(self.t_cursor, { x = pos, y = y })
end
if selected then draw_chip_front(selected) end
return true
end