
    UHj~O                       d Z ddlmZ ddlZddlZddlZddlmZ ddlm	Z	 ddl
mZmZ ddlmZ ddlmZ  ee      j'                         j(                  d	   Zed
z  Zedz  Zedz  ZddZddZd dZd!dZd"dZd#dZd$dZd%dZ d&dZ!d'dZ"	 	 	 	 	 	 	 	 d(dZ#	 	 	 	 	 	 	 	 	 	 d)dZd*dZ$d+dZ%d,dZ&d-dZ'e(dk(  r e'        yy).a  Export EXE-proximity enemy sprite candidates for battle review scenes.

The mapping is deliberately non-promoting: it connects battle background
resource descriptors to nearby enemy/object sprite resource descriptors in the
EXE address space, so the browser can render an original sprite candidate
instead of a placeholder. It does not prove original enemy rows, formations,
stats, rewards, formulas, or battle-entry execution.
    )annotationsN)Path)Any)decompress_cnsparse_image)read_sections)build_summary   outextract_fldzHwanse2.exec                p    	 t        j                  | j                  d            S # t        $ r |cY S w xY w)Nutf-8encoding)jsonloads	read_textFileNotFoundError)pathfallbacks     ;/home/exedev/hwanse/tools/export_battle_enemy_candidates.py	load_jsonr      s5    zz$..'.:;; s   $' 55c                    | j                  d      xs g D cg c]7  }|j                  d      |k(  r!t        |j                  d      t              r|9 c}S c c}w )NresourceDescriptorRowsclassrefVa)get
isinstanceint)resource_descriptorsclsrows      r   ref_rowsr#   $   sV    +//0HIOR777s"z#'''2BC'H 	  s   <Ac                h    t         | z  }|j                         sydt        |       j                   dS )N z../extract_fld/.cns)EXTRACT_FLDexistsr   stem)namesrcs     r   cns_browser_pathr,   +   s0    

C::<T$Z__-T22    c                F    |sy t        | d         t        |fd      S )Nr   c                    t        t        | d         z
        t        | j                  d      xs d      t        | d         fS )Nr   r*   r%   )absr   strr   )r"   ref_vas    r   <lambda>znearest_enemy.<locals>.<lambda>8   sA    CL!F*+%2&G
 r-   key)r   min)background_ref
enemy_refsr2   s     @r   nearest_enemyr9   2   s-    ()F
 r-   c                h   | |z  dz   dz  dz  }g }t        |      D ]  }||dz
  |z
  |z  ||z
  |z   }|dk(  r|j                  t        |d |               :g }|d | dz   dz   D ]9  }	|j                  |	dz	         t        |      | k  s&|j                  |	dz         ; |j                  |        |S )N          r
            )rangeappendlistlen)
widthheightpixelsbppstriderowsy
source_rowvaluesbytes
             r   unpack_palette_indicesrO   @   s    s{RB&!+FD6] 
VaZ!^v5!v8MN
!8KKZ/011%!)!12 	+DMM$!)$6{U"dTk*	+ 	F
 Kr-   c                n    | dk\  r| dz  dk(  rg dS | dk\  r| dz  dk(  rg dS | dk\  r| d	z  dk(  rg d
S dgS )Ni  r=   r   )r=   r?      r
   i,     )rR   r?   r=   r
      r?   )r?   r
   r=   r
    )rF   s    r   row_candidatesrU   Q   sN    }!q}!q}!q3Jr-   c                >    |dk\  ry|dk(  ry|dk(  ry|dk  r| dk\  ryy	)
Nr=      rR      r?   r>   @   ih     rT   )rE   rF   rJ   s      r   target_frame_countr[   [   s3    qyqyqy|r-   c                   	 |dk  s|dk  s
||z  s||z  ry ||z  }||z  }|dk  s|dk  ry t        |      D cg c]   t         fdt        |      D              " }}t        |      D 		cg c]   	t         	fdt        |      D              " }
}	t        |      xs d}d}d}t        d|      D ]7  }||z  |t        |t        ddz
        t        |dz                z  }|dz  }9 t        d|      D ]7  }||z  	|t        |
t        d	dz
        t        |	dz                z  }|dz  }9 d}d}t        |      D ]  }t        |      D ]  }||z  }||z   }||z  }||z   }d}t        ||      D ]$  	t        ||      D ]   	      dk7  s|dz  } & |dk(  r|dz  }W||dz
  fD ]$  |t         fdt        ||      D              z  }& ||dz
  fD ]$  	|t         	fdt        ||      D              z  }&   |t        d|      z  d	z  |z  }|d
z  |z  }||z  }t	        |||      }t        ||z
        dz  }|t        d|      z  }d}|dk  r	d|z
  dz  }n|dkD  r|dz
  dz  }d}t        |      d   }||k7  rd}||dz  z   |dz  z   |z   |z   |z   } | |||||t        | d      t        |      |dfS c c}w c c}	w )Nr      c              3  :   K   | ]  }|      d k7  sd  ywr   r
   NrT   .0rK   
index_rowsxs     r   	<genexpr>zgrid_score.<locals>.<genexpr>o   s!     KqZ]15E5JK   c              3  :   K   | ]  }   |   d k7  sd  ywr_   rT   ra   rc   rb   rK   s     r   rd   zgrid_score.<locals>.<genexpr>p   s!     GAAq1AQ1FaGre   r
   r?   c              3  :   K   | ]  }|      d k7  sd  ywr_   rT   r`   s     r   rd   zgrid_score.<locals>.<genexpr>   #     %XA*Q-PQBRVWBWa%Xre   c              3  :   K   | ]  }   |   d k7  sd  ywr_   rT   rg   s     r   rd   zgrid_score.<locals>.<genexpr>   ri   re   i  d   r>   g        g?x   g@P   #   g
ףp=
?Z   rR   )columnsrJ   sourceWidthsourceHeight
frameCountscore
cutPenalty
emptyCells)	rA   summaxr6   r[   r0   rU   roundr   )!rb   rE   rF   rp   rJ   frame_widthframe_heightrc   column_countsrK   
row_countstotal_visiblecut_penalty	cut_countcolumnr"   empty_cellsborder_penaltyx0x1y0y1visiblecut_densityborder_densityframe_counttarget_countcount_penaltyaspectaspect_penaltyrow_preference_penaltypreferred_rowsrt   s!   `      ` `                       r   
grid_scorer   g   s   !|tqyEGOv}7"KT>LR<",UZ[`UabPQSKE&MKKbMbQVW]Q^_A#GuGG_J_&+!MKI7# [ s=QAUAE9JKLLQ	 Q~ ,s:c!QUmc&!a%6HIJJQ	
 KNT{ YGn 	YF+%Bk!B|#Bl"BG2r] %r2 %A!!}Q'1,1%% !|q "q&\ Y#%Xr2%X"XXY"q&\ Y#%Xr2%X"XXY	YY& Q	!22d:]JK#c)M9ND.K%eVT:Ll23a7M3q,//FN}-3.	# 3,",#F+A.N~!#.4//+2BB]RUccf||E"$!ua+&!	 	 	m c_s   %K1%K
c           	     t   t        |xs i j                  d      xs d      }t        |xs i j                  d      xs d      }|r|sg S t        | z  }|j                         sg S 	 t	        |j                               }t        |      \  }}}}	}
||k7  s||k7  r||}}t        |||	|
      }g }t        |      }g d}|dk\  rg d}|D ],  }|D ]%  }t        |||||      }||j                  |       ' . |j                  d        |d d	 D cg c]  \  }}|	 c}}S # t        $ r g cY S w xY wc c}}w )
NrE   r   rF   )
r?   rR   r=   rQ   rZ      r>   	   
   rX   rS   )r=   rR   rQ   r?   rZ   r>   r   rX   c                *    | d   | d   d   | d   d   fS )Nr   r
   rp   rJ   rT   items    r   r3   z,inferred_layout_candidates.<locals>.<lambda>   s"    d1gtAwy/A476?%S r-   r4   r>   )r   r   r'   r(   r   
read_bytesr   rO   	ExceptionrU   r   rB   sort)r*   payloadrE   rF   r+   decodedparsed_widthparsed_height_paletterG   rH   rb   
candidatesrow_optionscolumn_optionsrJ   rp   scored_score	candidates                       r   inferred_layout_candidatesr      s`   B##G,12E'-R$$X.3!4F	

C::<	 !12=H=Q:mXvs5 MV$;(-6E+E663G
 ,.J (K5N}3 *% 	*G
E67DIF!!!&)	**
 OOSOT/9"1~>+&)I>>  	 ?s   'AD# D4#D10D1c                   t        |xs i j                  d      xs d      }t        |xs i j                  d      xs d      }|r|sdddddS t        | |      }t        ||dk\  rdn|      }t        ||dk\  rdn|      }|dk  r||k\  rt        |t	        d|            }|}dd||t	        d|t	        d|      z        t	        d|t	        d|      z        t	        d|t	        d|      z  |t	        d|      z  z        dd|d	d
d
d
dS )NrE   r   rF   )sourceXsourceYrq   rr   `   r
   zlegacy-dimension-fallbacklowz#palette0-grid-cut-score-review-onlyF)r   r   rq   rr   rp   rJ   rs   	inference
confidencelayoutCandidateslayoutCandidateSourceoriginalFrameRectsBoundoriginalFrameOffsetsBoundoriginalAnimationScriptBound)r   r   r   r6   rx   )r*   r   rE   rF   layout_candidatessource_widthsource_heights          r   
frame_hintr      s*   B##G,12E'-R$$X.3!4F1aPP24AuERKbU;Lfl?M|5#a.1#%q%3q,#778AvQ!667!es1l';;#aQ^J_@_`a0-!F#(%*(- r-   c                   i }t        |d       D ]-  }t        |j                  d      xs d      }|s$||vs)|||<   / t        dD ch c](  }t        j	                  |      D ]  }|j
                   * c}}t        |      z        }g }	i }
