Map Animation EXE Pattern Review

타일 교체/offset 가설과 EXE animation dirty redraw 근거를 분리한 요약이다.

결론: Current EXE/runtime evidence grounds layer1 0x40 dirty redraw and cache self-blit visible motion for the known fire/waterfall/beach animated regions.
The known visible map animation previews now use cache/self-blit evidence where available. Palette VM and tile-write handlers remain useful secondary paths, but they are not the primary visible-motion model for these regions.
50x40 animated maps
12000x40 cells
0/13tile replacement sequence hits
2map1-near palette candidates
0direct animated tile writes
2coordinate-only tile-write hits
0coordinate hits in animated roots
2coordinate hits rejected
24map_a self-blit command samples
24map_c unpromoted candidates
2map_c3 whirlpool frame loops

승격/미승격

확정: The layer1 0x40 consumer marks viewport cells dirty and does not choose alternate layer0 tile ids at that point. Palette opcodes 0x38/0x39 are table-dispatched VM commands and eventually apply through DirectDrawPalette::SetEntries. Opcode 0x58/0x6b/0x76 tile-grid mutation handlers are real, but they do not yet bind to the 0x40 fire/waterfall visible motion loop.

부정 증거: No simple contiguous tile-id replacement table was found for the known fire/waterfall candidate sequences.

미확정: The known visible map animation previews now use cache/self-blit evidence where available. Palette VM and tile-write handlers remain useful secondary paths, but they are not the primary visible-motion model for these regions.

map_review 미리보기 의미: visual approximation / audit helper. runtime tile-id replacement의 증거로 쓰지 않는다.

Known Tile Sequence Scan

familysequencecontiguous hits by encoding
map1_01a fire 4x3 row variants396 -> 436 -> 476u16le: 0
u32le: 0
map1_01a fire 4x3 row variants397 -> 437 -> 477u16le: 0
u32le: 0
map1_01a fire 4x3 row variants398 -> 438 -> 478u16le: 0
u32le: 0
map1_01a fire 4x3 row variants399 -> 439 -> 479u16le: 0
u32le: 0
map1_02b waterfall/water row variants394 -> 434 -> 474u16le: 0
u32le: 0
map1_02b waterfall/water row variants395 -> 435 -> 475u16le: 0
u32le: 0
map1_02b waterfall/water row variants436 -> 396 -> 476u16le: 0
u32le: 0
map1_02b waterfall/water row variants437 -> 397 -> 477u16le: 0
u32le: 0
map1_02b waterfall/water row variants438 -> 398 -> 478u16le: 0
u32le: 0
map1_02b waterfall/water row variants439 -> 399 -> 479u16le: 0
u32le: 0
map1_02b bridge/static neighbor controls58 -> 59 -> 60u8: 0
u16le: 0
u32le: 0
map1_02b bridge/static neighbor controls85 -> 86 -> 87u8: 0
u16le: 0
u32le: 0
map1_02b bridge/static neighbor controls293 -> 294 -> 295u16le: 0
u32le: 0

Individual Tile ID Occurrences

개별 u16 값은 EXE 안에 흩어져 있지만, 순차 치환 테이블 형태로는 잡히지 않는다.

tileu16 hit countsectionssample VAs
58285{'.text': 28, '.data': 210, '.rsrc': 1, '.reloc': 46}0x00405414 0x0040d5f9 0x0040f2c3 0x0040f3dc 0x0040f532 0x0040fe69 0x0040ffcc 0x00410da2
59177{'.text': 23, '.data': 110, '.reloc': 44}0x00407201 0x00407507 0x0040d9b5 0x00410483 0x0041520a 0x0041c100 0x0041c3ab 0x0041c6a4
60202{'.text': 33, '.data': 118, '.reloc': 51}0x0040251a 0x0040384b 0x00404362 0x004046ae 0x00404829 0x004048a6 0x004052fc 0x00406d4c
852295{'.text': 1470, '.data': 824, '.idata': 1}0x0040100a 0x0040102b 0x004010c7 0x00401183 0x004012b5 0x0040130a 0x00401321 0x00401338
8639{'.text': 11, '.data': 22, '.idata': 1, '.rsrc': 5}0x0040e277 0x00416478 0x0041a614 0x004226bf 0x00427fb0 0x00430e49 0x00430f55 0x00433d61
87907{'.text': 862, '.data': 40, '.idata': 5}0x00402dc7 0x00403128 0x00403383 0x004033ec 0x00403495 0x0040366d 0x004039e0 0x00403a99
29340{'.text': 1, '.data': 39}0x0042898e 0x00442ce3 0x00444bcc 0x0044544e 0x004454ca 0x00450dd2 0x00450e2e 0x0046832c
2948{'.text': 2, '.data': 6}0x0040f493 0x00421d6e 0x004d2e1f 0x0051e656 0x005220ea 0x0052212e 0x00526ea0 0x00526efa
29538{'.text': 6, '.data': 32}0x00407145 0x0040f4cb 0x00410cb5 0x0041326e 0x00413d0f 0x00424166 0x00444bc8 0x00468328
39423{'.text': 12, '.data': 11}0x004013a5 0x00401436 0x0040160c 0x0040179e 0x004153a9 0x004167be 0x0041690b 0x00416aca
39511{'.text': 4, '.data': 7}0x0043702c 0x004371e4 0x00437253 0x00438d1f 0x004ad6fa 0x004ad71e 0x004ad726 0x004ddd90
39611{'.text': 2, '.data': 8, '.reloc': 1}0x00424b46 0x0042ed6e 0x004a9fdc 0x004ad7da 0x004ad7fe 0x004ad81e 0x004b984f 0x004b9b13
3976{'.text': 2, '.data': 4}0x00401c28 0x00401c67 0x004ad892 0x004ad8b6 0x004ad8d6 0x004ccb56
3985{'.text': 2, '.data': 3}0x00405a27 0x00433b02 0x004acd6e 0x004acdfa 0x004de524
3995{'.text': 2, '.data': 3}0x0040c534 0x004359bb 0x004ace4e 0x004aceda 0x004e0542
43438{'.text': 5, '.data': 33}0x00407f55 0x00409311 0x0042b5c0 0x00430c33 0x00431647 0x004747c2 0x00474abe 0x00474bf2
4354{'.text': 1, '.data': 3}0x00401898 0x0047464a 0x00474686 0x0048bbf3
43615{'.text': 3, '.data': 11, '.reloc': 1}0x00408a44 0x0040cd37 0x0040e97a 0x00442e79 0x0047448a 0x004745ce 0x004746a2 0x00475032
43715{'.text': 3, '.data': 12}0x0040486a 0x004096c0 0x0040a0cf 0x00474482 0x004746a6 0x00474732 0x0047503a 0x004750d2
43894{'.text': 1, '.data': 93}0x0043a5a6 0x0043ceec 0x0043f13c 0x00444dc8 0x00444f78 0x004451dc 0x004456b0 0x004458e4
4393{'.data': 3}0x004748de 0x004748ea 0x0047671e
4749{'.text': 4, '.data': 3, '.idata': 1, '.rsrc': 1}0x00401871 0x00405f2f 0x0040cd27 0x00411356 0x00492276 0x00492296 0x004922b6 0x005a0c02
4754{'.text': 2, '.data': 2}0x00405f1c 0x0041c20b 0x0049231e 0x00492332
4767{'.text': 4, '.data': 3}0x0041dee9 0x004235cd 0x00424e5f 0x0042f10a 0x00492382 0x004923a6 0x004923c6
4777{'.text': 2, '.data': 5}0x004079c0 0x00420bae 0x0045ae4a 0x0045ae5e 0x0045ae7e 0x0045ae92 0x004ded0c
4786{'.text': 2, '.data': 4}0x00407752 0x00411454 0x00459fbe 0x00459fca 0x0045aec2 0x004ccb66
4795{'.text': 5}0x00407f28 0x004092e4 0x00423ba7 0x00430c06 0x0043161a

Tile-Write VM Command Scan

tile-grid write handler 자체는 확정이지만, 현재 known 0x40 source tile id를 직접 써서 모닥불/폭포를 재생한다는 증거는 없다.

summary: {'animatedTileIdCount': 27, 'animatedCoordinatePairCount': 1008, 'maxAnimatedMapWidth': 100, 'maxAnimatedMapHeight': 96, 'candidateAlignmentCounts': {'vm-aligned-local-high': 45, 'vm-aligned-local-medium': 45, 'vm-aligned-local-weak': 47}, 'plausibleAlignedOpcode58Count': 90, 'directAnimatedTileWriteCount': 0, 'coordinateOnlyAlignedHitCount': 2, 'coordinateOnlyInsideAnimatedRootCount': 0, 'coordinateOnlyRejectedCount': 2, 'rawAnimatedTileFalsePositiveSampleCount': 8, 'asciiFalsePositiveSampleCount': 16}

opcodehandlerbyteslayoutsemanticspromotion
0x580x00407686858 mode u16(tileId) u16(x) u16(y)mode 0 writes tileId to layer0 grid 0x00595af0 at y * mapWidth + x
mode 1 writes tileId/flag to layer1 grid 0x0058d7d0 at y * mapWidth + x
both modes call 0x004255eb(x, y) to invalidate the touched tile
confirmed-handler
0x6b0x00408d10126b mode actorFilter u16(xOffset) u16(yOffset) u16(tileId)iterates active descriptor slots 0x004576e8/0x0059dd70
matches actor id or 0xff wildcard
writes tileId at active-object base coordinate plus signed offsets
confirmed-handler-object-relative
0x760x00409f231276 mode actorFilter u16(xOffset) u16(yOffset) u16(tileId)iterates linked active object list rooted at 0x00574100
matches actor id, 0xfe current context, or 0xff wildcard
writes tileId at active-object base coordinate plus signed offsets
confirmed-handler-object-relative

Coordinate-only aligned hits

좌표만 0x40 영역과 겹치는 경우다. tile id가 animated source tile이 아니므로 animation proof로 승격하지 않는다.

VAmodetilex,yalignmentbest rootclassificationcontaining root grouppreview
0x00446ab802033,61vm-aligned-local-high0x00446aacrejected-nonanimated-or-unbound-root
resource-group-contained-nonanimated
scene-text-group-005 13:1 map5_11i map5_12i map5_13i map5_14i0x6d 00 00 00
0x03 -> 0x004469d4
0x58 00 14 00 21 00 3d 00
0x32 00 f9 00 d0 6a 44 00
0x58 00 15 00 21 00 3d 00
0x00446ac802133,61vm-aligned-local-high0x00446aacrejected-nonanimated-or-unbound-root
resource-group-contained-nonanimated
scene-text-group-005 13:1 map5_11i map5_12i map5_13i map5_14i0x6d 00 00 00
0x03 -> 0x004469d4
0x58 00 14 00 21 00 3d 00
0x32 00 f9 00 d0 6a 44 00
0x58 00 15 00 21 00 3d 00

Rejected raw animated tile hits

known animated tile id처럼 보이나 좌표가 맵 범위를 벗어난 raw byte overlap 샘플이다.

VAtilex,yalignmentreason
0x0047fb36590,456vm-aligned-local-weakknown animated tile id appears, but x/y is outside known map dimensions; treated as false-positive byte overlap
0x004bd74e580,496vm-aligned-local-weakknown animated tile id appears, but x/y is outside known map dimensions; treated as false-positive byte overlap
0x004bd776590,496vm-aligned-local-weakknown animated tile id appears, but x/y is outside known map dimensions; treated as false-positive byte overlap
0x004bd79e590,496vm-aligned-local-weakknown animated tile id appears, but x/y is outside known map dimensions; treated as false-positive byte overlap
0x004e3f26580,456vm-aligned-local-weakknown animated tile id appears, but x/y is outside known map dimensions; treated as false-positive byte overlap
0x005172c2600,456vm-aligned-local-weakknown animated tile id appears, but x/y is outside known map dimensions; treated as false-positive byte overlap
0x005172fa600,456vm-aligned-local-weakknown animated tile id appears, but x/y is outside known map dimensions; treated as false-positive byte overlap
0x00517382600,432vm-aligned-local-weakknown animated tile id appears, but x/y is outside known map dimensions; treated as false-positive byte overlap

Rejected ASCII/resource overlaps

리소스 문자열 주변에 걸린 0x58 byte는 command로 승격하지 않는다.

VAtile @ x,yalignmentascii contextreason
0x0043fbfa0 @ 0,0vm-aligned-local-weakzs_rr.cnscandidate overlaps asset/string bytes rather than an isolated VM command stream
0x00442f240 @ 0,0vm-aligned-local-weakzky_gen.cnscandidate overlaps asset/string bytes rather than an isolated VM command stream
0x00442f3c0 @ 0,0vm-aligned-local-weakzky_gen.cnscandidate overlaps asset/string bytes rather than an isolated VM command stream
0x004871500 @ 8,0vm-aligned-local-weakmiddata.candidate overlaps asset/string bytes rather than an isolated VM command stream
0x004871600 @ 16,0vm-aligned-local-weakmiddata.mlkcandidate overlaps asset/string bytes rather than an isolated VM command stream
0x004871700 @ 24,0vm-aligned-local-weakmiddata.mlkcandidate overlaps asset/string bytes rather than an isolated VM command stream
0x004871800 @ 32,0vm-aligned-local-mediummiddata.mlkcandidate overlaps asset/string bytes rather than an isolated VM command stream
0x004900470 @ 0,0vm-aligned-local-weakzky_ao.cnscandidate overlaps asset/string bytes rather than an isolated VM command stream
0x0049005f0 @ 0,0vm-aligned-local-weakzky_ao.cnscandidate overlaps asset/string bytes rather than an isolated VM command stream
0x004900730 @ 88,0vm-aligned-local-medium_ao.cnscandidate overlaps asset/string bytes rather than an isolated VM command stream
0x0049047b0 @ 32,0vm-aligned-local-mediumzi_ibo.cnscandidate overlaps asset/string bytes rather than an isolated VM command stream
0x004a3d610 @ 64,0vm-aligned-local-weakzi_ikkak.cnscandidate overlaps asset/string bytes rather than an isolated VM command stream
0x004a3d710 @ 0,0vm-aligned-local-weakzi_ikkak.cnscandidate overlaps asset/string bytes rather than an isolated VM command stream
0x004a5adc0 @ 0,0vm-aligned-local-weakzky_shu.cnscandidate overlaps asset/string bytes rather than an isolated VM command stream
0x004a5af40 @ 0,0vm-aligned-local-weakzky_shu.cnscandidate overlaps asset/string bytes rather than an isolated VM command stream
0x004b0f120 @ 0,0vm-aligned-local-weakzs_rg.cnscandidate overlaps asset/string bytes rather than an isolated VM command stream

Surface Self-Blit / Cache Command Scan

0x40 dirty redraw가 아니라, 실제 CNS surface 내부 cache를 갱신하는 경로다. map_a/map_b에는 강한 근거가 있으나 map_c 해변은 아직 이 경로에 묶이지 않았다.

status: self-blit-helper-grounded-map-c-beach-runtime-confirmed

VAroleevidence
0x004256D1surface self-blit helpercalls BltFast wrapper twice, surface 0x0a -> 0x0a and surface 0x0b -> 0x0b, using rectBase + wordIndex * 16
0x0040791Fstream consumer into self-blit helperreads current stream pointer from context+0x40, rect table base from context+0xa8, then forwards two stream words into 0x004256D1
0x00417750DirectDraw Blt/BltFast wrapperfinal DirectDraw surface copy wrapper used by the self-blit helper

map_a / map_b rect tables

baseroleindexrect VArectsize
0x00442761map_a 64x48 cache block + source frames00x00442761[576, 144, 640, 192][64, 48]
0x00442761map_a 64x48 cache block + source frames10x00442771[0, 144, 64, 192][64, 48]
0x00442761map_a 64x48 cache block + source frames20x00442781[64, 144, 128, 192][64, 48]
0x00442761map_a 64x48 cache block + source frames30x00442791[128, 144, 192, 192][64, 48]
0x004427A1map_b/map_a strip-style cache source candidate00x004427a1[192, 144, 256, 192][64, 48]
0x004427A1map_b/map_a strip-style cache source candidate10x004427b1[544, 144, 560, 192][16, 48]
0x004427A1map_b/map_a strip-style cache source candidate20x004427c1[0, 144, 16, 192][16, 48]
0x004427A1map_b/map_a strip-style cache source candidate30x004427d1[16, 144, 32, 192][16, 48]
0x004427B1strip cache rect continuation00x004427b1[544, 144, 560, 192][16, 48]
0x004427B1strip cache rect continuation10x004427c1[0, 144, 16, 192][16, 48]
0x004427B1strip cache rect continuation20x004427d1[16, 144, 32, 192][16, 48]
0x004427B1strip cache rect continuation30x004427e1[32, 144, 48, 192][16, 48]

map_a promoted-like command samples

VAopcodeword4word6ptr/arg8raw
0x00442b090x5d010x000200025d 02 00 00 00 00 01 00 02 00 02 00
0x00442b150x5d020x000200025d 02 00 00 00 00 02 00 02 00 02 00
0x00442b210x5d030x000200025d 02 00 00 00 00 03 00 02 00 02 00
0x00442b2d0x5d040x000200025d 02 00 00 00 00 04 00 02 00 02 00
0x00442b490x5d010x0000025d5d 02 00 00 00 00 01 00 5d 02 00 00
0x00442b510x5d450x0000025d5d 02 00 00 04 00 05 00 5d 02 00 00
0x00442b590x5d890x0000025d5d 02 00 00 08 00 09 00 5d 02 00 00
0x00442b610x5d12130x0000025d5d 02 00 00 0c 00 0d 00 5d 02 00 00
0x00442b690x5d16170x0000025d5d 02 00 00 10 00 11 00 5d 02 00 00
0x00442b710x5d20210x000200025d 02 00 00 14 00 15 00 02 00 02 00
0x00442b7d0x5d020x0000025d5d 02 00 00 00 00 02 00 5d 02 00 00
0x00442b850x5d460x0000025d5d 02 00 00 04 00 06 00 5d 02 00 00
0x00442b8d0x5d8100x0000025d5d 02 00 00 08 00 0a 00 5d 02 00 00
0x00442b950x5d12140x0000025d5d 02 00 00 0c 00 0e 00 5d 02 00 00
0x00442b9d0x5d16180x0000025d5d 02 00 00 10 00 12 00 5d 02 00 00
0x00442ba50x5d20220x000200025d 02 00 00 14 00 16 00 02 00 02 00
0x00442bb10x5d030x0000025d5d 02 00 00 00 00 03 00 5d 02 00 00
0x00442bb90x5d470x0000025d5d 02 00 00 04 00 07 00 5d 02 00 00
0x00442bc10x5d8110x0000025d5d 02 00 00 08 00 0b 00 5d 02 00 00
0x00442bc90x5d12150x0000025d5d 02 00 00 0c 00 0f 00 5d 02 00 00
0x00442bd10x5d16190x0000025d5d 02 00 00 10 00 13 00 5d 02 00 00
0x00442bd90x5d20230x000200025d 02 00 00 14 00 17 00 02 00 02 00
0x00442bf50x5d010x000400025d 02 00 00 00 00 01 00 02 00 04 00
0x00442c010x5d020x000400025d 02 00 00 00 00 02 00 02 00 04 00

map_c root candidates, not promoted

map_c root의 0x65/0x02 행들은 trailing 값이 local pointer처럼 보이며, 아직 0x004256D1 self-blit helper 소비자로 연결되지 않았다.

VAopcodeword4word6ptr/arg8raw
0x0045dbb80x65120x0045dd7065 02 00 00 01 00 02 00 70 dd 45 00
0x0045dbcc0x65220x0045dd7065 02 00 00 02 00 02 00 70 dd 45 00
0x0045dbe00x65320x0045dd7065 02 00 00 03 00 02 00 70 dd 45 00
0x0045dbf40x65420x0045dd7065 02 00 00 04 00 02 00 70 dd 45 00
0x0045dc080x65520x0045dd7065 02 00 00 05 00 02 00 70 dd 45 00
0x0045dc1c0x65620x0045dd7065 02 00 00 06 00 02 00 70 dd 45 00
0x0045dc300x65720x0045dd7065 02 00 00 07 00 02 00 70 dd 45 00
0x0045dc440x65820x0045dd7065 02 00 00 08 00 02 00 70 dd 45 00
0x0045dc580x65920x0045dd7065 02 00 00 09 00 02 00 70 dd 45 00
0x0045dc6c0x651020x0045dd7065 02 00 00 0a 00 02 00 70 dd 45 00
0x0045dc800x651120x0045dd7065 02 00 00 0b 00 02 00 70 dd 45 00
0x0045dc940x651220x0045dd7065 02 00 00 0c 00 02 00 70 dd 45 00
0x0045dca80x651320x0045dd7065 02 00 00 0d 00 02 00 70 dd 45 00
0x0045dcbc0x651420x0045dd7065 02 00 00 0e 00 02 00 70 dd 45 00
0x0045dcd00x651520x0045dd7065 02 00 00 0f 00 02 00 70 dd 45 00
0x0045dce40x651620x0045dd7065 02 00 00 10 00 02 00 70 dd 45 00
0x0045dcf80x651720x0045dd7065 02 00 00 11 00 02 00 70 dd 45 00
0x0045dd0c0x651820x0045dd7065 02 00 00 12 00 02 00 70 dd 45 00
0x0045dd200x651920x0045dd7065 02 00 00 13 00 02 00 70 dd 45 00
0x0045dd340x652020x0045dd7065 02 00 00 14 00 02 00 70 dd 45 00
0x0045dd480x652120x0045dd7065 02 00 00 15 00 02 00 70 dd 45 00
0x0045dd5c0x652220x0045dd7065 02 00 00 16 00 02 00 70 dd 45 00
0x0045e2500x65020x0045e28465 02 00 00 00 00 02 00 84 e2 45 00
0x0045e25c0x65120x0045e28465 02 00 00 01 00 02 00 84 e2 45 00

map6_26c / map_c3 Whirlpool Object Animation

이 섹션은 layer1 0x40 타일 strip이 아니라, map_c3.cns extra-object 프레임 루프 근거다.

status: source-rect-table-and-slot-frame-loop-confirmed-placement-candidate

candidate placement: {'x': 53, 'y': 4, 'w': 10, 'h': 8, 'hitCount': 2, 'evidenceStatus': 'nearby-active-object-position-word-pairs; direct draw consumer still unproven'}

source rect table 0x0052df6c

indexrect VArectsize
00x0052df6c[0, 0, 160, 128][160, 128]
10x0052df7c[160, 0, 320, 128][160, 128]
20x0052df8c[320, 0, 480, 128][160, 128]
30x0052df9c[480, 0, 640, 128][160, 128]

slot 0x0c frame loop hits

