Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Fire Emblem Ultimate Tutorial.doc
Скачиваний:
1
Добавлен:
01.07.2025
Размер:
7.86 Mб
Скачать

It’s not super long, but it’s got some new things we need to learn. Let’s get started.

First, we write the first part to 0x019B0A. As it turns out, this is the location of an existing ASM routine, and for us to write to this offset, we will be replacing codes there. As for how to find this offset, I’ll be writing a section on how to do that soon, or else I’ll just slowly integrate it into our teachings.

Now, when we overwrite those codes, we have to make sure we ultimately use them or else the output at the end will be different and things will go awry. Just like with the Seize hack, we have an ultimate goal, and we’re just sort of changing one or two values on our way or else just changing the conditions with which to output those values.

In this case, the ultimate lines we use (and replaced) are:

ldr r1, =0x08BE50E8

lsl r0, r0, #0x01

or

ldr r1, =0x09461900

lsl r0, r0, #0x01

depending on how the conditional check goes. Now, those are 2 opcodes we replaced, and they’re both 2 bytes, and 2*2 = 4 bytes, and a bl (branch with link) is 4 bytes, so we replaced 4 bytes with 4 bytes: sounds great.

Now with the actual code, we have

bl Event

Initial:

.org 0x0C6048

Event:

We start by branching the normal routine to the routine we’re writing. This is our way of “repointing”. However, we also note where we left off using the label “Initial”. The assembler doesn’t like when you use offsets, it prefers using label. So if we need to reference the offset after our branch instruction—since ultimately, we will want to continue where we left off, we need to give it a name.

Next, we set the offset for our hack—I used 0x0C6048 probably because that’s in the middle of where the weapon icons used to be, and was the next chunk of free space I had for ASM hacks. We call this part “Event”, as we referenced with the bl above.

The rest is comparatively trivial:

ldr r1, =0x0202BC06

ldrb r1, [r1]

cmp r1, #0x44

beq StarTiles

cmp r1, #0x45

beq StarTiles

We load the offset of the chapter value at 0x0202BC06, which you should have seen before, and then load the value. We check if it’s 0x44—if it is, we go to “StarTiles”. If not, we check 0x45, and if the chapter is 0x45, we also go to StarTiles. If it’s neither of those, we continue reading the code, and…

ldr r1, =0x08BE50E8

lsl r0, r0, #0x01

bl Initial

we end up loading the default list of text IDs at 0x08BE50E8 into r1, EXACTLY as the original code does, and then multiply r0 by 2 and store it in r0, which I don’t know what it does, but all I did was copy the code I replaced from earlier to make sure we still had it. (As for how I knew where that code was and what it was, we’ll figure that out later.)

Lastly, I branch to “Initial” to make the game go back to where I was before I left off. Note that the only register I used before loading the offset of tile text IDs was r1, and that ultimately we replaced r1 with the “ldr” opcode so it didn’t matter that we did it. If we needed to use other registers, we’d have had to push them, like I did in another example, and pop them back later.

The “alternate ending” though, if you will, has it load a NEW list of text tile IDs. This is only if the special conditions were met as shown before.

StarTiles:

ldr r1, =0x09461900

lsl r0, r0, #0x01

bl Initial

This time it loads a list at 0x09461900, a somewhat obscure offset that you could check at 0x01461900 in a hex editor, and then I use the lsl code again because I want to keep things the same, and then return back with the bl. As you can see, the only different there was the offset—everything else was just doing checks to see which offset I’d load. But the effect is pretty nifty, I think.

https://dl.dropbox.com/u/8875056/hacking/asm/Custom%20Map%20Sprite%20Palette%20for%20AR.zip this is just another short and similar example since branch links are important.

You branch from one offset to the next (this seems to be the first routine I wrote in the new space actually, since it uses 0x0C5EA4, which is exactly where weapon icons start, I believe…) and then I check the chapter to see if it’s less than 0x43—if it is, I laod the normal palette, but if not I load a new palette at some offset 0x09BB4200 that doesn’t really matter (all we need to know is that it holds the palette). Mov r1, #0xe0 is some code that I replaced and so I put it back.

https://dl.dropbox.com/u/8875056/hacking/asm/1.5x%20Critical%20Damage%20Hack.zip – This turns the critical damage to only 1.5x. I made it 2.5x in a hack of mine and someone requested 1.5x so I did that too.

I actually stuck this right in the middle of the critical damage routine or something. I branch to the hack and pop r2—not sure why I popped it but it probably had something to do with the original code… anyhow, I move 0x03 into r2 and multiply it by r1, which presumably contained the damage. Then I pushed r2 for some reason and used lsr, the opposite of lsl, to divide by 2^0x01, or 2, which means I multiplied the damage by 3 and divided it by 2… 3/2 = 1.5, I made it to 1.5x damage. bl Return makes it return back to where it was.

By the way guys, this might sound shocking, but I used to write a lot longer codes. Check this one out -- https://dl.dropbox.com/u/8875056/hacking/asm/Gradual%20Stat%20Increaser.zip I think it’s like 300 some lines. Why? Because I only knew a few codes so I just copied and pasted them to get my desired effect instead of using a loop: I manually edited each value of the enemies’ stats. Yeah, I was a serious noob back then; it also makes me look GOOD now, even though I’m really not. FYI, that’s only part 1—I had to split it into 2 parts because the assembler got mad after writing so many lines. People didn’t even know that could happen. >_>’