|D ]  }t        |      j                  }t        |      }|r||
|<   | j                  |      }|j                  |      xs i }|	j                  ||||j                  d      |j                  d      xs3 t        |j                  d      t              rdt        |d         d	nd|xs i j                  d
      |xs i j                  d      t        ||      dddd        |	|
fS c c}}w )Nc                z    t        | j                  d      xs d      t        | j                  d      xs d      fS )Nr*   r%   r   r   )r1   r   r   r   s    r   r3   z-all_enemy_sprite_asset_rows.<locals>.<lambda>   s7    C8H8NB4OQTUYU]U]^eUfUkjkQl3m r-   r4   r*   r%   )z	boss*.cnszz*.cnsr   refVaHex0x08xrE   rF   zextracted-enemy-object-spriteF)enemyCnsenemyAssetKeyenemyAssetPath
enemyRefVaenemyRefVaHexpayloadWidthpayloadHeight	frameHintselectionKindoriginalEnemyRowBoundoriginalStatsOrRewardsBound)sortedr1   r   r'   globr*   setr   r)   r,   rB   r   r   r   )payload_by_namer8   out_dirref_by_namer"   r*   patternr   namesrJ   asset_paths	asset_key
asset_pathr   refs                  r   all_enemy_sprite_asset_rowsr      s   
 $&Kj&mn $3776?(b)D+ #K$  3	
#((1	
  II	
	

 k
	E D"$K JOO	%d+
%/K	"!%%d+ood#)r&('''* WWZ0 0:3777;KS0Q"SW&s+,WY$]//8%m00:#D'2<%*+0
 	, ?	
