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 ] )
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 ] )
2020-10-31 03:28:18 +01:00
return _script_lib
2021-07-12 14:06:00 +02:00
def round_fixed ( f : float ) - > float :
g = f * 100.0
whole = round ( g )
if abs ( g - whole ) < = 100.0 / 1024.0 :
f = whole / 100.0
return f
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-04-28 10:58:21 +02:00
" AmbientSounds " , " NpcIDs " , " Emotes " , " NpcFlags " ,
2021-07-12 14:06:00 +02:00
" Events " , " Statuses " , " Elements " , " DamageTypes " , " HitResults " ,
2021-04-28 10:58:21 +02:00
" ActorFlags " , " ActorPartFlags " , " ActorEventFlags " , " ElementFlags " }
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
[ 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-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 ( ) :
if " #define _NPC_SPRITE_ " in line :
enum = " NPC_SPRITE "
elif " #define _NPC_PALETTE_ " in line :
enum = " NPC_PALETTE "
elif " #define _NPC_ANIM_ " in line :
enum = " NPC_ANIM "
else :
continue
name = line . split ( " " , 2 ) [ 1 ]
id_ = line . split ( " 0x " , 1 ) [ 1 ]
if " " in id_ :
id_ = id_ . split ( " " , 1 ) [ 0 ]
name = name . split ( f " _ { enum } _ " , 1 ) [ 1 ]
if enum == " NPC_SPRITE " :
saved_name = name
saved_id = id_
else :
name = name . rsplit ( f " { saved_name } _ " ) [ 1 ]
if enum == " NPC_SPRITE " :
if int ( id_ , 16 ) not in CONSTANTS [ " NPC_SPRITE " ] :
CONSTANTS [ enum ] [ int ( id_ , 16 ) ] = { " name " : " " , " palettes " : { } , " anims " : { } }
CONSTANTS [ enum ] [ int ( id_ , 16 ) ] [ " name " ] = name
elif enum == " NPC_PALETTE " :
CONSTANTS [ " NPC_SPRITE " ] [ int ( saved_id , 16 ) ] [ " palettes " ] [ int ( id_ , 16 ) ] = name
elif enum == " NPC_ANIM " :
CONSTANTS [ " NPC_SPRITE " ] [ int ( saved_id , 16 ) ] [ " anims " ] [ int ( id_ , 16 ) ] = name
2021-03-24 09:39:43 +01:00
return
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-04-08 19:42:36 +02:00
call = " NPC_ANIM( "
if sprite in CONSTANTS [ " NPC_SPRITE " ] :
call + = f " { CONSTANTS [ ' NPC_SPRITE ' ] [ sprite ] [ ' name ' ] } , "
if palette in CONSTANTS [ " NPC_SPRITE " ] [ sprite ] [ " palettes " ] :
call + = f " { CONSTANTS [ ' NPC_SPRITE ' ] [ sprite ] [ ' palettes ' ] [ palette ] } , "
else :
call + = f " 0x { palette : 02X } , "
if anim in CONSTANTS [ " NPC_SPRITE " ] [ sprite ] [ " anims " ] :
call + = f " { CONSTANTS [ ' NPC_SPRITE ' ] [ sprite ] [ ' anims ' ] [ anim ] } "
else :
call + = f " 0x { anim : 02X } "
call + = " ) "
self . INCLUDES_NEEDED [ " sprites " ] . add ( CONSTANTS [ ' NPC_SPRITE ' ] [ sprite ] [ ' name ' ] )
else :
call + = f " 0x { sprite : 02X } , 0x { palette : 02X } , 0x { anim : 02X } ) "
return call
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-04-03 19:21:49 +02:00
if ( ( arg == " D_80000000 " ) or ( arg . startswith ( " D_B " ) ) or
( i == 0 and func == " MakeEntity " and arg . startswith ( " D_ " ) ) ) :
arg = " 0x " + arg [ 2 : ]
if " 0x " in arg and int ( arg , 16 ) > = 0xF0000000 :
arg = f " { int ( 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
argNum = int ( arg , 0 )
if info [ i ] == " Bool " :
new_args . append ( f " { ' TRUE ' if argNum == True else ' FALSE ' } " )
elif info [ i ] == " Hex " :
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-04-08 19:42:36 +02:00
if func == " SetAnimation " and int ( new_args [ 1 ] , 10 ) == 0 :
2021-04-03 19:21:49 +02:00
call = f " { CONSTANTS [ ' PlayerAnims ' ] [ argNum ] } "
2021-04-28 10:58:21 +02:00
elif " SI_ " not in args [ 0 ] and int ( args [ 0 ] ) > = 0 and CONSTANTS [ " MAP_NPCS " ] . get ( int ( args [ 0 ] ) ) == " NPC_PLAYER " :
2021-04-08 19:42:36 +02:00
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 :
if sprite == 0 :
2021-04-08 19:42:36 +02:00
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 } "
2021-04-03 19:21:49 +02:00
else :
2021-04-08 19:42:36 +02:00
call = make_anim_macro ( self , sprite , palette , anim )
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 " :
2021-04-29 19:09:30 +02:00
if argNum not in CONSTANTS [ " MAP_NPCS " ] :
new_args . append ( f " 0x { argNum : X } " )
continue
2021-04-08 19:42:36 +02:00
if argNum > = 0 :
new_args . append ( CONSTANTS [ " MAP_NPCS " ] [ argNum ] )
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-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-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-04-03 19:21:49 +02:00
" MakeEntity " : { 0 : " Hex " , 5 : " ItemIDs " } ,
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-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
2020-10-31 03:28:18 +01:00
class ScriptDisassembler :
2021-04-22 05:19:31 +02:00
def __init__ ( self , bytes , script_name = " script " , symbol_map = { } , romstart = 0 , INCLUDES_NEEDED = { } , INCLUDED = { " functions " : set ( ) , " includes " : set ( ) } ) :
2020-10-31 03:28:18 +01:00
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 }
2021-04-03 19:21:49 +02:00
self . romstart = romstart
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-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
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 "
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 "
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 } "
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-04-03 19:21:49 +02:00
name = self . symbol_map [ addr ] [ 0 ] [ 1 ]
toReplace = True
suffix = " "
if name . startswith ( " N(func_ " ) :
prefix = " ApiStatus "
name = self . replace_star_rod_function_name ( name [ 2 : - 1 ] )
suffix = " (ScriptInstance* script, s32 isInitialCall) "
2021-04-08 19:42:36 +02:00
elif name [ 2 : - 1 ] in self . INCLUDED [ " includes " ] :
prefix = " ApiStatus "
suffix = " (ScriptInstance* script, s32 isInitialCall) "
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( " ) :
prefix = " Script "
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 :
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 ] ) } ), " )
2021-04-08 19:42:36 +02:00
elif opcode == 0x3D : self . write_line ( f " SI_CMD(ScriptOpcode_USE_FLAGS, { self . var ( argv [ 0 ] ) } ), " )
elif opcode == 0x3E : self . write_line ( f " SI_CMD(ScriptOpcode_NEW_ARRAY, { self . var ( argv [ 0 ] ) } , { self . var ( argv [ 1 ] ) } ), " )
2020-11-08 20:07:10 +01:00
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 ) } ), " )
2021-04-03 19:21:49 +02:00
elif opcode == 0x44 : self . write_line ( f " SI_CMD(ScriptOpcode_SPAWN_SCRIPT, { self . addr_ref ( argv [ 0 ] ) } ), " )
2020-11-08 20:07:10 +01:00
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 :
2021-04-03 19:21:49 +02:00
args = [ " ScriptOpcode_BIND_PADLOCK " , self . addr_ref ( argv [ 0 ] ) , self . trigger ( argv [ 1 ] ) , * map ( self . var , argv [ 2 : ] ) ]
2020-11-08 20:07:10 +01:00
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 ] ) } ), " )
2021-07-20 19:43:16 +02:00
elif opcode == 0x55 : self . write_line ( f " SI_CMD(ScriptOpcode_DOES_SCRIPT_EXIST, { 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 ) :
2021-04-28 10:58:21 +02:00
if arg in self . symbol_map and arg > = 0x80000000 :
2021-03-24 09:39:43 +01:00
return self . symbol_map [ arg ] [ 0 ] [ 1 ]
2021-04-03 19:21:49 +02:00
elif type ( arg ) is str :
return arg
2020-10-31 03:28:18 +01:00
v = arg - 2 * * 32 # convert to s32
if v > - 250000000 :
2021-07-12 14:06:00 +02:00
if v < = - 220000000 : return str ( round_fixed ( ( v + 230000000 ) / 1024 ) )
2020-10-31 03:28:18 +01:00
elif v < = - 200000000 : return f " SI_ARRAY_FLAG( { v + 210000000 } ) "
elif v < = - 180000000 : return f " SI_ARRAY( { v + 190000000 } ) "
2021-04-03 19:21:49 +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 "
2021-04-03 19:21:49 +02:00
elif ( arg & 0xFF000000 ) == 0x80000000 :
2020-10-31 03:28:18 +01:00
return f " 0x { arg : X } "
2021-04-03 19:21:49 +02:00
elif arg > = 0x80000000 :
return f " { arg - 0x100000000 } "
2020-10-31 03:28:18 +01:00
else :
return f " { arg } "
2021-07-20 19:43:16 +02:00
# TODO: use map's collider names when split
def collider_id ( self , arg ) :
if arg > = 0x4000 and arg < = 0x5000 :
return f " entity( { arg - 0x4000 } ) "
else :
return 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 )
2021-04-03 19:21:49 +02:00
2021-03-29 02:05:56 +02:00
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
2021-07-12 14:06:00 +02:00
if case and " handleEvent " in self . script_name and var in CONSTANTS [ " Events " ] :
return CONSTANTS [ " Events " ] [ var ]
elif case and " takeTurn " in self . script_name and var in CONSTANTS [ " HitResults " ] :
return CONSTANTS [ " HitResults " ] [ var ]
elif ( ( case and self . case_variable == " STORY_PROGRESS " ) or
2021-03-30 05:39:17 +02:00
( not case and self . save_variable == " STORY_PROGRESS " ) ) :
if var in CONSTANTS [ " StoryProgress " ] :
return CONSTANTS [ " StoryProgress " ] [ var ]
2021-04-03 19:21:49 +02:00
elif ( ( case and self . case_variable == " WORLD_LOCATION " ) or
2021-03-30 05:39:17 +02:00
( 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 ) :
2021-04-03 19:21:49 +02:00
# hacky hacky
if opcode == 0x43 and len ( argv ) > 1 and argv [ - 1 ] == 0x80000000 :
argv [ - 1 ] = " MAKE_ENTITY_END "
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
2021-04-22 05:19:31 +02:00
if ( ( self . in_case and 0x16 < = opcode < = 0x1B and self . case_variable == " STORY_PROGRESS " ) or
2021-03-30 05:39:17 +02:00
( 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
2021-04-03 19:21:49 +02:00
self . INCLUDED [ " functions " ] . add ( self . script_name )
2020-10-31 03:28:18 +01:00
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 ( " } " )
2021-04-03 19:21:49 +02:00
elif opcode == 0x07 : self . write_line ( f " break loop; " )
2020-12-24 12:15:05 +01:00
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-07-12 14:06:00 +02:00
self . write ( f " == { self . replace_enum ( argv [ 0 ] , True ) } " )
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-07-12 14:06:00 +02:00
self . write ( f " != { self . replace_enum ( argv [ 0 ] , True ) } " )
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-07-12 14:06:00 +02:00
self . write ( f " < { self . replace_enum ( argv [ 0 ] , True ) } " )
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-07-12 14:06:00 +02:00
self . write ( f " > { self . replace_enum ( argv [ 0 ] , True ) } " )
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-07-12 14:06:00 +02:00
self . write ( f " <= { self . replace_enum ( argv [ 0 ] , True ) } " )
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-07-12 14:06:00 +02:00
self . write ( f " >= { self . replace_enum ( argv [ 0 ] , True ) } " )
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 " :
2021-07-12 14:06:00 +02:00
self . out + = f " , { self . replace_enum ( argv [ 0 ] , True ) } "
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 :
2021-07-12 14:06:00 +02:00
self . write ( f " { self . replace_enum ( argv [ 0 ] , True ) } " )
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 " )
2021-07-12 14:06:00 +02:00
self . write_line ( f " ? { self . replace_enum ( argv [ 0 ] , True ) } " )
2020-11-08 16:35:41 +01:00
elif opcode == 0x20 :
2021-07-20 19:43:16 +02:00
#if not self.was_multi_case:
# raise UnsupportedScript("unexpected END_MULTI_CASE")
pass
2020-11-08 13:16:10 +01:00
elif opcode == 0x21 :
2021-07-20 19:43:16 +02:00
self . case_stack . append ( " CASE " )
self . write ( f " { self . replace_enum ( argv [ 0 ] , True ) } ... { self . replace_enum ( argv [ 1 ] , True ) } " )
2021-04-03 19:21:49 +02:00
elif opcode == 0x22 : self . write_line ( " break match; " )
2020-11-08 13:16:10 +01:00
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-04-03 19:21:49 +02:00
elif opcode == 0x24 :
2021-03-29 02:05:56 +02:00
varA = self . replace_enum ( argv [ 0 ] )
varB = self . replace_enum ( argv [ 1 ] )
2021-04-03 19:21:49 +02:00
if varB . startswith ( " script_ " ) :
varB = " N( " + varB + " ) "
2021-03-29 02:05:56 +02:00
self . write_line ( f " { varA } = { varB } ; " )
2021-07-12 14:06:00 +02:00
elif opcode == 0x25 :
varA = self . replace_enum ( argv [ 0 ] )
argNum = argv [ 1 ]
sprite = ( argNum & 0xFF0000 ) >> 16
palette = ( argNum & 0xFF00 ) >> 8
anim = ( argNum & 0xFF ) >> 0
call = make_anim_macro ( self , sprite , palette , anim )
if " 0x " in call :
call = self . var ( argNum )
self . write_line ( f " { varA } = (const) { call } ; " )
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 :
2021-07-12 14:06:00 +02:00
self . write_line ( f " { self . var ( argv [ 0 ] ) } = (float) { lhs } ; " )
2020-12-24 12:15:05 +01:00
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 :
2021-04-28 10:58:21 +02:00
self . write_line ( f " { self . var ( argv [ 0 ] ) } += (float) { 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 :
2021-04-28 10:58:21 +02:00
self . write_line ( f " { self . var ( argv [ 0 ] ) } -= (float) { 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 :
2021-04-28 10:58:21 +02:00
self . write_line ( f " { self . var ( argv [ 0 ] ) } *= (float) { 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 :
2021-04-28 10:58:21 +02:00
self . write_line ( f " { self . var ( argv [ 0 ] ) } /= (float) { lhs } ; " )
2021-07-20 19:43:16 +02:00
elif opcode == 0x30 : self . write_line ( f " buf_use { self . addr_ref ( argv [ 0 ] ) } ; " )
elif opcode == 0x31 : self . write_line ( f " buf_read { self . var ( argv [ 0 ] ) } ; " )
elif opcode == 0x32 : self . write_line ( f " buf_read { self . var ( argv [ 0 ] ) } { self . var ( argv [ 1 ] ) } ; " )
elif opcode == 0x33 : self . write_line ( f " buf_read { self . var ( argv [ 0 ] ) } { self . var ( argv [ 1 ] ) } { self . var ( argv [ 2 ] ) } ; " )
elif opcode == 0x34 : self . write_line ( f " buf_read { self . var ( argv [ 0 ] ) } { self . var ( argv [ 1 ] ) } { self . var ( argv [ 2 ] ) } { self . var ( argv [ 3 ] ) } ; " )
elif opcode == 0x35 : self . write_line ( f " buf_peek { self . var ( argv [ 0 ] ) } { self . var ( argv [ 1 ] ) } ; " )
elif opcode == 0x36 : self . write_line ( f " buf_usef { self . var ( argv [ 0 ] ) } ; " )
elif opcode == 0x37 : self . write_line ( f " buf_readf { self . var ( argv [ 0 ] ) } ; " )
elif opcode == 0x38 : self . write_line ( f " buf_readf { self . var ( argv [ 0 ] ) } { self . var ( argv [ 1 ] ) } ; " )
elif opcode == 0x39 : self . write_line ( f " buf_readf { self . var ( argv [ 0 ] ) } { self . var ( argv [ 1 ] ) } { self . var ( argv [ 2 ] ) } ; " )
elif opcode == 0x3A : self . write_line ( f " buf_readf { self . var ( argv [ 0 ] ) } { self . var ( argv [ 1 ] ) } { self . var ( argv [ 2 ] ) } { self . var ( argv [ 3 ] ) } ; " )
elif opcode == 0x3B : self . write_line ( f " buf_peekf { self . var ( argv [ 0 ] ) } { self . var ( argv [ 1 ] ) } ; " )
elif opcode == 0x3C : self . write_line ( f " arr_use { self . addr_ref ( argv [ 0 ] ) } ; " )
elif opcode == 0x3D : self . write_line ( f " flags_use { self . addr_ref ( argv [ 0 ] ) } ; " )
elif opcode == 0x3E : self . write_line ( f " arr_new { self . var ( argv [ 0 ] ) } { self . addr_ref ( argv [ 1 ] ) } ; " )
2020-12-24 12:15:05 +01:00
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 ] ) } ; " )
2021-04-28 10:58:21 +02:00
elif opcode == 0x41 : self . write_line ( f " { self . var ( argv [ 0 ] ) } &= (const) 0x { argv [ 1 ] : X } ; " )
elif opcode == 0x42 : self . write_line ( f " { self . var ( argv [ 0 ] ) } |= (const) 0x { 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-04-03 19:21:49 +02:00
func_name = self . addr_ref ( addr )
for i , arg in enumerate ( argv ) :
2021-04-29 19:09:30 +02:00
argv [ i ] = self . replace_star_rod_prefix ( arg , isArg = True )
2021-02-04 16:35:34 +01:00
argv_str = " , " . join ( self . var ( arg ) for arg in argv [ 1 : ] )
2021-04-03 19:21:49 +02:00
argv_str = replace_constants ( self , func_name , argv_str )
2021-03-24 09:39:43 +01:00
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 )
2021-04-08 19:42:36 +02:00
elif opcode == 0x44 :
name = self . addr_ref ( argv [ 0 ] )
if name . startswith ( " N( " ) :
self . INCLUDED [ " functions " ] . add ( name )
self . write_line ( f " spawn { name } ; " )
2020-12-24 12:15:05 +01:00
elif opcode == 0x45 : self . write_line ( f " { self . var ( argv [ 1 ] ) } = spawn { self . addr_ref ( argv [ 0 ] ) } ; " )
2021-04-08 19:42:36 +02:00
elif opcode == 0x46 :
name = self . addr_ref ( argv [ 0 ] )
if name . startswith ( " N( " ) :
self . INCLUDED [ " functions " ] . add ( name )
self . write_line ( f " await { name } ; " )
2020-10-31 03:28:18 +01:00
elif opcode == 0x47 :
assert argv [ 3 ] == 1
if argv [ 4 ] != 0 :
2021-07-20 19:43:16 +02:00
self . write_line ( f " { self . var ( argv [ 4 ] ) } = bind { self . addr_ref ( argv [ 0 ] ) } { self . trigger ( argv [ 1 ] ) } { self . collider_id ( argv [ 2 ] ) } ; " )
2020-10-31 03:28:18 +01:00
else :
2021-07-20 19:43:16 +02:00
self . write_line ( f " bind { self . addr_ref ( argv [ 0 ] ) } { self . trigger ( argv [ 1 ] ) } { self . collider_id ( argv [ 2 ] ) } ; " )
2020-12-24 12:15:05 +01:00
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 ] ) } ; " )
2021-07-20 19:43:16 +02:00
elif opcode == 0x4B : self . write_line ( f " priority ( { self . var ( argv [ 0 ] ) } ; " )
elif opcode == 0x4C : self . write_line ( f " timescale { self . var ( argv [ 0 ] ) } ; " )
2020-12-24 12:15:05 +01:00
elif opcode == 0x4D : self . write_line ( f " group { self . var ( argv [ 0 ] ) } ; " )
2021-07-20 19:43:16 +02:00
elif opcode == 0x4E :
assert argv [ 4 ] == 0
assert argv [ 5 ] == 1
self . write_line ( f " bind_padlock { self . addr_ref ( argv [ 0 ] ) } { self . trigger ( argv [ 1 ] ) } { self . collider_id ( argv [ 2 ] ) } { self . addr_ref ( argv [ 3 ] ) } ; " )
2020-12-24 12:15:05 +01:00
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 ] ) } ; " )
2021-07-20 19:43:16 +02:00
elif opcode == 0x55 : self . write_line ( f " { self . var ( argv [ 1 ] ) } = does_script_exist { 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-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-03-29 02:05:56 +02:00
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 :
2021-04-03 19:21:49 +02:00
gap = False
first_print = False
2021-04-29 19:09:30 +02:00
2021-03-29 02:05:56 +02:00
while args . offset < args . end :
f . seek ( args . offset )
2021-04-29 19:09:30 +02:00
script = ScriptDSLDisassembler ( f , " " , { } , 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-04-03 19:21:49 +02:00
if script . instructions > 1 and " SI_CMD " not in script_text :
if gap and first_print :
potential_struct_sizes = { " StaticNpc " : 0x1F0 , " NpcAISettings " : 0x30 , " NpcSettings " : 0x2C , " NpcGroupList " : 0xC }
gap_size = args . offset - gap_start
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
print ( f " ========== 0x { gap_size : X } byte gap ( { potential_count } { potential_struct } ?) 0x { gap_start : X } - 0x { args . offset : X } ========== " )
print ( )
gap = False
#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()
vram = f " { args . vram : X } _ " if vram_base > 0 else f " "
script_text = script_text . replace ( " Script script = SCRIPT( { " , f " Script N(D_ { vram } { args . offset : X } ) = " + " SCRIPT( { " )
2021-03-30 05:39:17 +02:00
print ( script_text , end = " " )
print ( )
#print(f"Valid script found at 0x{args.offset:X}")
2021-04-03 19:21:49 +02:00
args . vram + = script . end_pos - args . offset
2021-03-29 02:05:56 +02:00
args . 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 :
gap_start = args . offset
gap = True
2021-03-29 02:05:56 +02:00
args . 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 :
gap_start = args . offset
gap = True
2021-03-29 02:05:56 +02:00
args . 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-03-29 02:05:56 +02:00
f . seek ( args . offset )
2020-10-19 23:58:57 +02:00
2021-04-29 19:09:30 +02:00
script = ScriptDSLDisassembler ( f , " " , { } , 0x978DE0 , INCLUDES_NEEDED , INCLUDED )
2020-10-19 23:58:57 +02:00
2021-04-29 19:09:30 +02:00
if args . si :
print ( ScriptDisassembler ( f , " " , { } , 0x978DE0 , INCLUDES_NEEDED , INCLUDED ) . disassemble ( ) , end = " " )
else :
try :
script_text = script . disassemble ( )
2020-10-31 03:28:18 +01:00
2021-04-29 19:09:30 +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 = " " )
except UnsupportedScript :
f . seek ( args . offset )
print ( ScriptDisassembler ( f ) . disassemble ( ) , end = " " )