Punkline
Dr. Frankenstack
- Joined
- May 15, 2015
- Messages
- 423
This code allows [1C] “Subroutine” and [14] “Goto” subaction events to be written freely within any Player, Item, or Color subaction that is contained within a DAT file.
Normally, using Crazy Hand to insert these navigation events into a moveset subaction would require modifying the file’s relocation table. With this code installed however, file data offsets used by Subroutines and Gotos that are not already in the relocation table will become relocated on their first use.
This means that moveset strings can now reach any part of the file without even touching the relocation table.
Get the code here:
To give yourself more room for writing new subaction events, open a character file in a hex editor, and add bytes to the end of it. When you have all the bytes you need, write the number of bytes of the new file size into the first 32 bits of the file header:
Then, the bytes you’ve added may be accessed using any of the following opcodes in Crazy Hand:
[1C] = “Subroutine” goes to a new file data offset.
[14] = “GoTo” goes to a new file data offset, and memorizes where it came from.
- only 5 return addresses may be memorized without overflowing the memory stack.
Note that the vanilla syntax uses a file data offset -0x20 for its input:
Also included is a new shorthand navigation syntax that can be used to interpret literal file data offsets as though they were opcodes:
[00] = Subroutine shorthand (not relocated)
[01] = GoTo shorthand (not relocated)
On first use, [00] and [01] events relocate their given file data offset and record the resulting RAM address as one of the following:
[02] = Subroutine shorthand (absolute RAM address)
[03] = Goto shorthand (absolute RAM address)
Though they are intended to be written at run-time; these [02] and [03] events may still be written out in Crazy Hand as a way of reaching static RAM addresses, if desired.
Addresses are packed into 23-bits by shifting right by >>2 and ANDing by 0x007FFFFF.
The opcode may then be ORed onto the shifted address.
The example address used in the above screenshot points to mytoc slot 1, which might be useful for the sake of creating programmable destinations.
---
Edit: because of the fact that these new shorthand syntaxes are only 4 bytes in length, they can also be used to override vanilla navigation events without requiring any modifications to the original relocation offset.
I’ll be including this code in a much broader patch for the subaction event system sometime soon. Let me know if anyone finds any bugs, has any questions, or any suggestions.
The Cape Itaru UnclePunch DRGN Yakult TDRR
Normally, using Crazy Hand to insert these navigation events into a moveset subaction would require modifying the file’s relocation table. With this code installed however, file data offsets used by Subroutines and Gotos that are not already in the relocation table will become relocated on their first use.
This means that moveset strings can now reach any part of the file without even touching the relocation table.
Get the code here:
Code:
-==-
Modified Navigation Subaction Events
- [00] XXXXXX = Subroutine at file data offset X
- [01] XXXXXX = Goto file data offset X
Offset X is a literal file data offset.
No file reloaction entries are required.
File relocation entries for [14] and [1C] become optional.
[Punkline]
1.02 ----- 0x803b9840 --- 80005940 -> 804DC748
1.02 ----- 0x80276BE4 --- C842CD68 -> C84280A0
1.02 ----- 0x80276AE0 --- C842CD68 -> C84280A0
1.02 ----- 0x802769D4 --- C862CD68 -> C86280A0
1.02 ----- 0x8027686C --- C842CD68 -> C84280A0
1.02 ----- 0x80276764 --- C842CD68 -> C84280A0
1.02 ----- 0x80276654 --- C862CD68 -> C86280A0
1.02 ----- 0x80276590 --- C842CD68 -> C84280A0
1.02 ----- 0x804DC748 --- 43300000 -> Branch
81630008 800B0000 2C000000 41A20008
b <SAE_navigation_syntax>
b 0x80005940
60000000
<SAE_navigation_syntax> 1.02
7C0802A6 90010004 9421FFE0 BFA10010 7FE00026 7C7D1B78 809D0008 8004FFFC 3CA01C00 7C002800 3CA01400 7C802800 80A40000 54A6C39E 54BE023E 7CC10120 4DA23382 418D0034 40AF0020 811D000C 38080001 901D000C 39240004 5500103A 7D1D0214 91280010 88040000 60080002 99040000 41AE003C 7C832378
bl <datIdentifyEx>
2C060000 41A00010 38000000 90030000
b 0x80005940
7CBE3A14 418D0020 7CBE3214 54BEF23E 80A30000 53C5023E 90A30000 57C0103A 64058000 90BD0008 7FEFF120 BBA10010 38210020 80010004 7C0803A6 4E800020
<datIdentifyEx> All
7C0802A6 90010004 9421FFE0 BFC10010 4FFFF982 7C7E1B79 40800094 3FE08043 63FF2124 38000050 7C0903A6 A87F0008 2C03270F 40A2005C A87F0006 2C03FFFF 40810050 809F0014 2C040000 41820044 80840004 80640040 2C030000 41820034 7C1E1800 41A0002C 80A40000 7C651A14 7C1E1800 41A1001C 7FE5FB78 80C40040 7D06F050 80E40020 7D27F050 48000038 3BFF001C 401FFF98 419F0014 4FFFF842 8002CDB8 7C040379 4180FFAC 38800000 38A00000 38C00000 38E00000 39000000 39200000 7FC3F378 BBC10010 38210020 80010004 7C0803A6 4E800020
1.02 ----- 80005af8 --- 90030008 -> Branch
b <SAE_navigation_handle_vanilla_ops>
60000000 00000000
1.02 ----- 80005abc --- 90030008 -> Branch
b <SAE_navigation_handle_vanilla_ops>
60000000 00000000
<SAE_navigation_handle_vanilla_ops> All
2C000000 41A00008
b <SAE_navigation_syntax>
90030008 4E800020
<EOS_hooks> All
4E800021
b <EOS_PlCo_pointer>
# this hook is responsible for clearing the PlCo header object pointer on scene changes
# <-- additional hooks may be placed here
00000000
1.02 ----- 801a4268 --- bb21001c -> Branch
7C791B78
bl <EOS_event>
7F23CB78 BB21001C 00000000
<EOS_event> All
7C0802A6 90010004 9421EF00 BE011000 7C000026 90011080 48000019 7C0802A6 900110F0
bl <EOS_hooks>
7FE802A6 48000010 4E800021 83E110EC 3BFF0004 801F0000 2C000000 41820010 93E110EC 7FE903A6 4E800420 80011080 7C0FF120 BA011000 38211100 80010004 7C0803A6 4E800020
<EOS_continue> All
800110F0 7C0903A6 4E800420
1.02 ----- 8038033c --- 8001002c -> Branch
93C2CDBC 8001002C 00000000
1.02 ----- 80067ae8 --- 80610008 -> Branch
8062CDBC 9062CDB8 80610008 00000000
1.02 ----- 80279608 --- C822CDB8 -> C8228000
1.02 ----- 80279574 --- C842CDB8 -> C8428000
1.02 ----- 8027920C --- C822CDB8 -> C8228000
1.02 ----- 802791B4 --- C842CDB8 -> C8428000
1.02 ----- 80278F5C --- C822CDB8 -> C8228000
1.02 ----- 804DC798 --- 4330000000000000 -> 0000000000000000
<EOS_PlCo_pointer> All
38000000 9002CDB8
b <EOS_continue>
#
Code:
-==-
!
ASM - Modified Navigation Subaction Events
- [00] XXXXXX = Subroutine at file data offset X
- [01] XXXXXX = Goto file data offset X
Offset X is a literal file data offset.
No file reloaction entries are required.
File relocation entries for [14] and [1C] become optional.
[Punkline]
1.02 ----- 0x803b9840 --- 80005940 -> 804DC748
# change target callback of [00] control event pointer
1.02 ----- 0x80276BE4 --- C842CD68 -> C84280A0
1.02 ----- 0x80276AE0 --- C842CD68 -> C84280A0
1.02 ----- 0x802769D4 --- C862CD68 -> C86280A0
1.02 ----- 0x8027686C --- C842CD68 -> C84280A0
1.02 ----- 0x80276764 --- C842CD68 -> C84280A0
1.02 ----- 0x80276654 --- C862CD68 -> C86280A0
1.02 ----- 0x80276590 --- C842CD68 -> C84280A0
1.02 ----- 0x804DC748 --- 43300000 -> Branch
# mytoc 266: -0x3298(rtoc) = 804DC748
# pointer for control event [00] targets this static address
# r3 = event controller
lwz r11, 0x8(r3)
lwz r0, 0(r11)
cmpwi r0, 0
beq+ _default
# check to see if word is null
b <SAE_navigation_syntax>
# if word isn't null, then opcode + input qualifies for shorthand goto/subroutine syntax
_default:
b 0x80005940
# else default to vanilla termination event
nop
<SAE_navigation_syntax> 1.02
# r3 = event controller:
# handles [00] [01] [02] [03] [14] and [1C] events
# [1C] and [14] are only handled if their file offsets have not been relocated
# [00] and [01] are converted into [02] and [03] events
# [02] and [03] unpack a RAM address and then act like [1C] and [14]
# bools:
.set bVanillaSyntax, 13 # cr3
.set bRelocated, 14
.set bSetReturn, 15
mflr r0
stw r0, 0x4(sp)
stwu sp, -0x20(sp)
stmw r29, 0x10(sp)
mfcr r31
mr r29, r3
# backup CR so that we can use saved bools
# r29 = this event controller
lwz r4, 0x8(r29)
lwz r0, -0x4(r4)
lis r5, 0x1C00
cmpw cr0, r0, r5
lis r5, 0x1400
cmpw cr1, r0, r5
# check for vanilla syntax with cr0, cr1 comparisons
lwz r5, 0x0(r4)
rlwinm r6, r5, 24, 0x30000
# align bRelocated and bSetReturn to cr3
rlwinm r30, r5, 0, 0xFFFFFF
# extract file or RAM pointer as masked input
mtcrf 0b00010000, r6
cror bVanillaSyntax, eq, eq+4
# bools have been set
# r5 = input, unmasked
# r30 = input, masked
bt- bVanillaSyntax, _relocate_file_pointer
_check_input:
bf+ bSetReturn, _update_relocation_bit
_set_return:
lwz r8, 0xC(r29)
addi r0, r8, 1
stw r0, 0xC(r29)
# update controller stack word pointer
addi r9, r4, 4
slwi r0, r8, 2
add r8, r29, r0
stw r9, 0x10(r8)
# store return pointer in controller stack
_update_relocation_bit:
# format the pointer so that it can fit into the 24-bit input
lbz r0, 0x0(r4)
ori r8, r0, 0x2
stb r8, 0x0(r4)
# bit is written to file data in RAM.
# this causes relocation behavior to only trigger once
bt+ bRelocated, _unpack_RAM_pointer
# if this input has already been relocated, we unpack the relocation address
# else, this is the first time reading this event, so we relocate the file data offset
_relocate_file_pointer:
mr r3, r4
# r3 = address of this event data word
bl <datIdentifyEx>
# r3 = address of this event data word
# r4 = file header object
# r5 = alloc index element
# r6 = file base address
# r7 = relocation base address
# r8 = file offset
# r9 = relocation offset
cmpwi r6, 0
blt+ _commit_to_relocation
# if given address does not belong to a recognizable file
_bad_address:
li r0, 0
stw r0, 0x0(r3)
b 0x80005940
# then nullify word, and branch to default termination event
_commit_to_relocation:
add r5, r30, r7
bt- bVanillaSyntax, _update_event_pointer
# if this is a vanilla syntax, then we don't need to compress the pointer
_pack_navigation_shorthand:
add r5, r30, r6
rlwinm r30, r5, 30, 0xFFFFFF
lwz r5, 0x0(r3)
rlwimi r5, r30, 0, 0xFFFFFF
stw r5, 0x0(r3)
# else, pack compressed RAM pointer into navigation syntax
_unpack_RAM_pointer:
slwi r0, r30, 2
oris r5, r0, 0x8000
# <<2, and insert 0x80000000 bit
_update_event_pointer:
stw r5, 0x8(r29)
# update event pointer
_return:
mtcr r31
lmw r29, 0x10(sp)
addi sp, sp, 0x20
lwz r0, 0x4(sp)
mtlr r0
blr
<datIdentifyEx> All
# r3 = any address
# checks if input address is in range of any active dat file allocations
# - this variation of datIdentify checks for a PlCo exception if no match is found
# returns:
# r3 = unchanged
# r4 = file header object
# r5 = alloc index element
# r6 = file base address
# r7 = relocation base address
# r8 = file offset
# r9 = relocation offset
# addresses:
.set allocIndexAddr, 0x80432124
# dat allocation object offsets:
.set xEntrynum, 6
.set xStatus, 8
.set xHeaderObjectLink, 0x14
# header object link offsets:
.set xHeaderObject, 4
# header object offsets:
.set xFileSize, 0
.set xRelocBase, 0x20
.set xFileStart, 0x40
# mytoc offsets:
.set xPlCo, -0x3248
# bools:
.set bCheckedPlCo, 31
_code_start:
mflr r0
stw r0, 0x4(sp)
stwu sp, -0x20(sp)
stmw r30, 0x10(sp)
crclr bCheckedPlCo
# bit 31 in cr7 holds status of exception check
# function is a leaf, so volatile cr will still be useful
mr. r30, r3 # r30 = input query
bge- _return_null
# if given query is not an address, then return null
lis r31, allocIndexAddr @h
ori r31, r31, allocIndexAddr @l # r31 = loop index address
li r0, 80 # for each of 80 allocation slots...
mtctr r0
# else, setup CTR loop for parsing dat allocation index for header objects
_loop:
lha r3, xStatus(r31)
cmpwi r3, 9999
bne+ _iter_loop
# if alloc status == 9999
lha r3, xEntrynum(r31)
cmpwi r3, -1
ble- _iter_loop
# and entrynum is valid
_get_header_object:
lwz r4, xHeaderObjectLink(r31)
cmpwi r4, 0
beq- _iter_loop
lwz r4, xHeaderObject(r4)
# r4 = header object
_header_object_in_r4:
lwz r3, xFileStart(r4)
cmpwi r3, 0
beq- _iter_loop
# and header object isn't null
cmpw r30, r3
blt+ _iter_loop
# and query > low limit
lwz r5, xFileSize(r4)
add r3, r5, r3
cmpw r30, r3
bgt+ _iter_loop
# and query < high limit:
# then we have a matching header object.
_match:
mr r5, r31
lwz r6, xFileStart(r4)
sub r8, r30, r6
lwz r7, xRelocBase(r4)
sub r9, r30, r7
b _return
# r4 = file header object
# r5 = alloc index element
# r6 = file base address
# r7 = relocation base address
# r8 = file offset
# r9 = relocation offset
_iter_loop:
addi r31, r31, 0x1C
bdnzf+ bCheckedPlCo, _loop
# else if decremented CTR > 0 AND bCheckedPlCo is false, then iterate loop
# else no match was found in allocation index.
_no_match:
bt- bCheckedPlCo, _return_null
# if PlCo exception has not been checked:
_PlCo_exception:
crnot bCheckedPlCo, bCheckedPlCo
# invert bit, so check is only made once
# this also disables the CTR iteration in loop
lwz r0, xPlCo(rtoc)
mr. r4, r0
blt+ _header_object_in_r4
# if PlCo header object pointer exists, use it for final check before giving up on query
_return_null:
li r4,0
li r5,0
li r6,0
li r7,0
li r8,0
li r9,0
# any returned value aside from r3 can be checked for null
_return:
mr r3, r30 # r3 = (unchanged query)
lmw r30, 0x10(sp)
addi sp, sp, 0x20
lwz r0, 0x4(sp)
mtlr r0
blr
1.02 ----- 80005af8 --- 90030008 -> Branch
b <SAE_navigation_handle_vanilla_ops>
nop
.long 0 # 1C injection
1.02 ----- 80005abc --- 90030008 -> Branch
b <SAE_navigation_handle_vanilla_ops>
nop
.long 0 # 14 injection
<SAE_navigation_handle_vanilla_ops> All
cmpwi r0, 0
blt+ _default
# if file data offset has already been relocated,
# then use default behavior.
b <SAE_navigation_syntax>
# else, we are going to branch to navigation syntax
# -- this is a hard branch, so function blr returns from default, which is a leaf
_default:
stw r0, 0x0008 (r3)
blr
<EOS_hooks> All
4E800021
b <EOS_PlCo_pointer>
# this hook is responsible for clearing the PlCo header object pointer on scene changes
# <-- additional hooks may be placed here
00000000
1.02 ----- 801a4268 --- bb21001c -> Branch
7C791B78
bl <EOS_event>
7F23CB78 BB21001C 00000000
<EOS_event> All
7C0802A6 90010004 9421EF00 BE011000 7C000026 90011080 48000019 7C0802A6 900110F0
bl <EOS_hooks>
7FE802A6 48000010 4E800021 83E110EC 3BFF0004 801F0000 2C000000 41820010 93E110EC 7FE903A6 4E800420 80011080 7C0FF120 BA011000 38211100 80010004 7C0803A6 4E800020
<EOS_continue> All
800110F0 7C0903A6 4E800420
1.02 ----- 8038033c --- 8001002c -> Branch
93C2CDBC 8001002C 00000000
1.02 ----- 80067ae8 --- 80610008 -> Branch
8062CDBC 9062CDB8 80610008 00000000
1.02 ----- 80279608 --- C822CDB8 -> C8228000
1.02 ----- 80279574 --- C842CDB8 -> C8428000
1.02 ----- 8027920C --- C822CDB8 -> C8228000
1.02 ----- 802791B4 --- C842CDB8 -> C8428000
1.02 ----- 80278F5C --- C822CDB8 -> C8228000
1.02 ----- 804DC798 --- 4330000000000000 -> 0000000000000000
<EOS_PlCo_pointer> All
38000000 9002CDB8
b <EOS_continue>
#
To give yourself more room for writing new subaction events, open a character file in a hex editor, and add bytes to the end of it. When you have all the bytes you need, write the number of bytes of the new file size into the first 32 bits of the file header:
Then, the bytes you’ve added may be accessed using any of the following opcodes in Crazy Hand:
[1C] = “Subroutine” goes to a new file data offset.
[14] = “GoTo” goes to a new file data offset, and memorizes where it came from.
- only 5 return addresses may be memorized without overflowing the memory stack.
Note that the vanilla syntax uses a file data offset -0x20 for its input:
Also included is a new shorthand navigation syntax that can be used to interpret literal file data offsets as though they were opcodes:
[00] = Subroutine shorthand (not relocated)
[01] = GoTo shorthand (not relocated)
On first use, [00] and [01] events relocate their given file data offset and record the resulting RAM address as one of the following:
[02] = Subroutine shorthand (absolute RAM address)
[03] = Goto shorthand (absolute RAM address)
Though they are intended to be written at run-time; these [02] and [03] events may still be written out in Crazy Hand as a way of reaching static RAM addresses, if desired.
Addresses are packed into 23-bits by shifting right by >>2 and ANDing by 0x007FFFFF.
The opcode may then be ORed onto the shifted address.
The example address used in the above screenshot points to mytoc slot 1, which might be useful for the sake of creating programmable destinations.
---
Edit: because of the fact that these new shorthand syntaxes are only 4 bytes in length, they can also be used to override vanilla navigation events without requiring any modifications to the original relocation offset.
I’ll be including this code in a much broader patch for the subaction event system sometime soon. Let me know if anyone finds any bugs, has any questions, or any suggestions.
The Cape Itaru UnclePunch DRGN Yakult TDRR
Last edited: