Crusader_Decomp/USECODE/EUSECODE_extracted/immortality_npctrig_clauses.md
MaddoScientisto daa363c3d2 Add 'annotate-usecode' command to import USECODE IR JSON annotations
- Introduced a new command 'annotate-usecode' to import USECODE IR JSON annotation hints as Ghidra comments on compiled anchors.
- Added argument parsing for multiple IR JSON files, comment type selection, and a dry-run option.
- Implemented logic to read annotation records from the provided IR files and set comments on the corresponding addresses in Ghidra.
- Enhanced JSON schema to include response structure for the new command.
2026-03-24 18:14:20 +01:00

8.5 KiB

Immortality NPCTRIG Clauses

This report focuses on the surviving compact NPCTRIG frontier and splits the extracted slot bodies into prefix, clause, and tail regions. It is intended to make the slot 0x0A versus slot 0x20 difference explicit enough to compare against the runtime-side slot-0x0A consumer path.

NPCTRIG slot 0x0A

  • Event hint: equip.
  • Open header: 0x5A 0x06 0x5C 0x013E -> NPCTRIG with event-code byte 0x11.
  • First tail-field offset: 0x0145.
  • Subheader offsets: 0x0064, 0x0093, 0x00C2, 0x00F1, 0x0120.
  • Subheader targets: 0x00DB, 0x00AC, 0x007D, 0x004E, 0x001F.
  • Subheader offset deltas: 0x2F, 0x2F, 0x2F, 0x2F.
  • Subheader target deltas: 0xFFD1, 0xFFD1, 0xFFD1, 0xFFD1.
  • Runtime-shape motifs: writeback_57_02=yes, push_24_51=yes, field_4b_fe_0f=0.
Segment Range Len Local Labels Subheaders Branch 3F 0A Writeback 57 02 Push 24 51 Field 4B FE 0F Motif Offsets Prefix Suffix
prefix 0x0000..0x0064 100 0x0017,0x001A,0x0026,0x0030,0x0036,0x004D 0 1 1 1 0 branch_3f_0a=+0x45; writeback_57_02=+0x56; push_24_51=+0x49 5a065c3e014e50435452494700000b11 02630320006efe5e54010112
clause_1 0x0064..0x0093 47 0x007C 1 1 1 1 0 subheader_53_5c=+0x00; branch_3f_0a=+0x10; writeback_57_02=+0x21; push_24_51=+0x14 535cdb004e504354524947000052bc00 02630320006efe5e54010112
clause_2 0x0093..0x00C2 47 0x00AB 1 1 1 1 0 subheader_53_5c=+0x00; branch_3f_0a=+0x10; writeback_57_02=+0x21; push_24_51=+0x14 535cac004e5043545249470000528d00 02630320006efe5e54010112
clause_3 0x00C2..0x00F1 47 0x00DA 1 1 1 1 0 subheader_53_5c=+0x00; branch_3f_0a=+0x10; writeback_57_02=+0x21; push_24_51=+0x14 535c7d004e5043545249470000525e00 02630320006efe5e54010112
clause_4 0x00F1..0x0120 47 0x0109 1 1 1 1 0 subheader_53_5c=+0x00; branch_3f_0a=+0x10; writeback_57_02=+0x21; push_24_51=+0x14 535c4e004e5043545249470000522f00 02630320006efe5e54010112
clause_5 0x0120..0x0145 37 0x0130,0x013F 1 0 0 0 0 subheader_53_5c=+0x00 535c1f004e5043545249470000520000 1e0a24006efa5b4700500501
tail 0x0145..0x0175 48 - 0 0 0 0 0 - 6900007265666572656e740000690a00 74656d32000024fa026e007a

Repeated windows (8-byte):

  • 4E 50 43 54 52 49 47 00 at 0x0005, 0x0068, 0x0097, 0x00C6, 0x00F5, 0x0124
  • 50 43 54 52 49 47 00 00 at 0x0006, 0x0069, 0x0098, 0x00C7, 0x00F6, 0x0125
  • 40 06 57 02 02 63 03 20 at 0x0054, 0x0083, 0x00B2, 0x00E1, 0x0110
  • 06 57 02 02 63 03 20 00 at 0x0055, 0x0084, 0x00B3, 0x00E2, 0x0111
  • 57 02 02 63 03 20 00 6E at 0x0056, 0x0085, 0x00B4, 0x00E3, 0x0112
  • 02 02 63 03 20 00 6E FE at 0x0057, 0x0086, 0x00B5, 0x00E4, 0x0113

Repeated windows (6-byte):

  • 4E 50 43 54 52 49 at 0x0005, 0x0068, 0x0097, 0x00C6, 0x00F5, 0x0124
  • 50 43 54 52 49 47 at 0x0006, 0x0069, 0x0098, 0x00C7, 0x00F6, 0x0125
  • 43 54 52 49 47 00 at 0x0007, 0x006A, 0x0099, 0x00C8, 0x00F7, 0x0126
  • 54 52 49 47 00 00 at 0x0008, 0x006B, 0x009A, 0x00C9, 0x00F8, 0x0127
  • 40 06 57 02 02 63 at 0x0054, 0x0083, 0x00B2, 0x00E1, 0x0110
  • 06 57 02 02 63 03 at 0x0055, 0x0084, 0x00B3, 0x00E2, 0x0111

Runtime-fit candidates:

  • Candidate clause selector starts: 0x0064, 0x0093, 0x00C2, 0x00F1, 0x0120.
  • Candidate clause selector targets: 0x00DB, 0x00AC, 0x007D, 0x004E, 0x001F.
  • Uniform selector stride: 0x2F; full clauses carrying both push_24_51 and writeback_57_02: 4.
  • Runtime side anchor: 000d:5572 proves the wrapper extra word is additive (entity_vm_slot_load_value(...) + offset), while 000d:21ed -> 000d:2433 copies one inline blob, reads two signed metadata bytes, then consumes a word matrix where byte A controls the lead-word row count and byte B controls the shared target-list width.

