From 0c2b92125f9125dff02b78badc968d0b171014ea Mon Sep 17 00:00:00 2001 From: petrie911 <69443847+petrie911@users.noreply.github.com> Date: Wed, 9 Dec 2020 18:39:32 -0600 Subject: [PATCH] New tool: sfxconvert (#514) * Darkmeiro decompilation Bg_Gnd_Darkmeiro decompiled, matched, and documented. * give this a shot * fix conflict * one more try * could be useful * whoops * ZAP2 stuff * ZAP why * ZAP again * new tool * python function conventions * new name * new error handling * whoops comments --- .../ovl_Bg_Ganon_Otyuka/z_bg_ganon_otyuka.c | 2 +- src/overlays/actors/ovl_Demo_Gt/z_demo_gt.c | 4 +- src/overlays/actors/ovl_En_Ru1/z_en_ru1.c | 10 +- .../actors/ovl_Obj_Kibako/z_obj_kibako.c | 2 +- tools/sfxconvert.py | 176 ++++++++++++++++++ 5 files changed, 185 insertions(+), 9 deletions(-) create mode 100644 tools/sfxconvert.py diff --git a/src/overlays/actors/ovl_Bg_Ganon_Otyuka/z_bg_ganon_otyuka.c b/src/overlays/actors/ovl_Bg_Ganon_Otyuka/z_bg_ganon_otyuka.c index d7d473b343..0a4c528b4d 100644 --- a/src/overlays/actors/ovl_Bg_Ganon_Otyuka/z_bg_ganon_otyuka.c +++ b/src/overlays/actors/ovl_Bg_Ganon_Otyuka/z_bg_ganon_otyuka.c @@ -245,7 +245,7 @@ void BgGanonOtyuka_Fall(BgGanonOtyuka* this, GlobalContext* globalCtx) { } func_80033DB8(globalCtx, 10, 15); - Audio_PlaySoundAtPosition(globalCtx, &this->dyna.actor.posRot.pos, 0x28, 0x2839); + Audio_PlaySoundAtPosition(globalCtx, &this->dyna.actor.posRot.pos, 0x28, NA_SE_EV_BOX_BREAK); } Actor_Kill(&this->dyna.actor); } diff --git a/src/overlays/actors/ovl_Demo_Gt/z_demo_gt.c b/src/overlays/actors/ovl_Demo_Gt/z_demo_gt.c index 67857cac4e..96f8d2485e 100644 --- a/src/overlays/actors/ovl_Demo_Gt/z_demo_gt.c +++ b/src/overlays/actors/ovl_Demo_Gt/z_demo_gt.c @@ -1444,7 +1444,7 @@ void func_809818FC(DemoGt* this, GlobalContext* globalCtx) { u16 frames = globalCtx->csCtx.frames; if (frames == 845) { - func_80078914(&this->dyna.actor.projectedPos, 0x20DE); + func_80078914(&this->dyna.actor.projectedPos, NA_SE_EV_TOWER_PARTS_BROKEN - SFX_FLAG); } } void func_80981930(DemoGt* this, GlobalContext* globalCtx) { @@ -1626,7 +1626,7 @@ void func_809820AC(DemoGt* this, GlobalContext* globalCtx) { u16 frames = globalCtx->csCtx.frames; if (frames == 154) { - func_80078914(&this->dyna.actor.projectedPos, 0x20DE); + func_80078914(&this->dyna.actor.projectedPos, NA_SE_EV_TOWER_PARTS_BROKEN - SFX_FLAG); } } diff --git a/src/overlays/actors/ovl_En_Ru1/z_en_ru1.c b/src/overlays/actors/ovl_En_Ru1/z_en_ru1.c index 88c1fbaab9..5244c1652d 100644 --- a/src/overlays/actors/ovl_En_Ru1/z_en_ru1.c +++ b/src/overlays/actors/ovl_En_Ru1/z_en_ru1.c @@ -585,7 +585,7 @@ void func_80AEBAFC(EnRu1* this) { void func_80AEBB3C(EnRu1* this) { if (func_800A56C8(&this->skelAnime, 5.0f)) { - func_80078914(&this->actor.projectedPos, 0x863); + func_80078914(&this->actor.projectedPos, NA_SE_PL_FACE_UP); } } @@ -595,13 +595,13 @@ void func_80AEBB78(EnRu1* this) { if ((((func_800A56C8(skelAnime, 4.0f)) || (func_800A56C8(skelAnime, 13.0f))) || (func_800A56C8(skelAnime, 22.0f))) || (func_800A56C8(skelAnime, 31.0f))) { - func_80078914(&this->actor.projectedPos, 0x839); + func_80078914(&this->actor.projectedPos, NA_SE_PL_SWIM); } } void func_80AEBBF4(EnRu1* this) { if (func_800A56C8(&this->skelAnime, 8.0f)) { - func_80078914(&this->actor.projectedPos, 0x873); + func_80078914(&this->actor.projectedPos, NA_SE_PL_SUBMERGE); } } @@ -856,7 +856,7 @@ void func_80AEC650(EnRu1* this) { s32 pad[2]; if (this->unk_280 == 0) { if ((func_800A56C8(&this->skelAnime, 2.0f)) || (func_800A56C8(&this->skelAnime, 7.0f))) { - func_80078914(&this->actor.projectedPos, 0x803); + func_80078914(&this->actor.projectedPos, NA_SE_PL_WALK_DIRT); } } } @@ -1926,7 +1926,7 @@ void func_80AEF40C(EnRu1* this) { if ((func_800A56C8(skelAnime, 2.0f)) || (func_800A56C8(skelAnime, 7.0f)) || (func_800A56C8(skelAnime, 12.0f)) || (func_800A56C8(skelAnime, 18.0f)) || (func_800A56C8(skelAnime, 25.0f)) || (func_800A56C8(skelAnime, 33.0f))) { - func_80078914(&this->actor.projectedPos, 0x803); + func_80078914(&this->actor.projectedPos, NA_SE_PL_WALK_DIRT); } } diff --git a/src/overlays/actors/ovl_Obj_Kibako/z_obj_kibako.c b/src/overlays/actors/ovl_Obj_Kibako/z_obj_kibako.c index 3d81f6fe42..dd89cdb94b 100644 --- a/src/overlays/actors/ovl_Obj_Kibako/z_obj_kibako.c +++ b/src/overlays/actors/ovl_Obj_Kibako/z_obj_kibako.c @@ -212,7 +212,7 @@ void ObjKibako_Idle(ObjKibako* this, GlobalContext* globalCtx) { void ObjKibako_SetupHeld(ObjKibako* this) { this->actionFunc = ObjKibako_Held; this->actor.room = -1; - func_8002F7DC(&this->actor, 0x878); + func_8002F7DC(&this->actor, NA_SE_PL_PULL_UP_WOODBOX); } void ObjKibako_Held(ObjKibako* this, GlobalContext* globalCtx) { diff --git a/tools/sfxconvert.py b/tools/sfxconvert.py new file mode 100644 index 0000000000..62928316b3 --- /dev/null +++ b/tools/sfxconvert.py @@ -0,0 +1,176 @@ +#!/usr/bin/env python3 + +import os +import argparse + +AudioFunctions = {} +Verbose = False +Verbose2 = False + +def set_verbose(v): + global Verbose + global Verbose2 + + Verbose = v + Verbose2 = v + return 1 + +def make_audio_dict(AudioFunctions, repo): + with open(repo + os.sep + 'include' + os.sep + 'functions.h','r') as funcfile: + funcdata = funcfile.readlines() + for i, line in enumerate(funcdata): + if(line.count('sfxId')): + funcname, argnum = get_func_data(funcdata,i) + if(funcname != None): + AudioFunctions[funcname] = argnum + return 1 + +def get_func_data(funcdata,i): + j = i + while(funcdata[j - 1].count(';') == 0): + j -= 1 + k = i + 1 + while(funcdata[k - 1].count(';') == 0): + k += 1 + prototype = "".join(funcdata[j:k]) + argdata = prototype.replace('(',',').replace(')',',').split(',') + funcname = argdata[0].split(' ')[1] + for x in range(len(argdata)): + if(argdata[x].count('sfxId')): + break; + if(x == len(argdata) - 1): + print('sfxId not found in ', funcname) + return None,-1 + return funcname, x - 1 + +def lookup_sfx(idnum, repo): + if(type(idnum) is int): + id = '0x' + format(idnum,'X') + elif(idnum.isnumeric()): + id = '0x' + format(int(idnum),'X') + else: + id = idnum + idfix,sfxFlag = fix_sfx_flag(id) + with open(repo + os.sep + 'include' + os.sep + 'sfx.h','r') as sfxfile: + for line in sfxfile: + if(line.count(idfix)): + return line.split(' ')[1] + sfxFlag + return 'INVALID_ID' + +def fix_sfx_flag(id): + if(id.endswith(' - SFX_FLAG')): + splitdata = id.split('-') + return splitdata[0].strip(), ' -' + splitdata[1] + if not(int(id,16) & 0x800): + newid = '0x' + format(int(id,16) + 0x800,'X') + sfxFlag = ' - SFX_FLAG' + else : + newid = id + sfxFlag = '' + return newid,sfxFlag + +def fix_sfx_func(sourcedata, i, j, repo): + data = ''.join(sourcedata[i:j]) + func = find_audio_func(data) + if(not func): + print('Function parse error at line', i) + return -3 + index = data.find(func) + argnum = AudioFunctions.get(func,-1) + if(argnum == -1 or index == -1): + print('Function lookup error at line', i, 'in', func) + return -1 + args = data[index:].replace('(',',').replace(')',',').split(',') + sfxId = args[argnum + 1].strip() + if(sfxId.count('NA_SE') != 0): + return 0 + newId = lookup_sfx(sfxId, repo) + if(newId == 'INVALID_ID'): + print('ID parse error at line', i, 'in', func) + return -2 + for k in range(i, j): + sourcedata[k] = sourcedata[k].replace(sfxId,newId) + if Verbose: + print('Replaced', sfxId, 'with', newId, 'in', func, 'at line', i + 1) + return 1 + +def find_audio_func(line): + audiofuncs = list(AudioFunctions.keys()) + for func in audiofuncs: + if(line.count(func)): + return func + return False + +def fix_sfx_all(repo): + global Verbose2 + + tv = Verbose2 + Verbose2 = False + + for subdir, dirs, files in os.walk(repo + os.sep + 'src'): + for filename in files: + if(filename.endswith('.c')): + file = subdir + os.sep + filename + fix_sfx(file, repo) + + Verbose2 = tv + return 1 + +def fix_sfx(file, repo, outfile = None): + if(outfile == None): + outfile = file + make_audio_dict(AudioFunctions, repo) + with open(file,'r',encoding='utf-8') as sourcefile: + sourcedata = sourcefile.readlines() + replacements = set() + j = 0 + lookuperrors = 0 + funcerrors = 0 + iderrors = 0 + fixes = 0 + for i, line in enumerate(sourcedata): + if(i < j): + continue + if(find_audio_func(line)): + if(line.count(';')): + j = i + 1 + else: + j = i + while(sourcedata[j].count(';') == 0): + j += 1 + status = fix_sfx_func(sourcedata, i, j + 1, repo) + if(status == -3): + funcerrors += 1 + elif(status == -2): + iderrors += 1 + elif(status == -1): + lookuperrors += 1 + elif(status > 0): + fixes += 1 + if(fixes > 0): + with open(outfile,'w',encoding ='utf-8',newline='\n') as outfile: + outfile.writelines(sourcedata) + if Verbose: + print(file, 'updated') + elif Verbose2: + print('No changes made to', file) + if(lookuperrors > 0): + print('Problem with function lookup. Try formatting functions.h') + if(funcerrors > 0): + print('Problem with function parsing. Encountering this message should be impossible, so please report that you did.') + if(iderrors > 0): + print('Problem with id parsing. Make sure your SFX ids are in hex.') + return 1 + +parser = argparse.ArgumentParser(description='Convert hex SFX ids to macros') +parser.add_argument('file', help="source file to be processed") +parser.add_argument('repo', help="directory of the decomp repo") +parser.add_argument('-o', metavar='outfile',dest='outfile',help='file to write to instead of original') +parser.add_argument('-v', action='store_true',help='show what changes are made') + +if __name__ == "__main__": + args = parser.parse_args() + set_verbose(args.v) + fix_sfx(args.file, args.repo, outfile=args.outfile) + +