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

Read other people’s doc.

In programming in general, it is so important to read documentation. You don’t want to do what other people have done. You want to learn from their work, their mistakes, and their successes. You want to save time by taking knowledge and using it for your own purposes. That’s the whole idea behind “open doc”, “open source”, etc.—it’s seriously, SERIOUSLY helpful. I practically learned assembly and made a lot of my ASM hacks by stealing from other people. Only until MUCH later did I figure out how to obtain offsets myself.

If you read people’s documentation, you can actually go off on your own from here and do some serious work. I’ve taught you that much.

Hextator has one of the largest folders of documentation on Fire Emblem, if not the largest, and a LOT of it is ASM-based. Nintenlord also has some amazing work, some of which I never had any idea existed before I checked, which made me feel somewhat stupid after because I could have had an easier time had I known about all the useful information in there. There’s also other doc spread about on various websites and the such, including mine, though in a way I consider this entire 300+ page tutorial to be a large portion of my hacking career’s “documentation”. :P

That being said, I don’t intend to stop teaching now. I am going to teach you more codes, more examples, and eventually teach you how to use a debugger and some tricks on how to find your own offsets, although I don’t know everything there is and finding locations of ASM routines in the games you are hacking is one of the harder parts of hacking for sure (for me, right now, it is probably in a way harder than the actual ASM-writing itself).

Part 4: More Examples – “Speed-Analyzing”

Time to run through more hacks.

Here’s your next one - https://dl.dropbox.com/u/8875056/hacking/asm/Revive%20All.zip

It’s thumb. Write to offset 0. Start with label “Initial”. Push 5 registers and the last register, then start a loop counter in r2 with starting value 0x00.

… I think we can go a little faster.

New label HealLoop: add one to the counter. Load the base offset. Note that the base offset works like before and is one entry before the actual 1st entry for player character (0x0202BD50) but also accounts for which byte the turn status byte is (0x0C).

Take 0x48 and multiply it by the loop counter to get a relative offset, then add it to the base offset to get the offset of some character’s turn status in the memory. Then make it 0x00, which will make them “alive” so to speak (a bit combination of ‘0x04’ and ‘0x01’ renders them dead… though this is technically the inappropriate way to relate bits, I’m too lazy to think of it in binary: in short, if a character is dead, they will usually have a turn status value of 0x05, or at least have those bits activated).

Then it loads the max HP byte, which is 6 bytes after the character’s offset in the memory (which is in r0) and stores THAT in the current HP byte, which makes it so that they are fully healed.

Then it checks to see if it’s entry 0x2A and if it is, it continues to “End” which pops the registers we pushed, but if not, it keeps going, forcibly reviving characters.

https://dl.dropbox.com/u/8875056/hacking/asm/Multiple%20Seize%20Hack%20bT.zip – This hack lets you choose who can seize and stuff by using a table. Let’s check it out.

Note that we set the offset to 0x034884 this time. The reason why is because this ASM hack is an actual hack of an existing routine at 0x034884. In this case, the new routine is shorter than the old one, so we lucked out and don’t have to repoint it. Repointing ASM routines is a pain in the butt (definitely harder than repointing tables/arrays) but we’ll get to it eventually.

This time we only push r2-r5. It’s been a while, but I think I did this because I needed some extra registers to work with and only r0 and r1 were free by default, so I pushed r2-r5 so I could use them and will re-pop them later.

Before I continue, how the seize option appears is that it checks for a value 0x00 or 0x01, where 0x01 is true and 0x00 is false (I really hope I didn’t get these confused… >_<’). We don’t have to worry about when it checks that though—we just need to change how it decides to output either 0x00 or 0x01. Before, FE7 used a bunch of checks on the mode to see who can seize. Now, we’re going to use a table.

First, we start our counter. Then we load the offset of the table. In another register, we load the offset of the chapter value in the memory, 0x0202BC06. We use ldrb to load the byte there, which is the actual chapter value.

Next, a new code: lsl—this is a logical shift left, which essentially moves bits over to the left. I don’t really feel like explaining it, but due to how bits work this also doubles the value… or rather, it multiplies it by 2^(#), where the # in this case is 0x02. So lsl r1, r1, #0x02 multiplies r1 by 2^0x02 and stores that in r1, effectively multiplying it by 4. This saves us a register as we don’t have to use the mul code, and is thus more efficient. People don’t like the mul code in general and try to switch to this and its opposite, which is lsr, which shifts to the right, and divides by a power of 2. To divide by a power of non-2 though, things get a bit more complicated, which is why you either have to use some special bios function (not preferred) or do some fancy multiplication/division combinations… *sigh*

Anyhow, the point of this is that the table has 4 bytes for every chapter, and those 4 bytes are actually a pointer. So this user-created table has one pointer for every chapter, and the game finds what chapter it is and then calculates which pointer to use.

To do that it does a little math and loads the word, which you should be familiar with, and then it loads the first byte there into r3, because in this line:

ldrb r3, [r2,r4] @ Loads the byte there (based on loop/counter #) into r3

r2 + r4 on the first loop is r2 + 0x00 or just r2.

What it’s doing is trying to load a “list” of characters who can seize on that chapter. Thus it first checks to see if the byte is 0x00, and if it is, then it’s the end of the list (if it’s on our first run then that means there’s no entries and no one can seize!) and it marks the true/false marker as false, which is under “E3”, and I’ll briefly go into a little bit more later.

Otherwise, it loads the current character ID, which so magically can be done with the code

ldr r5, [r0, #0x00] @ Otherwise, load current character ID

ldrb r5, [r5, #0x04]

You can’t tell just by looking, but r0 contained the offset of the current character in the memory. Remember that the first word there is the character data pointer, and that the 4th byte in the character data pointer Is the character ID—so that’s what those two codes do. Get familiar with them, I know I at least used them plenty (and similar things with like classes and items).

Next, we see if they’re the same (organization is important here so that you know to check r5 with r3). If they are, we go to “E4”, which is my oddly named label which has code for setting the “can this unit seize?” value to true. Otherwise, we add one to the loop counter and go again, checking the next entry in the table, until we find a match or the table ends. :P

As for those ending codes:

First, we pop back those registers so they have their original values.

Then, for the false one, I’m not sure why, but we load the character ID yet again, and then set r0 equal to 00 for some reason. I really don’t know why but for some obscure reason I was encountering some problems with the code when I removed these lines, so I kept them. That’s one of the potential issues with hacking existing routines: you have to really understand the code to minimize your chance for breaking things.

Lastly, we do bx lr, which I believe we’ve seen before, though it may have said “bx r14”. This is our way of going back to where we started. I’m guessing the original code also used this, since I based my hack off the original code.

The E4 one is similar but just moves 0x01 into r0 so that when the game checks r0 to see if it’s “true” (0x01) or “false” (0x00), it knows it’s true (meaning the character can seize).

https://dl.dropbox.com/u/8875056/hacking/asm/Gold%20Requirement%20Code.zip – Next up, we’ll be looking at this rather old “Gold Requirement Code”.

We can do this. We’re writing thumb code to 0x00, starting by loading the location of the funds address, which happens to be 0x0202BC00 in FE7. Then we load the entire word there, because the funds value (how much money you have) is a word.

Next, we load something called “GoldAmount” into r1. What I did here was specify GoldAmount below using a label, just like how we do with branching codes (e.g. “beq End”). However, at the end, I used .long to write a “long” word, 0x000BDE31. IIRC, .short writes a half-word, .byte writes a byte, and .align can align the data to make sure that it is word-aligned (which can be important for “relative offsets”, something I will sadly eventually have to explain to you).

Next, it compares the amount needed (“Gold Amount”) with the amount of current funds, and if the amount needed is greater, it goes to end one and marks it as false, which has apparently changed to be the value 0x01 now (I really get confused by this myself, as you can see—idk, just try switching them until it works >_>’, I really don’t know if 0x01 is true or false or what), and then uses bx r14 to return back to whatever it was doing (cough, events). Otherwise, it uses the “sub” command to subtract the needed gold amount from the current funds and then stores it at the funds address. It then marks the result as “true” (which is apparently 0x00 now… I don’t even know).

Now, you might be wondering, what do we do with this 0x00/0x01 result now?

The trick is the code IFAT/IFAF BLA… Here’s a copy/paste from the EA doc:

FE7:

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