Compare commits

..
Author SHA1 Message Date
TaikoZhongandClaude Opus 5.5 c14075b8fa dan select: course panel closer to the cabinet
- Course rows show the song title alone (no subtitle). In CJK languages the title is set
  in runs (ASCII / everything else) so kanji and kana keep their width; it needs the
  engine's OutlinedText.text and falls back to the engine's title without it.
- Exam values: in CJK languages the digits are narrowed beside full-width 以上/未満, with
  a little room between them; smaller size and a thicker edge, centred on the row's
  coin and right-aligned with the cabinet's.
- Exam labels (yellow_box/exam_*.png) are smaller and edged in dark ochre, centred in
  their pills.
- The 合格条件 tab, frame and exam boxes sit 5 px higher, the tab joining the frame.
- The back chip's label set across (non-CJK languages) takes a smaller size instead of
  being squeezed to the chip.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 17:59:34 +08:00
TaikoZhongandClaude Opus 5.5 2e00d1a0f5 Keep checksums.sha256 in its previous line order
Same entries as the last commit; only the order is restored, with the new
paths appended.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 15:15:14 +08:00
TaikoZhongandClaude Opus 5.5 ec5731e3bd Update checksums.sha256 for #63
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 15:14:23 +08:00
GanYiZhong c78383fdc1 Merge pull request 'dan select: back chip, chip names, cursor and course rows' (#63) from GanYiZhong/YataiDONNijiiro:feat/dan-select-back-chip into main 2026-10-14 09:13:47 +02:00
12 changed files with 182 additions and 38 deletions

No files matched your search

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.
+3 -3
View File
@@ -83,12 +83,12 @@
"y": 186
},
"exam_header": {
"x": 420,
"y": 568
"x": 421,
"y": 563
},
"exam_frame": {
"x": 418,
"y": 601
"y": 596
},
"exam_box_top_left": {
"x": 420,
+14 -13
View File
@@ -628,7 +628,8 @@
"x": 632,
"y": 262,
"height": 60,
"font_size": 36
"font_size": 36,
"outline": 2.6
},
"dan_subtitle": {
"x": 632,
@@ -837,7 +838,7 @@
"dan_back_label": {
"x": 0,
"y": 89,
"width": 60,
"width": 52,
"height": 88,
"font_size": 42,
"text": {
@@ -952,11 +953,11 @@
},
"dan_exam_gauge_box": {
"x": 436,
"y": 615
"y": 610
},
"dan_exam_score_box": {
"x": 769,
"y": 615,
"y": 610,
"height": 132
},
"dan_exam_seg": {
@@ -965,16 +966,16 @@
"width": 327
},
"dan_select_exam_border_text": {
"x": 319,
"y": 54,
"font_size": 28,
"outline": 2.0
"x": 309,
"y": 55,
"font_size": 25,
"outline": 2.6
},
"dan_select_gauge_border_text": {
"x": 300,
"y": 55,
"font_size": 36,
"outline": 2.6666666666666665
"x": 291,
"y": 67,
"font_size": 32,
"outline": 3.1
},
"dan_exam_value": {
"x": 185,
@@ -982,7 +983,7 @@
},
"dan_exam_label_pill": {
"x": 28,
"y": 2
"y": -1
},
"dan_exam_value_left": {
"x": 528
+133 -3
View File
@@ -84,6 +84,123 @@ local function draw_level(level, x, y, f)
tex.draw_texture(id, { frame = math.min(level, 11) - 1, x = x, y = y, fade = f })
end
-- The course rows are set as the cabinet's: the song title alone (no subtitle line), and the
-- exam values with narrow digits beside full-width 以上/未満 and a little room between them.
-- The skin has one font, so each text is cut into runs of ASCII and of everything else, each
-- run made on its own and scaled as it is drawn, the runs butted together. The parent is handed
-- the box through a view whose song_subtitle_text gives nothing and whose song_title_text gives
-- such a title, and the captions it makes for the exam values are made the same way. Only CJK
-- languages are rescaled; the skin's font for the others is narrow already.
local function cjk_language()
local l = tex.language() or ""
return l:find("^ja") or l:find("^zh") or l:find("^ko") or l == "tw" or l == "cn"
end
local TITLE_CJK = { latin = 1, cjk = 1.02, sy = 1, dy = 0, max_w = 1100 }
local VALUE_CJK = { latin = 0.85, cjk = 1.0, sy = 1.0, dy = 0, gap = 8 }
local TITLE_PLAIN = { latin = 1, cjk = 1, sy = 1, dy = 0, max_w = 1100 }
local VALUE_PLAIN = { latin = 1, cjk = 1, sy = 1, dy = 0 }
local function runs_of(str)
local runs, cur, ascii = {}, {}, nil
for ch in str:gmatch("[%z\1-\127\194-\244][\128-\191]*") do
local a = ch:byte() < 128
if ascii ~= nil and a ~= ascii then
runs[#runs + 1] = { text = table.concat(cur), ascii = ascii }
cur = {}
end
cur[#cur + 1] = ch
ascii = a
end
if #cur > 0 then runs[#runs + 1] = { text = table.concat(cur), ascii = ascii } end
return runs
end
-- create: text.create_raw_text as it was before any wrapping. The parts' sizes are read when
-- they are used, since a text's texture (and size) may still be building when it is made.
local function mixed_text(create, str, size, color, outline_color, outline, spacing, style)
local pad = math.floor((outline or 0) * tex.get_screen_scale()) + 2
local parts = {}
for _, r in ipairs(runs_of(str)) do
parts[#parts + 1] = { t = create(r.text, size, color, outline_color, false, outline, spacing),
sx = r.ascii and style.latin or style.cjk }
end
local function layout()
local function span(k)
local x = 0
for n, q in ipairs(parts) do
q.x = x
local next_sx = parts[n + 1] and parts[n + 1].sx * k or 0
x = x + (q.t.width - pad) * q.sx * k - pad * next_sx
if parts[n + 1] then x = x + (style.gap or 0) * k end
end
local last = parts[#parts]
return last and (last.x + last.t.width * last.sx * k) or 0
end
local k, w = 1, span(1)
if style.max_w and w > style.max_w then
k = style.max_w / w
w = span(k)
end
local h = 0
for _, q in ipairs(parts) do h = math.max(h, q.t.height) end
return k, w, h * style.sy
end
return setmetatable({
text = str,
draw = function(_, p)
local k = layout()
for _, q in ipairs(parts) do
local sx = q.sx * k
q.t:draw({ x = p.x + q.x, y = (p.y or 0) + style.dy, fade = p.fade,
x2 = q.t.width * (sx - 1), y2 = q.t.height * (style.sy - 1) })
end
end,
}, {
__index = function(_, key)
if key == "width" then local _, w = layout(); return w end
if key == "height" then local _, _, h = layout(); return h end
end,
})
end
local title_cache = {} -- by string, size and outline: texts are built once, not per frame
local raw_create = text.create_raw_text -- the engine's, before draw_dan_open wraps it
local function course_view(box)
local titles = {}
return setmetatable({}, {
__index = function(_, k)
if k == "song_subtitle_text" then return function() return nil end end
if k == "song_title_text" then
return function(_, i)
if titles[i] == nil then
local t = box:song_title_text(i)
local ok, str = pcall(function() return t and t.text end)
local td = tex.get_skin_config("dan_title")
if t and ok and type(str) == "string" and str ~= "" and td then
local ol = td.outline >= 0 and td.outline or 5
local key = str .. "\0" .. td.font_size .. "\0" .. ol
title_cache[key] = title_cache[key]
or mixed_text(raw_create, str, td.font_size,
{ 255, 255, 255, 255 }, { 0, 0, 0, 255 }, ol, 2,
cjk_language() and TITLE_CJK or TITLE_PLAIN)
titles[i] = title_cache[key]
else
titles[i] = t or false -- an engine without OutlinedText.text
end
end
return titles[i] or nil
end
end
local v = box[k]
if type(v) == "function" then
return function(_, ...) return v(box, ...) end
end
return v
end,
})
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
@@ -109,7 +226,16 @@ if parent_open then
end
return draw(id, p)
end
local ok, err = pcall(parent_open, self, box)
local create = text.create_raw_text
text.create_raw_text = function(str, size, color, outline_color, vertical, outline, spacing, ...)
if vertical or type(str) ~= "string" then -- only the exam value captions
return raw_create(str, size, color, outline_color, vertical, outline, spacing, ...)
end
return mixed_text(raw_create, str, size, color, outline_color, outline, spacing,
cjk_language() and VALUE_CJK or VALUE_PLAIN)
end
local ok, err = pcall(parent_open, self, course_view(box))
text.create_raw_text = create
tex.draw_texture = draw
if not ok then error(err, 0) end
local f = box.open_fade.attribute
@@ -139,17 +265,21 @@ end
-- across, squeezed to the chip, for other languages.
local CJK = { ja = true, zh = true, ko = true, tw = true, cn = true }
local back_label
local BACK_ACROSS_SIZE = 0.7 -- size of a label set across, against dan_back_label.font_size
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
-- a word set across has only the chip's width, so it takes a smaller size than the
-- vertical labels rather than being squeezed hard
local size = vertical and cfg.font_size or math.floor(cfg.font_size * BACK_ACROSS_SIZE + 0.5)
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),
main = raw_create(tex.skin_text("dan_back_label"), size,
{ 0, 0, 0, 255 }, { 0, 0, 0, 255 }, vertical, 0, 2),
}
end
return back_label
+16 -3
View File
@@ -3457,7 +3457,7 @@ aae5cba4ab39d7b29c44bb43c79ae59c6ed7ddd151c8840bfeaf2bb4d6278c3d *./Graphics/dan
ac0e5f9f354f6059ea7687a706221ff863d317f6783f854897f023a5315e8d56 *./Graphics/dan_select/yellow_box/song_label/0.png
340ea6974d9c74280d7532d6eb66b7eab2fd2634071325f4ba4654edb89d9e8e *./Graphics/dan_select/yellow_box/song_label/1.png
5839347db9c87f848fe112052938d42de85d10448df52626d27d3b39147c9bdd *./Graphics/dan_select/yellow_box/song_label/2.png
a7d8044152e09d0de4d45e28f52be114f5270ad77c0eb561e5d7524d3cd42fde *./Graphics/dan_select/yellow_box/texture.json
a1a08080cb7e334b43b5af5e836cefab6000c2c768779592e1e7452239192820 *./Graphics/dan_select/yellow_box/texture.json
52b3b7c93ee491e74e3e4a627f77dd1b1689a58be3f0d814bf1fafc5cb101ec1 *./Graphics/dan_select/yellow_box/total_notes_bg.png
ded547deee71bf781f90e2d9c29ab2c0a8f3dbf1ec5f745a345859ebf7810184 *./Graphics/dan_select/yellow_box/total_notes_counter/0.png
caea6b27ce43889309a7d27150b37914ef64725dbd0765eab2c996839699b8d3 *./Graphics/dan_select/yellow_box/total_notes_counter/1.png
@@ -4374,7 +4374,7 @@ d21dc53600bab83b80352bad38cd598d216c6e1279a4d54a0a085ad82ad1430d *./Graphics/res
684c22481d2a0e4bb2d6dd67b5df87650e081edfeadffcc70c377c393334c06d *./Graphics/result/score/score_shinuchi_en.png
1c160a1a14016ea3a5f761b040db433420476363224011d615613af660e7d0e1 *./Graphics/result/score/score_shinuchi_ja.png
89c4d6afafb8010ec4da0b9f72f10f677ec8c87677fcb3d2c9edde923a5b5f9f *./Graphics/result/score/texture.json
546297e182cf47f1d498cf09c0dfa0bc46b162bab5fc7820077f6ee2a1003754 *./Graphics/skin_config.json
4675dc41015467ea66ecb77875e526ea50b371c48bb55118d201bb4f79b58ade *./Graphics/skin_config.json
a05d23f0997446d4db2b745602bff7fc3d2cdce968a1c24e078684d41cf2982c *./Graphics/song_select/animation.json
27e427b29774e04dc739b1c58a7205565de88cea6370876b623f8e13a7106b5c *./Graphics/song_select/box/back_graphic.png
b74432db46ec6d7ec080fbee6df6029c1451e243d30813fcf597a21704de4e74 *./Graphics/song_select/box/background/0.png
@@ -5005,7 +5005,7 @@ f204455c907d3e0e7affb89db3649a709a27d528d84cc58d51a7d8cfaa1d3deb *./Scripts/back
4e17bf53815d1e586fdba5f3501d6f2d9935ad5604da871d2e7e89c87499aedd *./Scripts/background/dancer_data/dancer_3.lua
6e2b3c136611c688cdfbe44b0bbcb9d25c2ab647903246b07f2aef9baa6bab0b *./Scripts/background/dancer_data/dancer_4.lua
3a4f1f45bb54c4303dc97afcc6f67df831d6d6011a2264baed3d933c789d210e *./Scripts/background/dancer_data/dancer_5.lua
0cf21c1fa200028935b148a71dd5a97942e9b73f5f957d358951ebbf60801ee0 *./Scripts/dan_select/dan_select.lua
44210159402b5a357ee1fb8f8420836d4a81d063e5ed9d2a03e4c1955d3ef1c6 *./Scripts/dan_select/dan_select.lua
020f929896e3f58c27bf54881afbbf1597ebd14951b5476f9a97a29fa670e2fc *./Scripts/entry/box.lua
0a941cea73b6a81f2c92219be139a43f5902067ce468ffd189520395b4739c91 *./Scripts/entry/costume_menu.lua
83fc6c160c85a68a75d146f455cb4e18fc962c23a0020d28ac6943a1843db504 *./Scripts/entry/entry.lua
@@ -5340,3 +5340,16 @@ c567acc69bf6e9a239e66a195f2d65a7ec6455acff3ee248f4302477d01c193d *./Videos/attra
433af3c4eef82636a70592e1bebaa44d9b8f88da5abe240fe55e06535d659110 *./Graphics/dan_select/yellow_box/clear_mark/0.png
15c702977afc97112aff1d435e87040ea3262ecd66fcfb9ca4dfa769311b23ff *./Graphics/dan_select/yellow_box/clear_mark/1.png
c2153f77e11087fcb078ae38527fa83bef29791e3700e30cc87fec4405a66d0f *./Graphics/dan_select/yellow_box/difficulty_ura.png
1fc18a7b407b17bf7adeae511968998c6a667ae0b6eb008895dc9867a6714dd6 *./Graphics/dan_select/back/folder.png
a7d33686dc618520da047779b3a47be6219940d386b32c1c3e54bb5aceae22ae *./Graphics/dan_select/back/texture.json
7a8488aae35dc8b279c0dfe10384b8f00fad2dee3ad1e60dd5772a432859d6af *./Graphics/dan_select/yellow_box/difficulty_level/0.png
bd85a2c83fcdc5e2cdaf06f1ffa966253469da4f0bbde53342cd7686a6f96a9c *./Graphics/dan_select/yellow_box/difficulty_level/1.png
1cc06453bff6e46e5ebf6bfaa8bdc268df3635ad37705b34165d13a2293c8c0e *./Graphics/dan_select/yellow_box/difficulty_level/10.png
3012ba59ef42231675b250b0a938bfd75d873de9d61f3569968d7c409ffe1be9 *./Graphics/dan_select/yellow_box/difficulty_level/2.png
ef2d82d94e4ab1d480b45e4ae13782210e54d17082ddc4172d2abe2f1cd598ea *./Graphics/dan_select/yellow_box/difficulty_level/3.png
e6834082724df4028007b8fac86ed3b8cbccb3741ff14ca7e227d0ad03a27158 *./Graphics/dan_select/yellow_box/difficulty_level/4.png
063373e623beed7494c636f619f10e98adc1c2b92bdac47ff9ebd4287f4b408b *./Graphics/dan_select/yellow_box/difficulty_level/5.png
088b3a9087ba64aeec320d94a95498ac83116f438c437a8825384c2144feffa7 *./Graphics/dan_select/yellow_box/difficulty_level/6.png
eed585daf6e7675be2c51f9dd315392400b8075a4dbbc7de8e9670e0cc76e2fd *./Graphics/dan_select/yellow_box/difficulty_level/7.png
23579f9c3f6d2e54d3df4ad8b64bdddd5a014d3d989af8e0a0b13a0383e2d173 *./Graphics/dan_select/yellow_box/difficulty_level/8.png
0e0ff6a91affcd09f57190a71b3a6b61af0553c4d281364f508b99770365cf6b *./Graphics/dan_select/yellow_box/difficulty_level/9.png