VAslotframesnearby x,y candidatesraw
0x005314f00x000c[0, 1, 2, 3]53,4 word-pairs e802 0035, ea02 000421 00 01 00 00 00 0c 00 21 00 01 00 01 00 0c 00 21 00 01 00 02 00 0c 00 21 00 01 00 03 00 0c 00
0x00531bc80x000c[0, 1, 2, 3]53,4 word-pairs e802 0035, ea02 000421 00 01 00 00 00 0c 00 21 00 01 00 01 00 0c 00 21 00 01 00 02 00 0c 00 21 00 01 00 03 00 0c 00

resource refs

maprecordresource refslotplacement status
map2_13c0x00531fc40x00531fec0x000cresource-ref-only; candidate x=53 exceeds map width 37
map6_26c0x0053207c0x005320a40x000csource-rect-and-frame-loop-confirmed; placement candidate x=53,y=4

map1 Palette Candidates

후보 command stream shape는 맞지만 map root 실행 연결은 아직 증명되지 않았다.

VAopcodekindrangebest rootbindingnearest animated scene records
0x0043d9200x38/m1range-step-to-rgb0x10..0xef0x0043d904
vm-aligned-local-high
near-animated-scene-record-unverifiedmap1_01a 0x0043e798 dist=3732
map1_02b 0x0043e7f0 dist=3820
0x0043d96c0x38/m2range-step-to-backup0x10..0xef0x0043d91c
vm-aligned-local-high
near-animated-scene-record-unverifiedmap1_01a 0x0043e798 dist=3708
map1_02b 0x0043e7f0 dist=3796

Carried EXE Evidence

{
  "source": "out/map_animation_tile_review.json",
  "status": "animation-redraw-consumer-confirmed",
  "summary": "EXE consumers for layer1 0x40, dirty redraw, and palette mutation were found. 0x40 marks cells that must be redrawn because their pixels can change without changing the layer0 tile id at the redraw consumer. Palette-only does not explain the observed spatial motion, so the per-map visible motion stream remains unproven.",
  "confirmed": [
    "layer1 bit 0x40 is read by EXE during viewport redraw preparation.",
    "The 0x40 consumer marks the same map cells dirty every redraw pass; it does not choose alternate tile ids.",
    "The map draw path uses the current layer0 tile id directly, while 0x40 only affects redraw invalidation.",
    "The EXE has palette VM handlers and a deferred DirectDrawPalette SetEntries path.",
    "Generic VM palette opcodes are now length/mode grounded: 0x38 and 0x39 are 8-byte commands, while 0x3a and 0x3b are 4-byte commands.",
    "Opcode 0x38 is a palette step family: mode 0 steps a list toward target RGB, mode 1 steps a range toward stream RGB, and mode 2 steps a range toward backup palette bytes.",
    "Opcode 0x39 is a palette set family: mode 0 sets current palette list, mode 1 fills current palette range, mode 2 fills backup palette range, and mode 3 sets backup palette list.",
    "The non-transparent palette indices used by the current 0x40 layer0 source tiles have been mapped from CNS pixels.",
    "A stricter local VM alignment scan promotes a subset of raw 0x38/0x39 byte-pattern hits to VM-shaped palette script candidates.",
    "VM-aligned palette script roots are now cross-checked against scene/resource groups and nearby map resource records.",
    "The animated fire/waterfall/water regions sit on ordinary layer0 tile ids; 0x40 dirty redraw is grounded, but the visible motion stream is still unbound."
  ],
  "unresolved": [
    "The exact executed palette command for each map animation has not been bound to a specific map root yet.",
    "The palette-cycle timing/order is not fully tied to a specific map root yet.",
    "Resource binding is a correlation layer only. A contained or nearby resource group does not by itself prove runtime execution for that map.",
    "Broad static palette-command scans contain false positives unless tied to an executed VM command stream; local alignment reduces but does not eliminate this risk.",
    "Generic VM tile-write handlers still exist, but current 0x40 map animation evidence does not require them."
  ],
  "keyAddresses": {}
}