
    HjS                      d Z ddlmZ ddlZddlZddlZddlZddlmZm	Z	m
Z
 ddlmZ ej                  j                  d e ee      j#                         j$                               ddlmZmZ  ee      j#                         j,                  d   Zedz  Zed	z  Zed
z  ZdZg dZi ddddddddddddddddddddddddddddddddddi ddddddddd dd!dd"dd#dd$dd%dd&dd'dd(dd)dd*dd+dd,di d-dd.dd/dd0dd1dd2dd3dd4dd5dd6dd7dd8dd9dd:dd;dd<dd=di d>dd?dd@ddAddBddCddDddEddFddGddHddIddJddddKddLddMdi dNddOddPddQddRddSddTddUddVddWddXddYddZdd[dd\dd]dd^di d_dd`ddaddbddcdddddeddfddgddhddiddjddkddlddmddnddodi dpddqddrddsddtdduddvddwddxddyddzdd{dd|dd}dd~dddddi ddddddddddddddddddddddddddddddddZddZddZddZ ddZ!ddZ"ddZ#ddZ$ddZ%ddZ&ddZ'ddZ(ddZ)ddZ*ddZ+ddZ,dddZ-ddZ.ddZ/ddZ0ddZ1ddZ2dddZ3ddZ4dddZ5ddZ6dddZ7ddZ8ddZ9ddZ:ddZ;ddZ<ddZ=ddZ>ddZ?ddZ@ddZAddZBdddZCddZDddZEddZFddZGddZHeIdk(  r eH        yy)zABuild a review page for layer1 0x40 animation-redraw map regions.    )annotationsN)Counterdefaultdictdeque)Path)decompress_cnsparse_image   outextract_fldzHwanse2.exe@   ))z.texti @ i i   )z.rdatai C iY  i  )z.data C   i                       	   
                                                                      !   "   #   $   %   &   '   (   )   *   +   ,   -   .   /   0   1   2   3   4   5   6   7   8   9   :   ;   <   =   >   ?   A   B   C   D   E   F   G   H   I   J   K   L   M   N   O   P   Q   R   S   T   U   V   W   X   Y   Z   [   \   ]   ^   _   `   a   b   c   d   e   f   g   h   i   j   k   l   m   n   o   p   q   r   s   t   u   v   w   x   y   z   {   |   }   ~                           c                     t         dz  j                  d      } t        j                  | j	                  dd      d   j                         j                  d            S )Nzmaps.jsutf-8encoding=r
   ;)OUT	read_textjsonloadssplitstriprstrip)texts    </home/exedev/hwanse/tools/build_map_animation_tile_review.py	load_mapsr      sL    )O&&&8D::djja(+113::3?@@    c           
         | d   }| d   d   }| d   d   }g }t        |      D ]3  \  }}|t        z  s|j                  ||z  ||z  ||   |d|dd       5 |S )Nwidthlayersr   r
   0x02x)xylayer0layer1	layer1Hex)	enumerateANIMATED_TILE_FLAGappend)map_infor   r   r   cellsindexflags          r   animated_cellsr      s    WEh"Fh"FE ( 
t))U]e^ -!$s_	

 Lr   c                R   | D ci c]  }|d   |d   f| }}t        |      }g }|rY|j                         }t        |g      }|g}|rm|j                         \  }}	|dz
  |	f|dz   |	f||	dz
  f||	dz   ffD ]:  }
|
|vr|j	                  |
       |j                  |
       |j                  |
       < |rm|D cg c]  }||   	 }}|D cg c]  }|d   	 }}|D cg c]  }|d   	 }}|j                  t        |      t        |      t        |      t        |      t        |      t        |      z
  dz   t        |      t        |      z
  dz   t        |      t        |D ch c]  }|d   	 c}      d       |rYt        |d       S c c}w c c}w c c}w c c}w c c}w )Nr   r   r
   r   )x0y0x1y1r   height	cellCountlayer0Tilesc                &    | d   | d   | d   | d   fS )Nr   r   r   r    rows    r   <lambda>z&connected_components.<locals>.<lambda>   s"    s4y#d)SYPSTXPY.Z r   key)
setpopr   popleftremover   minmaxlensorted)r   cellby_xypending
componentsstartqueuecoordsr   r   neighborcoordcomponent_cellsxsyss                  r   connected_componentsr      s   6;<dd3ic#T)<E<%jGJ
ug==?DAq!eQZ!a%aQZ!QUL (7*x(X&h'(  6<<E5<<<$34Dd3i44$34Dd3i44"g"g"g"gR3r7*Q.b'CG+a/ 1%/&R$tH~&RS		
 6 *"Z[[= = =44 'Ss   F;FFF%F$c                   | D ci c]  }|d   |d   f| }}t        |       }g }|D ]  }g }t        |d   |d   dz         D ]]  }g }t        |d   |d   dz         D ]-  }	|j                  |	|f      }|j                  |r|d   nd        / |j                  ||d	       _ |j                  i |d
|i        |S c c}w )Nr   r   r   r   r
   r   r   r   )r   tilesrows)r   rangegetr   )
r   r   r   r   
placements	componentr   r   r   r   s
             r   placement_componentsr      s    6;<dd3ic#T)<E<%e,JJ 7	y	$!(;< 	2AE9T?IdOa,?@ ?yy!Q(tT(^>? KKa%01	2 	5Y5567  =s   B=c                    t        t        |  dz  j                               }t        |      \  }}}}}|||dz  |dz  dS )N.cnsr   )r   r   columnsr   )r   EXTRACT_FLD
read_bytesr	   )stemdecodedr   r   _palette_pixels_bpps          r   tileset_sizer      sM    ktfDM9EEGHG-8-A*E68Wdf"fXZl[[r   c                   t        t        |  dz  j                               }t        |      \  }}}}}||z  dz   dz  dz  }g }t	        |      D ]  }	||dz
  |	z
  |z  ||	z
  |z   }
|dk(  r|j                  t        |
d |              :|dk(  r[g }|
d |dz   dz   D ]9  }|j                  |dz	         t        |      |k  s&|j                  |dz         ; |j                  |       t        d	|        ||||fS )
Nr   r-   r.   r   r
   r   r   r   zunsupported tileset bpp: )	r   r   r   r	   r   r   listr   
