[FE7] Charting the Battle Stat Computations

This seems to be the routine orchestrating all of this; it calls both the routines I have analyzed.
(Don’t worry; later I’ll reorganize the OP to be more coherent)

@params: r0 = pointer to data in RAM of the attacker, r1 = &the defender. NOT battle data.
@r8 = Attacker’s deployment data, r9= defender’s

08028424 B570     push    {r4-r6,r14}
  • For clobbers.

    08028426 1C0E mov r6,r1
    08028428 4D11 ldr r5,=#0x203A3F0
    0802842A 4C12 ldr r4,=#0x203A470
    0802842C 1C28 mov r0,r5
    0802842E 1C21 mov r1,r4

  • So let’s review: r6(stored for later) is the defender data in ram. r0 is &attacker battle data and r1 is &defender battle data.

    08028430 F000FABE bl #0x80289B0

  • The routine analyzed before. Does most of the calculations.

    08028434 1C20 mov r0,r4
    08028436 1C29 mov r1,r5
    08028438 F000FABA bl #0x80289B0

  • Ditto, but for the defender.

    0802843C 1C28 mov r0,r5
    0802843E 1C21 mov r1,r4
    08028440 F000FADC bl #0x80289FC

  • The other routine analyzed before. Calculated final hit, crit and applies various weapon effects.

    08028444 1C20 mov r0,r4
    08028446 1C29 mov r1,r5
    08028448 F000FAD8 bl #0x80289FC

  • Ditto for defender.

    0802844C 2E00 cmp r6,#0x0

  • Is there no defender? (Snag seems to pass 0x0 as the defender)

    0802844E D101 bne #0x8028454

  • If not snag, go to 8028454(which is just skipping the next branch call)

    08028450 F001FF42 bl #0x802A2D8

  • Stores 100 as the battle hit rate, 0 as the battle crit rate.

  • Stores 0xFF as the attack speed of the defender/snag. Since y’know, you can’t double snags.

  • Stores the snag’s (current) HP into the 0x72 byte of the battle data(Nintenlord has it marked as “???”)

  • Stores 0 into weapon triangle hit and damage effects. (This is after they’ve been factored into calculations, and snags don’t have weapons anyway – useless?)

-tl;dr Snag stuff.

08028454 4908     ldr     r1,=#0x203A3D8
  • Some data stored before the attacker? I don’t know what this is.

    08028456 2001 mov r0,#0x1
    08028458 8809 ldrh r1,[r1]
    0802845A 4008 and r0,r1
    0802845C 2800 cmp r0,#0x0
    0802845E D00F beq #0x8028480

  • This indicates it’s some kind of flags… if the LO bit is set, then do the following, if not, then skip down to 0x08028480.

  • (untested thought: maybe an arena?)

    08028460 4806 ldr r0,=#0x203A85C
    08028462 6980 ldr r0,[r0,#0x18]
    08028464 2800 cmp r0,#0x0
    08028466 D00B beq #0x8028480
    08028468 F002FA1E bl #0x802A8A8

  • Seems to load something associated with the last selected unit. I can’t figure out what it is exactly, though.

  • If it’s zero, then skip over until below the next two blocks.

  • The bl call:

  • Loads the value again

  • I think it’s supposed to be a pointer. It loads the 2nd byte after the value pointed to and ands it with 0x80.

  • Loads the battle buffer pointer… if the post-anding value is nonzero,

  • Copies the data at the place specified by the pointer and stores it into 0x203A4F0(start of battle buffer). Continues loading from the location and incrementing and repeating until it hits something with the top bit unset. (yeah idk what this is doing either)… Finding the next open slot in the battle buffer?

  • Stores the location of the battle buffer into the place where the pointer to the battle buffer goes.

    0802846C E00A b #0x8028484

  • Skips to the end of the routine.

    0802846E 0000 lsl r0,r0,#0x0
    08028470 A3F0 add r3,=#0x8028834
    08028472 0203 lsl r3,r0,#0x8
    08028474 A470 add r4,=#0x8028638
    08028476 0203 lsl r3,r0,#0x8
    08028478 A3D8 add r3,=#0x80287DC
    0802847A 0203 lsl r3,r0,#0x8
    0802847C A85C add r0,sp,#0x170
    0802847E 0203 lsl r3,r0,#0x8

  • Discourse is opposing me making that block code for some reason, so sorry for that. Anyway…

  • I think this is just a literal pool.

    08028480 F000FD96 bl #0x8028FB0

  • Allocates 2 words of data on the stack…

  • Calls 0x8028F84

  • Loads default battle buffer location and Battle Buffer Pointer Location.

  • Stores 0 into the first 7 words of the defender’s battle data.

  • Stores default battle buffer location into the battle buffer pointer location; effectively clears the battle buffer.

  • Moves r13(the stack pointer, I think?) into r0, and 0x4 after the sp into r1

  • Calls 0x8029028

  • Simple here, stores the attacking unit’s pointer(i.e. 0x203A3F0, always) 0x8 deep into the stack(into [r0]), and 0x203A470 0x4 deep into the stack(into [r1]).

  • Loads the battle buffer location.

  • Sets the 0x01 bit of the 3rd byte(unlabeled?)

  • Reloads 0x203A3F0 into r0 and 0x203A470 into r1.

  • Calls 0x80290B8

  • r8 is the attacking unit’s deployment data in ram.(r6 and r9 is the defender’s) Pushes r8.

  • Loads equipped item of enemy and sees if it’s zero(no equip)

    • If so, then it immediately returns 0x0 in r0(false, I assume).
  • If not, then it loads the location of the battle buffer and loads the first halfword.

  • It calls #0x8029114.

    • calls another subroutine that loads Weapon Abilities and checks for brave effect. Sets the flag in the buffer if so. This flag is in the 0x10 position. If so, returns 0x1.
    • lsl’s 0x1 by the return of that routine. So 0x1 for no brave, 0x2 for brave.
  • Compares that return to 0x0 (Always greater than?) Returns 0 immediately if the return value is less than or equal to 0.

  • Stores back the previous battle buffer orr’d with its new self(idk what this is supposed to accomplish since the brave code stored it anyway)

  • Calls 0x80294D8

    • Checks to see if the aggressor unit is the defender. If so marks the “Which side is attacking” bit. (0x8 of the 0x2 byte)
    • Calls 0x8029234, which does: Stores the attacker’s attack and the defender’s defense into the 0x6 and 0x8 halfwords of 0x203A3D8(I’m calling this the Battle Stats Data). Stores the Battle Hit of the attacker into the 0xA halfword and the Battle Crit to the 0xC halfword. The Lethality halfword gets stored into the 0xE byte.
    • Calls 0x8029324, which does: Checks the class and character abilities for either triangle attack. If so, checks the battle stats data’s 0x2(Range) byte against 1.
      • If it is 1(a direct attack), it checks the battle buffer to see if the “End” bit is set. Then if so then takes the first “Unknown” byte from the character’s data and takes its LO Nibble. If the LO nibble is not 0x4(exactly) then checks the 0x20 bit of the first halfword of the Battle Stats Data, then executes a routine and checks the return against 0. I assume this routine checks if you can perform a triangle attack. I’m just going to leave it at this…
    • Calls 0x8029264, which does: Stores 0 into the 0x4 byte of the Battle Stats Data (This will be damage at the end). Loads the 0xA(hit) and calls 0x80285A8 – Which grabs the average of two random numbers and determines if you hit if you’re in an actual battle. (Battle Preview always treats it as a hit). If it gets 0(miss), it writes the 0x2 byte of the battle buffer’s first halfword(miss). If it hits, then it stores the difference of attack and defense as the damage byte(0x4 of the Battle Stats Data). Then it calls 0x802857C, which I’m not analyzing, but I assume does critical checking. (Anyway at this point I have a decent idea of what to rewrite for my modular battle routine)
    • Rolls for a critical. If you get that, it rolls for lethality. If crit but no lethality, it triples damage. If lethality, it sets damage to 127. Also write to the corresponding Battle Buffer bits.

    08028484 BC70 pop {r4-r6}
    08028486 BC01 pop {r0}
    08028488 4700 bx r0

  • Returns. Finally done!