feat(rpgmaker): add face-aware dialogue wrapping
This commit is contained in:
parent
c9bca5b66f
commit
3d81c750fc
10 changed files with 193 additions and 29 deletions
|
|
@ -59,6 +59,9 @@ threads="1"
|
|||
#The wordwrap of dialogue text
|
||||
width="60"
|
||||
|
||||
#The narrower dialogue wrap used when code 101 displays a face graphic
|
||||
faceWidth="50"
|
||||
|
||||
#The wordwrap of items and help text
|
||||
listWidth="100"
|
||||
|
||||
|
|
|
|||
|
|
@ -166,7 +166,11 @@ geometry rather than generic RPG Maker defaults whenever project code is availab
|
|||
6. For dialogue, verify the recommendation against the actual message-row limit, commonly four.
|
||||
If a long message cannot fit without unreadable font reduction or horizontal overflow, flag it
|
||||
for pagination/manual reflow instead of forcing an unsafe four-line wrap.
|
||||
7. Recommend one conservative shared width and one readable font size for each category. If the
|
||||
7. Detect standard message faces from non-empty code-101 parameter 0 values. Calculate both the
|
||||
full dialogue width and the reduced `faceWidth`; DazedTL selects `faceWidth` automatically for
|
||||
those message groups. For plugin portraits outside code 101, document the detection gap and use
|
||||
a conservative global width or recommend custom handling.
|
||||
8. Recommend one conservative shared width and one readable font size for each category. If the
|
||||
current font should remain unchanged, say `keep current` and report its measured size. Cite the
|
||||
files/functions/plugin parameters supporting every recommendation and give a confidence level.
|
||||
|
||||
|
|
@ -179,7 +183,7 @@ Label the fence language as `rpgmaker_config`. Inside:
|
|||
```text
|
||||
CODE408 : ENABLE|SKIP - <runtime evidence, affected count, and confidence>
|
||||
|
||||
Dialogue : width=<DazedTL width> ; font=<px or keep current (measured px)> ; rows=<count>
|
||||
Dialogue : width=<full width> ; faceWidth=<code-101 face width> ; font=<px or keep current (measured px)> ; rows=<count>
|
||||
List/Help: listWidth=<DazedTL width> ; font=<px or keep current (measured px)> ; rows=<count or varies>
|
||||
Notes : noteWidth=<DazedTL width> ; font=<px or keep current (measured px)> ; rows=<count or varies>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,32 +1,48 @@
|
|||
You are an expert RPGMaker MV/MZ configuration analyst.
|
||||
|
||||
<task>
|
||||
Calculate the correct text-wrap width settings for a Japanese-to-English RPGMaker MV/MZ translation tool. The tool wraps translated English using character-count limits (not pixels). I need three values: width, listWidth, and noteWidth.
|
||||
Calculate the correct text-wrap and font recommendations for a Japanese-to-English RPGMaker
|
||||
MV/MZ translation tool. The tool wraps translated English using character-count limits, not pixels.
|
||||
I need `width`, `faceWidth`, `listWidth`, and `noteWidth`, plus a font recommendation for dialogue,
|
||||
list/help text, and notes.
|
||||
</task>
|
||||
|
||||
--- attach System.json and js/plugins.js here before continuing ---
|
||||
--- open the game repository and inspect its data/ and js/ folders before continuing ---
|
||||
|
||||
<instructions>
|
||||
1. Read screenWidth and fontSize from System.json.
|
||||
Check js/plugins.js for any MessageCore or Window plugin that overrides these values.
|
||||
2. For each window type, estimate its pixel width, subtract ~48px padding, then calculate:
|
||||
chars = floor(content_px / (font_size × 0.58))
|
||||
- width: main dialogue/message box (Show Text) — typically full screen width
|
||||
- listWidth: item/skill/help description windows — typically full or half screen width
|
||||
- noteWidth: database note fields — typically the narrowest pane (~40–50% screen width)
|
||||
3. If font size is above 26px and reducing it would meaningfully increase characters per line, note where to change it (System.json or the relevant plugin parameter).
|
||||
1. Read the resolution and base fonts from `System.json` and engine code. Inspect enabled entries in
|
||||
`js/plugins.js` and their plugin sources for message, help, list, note, portrait, font, padding,
|
||||
line-height, column, and window-size overrides.
|
||||
2. For dialogue, inspect code-101 commands. A non-empty parameter 0 is a standard face graphic and
|
||||
reserves horizontal space. Calculate both the full `width` and reduced `faceWidth`; DazedTL
|
||||
selects `faceWidth` automatically for those message groups. Identify plugin portraits that do
|
||||
not use code 101 as exceptions requiring a conservative width or custom handling.
|
||||
3. For Dialogue, List/Help, and Notes, calculate usable pixels from the actual window geometry:
|
||||
subtract padding, text inset, faces/portraits, icons, columns, and plugin margins. Calculate row
|
||||
capacity from usable height and line height.
|
||||
4. Account for the real font face and base size plus `\\{`, `\\}`, `\\FS[n]`, custom font codes,
|
||||
inline icons/images, and plugin scaling. Measure representative English glyphs in the real font
|
||||
when possible; otherwise state the conservative average used. Never copy pixels directly into a
|
||||
character-count setting.
|
||||
5. Test representative short, long, icon-heavy, control-code-heavy, and font-changed values. Check
|
||||
dialogue against its real row limit, commonly four. Recommend pagination/manual reflow when a
|
||||
message cannot fit without unreadable font reduction or horizontal overflow.
|
||||
6. Recommend a readable font for each category. Use `keep current (<N>px)` when no game-side font
|
||||
change is needed; otherwise cite the exact plugin parameter or function that would change it.
|
||||
</instructions>
|
||||
|
||||
<output_format>
|
||||
Output only the final values — do not show calculations:
|
||||
Output the recommendations followed by compact evidence and exceptions:
|
||||
|
||||
```
|
||||
width=<N>
|
||||
listWidth=<N>
|
||||
noteWidth=<N>
|
||||
fontSize=<N> # or: no change needed
|
||||
```
|
||||
Dialogue : width=<N> ; faceWidth=<N> ; font=<Npx or keep current (Npx)> ; rows=<N>
|
||||
List/Help: listWidth=<N> ; font=<Npx or keep current (Npx)> ; rows=<N or varies>
|
||||
Notes : noteWidth=<N> ; font=<Npx or keep current (Npx)> ; rows=<N or varies>
|
||||
|
||||
Followed by one sentence of assumptions if anything was estimated.
|
||||
Evidence:
|
||||
- <window/font/plugin locator and calculation>
|
||||
|
||||
Exceptions / playtests:
|
||||
- <plugin portraits, variant windows, or messages requiring pagination>
|
||||
```
|
||||
</output_format>
|
||||
|
||||
|
|
|
|||
|
|
@ -806,6 +806,18 @@ class ConfigTab(QWidget):
|
|||
self.width_spin.setSuffix(" chars")
|
||||
add_row(trans_section, "Dialogue Width:", size_field(self.width_spin))
|
||||
|
||||
self.face_width_spin = QSpinBox()
|
||||
self.face_width_spin.setButtonSymbols(QSpinBox.NoButtons)
|
||||
self.face_width_spin.setRange(10, 200)
|
||||
self.face_width_spin.setValue(50)
|
||||
self.face_width_spin.setSuffix(" chars")
|
||||
self.face_width_spin.setToolTip(
|
||||
"Dialogue wrap width when a standard code-101 face graphic reserves window space."
|
||||
)
|
||||
self.face_width_spin.setMaximum(self.width_spin.value())
|
||||
self.width_spin.valueChanged.connect(self.face_width_spin.setMaximum)
|
||||
add_row(trans_section, "Dialogue + Face:", size_field(self.face_width_spin))
|
||||
|
||||
self.list_width_spin = QSpinBox()
|
||||
self.list_width_spin.setButtonSymbols(QSpinBox.NoButtons)
|
||||
self.list_width_spin.setRange(20, 200)
|
||||
|
|
@ -1210,6 +1222,7 @@ class ConfigTab(QWidget):
|
|||
|
||||
# Formatting settings
|
||||
self.width_spin.setValue(int(_get("width", "60")))
|
||||
self.face_width_spin.setValue(int(_get("faceWidth", "50")))
|
||||
self.list_width_spin.setValue(int(_get("listWidth", "100")))
|
||||
self.note_width_spin.setValue(int(_get("noteWidth", "75")))
|
||||
self.convert_quotes_cb.setChecked(
|
||||
|
|
@ -1274,6 +1287,7 @@ class ConfigTab(QWidget):
|
|||
self.batch_size_spin.editingFinished.connect(self.auto_save)
|
||||
self.frequency_penalty_spin.editingFinished.connect(self.auto_save)
|
||||
self.width_spin.editingFinished.connect(self.auto_save)
|
||||
self.face_width_spin.editingFinished.connect(self.auto_save)
|
||||
self.list_width_spin.editingFinished.connect(self.auto_save)
|
||||
self.note_width_spin.editingFinished.connect(self.auto_save)
|
||||
self.convert_quotes_cb.stateChanged.connect(self._on_convert_quotes_changed)
|
||||
|
|
@ -1299,6 +1313,7 @@ class ConfigTab(QWidget):
|
|||
self.batch_size_spin.editingFinished.disconnect(self.auto_save)
|
||||
self.frequency_penalty_spin.editingFinished.disconnect(self.auto_save)
|
||||
self.width_spin.editingFinished.disconnect(self.auto_save)
|
||||
self.face_width_spin.editingFinished.disconnect(self.auto_save)
|
||||
self.list_width_spin.editingFinished.disconnect(self.auto_save)
|
||||
self.note_width_spin.editingFinished.disconnect(self.auto_save)
|
||||
self.convert_quotes_cb.stateChanged.disconnect(self._on_convert_quotes_changed)
|
||||
|
|
@ -1358,6 +1373,7 @@ class ConfigTab(QWidget):
|
|||
"batchsize": str(self.batch_size_spin.value()),
|
||||
"frequency_penalty": str(self.frequency_penalty_spin.value()),
|
||||
"width": str(self.width_spin.value()),
|
||||
"faceWidth": str(min(self.width_spin.value(), self.face_width_spin.value())),
|
||||
"listWidth": str(self.list_width_spin.value()),
|
||||
"noteWidth": str(self.note_width_spin.value()),
|
||||
"convertQuotes": "true" if self.convert_quotes_cb.isChecked() else "false",
|
||||
|
|
@ -1422,6 +1438,7 @@ class ConfigTab(QWidget):
|
|||
|
||||
# Formatting settings
|
||||
self.width_spin.setValue(60)
|
||||
self.face_width_spin.setValue(50)
|
||||
self.list_width_spin.setValue(100)
|
||||
self.note_width_spin.setValue(75)
|
||||
self.convert_quotes_cb.setChecked(True)
|
||||
|
|
@ -1468,6 +1485,7 @@ class ConfigTab(QWidget):
|
|||
"batchsize": self.batch_size_spin.value(),
|
||||
"frequency_penalty": self.frequency_penalty_spin.value(),
|
||||
"width": self.width_spin.value(),
|
||||
"faceWidth": min(self.width_spin.value(), self.face_width_spin.value()),
|
||||
"listWidth": self.list_width_spin.value(),
|
||||
"noteWidth": self.note_width_spin.value(),
|
||||
"convertQuotes": self.convert_quotes_cb.isChecked(),
|
||||
|
|
|
|||
|
|
@ -1744,13 +1744,14 @@ class WorkflowTab(QWidget):
|
|||
|
||||
wrap_hint = QLabel(
|
||||
"Use Project Setup's measured rpgmaker_config recommendations, then apply the three "
|
||||
"wrap widths to .env. Font recommendations describe the game UI and are not applied here."
|
||||
"category widths plus the dialogue-face variant to .env. Font recommendations "
|
||||
"describe the game UI and are not applied here."
|
||||
)
|
||||
wrap_hint.setWordWrap(True)
|
||||
wrap_hint.setStyleSheet("color:#9d9d9d;font-size:13px;")
|
||||
wrap_inner.addWidget(wrap_hint)
|
||||
|
||||
# All three spinboxes on one row
|
||||
# Wrap settings on one row, including the narrower code-101 face variant.
|
||||
spins_row = QHBoxLayout()
|
||||
spins_row.setSpacing(16)
|
||||
|
||||
|
|
@ -1764,10 +1765,14 @@ class WorkflowTab(QWidget):
|
|||
return lbl, sp
|
||||
|
||||
lbl_w, self.wrap_width_spin = _spin_pair("Dialogue", 60)
|
||||
lbl_fw, self.wrap_face_spin = _spin_pair("Dialogue+Face", 50)
|
||||
self.wrap_face_spin.setMaximum(self.wrap_width_spin.value())
|
||||
self.wrap_width_spin.valueChanged.connect(self.wrap_face_spin.setMaximum)
|
||||
lbl_lw, self.wrap_list_spin = _spin_pair("List/Help", 70)
|
||||
lbl_nw, self.wrap_note_spin = _spin_pair("Notes", 60)
|
||||
|
||||
for lbl, sp in [(lbl_w, self.wrap_width_spin),
|
||||
(lbl_fw, self.wrap_face_spin),
|
||||
(lbl_lw, self.wrap_list_spin),
|
||||
(lbl_nw, self.wrap_note_spin)]:
|
||||
spins_row.addWidget(lbl)
|
||||
|
|
@ -1776,7 +1781,9 @@ class WorkflowTab(QWidget):
|
|||
|
||||
apply_wrap_btn = _make_btn("✔ Apply to .env", "#3a7a3a")
|
||||
apply_wrap_btn.setFixedWidth(140)
|
||||
apply_wrap_btn.setToolTip("Write width / listWidth / noteWidth into .env")
|
||||
apply_wrap_btn.setToolTip(
|
||||
"Write width / faceWidth / listWidth / noteWidth into .env"
|
||||
)
|
||||
apply_wrap_btn.clicked.connect(self._apply_wrap_config)
|
||||
spins_row.addWidget(apply_wrap_btn)
|
||||
|
||||
|
|
@ -3840,10 +3847,11 @@ class WorkflowTab(QWidget):
|
|||
self._log(f"❌ Could not copy {filename}: {exc}")
|
||||
|
||||
def _apply_wrap_config(self):
|
||||
"""Write width / listWidth / noteWidth back into .env."""
|
||||
"""Write dialogue, face-dialogue, list, and note widths back into .env."""
|
||||
import re as _re
|
||||
updates = {
|
||||
"width": str(self.wrap_width_spin.value()),
|
||||
"faceWidth": str(min(self.wrap_width_spin.value(), self.wrap_face_spin.value())),
|
||||
"listWidth": str(self.wrap_list_spin.value()),
|
||||
"noteWidth": str(self.wrap_note_spin.value()),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,10 @@ VOCAB = VOCAB_PATH.read_text(encoding="utf-8")
|
|||
LOCK = threading.Lock()
|
||||
THREAD_CTX = threading.local()
|
||||
WIDTH = int(os.getenv("width"))
|
||||
FACEWIDTH = max(
|
||||
1,
|
||||
min(WIDTH, int(os.getenv("faceWidth", str(max(1, WIDTH - 10))))),
|
||||
)
|
||||
LISTWIDTH = int(os.getenv("listWidth"))
|
||||
NOTEWIDTH = int(os.getenv("noteWidth"))
|
||||
MAXHISTORY = 10
|
||||
|
|
@ -728,6 +732,16 @@ def _facename101_speaker(cmd) -> str | None:
|
|||
return None
|
||||
|
||||
|
||||
def _101_has_face_graphic(cmd) -> bool:
|
||||
"""Return whether a standard code-101 command reserves face-image space."""
|
||||
params = cmd.get("parameters") or []
|
||||
return (
|
||||
len(params) >= 4
|
||||
and isinstance(params[0], str)
|
||||
and bool(params[0].strip())
|
||||
)
|
||||
|
||||
|
||||
def _entry_orig(entry) -> dict:
|
||||
"""Return _original dict on a database entry, or empty dict if absent."""
|
||||
orig = entry.get("_original") if isinstance(entry, dict) else None
|
||||
|
|
@ -2332,7 +2346,7 @@ def searchCodes(page, pbar, jobList, filename):
|
|||
syncIndex = 0
|
||||
maxHistory = MAXHISTORY
|
||||
VNameValue = None
|
||||
reduceWidthFlag = False # Track if 101 code has non-empty first parameter
|
||||
reduceWidthFlag = False # Track whether the active 101 reserves face space
|
||||
global LOCK
|
||||
global NAMESLIST
|
||||
global MISMATCH
|
||||
|
|
@ -2366,6 +2380,17 @@ def searchCodes(page, pbar, jobList, filename):
|
|||
currentSourceGroup = []
|
||||
nametag = ""
|
||||
|
||||
# Face layout affects the following message even when code-101 name
|
||||
# translation is disabled or face-to-speaker resolution exits early.
|
||||
if "code" in codeList[i] and codeList[i]["code"] == 101:
|
||||
reduceWidthFlag = _101_has_face_graphic(codeList[i])
|
||||
elif (
|
||||
reduceWidthFlag
|
||||
and "code" in codeList[i]
|
||||
and codeList[i]["code"] not in (401, -1)
|
||||
):
|
||||
reduceWidthFlag = False
|
||||
|
||||
## Event Code: 401 Show Text
|
||||
if "code" in codeList[i] and codeList[i]["code"] in [401, 405, -1] and ((codeList[i]["code"] in [401, -1] and CODE401) or (codeList[i]["code"] == 405 and CODE405)):
|
||||
# Save Code and starting index (j)
|
||||
|
|
@ -2756,7 +2781,7 @@ def searchCodes(page, pbar, jobList, filename):
|
|||
finalJAString = finalJAString.replace("<br>", " ")
|
||||
|
||||
# Determine width based on reduceWidthFlag
|
||||
currentWidth = WIDTH - 15 if reduceWidthFlag else WIDTH
|
||||
currentWidth = FACEWIDTH if reduceWidthFlag else WIDTH
|
||||
|
||||
if FIXTEXTWRAP is True and "_ABL" in nametag:
|
||||
translatedText = dazedwrap.wrapText(translatedText, width=100)
|
||||
|
|
@ -3205,9 +3230,6 @@ def searchCodes(page, pbar, jobList, filename):
|
|||
# Grab String
|
||||
jaString = ""
|
||||
if len(codeList[i]["parameters"]) > 4:
|
||||
# Set flag if first parameter has a non-empty string
|
||||
if isinstance(codeList[i]["parameters"][0], str) and codeList[i]["parameters"][0].strip():
|
||||
reduceWidthFlag = True
|
||||
jaString = codeList[i]["parameters"][4]
|
||||
# Check for Var (only when parameters[0] is not a face file,
|
||||
# i.e. fewer than 4 params — standard code 101 always has 4:
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ class ConfigTabRegressionTests(unittest.TestCase):
|
|||
"batchsize",
|
||||
"frequency_penalty",
|
||||
"width",
|
||||
"faceWidth",
|
||||
"listWidth",
|
||||
"noteWidth",
|
||||
"convertQuotes",
|
||||
|
|
@ -89,6 +90,7 @@ class ConfigTabRegressionTests(unittest.TestCase):
|
|||
"batchsize=42",
|
||||
"frequency_penalty=0.75",
|
||||
"width=88",
|
||||
"faceWidth=77",
|
||||
"listWidth=99",
|
||||
"noteWidth=111",
|
||||
"convertQuotes=false",
|
||||
|
|
@ -142,6 +144,7 @@ class ConfigTabRegressionTests(unittest.TestCase):
|
|||
self.assertEqual(tab.batch_size_spin.value(), 42)
|
||||
self.assertAlmostEqual(tab.frequency_penalty_spin.value(), 0.75)
|
||||
self.assertEqual(tab.width_spin.value(), 88)
|
||||
self.assertEqual(tab.face_width_spin.value(), 77)
|
||||
self.assertEqual(tab.list_width_spin.value(), 99)
|
||||
self.assertEqual(tab.note_width_spin.value(), 111)
|
||||
self.assertFalse(tab.convert_quotes_cb.isChecked())
|
||||
|
|
@ -206,6 +209,7 @@ class ConfigTabRegressionTests(unittest.TestCase):
|
|||
tab.language_combo,
|
||||
tab.timeout_spin,
|
||||
tab.width_spin,
|
||||
tab.face_width_spin,
|
||||
tab.list_width_spin,
|
||||
tab.note_width_spin,
|
||||
),
|
||||
|
|
@ -319,6 +323,7 @@ class ConfigTabRegressionTests(unittest.TestCase):
|
|||
tab.batch_size_spin.setValue(64)
|
||||
tab.frequency_penalty_spin.setValue(1.25)
|
||||
tab.width_spin.setValue(72)
|
||||
tab.face_width_spin.setValue(62)
|
||||
tab.list_width_spin.setValue(84)
|
||||
tab.note_width_spin.setValue(96)
|
||||
tab.convert_quotes_cb.setChecked(True)
|
||||
|
|
@ -350,6 +355,7 @@ class ConfigTabRegressionTests(unittest.TestCase):
|
|||
"batchsize": "64",
|
||||
"frequency_penalty": "1.25",
|
||||
"width": "72",
|
||||
"faceWidth": "62",
|
||||
"listWidth": "84",
|
||||
"noteWidth": "96",
|
||||
"convertQuotes": "true",
|
||||
|
|
@ -374,6 +380,7 @@ class ConfigTabRegressionTests(unittest.TestCase):
|
|||
self.assertEqual(reloaded.batch_size_spin.value(), 64)
|
||||
self.assertAlmostEqual(reloaded.frequency_penalty_spin.value(), 1.25)
|
||||
self.assertEqual(reloaded.width_spin.value(), 72)
|
||||
self.assertEqual(reloaded.face_width_spin.value(), 62)
|
||||
self.assertEqual(reloaded.list_width_spin.value(), 84)
|
||||
self.assertEqual(reloaded.note_width_spin.value(), 96)
|
||||
self.assertTrue(reloaded.convert_quotes_cb.isChecked())
|
||||
|
|
@ -409,6 +416,7 @@ class ConfigTabRegressionTests(unittest.TestCase):
|
|||
self.assertEqual(tab.batch_size_spin.value(), 30)
|
||||
self.assertAlmostEqual(tab.frequency_penalty_spin.value(), 0.05)
|
||||
self.assertEqual(tab.width_spin.value(), 60)
|
||||
self.assertEqual(tab.face_width_spin.value(), 50)
|
||||
self.assertEqual(tab.list_width_spin.value(), 100)
|
||||
self.assertEqual(tab.note_width_spin.value(), 75)
|
||||
self.assertTrue(tab.convert_quotes_cb.isChecked())
|
||||
|
|
@ -431,6 +439,7 @@ class ConfigTabRegressionTests(unittest.TestCase):
|
|||
"batchsize": "30",
|
||||
"frequency_penalty": "0.05",
|
||||
"width": "60",
|
||||
"faceWidth": "50",
|
||||
"listWidth": "100",
|
||||
"noteWidth": "75",
|
||||
"convertQuotes": "true",
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import re
|
|||
import sys
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
os.chdir(ROOT)
|
||||
|
|
@ -192,6 +193,80 @@ def _has_japanese(s: str) -> bool:
|
|||
|
||||
|
||||
class TestMVMZSourceOriginal(unittest.TestCase):
|
||||
def test_code101_face_detection_supports_mv_and_mz_shapes(self):
|
||||
self.assertTrue(
|
||||
mvmz._101_has_face_graphic(
|
||||
{"parameters": ["Actor1", 0, 0, 2]}
|
||||
)
|
||||
)
|
||||
self.assertTrue(
|
||||
mvmz._101_has_face_graphic(
|
||||
{"parameters": ["Actor1", 0, 0, 2, "Alice"]}
|
||||
)
|
||||
)
|
||||
self.assertFalse(
|
||||
mvmz._101_has_face_graphic(
|
||||
{"parameters": ["", 0, 0, 2, "Alice"]}
|
||||
)
|
||||
)
|
||||
|
||||
def test_code101_face_uses_configured_face_width_after_speaker_resolution(self):
|
||||
page = {
|
||||
"list": [
|
||||
{
|
||||
"code": 101,
|
||||
"indent": 0,
|
||||
"parameters": ["___princess1", 0, 0, 2, ""],
|
||||
},
|
||||
{
|
||||
"code": 401,
|
||||
"indent": 0,
|
||||
"parameters": ["これは顔付きの長い台詞です。"],
|
||||
},
|
||||
]
|
||||
}
|
||||
widths = []
|
||||
|
||||
def capture_wrap(text, width):
|
||||
widths.append(width)
|
||||
return text
|
||||
|
||||
with (
|
||||
patch.object(mvmz, "WIDTH", 60),
|
||||
patch.object(mvmz, "FACEWIDTH", 50),
|
||||
patch.object(mvmz, "FACENAME101", True),
|
||||
patch.object(mvmz.dazedwrap, "wrapText", side_effect=capture_wrap),
|
||||
):
|
||||
_run_search_codes(page)
|
||||
|
||||
self.assertEqual(widths, [50])
|
||||
|
||||
def test_code101_without_face_uses_full_dialogue_width(self):
|
||||
page = {
|
||||
"list": [
|
||||
{"code": 101, "indent": 0, "parameters": ["", 0, 0, 2, ""]},
|
||||
{
|
||||
"code": 401,
|
||||
"indent": 0,
|
||||
"parameters": ["これは通常幅の台詞です。"],
|
||||
},
|
||||
]
|
||||
}
|
||||
widths = []
|
||||
|
||||
def capture_wrap(text, width):
|
||||
widths.append(width)
|
||||
return text
|
||||
|
||||
with (
|
||||
patch.object(mvmz, "WIDTH", 60),
|
||||
patch.object(mvmz, "FACEWIDTH", 50),
|
||||
patch.object(mvmz.dazedwrap, "wrapText", side_effect=capture_wrap),
|
||||
):
|
||||
_run_search_codes(page)
|
||||
|
||||
self.assertEqual(widths, [60])
|
||||
|
||||
def test_choice_condition_prefix_parser_handles_nested_calls(self):
|
||||
prefix, label = mvmz._split_choice_condition_prefix(
|
||||
"if($gameSwitches.value(1) && v[31]>=4)迷宮四階"
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ class TranslationEngineDropdownTests(unittest.TestCase):
|
|||
"language",
|
||||
"timeout",
|
||||
"width",
|
||||
"faceWidth",
|
||||
"listWidth",
|
||||
"noteWidth",
|
||||
)
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ class WorkflowTranslationPromptTests(unittest.TestCase):
|
|||
self.assertIn("code408 : enable|skip", lowered)
|
||||
self.assertIn("translate code 408 plugin/comment text", lowered)
|
||||
self.assertIn("dialogue : width=", lowered)
|
||||
self.assertIn("facewidth=<code-101 face width>", lowered)
|
||||
self.assertIn("list/help: listwidth=", lowered)
|
||||
self.assertIn("notes : notewidth=", lowered)
|
||||
self.assertIn("face/portrait reservation", lowered)
|
||||
|
|
@ -103,6 +104,13 @@ class WorkflowTranslationPromptTests(unittest.TestCase):
|
|||
self.assertIn("QA Game Data Skill", workflow_source)
|
||||
self.assertIn('load_clipboard_skill("rpgmaker_translation_qa.md")', workflow_source)
|
||||
|
||||
def test_wrap_prompt_accounts_for_code101_faces_and_font_changes(self):
|
||||
prompt = load_clipboard_skill("wrap_config.md").casefold()
|
||||
self.assertIn("facewidth", prompt)
|
||||
self.assertIn("non-empty parameter 0", prompt)
|
||||
self.assertIn("plugin portraits", prompt)
|
||||
self.assertIn("pagination/manual reflow", prompt)
|
||||
|
||||
def test_image_translation_prompt_ends_skips_with_recovery_options(self):
|
||||
prompt = load_clipboard_skill("image_translation.md")
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue