Inserting ASM Hacks?

I’ve written a custom routine for FE8 that lets you have unlimited B-supports, but only 1 A-support. The only thing is that I don’t know the /proper/ way to insert it.

What I’ve ended up doing is repointing some graphics (triangle attack) and pasting the routine there, then going into the debugger, manually changing the bl that calls the old routine (I can’t overwrite the old routine because it’s used elsewhere) and copying the hex that it gives me back into the ROM.

My routine also uses some of the subroutines that the old one did, but I can’t use bl to call them unless I bl to some empty label and then change it manually in the debugger.

I can’t help but feel like there must be a better way to do this.

Here’s the messy but somehow functional code:
[spoiler=What the hell is FLARD]

.thumb
.org 0x00000000

@@ Only 1 A support hack (FE8)
@@ This hack checks to see if the character has an A support AND the target support is at B or higher.
@@ Make sure to repoint the PK Triangle Attack graphic that used to be at $E17C0

push {r4-r7,r14}

@@if r0 = r5 it's the first time around
@@if r0 = r4 it's checking the other character
cmp    r0,r5          @First time around
beq    CheckforASupport
eor    r4,r5
eor    r5,r4          @swap the registers around, then proceed as usual
eor    r4,r5

CheckforASupport:
mov     r7,r5         @r7 is now active char's data
mov     r6,r4         @r6 is now target's data
bl      CheckSupportNum    @get number of supported characters
mov     r5,r0         @store it in r5
mov     r4,#0x0       @r4 is number of characters looped
Loop:
mov     r0,r7         
mov     r1,r4         @passing in params r0:chardata, r1:support partner to check
bl      CheckSupportLev    @check the support with character
cmp     r0,#0x3       @is it A support?
beq     CheckforBSupport
add     r4,#0x1       @add 1 to loop counter
cmp     r4,r5         @time to end the loop?
blt     Loop

False:
mov     r0,#0x0       @return false
True:
pop     {r4-r7}
pop     {r1}
bx      r1

CheckforBSupport:
@@ r5 is still number of support partners
mov     r1,r6
ldr     r1,[r1]         @ r1 is pointer to target character data
ldrb    r1,[r1,#0x4]    @ r1 is now the target character ID
mov     r6,r1           @ put it back in r6, r1 is about to be clobbered
ldr     r2,[r7]         @r2 is the pointer to the character data
ldr     r2,[r2,#0x2C]   @r2 is the pointer to the support data
mov     r4,#0x0         @loop counter

Loop_2:
ldrb    r3,[r2,r4]      @nth character's id
cmp     r3,r6           @is it a match?
bne     NoMatch
mov     r0,r7           @passing in params
mov     r1,r4
bl      CheckSupportLev    @check the support with character
cmp     r0,#0x2         @is it B support?
blt     False           @if not, return false
mov     r0,#0x1         @if it is, then return true
b       True

NoMatch:
add     r4,#0x1         @add one to loop counter
cmp     r4,r5           @end of loop?
blt     Loop_2          @no
b       False           @yes

CheckSupportLev:        @Routine at 0x802823C, change this in the debugger
nop

CheckSupportNum:        @Routine at 0x80281C8, change in debugger
nop

[/spoiler]

2 Likes

why not just count it only if an A is found (counter + 1) and change the max from 5 to 1?

If you only count the number of A supports, it won’t let you raise C supports to B once you get an A support.

Fair enough

message me on skype if you want

Have a constant be the location of the subroutine(+1) then call it using this method.

1 Like

Right, that works within the custom routine, thanks.

Is there a good way to replace the initial bl OriginalRoutine with bl/bx CustomRoutine?

at the OriginalRoutine location, replace the code with a longcall to your code.

The routine is also called elsewhere, I only want to replace it when it’s checking for a support.

I should go one level up instead huh

I mean you originall have some code that checks for a support. So it calls a subroutine bl 0xabcd. I mean go to abcd, and change the code there to bx 0xfreespace+1 and install your routine at 0xfreespace

Yeah but when the subroutine gets called from somewhere else, things are probably going to start breaking. So I’ll go one level up and just not call that particular subroutine

Think about the original function ane the return value. It has some kind of method contract, and you just want to always change that behaviour. Otherwise the program starts to stop being self-consistent, hacing one behavior at one place, and a different one elsewhere.

You need to be in the spirit of the hack! Do it first and then check to see if things broke.

1 Like

Right, the parent function determines whether to show the Support option, and part of that is a check against the max number of supports. I don’t want to change the CountSupports function, just replace it with a different check. So I should replace the parent function.

Oh, are you only replacing a part of the routine? Then replace the part you’re replacing with a longcall described in the post I shared, followed by nop’s until where you return to.