Implement BUNKI string layout opcodes
This commit is contained in:
@@ -2515,7 +2515,7 @@ matches BUNKI's later conversion: it finds the longest choice/title byte length,
|
||||
multiplies by 21, and divides by two to obtain the full-width glyph-space estimate used for panel width and
|
||||
the shared left edge of the primary labels.
|
||||
|
||||
The port currently skips `0x2c5`, leaving BUNKI's maximum-length local at zero. For FIELD's
|
||||
Before implementation, the port skipped `0x2c5`, leaving BUNKI's maximum-length local at zero. For FIELD's
|
||||
`待機`/`帰還`/`キャンセル` popup, the panel still hits the same 240-pixel minimum but the computed label
|
||||
origin moves from surface x=67 to x=120, a 53-pixel right shift which makes `キャンセル` touch/spill beyond
|
||||
the frame. TITLE's longer developer choices should expand the surface beyond 240 pixels; the skipped result
|
||||
@@ -2531,6 +2531,14 @@ row and advances the choice y cursor by `0x1e` even though the empty title has n
|
||||
`0x195` therefore removes the exact one-row downward shift; this is not a Godot font-baseline discrepancy or
|
||||
an inherited VN cursor indent.
|
||||
|
||||
Both operations are now implemented as shared VM semantics. `0x2c5` uses the same configurable native-string
|
||||
encoding helper as `0x1a6` (CP932 for SYS4), stops at an embedded NUL, and writes the unshifted byte count.
|
||||
`0x195` is ordinal inequality through the existing literal/global/local/string-pointer resolver and always
|
||||
writes zero or one, so stale destinations cannot leak into the branch. Focused tests cover mixed-width CP932,
|
||||
embedded-NUL termination, all observed comparison operand classes, and the exact BUNKI empty-title stale-handle
|
||||
case. The full 281-test engine suite, zero-warning Godot build, and threaded frontend selftest pass; manual
|
||||
DEBUGMAP and developer-menu visual rechecks remain.
|
||||
|
||||
---
|
||||
|
||||
## Native walls backlog (targets for this loop)
|
||||
|
||||
@@ -242,7 +242,7 @@ Implemented with domain-preserving addressed-array access, native signed 32-bit
|
||||
- **grounding:** source=investigation, confidence=high
|
||||
- **evidence:** Ghidra /v2: dispatch slot ctx[0x26c93+0x195] is op_0x195_string_not_equals@0x426f20. It resolves operands 2 and 3 as engine strings, compares their complete byte ranges through the same worker as sibling op 0x194, and writes compare_result!=0 to operand 1. Corpus: 17 sites; 15 immediately branch on the result. BUNKI uses three comparisons against the empty string for its optional title row.
|
||||
|
||||
This is the logical inverse of op 0x194 string-equals. Skipping it is stateful: the destination is not cleared. At BUNKI@0x905, local 0x99 still contains a nonzero graphics handle, so the missing write falsely reserves a 30-pixel title row and shifts every choice down.
|
||||
This is the logical inverse of op 0x194 string-equals. Skipping it is stateful: the destination is not cleared. At BUNKI@0x905, local 0x99 still contains a nonzero graphics handle, so the missing write falsely reserves a 30-pixel title row and shifts every choice down. The C# VM implements ordinal inequality through the shared string resolver; focused tests cover literal/global/local/pointer operands and the exact empty-title stale-handle overwrite.
|
||||
|
||||
### 0x1a6 `half-byte-string-length` (halve-strlen, argc 2)
|
||||
- **summary:** Write half the resolved string's byte length, using integer truncation.
|
||||
@@ -261,7 +261,7 @@ Native applies strlen to the NUL-terminated engine byte string and shifts the by
|
||||
- **grounding:** source=investigation, confidence=high
|
||||
- **evidence:** Ghidra /v2: op_0x2c5_byte_strlen@0x42a690 resolves operand 2, scans byte-by-byte through the terminating NUL, and writes the byte count to operand 1. Corpus: 23 sites in 10 scripts. BUNKI uses two sites to size its temporary menu surface and horizontally place all primary option strings.
|
||||
|
||||
This is raw strlen(bytes), not a .NET UTF-16 character count. BUNKI compares all option/title byte lengths, adds four bytes of padding, and converts the result to pixels; skipping the opcode leaves its local maximum at zero, forcing the minimum-width menu and shifting every primary label right.
|
||||
This is raw strlen(bytes), not a .NET UTF-16 character count. BUNKI compares all option/title byte lengths, adds four bytes of padding, and converts the result to pixels; skipping the opcode leaves its local maximum at zero, forcing the minimum-width menu and shifting every primary label right. The C# VM shares the configurable native-string byte counter used by op 0x1a6 (CP932 by default), including embedded-NUL termination; focused tests cover literals and local-string pointers.
|
||||
|
||||
## control
|
||||
|
||||
|
||||
@@ -462,8 +462,10 @@ the destination stays zero; the FIELD popup shifts 53 pixels right and the longe
|
||||
remains at its 240-pixel minimum. Corrected native/port screenshots reveal a separate exact one-row vertical
|
||||
shift: BUNKI uses missing opcode `0x195` (`string-not-equals`) to test its optional title against the empty
|
||||
string. Because a skipped opcode leaves its destination untouched, the final test reuses a nonzero graphics
|
||||
handle and falsely advances the choice cursor by 30 pixels. The next bounded implementation is therefore the
|
||||
shared CP932 byte-length opcode `0x2c5` plus inverse string comparison `0x195`, followed by a visual recheck.
|
||||
handle and falsely advances the choice cursor by 30 pixels. Both shared operations are now implemented with
|
||||
focused CP932/NUL, operand-resolution, and stale-destination regressions. All 281 engine tests, the zero-warning
|
||||
Godot build, and threaded selftest pass. The next bounded action is a visual recheck of the DEBUGMAP popup and
|
||||
TITLE developer menu.
|
||||
|
||||
## Later Phase B breadth
|
||||
|
||||
|
||||
Reference in New Issue
Block a user