2020-10-19 23:58:57 +02:00
#! /usr/bin/python3
import sys
2021-03-24 09:39:43 +01:00
from pathlib import Path
2020-10-19 23:58:57 +02: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 ] )
# Sort the symbols for each vram address by the difference
# 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 ] )
2020-10-31 03:28:18 +01:00
return _script_lib
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
valid_enums = { " StoryProgress " , " ItemIDs " , " PlayerAnims " , " ActorIDs " , " Events " , " SoundIDs " , " SongIDs " , " Locations " }
2021-03-24 18:30:25 +01:00
for enum in valid_enums :
2021-03-30 05:39:17 +02:00
CONSTANTS [ enum ] = { }
[ SAVE_VARS . add ( x ) for x in [ " WORLD_LOCATION " , " 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-03-29 02:05:56 +02:00
# define stuff
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-03-29 02:05:56 +02:00
last_num = 0
i + = 1
while " } " not in enums [ i ] :
if not enums [ i ] :
i + = 1
continue
name = enums [ i ] . strip ( )
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 )
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-03-24 09:39:43 +01:00
return
def fix_args ( args , info ) :
2021-03-30 05:39:17 +02:00
global CONSTANTS
2021-03-24 09:39:43 +01:00
new_args = [ ]
for i , arg in enumerate ( args . split ( " , " ) ) :
if i in info :
if " 0x " in arg :
argNum = int ( arg , 16 )
else :
argNum = int ( arg , 10 )
2021-03-24 18:30:25 +01:00
2021-03-30 05:39:17 +02:00
if argNum in CONSTANTS [ info [ i ] ] :
new_args . append ( f " { CONSTANTS [ info [ i ] ] [ argNum ] } " )
2021-03-24 09:39:43 +01:00
else :
2021-03-30 05:39:17 +02:00
print ( f " { argNum : X } was not found within { info [ i ] } CONSTANTS, add it. " )
if info [ i ] == " SoundIDs " :
2021-03-24 18:30:25 +01:00
# Ethan wanted sound IDs in hex instead, so convert it back
if " 0x " not in arg :
argNum = int ( arg , 10 )
arg = f " 0x { argNum : X } "
2021-03-24 09:39:43 +01:00
new_args . append ( f " { arg } " )
else :
new_args . append ( f " { arg } " )
return " , " . join ( new_args )
2021-03-24 18:30:25 +01:00
replace_funcs = {
2021-03-30 05:39:17 +02:00
" DispatchDamagePlayerEvent " : { 1 : " Events " } ,
" DispatchEvent " : { 0 : " ActorIDs " } ,
2021-03-24 18:30:25 +01:00
2021-03-30 05:39:17 +02:00
" ForceHomePos " : { 0 : " ActorIDs " } ,
2021-03-24 18:30:25 +01:00
2021-03-30 05:39:17 +02:00
" GetActorPos " : { 0 : " ActorIDs " } ,
" GetGoalPos " : { 0 : " ActorIDs " } ,
" GetItemPower " : { 0 : " ItemIDs " } ,
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-03-30 05:39:17 +02:00
" MakeEntity " : { 5 : " ItemIDs " } ,
" MakeItemEntity " : { 0 : " ItemIDs " } ,
2021-03-24 18:30:25 +01:00
2021-03-30 05:39:17 +02:00
" PlaySound " : { 0 : " SoundIDs " } ,
" PlaySoundAtActor " : { 0 : " ActorIDs " , 1 : " SoundIDs " } ,
2021-03-24 18:30:25 +01:00
2021-03-30 05:39:17 +02:00
" SetActorJumpGravity " : { 0 : " ActorIDs " } ,
" SetActorSpeed " : { 0 : " ActorIDs " } ,
" SetActorScale " : { 0 : " ActorIDs " } ,
" SetActorYaw " : { 0 : " ActorIDs " } ,
" SetAnimation " : { 0 : " ActorIDs " , 2 : " PlayerAnims " } ,
" SetGoalPos " : { 0 : " ActorIDs " } ,
" SetGoalToHome " : { 0 : " ActorIDs " } ,
" SetGoalToTarget " : { 0 : " ActorIDs " } ,
" SetJumpAnimations " : { 0 : " ActorIDs " , 2 : " PlayerAnims " , 3 : " PlayerAnims " , 4 : " PlayerAnims " } ,
" SetMusicTrack " : { 1 : " SongIDs " } ,
" SetTargetActor " : { 0 : " ActorIDs " } ,
2021-03-24 18:30:25 +01:00
2021-03-30 05:39:17 +02:00
" UseIdleAnimation " : { 0 : " ActorIDs " } ,
2021-03-24 18:30:25 +01:00
}
def replace_constants ( func , args ) :
global replace_funcs
2021-03-30 05:39:17 +02:00
2021-03-24 18:30:25 +01:00
if func in replace_funcs :
return fix_args ( args , replace_funcs [ func ] )
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
2020-10-31 03:28:18 +01:00
class ScriptDisassembler :
def __init__ ( self , bytes , script_name = " script " , symbol_map = { } ) :
self . bytes = bytes
self . script_name = script_name
2021-03-24 09:39:43 +01:00
self . symbol_map = { * * script_lib ( self . bytes . tell ( ) ) , * * symbol_map }
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
2020-10-31 03:28:18 +01:00
if opcode > 0xFF or argc > 0xFF :
2021-02-03 21:04:37 +01:00
raise Exception ( f " script ' { self . script_name } ' is malformed " )
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
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 "
def var ( self , arg ) :
if arg in self . symbol_map :
2021-03-24 09:39:43 +01:00
return self . symbol_map [ arg ] [ 0 ] [ 1 ]
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 :
2020-10-31 03:28:18 +01:00
if v < = - 220000000 : return f " SI_FIXED( { ( v + 230000000 ) / 1024 } ) "
2020-10-19 23:58:57 +02:00
elif v < = - 200000000 : return f " SI_ARRAY_FLAG( { v + 210000000 } ) "
elif v < = - 180000000 : return f " SI_ARRAY( { v + 190000000 } ) "
elif v < = - 160000000 : return f " SI_SAVE_VAR( { v + 170000000 } ) "
elif v < = - 140000000 : return f " SI_AREA_VAR( { v + 150000000 } ) "
elif v < = - 120000000 : return f " SI_SAVE_FLAG( { v + 130000000 } ) "
elif v < = - 100000000 : return f " SI_AREA_FLAG( { v + 110000000 } ) "
elif v < = - 80000000 : return f " SI_MAP_FLAG( { v + 90000000 } ) "
elif v < = - 60000000 : return f " SI_FLAG( { v + 70000000 } ) "
elif v < = - 40000000 : return f " SI_MAP_VAR( { v + 50000000 } ) "
elif v < = - 20000000 : return f " SI_VAR( { v + 30000000 } ) "
if arg == 0xFFFFFFFF :
return " -1 "
elif ( ( arg & 0xFF000000 ) == 0x80000000 ) or arg > 10000 :
return f " 0x { arg : X } "
else :
return f " { arg } "
2020-10-31 03:28:18 +01:00
def addr_ref ( self , addr ) :
if addr in self . symbol_map :
2021-03-24 09:39:43 +01:00
return self . symbol_map [ addr ] [ 0 ] [ 1 ]
return f " 0x { addr : 08X } "
2020-10-21 04:10:13 +02:00
2020-10-31 03:28:18 +01:00
def trigger ( self , trigger ) :
2020-10-19 23:58:57 +02:00
if trigger == 0x00000080 : trigger = " TriggerFlag_FLOOR_TOUCH "
if trigger == 0x00800000 : trigger = " TriggerFlag_FLOOR_ABOVE "
if trigger == 0x00000800 : trigger = " TriggerFlag_FLOOR_INTERACT "
if trigger == 0x00000200 : trigger = " TriggerFlag_FLOOR_JUMP "
if trigger == 0x00000400 : trigger = " TriggerFlag_WALL_TOUCH "
if trigger == 0x00000040 : trigger = " TriggerFlag_WALL_PUSH "
if trigger == 0x00000100 : trigger = " TriggerFlag_WALL_INTERACT "
if trigger == 0x00001000 : trigger = " TriggerFlag_WALL_HAMMER "
if trigger == 0x00040000 : trigger = " TriggerFlag_CEILING_TOUCH "
if trigger == 0x00010000 : trigger = " TriggerFlag_SAVE_FLAG_SET "
if trigger == 0x00020000 : trigger = " TriggerFlag_AREA_FLAG_SET "
if trigger == 0x00100000 : trigger = " TriggerFlag_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 :
2020-11-08 20:07:10 +01:00
self . write_line ( " SI_CMD(ScriptOpcode_END) " )
2020-10-31 03:28:18 +01:00
self . indent - = 1
if self . indent_used :
self . prefix_line ( " // *INDENT-OFF* " )
self . prefix_line ( f " Script { self . script_name } = {{ " )
self . write_line ( " }; " )
self . write_line ( " // *INDENT-ON* " )
2020-10-19 23:58:57 +02:00
else :
2020-10-31 03:28:18 +01:00
self . prefix_line ( f " Script { self . script_name } = {{ " )
self . write_line ( " }; " )
2020-10-19 23:58:57 +02:00
2020-10-31 03:28:18 +01:00
self . done = True
2020-11-08 20:07:10 +01:00
elif opcode == 0x02 : self . write_line ( f " SI_CMD(ScriptOpcode_RETURN), " )
elif opcode == 0x03 : self . write_line ( f " SI_CMD(ScriptOpcode_LABEL, { self . var ( argv [ 0 ] ) } ), " )
elif opcode == 0x04 : self . write_line ( f " SI_CMD(ScriptOpcode_GOTO, { self . var ( argv [ 0 ] ) } ), " )
2020-10-19 23:58:57 +02:00
elif opcode == 0x05 :
2020-11-08 20:07:10 +01:00
self . write_line ( f " SI_CMD(ScriptOpcode_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
2020-11-08 20:07:10 +01:00
self . write_line ( " SI_CMD(ScriptOpcode_END_LOOP), " )
elif opcode == 0x07 : self . write_line ( f " SI_CMD(ScriptOpcode_BREAK_LOOP), " )
elif opcode == 0x08 : self . write_line ( f " SI_CMD(ScriptOpcode_SLEEP_FRAMES, { self . var ( argv [ 0 ] ) } ), " )
elif opcode == 0x09 : self . write_line ( f " SI_CMD(ScriptOpcode_SLEEP_SECS, { self . var ( argv [ 0 ] ) } ), " )
2020-10-19 23:58:57 +02:00
elif opcode == 0x0A :
2020-11-08 20:07:10 +01:00
self . write_line ( f " SI_CMD(ScriptOpcode_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 :
2020-11-08 20:07:10 +01:00
self . write_line ( f " SI_CMD(ScriptOpcode_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 :
2020-11-08 20:07:10 +01:00
self . write_line ( f " SI_CMD(ScriptOpcode_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 :
2020-11-08 20:07:10 +01:00
self . write_line ( f " SI_CMD(ScriptOpcode_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 :
2020-11-08 20:07:10 +01:00
self . write_line ( f " SI_CMD(ScriptOpcode_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 :
2020-11-08 20:07:10 +01:00
self . write_line ( f " SI_CMD(ScriptOpcode_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 :
2020-11-08 20:07:10 +01:00
self . write_line ( f " SI_CMD(ScriptOpcode_IF_FLAG, { 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 == 0x11 :
2020-11-08 20:07:10 +01:00
self . write_line ( f " SI_CMD(ScriptOpcode_IF_NOT_FLAG, ( { self . var ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] ) } ), " )
2020-10-31 03:28:18 +01:00
self . indent + = 1
elif opcode == 0x12 :
self . indent - = 1
2020-11-08 20:07:10 +01:00
self . write_line ( f " SI_CMD(ScriptOpcode_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
2020-11-08 20:07:10 +01:00
self . write_line ( f " SI_CMD(ScriptOpcode_END_IF), " )
2020-10-19 23:58:57 +02:00
elif opcode == 0x14 :
2020-11-08 20:07:10 +01:00
self . write_line ( f " SI_CMD(ScriptOpcode_MATCH, { 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 :
2020-11-08 20:07:10 +01:00
self . write_line ( f " SI_CMD(ScriptOpcode_MATCH_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
2020-11-08 20:07:10 +01:00
self . write_line ( f " SI_CMD(ScriptOpcode_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
2020-11-08 20:07:10 +01:00
self . write_line ( f " SI_CMD(ScriptOpcode_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
2020-11-08 20:07:10 +01:00
self . write_line ( f " SI_CMD(ScriptOpcode_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
2020-11-08 20:07:10 +01:00
self . write_line ( f " SI_CMD(ScriptOpcode_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
2020-11-08 20:07:10 +01:00
self . write_line ( f " SI_CMD(ScriptOpcode_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
2020-11-08 20:07:10 +01:00
self . write_line ( f " SI_CMD(ScriptOpcode_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
2020-11-08 20:07:10 +01:00
self . write_line ( f " SI_CMD(ScriptOpcode_CASE_ELSE), " )
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
2020-11-08 20:20:09 +01:00
self . write_line ( f " SI_CMD(ScriptOpcode_CASE_MULTI_OR_EQ, { self . var ( argv [ 0 ] ) } ), " )
2020-11-08 20:07:10 +01:00
self . indent + = 1
elif opcode == 0x1E :
self . indent - = 1
2020-11-08 20:20:09 +01:00
self . write_line ( f " SI_CMD(ScriptOpcode_CASE_MULTI_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
2020-11-08 20:07:10 +01:00
self . write_line ( f " SI_CMD(ScriptOpcode_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
2020-11-08 20:07:10 +01:00
self . write_line ( f " SI_CMD(ScriptOpcode_END_CASE_MULTI), " )
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
2020-11-08 20:07:10 +01:00
self . write_line ( f " SI_CMD(ScriptOpcode_CASE_RANGE, { self . var ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] ) } ), " )
2020-10-31 03:28:18 +01:00
self . indent + = 1
2020-11-08 20:07:10 +01:00
elif opcode == 0x22 : self . write_line ( f " SI_CMD(ScriptOpcode_BREAK_CASE), " )
2020-10-19 23:58:57 +02:00
elif opcode == 0x23 :
2020-10-31 03:28:18 +01:00
self . indent - = 2
2020-11-08 20:07:10 +01:00
self . write_line ( f " SI_CMD(ScriptOpcode_END_MATCH), " )
elif opcode == 0x24 : self . write_line ( f " SI_CMD(ScriptOpcode_SET, { self . var ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] ) } ), " )
elif opcode == 0x25 : self . write_line ( f " SI_CMD(ScriptOpcode_SET_CONST, { self . var ( argv [ 0 ] ) } , 0x { argv [ 1 ] : X } ), " )
elif opcode == 0x26 : self . write_line ( f " SI_CMD(ScriptOpcode_SET_F, { self . var ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] ) } ), " )
elif opcode == 0x27 : self . write_line ( f " SI_CMD(ScriptOpcode_ADD, { self . var ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] ) } ), " )
elif opcode == 0x28 : self . write_line ( f " SI_CMD(ScriptOpcode_SUB, { self . var ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] ) } ), " )
elif opcode == 0x29 : self . write_line ( f " SI_CMD(ScriptOpcode_MUL, { self . var ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] ) } ), " )
elif opcode == 0x2A : self . write_line ( f " SI_CMD(ScriptOpcode_DIV, { self . var ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] ) } ), " )
elif opcode == 0x2B : self . write_line ( f " SI_CMD(ScriptOpcode_MOD, { self . var ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] ) } ), " )
elif opcode == 0x2C : self . write_line ( f " SI_CMD(ScriptOpcode_ADD_F, { self . var ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] ) } ), " )
elif opcode == 0x2D : self . write_line ( f " SI_CMD(ScriptOpcode_SUB_F, { self . var ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] ) } ), " )
elif opcode == 0x2E : self . write_line ( f " SI_CMD(ScriptOpcode_MUL_F, { self . var ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] ) } ), " )
elif opcode == 0x2F : self . write_line ( f " SI_CMD(ScriptOpcode_DIV_F, { self . var ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] ) } ), " )
elif opcode == 0x30 : self . write_line ( f " SI_CMD(ScriptOpcode_USE_BUFFER, { self . var ( argv [ 0 ] ) } ), " )
elif opcode == 0x31 :
args = [ " ScriptOpcode_BUFFER_READ_1 " , * map ( self . var , argv ) ]
self . write_line ( f " SI_CMD( { ' , ' . join ( args ) } ), " )
elif opcode == 0x32 :
args = [ " ScriptOpcode_BUFFER_READ_2 " , * map ( self . var , argv ) ]
self . write_line ( f " SI_CMD( { ' , ' . join ( args ) } ), " )
elif opcode == 0x33 :
args = [ " ScriptOpcode_BUFFER_READ_3 " , * map ( self . var , argv ) ]
self . write_line ( f " SI_CMD( { ' , ' . join ( args ) } ), " )
elif opcode == 0x34 :
args = [ " ScriptOpcode_BUFFER_READ_4 " , * map ( self . var , argv ) ]
self . write_line ( f " SI_CMD( { ' , ' . join ( args ) } ), " )
elif opcode == 0x35 :
args = [ " ScriptOpcode_BUFFER_PEEK " , * map ( self . var , argv ) ]
self . write_line ( f " SI_CMD( { ' , ' . join ( args ) } ), " )
elif opcode == 0x36 : self . write_line ( f " SI_CMD(ScriptOpcode_USE_BUFFER_f, { self . var ( argv [ 0 ] ) } ), " )
elif opcode == 0x37 :
args = [ " ScriptOpcode_BUFFER_READ_1_F " , * map ( self . var , argv ) ]
self . write_line ( f " SI_CMD( { ' , ' . join ( args ) } ), " )
elif opcode == 0x38 :
args = [ " ScriptOpcode_BUFFER_READ_2_F " , * map ( self . var , argv ) ]
self . write_line ( f " SI_CMD( { ' , ' . join ( args ) } ), " )
elif opcode == 0x39 :
args = [ " ScriptOpcode_BUFFER_READ_3_F " , * map ( self . var , argv ) ]
self . write_line ( f " SI_CMD( { ' , ' . join ( args ) } ), " )
elif opcode == 0x3A :
args = [ " ScriptOpcode_BUFFER_READ_4_F " , * map ( self . var , argv ) ]
self . write_line ( f " SI_CMD( { ' , ' . join ( args ) } ), " )
elif opcode == 0x3B :
args = [ " ScriptOpcode_BUFFER_PEEK_F " , * map ( self . var , argv ) ]
self . write_line ( f " SI_CMD( { ' , ' . join ( args ) } ), " )
elif opcode == 0x3C : self . write_line ( f " SI_CMD(ScriptOpcode_USE_ARRAY, { self . var ( argv [ 0 ] ) } ), " )
elif opcode == 0x3D : self . write_line ( f " SI_CMD(ScriptOpcode_NEW_ARRAY, { self . var ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] ) } ), " )
elif opcode == 0x3E : self . write_line ( f " SI_CMD(ScriptOpcode_USE_FLAGS, { self . var ( argv [ 0 ] ) } ), " )
elif opcode == 0x3F : self . write_line ( f " SI_CMD(ScriptOpcode_AND, { self . var ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] ) } ), " )
elif opcode == 0x40 : self . write_line ( f " SI_CMD(ScriptOpcode_OR, { self . var ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] ) } ), " )
elif opcode == 0x41 : self . write_line ( f " SI_CMD(ScriptOpcode_AND_CONST, { self . var ( argv [ 0 ] ) } , 0x { argv [ 1 ] : X } ) " )
elif opcode == 0x42 : self . write_line ( f " SI_CMD(ScriptOpcode_OR_CONST, { self . var ( argv [ 0 ] ) } , 0x { argv [ 1 ] : X } ) " )
2020-10-19 23:58:57 +02:00
elif opcode == 0x43 :
2020-11-08 20:07:10 +01:00
args = [ " ScriptOpcode_CALL " , self . addr_ref ( argv [ 0 ] ) , * map ( self . var , argv [ 1 : ] ) ]
self . write_line ( f " SI_CMD( { ' , ' . join ( args ) } ), " )
elif opcode == 0x44 : self . write_line ( f " SI_CMD(ScriptOpcode_SPAWN, { self . addr_ref ( argv [ 0 ] ) } ), " )
elif opcode == 0x45 : self . write_line ( f " SI_CMD(ScriptOpcode_SPAWN_GET_ID, { self . addr_ref ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] ) } ), " )
elif opcode == 0x46 : self . write_line ( f " SI_CMD(ScriptOpcode_AWAIT_SCRIPT, { self . addr_ref ( argv [ 0 ] ) } ), " )
2020-10-19 23:58:57 +02:00
elif opcode == 0x47 :
2020-11-08 20:07:10 +01:00
args = [ " ScriptOpcode_BIND_TRIGGER " , self . addr_ref ( argv [ 0 ] ) , self . trigger ( argv [ 1 ] ) , * map ( self . var , argv [ 2 : ] ) ]
self . write_line ( f " SI_CMD( { ' , ' . join ( args ) } ), " )
elif opcode == 0x48 : self . write_line ( f " SI_CMD(ScriptOpcode_UNBIND), " )
elif opcode == 0x49 : self . write_line ( f " SI_CMD(ScriptOpcode_KILL_SCRIPT, { self . var ( argv [ 0 ] ) } ), " )
elif opcode == 0x4A : self . write_line ( f " SI_CMD(ScriptOpcode_JUMP, { self . var ( argv [ 0 ] ) } ), " )
elif opcode == 0x4B : self . write_line ( f " SI_CMD(ScriptOpcode_SET_PRIORITY, { self . var ( argv [ 0 ] ) } ), " )
elif opcode == 0x4C : self . write_line ( f " SI_CMD(ScriptOpcode_SET_TIMESCALE, { self . var ( argv [ 0 ] ) } ), " )
elif opcode == 0x4D : self . write_line ( f " SI_CMD(ScriptOpcode_SET_GROUP, { self . var ( argv [ 0 ] ) } ), " )
2020-10-19 23:58:57 +02:00
elif opcode == 0x4E :
2020-11-08 20:07:10 +01:00
args = [ " ScriptOpcode_BIND_TRIGGER " , self . addr_ref ( argv [ 0 ] ) , self . trigger ( argv [ 1 ] ) , * map ( self . var , argv [ 2 : ] ) ]
self . write_line ( f " SI_CMD( { ' , ' . join ( args ) } ), " )
elif opcode == 0x4F : self . write_line ( f " SI_CMD(ScriptOpcode_SUSPEND_GROUP, { self . var ( argv [ 0 ] ) } ), " )
elif opcode == 0x50 : self . write_line ( f " SI_CMD(ScriptOpcode_RESUME_GROUP, { self . var ( argv [ 0 ] ) } ), " )
elif opcode == 0x51 : self . write_line ( f " SI_CMD(ScriptOpcode_SUSPEND_OTHERS, { self . var ( argv [ 0 ] ) } ), " )
elif opcode == 0x52 : self . write_line ( f " SI_CMD(ScriptOpcode_RESUME_OTHERS, { self . var ( argv [ 0 ] ) } ), " )
elif opcode == 0x53 : self . write_line ( f " SI_CMD(ScriptOpcode_SUSPEND_SCRIPT, { self . var ( argv [ 0 ] ) } ), " )
elif opcode == 0x54 : self . write_line ( f " SI_CMD(ScriptOpcode_RESUME_SCRIPT, { self . var ( argv [ 0 ] ) } ), " )
elif opcode == 0x55 : self . write_line ( f " SI_CMD(ScriptOpcode_SCRIPT_EXISTS, { self . var ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] ) } ), " )
2020-10-19 23:58:57 +02:00
elif opcode == 0x56 :
2020-11-08 20:07:10 +01:00
self . write_line ( " SI_CMD(ScriptOpcode_SPAWN_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
2020-11-08 20:07:10 +01:00
self . write_line ( " SI_CMD(ScriptOpcode_END_SPAWN_THREAD), " )
2020-10-19 23:58:57 +02:00
elif opcode == 0x58 :
2020-11-08 20:07:10 +01:00
self . write_line ( " SI_CMD(ScriptOpcode_PARALLEL_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
2020-11-08 20:07:10 +01:00
self . write_line ( " SI_CMD(ScriptOpcode_END_PARALLEL_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 } "
2020-10-31 03:28:18 +01:00
self . write_line ( f " SI_CMD(0x { opcode : 02X } { argv_str } ), " )
class UnsupportedScript ( Exception ) :
pass
class ScriptDSLDisassembler ( ScriptDisassembler ) :
2020-11-08 13:16:10 +01:00
def __init__ ( self , * args , * * kwargs ) :
super ( ) . __init__ ( * args , * * kwargs )
2020-11-08 16:35:41 +01:00
# True: case block
# CASE: single condition
# MULTI: multi-condition(s)
# MATCH: match block
2020-11-08 15:57:58 +01:00
self . case_stack = [ ]
2021-03-29 02:05:56 +02:00
# stores the variable type the case is switching on
self . case_variable = " "
self . save_variable = " "
2020-11-08 15:57:58 +01:00
self . was_multi_case = False
@property
def in_case ( self ) :
return self . case_stack [ - 1 ] if self . case_stack else False
2020-11-08 13:16:10 +01:00
2020-10-31 03:28:18 +01:00
def var ( self , arg ) :
if arg in self . symbol_map :
2021-03-24 09:39:43 +01:00
return self . symbol_map [ arg ] [ 0 ] [ 1 ]
2020-10-31 03:28:18 +01:00
v = arg - 2 * * 32 # convert to s32
if v > - 250000000 :
if v < = - 220000000 : return str ( ( v + 230000000 ) / 1024 )
elif v < = - 200000000 : return f " SI_ARRAY_FLAG( { v + 210000000 } ) "
elif v < = - 180000000 : return f " SI_ARRAY( { v + 190000000 } ) "
2021-03-29 02:05:56 +02:00
elif v < = - 160000000 :
2021-03-30 05:39:17 +02:00
if v + 170000000 == 0 :
self . save_variable = " STORY_PROGRESS "
elif v + 170000000 == 425 :
self . save_variable = " WORLD_LOCATION "
else :
self . save_variable = f " SI_SAVE_VAR( { v + 170000000 } ) "
2021-03-29 02:05:56 +02:00
return self . save_variable
2020-10-31 03:28:18 +01:00
elif v < = - 140000000 : return f " SI_AREA_VAR( { v + 150000000 } ) "
elif v < = - 120000000 : return f " SI_SAVE_FLAG( { v + 130000000 } ) "
elif v < = - 100000000 : return f " SI_AREA_FLAG( { v + 110000000 } ) "
elif v < = - 80000000 : return f " SI_MAP_FLAG( { v + 90000000 } ) "
elif v < = - 60000000 : return f " SI_FLAG( { v + 70000000 } ) "
elif v < = - 40000000 : return f " SI_MAP_VAR( { v + 50000000 } ) "
elif v < = - 20000000 : return f " SI_VAR( { v + 30000000 } ) "
if arg == 0xFFFFFFFF :
return " -1 "
elif ( ( arg & 0xFF000000 ) == 0x80000000 ) or arg > 10000 :
return f " 0x { arg : X } "
else :
return f " { arg } "
2020-11-08 16:35:41 +01:00
def is_float ( self , var ) :
2020-10-31 03:28:18 +01:00
try :
float ( var )
2020-11-08 16:35:41 +01:00
return True
2020-10-31 03:28:18 +01:00
except Exception :
2020-11-08 16:35:41 +01:00
return False
2020-10-31 03:28:18 +01:00
2021-03-29 02:05:56 +02:00
def replace_enum ( self , var , case = False ) :
varO = self . var ( var )
if case :
self . save_variable = " "
try :
var = int ( varO , 0 )
except Exception :
return varO
if var > 0x10000000 :
var - = 0x100000000
2021-03-30 05:39:17 +02:00
# put cases for replacing vars here
if ( ( case and self . case_variable == " STORY_PROGRESS " ) or
( not case and self . save_variable == " STORY_PROGRESS " ) ) :
if var in CONSTANTS [ " StoryProgress " ] :
return CONSTANTS [ " StoryProgress " ] [ var ]
elif ( ( case and self . case_variable == " WORLD_LOCATION " ) or
( not case and self . save_variable == " WORLD_LOCATION " ) ) :
if var in CONSTANTS [ " Locations " ] :
return CONSTANTS [ " Locations " ] [ var ]
2021-03-29 02:05:56 +02:00
return varO
2020-10-31 03:28:18 +01:00
def disassemble_command ( self , opcode , argc , argv ) :
2020-11-08 15:57:58 +01:00
# write case block braces
2020-11-08 16:35:41 +01:00
if self . in_case == " CASE " or self . in_case == " MULTI " :
2020-11-08 15:57:58 +01:00
if opcode == 0x1D : # multi case
pass
elif 0x16 < = opcode < = 0x21 : # standard case conditions
# open and close empty case
2020-11-08 16:35:41 +01:00
self . out + = " {} \n "
2020-11-08 15:57:58 +01:00
self . case_stack . pop ( )
2020-11-08 16:35:41 +01:00
assert self . in_case == " MATCH "
self . was_multi_case = False
2020-11-08 15:57:58 +01:00
else :
# open case
self . out + = " { \n "
self . case_stack . append ( True )
2020-11-08 16:35:41 +01:00
self . indent + = 1
elif self . in_case != " MATCH " and 0x16 < = opcode < = 0x21 : # new case, not including the first
assert self . case_stack . pop ( ) == True
self . was_multi_case = self . case_stack . pop ( ) == " MULTI "
assert self . in_case == " MATCH "
2020-11-08 15:57:58 +01:00
self . indent - = 1
self . write_line ( " } " )
2021-03-29 02:05:56 +02:00
#print(f"Op 0x{opcode:2X} saved_var \"{self.save_variable}\" case_var \"{self.case_variable}\"")
2021-03-30 05:39:17 +02:00
# case variables need to be saved ahead of time, since they span many instructions
if ( ( self . in_case and 0x16 < = opcode < = 0x1B and self . case_variable == " STORY_PROGRESS " ) or
( self . in_case and 0x16 < = opcode < = 0x1B and self . case_variable == " WORLD_LOCATION " ) ) :
2021-03-29 02:05:56 +02:00
argv [ 0 ] = self . replace_enum ( argv [ 0 ] , case = True )
2020-10-31 03:28:18 +01:00
if opcode == 0x01 :
2020-12-27 18:11:33 +01:00
if self . out . endswith ( " return; \n " ) :
2020-10-31 03:28:18 +01:00
# implicit return; break
2020-12-27 18:11:33 +01:00
self . out = self . out [ : - 8 ] . rstrip ( ) + " \n "
2020-10-31 03:28:18 +01:00
else :
2020-12-27 18:11:33 +01:00
self . write_line ( " break; " )
2020-10-31 03:28:18 +01:00
self . indent - = 1
self . prefix_line ( f " Script { self . script_name } = SCRIPT( {{ " )
self . write_line ( " }); " )
2020-10-19 23:58:57 +02:00
2020-10-31 03:28:18 +01:00
self . done = True
2020-12-24 12:15:05 +01:00
elif opcode == 0x02 : self . write_line ( f " return; " )
2020-12-27 18:11:33 +01:00
elif opcode == 0x03 :
self . indent - = 1
self . write_line ( f " { self . var ( argv [ 0 ] ) } : " )
self . indent + = 1
2020-12-24 12:15:05 +01:00
elif opcode == 0x04 : self . write_line ( f " goto { self . var ( argv [ 0 ] ) } ; " )
2020-10-31 03:28:18 +01:00
elif opcode == 0x05 :
if argv [ 0 ] == 0 :
self . write_line ( " loop { " )
else :
self . write_line ( f " loop { self . var ( argv [ 0 ] ) } {{ " )
self . indent + = 1
elif opcode == 0x06 :
self . indent - = 1
self . write_line ( " } " )
2020-12-24 12:15:05 +01:00
elif opcode == 0x07 : self . write_line ( f " break; " )
elif opcode == 0x08 : self . write_line ( f " sleep { self . var ( argv [ 0 ] ) } ; " )
elif opcode == 0x09 : self . write_line ( f " sleep { self . var ( argv [ 0 ] ) } secs; " )
2020-10-31 03:28:18 +01:00
elif opcode == 0x0A :
2021-03-29 02:05:56 +02:00
varA = self . replace_enum ( argv [ 0 ] )
varB = self . replace_enum ( argv [ 1 ] )
2021-03-30 05:39:17 +02:00
if varB in SAVE_VARS :
2021-03-29 02:05:56 +02:00
varA = self . replace_enum ( argv [ 0 ] )
self . write_line ( f " if ( { varA } == { varB } ) {{ " )
2020-10-31 03:28:18 +01:00
self . indent + = 1
elif opcode == 0x0B :
2021-03-29 02:05:56 +02:00
varA = self . replace_enum ( argv [ 0 ] )
varB = self . replace_enum ( argv [ 1 ] )
2021-03-30 05:39:17 +02:00
if varB in SAVE_VARS :
2021-03-29 02:05:56 +02:00
varA = self . replace_enum ( argv [ 0 ] )
self . write_line ( f " if ( { varA } != { varB } ) {{ " )
2020-10-31 03:28:18 +01:00
self . indent + = 1
elif opcode == 0x0C :
2021-03-29 02:05:56 +02:00
varA = self . replace_enum ( argv [ 0 ] )
varB = self . replace_enum ( argv [ 1 ] )
2021-03-30 05:39:17 +02:00
if varB in SAVE_VARS :
2021-03-29 02:05:56 +02:00
varA = self . replace_enum ( argv [ 0 ] )
self . write_line ( f " if ( { varA } < { varB } ) {{ " )
2020-10-31 03:28:18 +01:00
self . indent + = 1
elif opcode == 0x0D :
2021-03-29 02:05:56 +02:00
varA = self . replace_enum ( argv [ 0 ] )
varB = self . replace_enum ( argv [ 1 ] )
2021-03-30 05:39:17 +02:00
if varB in SAVE_VARS :
2021-03-29 02:05:56 +02:00
varA = self . replace_enum ( argv [ 0 ] )
self . write_line ( f " if ( { varA } > { varB } ) {{ " )
2020-10-31 03:28:18 +01:00
self . indent + = 1
elif opcode == 0x0E :
2021-03-29 02:05:56 +02:00
varA = self . replace_enum ( argv [ 0 ] )
varB = self . replace_enum ( argv [ 1 ] )
2021-03-30 05:39:17 +02:00
if varB in SAVE_VARS :
2021-03-29 02:05:56 +02:00
varA = self . replace_enum ( argv [ 0 ] )
self . write_line ( f " if ( { varA } <= { varB } ) {{ " )
2020-10-31 03:28:18 +01:00
self . indent + = 1
elif opcode == 0x0F :
2021-03-29 02:05:56 +02:00
varA = self . replace_enum ( argv [ 0 ] )
varB = self . replace_enum ( argv [ 1 ] )
2021-03-30 05:39:17 +02:00
if varB in SAVE_VARS :
2021-03-29 02:05:56 +02:00
varA = self . replace_enum ( argv [ 0 ] )
self . write_line ( f " if ( { varA } >= { varB } ) {{ " )
2020-10-31 03:28:18 +01:00
self . indent + = 1
2020-11-08 15:57:58 +01:00
elif opcode == 0x10 :
2020-12-29 12:37:19 +01:00
self . write_line ( f " if ( { self . var ( argv [ 0 ] ) } & { self . var ( argv [ 1 ] ) } ) {{ " )
2020-11-08 15:57:58 +01:00
self . indent + = 1
2020-12-27 18:11:33 +01:00
elif opcode == 0x11 :
2020-12-29 12:37:19 +01:00
self . write_line ( f " if ( { self . var ( argv [ 0 ] ) } !& { self . var ( argv [ 1 ] ) } ) {{ " )
2020-12-27 18:11:33 +01:00
self . indent + = 1
2020-10-31 03:28:18 +01:00
elif opcode == 0x12 :
self . indent - = 1
self . write_line ( " } else { " )
self . indent + = 1
elif opcode == 0x13 :
self . indent - = 1
self . write_line ( " } " )
2020-11-08 13:16:10 +01:00
elif opcode == 0x14 :
self . write_line ( f " match { self . var ( argv [ 0 ] ) } {{ " )
2020-11-08 16:35:41 +01:00
self . indent + = 1
2021-03-29 02:05:56 +02:00
self . case_variable = self . var ( argv [ 0 ] )
2020-11-08 16:35:41 +01:00
self . case_stack . append ( " MATCH " )
elif opcode == 0x15 :
self . write_line ( f " matchc { self . var ( argv [ 0 ] ) } {{ " )
self . indent + = 1
2021-03-29 02:05:56 +02:00
self . case_variable = self . var ( argv [ 0 ] )
2020-11-08 16:35:41 +01:00
self . case_stack . append ( " MATCH " )
2020-11-08 13:16:10 +01:00
elif opcode == 0x16 :
2020-11-08 16:35:41 +01:00
self . case_stack . append ( " CASE " )
2021-03-29 02:05:56 +02:00
self . write ( f " == { argv [ 0 ] } " )
2020-11-08 13:16:10 +01:00
elif opcode == 0x17 :
2020-11-08 16:35:41 +01:00
self . case_stack . append ( " CASE " )
2021-03-29 02:05:56 +02:00
self . write ( f " != { argv [ 0 ] } " )
2020-11-08 13:16:10 +01:00
elif opcode == 0x18 :
2020-11-08 16:35:41 +01:00
self . case_stack . append ( " CASE " )
2021-03-29 02:05:56 +02:00
self . write ( f " < { argv [ 0 ] } " )
2020-11-08 13:16:10 +01:00
elif opcode == 0x19 :
2020-11-08 16:35:41 +01:00
self . case_stack . append ( " CASE " )
2021-03-29 02:05:56 +02:00
self . write ( f " > { argv [ 0 ] } " )
2020-11-08 13:16:10 +01:00
elif opcode == 0x1A :
2020-11-08 16:35:41 +01:00
self . case_stack . append ( " CASE " )
2021-03-29 02:05:56 +02:00
self . write ( f " <= { argv [ 0 ] } " )
2020-11-08 13:16:10 +01:00
elif opcode == 0x1B :
2020-11-08 16:35:41 +01:00
self . case_stack . append ( " CASE " )
2021-03-29 02:05:56 +02:00
self . write ( f " >= { argv [ 0 ] } " )
2020-11-08 13:16:10 +01:00
elif opcode == 0x1C :
2020-11-08 16:35:41 +01:00
self . case_stack . append ( " CASE " )
2020-11-08 15:57:58 +01:00
self . write ( f " else " )
elif opcode == 0x1D :
2020-11-08 16:35:41 +01:00
if self . in_case == " CASE " or self . in_case == " MULTI " :
2020-11-08 15:57:58 +01:00
self . out + = f " , { self . var ( argv [ 0 ] ) } "
2020-11-08 16:35:41 +01:00
# replace(!) CASE with MULTI
self . case_stack . pop ( )
self . case_stack . append ( " MULTI " )
2020-11-08 15:57:58 +01:00
else :
self . write ( f " { self . var ( argv [ 0 ] ) } " )
2020-11-08 16:35:41 +01:00
self . case_stack . append ( " MULTI " )
2020-11-08 13:16:10 +01:00
# opcode 0x1E?
elif opcode == 0x1F :
2020-11-08 16:35:41 +01:00
self . case_stack . append ( " CASE " )
2020-11-08 15:00:53 +01:00
self . write_line ( f " ? { self . var ( argv [ 0 ] ) } " )
2020-11-08 16:35:41 +01:00
elif opcode == 0x20 :
if not self . was_multi_case :
raise UnsupportedScript ( " unexpected SI_END_MULTI_CASE " )
2020-11-08 13:16:10 +01:00
elif opcode == 0x21 :
self . indent - = 1
2020-11-08 16:35:41 +01:00
self . write_line ( f " { self . var ( argv [ 0 ] ) } .. { self . var ( argv [ 1 ] ) } " )
2020-11-08 13:16:10 +01:00
self . indent + = 1
elif opcode == 0x22 : self . write_line ( " break " )
elif opcode == 0x23 :
2020-11-08 16:35:41 +01:00
# close open case if needed
if self . in_case != " MATCH " :
self . case_stack . pop ( ) == True
self . case_stack . pop ( ) in [ " MULTI " , " CASE " ]
self . indent - = 1
2020-11-08 15:57:58 +01:00
self . write_line ( " } " )
2020-11-08 16:35:41 +01:00
assert self . case_stack . pop ( ) == " MATCH "
2020-11-08 13:16:10 +01:00
self . indent - = 1
2021-03-29 02:05:56 +02:00
self . case_variable = " "
2020-11-08 13:16:10 +01:00
self . write_line ( " } " )
2021-03-29 02:05:56 +02:00
elif opcode == 0x24 :
varA = self . replace_enum ( argv [ 0 ] )
varB = self . replace_enum ( argv [ 1 ] )
self . write_line ( f " { varA } = { varB } ; " )
2020-12-24 12:15:05 +01:00
elif opcode == 0x25 : self . write_line ( f " { self . var ( argv [ 0 ] ) } =c 0x { argv [ 1 ] : X } ; " )
2020-11-08 16:35:41 +01:00
elif opcode == 0x26 :
lhs = self . var ( argv [ 1 ] )
if self . is_float ( lhs ) :
2020-12-24 12:15:05 +01:00
self . write_line ( f " { self . var ( argv [ 0 ] ) } = { lhs } ; " )
2020-11-08 16:35:41 +01:00
else :
2020-12-24 12:15:05 +01:00
self . write_line ( f " { self . var ( argv [ 0 ] ) } =f { lhs } ; " )
elif opcode == 0x27 : self . write_line ( f " { self . var ( argv [ 0 ] ) } += { self . var ( argv [ 1 ] ) } ; " )
elif opcode == 0x28 : self . write_line ( f " { self . var ( argv [ 0 ] ) } -= { self . var ( argv [ 1 ] ) } ; " )
elif opcode == 0x29 : self . write_line ( f " { self . var ( argv [ 0 ] ) } *= { self . var ( argv [ 1 ] ) } ; " )
elif opcode == 0x2A : self . write_line ( f " { self . var ( argv [ 0 ] ) } /= { self . var ( argv [ 1 ] ) } ; " )
elif opcode == 0x2B : self . write_line ( f " { self . var ( argv [ 0 ] ) } %= { self . var ( argv [ 1 ] ) } ; " )
2020-11-08 16:35:41 +01:00
elif opcode == 0x2C :
lhs = self . var ( argv [ 1 ] )
if self . is_float ( lhs ) :
2020-12-24 12:15:05 +01:00
self . write_line ( f " { self . var ( argv [ 0 ] ) } += { lhs } ; " )
2020-11-08 16:35:41 +01:00
else :
2020-12-24 12:15:05 +01:00
self . write_line ( f " { self . var ( argv [ 0 ] ) } +=f { lhs } ; " )
2020-11-08 16:35:41 +01:00
elif opcode == 0x2D :
lhs = self . var ( argv [ 1 ] )
if self . is_float ( lhs ) :
2020-12-24 12:15:05 +01:00
self . write_line ( f " { self . var ( argv [ 0 ] ) } -= { lhs } ; " )
2020-11-08 16:35:41 +01:00
else :
2020-12-24 12:15:05 +01:00
self . write_line ( f " { self . var ( argv [ 0 ] ) } -=f { lhs } ; " )
2020-11-08 16:35:41 +01:00
elif opcode == 0x2E :
lhs = self . var ( argv [ 1 ] )
if self . is_float ( lhs ) :
2020-12-24 12:15:05 +01:00
self . write_line ( f " { self . var ( argv [ 0 ] ) } *= { lhs } ; " )
2020-11-08 16:35:41 +01:00
else :
2020-12-24 12:15:05 +01:00
self . write_line ( f " { self . var ( argv [ 0 ] ) } *=f { lhs } ; " )
2020-11-08 16:35:41 +01:00
elif opcode == 0x2F :
lhs = self . var ( argv [ 1 ] )
if self . is_float ( lhs ) :
2020-12-24 12:15:05 +01:00
self . write_line ( f " { self . var ( argv [ 0 ] ) } /= { lhs } ; " )
2020-11-08 16:35:41 +01:00
else :
2020-12-24 12:15:05 +01:00
self . write_line ( f " { self . var ( argv [ 0 ] ) } /=f { lhs } ; " )
elif opcode == 0x3F : self . write_line ( f " { self . var ( argv [ 0 ] ) } &= { self . var ( argv [ 1 ] ) } ; " )
elif opcode == 0x40 : self . write_line ( f " { self . var ( argv [ 0 ] ) } |= { self . var ( argv [ 1 ] ) } ; " )
elif opcode == 0x41 : self . write_line ( f " { self . var ( argv [ 0 ] ) } &=c { argv [ 1 ] : X } ; " )
elif opcode == 0x42 : self . write_line ( f " { self . var ( argv [ 0 ] ) } |=c { argv [ 1 ] : X } ; " )
2020-10-31 03:28:18 +01:00
elif opcode == 0x43 :
2021-02-04 16:35:34 +01:00
addr = argv [ 0 ]
if addr in self . symbol_map :
2021-03-24 09:39:43 +01:00
func_name = self . symbol_map [ addr ] [ 0 ] [ 1 ]
2021-02-04 16:35:34 +01:00
argv_str = " , " . join ( self . var ( arg ) for arg in argv [ 1 : ] )
2021-03-24 09:39:43 +01:00
argv_str = replace_constants ( func_name , argv_str )
2021-02-04 16:35:34 +01:00
self . write_line ( f " { func_name } ( { argv_str } ); " )
else :
print ( f " script API function { addr : X } is not present in symbol_addrs.txt, please add it " )
exit ( 1 )
2020-12-24 12:15:05 +01:00
elif opcode == 0x44 : self . write_line ( f " spawn { self . addr_ref ( argv [ 0 ] ) } ; " )
elif opcode == 0x45 : self . write_line ( f " { self . var ( argv [ 1 ] ) } = spawn { self . addr_ref ( argv [ 0 ] ) } ; " )
elif opcode == 0x46 : self . write_line ( f " await { self . addr_ref ( argv [ 0 ] ) } ; " )
2020-10-31 03:28:18 +01:00
elif opcode == 0x47 :
assert argv [ 3 ] == 1
if argv [ 4 ] != 0 :
2020-12-24 12:15:05 +01:00
self . write_line ( f " { self . var ( argv [ 4 ] ) } = bind { self . addr_ref ( argv [ 0 ] ) } to { self . trigger ( argv [ 1 ] ) } { self . var ( argv [ 2 ] ) } ; " )
2020-10-31 03:28:18 +01:00
else :
2020-12-24 12:15:05 +01:00
self . write_line ( f " bind { self . addr_ref ( argv [ 0 ] ) } to { self . trigger ( argv [ 1 ] ) } { self . var ( argv [ 2 ] ) } ; " )
elif opcode == 0x48 : self . write_line ( f " unbind; " )
elif opcode == 0x49 : self . write_line ( f " kill { self . var ( argv [ 0 ] ) } ; " )
2021-03-24 09:39:43 +01:00
elif opcode == 0x4A : self . write_line ( f " jump { self . var ( argv [ 0 ] ) } ; " )
2020-12-24 12:15:05 +01:00
elif opcode == 0x4D : self . write_line ( f " group { self . var ( argv [ 0 ] ) } ; " )
elif opcode == 0x4F : self . write_line ( f " suspend group { self . var ( argv [ 0 ] ) } ; " )
elif opcode == 0x50 : self . write_line ( f " resume group { self . var ( argv [ 0 ] ) } ; " )
elif opcode == 0x51 : self . write_line ( f " suspend others { self . var ( argv [ 0 ] ) } ; " )
elif opcode == 0x52 : self . write_line ( f " resume others { self . var ( argv [ 0 ] ) } ; " )
elif opcode == 0x53 : self . write_line ( f " suspend { self . var ( argv [ 0 ] ) } ; " )
elif opcode == 0x54 : self . write_line ( f " resume { self . var ( argv [ 0 ] ) } ; " )
2020-10-31 03:28:18 +01:00
elif opcode == 0x56 :
self . write_line ( " spawn { " )
self . indent + = 1
elif opcode == 0x57 :
self . indent - = 1
self . write_line ( " } " )
elif opcode == 0x58 :
self . write_line ( " parallel { " )
self . indent + = 1
elif opcode == 0x59 :
self . indent - = 1
self . write_line ( " } " )
else :
2020-11-08 15:57:58 +01:00
raise UnsupportedScript ( f " DSL does not support script opcode 0x { opcode : X } " )
2020-10-19 23:58:57 +02:00
2021-03-30 05:39:17 +02:00
# reset this at the end of each instruction
self . save_variable = " "
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-03-30 05:39:17 +02:00
parser . add_argument ( " offset " , type = lambda x : int ( x , 16 ) , default = 0 , help = " Offset to start dissassembling from " )
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-03-29 02:05:56 +02:00
args = parser . parse_args ( )
get_constants ( )
if args . end > args . 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 :
while args . offset < args . end :
f . seek ( args . offset )
script = ScriptDSLDisassembler ( f )
try :
script_text = script . disassemble ( )
2021-03-30 05:39:17 +02:00
if script . instructions > 1 and " SI_CMD " not in script_text and " break; " not in script_text :
print ( f " Script read from 0x { script . start_pos : X } to 0x { script . end_pos : X } "
f " (0x { script . end_pos - script . start_pos : X } bytes, { script . instructions } instructions) " )
print ( )
print ( script_text , end = " " )
print ( )
#print(f"Valid script found at 0x{args.offset:X}")
2021-03-29 02:05:56 +02:00
args . offset = script . end_pos
else :
args . offset + = 4
except Exception :
args . offset + = 4
else :
with open ( args . file , " rb " ) as f :
f . seek ( args . offset )
2020-10-19 23:58:57 +02:00
2021-03-29 02:05:56 +02:00
script = ScriptDSLDisassembler ( f )
try :
script_text = script . disassemble ( )
2020-10-19 23:58:57 +02:00
2021-03-29 02:05:56 +02:00
print ( f " Script read from 0x { script . start_pos : X } to 0x { script . end_pos : X } "
f " (0x { script . end_pos - script . start_pos : X } bytes, { script . instructions } instructions) " )
print ( )
print ( script_text , end = " " )
2020-10-31 03:28:18 +01:00
2021-03-29 02:05:56 +02:00
except UnsupportedScript :
print ( ScriptDisassembler ( f ) . disassemble ( ) , end = " " )