[FE8] Unit Status Rework (expanded buff & debuff types up to 63)

FE8U Unit-Status Rework

Download Here

updated 2022.05.25: fixed on MSG function to adapt to SkillSystem_FE8, add a new mss_def.s in folder /external for ModularStatScreen. Thanks for @Mikey_Seregon 's testing.


FE8U Unit-Status Rework

In vanilla, unit status (buff & debuffs) use a u8 byte at Unit Struct +0x30, 4 bits for status-index, 4 bits for status-duration. As a result, unit can only hold no more than 15 status, since there have been 13 status used in vanilla, hackers can only make 2 more status in vanilla routine.

Previously, SME tried to modify this by expanding the status index to 5 bits, but failed to handle the skill duration decreasing at the beginning of the turn. In this hack, I have expanded unit status index to 6 bits, which can support up to 63 different states simultaneously. Meanwhile, through a series of modifications, we successfully used the remaining 2 bits to make the status last for up to 4 turns.

At the same time, a table is build to store status informations, such as, how unit’s atk decrese during suffering this status or how long will this status continue, etc.

In addition, it provides adaptations for currently common patches, such as MSG and ModExpSave.

How to Use it

Directly include “UnitStatus.event”, then you will get this patch installed. As examples, I have makde some status as templetes, include “avoid”(unit grants avoid rate +15% in one turn), “Gravity”(unit cannot move in one turn), “Expose Def”(unit Def -5 in one turn), etc. All of these status is defined in Templates/UnitStatusDef.h, you can directly use function void SetUnitStatus(struct Unit* unit, int statusId) to give units status.

Meanwhile, you need to put functions defined in External folder to support patchs, including:

  • Modular Status Getter: “PowGetter_UnitStatus” to power-getter loop, “MagGetter_UnitStatus” to magic-getter loop …

  • Expanded Modular Save: “MSu_SaveUnitStatus” and “MSu_LoadUnitStatus” to save-suspand table, which needs 0x89 bytes to store data.

  • Pre-Battle Calc: “BC_UnitStatus” to Pre-Battle Calc loop.

  • Modular Stat Screen: use the fixed mss_def.s inside folder /external

How to make your own status

Please refer to Templates folder:

  • Add your status declearation to UnitStatusDef.h and UnitStatusDef.event

  • Create a new folder for your own.

  • Inside which, make the status info(struct UnitStatusInfo), on refer to include/unit-status.h

Note

  • in struct UnitStatusInfo, each status hold two attributes, “is_debuff” and “is_buff”, if you defined the status as .is_debuff = 1, then this status duration will decrease at enimy’s turn, otherwise decrease in its own turn.

  • “gbafe.h” which is included inside c files is used as FE-CLib-Mokha

9 Likes

a more polished example (gravity status):
cSkillSys3

5 Likes

there’s actually a fully functional version of my implementation floating around but I don’t think the download link on here was ever updated for various logistical reasons

1 Like

If there has been a solution to this problem before, that would be really nice.

But I think this hack is still meaningful, including rebuilding the database about various status informations, and expanding sprites object anim effects, etc.

1 Like

Yeah this is definitely still cool and useful :+1:
with this many IDs, now we can implement every Gungnir status effect in GBAFE

1 Like

I’m trying this, but there are some .event files that aren’t compiled.

error: C:\[...]\UnitStatusRework\Templates\UnitStatusInstaller.event:9:11: Could not find file "Gravity/GravityInfo.lyn.event".
error: C:\[...]\UnitStatusRework\Templates\UnitStatusInstaller.event:19:11: Could not find file "ExposeDef/ExposeDefInfo.lyn.event".
error: C:\[...]\UnitStatusRework\Templates\UnitStatusInstaller.event:29:11: Could not find file "ExposeRes/ExposeResInfo.lyn.event".
error: C:\[...]\UnitStatusRework\Templates\UnitStatusInstaller.event:38:11: Could not find file "Weaken/WeakenInfo.lyn.event".
error: C:\[...]\UnitStatusRework\Templates\UnitStatusInstaller.event:47:11: Could not find file "Avoid/AvoidInfo.lyn.event".
error: C:\[...]\UnitStatusRework\Templates\UnitStatusInstaller.event:56:11: Could not find file "AvoidPlus/AvoidPlusInfo.lyn.event".

