Learning programming languages, including assembly, is a bit like learning a spoken language. There's a big climb at the beginning where nothing makes sense. Once you get past that, things start making sense a lot quicker. The beginning steep climb often makes people worry they're not fit for it.
But I'm guessing you learned a spoken language from scratch using little more the gestures, pictures, and probably food. It may have taken years, but now you're about as good with it as a native speaker of the language. Anyone who can do such a thing is capable of the more trifling feat of reading and writing assembly. But it's still hard.
Hacking is rewarding though. It's painful at times, but the payoff is nice. When it all comes together, it's pretty amazing. But it pays to be passionate about what you're doing, because if you're meh about the result then the payoff won't be worth the road to get there.
Some more basic tips:
- Assembly is the step-by-step instructions for how to do something, boiled down to math. It seems weird at first, but it's all basic math.
- It helps to understand memory, which it sounds like you do. It's like a big checkerboard, with a little bit of information on every square. Every square has a position on that board, which is the address.
- You might try something even simpler, like making Eldin gain zero EXP or a fixed amount of EXP after each battle.
- Code is organized into "functions" which help programmers stay sane. These are building blocks that make bigger things happen, or sequences of those building blocks that make even bigger things happen.
For example, when you want to open a door you don't think about all the little steps of turning a door handle. Instead, you first do something to guess at what type of door this is, then you follow a standard process to open that type of door. Even when you used a new type of door handle the first time, you didn't think about the individual muscles to move or probably even where to put your fingers exactly.
Programs are just like that. Someone wrote a function once to bend your thumb. Later a totally different person wrote a function that grabs things, and it used that "bend thumb" function. Yet another person's function grabs doorknobs in particular, leveraging that popular "grab" function. Code is just a bunch of these functions.
To better explain some of my steps:
Create a breakpoint for reading from the EXP value's memory address.
https://problemkaputt.de/gbahlp.htm#breakpointsIf you press Ctrl-B, you'll get a dialog to create a breakpoint. If the EXP is at 0x02038E7C, you'd put the following in for the breakpoint:
[02038E7C]!
This will make the emulator pause (it'll focus the debugger pane) whenever that address is written to. You might see something like this:
ldr r1,=2038E7Ch
ldr r0,[r1]
adds r0,r0,4h
str r0,[r1]
I made the above code up, but let's break it down:
First, "ldr" means "load register". It reads data from memory (the checkboard) into a register. I tend to explain registers as things you're holding in your hands - but the computer is like an octopus, with many hands.
The GBA can't work with memory directly - it has to grab it into its hands first. Once there, it can manipulate it, and later put it back on the checkerboard. It may also help to think of memory as "farther away", like a refrigerator.
The first ldr is actually a shortcut to specify an address in a register. The GBA can't really think about anything that isn't in a register, so even to read from an address - it first has to put that address into a register.
The second ldr in my example reads r0 from the address specified by r1. So this would read the EXP value into r0. The registers go from r0 to r15, although some registers have special purposes (like thumbs or feet.) Usually r0 and r1 are the most readily accessible.
After that, my example adds 4 to r0. It says r0 twice because the first r0 is where to remember the added sum, and the second r0 is what to sum. For example, "adds r0,r1,r2" would add r1 and r2, and remember the result of that in r0.
Finally we have "str": store register. This compliments ldr and puts a value onto the checkerboard that is memory. So here, we're taking r0 (which is the original EXP + 4) and putting it back into the memory where EXP is normally kept.
In more common programming code, that example would be more like:
EXP += 4;
Assembly tends to be more verbose, because it's step by step. These are the steps the CPU is really taking to do that.
The code you find will be more complicated. For example, there's probably a base address where all party member information starts. For easy example numbers, imagine it looks like this:
02038E00 - Eldin's information
02038E7C - Eldin's EXP
02038F00 - Torma's information
02038F7C - Torma's EXP
In this case, you might see code more like:
ldr r1,=2038E00h
lsl r2,r0,8
adds r1,r1,r2
ldr r0,[r1,7Ch]
adds r0,r0,4
str r0,[r1,7Ch]
Some new things here again. The first ldr is familiar, but now it's the base address of the first character's information.
Next, we have "lsl" which is new. This stands for "Logical shift left". This is possibly the most complex math you'll see in GBA assembly. A shift is a multiply by a power of two. In this case, it's shifting r0 left by 8. In other words, it's multiplying r0 by 2 to the power of 8. For a computer, this is VERY EASY math (like multiplying 5 by 100 would be for you), so such a multiply is common.
It's called "logical" because of how negative numbers are handled, but don't worry about that detail for now.
So, why would it do this? In my theoretical scenario, the original "r0" is which character should gain 4 EXP. So if it's 0, it'd be Eldin... if it's 1, Torma... and so on. And my example was that each character's information is 0x100 apart (which is 0x001 shifted left 8 ), so we're just figuring out how much to add to get to the right character.
Next we add, that's pretty straight forward.
Finally we see a new trick from ldr. Instead of [r1], we see [r1,7Ch]. If you remember, my example has the player info at 00 and the EXP at 7C. This simply says to read from "r1 + 0x7C". When you say [r1], it actually means "r1 + 0". The extra number is called the "offset".
After that, my example should follow from the last example.
This is just an example, though. I didn't look at the game's actual code. There are many other things it could do. Obviously, it doesn't always add 4 EXP after a battle, and it probably needs to divide what it would add by 5 to give the bonus. But it follows the same building blocks: loading into registers, doing things with them, then putting them back.
-[Unknown]