s   -F
c                	   |D ci c]&  }|j                  d      s|j                  d      |( }}t        | d      }t        | d      }t        |||      \  }}	i }
|D ]?  }|
j                  t	        |j                  d      xs d      g       j                  |       A g }i }|j                  d      xs g D ]  }t	        |j                  d      xs d      }|r|j                  d      s| dn|}|
j                  |      xs g }d }|D ]L  }t        ||      }|st        t        |d         t        |d         z
        }|||f}||d	   |d	   k  sK|}N |s|\  }}}t	        |j                  d      xs d      }t        |      j                  }t        |      }|r
||	|<   |||<   |j                  |      }t        ||      }|j                  i d
|j                  d      xs dd|j                  d      xs dd|d|j                  d      d|j                  d      xs dt        |d         dd|d|d|d|j                  d      d|j                  d      xs dt        |d         dd|d|xs i j                  d      d|xs i j                  d      d|dddd d!d        
 |D ci c]  }|j                  d
      s|d
   | }}i }t        |d" #      D ]  }|j                  |d   |        |D ci c]  }|j                  d      r|d   | }}|D ch c]  }|j                  d      s|d    }}i d$d%d&g d'd(d)d*t        |      d+t        |D ch c]  }|d   	 c}      d,t        |      d-t        |      d.t        |	      d/|	d0|d|d1|d2|d3|d4t        |      d	kD  t        |      t        |      k(  t        |	      t        |D ch c]  }|d   s	|d    c}      k(  t        |      t        |	      k(  xr t        |      t        |      k\  d d d d5d6t        |       d7t        |       d8S c c}w c c}w c c}w c c}w c c}w c c}w )9Nr*   zbattle-background-tilemapzenemy-object-sprite-imager%   r   battleBackgroundr&   r   r   candidateIdidblockIdbattleBackgroundRefVabattleBackgroundRefVaHexr   r   r   r   r   r   r   r   refDistancer   rE   r   rF   r   r   znearest-exe-resource-descriptorr   Fr   c                    | d   | d   fS )Nr   r   rT   r   s    r   r3   zbuild_summary.<locals>.<lambda>X  s    ]8KTR_M`7a r-   r4   scopezKBattle enemy sprite candidates chosen by EXE resource descriptor proximity.source)z+in-memory EXE resource descriptor proximityz out/battle_event_candidates.jsonzout/cns_payloads.jsonzextract_fld/*.cnspromotionStatusz(sprite-proximity-candidate-not-enemy-rowcandidateCountuniqueEnemySpriteCountcandidateAssetCountextractedEnemySpriteAssetCount
assetCountassetsspriteAssetsbyCandidateIdbyBattleBackgroundbyEnemyAssetKeychecks)!battleEnemySpriteCandidatesMapped!candidateEnemyAssetsHaveCnsSourceenemyAssetsHaveCnsSource.allExtractedEnemySpriteAssetsRuntimeSelectableoriginalEnemyRowsBoundr   originalBattleEntryProven
conclusionz} battle review candidates now have an EXE-nearest enemy/object sprite visual candidate. The runtime asset table also exposes a   extracted boss*/z* sprite assets for prototype battle selection. This improves the browser battle review scene with original sprite assets, but it is proximity evidence only: enemy rows, stats, formations, rewards, formulas, and battle-entry execution remain unproven.)r   r#   r   
setdefaultr1   rB   endswithr9   r0   r   r   r)   r,   r   r   rD   )r    battle_event_candidatescns_payloadsr   r"   r   backgroundsr8   sprite_asset_rowsr   background_by_namecandidate_rowscandidate_asset_pathsr   background_keybackground_namematching_backgrounds	best_pairr7   enemydistancepair
enemy_namer   r   r   hintby_candidateby_backgroundby_enemy_asset_keycandidate_asset_keyss                                  r   r	   r	     s3    8DWswwvswwv+WOW/1LMK.0KLJ%@R\^e%f"{02 R%%c#''&/*?R&@"ELLSQR N,.,00>D" *	Y]]+=>D"E5CNLcLcdjLk^,D1q155oFL"	2 	!N!.*=E3uW~.^G5L1MMNHne4D DGil$: 		! *3'.%6*0b1
$))	%j1
%/K	"/9!),!%%j1*g. 
9==.4"
y}}Y/52
 
 $^%7%7%@	

 '(:(::(F(qBsSabiSjOkloNpJq
 

 Y
 j
 %))G,
 UYYz2T3uW~;Ns:S6T
 8
 W]//8
 gm00:
 
 >
  $U!
" *5#
 	1*X 8F`Q^I_C&+`L`Mn*ab ?  %7!8#>? %77?# 	Oc! 
 =KgScggVeNfC0gg#^# 
# 	E# 	#n-# 	!#.&Q3s:&Q"R# 	s#89# 	)#.?*@# 	c+&# 	+# 	)#  	n!#" 	##$ 	m%#& 	-'#( 	14^1Dq1H145J1KsSgOh1h(+K(8Car  AMZ]vy  {K  wL_AU  AM  =N  )N>ABS>TX[\gXh>h  ?bmp  rC  nD  HK  La  Hb  nb&++0).
)#: 	>"# $4478I4J3K Lll=# #C Xl a
 h 'R AMs:   Q(Q(Q-Q-Q2;Q7Q7=Q<=
RRc                   dj                  d | d   j                         D              }dj                  d | d   D              }dj                  d | d   D              }dj                  d	d
ddddddddt        j                  | d          ddt        j                  | d          ddd| ddd| ddd| ddd dg      S )!Nr%   c           	   3     K   | ]?  \  }}d t        j                  |       dt        j                  t        |             d A yw)<tr><td>z	</td><td>z
</td></tr>N)htmlescaper1   )ra   r5   values      r   rd   zhtml_page.<locals>.<genexpr>  sC      C 4;;s#$Idkk#e*.E-FjQs   AAr   c              3  Z  K   | ]  }d t        j                  |d          dt        j                  |d          dt        j                  |d          dt        j                  |d          dt        j                  |d          d|d	    dt        j                  |d
          d  yw)r  r   </td><td><code>r   </code></td><td><code>r   r   r   </code></td><td>r   r   </code></td></tr>N)r  r  ra   r"   s     r   rd   zhtml_page.<locals>.<genexpr>  s       	{{3}-./ 0[[%7!89: ;[[Z12 3[[%?!@AB C[[_!567 8=!" #[[_!567 8	s   B)B+r   c              3    K   | ]  }d t        j                  |d          dt        j                  t        |j                  d      xs d             dt        j                  t        |j                  d      xs d             dt        j                  |j                  d      xs d       d	t        j                  |d
          d  yw)z<tr><td><code>r   r  r   -rc   r   r  r   r  r   r  N)r  r  r1   r   r  s     r   rd   zhtml_page.<locals>.<genexpr>  s       	[[Z12 3{{3sww~6=#>?@$++cRURYRYZiRjRqnqNrBsAt u[[!9!@SAB C[[_!567 8		s   CCr   
z<!doctype html>z<html lang="en">z<head>z  <meta charset="utf-8">z/  <title>Battle Enemy Sprite Candidates</title>a    <style>body{font-family:system-ui,sans-serif;margin:24px;line-height:1.45;max-width:1200px}table{border-collapse:collapse;width:100%;margin:16px 0}td,th{border:1px solid #ddd;padding:6px 8px;text-align:left;vertical-align:top}th{background:#f5f5f5}code{white-space:nowrap}</style>z</head>z<body>z)  <h1>Battle Enemy Sprite Candidates</h1>z  <p>r   z</p>z  <p>Promotion status: <code>r   z</code></p>z  <h2>Checks</h2>zD  <table><thead><tr><th>check</th><th>value</th></tr></thead><tbody>z</tbody></table>z  <h2>Candidates</h2>z  <table><thead><tr><th>battle candidate</th><th>background</th><th>enemy sprite</th><th>bg ref</th><th>enemy ref</th><th>distance</th><th>asset</th></tr></thead><tbody>z"  <h2>Extracted Sprite Assets</h2>zf  <table><thead><tr><th>sprite</th><th>size</th><th>ref</th><th>runtime asset</th></tr></thead><tbody>z</body>z</html>)joinitemsr  r  )summary
check_rowsr   sprite_rowss       r   	html_pager    s7    !(+113 J WW  <( N ''  >* K 99"9 	e3
GL12348
'G<M4N(O'PP[\
NzlZjk t  uC  tD  DT  	U,
pq|p}  ~N  	O
)  r-   c                2    t        j                  | dd      S )NF),:)ensure_ascii
separators)r   dumps)r  s    r   js_jsonr%    s    ::e%JGGr-   c                H   |j                  dd       |dz  j                  t        j                  | dd      dz   d	       |d
z  j                  dt	        | d   | d   | d   | d   | d   | d   | d   | d   | d   | d   d
      z   dz   t	        | d         z   dz   d	       y )NT)parentsexist_okzbattle_enemy_candidates.jsonFr?   )r"  indentr  r   r   battle_enemy_candidates.jsz(window.HWANSE_BATTLE_ENEMY_CANDIDATES = r   r   r   r   r   r   r   r   r   r   )
r   r   r   r   r   r   r   r   r   r   z&;
window.HWANSE_BATTLE_ENEMY_ASSETS = r   z;
)mkdir
write_textr   r$  r%  )r  r   s     r   write_outputsr-    s    MM$M.--99

7q9D@ :  ++772
&'89%&67&-.F&G#*+@#A.56V.W!,/#N3$_5")*>"?&'89
 	 4	4 '(#
$	% 	  # 8 r-   c                    t        j                  t              } | j                  dt        t
               | j                         }t        |j                  dz  g       }t        |j                  dz  i       }|s,t        j                         }t        |      }t        |||      }t        |t        |j                  dz  i       ||j                        }t        ||j                         t        d|j                  dz          y )	N)descriptionz	--out-dir)typedefaultzcns_payloads.jsonz)original_battle_resource_descriptors.jsonzbattle_event_candidates.jsonz(wrote battle enemy sprite candidates -> r*  )argparseArgumentParser__doc__add_argumentr   OUT
parse_argsr   r   EXEr   r   !build_resource_descriptor_summaryr	   r-  print)parserargsr   r    exe_datasectionsr  s          r   mainr?    s    $$9F
$<DT\\,??DL$T\\4_%_acd>># *@ 

 $,,!??D	G '4<<(	4T\\D`5`4a
bcr-   __main__)r   r   r   r   returnr   )r    dictr!   r1   rA  
list[dict])r*   r1   rA  r1   )r7   rB  r8   rC  rA  dict | None)
rE   r   rF   r   rG   bytesrH   r   rA  list[list[int]])rF   r   rA  z	list[int])rE   r   rF   r   rJ   r   rA  r   )rb   rF  rE   r   rF   r   rp   r   rJ   r   rA  ztuple[float, dict] | None)r*   r1   r   rD  rA  rC  )r*   r1   r   rD  rA  rB  )r   zdict[str, dict]r8   rC  r   r   rA  z!tuple[list[dict], dict[str, str]])
r    rB  r   rB  r   rC  r   r   rA  rB  )r  rB  rA  r1   )r  r   rA  r1   )r  rB  r   r   rA  None)rA  rG  ))r4  
__future__r   r2  r  r   pathlibr   typingr   
decode_cnsr   r   probe_exe_scene_tablesr   .summarize_original_battle_resource_descriptorsr	   r9  __file__resolver'  ROOTr6  r'   r8  r   r#   r,   r9   rO   rU   r[   r   r   r   r   r  r%  r-  r?  __name__rT   r-   r   <module>rR     s&   #      2 0 m H~''*
Ul]"
]3"	GT?>:*$** * '	*Zjj!j j 	j
 
jZ/dH6d0 zF r-   