ValueError)r   r   r   r   palettepixelsbppstrider   r   r   valuesbytes                r   load_tileset_indicesr      s1   ktfDM9EEGHG*5g*>'E67FCs{RB&!+FD6] @fqj1n.&1*1FG!8KKS%[)*AXF.uqyQ./ /dai(v;&MM$+./ KK8>??@ &'4''r   c           	         | sg S g }| d   x}}| dd  D ]/  }||dz   k(  r|}|j                  ||d|dd|dd       |x}}1 |j                  ||d|dd|dd       |S )Nr   r
   r   r   r   endstartHexendHex)r   )indicesrangesr   previousr   s        r   palette_rangesr     s    	Fqz!EH !HqL HhbsDTbdemnqdr`stu  ! MME("U3K@P^`aijm`n\opqMr   c                @    | sy 	 t        | d      S # t        $ r Y y w xY w)Nr   )intr   values    r   parse_hex_var     s+    5"~ s    	c                N    | j                         j                  d      r| d d S | S )Nr   )lowerendswith)names    r   normalize_resource_namer  )  s&    

--f549?4?r   c                    t         dz  } | j                         sg S t        j                  | j	                  d            }g }|j                  dg       D ]p  }t        |j                  d            }t        |j                  d            }|j                  dg       D cg c]  }t        |       }}t        |j                  d      xs g       }|j                  d	      r(|j                  d	      d
k7  r|j                  |d	          |j                  |j                  d      |j                  d      |j                  d      |j                  d      |j                  d      |j                  d      ||t        t        |            t        t        |            |j                  d      |j                  d      d       s |S c c}w )Nz*scene_seq_resource_record_link_review.jsonr   r   groups	rootVaHexrootEndVaHex	resources	fieldMapsmapunboundidcontextKindcontextLabelselector	linkClassevidenceStatus)r  r  r  r  r  r  startVaendVamapsr  r  r  )r   existsr   r   r   r   r  r  r   r   r   r   )	pathpayloadr  groupstart_vaend_var
  r  r  s	            r   load_scene_resource_groupsr#  -  s~   ==D;;=	jj9:GFXr* 
		+ 67eii78?DyyVX?YZt,T2Z	ZEIIk*0b199U		% 0I =KKe%iio$yy7 %		. 9!IIj1"YY{3 %		. 9#s4y)#C	N3"YY{3"')),<"=	

. M) [s   !Gc                    g } t         dz  }|j                         r	t        j                  |j	                  d            D ]  }|j                  d      }t        |t              s%| j                  |j                  d      ||j                  d      xs d|d|j                  d	      |j                  d
g       D cg c]  }t        |       c}|j                  dg       D cg c]/  }|j                  d      st        |j                  dd            1 c}d        i }| D ]  }|d   |d   f}|||<    t        |j                         d       S c c}w c c}w )Nzscene_manifest.jsonr   r   recordVar  recordVaHexr   08x
sceneIdHextilesetsr  r
   )r  r%  r&  r(  r)  r  c                    | d   S Nr%  r   r   s    r   r   z$load_scene_records.<locals>.<lambda>c  s
    C
O r   r   )r   r  r   r   r   r   
isinstancer  r   r  r   r   )recordsr  r   	record_var
  itemdedupedr   s           r   load_scene_recordsr2  M  sg   G&&D{{}::dnngn>? 	C
+Ii-NN775> )#&77=#9#Qr)C=Q"%'',"7KN77S]_aKb c4!8!> c\_\c\cdoqs\t  "JTXx|  yA  yA  BH  yI"9$((62:N"O  "J			 G 5z3z?+ '.."(CDD !d "Js   ?E'E>Ec                   | j                  d      xs g }| j                  d      xs g }| j                  d      | j                  d      xs d| j                  d      xs d| j                  d      xs d|d d |d d t        t        |      |z        t        t        |      |z        | j                  d	      xs d| j                  d
      xs dd
S )Nr  r  r  r  r*  r  r  r   r  r  )
r  r  r  r  r  r  animatedMapsanimatedTilesetsr  r  )r   r   r   )r   animated_mapsanimated_tilesetsr  r  s        r   group_summaryr8  f  s    99V"D		+&,"IiioIIj)/RYY{+1r		.17RRar]s4y=89"3y>4E#EFYY{+1r))$45; r   c                H   | j                  d      | j                  d      | j                  d      t        || d   z
        | j                  dg       d d | j                  dg       d d | j                  d      |v t        t        | j                  dg             |z        d	S )
Nr  r&  r(  r%  r)  r   r  r   )r  r&  r(  distanceBytesr)  r  animatedMapr5  )r   absr   r   )recordr6  r7  root_vas       r   scene_record_summaryr?  w  s    zz% zz-0jj.Wvj'99:JJz2.r2ZZR0!4zz%(M9"3vzz*b'A#BEV#VW	 	r   c                    | D ch c]  }|d   	 c}| D ch c]  }|d   	 c}t               t               dS c c}w c c}w )Nr  sourceTileset)r4  r5  r  sceneRecords)r#  r2  )r   r   s     r   build_palette_binding_contextrC    sC    /34U4=ABcS1B,.*,	 4Bs   :?c           	        t        |       dddS |j                  d      xs
 t               }|j                  d      xs
 t               }|j                  d      xs g }|j                  d      xs g }|D cg c]:  }|j                  d      '|j                  d	      |d   cxk  r|d	   k  rn n|< }}|D cg c]  }t        |||       }}|D cg c](  }|j                  d      |j                  d	      '|* }	}g }
|	D ]D  }||v rt	        t        |d   z
        t        |d	   z
              }|
j                  ||f       F g }t        |
d
       d d D ](  \  }}t        |||      }||d<   |j                  |       * t        |fd      d d D cg c]  }t        |||       }}|D cg c]  }|d   s|d   s| }}|D cg c]  }|d   dk  s|d   s|d   s| }}|D cg c]  }|d   dk  s|d   s|d   s| }}|rd}d}n|rd}d}n|rd}d}n|rd}d}nd}d}|dd||||||dS c c}w c c}w c c}w c c}w c c}w c c}w c c}w ) Nz
no-vm-rootz;No VM root was selected for this palette command candidate.statusnoter4  r5  r  rB  r  r  c                    | d   S )Nr   r   )r0  s    r   r   z/palette_root_resource_binding.<locals>.<lambda>  s
    47 r   r   r   r:  c                &    t        | d   z
        S r,  )r<  )r   r>  s    r   r   z/palette_root_resource_binding.<locals>.<lambda>  s    c'C
O:S6T r   r   i   r;  i @  $resource-group-contains-animated-mapz[The VM root falls inside a selector-root group that also references animated map resources.z$resource-group-contained-nonanimatedzThe VM root falls inside a selector-root group, but that group does not reference the currently known 0x40 animated maps/tilesets.z%near-animated-scene-record-unverifiedz`The VM root is close to an animated scene/resource record, but not inside a selector-root range.z'near-animated-resource-group-unverifiedzeThe nearest selector-root group references animated resources, but the VM root is outside that group.zmap-binding-unprovenzZNo resource group or scene record currently binds this VM root to a specific animated map.r   r'  )rF  r  containingGroupsnearestGroupsnearestSceneRecordsnearestAnimatedSceneRecordsnearestAnimatedGroupsrG  )	r  r   r   r8  r   r<  r   r   r?  )root_va_hexcontextr6  r7  r  r.  r   
containingcontaining_summariesranged_groupsnearest_groupsdistancenearest_group_summariessummaryr=  nearest_recordsr   contained_animatednear_record_animatednear_group_animatedrF  rG  r>  s                         @r   palette_root_resource_bindingr]    sA   ;'G&0mnnKK/835M$67@35[["(bFkk.)/RG 99Y+		'0B0NSXYbScgnSqvw~qS 	J 
 akkW\M%@QRkk(.vu%))I2F2RW\W`W`ahWiWuUvMvN 1Js7U9%556GeGn<T8UVx/0	1
 !!.6JKBQO 0%}6GH#+ &&w/0 W*TUVXWXY 	V]4EwOO  ,s>/BcJ\F]  '#o*>&*HcR_N`dghzd{  /#o2F&2PVYZhVimp  rD  nE  7l	7 T	8q	:v'k '#'00.';!4	 	g
 lv
sT   <?III2II(II"I"I'+
I'6I' I,
I,I,c                    ||z  }||z  }t               }t        ||z  ||z  |z         D ]/  }t        ||z  ||z  |z         D ]  }|| |   |   xx   dz  cc<    1 |S )Nr
   )r   r   )	
index_rowstiler   	tile_sizetile_xtile_ycountsr   r   s	            r   tile_palette_countsre    s    G^FW_FiF6I%v	'9I'EF *v	)6I+=	+IJ 	*A:a=#$)$	** Mr   c                P   t        |       \  }}}}t               }g }|D ]  }	t        ||	|      }
t        |
j                         D ci c]  \  }}|dk7  s|| c}}      }|j	                  |       t        |      }|j                  |	t        |j                               t        |      |t        |      d        t        |      }ddt        |      t        |      |t        |      |j                  d      D cg c]  \  }}|d|d|d c}}|dd		S c c}}w c c}}w )
Nr   )r`  nonzeroPixelCount
indexCountr   r   zcns-palette-indices-mappedr   r   r   )r   indexHexr   zCounts are from the current layer0 source tiles inside layer1 0x40 cells. Index 0 is treated as transparent/background and excluded from this summary.)	rF  transparentIndexpaletteSizerh  r   r   
topIndicesperTilerG  )r   r   re  itemsupdater   r   sumr   r   r   most_common)r   r   r   _width_heightr   r_  totalper_tiler`  rd  r   countnonzero_countsr   useds                   r   palette_usagery    s8   +?+E(FGWjYEH 
$Zw? 6<<>!`<5%UZ^_U_%,!`a^$(%()>)>)@%A!'l"(1	

 %=D.7|$i & !& 1 1" 5
u 2eC[)9UK
  i  "a(
s   DD D"c                Z    t         D ]"  \  }}}}|| cxk  r	||z   k  sn || |z
  z   c S  y NPE_SECTIONS)va_namevmasizeoffsets        r   va_to_offsetr    s?    $/ ' sD&"!sTz!R#X&&' r   c                Z    t         D ]"  \  }}}}|| cxk  r	||z   k  sn || |z
  z   c S  y r{  r|  )r  r  r  r  section_offsets        r   offset_to_var  
  sA    ,7 3(sD.V;nt&;;&>1223 r   c           	         t        |      }|y g }|}t        d      D ]X  }|t        |       k\  r y | |   }|dk(  r|c S |dz   t        |       kD  r y |j                  t	        | ||dz                 |dz  }Z y )N      r   )r  r   r   r   tuple)exeptrr  entriescursor_r   s          r   palette_list_entriesr    s    #F~/1GF3Z 	SXFD=NA:C uS&1*567!	 r   c                *   | j                  d      xs i }|j                  d      }|j                  d      }t        |t              rt        |t              r||k\  r||z
  dz   nd }|dd ddS |dk\  s
|d	k  r|d
k\  rd|ddS |dk\  rd|ddS d|ddS )Nr   r   r   r
   zunknown-palette-scopez>No bounded palette index range was available for this command.)classpaletteEntryCountrG     r      broad-screen-palette-transitionzvTouches a broad palette range; treat as screen fade/transition evidence, not a localized map animation loop by itself.r>   zmedium-palette-transitionzgTouches a medium palette range; this can be an effect/fade and needs map-root binding before promotion.zlocalized-palette-candidatezbTouches a relatively small palette range; still needs map-root execution binding before promotion.)r   r-  r  )r   palette_ranger   r   r   s        r   palette_effect_scoper  $  s    GGG$*Mg&E


E
"C)%5*S#:NSVZ_S_C%K!OeiE},!%T
 	

 |#+6!& M
 	

 {0!&}
 	
 /"t r   c                   t        j                  d|      }g }d}	 | j                  ||      dk  r	 |S t              }|Bt	        fdt
        D        d      }|j                  d|d|d       t        |      |k\  r	 |S dz   }o)	N<Ir   c              3  P   K   | ]  \  }}}}|cxk  r	||z   k  sn n|  y wr{  r   ).0r
  r  r  r  r  s        r   	<genexpr>z#dword_references.<locals>.<genexpr>L  sI       I%DT3nWeio  XH  sA  DH  sH  XHD  Is   &
