Skip to content
Sme edited this page Apr 15, 2024 · 6 revisions

There are many skills and other engine hacks that all need to make some change at an identical or very similar point in the code to apply their effect. To prevent each of these locations either having one incredibly long function with a myriad of effects within it or conflicts between skills and/or other engine hacks, these locations are converted to modular hooks.

A modular hook is a wrapper inserted into a function that will call an arbitrary number of other functions when run. This is accomplished with a list of pointers to the functions to be run, which the wrapper will loop through all of. This also makes writing functions that go within these lists less complicated, as rather than a function that hooks in the middle of some existing function and needs to preserve register values when it returns, these functions are called like any normal function would be and therefore follow the comparatively less strict conventions of normal functions.

Here, type signatures will be given for the functions called by each modular hook. The types and naming conventions are taken from the FE8U decomp.

Calculation Loops

Calculation loops, or calc loops for short, are the majority of the modular hooks used by the skill system. They cover a broad amount of the commonly used areas, with most of the rest covered by other, more specific modular hooks elsewhere.

Battle Proc Calc Loop

void BattleProcFunc(struct BattleUnit* bunitA, struct BattleUnit* bunitB, struct BattleHit* curRound, struct BattleStats* stats)

The Battle Proc Calc Loop is run on each round of battle being calculated and is used primarily for skills that have a chance of activating during battle, commonly referred to as "proc skills". Within the function list, functions here should go between Proc_Start and Proc_Finish.

Can Unit Double Calc Loop

int CanUnitDoubleFunc(struct BattleUnit* bunitA, struct BattleUnit* bunitB)

The Can Unit Double Calc Loop is run when determining if unit A can double unit B, immediately following the normal Attack Speed calculation. The value returned by these functions determines the behavior:

  • 0 forces unit A to be unable to double, and exits the loop.
  • 1 forces unit A to be able to double, and exits the loop.
  • 2 continues the loop. If the end of the loop is reached without a function returning 0 or 1, the Attack Speed result is kept.

EXP Calc Loop

int EXPFunc(int exp, struct BattleUnit* bunitA, struct BattleUnit* bunitB

The EXP Calc Loop is run during post-battle experience gain calculation, immediately following the standard calculation's conclusion. The value returned by these functions is the modified EXP value, or the input exp if no changes are made.

HP Restoration Calc Loop

int HPRestorationFunc(struct Unit* unit, int healPercent)

The HP Restoration Calc Loop is run at the start of each phase when determining what units should be healed by things such as terrain. The value returned by these functions is the modified heal %, or the input healPercent if no changes are made.

Mug Loading Calc Loop

int MugLoadingFunc(u16 controlCode)

The Mug Loading Calc Loop is run when interpreting a control code in text. The value returned by these functions is the mug ID to display. If a function returns a non-zero value, the loop is exited and that value is used as the mug ID. If a function returns 0, the loop continues.

Post-Action Calc Loop

void PostActionFunc(Unit* unit)

The Post-Action Calc Loop is run immediately after a unit's state is set to have acted for the turn.

Post-Battle Calc Loop

void PostBattleFunc()

The Post-Battle Calc Loop is run in place of the normal function that sets if a unit is able to Canto.

Pre-Battle Calc Loop

void PreBattleFunc(struct BattleUnit* bunitA, struct BattleUnit* bunitB)

The Pre-Battle Calc Loop is run in place of calculating battle stats.

Range Calc Loop

u32 RangeFunc(struct Unit* unit, u16 item, u32 minMaxRange)

The Range Calc Loop is run during weapon range calculations. This one is somewhat unique in that the loop itself contains a built-in skill check, so functions do not need to include one, only specify a skill ID when placed into the loop. The value returned by these functions is the updated minMaxRange word, or the input one if unchanged. The format of this value is (minRange << 16 | maxRange).

Skill Activation Chance Calc Loop

int SkillActivationChanceFunc(int activationChance, struct BattleUnit* unit)

The Skill Activation Chance Calc Loop contains modifiers on the activation rate of proc skills. The value returned by these functions is the updated activation chance %, or the input activationChance if no change.

Weapon Usability Calc Loop

int WeaponUsabilityFunc(struct Unit* unit, u16 item, u8 rank)

The Weapon Usability Calc Loop is run when determining if a unit is able to wield a weapon. The value returned by these functions is one of 3:

  • 0 means the unit cannot use the weapon, and the loop is exited.
  • 1 means the unit can use the weapon, and the loop is exited.
  • 2 means to continue the loop.

WTA Calc Loop

void WTAFunc(struct BattleUnit* bunitA, struct BattleUnit* bunitB)

The WTA Calc Loop is run immediately after calculating the weapon triangle stat bonuses.

Turn Loop

The Turn Loop encompasses a few different calc loops, each with their own signature:

void StartOfTurnSilentFunc()

The TurnCalcLoop_Silent list contains functions that run silently at the start of each turn. They take no arguments and return no value. This is the only turn loop that runs multiple functions per frame: every other loop only runs one function per frame.

void StartOfTurnFunc(struct Proc* parent)

The StartOfTurnCalcLoop list contains functions that run at the start of each turn. They take a proc as an argument, and blocking that proc allows them to apply effects before the loop advances.

void EndOfTurnFunc(struct Proc* parent)

The EndOfTurnCalcLoop list contains functions that run at the end of each turn. They take a proc as an argument, and blocking that proc allows them to apply effects before the loop advances.

Modular Stat Getters

Modular Stat Getters are used when calculating a unit's stats. All stat getters use the same function signature.

u8 StatGetterFunc(u8 stat, struct Unit* unit)

stat is the stat as has been calculated so far by the loop. unit is the unit whose stat is being calculated. Returns the modified stat, to be passed to the next function in the loop.