[EA] [WIP] A Guide To Inserting Everything Through EA

 _____                 _   _   _            _____                   _   _         
|   __|_ _ ___ ___ _ _| |_| |_|_|___ ___   |  _  |___ ___ ___ _____| |_| |___ ___ 
|   __| | | -_|  _| | |  _|   | |   | . |  |     |_ -|_ -| -_|     | . | | -_|  _|
|_____|\_/|___|_| |_  |_| |_|_|_|_|_|_  |  |__|__|___|___|___|_|_|_|___|_|___|_|  
                  |___|             |___| 

#Sections

WIP
it’s a work in progress.
WIP
it’s a work in progress.
WIP
it’s a work in progress.
WIP
it’s a work in progress.
WIP
it’s a work in progress.
WIP
it’s a work in progress.
WIP
it’s a work in progress.
WIP

9 Likes

#Premonition - Why Use EA for Everything?

This is going to be a short section, but I’m just going to convince you why EA is just always the right tool.

  • Automatic Space Management
  • If you have everything to build in one EA script file, then EA is able to insert it in one continuous block of data. So you can just point it to the end of the used space in ROM and have it automatically stick everything there, and repoint as proper.
  • Honestly, this was the biggest motivation for me to start using EA.
  • Script Portability
  • You’re able to customize installs of things by changing just a few definitions, placable at the top of a file.
  • It’s not FEditor.
  • The only way EA will screw up your ROM is if you tell it to.
  • (Fairly) Organized
  • You can #include things in directories, so you can structure your project folder in a logical manner and get to data you need to change quickly.
  • Less(if not no) Need for Backups
  • Since you’re building everything at once, if you add something and your ROM breaks, you can just comment that line out and restore from a Vanilla ROM.
  • Also, you can comment out a line or two at a time to see what breaks your ROM, and debug the section that does.
5 Likes

#Prologue - The Basics: Events

Now, I’m going to at least assume you’re used to using EA to make events, as well as general EA syntax. If not, you really should check out Arch’s eventing tutorial.

So I’m not going to tell you how to event chapters, but let’s talk about some necessary changes to the way you write chapters to be compatible with making a single file for everything.


#ifdef, #ifndef, #else, and #endif

If you’ve programmed in C, you should be familiar with these guys. If not, I’ll explain.

So, as you should know, you can #define things in EA. Here’s a quick example:

#define Eirika 0x1 //Define a constant
#define EndOfTable "BYTE 0xFF 0xFF 0xFF 0xFF" //Define a constant section of code; techncially same as above
#define EAFlag //Sets the state of "EAFlag" to defined
#define repointMyTable(newLoc) "ORG MyTableLoc; POIN newLoc" //Define a macro -- note that its definition uses MyTableLoc, which is assumed to be defined before.

Note that if you have defined something, you can remove it with #undef.

So what #ifdef does is that EA will assemble the events between the #ifdef and the #else or #endif ONLY IF the name you’re checking has been defined. To undefine a macro, you need to also provide its parameters. #ifndef is “if not defined” and acts the opposite way.

To bring this around, I will give three very practical examples of why this is useful:

Example 1
Recall that EA automatically defines _FE#_, where # is 6, 7, or 8 depending on which option you selected on the GUI. I don’t know about you, but I can forget to click the right button sometimes. So a good way to protect my ROM is like so:

#ifdef _FE8_
  //Things you want to assemble
#else
  ERROR "You're not assembling FE8 events!"
#endif

Example 2
This is a use very familiar to C programmers. Let’s say we have a definitions file for our hack, that we want to include in every other file, and it goes like so:

#define MyCruddySelfInsert 0x01
#define MyCruddyLoveInterest 0x02
#define MyCruddyAntagonist 0x03
#define ActuallyJustAnIronSwordReskin IronSword
//...

Well, if I tried to include this file in multiple files, each of which were included by one central file, well, I’d be defining everything multiple times. So one way to avoid this is to do

#ifndef MY_HACK_DEFINITIONS
#define MY_HACK_DEFINITIONS

#define MyCruddySelfInsert 0x01
#define MyCruddyLoveInterest 0x02
#define MyCruddyAntagonist 0x03
#define ActuallyJustAnIronSwordReskin IronSword
//...

#endif

That way, for all EA cares, I can do

#include "Hack Definitions.txt"
#include "Hack Definitions.txt"
#include "Hack Definitions.txt"
#include "Hack Definitions.txt"
#include "Hack Definitions.txt"

But it doesn’t matter; the variables will be defined only and exactly once.

Example 3
I mentioned previously that EA is great for memory management. Well, that’s kind of useless if you’re ORG-ing your chapter events to various locations. But it’s a bit dangerous to just completely remove that; or at least, I like the philosophy that each event file should be able to assemble on its own. But one way to get both benefits with no cost is like so:

#ifndef InlineEvents
  #define ChName_DefaultChapterOffset 0x01000000
  EventPointerTable(0x01, ChName_ThisChapter) //Note that this changes where EA is ORG'd, so if you do an in-place install, you need to have this command somewhere else.
  ORG ChName_DefaultChapterOffset
#endif
//Event Pointer Arrays go here

Then in your ROM Makefile, discussed in the next chapter, you can just #define InlineEvents.


Suggested Edits to the Eventing Template

There is one really relevant weakness to EA – you won’t be able to have the same name for two things; whether it’s #defined, or used as a label, or otherwise.

As a side note, it is possible to limit the scope of labels by surrounding the events (or in this case, an #include directive) with braces {}, but then we won’t be able to point to inside the braces from outside, which is something we might want to do with various hacks or map changes (if we have them with events).

So if you have in your prologue events

POIN TurnBasedEvents
POIN CharacterBasedEvents
POIN LocationBasedEvents
POIN MiscBasedEvents

etc. And in your Chapter 1 events you have the exact same

POIN TurnBasedEvents
POIN CharacterBasedEvents
POIN LocationBasedEvents
POIN MiscBasedEvents

Then you can see how you can run into problems when we try making one master file with all of these events.

So instead, I came up with this skeleton:
[spoiler=FE7]
TODO: Make this skeleton[/spoiler]
[spoiler=FE8]
//Made by CrazyColorz5 of Fire Emblem Universe
//Based off of Camtech75’s Skeleton
#include EAstdlib.event

#ifndef InlineEvents
  //Assume the Map is contained and documented elsewhere.
  #define ChName_DefaultChapterOffset 0x01000000
  #define ChName_ID 0x01 //TODO: Change this depending on what chapter you're making.
  
  EventPointerTable(ChName_ID, ChName_ThisChapter)
  ORG ChName_DefaultChapterOffset
#endif

ChName_ThisChapter:

POIN ChName_TurnBasedEvents
POIN ChName_CharacterBasedEvents
POIN ChName_LocationBasedEvents
POIN ChName_MiscBasedEvents
POIN ChName_Dunno ChName_Dunno ChName_Dunno
POIN ChName_Tutorial
POIN ChName_Ballista1 ChName_Ballista2
POIN ChName_Units1 ChName_Units1
POIN $0 $0 $0 $0 $0 $0
POIN ChName_BeginningScene ChName_EndingScene

ChName_TurnBasedEvents:
TURN

ChName_CharacterBasedEvents:
CHAR

ChName_LocationBasedEvents:
LOCA

ChName_MiscBasedEvents:
CauseGameOverIfLordDies
//Add Win Condition
AFEV

ChName_Dunno:
END_MAIN

ChName_Tutorial:
END_MAIN

ChName_Ballista1:
BLST

ChName_Ballista2:
BLST
ALIGN 4

ChName_Units1:
//Add Player Units
UNIT


ChName_BeginningScene:
FADU 0x8

ENDB


ChName_EndingScene:

MNCH 0x01 //TODO: Replace with proper code for next chapter.
ENDA


#ifndef InlineEvents
  MESSAGE Events end at offset currentOffset
#endif

[/spoiler]

When you make your chapter, find and replace ChName with a unique identifier for your chapter, such as Prologue, or ChOne, or something. Also follow this naming convention for labels, for events within the chapter. This way, you’ll never run into a naming conflict.


#Chapter 1 - Making a ROM Buildfile

The idea is to have one event file that #includes, assembles, and organizes all of your other files, so you can just load this file up into EA and click “Assemble” like it’s some kind of “Make Hack” button.

There’s not much to it, but I’ll offer some suggestions.

1) Include #ifdef guards for the game you’re assembling for.

  • This is shown in Example 1 in the Prologue. There’s no reason to waste some time and potentially breaking a ROM because your definitions were wrong or you were writing that assembly to the wrong location.
  • There’s just really no reason not to have this on your buildfile.

2) Follow a freespace convention.

  • Have your main ROM Buildfile ORG to some free space. Then in each #included file, assume it starts at some free space in the ROM. In return, have it return to the end of free space at the end of the file.
    • Consequentially, if you need to ORG away, that means PUSH the current offset before you do, and POP once you’re done. There’ll be more examples on this later.

3) #include a lot. A. Lot.

  • The purpose of your build file isn’t to do much actual eventing. It’s to organize everything else you’re written. So most of your lines should just be #includeing your other files. In fact, I would say labels and include statements should be about 80% of your installation file.

4) Organize things Into folders.

  • You don’t have to call your folders these, but to stay organized, keep data in relevantly named folders. Put your text data in a Text folder, then just say #include "Text/Text Install.txt". Put your chapter events into an Events folder. Put your graphics into a Graphics folder. Etc.

Let’s take a look at the buildfile (with file names changed) of a hack I’m working on (It’s also a WIP):

#ifdef _FE8_
    #include "Hack Definitions.txt"
    #include "EAstdlib.event"
    
    #define Free_Space 0xb2a610
    ORG Free_Space
    #define INLINE
    MESSAGE "Used free space starts at CURRENTOFFSET"

    //CSV tables
    #include "Table Installer.txt"
    #include "Tables/Table Data External.txt"
    
    //Install Hacks
    #include "Engine Hacks/_MasterHackInstaller.txt"

    //Graphics
    #include "Mugs and Graphics/Install Graphics Data.txt"

    //Chapter Events
    #define InlineEvents //Assemble events into this free space.
    #include "Events/Chapter Events Installer.txt"
    #include "Events/World Map Events Installer.txt"

    //Maps
    #include "Maps/Master Map Installer.txt"
    
    #undef InlineEvents

    //Music
    #include "Music and Sound/Music Installer.txt"

    //Text
    //MESSAGE Text data at currentOffset
    #include "Text/Install Text.txt"
    
    MESSAGE Used free space ends at currentOffset
   


#else
    ERROR You are not assembling FE8 events!
#endif

Let’s look at how I organized this and why, a few lines at a time.

#include "Hack Definitions.txt"
#include "EAstdlib.event"

This just brings all relevant definitions into scope, for all subsequent files to use them. Even if they #include them themselves, it’s safe since Hack Definitions has #ifndef guards.

#define Free_Space 0xb2a610
ORG Free_Space

From there, it mostly just #includes every sub-installer file to hand each part of the hack. Because we ORGed to free space, each installer may assume it has access to as much free space as it needs. All the repointing is handled automatically by EA since we’ll be using labels.

It’s a very simple structure.


#Chapter 2 - Basically Nightmare+

setCharacterName(Arch, Arch_Name)
setCharacterDescription(Arch, Arch_Description)
setCharacterGrowths(Arch, 80, 45, 35, 30, 25, 40, 20)
setCharacterBases(Arch, 2, 0, 0, 0, 3, 2, negateByte(2))
setCharacterWeaponBases(Arch, DRank, NoRank, NoRank, NoRank, NoRank, NoRank, NoRank, NoRank)
setCharacterSkills(Arch, Lord)

Uh… w-what?


###Section 2.1 - Turning a Nightmare Module into Macros

All nightmare does is calclate a certain offset based on table entry size and offset within the table, then write to that location. You can replicate these as long as you know the size of the data. The .nmm file handily gives you all of the information you need, so you can define macros to make editing data in the ROM very readable and easy. Let’s look at some examples with the FE8 Character Editor.nmm.

#FE8 Character Editor by SpyroDi
#

1
FE8 Character Editor by SpyroDi
0x803D30
256
52
FE8 Character Editor.txt
NULL

Name value
0
2
NEHU
NULL

Description value
2
2
NEHU
NULL

Character Number
4
1
NEHU
NULL

Class (support viewer only)
5
1
NDHU
Class List.txt

Portrait (Zero is Default)
6
1
NDHU
Portrait List.txt

***UNKNOWN*** (Zero)
7
1
NEHU
NULL

Mini Portrait (Zero is Default)
8
1
NEHU
NULL

Affinity
9
1
NDDU
Character Affinity.txt

***UNKNOWN*** (Zero)
10
1
NEHU
NULL

Level
11
1
NEDU
NULL

Base HP
12
1
NEDS
NULL

Base Strength/Magic
13
1
NEDS
NULL

Base Skill
14
1
NEDS
NULL

Base Speed
15
1
NEDS
NULL

Base Luck
18
1
NEDS
NULL

Base Defense
16
1
NEDS
NULL

Base Magic Defense
17
1
NEDS
NULL

Constitution Bonus
19
1
NEDS
NULL

Sword Level
20
1
NDDU
Weapon Rank.txt

Spear Level
21
1
NDDU
Weapon Rank.txt

Axe Level
22
1
NDDU
Weapon Rank.txt

Bow Level
23
1
NDDU
Weapon Rank.txt

Staff Level
24
1
NDDU
Weapon Rank.txt

Anima Level
25
1
NDDU
Weapon Rank.txt

Light Level
26
1
NDDU
Weapon Rank.txt

Dark Level
27
1
NDDU
Weapon Rank.txt

HP Growth
28
1
NEDU
NULL

Strength/Magic Growth
29
1
NEDU
NULL

Skill Growth
30
1
NEDU
NULL

Speed Growth
31
1
NEDU
NULL

Luck Growth
34
1
NEDU
NULL

Defense Growth
32
1
NEDU
NULL

Magic Defense Growth
33
1
NEDU
NULL

***UNKNOWN*** (Zero)
35
1
NEHU
NULL

***UNKNOWN*** (Zero)
36
1
NEHU
NULL

***UNKNOWN*** (Zero)
37
1
NEHU
NULL

***UNKNOWN*** (Zero)
38
1
NEHU
NULL

***UNKNOWN*** (Zero)
39
1
NEHU
NULL

Character Ability 1
40
1
NDHU
Ability 1.txt

Character Ability 2
41
1
NDHU
Ability 2.txt

Character Ability 3
42
1
NDHU
Ability 3.txt

Character Ability 4
43
1
NDHU
Ability 4.txt

Supports Data Pointer
44
4
NDHU
Support Pointers.txt

***UNKNOWN***
48
1
NEHU
NULL

***UNKNOWN*** (Zero)
49
1
NEHU
NULL

***UNKNOWN*** (Zero)
50
1
NEHU
NULL

***UNKNOWN*** (Zero)
51
1
NEHU
NULL

Example 1 - Setting a Single Data Field

For now, let’s look at the description value. The nightmare file tells uf the following:

  • The offset of the character table is 0x803D30.
  • Each character is 52 (=0x34) bytes long.
  • The description field has an offset of 2.
  • The description field is 2 bytes long (i.e. it’s a short).

From this data we can use the following formula to make a macro: `#define informativeName(entry, param) “PUSH; ORG tableStart + entry*entrySize + offsetInTable; BYTE/SHORT/LONG/POIN param; POP”

Note that it’s best to PUSH and POP in your definition like that, so that using a setter doesn’t change the current offset that EA is writing to.

It’s also a good idea to #define your table’s offset so if you repoint it, you only need to change it once.
So we can make a macro to set a character’s description’s textID like so:

#ifndef CharacterTable
    #define CharacterTable 0x803D30
#endif
#define setCharacterDescription(char, descID) "PUSH; ORG CharacterTable + char*52 + 2; SHORT descID; POP"

Example 2 - Setting Multiple Data Fields

We don’t need to set only one field per macro, though it gets unwieldy if you set many non-contiguous fields. However, one good example on when it’s easy to have one macro to set many fields is stats (bases and growths)

Note that in the nightmare module, we have

  • At offset 12: base HP
  • At offset 13: strength
  • At offset 14: skill
  • At offset 15: speed
  • At offset 18: luck
  • At offset 16: defense
  • At offset 17: resistance (magic defense)

Or in order in the ROM; hp, str, skl, spd, def, res, luk.

Since they’re continuous and all one byte, it’s very easy to make a macro for them. Assuming we still have the CharacterTable definition from before,

#define setCharacterBases(char, hp, str, skl, spd, luk, def, res) "PUSH; ORG CharacterTable + char*52 + 12; BYTE hp str skl spd def res; POP"

Note that the macro defines the stats in display order, and we shuffle around the parameters into ROM order in the macro. This is useful functionality when editing the stats of a character.

Example 3 - A Pointer to Data

For this example, I’ll use the effectiveness pointers in the Item Editor. For reference, here’s the relevant parts of the nightmare module:

1
FE8 Item Editor by SpyroDi
0x809B34
205
36
FE8 Item Editor.txt
NULL

. . .

Effectiveness Pointer
16
4
NEHU
NULL

Since the effectiveness pointer is, well, a pointer, we need to use the POIN command to make an entry. Note also we should be using ROM offsets and not hardware offsets (that is, it should NOT be in the 0x08000000 range). This is important in a moment.

#ifndef ItemTable
    #define ItemTable 0x809B34
#endif
#define setEffectiveness(item, ptr) "PUSH; ORG ItemTable + item*36 + 16; POIN ptr; POP"

It may also be handy to have something like such, for the built in effectivenesses (these are for FE8):

#define FlyingEffectiveness 0x8ADF2A
#define HorseEffectiveness 0x8ADEE0
#define ArmorEffectiveness 0x8ADEBB
#define DragonEffectiveness 0x8ADF13
#define HorseAndArmorEffectiveness 0x8ADEC2
#define SwordfighterEffectiveness 0x8ADF57

But it gets MORE interesting. Let’s say we have some free space (if, by convention, we can assume the file starts in freespace). Then we can actually, in EA, write our own list, and automatically point to that. Check it out!

#define LordSlayer 0x01 //Just used as an example
setEffectiveness(LordSlayer, LordEffectiveness)

ALIGN 4
LordEffectiveness:
BYTE EirikaLord EphraimLord EirikaMasterLord EphraimMasterLord 0x00

Note that this does require knowing the format of what the data that the pointer takes to takes. In the case of effectiveness lists, it’s a list of class IDs terminated by 00.

By declaring our pointer and data this way, we can move around the list, and have EA take care of the addressing. We can also easily expand or change the list. We will see this pattern and flexibility a lot more in the section about general ROM data, like text and portraits.


###Section 2.2 - Editing Properties with EA

NMM2CSV and CSV2EA are other great ways to edit Nightmare properties, and they output event files. These methods of editing can be combined, though I suggest that you #include the Table Installer from c2e before you do your own table editing through events.

In any case, the idea is, is that once we have all the macros we need, we can just serially (and readably) tell the changes we need to make to each table entry.

Here’s an example:

makeThrowableWeapon(HandAxe)
setWeaponStats(HandAxe, 7, 65, 0, 0xFF)
setWeaponType(HandAxe, Axes)
setWeaponRank(HandAxe, DRank)
setNoStatBoosts(HandAxe)
makeNotEffectiveWeapon(HandAxe)

And you’re able to have a small block like this for every item you need to change. To further make a change, you just need to search/find the item to change and add a macro or change an existing one.


#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:

  1. 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 ItemTables, 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.


#Chapter 4 - Insertion Through the “Insert, Rip, and Paste” Pattern

In this chapter we’ll be looking at using other tools to correctly insert data, then we’ll copy that data out of the ROM and write an EA installer for it.

This is, quite honestly, a pain, especially when making a lot of quick or small changes. In Chapter 5, we’ll be looking at the tools specifically designed to avoid having to do this, but let’s look at this pattern, in case something comes up that there isn’t a tool for yet.


###Section 4.1 - Text

First, we insert the text we want with FEditor. It doesn’t have to be in the ROM you’re changing, so FEditor never has to touch your ROM; it can be into any ROM.

This is some tutorial text.
It's for nubs.[A][X]

Search for this text that was inserted in the hex of your ROM by searching for some part of the text. In this example, we could search for “This is some tutorial text.”. Find the start of your text. Note that there may be some control codes at the start. You may feel free to add some nonsense to the start of your text in that case, to mark where it starts. Example:

asdfgh[OpenRight][LoadPortrait][0x02][0x01]Hi! This is some text.[A][X]

so you can search for asdfgh and start copying after that. Then copy all of the data from the start of the text up to and including a 0x00.

Paste this data into an empty file. Let’s suppose you called it text.dmp

Now, in EA, you’ll want to install the text in this way:

#define TextTable (depends on your FE version)
#define setText(textID, offset) "PUSH; ORG (TextTable+4*textID); POIN (offset | 0x80000000); POP" //Anti-huffman

#define myText 0x100 //TextID
myText_Pointer:
    setText(myText, myText_Pointer)
    #incbin "text.dmp"

Note that TextTable and setText are defined in #include "Tools/Tool Helpers.txt". If you need to redefine TextTable for some reason, then just define it before including Tool Helpers.txt.


###Section 4.2 - Portraits/Mugs


###Section 4.3 - Maps and Map Changes


###Section 4.4 - Icons/Tilesets/Etc


###Section 4.5 - Battle Frames

Battle Frames Insertion, by @circleseverywhere
How to insert battle frames with EA:

  1. Follow the tutorial to make your battle frame

  2. Insert your graphics with GBAGE

  3. For each graphic, either use Raw Dump to get the hex and run it through an LZ77 compressor like NLCompressor or copy the data out using a hex editor

  4. Copy the TSA out of the rom into a new file (80210c - 802557)

  5. Copy the palette as well (802558-8025d7)

  6. Use the template here:

//New Battle Frame:
    ORG $51f68
    POIN BattleFrame
    ORG $51fc8
    POIN BF_EN
    ORG $52088
    POIN BF_PN
    ORG $52028
    POIN BF_EW
    ORG $52164
    POIN BF_PW
    ORG $80201c
    #incbin "bin\BF_TSA.bin"
    #incbin "bin\BF_Pal.bin"


//Put this part in free space
    BattleFrame:
    #incbin "bin\BattleFrame.bin"
    BF_EN:
    #incbin "bin\BF_Enemyname.bin"
    BF_PN:
    #incbin "bin\BF_Playername.bin"
    BF_EW:
    #incbin "bin\BF_Enemywep.bin"
    BF_PW:
    #incbin "bin\BF_Playerwep.bin"

#Chapter 5 - EA Formatting Suite

So this is what the Tools folder in EA is for…

Everything in this section uses the #incext command for EA.


###Section 5.1 - Text, the Anti-Huffman Way

In the way back, before FEditor days, text was writen in hex into the ROM, using the anti-huffman format.
You could write the Anti-Huffman format directly into a file, then #incbin that, but we have better tools.

ParseFile ships with EA now. Note that this does require the anti-huffman patch, which you can either apply the EA installer for or have FEditor autopatch to your ROM.

Creating an EA Installer by Hand
First write you text in ParseFile’s format. Suppose you save it in text.txt. In EA, write

#define myText 0x100 //The textID to replace
myText_Pointer:
setText(myText, myText_Pointer)
#incext ParseFile "text.txt"

Make a similar section for each textID to replace. I recommend having a different file for all the textID definitions.

The only warning is that if you plan on using Parse Definitions.txt with ParseFile, Parse Definitions.txt must be in the same directory as the installing event file. Note that "text.txt" is also relative to the installing event.

Automatic Installer Generation
@circleseverywhere made a tool for creating EA installer files for folders of texts. TO see how to use it, you can read that thread. The general idea is that you put a comment at the top of your text files with the textID in it, then run textprocess.exe in the folder with your texts. This generates an event file that you can #include.


###Section 5.2 - Portraits, 100% Organic, no FEditor Added

WIP
it’s a work in progress.
WIP
it’s a work in progress.
WIP
it’s a work in progress.
WIP
it’s a work in progress.
WIP
it’s a work in progress.
WIP
it’s a work in progress.
WIP
it’s a work in progress.
WIP


WIP
it’s a work in progress.
WIP
it’s a work in progress.
WIP
it’s a work in progress.
WIP
it’s a work in progress.
WIP
it’s a work in progress.
WIP
it’s a work in progress.
WIP
it’s a work in progress.
WIP

Idk here’s a good tutorial for palettes:

Reserved Chapter 6

Reserved Chapter 7

Reserved

Possibly Reserved?