To end this part of the tutorial (I know my parts are super long, sorry, there’s a lot to teach and I want this to be thorough), let’s do a long script that could probably be more efficient but isn’t as bad as the last one, I don’t think.

https://dl.dropbox.com/u/8875056/hacking/asm/Stat%20Maxer.zip – This hack is used in TLP to allow the player to max their stats if they had the money. It had a “cost” for each stat and calculated how much the player needed, then subtracted it. Fun times.

“Oh man Blazer, you really hate us, don’t you?”

Nah, this is actually not so bad. We’ve done a lot of practice: hardly any of it really needs explaining. Just some more practice with some different circumstances, really.

We push registers for use, including the last register, so you can expect us to return using pop {pc}. We set 3 registers to 0x00, where r2 is a counter and r7 is another check and r3 we just set to 0 because we’ll want it to be empty later.

In “Main”, we add one to the counter, load the memory table one entry back as usual, and do a little multiplication and addition to get the character memory address in r3. Then we load the byte there, and see if it’s 0x00: if it is, we go to the end, because we’re done checking (this might be risky in retrospect: what if the byte happens to be a 00 because the character data pointer happens to end in 00? I’m not sure what I was thinking since I’ve used other methods besides this but oh well).

If it’s not 0, we check the turn status byte and see if it’s active. 0x01 and 0x41 are the two values you’ll ever see for active, though a more proper solution would probably be to check the actual turn status bit that says “this character is active”… also, 0x01 has other uses besides the bit for “active”, which is kind of weird, but whatever, details don’t matter too much.

Anyhow, if it IS the active character, then we’ve found the character we’re trying to max. Why? Because how this hack works is that the character talks to another character who asks if they want to max their stats. While talking to a character, the character who initiates the talk is active—so we find which character it is by checking for the active character. Clever, no?

By the way, if it doesn’t find a match, it goes back and loops until it either finds an active character or doesn’t find anyone (which would be awkward given the nature of the ASM hack, but I have to let it end somehow).

Now we set r6 to 0x00. This will serve as the register that contains how much money we need to max all the stats. We will keep adding to r6 until we calculate how much money is needed, then check with our funds to see if we have that much money.

Under “StatChecks” we load the pointer to the class data from the memory into r0 (it says r1, that’s a typo or something—trust the code more than the notes, haha). If you don’t know, a unit’s/character’s memory data has the character pointer (1 word) and then the class pointer (1 word) which is why we used [r3,#0x04], it loads the memory address of the current character from r3 and adds 0x04 to it and then loads the word there into r0… meaning the pointer.

Next what it does is it goes through every stat and does some math to calculate how much money is needed. We’ll go through Strength and the rest are just copies but with slightly different numbers due to different offsets and other small details. We load the max strength from the class data, which we can tell using Nightmare + a hex editor is the 14th byte. Then we load the current strength from the memory, which also happens to be the 14th byte, into r2 (we don’t want to overwrite r3 as we want to keep that handy so we can keep working with it).

Then we subtract r2 from r1 (r1 – r2) and store that in r4. This tells us the difference between the max strength and current strength. If it’s 00, then r1 = r2 or max strength = current strength. Otherwise it should be some positive #.

Then we move 0xFA into r5 and multiply it by 2 to get 500, because this is how much gold is required to up strength one time.

Then we multiply it by how much we need to (r4) and find how much it costs to totally max strength, and add that to r6, our total cost for EVERYTHING. Then we have this seemingly odd check where we check if this is the “first time”. What the hack does is the first time it goes through, it just calculates it—if it turns out it can go do the change, it goes back AGAIN, but this time makes the change. To know whether or not it can make the change or not, r7 contains either 0x00 (false) or 0x01 (true). I actually wrote the code to check if r7 is true or false here, by the same logic as in other times or like with the IFAT command which checks the result for you and lets you do events based on it.

In the case that it’s the second time, it just uses:

strb r1, [r3,#0x14] @ Otherwise, store the max stat into the offset of the current stat

to store the max strength into the offset of the current strength in the memory. The actual gold subtraction will be done at the end.

It goes through all the other stats similarly, except for HP, the max is 60, and for luck, the max is 30, as those do not vary between classes in this hack.

At the end of the check for the luck stat, we have

cmp r7, #0x00 @ If r7 is 0x00, i.e. this hasn't been done before

beq MoneyCheck @ Then see if there's enough money to actually make the change

On our first time, this will be true, so we go to “MoneyCheck”. On our second time, it’ll go to End1, which marks the result as true (so that I can use an event to have a different text output depending on whether or not it was successful) and pop registers accordingly. (End2 is the same thing but marks the output as false and occurs if you don’t have enough money to max all stats.)

Here, we do something like the gold requirement code before, where the gold required is in r6. We check to see if we have enough and if not, we go to End2, marking the result as false/a failure, and if we do, we go ahead and subtract the money and then set r7 to 0x01, so that this time when we go back through the checks, it will actually make the stat changes.

Again, this isn’t the most efficient code, and it’s not even the most complex or fancy—I mean, you can’t choose what stats to max, you can’t choose how many of them to max, the gold cost for east stat is a constant, etc.—it’s simple, but for my intents and purposes, it works, and is fun enough for me. :P

With that, you are FINALLY freaking done with this part. Next up I will cover how to find routines and how to debug. After that, I will have taught you practically everything I know, so we will be done!

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]