diff --git a/Graphics/dan_select/back/folder.png b/Graphics/dan_select/back/folder.png new file mode 100644 index 0000000..806c3e3 --- /dev/null +++ b/Graphics/dan_select/back/folder.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1fc18a7b407b17bf7adeae511968998c6a667ae0b6eb008895dc9867a6714dd6 +size 6613 diff --git a/Graphics/dan_select/back/texture.json b/Graphics/dan_select/back/texture.json new file mode 100644 index 0000000..5d6c964 --- /dev/null +++ b/Graphics/dan_select/back/texture.json @@ -0,0 +1,6 @@ +{ + "folder": { + "x": -44, + "y": 16 + } +} \ No newline at end of file diff --git a/Graphics/dan_select/yellow_box/difficulty_level/0.png b/Graphics/dan_select/yellow_box/difficulty_level/0.png new file mode 100644 index 0000000..c82ea0c --- /dev/null +++ b/Graphics/dan_select/yellow_box/difficulty_level/0.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7a8488aae35dc8b279c0dfe10384b8f00fad2dee3ad1e60dd5772a432859d6af +size 597 diff --git a/Graphics/dan_select/yellow_box/difficulty_level/1.png b/Graphics/dan_select/yellow_box/difficulty_level/1.png new file mode 100644 index 0000000..a996b93 --- /dev/null +++ b/Graphics/dan_select/yellow_box/difficulty_level/1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bd85a2c83fcdc5e2cdaf06f1ffa966253469da4f0bbde53342cd7686a6f96a9c +size 693 diff --git a/Graphics/dan_select/yellow_box/difficulty_level/10.png b/Graphics/dan_select/yellow_box/difficulty_level/10.png new file mode 100644 index 0000000..9b0d3d3 --- /dev/null +++ b/Graphics/dan_select/yellow_box/difficulty_level/10.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1cc06453bff6e46e5ebf6bfaa8bdc268df3635ad37705b34165d13a2293c8c0e +size 977 diff --git a/Graphics/dan_select/yellow_box/difficulty_level/2.png b/Graphics/dan_select/yellow_box/difficulty_level/2.png new file mode 100644 index 0000000..0832c21 --- /dev/null +++ b/Graphics/dan_select/yellow_box/difficulty_level/2.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3012ba59ef42231675b250b0a938bfd75d873de9d61f3569968d7c409ffe1be9 +size 729 diff --git a/Graphics/dan_select/yellow_box/difficulty_level/3.png b/Graphics/dan_select/yellow_box/difficulty_level/3.png new file mode 100644 index 0000000..2e1b03f --- /dev/null +++ b/Graphics/dan_select/yellow_box/difficulty_level/3.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ef2d82d94e4ab1d480b45e4ae13782210e54d17082ddc4172d2abe2f1cd598ea +size 707 diff --git a/Graphics/dan_select/yellow_box/difficulty_level/4.png b/Graphics/dan_select/yellow_box/difficulty_level/4.png new file mode 100644 index 0000000..607c83c --- /dev/null +++ b/Graphics/dan_select/yellow_box/difficulty_level/4.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e6834082724df4028007b8fac86ed3b8cbccb3741ff14ca7e227d0ad03a27158 +size 723 diff --git a/Graphics/dan_select/yellow_box/difficulty_level/5.png b/Graphics/dan_select/yellow_box/difficulty_level/5.png new file mode 100644 index 0000000..c528a8f --- /dev/null +++ b/Graphics/dan_select/yellow_box/difficulty_level/5.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:063373e623beed7494c636f619f10e98adc1c2b92bdac47ff9ebd4287f4b408b +size 706 diff --git a/Graphics/dan_select/yellow_box/difficulty_level/6.png b/Graphics/dan_select/yellow_box/difficulty_level/6.png new file mode 100644 index 0000000..7026959 --- /dev/null +++ b/Graphics/dan_select/yellow_box/difficulty_level/6.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:088b3a9087ba64aeec320d94a95498ac83116f438c437a8825384c2144feffa7 +size 643 diff --git a/Graphics/dan_select/yellow_box/difficulty_level/7.png b/Graphics/dan_select/yellow_box/difficulty_level/7.png new file mode 100644 index 0000000..73956c3 --- /dev/null +++ b/Graphics/dan_select/yellow_box/difficulty_level/7.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:eed585daf6e7675be2c51f9dd315392400b8075a4dbbc7de8e9670e0cc76e2fd +size 678 diff --git a/Graphics/dan_select/yellow_box/difficulty_level/8.png b/Graphics/dan_select/yellow_box/difficulty_level/8.png new file mode 100644 index 0000000..0339318 --- /dev/null +++ b/Graphics/dan_select/yellow_box/difficulty_level/8.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:23579f9c3f6d2e54d3df4ad8b64bdddd5a014d3d989af8e0a0b13a0383e2d173 +size 683 diff --git a/Graphics/dan_select/yellow_box/difficulty_level/9.png b/Graphics/dan_select/yellow_box/difficulty_level/9.png new file mode 100644 index 0000000..1fdc4f9 --- /dev/null +++ b/Graphics/dan_select/yellow_box/difficulty_level/9.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0e0ff6a91affcd09f57190a71b3a6b61af0553c4d281364f508b99770365cf6b +size 868 diff --git a/Graphics/dan_select/yellow_box/texture.json b/Graphics/dan_select/yellow_box/texture.json index e1d1939..df12103 100644 --- a/Graphics/dan_select/yellow_box/texture.json +++ b/Graphics/dan_select/yellow_box/texture.json @@ -190,7 +190,7 @@ }, "song_label": { "x": 430, - "y": 230 + "y": 246 }, "exam_seg_label": { "x": 0, @@ -204,5 +204,9 @@ "x": 100, "y": 505 }, - "difficulty_ura": {} + "difficulty_ura": {}, + "difficulty_level": { + "x": 538, + "y": 287 + } } diff --git a/Graphics/skin_config.json b/Graphics/skin_config.json index 2537c6a..fe6847f 100644 --- a/Graphics/skin_config.json +++ b/Graphics/skin_config.json @@ -45,6 +45,7 @@ "combo_color_tiers": true, "gauge_cell_fade_in": true, "dan_exam_grid": true, + "dan_chip_name_black": true, "disable_chara_3d": false } }, @@ -833,6 +834,19 @@ "height": 88, "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": { "x": 187, "y": 934 diff --git a/Scripts/dan_select/dan_select.lua b/Scripts/dan_select/dan_select.lua index 838aa75..9ec1898 100644 --- a/Scripts/dan_select/dan_select.lua +++ b/Scripts/dan_select/dan_select.lua @@ -47,12 +47,14 @@ function DanSelect.new() end -- 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). -local function draw_cursor(self, pos, now_ms, moved_ms) +-- now_ms: engine clock; moved_ms: ms since the last ribbon step (-1 = never); +-- 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 local f = (now_ms * 0.06) % 60 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 if moved_ms and moved_ms >= 0 then 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 if a > 0 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 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 @@ -73,6 +75,15 @@ 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 -- 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 @@ -82,16 +93,35 @@ local held_stamp -- shared: the boxes and the title can be drawn through diffe if parent_open then function DanSelect:draw_dan_open(box) 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 tex.draw_texture = function(id, p) 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) end local ok, err = pcall(parent_open, self, box) tex.draw_texture = draw 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 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 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