Creature Campaign units are something that get asked about a lot, so this post will explain how they work.
Creature Campaign units are unlocked by meeting certain requirements in Tower of Valni or Lagdou Ruins during the postgame. The requirements for each are as follows:
Caellach Clear Valni 3
Orson Clear Valni 6
Riev Defeat 200+ enemies in 1 run of Valni
Ismaire Clear Valni 8
Selena Clear all of Valni 3 times
Glen Clear Lagdou 5
Hayden Defeat 200+ enemies in 1 run of Lagdou
Valter Clear Lagdou 7
Fado Clear Lagdou 10
Lyon Clear all of Lagdou 3 times
Unlocking
Marking a unit as unlocked is done via global flags, and has them join your party at the next prep screen. There are 3 general methods by which the game marks Creature Campaign units unlocked, the simplest of which are the ones that join after clearing a specific floor. These are fully implemented via events:
#define SetFlagIfPostgame $9EE184
#define ExitDungeon $9EE97C
#define PromptIfNextFloor $9EE920
ExitDungeonIfProgressionDisallowed:
CHECK_EVENTID 0xFFFF
BNE 0x0 0xC 0x0
ASMC 0x85C65
SADD 0x32
MNCH 0xFFFF
ASMC 0x37D59
ENDB
Lagdou5_EndingScene:
SVAL 0x2 0x68 //0x68 is the flag used by Glen
CALL SetFlagIfPostgame
SVAL 0x2 0x2E //0x2E is the chapter ID of Lagdou 1
SVAL 0x3 0x33 //0x33 is the chapter ID of Lagdou 6
CALL PromptIfNextFloor
ENDA
Lagdou7_EndingScene:
SVAL s2 0x6A //0x6A is the flag used by Valter
CALL SetFlagIfPostgame
SVAL 0x2 0x2E //0x2E is the chapter ID of Lagdou 1
SVAL 0x3 0x35 //0x35 is the chapter ID of Lagdou 8
CALL PromptIfNextFloor
ENDA
Lagdou10_EndingScene:
SVAL s2 0x6D //0x6D is the flag used by Fado
CALL SetFlagIfPostgame
SVAL s2 0x2E //0x2E is the chapter ID of Lagdou 1
CALL ExitDungeon
ENDA
Valni3_EndingScene:
SVAL 0x2 0x67 //0x67 is the flag used by Caellach
CALL SetFlagIfPostgame
SVAL 0x2 0x73 //0x73 is the flag checked for allowing progression
SVAL 0x3 0x24 //0x24 is the chapter ID of Valni 1
CALL ExitDungeonIfProgressionDisallowed
SVAL 0x2 0x24 //0x24 is the chapter ID of Valni 1
SVAL 0x3 0x27 //0x27 is the chapter ID of Valni 4
CALL PromptIfNextFloor
ENDA
Valni6_EndingScene:
SVAL 0x2 0x69 //0x69 is the flag used by Orson
CALL SetFlagIfPostgame
SVAL 0x2 0x76 //0x76 is the flag checked for allowing progression
SVAL 0x3 0x24 //0x24 is the chapter ID of Valni 1
CALL ExitDungeonIfProgressionDisallowed
SVAL 0x2 0x24 //0x24 is the chapter ID of Valni 1
SVAL 0x3 0x2A //0x2A is the chapter ID of Valni 7
CALL PromptIfNextFloor
ENDA
Valni8_EndingScene:
SVAL 0x2 0x6E //0x6E is the flag used by Ismaire
CALL SetFlagIfPostgame
SVAL 0x2 0x24 //0x24 is the chapter ID of Valni 1
CALL ExitDungeon
ENDA
In essence, the important piece of these is just setting a flag if you’re in the postgame, as the unlocking of creature campaign units uses flags to know if you should recieve the unit.
The next two cases are both more complex and implemented similarly: defeating 200+ enemies in a single run and clearing the last floor 3 times. Both of these are implemented through assembly, within functions called in the exit dungeon events that evaluate your score to set flags if necessary.
Riev and Hayden are unlocked by defeating 200+ enemies in a single run of a dungeon, within the function at $8037CA0:
...
08037CC6 (T) cmp r0,0C7h //0xC7 = 199, r0 = defeated count
08037CC8 (T) ble 8037CD0h //if # defeated <= 199, skip to just after the flag is set
08037CCA (T) mov r0,6Bh //otherwise, load the ID of the flag to set for unlocking Riev
08037CCC (T) bl SetEventId //and call the function to set the flag
08037CD0 (T) ldr r0,=gDungeonState
...
...
08037CE0 (T) cmp r0,0C7h //0xC7 = 199, r0 = defeated count
08037CE2 (T) ble 8037CEAh //if # defeated <= 199, skip to just after the flag is set
08037CE4 (T) mov r0,6Ch //otherwise, load the ID of the flag to set for unlocking Hayden
08037CE6 (T) bl SetEventId //and call the function to set the flag
...
Then, Selena and Lyon unlocking after 3 clears are handled by very similar sections of the function at $8038CF8:
...
08037D28 (T) cmp r0,2h //r0 = clear count
08037D2A (T) ble 8037D32h //if # of clears <= 2, skip to just after the flag is set
08037D2C (T) mov r0,6Fh //otherwise, load the ID of the flag to set for unlocking Selena
08037D2E (T) bl SetEventId ///and call the function to set the flag
...
...
08037D40 (T) cmp r0,2h //r0 = clear count
08037D42 (T) ble 8037D4Ah //if # of clears <= 2, skip to just after the flag is set
08037D44 (T) mov r0,70h //otherwise, load the ID of the flag to set for unlocking Lyon
08037D46 (T) bl SetEventId ///and call the function to set the flag
...
So to recap, flags denoting the unlocking of Creature Campaign units are set either in the chapter end event for the floor that clearing recruits them, in the assembly function at $8037CA0
if they are recruited via defeating 200+ enemies in one dungeon run, or in the assembly function at $8038CF8
if they are recruited via clearing a dungeon 3 times.
Recruiting
Once the flag for a given unit is set, then at the start of the next prep screen the unit will join your army. But, how does the game determine this? Luckily, it isn’t hardcoded, and is easily expandable.
At 0xD8018
is a list of flag/unit block pairs, laid out as so:
+0x0 Short Flag ID
+0x4 Word Pointer to Unit Block
The list is terminated by a null entry. The unit blocks here are laid out the same as in any other event. For instance, Lyon’s unit block pointer points to:
LyonCCUnit:
UNIT LyonCC Necromancer 0 Level(14,Ally,0) [11,13] 0 0 0 0x34B [Naglfar,Physic,Hammerne] NoAI
UNIT
The 0x34B
is junk data that’s never read, it serves no purpose.
By repointing this list, you can add more entries and all will function the same as the normal set of Creature Campaign units; all you need is a flag and a pointer to a unit block.
If you wanted to add a new unit to this list, you would need 1. a global flag to use, 2. a pointer to the unit block containing the unit you wish to add, and 3. something somewhere that sets the flag when your desired conditions are met. All of these put together would recruit your new Creature Campaign unit at the next prep screen automatically.
As always, please let me know if you see any errors here so that they may be corrected.