&?r   r'  )r~  sectionr
   )structpackfindr  nextr}  r   r   )	r  r~  limitneedlerefsr   ref_var  r  s	           @r   dword_referencesr  B  s    [[r"FDE
&%(A: K f%  I  I  KN  OGKKF3<0WEF4yE!K 
 r   c                :   | |   }|dv r|dz   t        |       k  r| |dz      nd}|dz   t        |       kD  r
d|dd| dS |d	k(  r3|dk(  r.| |d
z      }t        j                  d| |dz         d   }d|dd| S |d	k(  r@|dk(  r;| |d
z      }| |dz      }t        | |dz   |dz          }	| |dz      }d|dd| d|	 d| S |d	k(  r)|d
k(  r$| |d
z      }| |dz      }| |dz      }d|dd| d| S |dk(  r(|dk(  r#t        j                  d| |dz         d   }d|dS |dk(  r)|dk(  r$| |d
z      }| |dz      }| |dz      }
d|dd| d|
 S |dk(  r)|d
k(  r$| |d
z      }| |dz      }| |dz      }
d|dd| d|
 S |dk(  r(|dk(  r#t        j                  d| |dz         d   }d|dS |dv rH|dk\  rC|dz   t        |       k  r2t        j                  d| |dz         d   }t	        |      
d|dd|dS d|dd| |dz   ||z    j                  d       j                         S )NrF   rG   r
   r   r   r   r   z/mz
 truncatedrF   r   r  r   z0x38/m0 list-step ptr=0xr'  z repeat=r   r   z0x38/m1 range-step-to-rgb 0x+z rgb=z0x38/m2 range-step-to-backup 0xrG   z0x39/m0 list-set-current ptr=0xz!0x39/m1 range-set-current-gray 0xz value=z 0x39/m2 range-set-backup-gray 0xz0x39/m3 list-set-backup ptr=0xr   r   r   r!   r"   r#   z -> 0x )r   r  unpack_fromr  r  hexr   )r  r  lengthopcodemoderepeatr  r   rv  rgbr  s              r   command_summaryr  T  s   [F"(1*s3x"7s6A:QA:C s|2dV:66T>dai!_F$$T3
;A>C-c#YhvhGGT>dai
OE
OEFQJ!45C!_F1%AeWE#hW]V^__T>dai
OE
OE!_F4U3KqxPVxXXT>dai$$T3
;A>C4SI>>T>dai
OE
OE
OE6uSk5'QVPWXXT>dai
OE
OE
OE5eC[%PUwWWT>dai$$T3
;A>C3C9==55&A+&ST*X[\_X`J`  sFQJ7:(s|6#c33s|1S!fvo>BB3GHIPPRRr   c                :   g }|}||k  rt        |      |k  r| |   }t        j                  |      }|||z   |kD  r	 |S t        |      }|j	                  |||d|dnd |d|d|t        | ||      d       |dk(  r	 |S ||z  }||k  rt        |      |k  r|S )Nr   r'  r   )r  r~  vaHexr  	opcodeHexr  rX  r   )r   VM_OPCODE_LENGTHSr   r  r   r  )	r  start_offset
max_offsetmax_commandscommandsr  r  r  r~  s	            r   parse_vm_streamr    s    HF
:
#h-,">V"&&v.>Vf_z9  O &! *,.2bXd !&. *3?
	
 T>O 	&' :
#h-,">( Or   c                B   t        d      xs d}t        t        |       |dz         }t        ||dz
        }t        |dz   |      }g }t	        ||dz         D ]  }t        | ||      }t        |      D 	
cg c]  \  }	}
|
d   |k(  s|	 }}	}
|s:|d   }|}t        dt        |      |z
  dz
        }t        |      }|t        | |d	      ng }g }|D 
ch c]  }
|
d   	 }}
|D ]|  }
|
d
   dvs|
d   dz   t        |       kD  rt        j                  d| |
d   dz         d   }t        |      }|M|j                  |
d   d|d||v xs ||cxk  xr |k  nc d       ~ t        |      |dz  z   |z   t        |      dz  z   t        d |D              dz  z   }|dz  dk(  r|dz  }|j                  |||d|dnd |t        |      ||t        |      ||d d ||d d D 
cg c]  }
|
d   	 c}
d        |sdddS |j                  d d       |d   }|d   dk\  r|d   dk\  r|d    dk\  rd!}n|d   dk\  r|d    dk\  rd"}nd#}||d$   |d%   |d   |d   |d    |d&   |d'   |d(   |d)   |d*   t        dt        |      dz
        d+d,S c c}
}	w c c}
w c c}
w )-Nr   r   r   rm      r
   r  r   )r  r  r  r  r   r  r   r'  )fromVatargetVainsideParsedWindowr   c              3  ,   K   | ]  }|d    s	d  yw)r  r
   Nr   r  r   s     r   r  z,palette_command_alignment.<locals>.<genexpr>  s)       ICshk  mA  iB  ICs   
r   r   rX  )
rootOffsetrootVar  commandIndexcommandCountcommandsBeforecommandsAfterdirectReferenceCountdirectReferencesbranchTargetsscorepreviewzunbound-static-candidatezNNo plausible local VM command stream alignment found around this byte pattern.rE  c                    | d   | d   | d   fS )Nr  r  r  r   r   s    r   r   z+palette_command_alignment.<locals>.<lambda>  s    S\3~3FL\H]$^ r   T)r   reverser  r  r  vm-aligned-local-highzvm-aligned-local-mediumzvm-aligned-local-weakr  r  r  r  r  r  r  zLocal alignment proof only. This shows the palette bytes fit the generic VM command stream shape; it does not yet bind the stream to a specific map root.)rF  
bestRootVar  r  r  r  r  r  r  r  r  alternateRootCountrG  )r  r   r   r   r   r  r   r  r  r  r  r   rp  sort)r  command_offset
data_startdata_endr  upper
candidatesr   r  r   commandboundary_indexesboundary_indexbeforeafterr>  r  branch_targetscommand_offsetsr  target_offsetr  bestrF  s                           r   palette_command_alignmentr    s   j).QJ3s8Z(23H
NR/0E$h/EJunq01 ,
"3u58A(8KsneWwW_O`drOrEss)!,As8}~59:u%:A:MWA6SU<DE78,EE 	Gx (LLPWX`PadePehklohpPp$$T30AA0EFqIC(-M$!!%g."$SI*7?*J*leWdNlglNl	 H
*U2SY]BS  ICVd  IC  FC  FG  FG  G19>QJE#!3:3Fr'#/D . #H"(!&(+D	$(!/!4>FsmL7GI.L	
;,
Z 0d
 	
 OO^hlOma=DNq T*:%;q%@T/EZ^_E_(	n		"tO'<'A*(;'^,^,/0o. $%; < !34o.g	?!!S_q%89 l q t F> Ms   6JJJ%J c                j	   t         j                         sdg dS t         j                         }| sdg dS t        |       t	        |       g }t        d      xs d}|dz   }t        |t        t        |      dz
  |            D ]U  }||   }|dvr||d	z      }t        |      }	|	$d }
|d
k(  r|dk(  rt        j                  d||dz         d   }t        ||      }|rvt        |      dk  rgt        |D ch c]  }|d   	 c}      }t        fd|D              r5d|	dd|dd|dt        |      ||dz      t        |      t	        |      dt        |      ddt	        |      dddd	}
n|d
k(  r|dv r||dz      }||dz      }||z   d	z
  }|r|dk  r|k  r|k\  rd|	dd||d	k(  rdnd||d|dd|dd|d	k(  r||dz      n||dz      |d	k(  rt        ||dz   |dz          nd ||dz   |dz    j                  d      dd 	}
n?|d!k(  rs|dv ro||dz      }||dz      }||z   d	z
  }|r|dk  r|k  r|k\  r	d|	dd"||d	k(  rd#nd$||d|dd|dd||dz      ||dz   |dz    j                  d      dd%}
n|d!k(  r|d&v rt        j                  d||dz         d   }t        ||      }|rt        |      dk  rt        |D ch c]  }|d   	 c}      }t        fd'|D              rTd|	dd"||dk(  rd(nd)d|dt        |      t        |      t	        |      dt        |      ddt	        |      dddd*}
|
st!        |
      |
d+<   t#        ||	      }t        |      |
d,<   ||
d-<   t%        ||      |
d.<   |r1t'        |
j)                  d.      xs i j)                  d/      |      |
d0<   |j+                  |
       X t-        d1 |D              }t-        d2 |D              }t-        d3 |D              }t/        d4 |D              }d5dddddt        |      t1        t        |j3                                     t1        t        |j3                                     t1        t        |j3                                     ||d d6 d7d8	S c c}w c c}w )9Nzexe-missing)rF  r  z
no-indexesr   r   r   r   r  r
   rF   r  r   rq   c              3  >   K   | ]  }|cxk  xr k  nc   y wr{  r   r  r   maximumminimums     r   r  z'palette_command_scan.<locals>.<genexpr>       Huw%2722H   r   r'  0x38zlist-step-to-rgbr   r   r   z&list-overlaps-animated-palette-indices)	r~  r  r  kindlistPointer
entryCountrepeatCountr   rF  )r
   r   r   r  zrange-step-to-rgbzrange-step-to-backupr   r  z'range-overlaps-animated-palette-indices)	r~  r  r  r  r   r  	targetRgb
payloadHexrF  rG   0x39zrange-set-current-grayzrange-set-backup-gray)r~  r  r  r  r   r  r  rF  )r   r   c              3  >   K   | ]  }|cxk  xr k  nc   y wr{  r   r  s     r   r  z'palette_command_scan.<locals>.<genexpr>9  r  r  zlist-set-currentzlist-set-backup)r~  r  r  r  r  r  r   rF  effectScoper  r  scriptAlignmentr  resourceBindingc              3  f   K   | ])  }|j                  d       xs i j                  dd       + yw)r  rF  noneNr   r  r  s     r   r  z'palette_command_scan.<locals>.<genexpr>U  s.     t`g,= > D"II(TZ[t   /1c              3  f   K   | ])  }|j                  d       xs i j                  dd       + yw)r  rF  znot-scannedNr  r  s     r   r  z'palette_command_scan.<locals>.<genexpr>V  s.     yelgkk*;<BGGR_`yr  c              3  f   K   | ])  }|j                  d       xs i j                  dd       + yw)r  r  unknownNr  r  s     r   r  z'palette_command_scan.<locals>.<genexpr>W  s,     nZaGKK6<"AA'9Unr  c              3     K   | ]Q  }|j                  d       xs i j                  d      dk(  r(|j                  d      xs i j                  d      rd S yw)r  r  r  r  rN  r
   Nr  r  s     r   r  z'palette_command_scan.<locals>.<genexpr>X  sX      /KK&,"11':>__[[*+1r667TU 	
/s   AAzcandidate-static-scanr]   zThis is a broad static scan over .data for palette VM command forms. It proves matching command shapes exist, not that a specific map root executes them.)	rF  
indexRanger  alignmentCountsresourceBindingCountseffectScopeCounts nearAnimatedBroadTransitionCountr  rG  )EXEr  r   r   r   r  r   r   r  r  r  r  r   anyr   r  r  r  r  r]  r   r   r   rp  dictrn  )indexes_of_interestbinding_contextr  r  data_offsetr  r  r  r  r~  r   r  r  entryr   r   rv  r   r  alignment_countsbinding_countsscope_counts$near_animated_broad_transition_countr  r  s                          @@r   palette_command_scanr    s   ::<'R88
..
C&B77%&G%&GHz*/aKX%HSSAx%@A ^!V%6A:&!:T>dai$$T3
;A>C*34G3w<3. !@u%(!@AHHH "2c(m"( $ 2)+C9~&)'l'*6A:%(\#&w<*,S\#,>(?(*3w<*<&=	" #KC  t^
OE
OE%-!#Cu')9cWnr#h-$ 3719/BX',S5QT+FVdfgjknfobpq6:ai3vz?SRS_GKqyc&1*vz&B!CVZ"%fqj6A:">"B"B3"GG
 t^
OE
OE%-!#Cu')9cWnr#h-$ 8<	4G^',S5QT+FVdfgjknfobpq !_"%fqj6A:">"B"B3"GG	 t^$$T3
;A>C*34G3w<3. !@u%(!@AHHH "2c(m"( $6:ai 2EV)+C9~&)'l%(\#&w<*,S\#,>(?(*3w<*<&=	" #KC !5c!:C#C,D*-d)C&'&*C"#%>sF%KC!")FWW./52::<H#*%& OOC }^!~ tksttypxyyNnemnnL+. // ,( *WSM*73-(	
 H'7'='='? @A!%f^-A-A-C&D!E!&););)=">?,PSbM l w "Aj "As   9R+
R0
c                   | j                  d      sy | d   d   d   }|r|d   y |d   }||z  }||z  }|| d   z   |kD  ry t        | d         D ].  \  }}t        |d         D ]  \  }}	|||z  z   |z   }
|	|
k7  s  y  0 d||| d   | d   |dS )Nr   r   r   r   zrectangular-source-blockr   )rF  sourceXsourceYr   r   baseTile)r   r   )r   r   	first_row	base_tilesource_xsource_yy_offsetplacement_rowx_offsetr`  expecteds              r   component_source_blockr  p  s    == &!!$W-I	!,!I7"HG#H)G$$w.#,Yv->#? -'g(>? 	NHd 8g#55@Hx	 -7#H% r   c                6   | j                  d      }|sg S |d   }|d   }|d   }|dk  s|dk  s||z   |d   kD  rg S |d   |z  dk(  rt        d|d   |z
  dz   |      }nt        d|d   |z
  dz         }|D cg c]  }||||||z  |z   ||d	   k(  d
 c}S c c}w )NsourceBlockr   r   r  r   r   r   r
   r  )r  r  r   r   r  isPlacedBaseBlock)r   r   )	r   r   source_sizeblockr   r   r  source_x_valuesr  s	            r   source_block_candidatesr&    s    MM-(E	'NE8_FYHzVq[Hv$5F8K$K	9%*;y#9E#AA#EuM;y#9E#AA#EF (
    7*X5!)U9-=!=	

 
 
s   7Bc           
        t        t              }| D ]  }|d   }||z     |xx   dz  cc<    g }t        |j                               D ]  \  }}t        |      t	              dk\  xr t        fdD              }D cg c]  }|d   z
  z   }	}|rd}
d}nd}
d	}|j                  |D cg c]  }||   	 c}|	|
|d
        |S c c}w c c}w )Nr   r
   r   c              3  :   K   | ]  }|d    z
  z  d k(    yw)r   Nr   )r  r`  r   r   s     r   r  z)summarize_frame_groups.<locals>.<genexpr>  s%     0dVZ$q/W1LPQ1Q0ds   r   !same-column-static-source-clusterzlsame source-column layer0 tiles inside 0x40 cells; this is static tile coverage, not an animation frame listzsingle-layer0-tilezY0x40 cell source tile; 0x40 marks redraw coverage; final motion source is not proven here)columnr   rd  rowOffsetsFromFirstTile
confidencerG  )r   r   r   rn  r   allr   )r   r   	by_columnr   r`  r  r*  rd  has_alternatesrow_offsetsr,  rG  r   s    `          @r   summarize_frame_groupsr1    s	   $/$8I -H~$.!$'1,'- F !23 
vUqdS0d^c0d-d@EFuQxG3FF<J BD-JnD 49:D6$<:+6(		

( M# G ;s   C6Cc                     t               } g }t        | j                               D ]  \  }}t        |      }|s|j	                  d      xs d}|j	                  d      xs |j	                  d      gd   }t        |      }t        |      }|D ]!  }	t        |	|      |	d<   t        |	||      |	d<   # |j                  i d|d	|d	   d
|d
   d|j	                  dd      d|d|d|j	                  d      xs g d|dt        |      dt        t        |            dt        |      d|d|dt        |D 
ch c]  }
|
d   	 c}
      dt        |D 
ch c]  }
|
d   	 c}
      dt        ||      dt        |t        |D 
ch c]  }
|
d   	 c}
      |      dddddddi        t        |D ch c]  }|d   d    D ]  }|  c}}      }t        |      }t        ||      }d!d"d#d$d%d&d'd(d)d*d+d,d-d.d*d/d0d1d2d*d3d4d5d6d*d7d8d9d:d*d;d<d=d>d*d?d@dAdBd*dCdDdEdFd*dGdDdHdId*dJdKdLdMd*dNdOdPdQd*dRdSdTdUd*dVdWdXdYd*dZd[d\d]d*d^d_d`dad*dbdcddded*dfdgdhdid*djdkdldmd*gg dng dodpt        |       t        |      t!        dq |D              t!        dr |D              t!        ds |D              t!        dt |D              t        |      t#        |      |j	                  dud      |j	                  dvi       |j	                  dvi       j	                  dwd      |j	                  dxi       |j	                  dxi       j	                  dyd      |j	                  dzi       |j	                  d{d      d||g d}|d~S c c}
w c c}
w c c}
w c c}}w )NtilesetColumnsr6   layerTilesetstilesetr   r!  sourceBlockCandidatesr  r   r   tileSizer   rA  sourceTilesetSizeanimatedCellCountcomponentCountr   placementComponentsanimatedCellsuniqueLayer0TileCountr   uniqueLayer0TilesframeGroupspaletteUsageevidencezlayer1 bit 0x40z#layer0 tile id at each flagged cellzBsame tile column in a 40-column map tileset, separated by +40 rowsz@non-zero palette indices used by the flagged layer0 source tilesznot detected here)
flagSource
tileSourcesourceGroupingpaletteSourcetimingr   r
   z,hwanse-map-layer1-0x40-animation-tile-review0x40z#animation-redraw-consumer-confirmedaA  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.
0x00425494zlayer1-grid-readz!reads WORD [0x0058d7d0 + index*2]z-viewport scan over layer1 collision/flag grid)r~  r  rA  meaning
0x0042549czlayer1-0x40-consumerztest cl, 0x40z\flags 0x40 cells into the redraw/dirty byte grid; does not choose alternate frame tiles here
0x0040234czvm-dispatchz&call DWORD PTR [opcode*4 + 0x00440538]z7command stream dispatch table used by the game/event VM
0x00407686ztile-write-handlerzJhandler table entry at 0x00440698; writes WORD to 0x00595af0 or 0x0058d7d0zTcommand layout uses layer selector, tile id, x, y; then invalidates the touched tile
0x00408d10z!active-object-relative-tile-writezQiterates active object list and writes tile id at object-relative map coordinatesz6variant for object/NPC/event-relative map-grid changes
0x00409f23zactive-object-list-tile-writezXiterates linked active object list and writes tile id at object-relative map coordinatesz0another object-list variant for map-grid changes
0x004255ebztile-invalidatez(called after tile-grid mutation with x/yz%marks one touched map tile for redraw
0x004060dbzpalette-vm-handlerz%dispatch table 0x00440538 opcode 0x38za8-byte palette step command: list-step to RGB, range-step to RGB, or range-step to backup palette
0x00406206z%dispatch table 0x00440538 opcode 0x39z\8-byte palette set command: set current palette list/range or seed backup palette list/range
0x00401036zpalette-list-setterzYreads entries until 0xff terminator and writes RGB nibbles into 0x004676e8 palette bufferzFsets palette entries immediately and marks palette dirty at 0x00559d98
0x004010d2zpalette-list-stepperzEuses 0x0040118e to increment/decrement RGB bytes toward target valuesz&gradual palette transition/fade helper
0x00401518zpalette-range-stepperzKcalled by opcode 0x38 mode 1; walks a palette range toward stream RGB bytesz-range fade helper for current palette entries
0x0040146azpalette-range-step-to-backupzWcalled by opcode 0x38 mode 2; walks a palette range toward backup bytes at 0x00559da1..z#range restore/fade-to-backup helper
0x004015b9zpalette-current-range-setterzOcalled by opcode 0x39 mode 1; writes one gray/RGB byte to current palette rangez(direct current palette range fill helper
0x00401632zpalette-backup-range-setterzNcalled by opcode 0x39 mode 2; writes one gray/RGB byte to backup palette rangez backup palette range fill helper
0x00401699zpalette-backup-list-setterz@called by opcode 0x39 mode 3; reads 0xff-terminated palette listzbackup palette list seed helper
0x00401000zdeferred-palette-applyz^if 0x00559d98 is set, calls 0x00416677 with start 0 and count 0x100 then clears the dirty flagzGapplies changed palette buffer to DirectDraw before presentation/update
0x00416677zdirectdraw-palette-setentriesz?calls IDirectDrawPalette::SetEntries through vtable offset 0x18zIpushes a palette range from 0x004676e8 into the active DirectDraw palette)zBlayer1 bit 0x40 is read by EXE during viewport redraw preparation.zjThe 0x40 consumer marks the same map cells dirty every redraw pass; it does not choose alternate tile ids.zhThe map draw path uses the current layer0 tile id directly, while 0x40 only affects redraw invalidation.zQThe EXE has palette VM handlers and a deferred DirectDrawPalette SetEntries path.zGeneric VM palette opcodes are now length/mode grounded: 0x38 and 0x39 are 8-byte commands, while 0x3a and 0x3b are 4-byte commands.zOpcode 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.zOpcode 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.zrThe non-transparent palette indices used by the current 0x40 layer0 source tiles have been mapped from CNS pixels.zA stricter local VM alignment scan promotes a subset of raw 0x38/0x39 byte-pattern hits to VM-shaped palette script candidates.ztVM-aligned palette script roots are now cross-checked against scene/resource groups and nearby map resource records.zThe animated fire/waterfall/water regions sit on ordinary layer0 tile ids; 0x40 dirty redraw is grounded, but the visible motion stream is still unbound.)zhThe exact executed palette command for each map animation has not been bound to a specific map root yet.zLThe palette-cycle timing/order is not fully tied to a specific map root yet.zResource binding is a correlation layer only. A contained or nearby resource group does not by itself prove runtime execution for that map.zBroad static palette-command scans contain false positives unless tied to an executed VM command stream; local alignment reduces but does not eliminate this risk.zjGeneric VM tile-write handlers still exist, but current 0x40 map animation evidence does not require them.)rF  rX  	addresses	confirmed
unresolvedc              3  &   K   | ]	  }|d      yw)r9  Nr   r  s     r   r  zbuild_review.<locals>.<genexpr>  s     $N#S)<%=$N   c              3  &   K   | ]	  }|d      yw)r:  Nr   r  s     r   r  zbuild_review.<locals>.<genexpr>  s     !HC#&6"7!Hr_  c              3  D   K   | ]  }|d    D ]  }|d   dk(  rd   yw)r?  r,  r)  r
   Nr   )r  r   r   s      r   r  zbuild_review.<locals>.<genexpr>  s@      4 /4 &*MM 44s    c              3  V   K   | ]!  }|d    D ]  }|j                  d      rd  # yw)r;  r!  r
   Nr  )r  r   r   s      r   r  zbuild_review.<locals>.<genexpr>  s?      8!$%:!;8 ==/ 88   ')r  r  r  r  rJ  r  r  )mapCountanimatedMapCountr9  r:   sameColumnStaticSourceGroupCount$rectangularSourceBlockComponentCountanimatedPaletteIndexCountanimatedPaletteIndexRangespaletteCommandCandidateCountpaletteCommandAlignmentCounts paletteCommandHighAlignmentCount#paletteCommandResourceBindingCounts"paletteCommandAnimatedBindingCountpaletteCommandEffectScopeCounts.paletteCommandNearAnimatedBroadTransitionCount)zThis review is CNS-grounded: layer1 0x40 identifies animated cells and layer0 identifies the visible source tile used by those cells.zEXE analysis found that layer1 0x40 feeds redraw/dirty marking and that palette changes are deferred into DirectDrawPalette::SetEntries.zPalette index usage is CNS-grounded. Palette command candidates are broad EXE static-scan evidence and must not be promoted to per-map execution proof yet.zPalette command local alignment now checks whether the bytes sit on generic VM command boundaries near 0x00440538 command lengths. High alignment is stronger than a raw byte-pattern hit, but still not a per-map execution binding.zResource binding now shows whether the selected VM root is inside a selector-root resource group or only near scene records. This is a prioritization aid, not final execution proof.zuSame-column tile groups are static source coverage inside flagged cells, not complete animation frames by themselves.zThe old alternate-source-rect model is now demoted for these map animations; keep tile-write VM evidence separate for doors/objects/event changes.z\This does not yet prove the exact palette cycle range, timing, or per-map activation script.)versionr  animatedFlagHexexeEvidencerX  paletteCommandScannotesr  )r   r   rn  r   r   r   r   r  r&  r   r   r   r1  ry  rC  r  rp  r   )r  r   r
  r   r   r   source_tilesetr#  r   r   r   r   r   all_palette_indicesr  palette_scans                   r   build_reviewry    sU   ;DD . &
hx(,,/06B",,7THLL<S;TVWX">2)%0
# 	jI'=i'QIm$1HT[]h1iI-.	j 	t'* (8, HLLR8	
   $[  o!>!D" !' $SZ !#&:5&A"B 259 &z   (-Od8n-O)P $V,NT(^,N%O  5eWE!" nfafEgY]d8nEg>hjq r#$ "3"G&j%g1%	
&
N !4!dCSEXYbEc!dE%!d%!de3D9O'(;_ML>!;f '. CN	 '2 /}	 ') HX	 '0 lu	 '? sW	 '; zQ	 '- JF	 '0 G  C	 '0 G}	 '1 {g	 '2 gG	 '3 mN	 ': yD	 ': qI	 '9 pA	 '8 b@	 '4 !Ah	 '; aj	Om\GJ
X D	 #D	!$$N$N!N!!H4!HH03 44 1 58 88 5 *--@)A*89L*M,8,<,<^Q,O-9-=-=>OQS-T0<0@0@ARTV0W0[0[\suv0w3?3C3CD[]_3`2>2B2BCZ\^2_2c2c  eK  MN  3O/;/?/?@SUW/X>J>N>NOqst>u3
6 +	
 kv v! .P,NEg "es   >M;N N?N

c                >    t        j                  t        |             S r{  )htmlescapestrr  s    r   escr~    s    ;;s5z""r   c                   g }| d   D ]  }|d   }|d   }g }t        ||d   d      D ]5  \  }}|j                  dt        | d          d	| d
    d| d| d| d       7 |j                  d|dk(  rdnd dt        |       d|d    ddj                  |       dt        |d          d        dj                  |      S )Nr?  r,  r   rd  T)strictzb<span class="tile-preview-wrap"><canvas class="tile-preview" width="48" height="48" data-tileset="rA  z" data-columns="r3  z" data-tile=""></canvas><code>#z</code><span class="count">xz</span></span>z/<div class="frame-group"><div><span class="tag r)  goodr*  ">z </span> <span class="muted">col r*  z+</span></div><div class="tile-preview-row">z	</div><p>rG  z
</p></div>)zipr   r~  join)r   partsr   r,  r   canvas_listr`  rv  s           r   render_group_previewsr    s3   E]# 
<(
gueHodC 		KD%""%c/&:";!< =""%&6"7!8 9#f %=eW E		 	&0:>a0afgi%jjmnqr|n}m~ )).x(9 ://1ww{/C.D EeFm$% &		

, 775>r   c                8    dj                  d | d   D              S )Nz<br>c              3  v   K   | ]1  }d |d    d|d    d|d    d|d    d|d    d	|d
    d|d    d 3 yw)z<code>(r   ,r   )-(r   r   z	)</code> r   r   r   u    · r    cellsNr   )r  r   s     r   r  z$render_components.<locals>.<genexpr>  st        )D/"!IdO#4C	$7H)TX/IZZcW
a	( 34D;9O8PPV	Xs   79r   r  r   s    r   render_componentsr    s'    ;;  \*  r   c                   g }t        | d   d      D ]  \  }}g }|d   D ]h  }|d   }t        |d         D ]P  \  }}|d   |z   }	||j                  d       "|| d	   z  d
z  dz  }
|j                  d|
 d|	 d| d| d| d       R j |j                  d| d|d    d|d    d|d    d|d    d|d    ddj                  |       d        ddj                  |       dS ) Nr;  r
   r   r   r   r   r   z-<span class="placement-cell missing">.</span>r3  r-   ih  z/<span class="placement-cell" style="--tile-hue:z" title="x=z, y=z, layer0 tile #r  </span>0<section class="placement-component"><h3>region z	: <code>(r  r   r  r   r   zN)</code></h3><div class="placement-grid" style="grid-template-columns: repeat(r   z
, 34px);">r*  z</div></section>zx<details class="placement-details"><summary>0x40 placement grid: flagged map cells and current layer0 tile ids</summary>
</details>)r   r   r  )r   sectionsr   r   r   r  r   r  r`  r   hues              r   render_placement_gridr    s   H%c*?&@J 
y&v. 	Mc"A )-*@ A 	dOf,<LL!PQs#344:cAH N!!"4s/$s4&Q		 		)D/):!IdO;LCPYZ^P_O``abklpbqar sSS\]dSeRffqrtryryz  sA  rB B	

*	`778
	r   c                f   g }t        | d   d      D ]  \  }}|j                  d      }|s|j                  d| d       /|j                  d| d|d    d	|d
    d|d    d|d    dt        | d          d|d    d|d
    d|d    d|d    d|d    d        ddj	                  |       dS )Nr;  r
   r  r!  r  u   </h3><p class="muted">이 영역은 소스 타일셋의 단일 직사각형 블록으로 떨어지지 않는다. 폭포처럼 넓은 영역은 여러 정적 layer0 tile을 0x40 redraw 대상으로 묶는다.</p></section>z!: static source footprint <code>(r  r  r  z) r   r   r   ze</code></h3><span class="source-block-wrap"><canvas class="source-block-canvas placed" data-tileset="rA  z" data-block-x="z" data-block-y="z" data-block-w="z" data-block-h="r  r  u   </code><span class="count">current layer0 block</span></span><p class="muted">현재 맵에 놓인 정적 layer0 블록이다. 대체 프레임 rect 후보가 아니라 animation redraw 대상 footprint로 본다.</p></section>zm<details class="placement-details"><summary>source footprint: current layer0 block or grouped tiles</summary>r*  r  )r   r   r   r~  r  )r   r  r   r   r$  s        r   render_source_block_candidatesr    sL   H%c*?&@J 
ym,OO#W %  A%	BRASSTUZ[dUeTffhinoviwhxxyz  AI  {J  zK K "#o"678 9#I./ 0#I./ 0#Gn- .#Ho. /J'( )	

4	U778
	r   c                2    dj                  d | D              S )N, c              3  V   K   | ]!  }|d    |d   k(  r|d   n|d    d|d     # yw)r   r   r   -r   Nr   r  s     r   r  z render_ranges.<locals>.<genexpr>  sG       w<3u:5Jc*o=NaPST\P];__rc  r  )r   s    r   render_rangesr    s     99   r   c           	         | d   }dj                  d |d   d d D              }d|d    dt        t        |d	         xs d
       dt        |xs d
       dS )Nr@  r  c              3  8   K   | ]  }|d     d|d    d  yw)ri  (r   )Nr   r  r0  s     r   r  z'render_palette_usage.<locals>.<genexpr>  s(     atJ'($x.)9;as   rl  r   zj<details class="placement-details"><summary>palette indices used by 0x40 source tiles</summary><p><strong>rh  u+   </strong> non-transparent indices · <code>r   r  z.</code></p><p class="muted">top pixel counts: z</p></details>)r  r~  r  )r   usagetops      r   render_palette_usager    s    E
))alH[\_]_H`a
aC	L)* +]5?3:s;< =003CJ3/@ A		r   c                |    | sy| d | }t        |       |kD  rdt        |       |z
   nd}dj                  |      |z   S )Nr   +r*  r  )r   r  )r   r  shownsuffixs       r   compact_listr  $  sJ    6ENE+.v;+>r#f+%&'BF99Uf$$r   c                   | j                  dd      }|dk(  rdnd}d| dt        |       dd	t        | j                  d
d             dg}| j                  d      xs g }|r|d   }t        |j                  d      xs |j                  d      xs g       }t        |j                  d      xs g       }|j                  dt        |j                  dd             dt        |j                  dd             dt        |       dt        |       d	       | j                  d      xs g }|rg }	|d d D ]p  }
|
j                  d      s|
j                  d      rdnd}|	j                  |
j                  d       | d|
j                  d       d|
j                  d              r |j                  d t        d!j	                  |	             d       | j                  d"      xs g }|rg }|d d D ]^  }|j                  d      s|j                  d      rdnd}|j                  |j                  d       | d|j                  d              ` |j                  d#t        d!j	                  |             d       |j                  d$t        | j                  d%d             d       dj	                  |      S )&NrF  r  rJ  r  r*  z<span class="tag r  r  z
<br><code>r  z</code>rK  r   r4  r5  r  z!<br><span class="muted">contains r  r  r  u    · animated: u
    · maps: rM  r   r;  *r  @r&  r  r:  z$<br><span class="muted">near scene: z; rL  z$<br><span class="muted">near group: z<br><span class="muted">rG  )r   r~  r  r   r  )bindingrF  taglinesrR  r   animatedr  rY  record_partsr=  markerrU  group_partss                 r   render_resource_bindingr  ,  s   [[3'FDD&"C
SES[M9
S[#678@E /06BJ1		. 9 `UYYGY=Z `^`aEIIf-341#eiic6J2K1LA599Z,-.nS]O:VYZ^V_U``gi	
 kk"78>BO%bq) 	{F"JJ}5DV9WS]_F6::e#4"5fXQvzz-?X>YY[\b\f\fgv\w[x yz	{ 	=c$))LBY>Z=[[bcd[[17RN#BQ' 	[E!IIn5CU9VS\^F%))D/!26("UYY=W<XYZ	[ 	=c$))KBX>Y=ZZabc	LL-c'++fb2I.J-K7ST775>r   c                ^	   | j                  d      xs i }g }|j                  dg       d d D ]  }|j                  d      xs i }|j                  d      xs i }|j                  dd      }|dk(  rd	nd
}dj                  |j                  dg       d d       }dj                  d |j                  dg       d d D              }	|j                  d      xs i }
|j                  d      xs i }|j                  d
j                  g dt        |j                  dd             dt        |j                  dd             dt        |j                  dd             dt        |j                  dd             dt        |j                  dd             dt        |j                  dd             dt        |j                  d d             d!t        |j                  d"d             d#t        |j                  d$d
             d%t        |j                  d&      xs |j                  d'      xs d       d(| d)t        |       d*t        |j                  d+d             d,t        |j                  d-d             d.t        |j                  d/d             d0t        |	xs d       d#t        |xs |j                  d$d             d%t	        |
       d1              |s|j                  d2       |j                  d3      xs i }|j                  d4      xs i }|j                  d5      xs i }|j                  d6      xs i }dj                  d7 |j                         D              xs d}dj                  d8 |j                         D              xs d}dj                  d9 |j                         D              xs d}d:t        |j                  dd             dt        |j                  dd             d;t        |j                  d/d<             d=t        |       d>t        |       d?t        |       d@t        |j                  dAd<             dBt        |j                  d$d
             dCd
j                  |       dDS )ENrt  r  r6   r   r  rF  r  r  r  r*  z / r  r   r  c              3  f   K   | ])  }|j                  d        d|j                  d        + yw)r~  :r  Nr  )r  refs     r   r  z.render_palette_command_scan.<locals>.<genexpr>W  s-     vSCGGDM?!CGGI,>+?@vr  r  r   r  r  <tr><td><code>r~  </code></td><td>r  z / mode r  	</td><td>r  z</td><td><code>r   r   z"</code></td><td><span class="tag">r  z(</span><br><span class="muted">entries: r  z</span><br><span class="muted">rG  </span></td><td>r  r  z</td><td><span class="tag r  z</span><br><code>r  z </code> <span class="muted">idx r  z / cmds r  z%</span><br><span class="muted">refs: 
</td></tr>zV<tr><td colspan="8" class="muted">No overlapping palette command candidates.</td></tr>r  r  r  r  c              3  0   K   | ]  \  }}| d |   ywz: Nr   r  r   r  s      r   r  z.render_palette_command_scan.<locals>.<genexpr>r  s     !_
USEE7"3!_   c              3  0   K   | ]  \  }}| d |   ywr  r   r  s      r   r  z.render_palette_command_scan.<locals>.<genexpr>s  s     [jc53%r% 1[r  c              3  0   K   | ]  \  }}| d |   ywr  r   r  s      r   r  z.render_palette_command_scan.<locals>.<genexpr>t  s     WJCRw/Wr  z{
  <section class="panel">
    <h2>Palette command static scan</h2>
    <p>animated source tile palette index range: <code>u   </code> · candidates r   z&</p>
    <p>local VM alignment: <code>z+</code></p>
    <p>resource binding: <code>z'</code></p>
    <p>effect scope: <code>u2   </code> · near animated broad transitions: <code>r  z!</code></p>
    <p class="muted">a{  </p>
    <details class="placement-details">
      <summary>candidate palette commands touching animated tile indices</summary>
      <div class="table-wrap">
        <table>
          <thead><tr><th>VA</th><th>opcode/mode</th><th>kind</th><th>range</th><th>effect scope</th><th>payload/list</th><th>local VM alignment</th><th>resource binding</th></tr></thead>
          <tbody>C</tbody>
        </table>
      </div>
    </details>
  </section>
)r   r  r   r~  r  rn  )reviewscanr   r  	range_row	alignmentalignment_statusalignment_tagr  r  r  scopeindex_ranger  r  r  alignment_summarybinding_summaryscope_summarys                      r   render_palette_command_scanr  N  s   ::*+1rDD88J+CR0 
KK(.B	KK 128b	$==37"26M"MSU**Y]]9b9"1=>yyvIMMZlnpLqrtstLuvv++/06BM*0b   W[[s3456w{{8S1233;<?FTW@X<Y;Z[ w{{63/012 Y]]:s;<=	 >?	 @C9==QY[^C_?`>a	b'	
 (+599Wc+B'C&D
E. /2%))<OQT2U.V-WX% &)62)>%?$@A w{{=1UW[[5NURUVWX% &3O 47 8;;K7L6MN |S9:;<) *-Y]]>3-O)P(Q RZ [^^g^k^klz|  _A  [B  ZCC/ 034;3/?.@A) *-W-R	fc8R)S(TU +7345	

6 lm((<(.BKxx 128bXX56<"N88/06BL		!_FVF\F\F^!__fcfii[NDXDXDZ[[b_bOIIW,BTBTBVWW^[^M8 9<KOOJX[<\8]7^^_`cdodsdst|  B  eC  aD  `E  E[  \_  `d  `h  `h  iw  yz  `{  \|  [} }""%&7"8!9 :  #O 45 6.//abefjfnfn  pR  TU  gV  cW  bX X$((62./0 1 ''$- ! r   c                   | d   }g }|d   D ]P  }|j                  dt        |d          dt        |d          dt        |d          dt        |d	          d
	       R dj                  d |d   D              }dj                  d |d   D              }dt        |d          d| d| ddj                  |       d	S )Nrs  r[  r  r~  r  r  r  rA  rI  r  r*  c              3  :   K   | ]  }d t        |       d  ywz<li>z</li>Nr~  r  s     r   r  z&render_exe_evidence.<locals>.<genexpr>  s     RD$s4yk/R   r\  c              3  :   K   | ]  }d t        |       d  ywr  r  r  s     r   r  z&render_exe_evidence.<locals>.<genexpr>  s     TT4D	{%0Tr  r]  zE
  <section class="panel">
    <h2>EXE consumer evidence</h2>
    <p>rX  zS</p>
    <div class="two-cols">
      <div>
        <h3>confirmed</h3>
        <ul>zG</ul>
      </div>
      <div>
        <h3>unresolved</h3>
        <ul>a  </ul>
      </div>
    </div>
    <details class="placement-details" open>
      <summary>address evidence</summary>
      <div class="table-wrap">
        <table>
          <thead><tr><th>VA</th><th>kind</th><th>evidence</th><th>meaning</th></tr></thead>
          <tbody>r  )r   r~  r  )r  rA  address_rowsr   r\  r]  s         r   render_exe_evidencer    s   m$HL$ 
