diff --git a/Graphics/skin_config.json b/Graphics/skin_config.json index 9b5a4d2..f306137 100644 --- a/Graphics/skin_config.json +++ b/Graphics/skin_config.json @@ -809,7 +809,6 @@ "song_num_max_game": { "x": 1814, "y": 122 - }, "note_arc_curve_height": { "height": 608 @@ -1002,5 +1001,181 @@ "note_arc_pivot_2p": { "x": 1282.19, "y": -167.83 + }, + "entry_game_comment_1": { + "text": { + "ja": "すきな曲や、むずかしさを", + "en": "Select a song and", + "zh": "可选择喜爱的" + } + }, + "entry_game_comment_2": { + "text": { + "ja": "えらんであそべるよ!", + "en": "difficulty to play!", + "zh": "歌曲、难度游玩哦!" + } + }, + "entry_practice_comment_1": { + "text": { + "ja": "曲の一部をくりかえし練習して", + "en": "Practice a section of a song", + "zh": "反复练习歌曲的片段" + } + }, + "entry_practice_comment_2": { + "text": { + "ja": "腕をみがこう!", + "en": "over and over to improve!", + "zh": "磨练技巧吧!" + } + }, + "entry_costume_comment_1": { + "text": { + "ja": "どんちゃんのきせかえを", + "en": "Choose an outfit", + "zh": "可为咚酱选择" + } + }, + "entry_costume_comment_2": { + "text": { + "ja": "えらんであそべるよ!", + "en": "for your Don-chan!", + "zh": "服饰游玩哦!" + } + }, + "entry_ai_battle_comment_1": { + "text": { + "ja": "「AIどん」と勝つか負けるか", + "en": "See if you can beat AI-DON", + "zh": "与「AI咚」来一场" + } + }, + "entry_ai_battle_comment_2": { + "text": { + "ja": "ギリギリのバトルをたのしもう!", + "en": "in this neck-and-neck competition!", + "zh": "不到最后难分胜负的对战吧!" + } + }, + "mode_dan_comment_1": { + "text": { + "ja": "3曲連続して演奏しながら、", + "en": "Play three songs in a row", + "zh": "连续演奏3首指定曲" + } + }, + "mode_dan_comment_2": { + "text": { + "ja": "お題の合格を目指そう!", + "en": "and aim to clear the task!", + "zh": "并达成题目的合格条件吧!" + } + }, + "mode_dan_comment_3": { + "text": { + "ja": "合格すると腕前が認定されるよ!", + "en": "Your skills will be rewarded!", + "zh": "只要合格实力就会备受肯定哦!" + } + }, + "entry_settings_comment_1": { + "text": { + "ja": "ゲームのせっていを", + "en": "Change the game's", + "zh": "可以变更" + } + }, + "entry_settings_comment_2": { + "text": { + "ja": "かえられるよ!", + "en": "settings here!", + "zh": "游戏设定哦!" + } + }, + "sort_window_diff": { + "text": { + "ja": "むずかしさ", + "en": "Difficulty", + "zh": "难度" + } + }, + "sort_window_star": { + "text": { + "ja": "★の数", + "en": "Number of \"★\"", + "zh": "★的个数" + } + }, + "sort_window_order": { + "text": { + "ja": "表示順", + "en": "Sort by", + "zh": "排序" + } + }, + "sort_window_order_0": { + "text": { + "ja": "いつもどおり", + "en": "Default", + "zh": "通常" + } + }, + "sort_window_order_1": { + "text": { + "ja": "未クリア優先", + "en": "Not cleared", + "zh": "未通关优先" + } + }, + "sort_window_order_2": { + "text": { + "ja": "未フルコンボ優先", + "en": "Not Full Combo", + "zh": "未全连段优先" + } + }, + "sort_window_order_3": { + "text": { + "ja": "未ドンダフルコンボ優先", + "en": "Not Donderful Combo", + "zh": "未全良连段优先" + } + }, + "sort_window_songs": { + "text": { + "ja": "曲", + "en": "Songs", + "zh": "首" + } + }, + "folder_sort_select": { + "text": { + "ja": "むずかしさからえらぶ", + "en": "Select by difficulty", + "zh": "根据难度选择" + } + }, + "dan_gauge_name": { + "text": { + "ja": "魂ゲージ", + "en": "Soul Gauge", + "zh": "魂槽", + "ko": "클리어 게이지" + } + }, + "skip_badge_text": { + "text": { + "ja": "演奏スキップON", + "en": "演奏スキップON", + "zh": "演奏スキップON" + } + }, + "mode_dan": { + "text": { + "ja": "段位道場", + "en": "Dan-i Dojo", + "zh": "段位道场" + } } } diff --git a/Scripts/background/bg_objects/dan_info.lua b/Scripts/background/bg_objects/dan_info.lua index 7c1a8e5..5e3bb34 100644 --- a/Scripts/background/bg_objects/dan_info.lua +++ b/Scripts/background/bg_objects/dan_info.lua @@ -251,17 +251,13 @@ function M:draw() local x = GAUGE_X0 + CELL_PITCH * n - CELL_PITCH / 2 - 1 if self.label_for ~= ex.red then - -- cabinet wordlist: clear_theme_soul_gauge = 魂ゲージ / Soul Gauge / 魂槽 / 클리어 게이지 - local lang = (tex.language and tex.language()) or "ja" - local W = { - ja = { "魂ゲージ", "%以上" }, en = { "Soul Gauge", "% or more" }, - zh = { "魂槽", "%以上" }, ko = { "클리어 게이지", "% 이상" }, - } - local w = W[lang] or W.ja - self.label = text.create_raw_text(tostring(ex.red) .. w[2], + -- skin_config: dan_gauge_name (魂ゲージ) and dan_exam_text_gauge ("%s %以上", %% = %) + local fmt = tex.skin_text("dan_exam_text_gauge"):gsub("%%%%", "\1") + local caption = fmt:gsub("%%s", tostring(ex.red)):gsub("\1", "%%") + self.label = text.create_raw_text(caption, VALUE_SIZE, CAP_FILL, VALUE_OUTLINE, false, 4.0 / tex.get_screen_scale()) - self.name_label = text.create_raw_text(w[1], + self.name_label = text.create_raw_text(tex.skin_text("dan_gauge_name"), NAME_SIZE, CAP_FILL, CAP_OUTLINE, false, 3.0 / tex.get_screen_scale()) self.label_for = ex.red diff --git a/Scripts/entry/box.lua b/Scripts/entry/box.lua index f9b3672..dc55355 100644 --- a/Scripts/entry/box.lua +++ b/Scripts/entry/box.lua @@ -60,39 +60,23 @@ local TITLE_SPACING, INFO_SPACING = 2.0, 1.0 local MODES = { game = { frame = 0, outline = {251, 1, 29, 255}, - titles = { ja = "演奏ゲーム", en = "Game", zh = "节奏游戏" }, - comment = { - ja = { "すきな曲や、むずかしさを", "えらんであそべるよ!" }, - en = { "Select a song and", "difficulty to play!" }, - zh = { "可选择喜爱的", "歌曲、难度游玩哦!" }, - }, + title_key = "entry_game", + comment_keys = { "entry_game_comment_1", "entry_game_comment_2" }, }, practice = { frame = 2, outline = {34, 138, 117, 255}, - titles = { ja = "特訓モード", en = "Practice", zh = "练习游戏" }, - comment = { - ja = { "曲の一部をくりかえし練習して", "腕をみがこう!" }, - en = { "Practice a section of a song", "over and over to improve!" }, - zh = { "反复练习歌曲的片段", "磨练技巧吧!" }, - }, + title_key = "entry_practice", + comment_keys = { "entry_practice_comment_1", "entry_practice_comment_2" }, }, costume = { frame = 4, outline = {200, 120, 222, 255}, - titles = { ja = "きせかえ", en = "Costume", zh = "装扮" }, - comment = { - ja = { "どんちゃんのきせかえを", "えらんであそべるよ!" }, - en = { "Choose an outfit", "for your Don-chan!" }, - zh = { "可为咚酱选择", "服饰游玩哦!" }, - }, + title_key = "entry_costume", + comment_keys = { "entry_costume_comment_1", "entry_costume_comment_2" }, }, ai = { frame = 2, outline = {34, 138, 117, 255}, - titles = { ja = "AIバトル", en = "AI Battle", zh = "AI斗争" }, - comment = { - ja = { "「AIどん」と勝つか負けるか", "ギリギリのバトルをたのしもう!" }, - en = { "See if you can beat AI-DON", "in this neck-and-neck competition!" }, - zh = { "与「AI咚」来一场", "不到最后难分胜负的对战吧!" }, - }, + title_key = "entry_ai_battle", + comment_keys = { "entry_ai_battle_comment_1", "entry_ai_battle_comment_2" }, }, -- ROUND 83 (r83-dandojo-as-mode) — 段位道場 is a MODE on the cabinet -- (`mode_select.lua` CreateBoardList l.289-296 appends GameMode.kDani right after @@ -103,24 +87,16 @@ local MODES = { -- mode_select_comment_dani (three lines; every other board here has two). dan = { frame = 6, outline = {76, 60, 151, 255}, - titles = { ja = "段位道場", en = "Dan-i Dojo", zh = "段位道场" }, - comment = { - ja = { "3曲連続して演奏しながら、", "お題の合格を目指そう!", "合格すると腕前が認定されるよ!" }, - en = { "Play three songs in a row", "and aim to clear the task!", "Your skills will be rewarded!" }, - zh = { "连续演奏3首指定曲", "并达成题目的合格条件吧!", "只要合格实力就会备受肯定哦!" }, - }, + title_key = "mode_dan", + comment_keys = { "mode_dan_comment_1", "mode_dan_comment_2", "mode_dan_comment_3" }, }, -- ROUND 83: ゲーム設定 has no cabinet counterpart and was wearing 段位道場's board -- (dani, frames 6/7) since ROUND 6. Moved onto `aprilfool`, baked as frames 9/10 by -- bake_entry.py's EXTRA list; its title colour-add at label `aprilfool` is (0,132,212). settings = { frame = 9, outline = {0, 132, 212, 255}, - titles = { ja = "ゲーム設定", en = "Settings", zh = "游戏设定" }, - comment = { - ja = { "ゲームのせっていを", "かえられるよ!" }, - en = { "Change the game's", "settings here!" }, - zh = { "可以变更", "游戏设定哦!" }, - }, + title_key = "entry_settings", + comment_keys = { "entry_settings_comment_1", "entry_settings_comment_2" }, }, } @@ -129,16 +105,19 @@ local MODES = { -- (pairs() order is unspecified). Ask the engine which language it is actually running -- (`tex.language()`, script.cpp:693 -> config.general.language) and try that key first; -- the old scan stays as the fallback for a language the table has no column for. +-- Titles and comments live in skin_config (entry_* / entry_*_comment_N); the engine hands +-- us the title it drew, so the mode is the one whose skin_config title matches. +local LANGS = { "ja", "en", "zh", "ko" } local function find_mode(text_str) local ok, cur = pcall(function() return tex.language() end) if ok and type(cur) == "string" then for key, m in pairs(MODES) do - if m.titles[cur] == text_str then return m, cur end + if tex.skin_text(m.title_key, cur) == text_str then return m, cur end end end for key, m in pairs(MODES) do - for lang, t in pairs(m.titles) do - if t == text_str then return m, lang end + for _, lang in ipairs(LANGS) do + if tex.skin_text(m.title_key, lang) == text_str then return m, lang end end end return MODES.settings, "ja", true @@ -297,7 +276,8 @@ function EntryBox.new(text_str, font_size) self.title = text.create_raw_text(text_str, TITLE_SIZE, { 255, 255, 255, 255 }, mode.outline, false, TITLE_INNER_T, TITLE_SPACING) self.info = {} if not unknown then - local lines = mode.comment[lang] or mode.comment.ja + local lines = {} + for i, key in ipairs(mode.comment_keys) do lines[i] = tex.skin_text(key, lang) end for i, line in ipairs(lines) do self.info[i] = text.create_raw_text(line, INFO_SIZE, INFO_COLOR, INFO_OUTLINE, false, INFO_BORDER / tex.get_screen_scale(), INFO_SPACING) diff --git a/Scripts/entry/costume_menu.lua b/Scripts/entry/costume_menu.lua index 2e75ada..4ba9934 100644 --- a/Scripts/entry/costume_menu.lua +++ b/Scripts/entry/costume_menu.lua @@ -86,21 +86,6 @@ local ITEM_KEYS = { "preset_1", "preset_2", "preset_3", "random_item", } -local GUIDE_TEXT = { - ja = { "えらぶ", "決定" }, - en = { "Move", "Confirm" }, - zh = { "选择", "决定" }, -} - -local function detect_lang(s) - if s:find("[\227-\239]") then - -- kana block (U+3040..U+30FF) => ja, otherwise CJK => zh - if s:find("\227[\129-\131]") then return "ja" end - return "zh" - end - return "en" -end - local function clamp(v, lo, hi) if v < lo then return lo end if v > hi then return hi end @@ -140,10 +125,9 @@ function CostumeMenu.new(is_2p, text_str, title_x, title_y) -- arcade: font 54 white, outline 6 (renderer default = black); thickness here is x1.5 on screen self.title_text = text.create_raw_text(text_str, TITLE_SIZE, { 255, 255, 255, 255 }, { 0, 0, 0, 255 }, false, 4, 2.0) - local lang = detect_lang(text_str) - local gt = GUIDE_TEXT[lang] or GUIDE_TEXT.ja - self.guide_sel = text.create_raw_text(gt[1], GUIDE_SIZE, { 30, 30, 30, 255 }, { 30, 30, 30, 255 }, false, 0, 1.0) - self.guide_dec = text.create_raw_text(gt[2], GUIDE_SIZE, { 30, 30, 30, 255 }, { 30, 30, 30, 255 }, false, 0, 1.0) + -- guide words from skin_config (guide_select_label / guide_decide_label) + self.guide_sel = text.create_raw_text(tex.skin_text("guide_select_label"), GUIDE_SIZE, { 30, 30, 30, 255 }, { 30, 30, 30, 255 }, false, 0, 1.0) + self.guide_dec = text.create_raw_text(tex.skin_text("guide_decide_label"), GUIDE_SIZE, { 30, 30, 30, 255 }, { 30, 30, 30, 255 }, false, 0, 1.0) self.costume_select_mode = false -- arcade cursor_idx_ (1..5, here 0-based) and select_offset_ diff --git a/Scripts/global/allnet_indicator.lua b/Scripts/global/allnet_indicator.lua index ba75efb..01550d4 100644 --- a/Scripts/global/allnet_indicator.lua +++ b/Scripts/global/allnet_indicator.lua @@ -61,7 +61,7 @@ function AllNetIcon:draw_song_max() local limit = tex.song_limit() if not limit or limit <= 0 then return end if self._song_max_n ~= limit then - self._song_max = text.create_raw_text(tostring(limit) .. (({ ja = "曲", en = " Songs", zh = "首", ko = "곡" })[(tex.language and tex.language()) or "ja"] or "曲"), + self._song_max = text.create_raw_text((tex.skin_text("song_num_max"):gsub("{0}", tostring(limit))), SONG_MAX_FONT, { 255, 255, 255, 255 }, { 0, 0, 0, 255 }, false, SONG_MAX_BORDER / tex.get_screen_scale(), 2.0) self._song_max_n = limit end diff --git a/Scripts/global/transition.lua b/Scripts/global/transition.lua index 000f9bf..f33cf74 100644 --- a/Scripts/global/transition.lua +++ b/Scripts/global/transition.lua @@ -180,7 +180,7 @@ function SongTransition.new(title, subtitle, is_second) -- locale and so do we. Built HERE and not in skip_armed(): the glyph -- atlas needs a frame to upload, so creating it on the first drawn frame -- left the first frames showing an empty pill. - self.skip_text = text.create_raw_text("演奏スキップON", SKIP_TEXT_SIZE, + self.skip_text = text.create_raw_text(tex.skin_text("skip_badge_text"), SKIP_TEXT_SIZE, { 0, 0, 0, 255 }, { 0, 0, 0, 0 }, false, 0, 2) end return self diff --git a/Scripts/song_select/song_select.lua b/Scripts/song_select/song_select.lua index 594a3fb..4063843 100644 --- a/Scripts/song_select/song_select.lua +++ b/Scripts/song_select/song_select.lua @@ -329,7 +329,7 @@ function SongSelect:draw_song_max() if self._song_max_n ~= limit then local sc = tex.get_skin_config("song_num") or {} self._song_max_y = sc.y or 252 - self._song_max = text.create_raw_text(tostring(limit) .. (({ ja = "曲", en = " Songs", zh = "首", ko = "곡" })[(tex.language and tex.language()) or "ja"] or "曲"), + self._song_max = text.create_raw_text((tex.skin_text("song_num_max"):gsub("{0}", tostring(limit))), -- `common_song_select_number_of_songs` id 3 `text_total_songs`: size 24, border 3.5 sc.font_size or 24, { 255, 255, 255, 255 }, { 0, 0, 0, 255 }, false, ol(3.5), 2.0) self._song_max_n = limit @@ -2498,30 +2498,23 @@ local SW_CURSOR_CYCLE = 51.0 -- The strings are the cabinet's own word table (the reference build `datatable` wordlist), not invented: -- sort_window_diff / _star / _order, course_easy..course_mania, sort_window_order_*, -- folder_sort_select, sort_window_songs. Keyed by `tex.language()` with en as the fallback. -local SW_WORDS = { - header = { - ja = { "むずかしさ", "★の数", "表示順" }, - en = { "Difficulty", 'Number of "★"', "Sort by" }, - zh = { "难度", "★的个数", "排序" }, - }, - course = { - ja = { "かんたん", "ふつう", "むずかしい", "おに", "おに" }, - en = { "Easy", "Normal", "Hard", "Extreme", "Extreme" }, - zh = { "简单", "普通", "困难", "魔王", "魔王" }, - }, - order = { - ja = { "いつもどおり", "未クリア優先", "未フルコンボ優先", "未ドンダフルコンボ優先" }, - en = { "Default", "Not cleared", "Not Full Combo", "Not Donderful Combo" }, - zh = { "通常", "未通关优先", "未全连段优先", "未全良连段优先" }, - }, - title = { ja = "むずかしさからえらぶ", en = "Select by difficulty", zh = "根据难度选择" }, - songs = { ja = "曲", en = "Songs", zh = "首" }, +-- skin_config keys (the strings themselves live there, per language) +local SW_KEYS = { + header = { "sort_window_diff", "sort_window_star", "sort_window_order" }, + course = { "course_name_0", "course_name_1", "course_name_2", "course_name_3", "course_name_3" }, + order = { "sort_window_order_0", "sort_window_order_1", "sort_window_order_2", "sort_window_order_3" }, + title = "folder_sort_select", + songs = "sort_window_songs", } local function sw_words(group) - local lang = (tex.language and tex.language()) or "en" - local t = SW_WORDS[group] - return t[lang] or t.en + local k = SW_KEYS[group] + if type(k) == "table" then + local out = {} + for i, key in ipairs(k) do out[i] = tex.skin_text(key) end + return out + end + return tex.skin_text(k) end -- OutlinedText cache: key = group .. "\0" .. index (the strings never change at runtime).