#Chapter 3 - Assembly Hacks
This is what got me to start using EA for installing everything. It’s just so much easier than anything else. Let’s take a look at the alternatives:
- Just try finding Hextator’s patch format installer/Cam’s improved one. And find code that is written in that format.
- You want to install and run python to install a hack? Also, hope you don’t make a typo. Also, you have to keep track of all the offsets, ew.
- Be able to know what within a .dmp file you have to replace with what. Don’t mess up your little endian-ing.
Additionally, on you, you need to:
- remember formats for table entries for many hacks
- possibly repoint included nightmare modules with hacks?
Why and How to Use Installers
Let’s take a look at #3 in particular, since I still do think it’s one of the easier ways to distribute a hack.
Take a look at Blazer’s Character Changing Hack
[spoiler=The Files]
Here’s the readme file (“Notes.txt”)
This is definitely my most extensive hack yet. What it does it changes one character from another (like how certain Lyn's Mode characters in FE7 have their character ID changed) as well as changes what items they have in their inventory.
You can reassemble the ASM and change the offsets as the source is included (.asm). The .dmp has the ASM hack in hex (assembled for you), and the .symbols file is... don't worry about it.
If you look at the hack in hex, you may notice the last like, 0x18 bytes are actually all pointers:
B0 2E B9 08
FF 45 D7 08 FF 46 D7 08 18 CE BD 08 FC 47 D7 08
60 60 01 08
the first one and last one should never need to be changed unless there are some really odd circumstances, but the 2nd through 5th ones may need to be, either my reassembling the ASM as I said or editing them in hex.
0xD745FF (AKA "FF 45 D7 08"; google "little endian" or something for how reversing pointers in hex works) is the offset of a list of characters to check for, i.e. the character to change, minus one. So the actual list goes at 0xD74600, but for the offset in the ASM, one hsa to wrtie 0x08D745FF or it won't work. At this offset (0xD74600) just put the character ID's right next to each other in a simple list. Make sure to end it with 0x00.
0xD746FF is the offset of the respective characters to change to minus 1, so the actual list goes at 0xD74700. Again, be careful when repointing. Also, the character # in one list corresponds to the same character # in the other list. I'll put an example later.
18 CE BD 08 ("0x08BDCE18 or just 0xBDCE18 in a hex editor) is the offset of the character data minus one entry (i.e. minus 0x48 bytes). If your character table was repointed for some obscure reason I don't know, be sure to change this, or it won't work.
Lastly, 0xD747FC is the offset of the list of items to give the character, minus 0x04 (4) bytes. So the actual table of items goes at 0xD74800.
Now, each of these lists has to be in line with one another, so it won't work. So to set up character #1, you'd have to:
- put their original character ID at 0xD74600
- put their character ID to change to at 0xD74700
- put their 4 items at 0xD74800 (no item = 0x00)
But for character #2, the data lengths of the first 2 tables and the last one are a bit different, so be careful:
- 0xD74601 - offset of original char ID for char 2
- 0xD74701 - offset of new char ID for char 2
- 0xD74804 - offset of items for char 2
So you just add 1 for the first two tables, but 4 for the items.
The ASM itself should be able to be put anywhere. Just be sure to load it with ASMC (0xOFFSET+1), i.e. if you put it at 0xD74400 like I initially did, load it with the ASMC code in the Event Assembler like: "ASMC 0xD74401", or else the game will probably freeze (yes, the "+1" is very important for loading thumb routines).
Be sure to credit Blazer if you use it... no permission is needed. Enjoy!
Item 5 of any unit is kept
And here’s dump file:
Character Changing Hack 2.dmp: 70 B5 00 22 01 32 17 4D 94 00 2B 59 00 2B 28 D0 1C 68 24 79 00 26 01 36 13 4D AD 5D 00 2D F1 D0 AC 42 00 D0 F7 E7 11 48 80 5D 34 21 48 43 10 49 40 18 18 60 00 27 B6 00 01 37 05 2F 0D D0 0D 48 80 5D 02 33 18 77 24 21 48 43 0B 49 09 68 40 18 14 30 00 78 58 77 01 36 EE E7 00 20 02 33 98 83 D0 E7 70 BD B0 2E B9 08 FF 45 D7 08 FF 46 D7 08 18 CE BD 08 FC 47 D7 08 60 60 01 08
[/spoiler]
Okay, I’ll give him that he wrote very detailed instructions. But still, how many places are there for you to mess up? Would you mess it up? I’d probably miss a +0x1 somewhere and have to reinsert it at least once or twice.
To show some installs from my own work as well, here’s my Luk Gains on Promotion Hack:
[spoiler=The Files]
Here’s “Instructions.txt”
Installation:
Copy-replace the dump file into 0x2983C
You also might want to clear the first 0x99ish bytes of wherever you place your table too.
Repointing:
By default, the Luk promotion bonus table is at 0xDA0000
To change, change th last 4 bytes of the dump file from
00 00 DA 08
to a pointer to the new location, and change the offset in the nightmare module accordingly.
Also you might want to clear the table by placing all 0x00's for the first Class-number of bytes.
Things to Keep In Mind:
Promotion bonuses gained are according to the class you are promoting TO, not from.
Here’s “Luk Upon Promotion.nmm”
1
FE7 Class Luk Upon Promotion Editor by Crazycolorz5
0xDA0000
99
1
Class List.txt
NULL
Luk Bonus
0
1
NEDU
NULL
And finally here’s the actual dump file: C0 B4 18 1C 23 30 14 26 A5 5D 07 78 EF 19 A7 55 3F 06 9A 5D 11 06 8F 42 00 DD A2 55 01 30 01 36 18 2E F1 DD 18 79 06 49 41 5C 65 7E 4F 19 A7 55 3F 06 1E 22 11 06 8F 42 00 DD 62 76 C0 BC 1B E0 00 00 DA 08
[/spoiler]
Even though there are fewer steps here, you still need to repoint the table, and make sure it’s cleared free space. It’s a hassle to install and maintain.
Now here’s my Event Installer for 3DS battle for FE8. It’s much more complex of a hack, with many files to install (I count 9)! But look:
//Change this to suit your ROM
#define Free_Space 0xEAC000
#define Item_Table 0x809B10
#define WTATable 0x59BA90
//Rewrite the WTATable in my new format.
#define Swords 0x0
#define Lances 0x1
#define Axes 0x2
#define Bows 0x3
#define Staves 0x4
#define Anima 0x5
#define Light 0x6
#define Dark 0x7
#define endWTATable "BYTE 0xFF 0xFF"
#define defWTAAdvantage(attackingType, defendingType) "BYTE attackingType defendingType"//"BYTE attackingType defendingType 0x0F 0x01"
ORG WTATable
defWTAAdvantage(Swords, Axes)
defWTAAdvantage(Lances, Swords)
defWTAAdvantage(Axes, Lances)
defWTAAdvantage(Anima, Light)
defWTAAdvantage(Light, Dark)
defWTAAdvantage(Dark, Anima)
endWTATable
//Installer~~~
#include "Extensions/Hack Installation.txt" //EA Extension Library
//Negative Display Hack
ORG $4146
BYTE 0x00 0x00 //Word alignment
jumpToHack(NegativeDisplayHack)
ORG 0x16BEC
#incbin "Effectiveness.dmp"
POIN Item_Table
ORG 0x2AABC
#incbin "3DS Power.dmp"
ORG 0x2AB74
#incbin "3DS Attack Speed.dmp"
ORG 0x2ABAC
#incbin "3DS Hit.dmp"
ORG 0x2ABE4
gotoHack(Avoid)
ORG 0x2AC18
#incbin "3DS Crit.dmp"
ORG 0x2AC54
jumpToHack(Dodge)
ORG 0x2C7C0
gotoHack(WeaponRankBasedWTA)
ORG 0x3673E //This stops the glowing for an inversely effective weapon for the attacker (changes a cmp r0, #0x00; beq to cmp r0, #0x01 bne)
SHORT 0x0000 0x2801 0xD103
ORG 0x367DA //And here for the defender
SHORT 0x0000 0x2801 0xD101
ORG 0x2AFBC //This sets the doubling threshold to 5
BYTE 0x04
ORG 0x2AFCE
BYTE 0x04
ORG Free_Space
Avoid:
#incbin "3DS Avoid.dmp"
Dodge:
#incbin "3DS Dodge.dmp"
WeaponRankBasedWTA:
#incbin "Weapon Rank Based WTA.dmp"
POIN WTATable
NegativeDisplayHack:
#incbin "negative_display.dmp"
MESSAGE Used space ends at currentOffset
(Note that this installer was written before EA supported PUSH/POP) Yes, the file is long, but when making your install, the file has the relevant lines to you in the top 3 lines. “Where can I find free space, where’s the item table, and where’s the WTA Table”. In fact, in 95% of hacks, the WTA Table will be in the default locations, and maybe 60% of hacks the Item Table will be as well.
Even better, if you have a master assembly hack installer, or are using a ROM makefile, etc, you can stick the section needing freespace in that section of the file without the ORG, to just put it at the end of your used space. That way you might not have to define anything at all!
It’s also very readable – you can see what each part is installing, and there are comments to help out with it as well. You can customize it while you’re in there, like if you don’t want the doubling threshold to be 5, you can comment that section out.
And do keep in mind, this is one of the more complicated installers, so if you can kind of make out what’s going on, most of them will be a piece of cake (though I will admit I have one that is more complex).
Integrating Installers into a Master Installation File
This will work similarly to making the whole ROM buildfile, with the exception of the requirement of free space within BL range.
Most hack EA installers will have definitions for you to edit near the top of the file, then code within the ROM’s code to link to the hack, then, sometimes, data that needs to be written to free space. Rarely, code will also require to be written to free space in BL range.
First, we should start with a skeleton for the Master Hack Installation File (credits to @circleseverywhere):
/////////////////////////////////////////////////////////
// //
// Master Hack Installer //
// circleseverywhere //
/////////////////////////////////////////////////////////
#include "Extensions/Hack Installation.txt" //Allows tools such as jumpTo(hack), etc
////////////////////////////////Definitions
#define Free_Space 0xE80000 //Feel free to move this or define it in the ROM Buildfile, etc
////////////////////////////////SUPPORTING CHANGES
PUSH
////////////////////////////////FREE SPACE WITHIN BL RANGE
ORG $e17c0
////////////////////////////////FREE SPACE OUT OF BL RANGE
POP
MESSAGE Used free space starts at Free_Space
ORG Free_Space
I do like using my hack installation file as the file in my ROM Buildfile that ORGs to free space, but it’s not necessary; you can have it in a different file.
This is best illustrated by an example. Consider the following two installation files:
#define itemToHack 0x01
#define ItemTable 0x809B34
PUSH
ORG 0x12348
callHack_r3(myItemHack)
POP
myItemHack:
#incbin "myItemHack.dmp"
WORD itemToHack
POIN ItemTable
and
#define characterToHack 0x01
#define ItemTable 0x809B34
PUSH
ORG 0x54320
callHack_r3(myCharacterHack)
POP
myCharacterHack:
#incbin "myCharacterHack.dmp"
WORD characterToHack
POIN ItemTable
Combining our definitions, we get:
#define itemToHack 0x01
#define ItemTable 0x809B34
#define characterToHack 0x01
#define ItemTable 0x809B34
We can furthermore discard one of the ItemTable
s, or even both of them if we defined its location elsewhere in our build process (such as a definitions file).
#define ItemTable 0x809B34
#define itemToHack 0x01
#define characterToHack 0x01
Now, taking a look at the in-ROM-code changes, we can combine them simply like so, putting them under the same PUSH:
PUSH
org 0x12348
callHack_r3(myItemHack)
org 0x54320
callHack_r3(myCharacterHack)
For clarity, it’s also best to comment in what hack you’re installing with each part.
PUSH
//My Item Hack
org 0x12348
callHack_r3(myItemHack)
//My Character Hack
org 0x54320
callHack_r3(myCharacterHack)
Finally, we just need to combine the free space sections of the installers. Note that for safety, it’s best to add ALIGN 4’s before each hack, but it shouldn’t be necessary if your free space was word aligned and the programmers did their job right. Since we need to install to the free space, we POP beforehand:
POP
ALIGN 4
myItemHack:
#incbin "myItemHack.dmp"
WORD itemToHack
POIN ItemTable
ALIGN 4
myCharacterHack:
#incbin "myCharacterHack.dmp"
WORD characterToHack
POIN ItemTable
And that’s it! Putting it all back together in the Master Installation File, we have:
/////////////////////////////////////////////////////////
// //
// Master Hack Installer //
// circleseverywhere //
/////////////////////////////////////////////////////////
#include "Extensions/Hack Installation.txt" //Allows tools such as jumpTo(hack), etc
////////////////////////////////Definitions
#define Free_Space 0xE80000 //Feel free to move this or define it in the ROM Buildfile, etc
#define ItemTable 0x809B34 //Remove if defined in another file
#define itemToHack 0x01
#define characterToHack 0x01
////////////////////////////////SUPPORTING CHANGES
PUSH
//My Item Hack
org 0x12348
callHack_r3(myItemHack)
//My Character Hack
org 0x54320
callHack_r3(myCharacterHack)
////////////////////////////////FREE SPACE WITHIN BL RANGE
ORG $e17c0
////////////////////////////////FREE SPACE OUT OF BL RANGE
POP
MESSAGE Used free space starts at Free_Space
ALIGN 4
org Free_Space
myItemHack:
#incbin "myItemHack.dmp"
WORD itemToHack
POIN ItemTable
ALIGN 4
myCharacterHack:
#incbin "myCharacterHack.dmp"
WORD characterToHack
POIN ItemTable
Making Installers
(This section is more directed to those interested in making assembly hacks.)
This is similar to a ROM buildfile. There will be definitions, repointing, and possibly data installation. As by the convention, PUSH before repointing, and POP after.
For definitions, I’d separate a section for the definitions you need the user to provide. This is something that you could possibly expect to be dynamic, such as a table offset, to even locations of in-game table.
Repointing is where you hook the hack into the ROM. In the upcoming release of EA, included is the file Extensions\Hack Installation.txt
that defines several macros for automatically writing a routine to hook into your hack.
-
BL(pointer)
will insert a BL call to your code, as long as it’s in BL range.
- The following three must be word aligned.
-
replaceWithHack(hack)
will push r4, then use r4 to jump to your hack, then pop r4 and return. It takes 0x14
bytes. It is meant for replacing entire routines.
-
callHack_r3(hack)
loads the hack offset into r3, and bl’s to it. After returning, it jumps over the literal and resumes the rest of the routine. It’s meant for expanding upon what a routine does. Hence it takes only 0xC
bytes.
-
jumpToHack(hack)
loads the hack offset into r3 and immediately bx’s to it. It’s for when you’re really conscious about space. It takes only 0x8
bytes.
The file then defines macros for setting table entries that you can use to define your own macros for Nightmare-like functionality. The file is worth a read.
Finally, data installation is where you put all routines you are unable to fit inline. You use #incbin
to include a compiled file, or you can just paste the contents into EA and use BYTE
to actually have the whole install just in the event file.