Hi guys, I’ve been delving into C for the last year or so and wanted to make a list of all the little tips and tricks I’ve found along the way. If this is your first time with C, then be sure to visit the link below to get set up and follow along.
C + Buildfile Setup
Allow units without portrait data to attack on player phase
READ ME
Now, by default the game does not expect you to have playable units on your team with no portrait data (like monsters) and thus doesn’t account for it if you try to access the weapon select screen without setting portrait data in advance.
If we look at the decomp, we can see the function that controls this behaviour is called StartUnitWeaponSelect
.
u8 StartUnitWeaponSelect(struct MenuProc* menu, struct MenuItemProc* menuItem) {
ProcPtr proc = StartOrphanMenu(&gUnknownMenuDef);
if (gActiveUnit->pClassData->number != CLASS_PHANTOM) {
StartFace(0, GetUnitPortraitId(gActiveUnit), 0xB0, 0xC, 2);
SetFaceBlinkControlById(0, 5);
}
ForceMenuItemPanel(proc, gActiveUnit, 0xF, 0xB);
sub_80832C4();
return MENU_ACT_SKIPCURSOR | MENU_ACT_END | MENU_ACT_SND6A | MENU_ACT_CLEAR;
}
Now, looking closely we can see a special exception is made for the phantom class to avoid displaying a portrait (as it doesn’t have one). Thus, the weapon select screen can display without crashing the game.
So how do we make it work for other classes? Well as it turns out, any unit that doesn’t have portrait data will always have their portrait ID set to 0. So if we just check for that in advance instead of looking for the phantom class, we can make the function much more flexible. E.g.
u8 StartUnitWeaponSelect(struct MenuProc* menu, struct MenuItemProc* menuItem) {
bool noPortraitUnit = false;
ProcPtr proc = StartOrphanMenu(&gUnknownMenuDef);
if (gActiveUnit->pCharacterData->portraitId == 0)
noPortraitUnit = true;
if (!noPortraitUnit)
{
StartFace(0, GetUnitPortraitId(gActiveUnit), 0xB0, 0xC, 2);
SetFaceBlinkControlById(0, 5);
}
ForceMenuItemPanel(proc, gActiveUnit, 0xF, 0xB);
sub_80832C4();
return MENU_ACT_SKIPCURSOR | MENU_ACT_END | MENU_ACT_SND6A | MENU_ACT_CLEAR;
}
Now, if we find a unit without portrait data, then we set the noPortraitUnit
variable to true. This lets the function know we don’t want to bother displaying anything.