2020-10-19 23:58:57 +02:00
#! /usr/bin/python3
2021-12-16 01:27:26 +01:00
import sym_info
2021-03-24 09:39:43 +01:00
from pathlib import Path
2020-10-19 23:58:57 +02:00
2021-12-23 13:16:12 +01:00
2020-10-31 03:28:18 +01:00
_script_lib = None
2021-03-24 09:39:43 +01:00
def script_lib ( offset ) :
2020-10-31 03:28:18 +01:00
global _script_lib
2020-10-19 23:58:57 +02:00
2020-10-31 03:28:18 +01:00
if not _script_lib :
_script_lib = { }
2020-10-19 23:58:57 +02:00
from os import path
import re
2020-10-31 03:28:18 +01:00
# star rod database
"""
2020-10-19 23:58:57 +02:00
LIB_LINE_RE = re . compile ( r " \ s+: \ s+ " )
NAME_RE = re . compile ( r " ( { [^}]*})? \ s*([a-zA-Z0-9_]+) " )
for filename in Path ( path . dirname ( __file__ ) , " star-rod " , " database " ) . rglob ( " *.lib " ) :
with open ( filename , " r " ) as file :
for line in file . readlines ( ) :
parts = LIB_LINE_RE . split ( line )
if len ( parts ) > = 3 :
try :
kind = parts [ 0 ]
vaddr = int ( parts [ 1 ] . split ( " , " ) [ 0 ] , 16 )
if name := NAME_RE . match ( parts [ 2 ] ) :
name = name . group ( 2 )
2020-10-31 03:28:18 +01:00
_script_lib [ vaddr ] = name
2020-10-19 23:58:57 +02:00
except :
pass
2020-10-31 03:28:18 +01:00
"""
2021-03-24 09:39:43 +01:00
repo_root = Path ( __file__ ) . resolve ( ) . parent . parent
symbols = Path ( repo_root / " ver " / " current " / " symbol_addrs.txt " )
with open ( symbols , " r " ) as file :
2020-10-31 03:28:18 +01:00
for line in file . readlines ( ) :
2020-11-08 11:28:08 +01:00
s = [ s . strip ( ) for s in line . split ( " = " , 1 ) ]
2020-10-31 03:28:18 +01:00
name = s [ 0 ]
2021-03-24 09:39:43 +01:00
vaddr = int ( s [ 1 ] . split ( " ; " ) [ 0 ] . split ( " " ) [ 0 ] , 16 )
raddr = " 0xFFFFFFFF "
if " rom: " in line :
raddr = line . split ( " rom: " , 1 ) [ 1 ]
if " " in raddr :
raddr = raddr . split ( " " , 1 ) [ 0 ]
raddr = raddr . strip ( )
if vaddr not in _script_lib :
_script_lib [ vaddr ] = [ ]
_script_lib [ vaddr ] . append ( [ int ( raddr , 16 ) , name ] )
2021-12-28 18:11:07 +01:00
"""
2021-04-03 19:21:49 +02:00
# Sort the symbols for each vram address by the difference
2021-03-24 09:39:43 +01:00
# between their rom address and the offset passed in.
# If offset - rom address goes below 0, it's part of the
# previous file, so treat it as min priority, same as a default.
# After sorting, the first rom address and name should be the best candidate.
for k in _script_lib . keys ( ) :
for i , entry in enumerate ( _script_lib [ k ] ) :
diff = offset - entry [ 0 ]
entry [ 0 ] = 0xFFFFFFFF if diff < 0 else diff
_script_lib [ k ] [ i ] [ 0 ] = entry [ 0 ]
_script_lib [ k ] = sorted ( _script_lib [ k ] , key = lambda x : x [ 0 ] )
2021-12-28 18:11:07 +01:00
"""
2020-10-31 03:28:18 +01:00
return _script_lib
2021-12-23 13:16:12 +01:00
2021-12-28 18:11:07 +01:00
def extend_symbol_map ( a , b ) :
for k in b :
if k not in a :
a [ k ] = b [ k ]
else :
a [ k ] + = b [ k ]
return a
2021-07-12 14:06:00 +02:00
def round_fixed ( f : float ) - > float :
2021-12-28 18:11:07 +01:00
"""
2021-07-12 14:06:00 +02:00
g = f * 100.0
whole = round ( g )
if abs ( g - whole ) < = 100.0 / 1024.0 :
f = whole / 100.0
2021-12-28 18:11:07 +01:00
"""
2021-07-12 14:06:00 +02:00
return f
2021-12-23 13:16:12 +01:00
2021-12-28 18:11:07 +01:00
def find_symbol_in_overlay ( symbol_map , overlay_rom_addr , symbol_ram_addr ) :
if not symbol_ram_addr in symbol_map :
return None
lowest_delta = None
lowest_symbol_name = None
for rom_addr , symbol_name in symbol_map [ symbol_ram_addr ] :
delta = rom_addr - overlay_rom_addr
if delta > = 0 and ( lowest_delta is None or delta < = lowest_delta ) :
lowest_delta = delta
lowest_symbol_name = symbol_name
if lowest_symbol_name :
return lowest_symbol_name
return symbol_map [ symbol_ram_addr ] [ 0 ] [ 1 ]
2021-03-30 05:39:17 +02:00
# Grab CONSTANTS from the include/ folder to save manual work
CONSTANTS = { }
SAVE_VARS = set ( )
2021-03-24 09:39:43 +01:00
def get_constants ( ) :
2021-03-30 05:39:17 +02:00
global CONSTANTS
global VALID_SAVE_VARS
2021-04-22 05:19:31 +02:00
valid_enums = { " StoryProgress " , " ItemIDs " , " PlayerAnims " ,
2021-04-03 19:21:49 +02:00
" ActorIDs " , " Events " , " SoundIDs " , " SongIDs " , " Locations " ,
2021-12-24 14:29:05 +01:00
" AmbientSounds " , " NpcIDs " , " Emotes " , " NpcFlags " , " Statuses " , " Elements " ,
" DamageTypes " , " HitResults " , " ActorFlags " , " ActorPartFlags " ,
" ActorEventFlags " , " ElementFlags " , " EncounterTriggers " , " Abilities " ,
" Easings " , " DecorationIDs " , " HitResults " , " Phases " , " ItemSpawnModes " ,
" ActionStates " , " Triggers " , " Buttons " , " ActionCommand " , " MoveIDs " }
2021-03-24 18:30:25 +01:00
for enum in valid_enums :
2021-03-30 05:39:17 +02:00
CONSTANTS [ enum ] = { }
2021-04-03 19:21:49 +02:00
CONSTANTS [ " NPC_SPRITE " ] = { }
2021-04-08 19:42:36 +02:00
CONSTANTS [ " MAP_NPCS " ] = { }
2021-03-30 05:39:17 +02:00
2021-08-29 16:34:42 +02:00
[ SAVE_VARS . add ( x ) for x in [ " EVT_WORLD_LOCATION " , " EVT_STORY_PROGRESS " ] ]
2021-03-24 09:39:43 +01:00
include_path = Path ( Path ( __file__ ) . resolve ( ) . parent . parent / " include " )
2021-03-29 02:05:56 +02:00
enums = Path ( include_path / " enums.h " ) . read_text ( ) . splitlines ( )
2021-03-24 09:39:43 +01:00
2021-03-30 05:39:17 +02:00
'''
2021-04-03 19:21:49 +02:00
# defines
2021-03-29 02:05:56 +02:00
for line in enums :
2021-03-24 18:30:25 +01:00
this_enum = " "
2021-03-29 02:05:56 +02:00
for enum in valid_defines :
2021-03-24 18:30:25 +01:00
if f " #define { enum } _ " in line :
this_enum = enum
break ;
2021-03-24 09:39:43 +01:00
2021-03-24 18:30:25 +01:00
if this_enum :
2021-03-24 09:39:43 +01:00
name = line . split ( " " , 2 ) [ 1 ]
id_ = line . split ( " 0x " , 1 ) [ 1 ]
if " " in id_ :
id_ = id_ . split ( " " , 1 ) [ 0 ]
2021-03-30 05:39:17 +02:00
CONSTANTS [ this_enum ] [ int ( id_ , 16 ) ] = name
'''
2021-03-29 02:05:56 +02:00
# enums
for i , line in enumerate ( enums ) :
if line . startswith ( " enum " ) :
enum_name = line . split ( " " , 1 ) [ 1 ] . split ( " { " , 1 ) [ 0 ]
if enum_name in valid_enums :
2021-03-30 05:39:17 +02:00
CONSTANTS [ enum_name ] = { }
2021-04-03 19:21:49 +02:00
last_num = - 1
2021-03-29 02:05:56 +02:00
i + = 1
while " } " not in enums [ i ] :
if not enums [ i ] :
i + = 1
continue
2021-04-03 19:21:49 +02:00
if " // " in enums [ i ] :
name = enums [ i ] . split ( " // " , 1 ) [ 0 ] . strip ( )
else :
name = enums [ i ] . strip ( )
2021-03-29 02:05:56 +02:00
val = last_num + 1
if " = " in name :
2021-03-30 05:39:17 +02:00
name , val = name . split ( " = " )
2021-03-29 02:05:56 +02:00
val = int ( val [ : - 1 ] , 0 )
2021-04-03 19:21:49 +02:00
if val > = 0x80000000 :
val - = 0x100000000
2021-03-29 02:05:56 +02:00
else :
name = name [ : - 1 ]
2021-03-30 05:39:17 +02:00
name = name . strip ( )
#print("\"" + name + "\"", "===", val)
2021-03-29 02:05:56 +02:00
2021-03-30 05:39:17 +02:00
CONSTANTS [ enum_name ] [ val ] = name . strip ( )
2021-03-29 02:05:56 +02:00
i + = 1
last_num = val
2021-04-08 19:42:36 +02:00
#exit()
2021-04-03 19:21:49 +02:00
# sprites
sprite_path = Path ( Path ( __file__ ) . resolve ( ) . parent . parent / " ver " / " current " / " build " / " include " / " sprite " / " npc " )
for file in sprite_path . iterdir ( ) :
fd = file . read_text ( )
for line in fd . splitlines ( ) :
2021-10-25 13:44:55 +02:00
if " #define NPC_ANIM_ " not in line :
2021-04-03 19:21:49 +02:00
continue
2021-10-25 13:44:55 +02:00
header_file_name = file . parts [ - 1 ]
2021-04-03 19:21:49 +02:00
name = line . split ( " " , 2 ) [ 1 ]
2021-10-25 13:44:55 +02:00
value = int ( line . split ( " 0x " , 1 ) [ 1 ] , base = 16 )
2021-04-03 19:21:49 +02:00
2021-10-25 13:44:55 +02:00
CONSTANTS [ " NPC_SPRITE " ] [ value ] = name
CONSTANTS [ " NPC_SPRITE " ] [ str ( value ) + " .h " ] = header_file_name
2021-04-03 19:21:49 +02:00
2021-03-24 09:39:43 +01:00
return
2021-12-23 13:16:12 +01:00
2021-04-08 19:42:36 +02:00
def make_anim_macro ( self , sprite , palette , anim ) :
2021-04-29 19:09:30 +02:00
if sprite == 0xFF and palette == 0xFF and anim == 0xFF :
return " -1 "
2021-10-25 13:44:55 +02:00
value = ( sprite << 16 ) | ( palette << 8 ) | anim
if value in CONSTANTS [ " NPC_SPRITE " ] :
self . INCLUDES_NEEDED [ " sprites " ] . add ( CONSTANTS [ ' NPC_SPRITE ' ] [ str ( value ) + " .h " ] )
return CONSTANTS [ ' NPC_SPRITE ' ] [ value ]
2021-04-08 19:42:36 +02:00
else :
2021-10-25 13:44:55 +02:00
return f " 0x { sprite : 02X } { palette : 02X } { anim : 02X } "
2021-12-23 13:16:12 +01:00
2021-10-25 13:44:55 +02:00
def remove_evt_ptr ( s ) :
if s . startswith ( " EVT_PTR( " ) :
return s [ 8 : - 1 ]
else :
return s
2021-04-08 19:42:36 +02:00
2021-12-23 13:16:12 +01:00
2021-04-03 19:21:49 +02:00
def fix_args ( self , func , args , info ) :
2021-03-30 05:39:17 +02:00
global CONSTANTS
2021-04-22 05:19:31 +02:00
2021-03-24 09:39:43 +01:00
new_args = [ ]
2021-04-08 19:42:36 +02:00
args = args . split ( " , " )
for i , arg in enumerate ( args ) :
2021-10-25 13:44:55 +02:00
if ( ( remove_evt_ptr ( arg ) == " D_80000000 " ) or ( remove_evt_ptr ( arg ) . startswith ( " D_B " ) ) or
2021-04-03 19:21:49 +02:00
( i == 0 and func == " MakeEntity " and arg . startswith ( " D_ " ) ) ) :
2021-10-25 13:44:55 +02:00
if func == " MakeEntity " :
arg = " MAKE_ENTITY_END "
else :
arg = " 0x " + remove_evt_ptr ( arg ) [ 2 : ]
if " 0x " in arg and int ( remove_evt_ptr ( arg ) , 16 ) > = 0xF0000000 :
arg = f " { int ( remove_evt_ptr ( arg ) , 16 ) - 0x100000000 } "
2021-04-29 19:09:30 +02:00
if i in info or ( i + 1 == len ( args ) and - 1 in info ) :
if i + 1 == len ( args ) and - 1 in info :
i = - 1
2021-04-03 19:21:49 +02:00
if " _ " in arg :
new_args . append ( f " { arg } " )
continue
2021-12-28 18:11:07 +01:00
try :
argNum = int ( arg , 0 )
except ValueError :
new_args . append ( f " { arg } " )
continue
2021-04-03 19:21:49 +02:00
if info [ i ] == " Bool " :
new_args . append ( f " { ' TRUE ' if argNum == True else ' FALSE ' } " )
2021-10-25 13:44:55 +02:00
elif info [ i ] == " Hex " and argNum > 0 :
2021-04-03 19:21:49 +02:00
new_args . append ( f " 0x { argNum : 08X } " )
elif info [ i ] == " CustomAnim " :
sprite = ( argNum & 0xFF0000 ) >> 16
palette = ( argNum & 0xFF00 ) >> 8
anim = ( argNum & 0xFF ) >> 0
2021-04-22 05:19:31 +02:00
2021-04-29 19:09:30 +02:00
#if argNum not in CONSTANTS["MAP_NPCS"]:
# new_args.append(f"0x{argNum:X}")
# continue
2021-07-12 14:06:00 +02:00
2021-12-28 18:11:07 +01:00
try :
if func == " SetAnimation " and int ( new_args [ 1 ] , 10 ) == 0 :
2021-04-08 19:42:36 +02:00
call = f " { CONSTANTS [ ' PlayerAnims ' ] [ argNum ] } "
2021-12-28 18:11:07 +01:00
elif " EVT_ " not in args [ 0 ] and int ( args [ 0 ] ) > = 0 and CONSTANTS [ " MAP_NPCS " ] . get ( int ( args [ 0 ] ) ) == " NPC_PLAYER " :
if sprite == 0 :
print ( f " Func { func } arg { i } ( { CONSTANTS [ ' MAP_NPCS ' ] [ int ( args [ 0 ] ) ] } ) -- sprite was 0, is this really valid? Arg 0x { argNum : X } -- sprite: { sprite } , palette: { palette } , anim: { anim } " )
call = f " 0x { argNum : X } "
else :
call = f " { CONSTANTS [ ' PlayerAnims ' ] [ argNum ] } "
2021-04-03 19:21:49 +02:00
else :
2021-12-28 18:11:07 +01:00
if sprite == 0 :
print ( f " Func { func } arg { i } -- sprite was 0, is this really valid? Arg 0x { argNum : X } -- sprite: { sprite } , palette: { palette } , anim: { anim } " )
call = f " 0x { argNum : X } "
else :
call = make_anim_macro ( self , sprite , palette , anim )
except KeyError :
call = f " 0x { argNum : 06X } "
2021-04-03 19:21:49 +02:00
new_args . append ( call )
elif info [ i ] == " CustomMsg " :
type_ = ( argNum & 0xFF0000 ) >> 16
num_ = ( argNum & 0xFFFF ) >> 0
new_args . append ( f " MESSAGE_ID(0x { type_ : 02X } , 0x { num_ : 04X } ) " )
2021-04-08 19:42:36 +02:00
elif info [ i ] == " NpcFlags " :
enabled = [ ]
for x in range ( 32 ) :
flag = argNum & ( 1 << x )
if flag :
if flag in CONSTANTS [ " NpcFlags " ] :
enabled . append ( CONSTANTS [ " NpcFlags " ] [ flag ] )
else :
enabled . append ( f " 0x { flag : 08X } " )
if not enabled :
enabled . append ( f " 0 " )
new_args . append ( " (( " + " | " . join ( enabled ) + " )) " )
elif info [ i ] == " NpcIDs " :
if argNum > = 0 :
2021-10-25 13:44:55 +02:00
if argNum in CONSTANTS [ " MAP_NPCS " ] :
new_args . append ( CONSTANTS [ " MAP_NPCS " ] [ argNum ] )
else :
new_args . append ( str ( argNum ) )
2021-04-08 19:42:36 +02:00
else :
new_args . append ( CONSTANTS [ " NpcIDs " ] [ argNum ] )
2021-07-12 14:06:00 +02:00
elif info [ i ] == " DamageTypes " :
enabled = [ ]
for x in range ( 32 ) :
flag = argNum & ( 1 << x )
if flag :
if flag in CONSTANTS [ " DamageTypes " ] :
enabled . append ( CONSTANTS [ " DamageTypes " ] [ flag ] )
else :
enabled . append ( f " 0x { flag : 08X } " )
if not enabled :
enabled . append ( f " 0 " )
new_args . append ( " (( " + " | " . join ( enabled ) + " )) " )
2021-12-24 14:29:05 +01:00
elif info [ i ] == " SoundIDs " :
if argNum in CONSTANTS [ " SoundIDs " ] :
new_args . append ( CONSTANTS [ " SoundIDs " ] [ argNum ] )
else :
new_args . append ( " 0x %X " % argNum )
elif info [ i ] == " StoryProgress " :
print ( info [ i ] )
if argNum in CONSTANTS [ " StoryProgress " ] :
new_args . append ( CONSTANTS [ " StoryProgress " ] [ argNum ] )
else :
new_args . append ( str ( argNum ) )
2021-04-03 19:21:49 +02:00
elif argNum in CONSTANTS [ info [ i ] ] :
2021-03-30 05:39:17 +02:00
new_args . append ( f " { CONSTANTS [ info [ i ] ] [ argNum ] } " )
2021-03-24 09:39:43 +01:00
else :
2021-04-03 19:21:49 +02:00
if not ( info [ i ] == " NpcIDs " and argNum > 0 ) :
2021-04-08 19:42:36 +02:00
print ( f " 0x { argNum : X } was not found within { info [ i ] } constants for function { func } arg { i } , add it. " )
2021-04-22 05:19:31 +02:00
2021-04-08 19:42:36 +02:00
if ( info [ i ] == " ItemIDs " and argNum < 0 ) :
new_args . append ( f " { int ( argNum ) } " )
else :
#Print the unknowns in hex
2021-07-20 19:43:16 +02:00
new_args . append ( self . var ( argNum ) )
2021-04-29 19:09:30 +02:00
2021-03-24 09:39:43 +01:00
else :
new_args . append ( f " { arg } " )
return " , " . join ( new_args )
2021-12-23 13:16:12 +01:00
2021-03-24 18:30:25 +01:00
replace_funcs = {
2021-04-03 19:21:49 +02:00
" AddActorDecoration " : { 0 : " ActorIDs " } ,
" AddKeyItem " : { 0 : " ItemIDs " } ,
" AddGoalPos " : { 0 : " ActorIDs " } ,
" BattleCamTargetActor " : { 0 : " ActorIDs " } ,
" BindNpcAI " : { 0 : " NpcIDs " } ,
" BindNpcDefeat " : { 0 : " NpcIDs " } ,
" BindNpcIdle " : { 0 : " NpcIDs " } ,
" BindNpcInteract " : { 0 : " NpcIDs " } ,
" ContinueSpeech " : { 1 : " CustomAnim " , 2 : " CustomAnim " , 4 : " CustomMsg " } ,
" DisablePlayerInput " : { 0 : " Bool " } ,
" DisablePlayerPhysics " : { 0 : " Bool " } ,
2021-03-30 05:39:17 +02:00
" DispatchDamagePlayerEvent " : { 1 : " Events " } ,
" DispatchEvent " : { 0 : " ActorIDs " } ,
2021-03-24 18:30:25 +01:00
2021-04-03 19:21:49 +02:00
" EnableIdleScript " : { 0 : " ActorIDs " } ,
" EnableNpcShadow " : { 0 : " NpcIDs " , 1 : " Bool " } ,
2021-04-29 19:09:30 +02:00
" EndSpeech " : { 1 : " CustomAnim " , 2 : " CustomAnim " } ,
2021-07-12 14:06:00 +02:00
" EnemyDamageTarget " : { 0 : " ActorIDs " , 2 : " DamageTypes " } ,
" EnemyTestTarget " : { 0 : " ActorIDs " , 2 : " DamageTypes " } ,
2021-04-03 19:21:49 +02:00
2021-04-29 19:09:30 +02:00
" FindKeyItem " : { 0 : " ItemIDs " } ,
2021-03-30 05:39:17 +02:00
" ForceHomePos " : { 0 : " ActorIDs " } ,
2021-04-03 19:21:49 +02:00
" func_802CFE2C " : { 0 : " NpcIDs " } ,
" func_802CFD30 " : { 0 : " NpcIDs " } ,
" func_802D2520 " : { 0 : " PlayerAnims " } ,
2021-03-30 05:39:17 +02:00
" GetActorPos " : { 0 : " ActorIDs " } ,
" GetGoalPos " : { 0 : " ActorIDs " } ,
" GetItemPower " : { 0 : " ItemIDs " } ,
2021-04-03 19:21:49 +02:00
" GetLastEvent " : { 0 : " ActorIDs " } ,
" GetNpcPos " : { 0 : " NpcIDs " } ,
" HidePlayerShadow " : { 0 : " Bool " } ,
" HPBarToHome " : { 0 : " ActorIDs " } ,
" InterpNpcYaw " : { 0 : " NpcIDs " } ,
2021-03-24 09:39:43 +01:00
2021-03-30 05:39:17 +02:00
" JumpToGoal " : { 0 : " ActorIDs " } ,
2021-03-29 02:05:56 +02:00
2021-10-25 13:44:55 +02:00
" MakeEntity " : { 0 : " Hex " } ,
2021-03-30 05:39:17 +02:00
" MakeItemEntity " : { 0 : " ItemIDs " } ,
2021-04-03 19:21:49 +02:00
" ModifyColliderFlags " : { 2 : " Hex " } ,
" NpcFaceNpc " : { 0 : " NpcIDs " , 1 : " NpcIDs " } ,
" NpcFacePlayer " : { 0 : " NpcIDs " } ,
" NpcJump0 " : { 0 : " NpcIDs " } ,
" NpcJump1 " : { 0 : " NpcIDs " } ,
" NpcMoveTo " : { 0 : " NpcIDs " } ,
" PlayAmbientSounds " : { 0 : " AmbientSounds " } ,
2021-03-30 05:39:17 +02:00
" PlaySound " : { 0 : " SoundIDs " } ,
2021-04-03 19:21:49 +02:00
" PlaySoundAt " : { 0 : " SoundIDs " } ,
2021-03-30 05:39:17 +02:00
" PlaySoundAtActor " : { 0 : " ActorIDs " , 1 : " SoundIDs " } ,
2021-04-03 19:21:49 +02:00
" PlaySoundAtNpc " : { 0 : " NpcIDs " , 1 : " SoundIDs " } ,
" RemoveActorDecoration " : { 0 : " ActorIDs " } ,
" RemoveNpc " : { 0 : " NpcIDs " } ,
2021-07-12 14:06:00 +02:00
" RunToGoal " : { 0 : " ActorIDs " , 2 : " Bool " } ,
" JumpToGoal " : { 0 : " ActorIDs " , 2 : " Bool " , 3 : " Bool " , 4 : " Bool " } ,
2021-04-03 19:21:49 +02:00
" SetActorDispOffset " : { 0 : " ActorIDs " } ,
2021-03-30 05:39:17 +02:00
" SetActorJumpGravity " : { 0 : " ActorIDs " } ,
2021-04-03 19:21:49 +02:00
" SetActorRotation " : { 0 : " ActorIDs " } ,
2021-03-30 05:39:17 +02:00
" SetActorSpeed " : { 0 : " ActorIDs " } ,
" SetActorScale " : { 0 : " ActorIDs " } ,
" SetActorYaw " : { 0 : " ActorIDs " } ,
2021-04-03 19:21:49 +02:00
" SetAnimation " : { 0 : " ActorIDs " , 2 : " CustomAnim " } ,
" SetAnimationRate " : { 0 : " ActorIDs " } ,
2021-03-30 05:39:17 +02:00
" SetGoalPos " : { 0 : " ActorIDs " } ,
" SetGoalToHome " : { 0 : " ActorIDs " } ,
" SetGoalToTarget " : { 0 : " ActorIDs " } ,
" SetJumpAnimations " : { 0 : " ActorIDs " , 2 : " PlayerAnims " , 3 : " PlayerAnims " , 4 : " PlayerAnims " } ,
" SetMusicTrack " : { 1 : " SongIDs " } ,
2021-04-03 19:21:49 +02:00
" SetNpcAnimation " : { 0 : " NpcIDs " , 1 : " CustomAnim " } ,
" SetNpcAux " : { 0 : " NpcIDs " } ,
2021-04-08 19:42:36 +02:00
" SetNpcFlagBits " : { 0 : " NpcIDs " , 1 : " NpcFlags " , 2 : " Bool " } ,
2021-04-03 19:21:49 +02:00
" SetNpcJumpscale " : { 0 : " NpcIDs " } ,
" SetNpcPos " : { 0 : " NpcIDs " } ,
" SetNpcRotation " : { 0 : " NpcIDs " } ,
" SetNpcScale " : { 0 : " NpcIDs " } ,
" SetNpcSpeed " : { 0 : " NpcIDs " } ,
2021-04-29 19:09:30 +02:00
" SetNpcSprite " : { 1 : " Hex " } ,
2021-04-03 19:21:49 +02:00
" SetNpcYaw " : { 0 : " NpcIDs " } ,
" SetPlayerAnimation " : { 0 : " PlayerAnims " } ,
2021-04-08 19:42:36 +02:00
" SetSelfEnemyFlagBits " : { 0 : " NpcFlags " , 1 : " Bool " } ,
2021-04-03 19:21:49 +02:00
#"SetSelfVar" :{1:"Bool"}, # apparently this was a bool in some scripts but it passes non-0/1 values, including negatives
2021-07-12 14:06:00 +02:00
" SetTargetActor " : { 0 : " ActorIDs " , 1 : " ActorIDs " } ,
2021-04-29 19:09:30 +02:00
" ShowChoice " : { 0 : " CustomMsg " } ,
2021-04-03 19:21:49 +02:00
" ShowEmote " : { 1 : " Emotes " } ,
" ShowMessageAtScreenPos " : { 0 : " CustomMsg " } ,
2021-04-29 19:09:30 +02:00
" ShowMessageAtWorldPos " : { 0 : " CustomMsg " } ,
" SpeakToPlayer " : { 0 : " NpcIDs " , 1 : " CustomAnim " , 2 : " CustomAnim " , - 1 : " CustomMsg " } ,
" SwitchMessage " : { 0 : " CustomMsg " } ,
2021-03-24 18:30:25 +01:00
2021-07-12 14:06:00 +02:00
" UseIdleAnimation " : { 0 : " ActorIDs " , 1 : " Bool " } ,
" BindTakeTurn " : { 0 : " ActorIDs " } ,
" BindIdle " : { 0 : " ActorIDs " } ,
" BindHandleEvent " : { 0 : " ActorIDs " } ,
" SetActorIdleSpeed " : { 0 : " ActorIDs " } ,
" SetIdleAnimations " : { 0 : " ActorIDs " } ,
" SetIdleGoal " : { 0 : " ActorIDs " } ,
" IdleFlyToGoal " : { 0 : " ActorIDs " } ,
" GetStatusFlags " : { 0 : " ActorIDs " } ,
" ResetAllActorSounds " : { 0 : " ActorIDs " } ,
" FlyToGoal " : { 0 : " ActorIDs " } ,
" SetActorPos " : { 0 : " ActorIDs " } ,
" HPBarToCurrent " : { 0 : " ActorIDs " } ,
" SetActorFlagBits " : { 0 : " ActorIDs " } , # TODO: 1:"ActorFlags"
" SetPartFlags " : { 0 : " ActorIDs " } ,
" SetPartPos " : { 0 : " ActorIDs " } ,
" SetPartDispOffset " : { 0 : " ActorIDs " } ,
2021-03-24 18:30:25 +01:00
}
2021-12-23 13:16:12 +01:00
2021-04-03 19:21:49 +02:00
def replace_constants ( self , func , args ) :
2021-03-24 18:30:25 +01:00
global replace_funcs
2021-03-30 05:39:17 +02:00
2021-03-24 18:30:25 +01:00
if func in replace_funcs :
2021-04-03 19:21:49 +02:00
return fix_args ( self , func , args , replace_funcs [ func ] )
2021-03-24 18:30:25 +01:00
elif func == " PlayEffect " :
argsZ = args . split ( " , " )
if " 0x " not in argsZ [ 0 ] :
argsZ [ 0 ] = f " 0x { int ( argsZ [ 0 ] , 10 ) : X } "
args = " , " . join ( argsZ )
2021-03-24 09:39:43 +01:00
return args
2021-12-23 13:16:12 +01:00
2020-10-31 03:28:18 +01:00
class ScriptDisassembler :
2021-12-28 18:11:07 +01:00
def __init__ ( self , bytes , script_name = " script " , symbol_map = { } , romstart = 0 , INCLUDES_NEEDED = { " forward " : [ ] , " sprites " : set ( ) , " npcs " : [ ] } , INCLUDED = { " functions " : set ( ) , " includes " : set ( ) } , prelude = True , transform_symbol_name = None ) :
2020-10-31 03:28:18 +01:00
self . bytes = bytes
self . script_name = script_name
2021-10-25 13:44:55 +02:00
self . prelude = prelude
2021-03-24 09:39:43 +01:00
2021-12-28 18:11:07 +01:00
self . symbol_map = extend_symbol_map ( symbol_map , script_lib ( self . bytes . tell ( ) ) )
2021-04-03 19:21:49 +02:00
self . romstart = romstart
2021-12-28 18:11:07 +01:00
self . transform_symbol_name = transform_symbol_name
2021-04-03 19:21:49 +02:00
self . INCLUDES_NEEDED = INCLUDES_NEEDED
self . INCLUDED = INCLUDED
2020-10-31 03:28:18 +01:00
self . out = " "
self . prefix = " "
self . indent = 1
self . indent_used = False
self . done = False
2021-03-24 09:39:43 +01:00
self . start_pos = self . bytes . tell ( )
self . end_pos = 0
self . instructions = 0
2020-10-31 03:28:18 +01:00
def disassemble ( self ) :
while True :
opcode = self . read_word ( )
argc = self . read_word ( )
2020-10-19 23:58:57 +02:00
2021-04-03 19:21:49 +02:00
#print(f"Op {opcode:X}, argc {argc}")
2020-10-31 03:28:18 +01:00
if opcode > 0xFF or argc > 0xFF :
2021-12-28 18:11:07 +01:00
raise Exception ( f " script ' { self . script_name } ' is malformed (opcode { opcode : X } , argc { argc : X } ) " )
2020-10-19 23:58:57 +02:00
2020-10-31 03:28:18 +01:00
argv = [ ]
for i in range ( 0 , argc ) :
argv . append ( self . read_word ( ) )
2020-10-19 23:58:57 +02:00
2021-04-03 19:21:49 +02:00
#print(argv)
2020-10-31 03:28:18 +01:00
self . disassemble_command ( opcode , argc , argv )
2020-10-19 23:58:57 +02:00
2021-03-24 09:39:43 +01:00
self . instructions + = 1
2020-10-31 03:28:18 +01:00
if self . done :
2021-03-24 09:39:43 +01:00
self . end_pos = self . bytes . tell ( )
2020-10-31 03:28:18 +01:00
return self . prefix + self . out
2020-10-19 23:58:57 +02:00
2020-11-08 15:57:58 +01:00
def write ( self , line ) :
2020-10-31 03:28:18 +01:00
if self . indent < 0 : self . indent = 0
if self . indent > 1 : self . indent_used = True
self . out + = " " * self . indent
self . out + = line
2020-11-08 15:57:58 +01:00
def write_line ( self , line ) :
self . write ( line )
2020-10-31 03:28:18 +01:00
self . out + = " \n "
def prefix_line ( self , line ) :
self . prefix + = line
self . prefix + = " \n "
2021-10-25 13:44:55 +02:00
def var ( self , arg , prefer_hex = False , use_evt_ptr = True ) :
2020-10-31 03:28:18 +01:00
if arg in self . symbol_map :
2021-10-25 13:44:55 +02:00
s = self . symbol_map [ arg ] [ 0 ] [ 1 ]
2021-12-28 18:11:07 +01:00
return f " EVT_ADDR( { s } ) " if use_evt_ptr else s
2020-10-21 04:10:13 +02:00
2020-10-19 23:58:57 +02:00
v = arg - 2 * * 32 # convert to s32
if v > - 250000000 :
2021-12-28 18:11:07 +01:00
if v < = - 220000000 : return f " EVT_FLOAT( { round_fixed ( ( v + 230000000 ) / 1024 ) } ) "
elif v < = - 200000000 : return f " UF( { v + 210000000 } ) "
elif v < = - 180000000 : return f " UW( { v + 190000000 } ) "
elif v < = - 160000000 : return f " GSW( { v + 170000000 } ) "
elif v < = - 140000000 : return f " LSW( { v + 150000000 } ) "
elif v < = - 120000000 : return f " GSWF( { v + 130000000 } ) "
elif v < = - 100000000 : return f " LSWF( { v + 110000000 } ) "
elif v < = - 80000000 : return f " GF( { v + 90000000 } ) "
elif v < = - 60000000 : return f " LF( { v + 70000000 } ) "
elif v < = - 40000000 : return f " GW( { v + 50000000 } ) "
elif v < = - 20000000 : return f " LW( { v + 30000000 } ) "
2020-10-19 23:58:57 +02:00
if arg == 0xFFFFFFFF :
return " -1 "
2021-04-03 19:21:49 +02:00
elif ( arg & 0xFF000000 ) == 0x80000000 :
2020-10-19 23:58:57 +02:00
return f " 0x { arg : X } "
2021-04-03 19:21:49 +02:00
elif arg > = 0x80000000 :
return f " { arg - 0x100000000 } "
2021-10-25 13:44:55 +02:00
elif prefer_hex and arg > 0 :
return f " 0x { arg : X } "
2020-10-19 23:58:57 +02:00
else :
return f " { arg } "
2021-04-03 19:21:49 +02:00
def replace_star_rod_function_name ( self , name ) :
vram = int ( name . split ( " _ " , 1 ) [ 1 ] , 16 )
2021-04-08 19:42:36 +02:00
name = " N( " + name . replace ( " function " , " func " ) + f " _ { ( vram - 0x80240000 ) + self . romstart : X } " + " ) "
2021-04-03 19:21:49 +02:00
return name
2021-04-29 19:09:30 +02:00
def replace_star_rod_prefix ( self , addr , isArg = False ) :
if type ( addr ) is str :
return addr
2021-04-28 10:58:21 +02:00
if addr > 0x80000000 and addr in self . symbol_map :
2021-12-28 18:11:07 +01:00
name = find_symbol_in_overlay ( self . symbol_map , self . romstart , addr )
if self . transform_symbol_name :
name = self . transform_symbol_name ( name )
2021-04-03 19:21:49 +02:00
toReplace = True
suffix = " "
2021-10-25 13:44:55 +02:00
if False and name . startswith ( " N(func_ " ) :
2021-04-03 19:21:49 +02:00
prefix = " ApiStatus "
name = self . replace_star_rod_function_name ( name [ 2 : - 1 ] )
2021-08-22 23:50:10 +02:00
suffix = " (Evt* script, s32 isInitialCall) "
2021-04-08 19:42:36 +02:00
elif name [ 2 : - 1 ] in self . INCLUDED [ " includes " ] :
prefix = " ApiStatus "
2021-08-22 23:50:10 +02:00
suffix = " (Evt* script, s32 isInitialCall) "
2021-04-08 19:42:36 +02:00
elif name . startswith ( " N(npcAISettings_ " ) :
2021-04-03 19:21:49 +02:00
prefix = " NpcAISettings "
2021-04-08 19:42:36 +02:00
elif name . startswith ( " N(npcSettings_ " ) :
2021-04-03 19:21:49 +02:00
prefix = " NpcSettings "
2021-04-08 19:42:36 +02:00
elif name . startswith ( " N(npcGroup_ " ) :
2021-04-03 19:21:49 +02:00
prefix = " StaticNpc "
2021-04-08 19:42:36 +02:00
elif name . startswith ( " N(entryList_ " ) :
prefix = " EntryList "
elif name . startswith ( " N(npcGroupList_ " ) :
2021-04-03 19:21:49 +02:00
prefix = " NpcGroupList "
2021-04-08 19:42:36 +02:00
elif name . startswith ( " N( " ) :
2021-08-22 23:50:10 +02:00
prefix = " EvtSource "
2021-04-03 19:21:49 +02:00
else :
toReplace = False
if toReplace :
if name not in self . INCLUDED [ " functions " ] :
self . INCLUDES_NEEDED [ " forward " ] . append ( prefix + name + suffix + " ; " )
2021-04-08 19:42:36 +02:00
self . INCLUDED [ " functions " ] . add ( name )
2021-04-29 19:09:30 +02:00
return name
elif not isArg or name . startswith ( " \" " ) :
return name
else :
return str ( addr )
2021-04-03 19:21:49 +02:00
return addr
2021-04-29 19:09:30 +02:00
def addr_ref ( self , addr , isArg = False ) :
2020-10-31 03:28:18 +01:00
if addr in self . symbol_map :
2021-04-29 19:09:30 +02:00
return self . replace_star_rod_prefix ( addr , isArg )
2021-07-20 19:43:16 +02:00
return self . var ( addr ) #f"0x{addr:08X}"
2020-10-21 04:10:13 +02:00
2020-10-31 03:28:18 +01:00
def trigger ( self , trigger ) :
2021-04-03 19:21:49 +02:00
if trigger == 0x00000040 : trigger = " TRIGGER_WALL_PUSH "
if trigger == 0x00000080 : trigger = " TRIGGER_FLOOR_TOUCH "
if trigger == 0x00000100 : trigger = " TRIGGER_WALL_PRESS_A "
if trigger == 0x00000200 : trigger = " TRIGGER_FLOOR_JUMP "
if trigger == 0x00000400 : trigger = " TRIGGER_WALL_TOUCH "
if trigger == 0x00000800 : trigger = " TRIGGER_FLOOR_PRESS_A "
if trigger == 0x00001000 : trigger = " TRIGGER_WALL_HAMMER "
if trigger == 0x00010000 : trigger = " TRIGGER_GAME_FLAG_SET "
if trigger == 0x00020000 : trigger = " TRIGGER_AREA_FLAG_SET "
if trigger == 0x00040000 : trigger = " TRIGGER_CEILING_TOUCH "
if trigger == 0x00080000 : trigger = " TRIGGER_FLOOR_ABOVE "
if trigger == 0x00100000 : trigger = " TRIGGER_POINT_BOMB "
2020-11-08 20:07:10 +01:00
return f " 0x { trigger : X } " if type ( trigger ) is int else trigger
2020-10-19 23:58:57 +02:00
2020-10-31 03:28:18 +01:00
def read_word ( self ) :
return int . from_bytes ( self . bytes . read ( 4 ) , byteorder = " big " )
2020-10-19 23:58:57 +02:00
2020-10-31 03:28:18 +01:00
def disassemble_command ( self , opcode , argc , argv ) :
2020-10-19 23:58:57 +02:00
if opcode == 0x01 :
2021-10-25 13:44:55 +02:00
self . write_line ( " EVT_END " )
2020-10-31 03:28:18 +01:00
self . indent - = 1
2021-10-25 13:44:55 +02:00
if self . prelude :
2021-12-24 14:29:05 +01:00
self . prefix_line ( f " EvtSource { self . script_name } = {{ " )
2020-10-31 03:28:18 +01:00
self . write_line ( " }; " )
2020-10-19 23:58:57 +02:00
2020-10-31 03:28:18 +01:00
self . done = True
2021-10-25 13:44:55 +02:00
elif opcode == 0x02 : self . write_line ( f " EVT_RETURN " )
elif opcode == 0x03 : self . write_line ( f " EVT_LABEL( { self . var ( argv [ 0 ] ) } ) " )
elif opcode == 0x04 : self . write_line ( f " EVT_GOTO( { self . var ( argv [ 0 ] ) } ) " )
2020-10-19 23:58:57 +02:00
elif opcode == 0x05 :
2021-10-25 13:44:55 +02:00
self . write_line ( f " EVT_LOOP( { self . var ( argv [ 0 ] ) } ) " )
2020-10-31 03:28:18 +01:00
self . indent + = 1
2020-10-19 23:58:57 +02:00
elif opcode == 0x06 :
2020-10-31 03:28:18 +01:00
self . indent - = 1
2021-10-25 13:44:55 +02:00
self . write_line ( " EVT_END_LOOP " )
elif opcode == 0x07 : self . write_line ( f " EVT_BREAK_LOOP " )
elif opcode == 0x08 : self . write_line ( f " EVT_WAIT_FRAMES( { self . var ( argv [ 0 ] ) } ) " )
elif opcode == 0x09 : self . write_line ( f " EVT_WAIT_SECS( { self . var ( argv [ 0 ] ) } ) " )
2020-10-19 23:58:57 +02:00
elif opcode == 0x0A :
2021-10-25 13:44:55 +02:00
self . write_line ( f " EVT_IF_EQ( { self . var ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] ) } ) " )
2020-10-31 03:28:18 +01:00
self . indent + = 1
2020-10-19 23:58:57 +02:00
elif opcode == 0x0B :
2021-10-25 13:44:55 +02:00
self . write_line ( f " EVT_IF_NE( { self . var ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] ) } ) " )
2020-10-31 03:28:18 +01:00
self . indent + = 1
2020-10-19 23:58:57 +02:00
elif opcode == 0x0C :
2021-10-25 13:44:55 +02:00
self . write_line ( f " EVT_IF_LT( { self . var ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] ) } ) " )
2020-10-31 03:28:18 +01:00
self . indent + = 1
2020-10-19 23:58:57 +02:00
elif opcode == 0x0D :
2021-10-25 13:44:55 +02:00
self . write_line ( f " EVT_IF_GT( { self . var ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] ) } ) " )
2020-10-31 03:28:18 +01:00
self . indent + = 1
2020-10-19 23:58:57 +02:00
elif opcode == 0x0E :
2021-10-25 13:44:55 +02:00
self . write_line ( f " EVT_IF_LE( { self . var ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] ) } ) " )
2020-10-31 03:28:18 +01:00
self . indent + = 1
2020-10-19 23:58:57 +02:00
elif opcode == 0x0F :
2021-10-25 13:44:55 +02:00
self . write_line ( f " EVT_IF_GE( { self . var ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] ) } ) " )
2020-10-31 03:28:18 +01:00
self . indent + = 1
2020-10-19 23:58:57 +02:00
elif opcode == 0x10 :
2021-10-25 13:44:55 +02:00
self . write_line ( f " EVT_IF_FLAG( { self . var ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] , prefer_hex = True ) } ) " )
2020-10-31 03:28:18 +01:00
self . indent + = 1
2020-10-19 23:58:57 +02:00
elif opcode == 0x11 :
2021-10-25 13:44:55 +02:00
self . write_line ( f " EVT_IF_NOT_FLAG( { self . var ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] , prefer_hex = True ) } ) " )
2020-10-31 03:28:18 +01:00
self . indent + = 1
elif opcode == 0x12 :
self . indent - = 1
2021-10-25 13:44:55 +02:00
self . write_line ( f " EVT_ELSE " )
2020-10-31 03:28:18 +01:00
self . indent + = 1
2020-10-19 23:58:57 +02:00
elif opcode == 0x13 :
2020-10-31 03:28:18 +01:00
self . indent - = 1
2021-10-25 13:44:55 +02:00
self . write_line ( f " EVT_END_IF " )
2020-10-19 23:58:57 +02:00
elif opcode == 0x14 :
2021-10-25 13:44:55 +02:00
self . write_line ( f " EVT_SWITCH( { self . var ( argv [ 0 ] ) } ) " )
2020-10-31 03:28:18 +01:00
self . indent + = 2
2020-10-19 23:58:57 +02:00
elif opcode == 0x15 :
2021-10-25 13:44:55 +02:00
self . write_line ( f " EVT_SWITCH_CONST(0x { argv [ 0 ] : X } ) " )
2020-10-31 03:28:18 +01:00
self . indent + = 2
2020-10-19 23:58:57 +02:00
elif opcode == 0x16 :
2020-10-31 03:28:18 +01:00
self . indent - = 1
2021-10-25 13:44:55 +02:00
self . write_line ( f " EVT_CASE_EQ( { self . var ( argv [ 0 ] ) } ) " )
2020-10-31 03:28:18 +01:00
self . indent + = 1
2020-10-19 23:58:57 +02:00
elif opcode == 0x17 :
2020-10-31 03:28:18 +01:00
self . indent - = 1
2021-10-25 13:44:55 +02:00
self . write_line ( f " EVT_CASE_NE( { self . var ( argv [ 0 ] ) } ) " )
2020-10-31 03:28:18 +01:00
self . indent + = 1
2020-10-19 23:58:57 +02:00
elif opcode == 0x18 :
2020-10-31 03:28:18 +01:00
self . indent - = 1
2021-10-25 13:44:55 +02:00
self . write_line ( f " EVT_CASE_LT( { self . var ( argv [ 0 ] ) } ) " )
2020-10-31 03:28:18 +01:00
self . indent + = 1
2020-10-19 23:58:57 +02:00
elif opcode == 0x19 :
2020-10-31 03:28:18 +01:00
self . indent - = 1
2021-10-25 13:44:55 +02:00
self . write_line ( f " EVT_CASE_GT( { self . var ( argv [ 0 ] ) } ) " )
2020-10-31 03:28:18 +01:00
self . indent + = 1
2020-10-19 23:58:57 +02:00
elif opcode == 0x1A :
2020-10-31 03:28:18 +01:00
self . indent - = 1
2021-10-25 13:44:55 +02:00
self . write_line ( f " EVT_CASE_LE( { self . var ( argv [ 0 ] ) } ) " )
2020-10-31 03:28:18 +01:00
self . indent + = 1
2020-10-19 23:58:57 +02:00
elif opcode == 0x1B :
2020-10-31 03:28:18 +01:00
self . indent - = 1
2021-10-25 13:44:55 +02:00
self . write_line ( f " EVT_CASE_GE( { self . var ( argv [ 0 ] ) } ) " )
2020-10-31 03:28:18 +01:00
self . indent + = 1
2020-10-19 23:58:57 +02:00
elif opcode == 0x1C :
2020-10-31 03:28:18 +01:00
self . indent - = 1
2021-10-25 13:44:55 +02:00
self . write_line ( f " EVT_CASE_DEFAULT " )
2020-10-31 03:28:18 +01:00
self . indent + = 1
2020-10-19 23:58:57 +02:00
elif opcode == 0x1D :
2020-10-31 03:28:18 +01:00
self . indent - = 1
2021-10-25 13:44:55 +02:00
self . write_line ( f " EVT_CASE_OR_EQ( { self . var ( argv [ 0 ] ) } ) " )
2020-11-08 20:07:10 +01:00
self . indent + = 1
elif opcode == 0x1E :
self . indent - = 1
2021-10-25 13:44:55 +02:00
self . write_line ( f " EVT_CASE_AND_EQ( { self . var ( argv [ 0 ] ) } ) " )
2020-10-31 03:28:18 +01:00
self . indent + = 1
2020-10-19 23:58:57 +02:00
elif opcode == 0x1F :
2020-10-31 03:28:18 +01:00
self . indent - = 1
2021-10-25 13:44:55 +02:00
self . write_line ( f " EVT_CASE_FLAG( { self . var ( argv [ 0 ] ) } ) " )
2020-10-31 03:28:18 +01:00
self . indent + = 1
2020-10-19 23:58:57 +02:00
elif opcode == 0x20 :
2020-10-31 03:28:18 +01:00
self . indent - = 1
2021-10-25 13:44:55 +02:00
self . write_line ( f " EVT_END_CASE_GROUP " )
2020-10-31 03:28:18 +01:00
self . indent + = 1
2020-10-19 23:58:57 +02:00
elif opcode == 0x21 :
2020-10-31 03:28:18 +01:00
self . indent - = 1
2021-10-25 13:44:55 +02:00
self . write_line ( f " EVT_CASE_RANGE( { self . var ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] ) } ) " )
2020-10-31 03:28:18 +01:00
self . indent + = 1
2021-10-25 13:44:55 +02:00
elif opcode == 0x22 : self . write_line ( f " EVT_BREAK_SWITCH " )
2020-10-19 23:58:57 +02:00
elif opcode == 0x23 :
2020-10-31 03:28:18 +01:00
self . indent - = 2
2021-10-25 13:44:55 +02:00
self . write_line ( f " EVT_END_SWITCH " )
elif opcode == 0x24 : self . write_line ( f " EVT_SET( { self . var ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] ) } ) " )
elif opcode == 0x25 :
argNum = argv [ 1 ]
sprite = ( argNum & 0xFF0000 ) >> 16
palette = ( argNum & 0xFF00 ) >> 8
anim = ( argNum & 0xFF ) >> 0
if sprite > 0 :
value = make_anim_macro ( self , sprite , palette , anim )
else :
value = f " 0x { argNum : 08X } "
self . write_line ( f " EVT_SET_CONST( { self . var ( argv [ 0 ] ) } , { value } ) " )
elif opcode == 0x26 : self . write_line ( f " EVT_SETF( { self . var ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] ) } ) " )
elif opcode == 0x27 : self . write_line ( f " EVT_ADD( { self . var ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] ) } ) " )
elif opcode == 0x28 : self . write_line ( f " EVT_SUB( { self . var ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] ) } ) " )
elif opcode == 0x29 : self . write_line ( f " EVT_MUL( { self . var ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] ) } ) " )
elif opcode == 0x2A : self . write_line ( f " EVT_DIV( { self . var ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] ) } ) " )
elif opcode == 0x2B : self . write_line ( f " EVT_MOD( { self . var ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] ) } ) " )
elif opcode == 0x2C : self . write_line ( f " EVT_ADDF( { self . var ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] ) } ) " )
elif opcode == 0x2D : self . write_line ( f " EVT_SUBF( { self . var ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] ) } ) " )
elif opcode == 0x2E : self . write_line ( f " EVT_MULF( { self . var ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] ) } ) " )
elif opcode == 0x2F : self . write_line ( f " EVT_DIVF( { self . var ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] ) } ) " )
elif opcode == 0x30 : self . write_line ( f " EVT_USE_BUF( { self . var ( argv [ 0 ] ) } ) " )
elif opcode == 0x31 or opcode == 0x32 or opcode == 0x33 or opcode == 0x34 :
args = [ * map ( self . var , argv ) ]
self . write_line ( f " EVT_BUF_READ { opcode - 0x30 } ( { ' , ' . join ( args ) } ) " )
2020-11-08 20:07:10 +01:00
elif opcode == 0x35 :
2021-10-25 13:44:55 +02:00
args = [ * map ( self . var , argv ) ]
self . write_line ( f " EVT_BUF_PEEK( { ' , ' . join ( args ) } ) " )
elif opcode == 0x36 : self . write_line ( f " EVT_USE_FBUF( { self . var ( argv [ 0 ] ) } ) " )
elif opcode == 0x37 or opcode == 0x38 or opcode == 0x39 or opcode == 0x3A :
args = [ * map ( self . var , argv ) ]
self . write_line ( f " EVT_FBUF_READ { opcode - 0x36 } ( { ' , ' . join ( args ) } ) " )
2020-11-08 20:07:10 +01:00
elif opcode == 0x3B :
2021-10-25 13:44:55 +02:00
args = [ * map ( self . var , argv ) ]
self . write_line ( f " EVT_FBUF_PEEK( { ' , ' . join ( args ) } ) " )
elif opcode == 0x3C : self . write_line ( f " EVT_USE_ARRAY( { self . var ( argv [ 0 ] ) } ) " )
elif opcode == 0x3D : self . write_line ( f " EVT_USE_FLAG_ARRAY( { self . var ( argv [ 0 ] ) } ) " )
elif opcode == 0x3E : self . write_line ( f " EVT_MALLOC_ARRAY( { self . var ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] ) } ) " )
elif opcode == 0x3F : self . write_line ( f " EVT_BITWISE_AND( { self . var ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] ) } ) " )
elif opcode == 0x40 : self . write_line ( f " EVT_BITWISE_OR( { self . var ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] ) } ) " )
elif opcode == 0x41 : self . write_line ( f " EVT_BITWISE_AND_CONST( { self . var ( argv [ 0 ] ) } , 0x { argv [ 1 ] : X } ) " )
elif opcode == 0x42 : self . write_line ( f " EVT_BITWISE_OR_CONST( { self . var ( argv [ 0 ] ) } , 0x { argv [ 1 ] : X } ) " )
2020-10-19 23:58:57 +02:00
elif opcode == 0x43 :
2021-10-25 13:44:55 +02:00
func = self . addr_ref ( argv [ 0 ] )
args = [ self . var ( a , use_evt_ptr = True ) for a in argv [ 1 : ] ]
2021-12-24 14:29:05 +01:00
args_str = ' , ' . join ( args )
2021-10-25 13:44:55 +02:00
args_str = replace_constants ( self , func , args_str )
if func . startswith ( " evt_ " ) :
# use func-specific macro
self . write_line ( f " { func } ( { args_str } ) " )
2021-12-24 14:29:05 +01:00
# Since the map ascii for map transitions is global, and several of them share the same RAM address,
# or ar not migrated, we have to create a placeholder
elif func == " GotoMap " or func == " GotoMapSpecial " :
args = [ self . var ( a , use_evt_ptr = True ) for a in argv [ 2 : ] ]
args_str = ' , ' . join ( args )
self . write_line ( f " EVT_CALL( { func } , EVT_PTR(UNK_STR_ { argv [ 1 ] : X } ), { args_str } ) " )
2021-10-25 13:44:55 +02:00
elif args_str :
self . write_line ( f " EVT_CALL( { func } , { args_str } ) " )
else :
self . write_line ( f " EVT_CALL( { func } ) " ) # no args
elif opcode == 0x44 : self . write_line ( f " EVT_EXEC( { self . addr_ref ( argv [ 0 ] ) } ) " )
elif opcode == 0x45 : self . write_line ( f " EVT_EXEC_GET_TID( { self . addr_ref ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] ) } ) " )
elif opcode == 0x46 : self . write_line ( f " EVT_EXEC_WAIT( { self . addr_ref ( argv [ 0 ] ) } ) " )
2020-10-19 23:58:57 +02:00
elif opcode == 0x47 :
2021-10-25 13:44:55 +02:00
args = [ self . addr_ref ( argv [ 0 ] ) , self . trigger ( argv [ 1 ] ) , self . collider_id ( argv [ 2 ] ) , * map ( self . var , argv [ 3 : ] ) ]
self . write_line ( f " EVT_BIND_TRIGGER( { ' , ' . join ( args ) } ) " )
elif opcode == 0x48 : self . write_line ( f " EVT_UNBIND " )
elif opcode == 0x49 : self . write_line ( f " EVT_KILL_THREAD( { self . var ( argv [ 0 ] ) } ) " )
elif opcode == 0x4A : self . write_line ( f " EVT_JUMP( { self . var ( argv [ 0 ] ) } ) " )
elif opcode == 0x4B : self . write_line ( f " EVT_SET_PRIORITY( { self . var ( argv [ 0 ] ) } ) " )
elif opcode == 0x4C : self . write_line ( f " EVT_SET_TIMESCALE( { self . var ( argv [ 0 ] ) } ) " )
elif opcode == 0x4D : self . write_line ( f " EVT_SET_GROUP( { self . var ( argv [ 0 ] ) } ) " )
2020-10-19 23:58:57 +02:00
elif opcode == 0x4E :
2021-10-25 13:44:55 +02:00
args = [ self . addr_ref ( argv [ 0 ] ) , self . trigger ( argv [ 1 ] ) , self . collider_id ( argv [ 2 ] ) , * map ( self . var , argv [ 3 : ] ) ]
self . write_line ( f " EVT_BIND_PADLOCK( { ' , ' . join ( args ) } ) " )
elif opcode == 0x4F : self . write_line ( f " EVT_SUSPEND_GROUP( { self . var ( argv [ 0 ] ) } ) " )
elif opcode == 0x50 : self . write_line ( f " EVT_RESUME_GROUP( { self . var ( argv [ 0 ] ) } ) " )
elif opcode == 0x51 : self . write_line ( f " EVT_SUSPEND_OTHERS( { self . var ( argv [ 0 ] ) } ) " )
elif opcode == 0x52 : self . write_line ( f " EVT_RESUME_OTHERS( { self . var ( argv [ 0 ] ) } ) " )
elif opcode == 0x53 : self . write_line ( f " EVT_SUSPEND_THREAD( { self . var ( argv [ 0 ] ) } ) " )
elif opcode == 0x54 : self . write_line ( f " EVT_RESUME_THREAD( { self . var ( argv [ 0 ] ) } ) " )
elif opcode == 0x55 : self . write_line ( f " EVT_IS_THREAD_RUNNING( { self . var ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] ) } ) " )
2020-10-19 23:58:57 +02:00
elif opcode == 0x56 :
2021-10-25 13:44:55 +02:00
self . write_line ( " EVT_THREAD " )
2020-10-31 03:28:18 +01:00
self . indent + = 1
2020-10-19 23:58:57 +02:00
elif opcode == 0x57 :
2020-10-31 03:28:18 +01:00
self . indent - = 1
2021-10-25 13:44:55 +02:00
self . write_line ( " EVT_END_THREAD " )
2020-10-19 23:58:57 +02:00
elif opcode == 0x58 :
2021-10-25 13:44:55 +02:00
self . write_line ( " EVT_CHILD_THREAD " )
2020-10-31 03:28:18 +01:00
self . indent + = 1
2020-10-19 23:58:57 +02:00
elif opcode == 0x59 :
2020-10-31 03:28:18 +01:00
self . indent - = 1
2021-10-25 13:44:55 +02:00
self . write_line ( " EVT_END_CHILD_THREAD " )
2020-10-19 23:58:57 +02:00
else :
# unknown opcode
argv_str = " "
for arg in argv :
argv_str + = " , "
argv_str + = f " 0x { arg : X } "
2021-10-25 13:44:55 +02:00
self . write_line ( f " 0x { opcode : 02X } { argv_str } ), " )
def collider_id ( self , arg ) :
if arg > = 0x4000 and arg < = 0x5000 :
return f " EVT_ENTITY_INDEX( { arg - 0x4000 } ) "
else :
return self . var ( arg )
2020-10-31 03:28:18 +01:00
2021-12-23 13:16:12 +01:00
2020-10-31 03:28:18 +01:00
class UnsupportedScript ( Exception ) :
pass
2021-03-30 05:39:17 +02:00
2020-10-19 23:58:57 +02:00
if __name__ == " __main__ " :
2021-03-29 02:05:56 +02:00
import argparse
parser = argparse . ArgumentParser ( )
parser . add_argument ( " file " , type = str , help = " File to dissassemble from " )
2021-12-16 01:27:26 +01:00
parser . add_argument ( " offset " , help = " Offset to start dissassembling from " )
2021-03-30 05:39:17 +02:00
parser . add_argument ( " -end " , " -e " , " --e " , type = lambda x : int ( x , 16 ) , default = 0 , dest = " end " , required = False , help = " End offset to stop dissassembling from. \n Only used as a way to find valid scripts. " )
2021-04-03 19:21:49 +02:00
parser . add_argument ( " -vram " , " -v " , " --v " , type = lambda x : int ( x , 16 ) , default = 0 , dest = " vram " , required = False , help = " VRAM start will be tracked and used for the script output name " )
2021-04-29 19:09:30 +02:00
parser . add_argument ( " -si " , " --si " , action = " store_true " , default = False , dest = " si " , required = False , help = " Force si script output " )
2021-03-29 02:05:56 +02:00
args = parser . parse_args ( )
2021-04-03 19:21:49 +02:00
vram_base = args . vram
2021-03-29 02:05:56 +02:00
get_constants ( )
2021-04-29 19:09:30 +02:00
INCLUDED = { }
INCLUDED [ " functions " ] = set ( )
INCLUDED [ " includes " ] = set ( )
INCLUDES_NEEDED = { }
INCLUDES_NEEDED [ " include " ] = [ ]
INCLUDES_NEEDED [ " forward " ] = [ ]
INCLUDES_NEEDED [ " npcs " ] = { }
INCLUDES_NEEDED [ " sprites " ] = set ( )
2021-12-16 01:27:26 +01:00
try :
offset = int ( args . offset , 0 )
except ValueError :
info = sym_info . search_symbol ( args . offset )
if info is None :
print ( f " { args . offset } is not a valid symbol name " )
exit ( 1 )
offset = info [ 0 ]
if args . end > offset :
2021-03-30 05:39:17 +02:00
# Search the given memory range and report scripts
2021-03-29 02:05:56 +02:00
with open ( args . file , " rb " ) as f :
2021-04-03 19:21:49 +02:00
gap = False
first_print = False
2021-04-29 19:09:30 +02:00
2021-12-16 01:27:26 +01:00
while offset < args . end :
f . seek ( offset )
2021-03-29 02:05:56 +02:00
2021-12-24 14:29:05 +01:00
script = ScriptDisassembler ( f , args . offset , { } , 0x978DE0 , INCLUDES_NEEDED , INCLUDED )
2021-03-29 02:05:56 +02:00
try :
script_text = script . disassemble ( )
2021-03-30 05:39:17 +02:00
2021-10-25 13:44:55 +02:00
if script . instructions > 1 and " _EVT_CMD " not in script_text :
2021-04-03 19:21:49 +02:00
if gap and first_print :
potential_struct_sizes = { " StaticNpc " : 0x1F0 , " NpcAISettings " : 0x30 , " NpcSettings " : 0x2C , " NpcGroupList " : 0xC }
2021-12-16 01:27:26 +01:00
gap_size = offset - gap_start
2021-04-03 19:21:49 +02:00
potential_struct = " Unknown data "
potential_count = 1
for k , v in potential_struct_sizes . items ( ) :
if gap_size % v == 0 :
potential_struct = k
potential_count = gap_size / / v
2021-12-16 01:27:26 +01:00
print ( f " ========== 0x { gap_size : X } byte gap ( { potential_count } { potential_struct } ?) 0x { gap_start : X } - 0x { offset : X } ========== " )
2021-04-03 19:21:49 +02:00
print ( )
gap = False
2021-08-22 23:50:10 +02:00
#print(f"EvtSource read from 0x{script.start_pos:X} to 0x{script.end_pos:X} "
2021-04-03 19:21:49 +02:00
# f"(0x{script.end_pos - script.start_pos:X} bytes, {script.instructions} instructions)")
#print()
vram = f " { args . vram : X } _ " if vram_base > 0 else f " "
2021-12-16 01:27:26 +01:00
script_text = script_text . replace ( " EvtSource script = SCRIPT( { " , f " EvtSource N(D_ { vram } { offset : X } ) = " + " SCRIPT( { " )
2021-03-30 05:39:17 +02:00
print ( script_text , end = " " )
print ( )
2021-12-16 01:27:26 +01:00
#print(f"Valid script found at 0x{offset:X}")
args . vram + = script . end_pos - offset
offset = script . end_pos
2021-04-03 19:21:49 +02:00
first_print = True
2021-03-29 02:05:56 +02:00
else :
2021-04-03 19:21:49 +02:00
if not gap :
2021-12-16 01:27:26 +01:00
gap_start = offset
2021-04-03 19:21:49 +02:00
gap = True
2021-12-16 01:27:26 +01:00
offset + = 4
2021-04-03 19:21:49 +02:00
args . vram + = 4
2021-03-29 02:05:56 +02:00
except Exception :
2021-04-03 19:21:49 +02:00
if not gap :
2021-12-16 01:27:26 +01:00
gap_start = offset
2021-04-03 19:21:49 +02:00
gap = True
2021-12-16 01:27:26 +01:00
offset + = 4
2021-04-03 19:21:49 +02:00
args . vram + = 4
2021-03-29 02:05:56 +02:00
else :
with open ( args . file , " rb " ) as f :
2021-04-03 19:21:49 +02:00
2021-12-16 01:27:26 +01:00
f . seek ( offset )
2020-10-19 23:58:57 +02:00
2021-12-24 14:29:05 +01:00
script = ScriptDisassembler ( f , args . offset , { } , 0x978DE0 , INCLUDES_NEEDED , INCLUDED )
2020-10-19 23:58:57 +02:00
2021-04-29 19:09:30 +02:00
if args . si :
2021-12-24 14:29:05 +01:00
print ( ScriptDisassembler ( f , args . offset , { } , 0x978DE0 , INCLUDES_NEEDED , INCLUDED ) . disassemble ( ) , end = " " )
2021-04-29 19:09:30 +02:00
else :
try :
script_text = script . disassemble ( )
2020-10-31 03:28:18 +01:00
2021-08-22 23:50:10 +02:00
print ( f " EvtSource read from 0x { script . start_pos : X } to 0x { script . end_pos : X } "
2021-04-29 19:09:30 +02:00
f " (0x { script . end_pos - script . start_pos : X } bytes, { script . instructions } instructions) " )
print ( )
print ( script_text , end = " " )
except UnsupportedScript :
2021-12-16 01:27:26 +01:00
f . seek ( offset )
2021-04-29 19:09:30 +02:00
print ( ScriptDisassembler ( f ) . disassemble ( ) , end = " " )