How can I compile those files?

Oh it’s my fault that forgot to compile C files inside Templates folder. I have updated the repo, and I think now you will make it.

1 Like

As for compiling, you need to make the makefile find the C-Lib header “gbafe.h”(here used as FE-CLib-Mokha) and the file “include/unit-status.h” inside the repo. If you have no idea how to compile C, it is recomended on refering to StanH’s C Toturial

Here is my example on buildfile construction (in which, unit status hack is in ‘Wizardry/CoreHacks/UnitStatus’ and ‘Wizardry/Features/UnitStatusInstaller’),you can also refer to StanH’s CHAX repo

1 Like

I’m having some problems implementing this.

I included the UnitStatus.event in the build, then added PowGetter_UnitStatus and MagGetter_UnitStatus to the respective MSG:

EngineHacks\Necessary\StatGetters\Power.event:
[...]
pPowerModifiers:
	POIN prAddUnitPower prHalveIfCapturing prDebuffStr prAddEquipPower prItemPassivePow prRallyStr prLifeAndDeathBonus prFortressDefensePow VigorDanceCheck prFortressResistancePow prResolve prDefiantStr prPushStr prPlusStr prEnfeebleStrDebuff prEquipmentStrBonus PowGetter_UnitStatus
	#ifdef DEBUFFS_MIN_ZERO
	POIN prMinZero
	#endif
WORD 0
[...]

EngineHacks\Necessary\StatGetters\Power.event:
[...]
pMagicModifiers:
	POIN prAddUnitMagic prAddEquipMagic prDebuffMag-1 prRallyMag-1 prFortressDefensePow prFortressResistancePow prItemPassiveMag VigorDanceCheck prLifeAndDeathBonus prDefiantMag prPushMag prPlusMag prEnfeebleMagDebuff prEquipmentMagBonus
	#ifdef DEBUFFS_MIN_ZERO
	POIN prMinZero
	#endif
WORD 0 
[...]

For the Expanded Modular Save:

EngineHacks\Necessary\ExpandedModularSave\ExModularSave.event:
[...]
	// Permanent eids (moved here because of a mistake in the previous allocation)
	DeclSaveChunk($2DA8, $0019, $0A3150+1, $0A3198+1)

	DeclSaveChunk($2DC1, $0089, MSu_SaveUnitStatus, MSu_LoadUnitStatus)
[...]

And finally added BC_UnitStatus to EngineHacks\Necessary\CalcLoops\PreBattleCalcLoop\PreBattleCalcLoop.event

But the game crashes as soon as I try to do any action with any unit, it even crashes when trying to see the unit status screen.

Then I tried it in a clean Skill System build, but now the units get random buffs/debuffs:
SkillsTest.emulator_01SkillsTest.emulator_02

What am I doing wrong?
Or this isn’t compatible with the Skill System build?

I think the problem lies in two point, one for draw-unit-stat routinue in MSS’s mss_def, one for existing debuff hacks.

as for MSS, you should modify the macro draw_status_text_at as below:

.macro draw_status_text_at, tile_x, tile_y, colour=Blue  
  draw_textID_at \tile_x, \tile_y, 0x4fa, width=9 @cond
  mov     r4, r7
  sub     r4, #8
  mov     r1, r8  
  mov     r0, r1   
  blh     WriteStatusText
  mov     r3, r0     
  mov     r0, r4 
  mov     r1, #0x16        @16 if status, otherwise 18???
  mov     r2, #\colour   
  blh     Text_InsertString, r4
  mov     r0, r8
  blh     GetUnitStatusDura
  mov     r2, r0
  cmp     r2, #0
  beq     NoStatusCount
  ldr     r0, =(0x2003ca2+(0x20*2*\tile_y)+(2*\tile_x))
  mov     r1, #0
  blh     DrawUiSmallNumber
  NoStatusCount:
.endm

Since the Stat-Screen Draw-Page routinue in my own work is directly writen in C, so I did not focus on how to adapt to MSS berfore (And I also recommend you rewrite the draw page routinue in C, on reference of Decomp project).

Also, there seem to be some modifications to Unit Status within SkillSystem_FE8, such as External/StatusWeapons, in which it also set the UnitStruct + 0x30 in the way that conflict to this patch.

Finally, It seems that the calculation result of Unit Power is a negative number, and the calculation process fails to zero the negative value . It is recommended to use No$GBA to check the calculation result of Modular Power Getter (function: GetUnitPower, 0x80191B1 in vanilla).

besides, did you properly set the status duration? Since the status duration just occcupy the highest 2 bits, if you set the wrong value such as “0x14”, the status index will be “0x14” rather than 0x4

The stat buffs/debuffs appear even when the unit doesn’t have an status.

As for the duration, I tested Poison with 0x41, 0x81 and 0xC1 and they seem to work fine, except that it doesn’t show the correct number:
SkillsTest.emulator_01SkillsTest.emulator_02
In both images the status is 0x41
image

it worked well on status duration. If you set as 0x01, you will get one turn status.

I think I have found the reason on msg bug.

In SkillSystem_FE8U,MSG function is called as:
s8 ( * ) (s8 cur, struct Unit * ), but in my status-getter in cSkillSys, MSG function is called as s8( * )(struct Unit *, s8 cur).

You may rewrite the MSG function as:

NewPowerGetter_UnitStatus:
push {lr}
mov r2,r0
mov r0,r1
mov r1,r2
blh PowerGetter_UnitStatus
pop {pc}

Another potential problem may lie in prMinZero. Maybe you also need to check whether DEBUFFS_MIN_ZERO has been uncommented.

1 Like

This fixed that bug.

I still can’t fix the MSS.
I changed the macro an recompiled the files using that macro, but still doesn’t show the correct number

Have you replaced the macro draw_status_text_at?

Turns out I was editting the wrong mss_defs file.

It’s working now.

Thank you very much!

1 Like

I have now updated the repo, now you shall not bother for adapting to MSG functions.

1 Like

I found another bug.

Apparently this isn’t compatible with SkillSys’ debuff system.

Debuffs don’t get applied correctly:
SkillsTest.emulator_01
(Correct debuffs are -4 Skl/Spd/Mag)

And debuffs don’t decrease each turn, as they should.
SkillsTest.emulator_02
(Ex.: when you get affected by a Seal skill in the enemy turn, in your turn the debuff should be -5, but it remains as -6 until the chapter ends)

Rallies also are infinite.
SkillsTest.emulator_03

I tested this on a vanilla ROM+SkillSys+Unit Status Rework.

Truly it is.

In SkillSys_FE8, since it has only reach up to 5 bits for restoring debuff index(which means max number = 2^5 = 32, not to mention that the debuffs in vanllia has taken up to 10+ index), there are a lot of alternative methods to make it to get more buff & debuffs, such as introducing patch: Necessary/SuspendedDebuffs in SKillSys_FE8 to make an external table to store more debuff index.

At the same time, the non-standard API interface operation in SkillSys_FE8 will also destroy the stability of the patch. Such as, in ExternalHacks/StatusWeapon, people should use the common API, function void SetUnitStatus(struct Unit* unit, int statusId) and void SetUnitStatusExt(struct Unit* unit, int status, int duration) rather than directly store bytes in unit struct.

There should be other places that need to be adapted, The main problem should be that in SkillSys_FE8, the patch fails to call the API function correctly