Tail field offsets:

  • 0x0145 -> 69:0000->referent
  • 0x0152 -> 69:000A->event
  • 0x015C -> 24:02FE->item
  • 0x015F -> 69:6574->m
  • 0x0165 -> 24:02FC->item2
  • 0x0168 -> 69:6574->m2
  • 0x016F -> 24:02FA->n

NPCTRIG slot 0x20

  • Event hint: -.
  • Open header: 0x5A 0x06 0x5C 0x0120 -> NPCTRIG with event-code byte 0x01.
  • First tail-field offset: 0x0127.
  • Subheader offsets: 0x00BA.
  • Subheader targets: 0x0067.
  • Subheader offset deltas: -.
  • Subheader target deltas: -.
  • Runtime-shape motifs: writeback_57_02=no, push_24_51=no, field_4b_fe_0f=10.
Segment Range Len Local Labels Subheaders Branch 3F 0A Writeback 57 02 Push 24 51 Field 4B FE 0F Motif Offsets Prefix Suffix
prefix 0x0000..0x00BA 186 0x001C,0x0029,0x0037,0x0044,0x004C,0x004D,0x005B,0x0068 0 1 0 0 5 branch_3f_0a=+0x51; field_4b_fe_0f=+0x53,+0x60,+0x6D,+0x7A,+0xA0 5a065c20014e50435452494700000b01 570002110a23005e54010112
clause_1 0x00BA..0x0127 109 0x00C7,0x00D4,0x00E1,0x00EE,0x00F1,0x00FF,0x0112,0x0121 1 0 0 0 5 subheader_53_5c=+0x00; field_4b_fe_0f=+0x12,+0x1F,+0x2C,+0x4D,+0x5F 535c67004e50435452494700005b6200 0f06e5006efa5b6f00500501
tail 0x0127..0x0159 50 - 0 0 0 0 0 - 6900007265666572656e740000690a00 000024fa026974656d32007a

Repeated windows (8-byte):

  • 4E 50 43 54 52 49 47 00 at 0x0005, 0x00BE
  • 50 43 54 52 49 47 00 00 at 0x0006, 0x00BF
  • 4B FE 0F 06 52 00 6E FA at 0x0060, 0x00CC
  • FE 0F 06 52 00 6E FA 5B at 0x0061, 0x00CD
  • 4B FE 0F 06 53 00 6E FA at 0x006D, 0x00D9
  • FE 0F 06 53 00 6E FA 5B at 0x006E, 0x00DA

Repeated windows (6-byte):

  • 00 0A 00 4B FE 0F at 0x005D, 0x006A, 0x0077
  • 0A 00 4B FE 0F 06 at 0x005E, 0x006B, 0x0078
  • 00 0A 05 4B FE 0F at 0x00C9, 0x00D6, 0x00E3
  • 0A 05 4B FE 0F 06 at 0x00CA, 0x00D7, 0x00E4
  • 4E 50 43 54 52 49 at 0x0005, 0x00BE
  • 50 43 54 52 49 47 at 0x0006, 0x00BF

Runtime-fit candidates:

  • Candidate clause selector starts: 0x00BA.
  • Candidate clause selector targets: 0x0067.
  • Uniform selector stride: -; full clauses carrying both push_24_51 and writeback_57_02: 0.
  • Runtime side anchor: 000d:5572 proves the wrapper extra word is additive (entity_vm_slot_load_value(...) + offset), while 000d:21ed -> 000d:2433 copies one inline blob, reads two signed metadata bytes, then consumes a word matrix where byte A controls the lead-word row count and byte B controls the shared target-list width.

Tail field offsets:

  • 0x0127 -> 69:0000->referent
  • 0x0134 -> 69:000A->typeNpc
  • 0x0140 -> 24:02FE->n
  • 0x0146 -> 24:02FC->item
  • 0x0149 -> 69:6574->m
  • 0x014F -> 24:02FA->item2
  • 0x0152 -> 69:6574->m2

Current Read

  • Slot 0x0A now reads as a repeated clause ladder, not a monolithic blob: 5 subheaders sit on a uniform 0x2F, 0x2F, 0x2F, 0x2F byte stride, and their targets walk backward by 0xFFD1, 0xFFD1, 0xFFD1, 0xFFD1. Each clause block carries one branch_3f_0a, one push_24_51, and one writeback_57_02, which fits an event-bearing clause stream better than a pure type filter.
  • Slot 0x20 is structurally different even before the tail fields: its open event-code byte is 0x01 instead of 0x11, it has only one class-labelled subheader, no writeback_57_02, no push_24_51, and 10 field_4b_fe_0f hits concentrated around repeated 0x0A 00/05 4B FE 0F ... windows. That is a materially better fit for a typed gate or setup/attachment body than for the live event-emission ladder.
  • This split matches the current runtime-side bridge better than the previous undifferentiated frontier. The verified slot-0x0A wrapper 0005:2c35 seeds mask 0x0400, slot 0x0A, and one additive word that 000d:5572 applies directly to the loaded slot value before 000d:21ed consumes the result. The exact 000d:21ed -> 000d:22bc contract is now narrower too: after copying the inline blob it reads two signed bytes, uses byte A as the lead-word row count, uses byte B as the shared target-list width, performs A x B entity_link calls, and pushes back only non-0x0400 words. NPCTRIG slot 0x0A is the only surviving compact body here with a natural five-row selector family (5 evenly spaced clause starts at stride 0x2F), while slot 0x20 offers only one clause and no matching writeback/push motif.