SY( )s6{#$ %s:'( )s9~&' (		

 RH[<QRRITXl=STTJ 	HY ! " K  L  '','( )' r   c                p   | d   }g }| d   D ]  }|j                  dt        |d          dt        |d          dt        |d          dt        d	j                  |d
                d|d    d|d    d|d    dt        |       dt	        |       t        |       t        |       t        |       d        d|d    d|d    d|d    d|d    d|d    d|d    d|d    d |d!    d"|d#    d$t        |        d%t        |        d&d'j                  |       d(}t        d)z  j                  |d*+       y ),NrX  r  z,<tr><td><a href="../web/map_review.html?map=r  z3&amp;visualFilter=animation" target="_blank"><code>z</code></a></td><td><code>rA  z</code><br><span class="muted">r  r4  r  r9  z
 cells<br>r:  z components<br>r=  z layer0 tiles</td><td>r  r  u  <!doctype html>
<html lang="ko">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" href="../favicon.ico">
  <title>맵 애니메이션 0x40 redraw 리뷰</title>
  <style>
    body { margin: 0; padding: 18px; font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; background: #f6f7f9; color: #17202a; }
    h1 { margin: 0 0 6px; font-size: 24px; }
    p { margin: 6px 0; }
    a { color: #185abc; text-decoration: none; }
    a:hover { text-decoration: underline; }
    .panel { background: #fff; border: 1px solid #d8dee6; border-radius: 8px; padding: 14px; margin: 14px 0; }
    .metrics { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 10px; }
    .metric { border: 1px solid #d8dee6; border-radius: 6px; background: #f8fafc; padding: 10px; }
    .metric strong { display: block; font-size: 20px; }
    .muted, .count { color: #607080; font-size: 12px; }
    table { width: 100%; border-collapse: collapse; background: #fff; }
    th, td { border: 1px solid #d8dee6; padding: 8px; vertical-align: top; text-align: left; }
    th { background: #eef2f6; }
    code { background: #f1f5f9; border-radius: 4px; padding: 1px 4px; }
    .tag { display: inline-block; border: 1px solid #d8dee6; border-radius: 999px; padding: 1px 7px; font-size: 12px; color: #607080; background: #f8fafc; }
    .tag.good { border-color: #99d3ca; color: #0f766e; background: #ecfdf5; }
    .frame-group { margin-bottom: 10px; }
    .frame-group p { color: #607080; font-size: 12px; margin: 3px 0 0; }
    .tile-preview-row { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 5px; }
    .tile-preview-wrap { display: inline-grid; grid-template-columns: auto; gap: 2px; align-items: center; justify-items: center; }
    .tile-preview { width: 48px; height: 48px; image-rendering: pixelated; background: repeating-conic-gradient(#ddd 0 25%, #f8fafc 0 50%) 0 / 12px 12px; border: 1px solid #cbd5e1; }
    .placement-details { margin-top: 10px; border-top: 1px solid #d8dee6; padding-top: 8px; }
    .placement-details summary { cursor: pointer; font-weight: 700; color: #185abc; }
    .placement-component h3 { margin: 10px 0 6px; font-size: 13px; }
    .placement-grid { display: grid; gap: 1px; width: max-content; max-width: 100%; overflow: auto; padding: 6px; background: #e2e8f0; border: 1px solid #cbd5e1; }
    .placement-cell { display: inline-flex; align-items: center; justify-content: center; width: 34px; height: 20px; font: 10px/1 ui-monospace, SFMono-Regular, Menlo, monospace; color: #17202a; background: hsl(var(--tile-hue) 85% 88%); border: 1px solid hsla(var(--tile-hue), 60%, 48%, 0.45); }
    .placement-cell.missing { background: #f8fafc; color: #94a3b8; border-color: #e2e8f0; }
    .source-block-row { display: flex; flex-wrap: wrap; gap: 8px; }
    .source-block-wrap { display: inline-grid; gap: 3px; justify-items: center; }
    .source-block-canvas { image-rendering: pixelated; background: repeating-conic-gradient(#ddd 0 25%, #f8fafc 0 50%) 0 / 12px 12px; border: 1px solid #cbd5e1; }
    .source-block-canvas.placed { border: 3px solid #0f766e; }
    .table-wrap { overflow-x: auto; }
    h2 { margin: 0 0 8px; font-size: 18px; }
    h3 { margin: 10px 0 6px; font-size: 13px; }
    ul { margin: 6px 0 0; padding-left: 20px; }
    .two-cols { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 14px; }
  </style>
</head>
<body>
  <h1>맵 애니메이션 0x40 redraw 리뷰</h1>
  <p>layer1 <code>0x40</code> 플래그 셀에서 실제로 표시되는 layer0 타일을 뽑고, EXE의 redraw/palette consumer 근거와 함께 정리했다.</p>
  <p class="muted">현재 결론: layer1 0x40 dirty redraw 대상은 확정이지만, 불꽃/폭포/물결의 실제 움직임 stream은 아직 미확정이다. palette-only는 시각적으로 맞지 않는다.</p>
  <section class="panel metrics">
    <div class="metric"><strong>re  zY</strong><span class="muted">0x40 flag maps</span></div>
    <div class="metric"><strong>zY</strong><span class="muted">animated cells</span></div>
    <div class="metric"><strong>z\</strong><span class="muted">connected regions</span></div>
    <div class="metric"><strong>rf  zd</strong><span class="muted">same-column source groups</span></div>
    <div class="metric"><strong>rg  zk</strong><span class="muted">rectangular source block regions</span></div>
    <div class="metric"><strong>rh  zc</strong><span class="muted">animated palette indices</span></div>
    <div class="metric"><strong>rj  ze</strong><span class="muted">palette command candidates</span></div>
    <div class="metric"><strong>rl  ze</strong><span class="muted">high VM-aligned candidates</span></div>
    <div class="metric"><strong>rn  zR</strong><span class="muted">animated resource bindings</span></div>
  </section>

z
  <section class="panel table-wrap">
    <table>
      <thead><tr><th>map</th><th>source tileset</th><th>coverage</th><th>flagged region</th><th>layer0 source / animation redraw footprint</th></tr></thead>
      <tbody>r*  a
  </tbody>
    </table>
  </section>
  <script src="../web/engine/cns/renderer.js"></script>
  <script>
    async function drawTilePreview(canvas) {
      const tileset = canvas.dataset.tileset;
      const tile = Number(canvas.dataset.tile);
      const columns = Number(canvas.dataset.columns || 40);
      const source = await window.HWANSE_CNS_RENDERER.loadImageCanvas(tileset);
      const scale = 3;
      canvas.width = 16 * scale;
      canvas.height = 16 * scale;
      const ctx = canvas.getContext("2d");
      ctx.imageSmoothingEnabled = false;
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      const sx = (tile % columns) * 16;
      const sy = Math.floor(tile / columns) * 16;
      ctx.drawImage(source, sx, sy, 16, 16, 0, 0, 16 * scale, 16 * scale);
    }
    async function drawSourceBlockPreview(canvas) {
      const tileset = canvas.dataset.tileset;
      const source = await window.HWANSE_CNS_RENDERER.loadImageCanvas(tileset);
      const tileSize = 16;
      const scale = 2;
      const blockX = Number(canvas.dataset.blockX);
      const blockY = Number(canvas.dataset.blockY);
      const blockW = Number(canvas.dataset.blockW);
      const blockH = Number(canvas.dataset.blockH);
      canvas.width = blockW * tileSize * scale;
      canvas.height = blockH * tileSize * scale;
      const ctx = canvas.getContext("2d");
      ctx.imageSmoothingEnabled = false;
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      ctx.drawImage(
        source,
        blockX * tileSize,
        blockY * tileSize,
        blockW * tileSize,
        blockH * tileSize,
        0,
        0,
        canvas.width,
        canvas.height,
      );
    }
    for (const canvas of document.querySelectorAll(".tile-preview")) {
      drawTilePreview(canvas).catch((error) => {
        const ctx = canvas.getContext("2d");
        ctx.fillStyle = "#fee2e2";
        ctx.fillRect(0, 0, canvas.width, canvas.height);
        ctx.fillStyle = "#991b1b";
        ctx.font = "10px sans-serif";
        ctx.fillText("load fail", 2, 14);
        console.error(error);
      });
    }
    for (const canvas of document.querySelectorAll(".source-block-canvas")) {
      drawSourceBlockPreview(canvas).catch((error) => {
        const ctx = canvas.getContext("2d");
        ctx.fillStyle = "#fee2e2";
        ctx.fillRect(0, 0, canvas.width || 96, canvas.height || 72);
        ctx.fillStyle = "#991b1b";
        ctx.font = "10px sans-serif";
        ctx.fillText("load fail", 2, 14);
        console.error(error);
      });
    }
  </script>
</body>
</html>
zmap_animation_tile_review.htmlr   r   )r   r~  r  r  r  r  r  r  r  r  r   
write_text)r  rX  	rows_htmlr   docs        r   
write_htmlr    s8   YGIf~ 	
88;CJ7HH~  @C  DG  HM  DN  @O  P PS1233TUXY]YbYbcfgvcwYxUyTz {*+,Js;K7L6M_]`ax]y\z {$S)* +(-./CC/H.IJ_`cJdIe  gE  FI  gJ  fK K	
	
3!f "));!< = >!!()<!= > ?!!()9!: ; <!!()K!L M N!!()O!P Q R!!()D!E F G!!()G!H I J!!()K!L M N!!()M!N O PV  V$ % & ggi ! G"EICT 	++77g7Nr   c                     t               } t        dz  j                  t        j                  | dd      d       t        |        t        d| d   d	    d
| d   d    d       y )Nzmap_animation_tile_review.jsonFr   )ensure_asciiindentr   r   z!wrote map animation tile review: rX  re  z maps, r9  r  )ry  r   r  r   dumpsr  print)r  s    r   mainr  N  sp    ^F++77

6X]fg8hsz7{v	
+F9,=>P,Q+RRY)01
2&	:r   __main__)returnr	  )r   r	  r  
list[dict])r   r  r  r  )r   r}  r  r	  )r   r}  r  z<tuple[int, int, list[tuple[int, int, int]], list[list[int]]])r   	list[int]r  r  )r  
str | Noner  
int | None)r
  r}  r  r}  )r  r  )r   r	  r6  set[str]r7  r  r  r	  )
r=  r	  r6  r  r7  r  r>  r  r  r	  )r   r  r  r	  )rP  r  rQ  r	  r  r	  )r   )
r_  zlist[list[int]]r`  r  r   r  ra  r  r  r   )r   r}  r   r  r   r  r  r	  )r~  r  r  r  )r  r  r  r  )r  bytesr  r  r  z&list[tuple[int, int, int, int]] | None)r   r	  r  r	  )r   )r  r  r~  r  r  r  r  r  )r  r  r  r  r  r  r  r}  )r>   )
r  r  r  r  r  r  r  r  r  r  )r  r  r  r  r  r	  r{  )r
  r  r  dict | Noner  r	  )r   r	  r   r  r  r  )r   r	  r   r  r#  r	  r  r  )r   r  r   r  r  r  )r  r}  )r   r	  r  r}  )r   r  r  r}  )r   )r   z	list[str]r  r  r  r}  )r  r	  r  r}  )r  r	  r  r}  )r  r	  r  None)r  r  )J__doc__
__future__r   r{  r   r  syscollectionsr   r   r   pathlibr   r  insertr}  __file__resolveparent
decode_cnsr   r	   parentsROOTr   r   r  r   r}  r  r   r   r   r   r   r   r   r  r  r#  r2  r8  r?  rC  r]  re  ry  r  r  r  r  r  r  r  r  r  r  r&  r1  ry  r~  r  r  r  r  r  r  r  r  r  r  r  r  __name__r   r   r   <module>r     sK	   G "    
 3 3  3tH~--/667 8 2 H~''*
Ul]"
] H!H!H 	!H 	!	H
 	!H 	!H 	!H 	!H 	!H 	!H 	!H 	!H 	!H 	!H 	!H  	!!H" 	!#H$ 	!%H& 	!'H( 	!)H* 	!+H, 	!-H. 	!/H0 	!1H2 	!3H4 	!5H6 	!7H8 	!9H: 	!;H< 	"=H> 	!?H@ 	!AHB 	!CHD 	!EHF 	!GHH 	!IHJ 	!KHL 	!MHN 	!OHP 	!QHR 	!SHT 	!UHV 	!WHX 	!YHZ 	![H\ 	!]H^ 	"_H` 	!aHb 	!cHd 	!eHf 	!gHh 	!iHj 	!kHl 	!mHn 	!oHp 	!qHr 	!sHt 	!uHv 	!wHx 	!yHz 	!{H| 	!}H~ 	!H@ 	!AHB 	!CHD 	!EHF 	!GHH 	!IHJ 	!KHL 	!MHN 	"OHP 	!QHR 	!SHT 	!UHV 	!WHX 	!YHZ 	"[H\ 	!]H^ 	!_H` 	!aHb 	!cHd 	!eHf 	!gHh 	"iHj 	!kHl 	!mHn 	!oHp 	!qHr 	!sHt 	!uHv 	!wHx 	!yHz 	!{H| 	!}H~ 	!H@ 	!AHB 	!CHD 	!EHF 	!GHH 	!IHJ 	!KHL 	"MHN 	!OHP 	!QHR 	!SHT 	!UHV 	!WHX 	"YHZ 	"[H\ 	!]H^ 	!_H` 	!aHb 	!cHd 	"eHf 	!gHh 	!iHj 	!kHl 	!mHn 	"oHp 	"qHr 	!sHt 	!uHv 	!wHx 	!yHz 	!{H| 	!}H~ 	!H@ 	!AHB 	!CHD 	!EHF 	!GHH 	!IHJ 	!KHL 	!MHN 	!OH VA
(\D \(*@@E2"
FR F&<$)SX4NbBJ44<cL#6< F
%D9x&RXOv zF r   