[FE7 and FE8] Shuusuke's Simple Sorcery

I almost titled this thread “Shuu’ssembly” before the alliteration dawned upon me

I don’t make it a secret that I’m not a fan of ASM, but even then, I’ve done some very basic stuff that I figured I should put together somewhere, and thus this here SSS was created.

I’ll include whether there is an FEBuilder patch for it (and if not, why), the source(s) for more information if there are any, explanations and images of the result/how to do it. Thanks to 7743, Sme, Leonarth, Pikmin, Epicer, and Vesly for helping with some of these at some point. They’re currently FE8 exclusive, some specifically for FE8U only.

Change easy/normal mode penalty into bonus

FEB Patch: “Change Easy and Normal modes level penalty into level bonus”
Source: [FE7/FE8] Difficulty stat changes
image
With this, the values previously read to lower autoleveled unit’s levels in easy and normal modes will instead be used to increase their level, like what’s done for hard mode. (Note that FEBuilder’s interface won’t change to reflect the patch).
Example of the same unit in Normal mode using the same modifier of 0xF (15 levels), left is vanilla behavior (penalty, essentially nothing since the unit has less than 15 levels), right is with the edit (stats are calculated as if the unit was 15 levels above their actual level).


The idea for this was that you would design around the Easy difficulty having no modifiers, so that you could have two increased difficulty options.

How to do it: In the Disassembler, go to address 18064, go to line 080180FA, and change the value 08018064 to 08017FC4. image

Allow the player to trade with NPCs

FEB Patch: No, because it conflicts with Capture, which is part of the skill system. If you use the skill system, the code will be different and this won’t work.
Source: N/A
image

How to do it: Go to address 2521C, line 0802522E , and change the value there to 08024D8Cimage

Allow Enemies/NPCs/Other units to also gain exp

FEB Patch: No, because there are visual glitches, but it still functions normally otherwise.
Source: N/A
image image
Visual bug: image
The Soldier is the one who leveled up, but it displays Eirika’s data instead, since only the unit on the right can normally level up. Also, since the Soldier uses a generic portrait, it displays a broken image instead. But it occurred correctly, and as seen above, the Soldier’s stats were updated. Both units leveling up will also occur correctly, despite graphical bugs.

How to do it: Go to address 2B9F4, line 0802BA0E, the default value there is 0xC0, meaning only blue units can gain exp. To make it so all units can gain EXP, change it to 0x0 like in the image. Change to 0x40 to allow only enemies to gain EXP, or 0x80 to allow only NPCs to gain EXP.


Once this is done, you have to set the EXP of the units that you want to level up to a value other than 255, which is another condition that restricts EXP gain in vanilla, and was not changed for convenience (this makes it so units don’t break their level cap, and lets you select which units can gain EXP instead of making all of them do so unconditionally) through events. With the “Set all unit status” patch it’s easy to set this for multiple units at once, if that’s what you want. Note that units will use their unit growths when leveling up this way, regardless of autolevel, even generics.

Allow the player to steal from NPCs

FEB Patch: Allow the player to steal from NPCs (green units)
Source: N/A
image
How to do it: Go to 25BA0, lines 08025BAA and 08025BAC, change r0 to r1 and #0x80 to r0 respectively.image
NPCs won’t steal from the player, even with this.

Allow Enemies/NPCs/Other units to get droppable items

FEB Patch: Remove restriction on droppable items
Source: N/A
image image image image image image
How to do it: Go to 3292C, line 08032942, the default value is 0xC0, meaning only blue units. Change to 0x0 to allow all units to get droppable items, 0x40 to allow NPCs, or 0x80 to allow enemies.
image
Note that if an enemy/npc gets an item and can’t carry any more, the player will be prompted to discard or store one of their items, depending on whether the convoy is enabled.

Get currently pressed keys

FEB Patch: GetCurrentlyPressedKeys
Source:This post, 7743 later improved the code which is listed below.


This is an ASMC, so if you use FEBuilder, just apply the patch. If you don’t use FEBuilder, the code is listed below.
This ASMC makes it so the bitmask of the keys being pressed by the player are returned to memory slot C. The bitmask is the same used for vanilla command IGNORE_KEYS, so A is 1, B is 2, A+B is 3, select is 4, and so on. FEBuilder’s patch also includes a command to check if the pressed keys are the one(s) you want, using the intuitive menu you see in the images.

//GetCurrentlyPressedKeys.s

.thumb
ldr r0,=0x2024CC0 @Key press bitfield pointer
ldrh r1,[r0,#0x4] @Key press bitfield start <<<<
mov r2,r1
ldr r0,=0x30004B8 @FE8U MemorySlot0
mov r1,#0x0C @FE8U MemorySlotC
lsl r1,#2
str r2,[r0,r1]
bx lr

At first this was made to simulate RPG walking, but later Sme’s Free Walk ASMC was made, so it was surpassed for this purpose. Still, you can use it if you want to know what the player is pressing during an event, such as letting the player decide with direction to move to by checking the right/left keys, or if they approve/deny a suggestion by checking A/B, and so on.

Allow enemy/NPC dancers/thieves/summoners to gain exp from dancing/stealing/summoning

In function
2C6A0, go to line 0802C6A8 and change the 0xC0 value to 0x00


image

Enable Augury on hard mode (FE7U)

This enables Augury even on hard mode. It’s still disabled in Lyn mode.
For EA:

PUSH
ORG $9930A
SHORT 0x2001
POP

For FEBuilder

NAME.en=Enable viewing Augury on hard mode [FE7U]
INFO.en=Normally, you can only view Augury on normal mode. This patch lets you change that.
AUTHOR=Shuusuke

TYPE=SWITCH
TAG=#ENGINE

COMBO=Default|OFF|Fix|FIX

OFF:0x9930A=0x00 0x20

FIX:0x9930A=0x01 0x20

Count Unit Range State

This ASMC is a variation of 7743’s “count unit” patches which lets you specify a unit state as a condition, like “dead”, “under a roof”, etc.

@Original author: 7743
@State check added by Shuusuke

.align 4
.macro blh to, reg=r3
  ldr \reg, =\to
  mov lr, \reg
  .short 0xf800
.endm
.thumb

push {r4,r5,r6,lr}
                    @MemorySlot1 (UnitID)  00=ANY
                    @MemorySlot2 (ClassID) 00=ANY
                    @MemorySlot3 (ItemID)  00=ANY
                    @MemorySlot4 (affiliation)  FF=ANY 00=Player 01=Enemy 02=NPC
                    @MemorySlot5 XXYY start range
                    @MemorySlot6 XXYY end   range
                    @MemorySlot7 (State)   00=ANY

mov r6,#0x0	@Countup

@ldr  r4,=0x030004B0 @MemorySlot FE8J
ldr  r4,=0x030004B8 @MemorySlot FE8U

@ldr r0, =0x0202BE48 @UnitRAM FE8J
ldr r0, =0x0202BE4C @UnitRAM FE8U

ldr r5,=0x85 * 0x48 @Player+Enemy+NPC
add r5,r0

sub r0,#0x48        @Because it is troublesome, first subtract

next_loop:
cmp r0,r5
bgt break_loop

add r0,#0x48

ldr r2, [r0]          @unitram->unit
cmp r2, #0x00
beq next_loop         @Check Empty

ldr r2, [r0,#0xC]    @unitram->status
ldr r3,[r4,#0x07 * 4] @MemorySlot7 (State)
cmp r3,#0x00
beq check_unit_id
and  r2,r3
cmp  r2,r3          @state mismatch
bne  next_loop

check_unit_id:
ldr r3,[r4,#0x01 * 4] @MemorySlot1 (UnitID)
cmp r3,#0x00
beq check_class_id

ldr r2, [r0]          @unitram->unit
ldrb r2, [r2, #0x4]   @unitram->unit->id
cmp  r2, r3
bne  next_loop

check_class_id:
ldr r3,[r4,#0x02 * 4] @MemorySlot2 (ClassID)
cmp r3,#0x00
beq check_item_id

ldr r2, [r0, #0x4]    @unitram->class
cmp r2, #0x00
beq next_loop

ldrb r2, [r2, #0x4]   @unitram->class->id
cmp  r2, r3
bne  next_loop


check_item_id:
ldr r3,[r4,#0x03 * 4]  @MemorySlot3 (ItemID)
cmp r3,#0x00
beq check_affiliation

ldrb r2, [r0, #0x1e]    @unitram->item1
cmp  r2, r3
beq  item_match

mov  r2, #0x20
ldrb r2, [r0, r2]    @unitram->item2
cmp  r2, r3
beq  item_match

mov  r2, #0x22
ldrb r2, [r0, r2]    @unitram->item3
cmp  r2, r3
beq  item_match

mov  r2, #0x24
ldrb r2, [r0, r2]    @unitram->item4
cmp  r2, r3
beq  item_match

mov  r2, #0x26
ldrb r2, [r0, r2]    @unitram->item5
cmp  r2, r3
bne  next_loop

item_match:
check_affiliation:

ldr r3,[r4,#0x04 * 4] @MemorySlot4 (affiliation) 
cmp r3,#0xFF          @FF=ANY
beq affiliation_match

ldrb r2, [r0, #0xb]    @unitram->affiliation

cmp r3,#0x01          @01=Enemy
beq check_affiliation_enemy

cmp r3,#0x02          @02=NPC
beq check_affiliation_npc

check_affiliation_player: @00=Player
                          @Player that did misconfiguration is treated as Player.
cmp r2,#0x40          @if (unit->affiliation >= 0x40){ cotinue; }
bge next_loop
b   affiliation_match

check_affiliation_npc:
cmp r2,#0x40          @if (unit->affiliation < 0x40 || unit->affiliation >= 0x80){ cotinue; }
blt next_loop
cmp r2,#0x80
bge next_loop
b   affiliation_match

check_affiliation_enemy:
cmp r2,#0x80          @if (unit->affiliation < 0x80){ cotinue; }
blt next_loop
@b   affiliation_match


affiliation_match:
check_range:
ldr r3,[r4,#0x04 * 6] @MemorySlot6 (end range) 
cmp r3,#0x0           @00=ANY
beq check_match

ldrb r1, [r0, #0x10]    @unitram->x
ldrb r3,[r4,#0x04 * 5 + 0] @MemorySlot5 (start->x) 
cmp  r1,r3
blt  next_loop

ldrb r1, [r0, #0x11]    @unitram->y
ldrb r3,[r4,#0x04 * 5 + 2] @MemorySlot5 (start->y) 
cmp  r1,r3
blt  next_loop

ldrb r1, [r0, #0x10]    @unitram->x
ldrb r3,[r4,#0x04 * 6 + 0] @MemorySlot6 (end->x) 
cmp  r1,r3
bgt  next_loop

ldrb r1, [r0, #0x11]    @unitram->y
ldrb r3,[r4,#0x04 * 6 + 2] @MemorySlot6 (end->y) 
cmp  r1,r3
bgt  next_loop
@b check_match

check_match:
found:

	add r6,#0x01

b   next_loop

break_loop:

str  r6,[r4,#0x0C * 4]    @MemorySlotC (Result Value)
mov r0,r6

pop {r4,r5,r6}
pop {r1}
bx r1


Autolevel player unit

I submitted this to FEBuilder and it was made a patch. The code is below.

.align 4
.macro blh to, reg=r3
ldr \reg, =\to
mov lr, \reg
.short 0xf800
.endm

.thumb
.equ MemorySlot0, 0x30004B8
.equ GetUnitByCharId, 0x0801829C
.equ GetUnitByEventParameter, 0x800bc50
.equ CopyUnitToBattleStruct, 0x0802A584
.equ CheckForLevelUp, 0x0802BA28
.equ SaveUnitFromBattle, 0x0802C1EC
.equ EnsureNoUnitStatCapOverflow, 0x80181c9

PUSH {r4-r7,lr}
SUB SP, #0x80
LDR r0, =MemorySlot0 @FE8U MemorySlot0
LDR r5,[r0,#0x20] @FE8U MemorySlot8 - # of levels
LDR r0,[r0,#0x1C] @FE8U MemorySlot7 - Unit ID
BLH GetUnitByEventParameter @0x800bc50
cmp r0, #0
beq Exit

ldrb r1, [r0,#0xB] @Do not use for enemies
cmp r1, #0x40
bge Exit

ldrb r1, [r0, #0x9] @Get unit exp
cmp r1, #0x64 @check EXP:–
bge Exit @level caps

cmp r5, #0x0 @ what’s LV+0?
beq Exit

MOV r6 ,r0 @Copy unit address
@Get unit level
LDRB r4, [r6, #0x8] @ current lvl
add r5, r4 @ # of lvls + current lvl = final lvls

LoopStart:
MOV r7, SP
MOV r0, SP
MOV r1 ,r6
BLH CopyUnitToBattleStruct
LDRB r0, [r7, #0x9]
ADD r0, #0x64
STRB r0, [r7, #0x9]
MOV r0, SP
BLH CheckForLevelUp

LDRB r0, [r7, #0x9] @Get unit exp
CMP r0, #0x64
BLT NotMaxLevel @If the unit already reached its level cap, do not give more levels
MOV r0 ,r6
MOV r1, SP
BLH SaveUnitFromBattle
B MaxLevel

NotMaxLevel:
MOV r0 ,r6
MOV r1, SP
BLH SaveUnitFromBattle
ADD r0 ,r4, #0x1
LSL r0 ,r0 ,#0x18
LSR r4 ,r0 ,#0x18
CMP r4 ,r5
BCC LoopStart

MOV r0, #0x0 @Set EXP to 0
STRB r0, [r6, #0x9]

MaxLevel:
mov r0, r6 @ unit
blh EnsureNoUnitStatCapOverflow

Exit:

ADD SP, #0x80
POP {r4,r5,r6,r7}
POP {r0}
BX r0

.ltorg
.align 4

To use in FEBuilder, go to the Insert ASM/C menu, copy the address and click Run. In events, use the CALL ASMC command, paste the copied address and add +1 to it, then click Write. When you CALL, the value in slot 7 is the ID of the unit you want to autolevel, and slot 8 is the amount of levels you want to give to the unit. (Note that the addresses in the image don’t match since I show the Insert menu after already inserting file)

This uses the same routines as the vanilla game uses after the route split, but isn’t hardcoded to Eirika or Ephraim and doesn’t do the other things it also does (such as giving a steel weapon and weapon experience). It will not work on enemy units, which is why in the example I make O’Neill a playable unit first, and change him back after autoleveling.

This routine will stop giving levels once the unit has reached its level cap, by checking that its exp has become – through the game’s own judgement, so any alterations you make to level caps will accurately be reflected. As an aside, unless you intentionally edit ExModularSave, levels after 31 won’t correctly be saved, though they can still be set and will be respected by this routine.

Special thanks to Contro and Vesly for their help with making this, and 7743 for various fixes after my initial code and for making the FEBuilder patch. Incidentally, Vesly also has an Autolevel patch in FEBuilder, which uses class growths instead, while mine uses unit growths.

EraseZombies, GetSuccessor, SetUnitStatusByCommander
Demon King Summons Allegiance, 11 staff targetting-related ones, and CUSF

21 Likes

:eyes: cool stuff

I see you like to do stuff with NPCs as an opposing army, hah

1 Like
My master plan

9 Likes

sus-sembly

1 Like

If you make a patch, I’ll register it.
In FEBuilderGBA, patches that fix multiple locations are implemented as switch patches.

For example, the patch that fixes 0x73758 and 0x73D2C, 0x73722 is written as follows.
When Default is selected, the OFF item is executed, and when Fix is selected, the FIX item is executed.

NAME.en=Fixed the display of large level-up screens
INFO.en=Move the text tiles in vram so that they don't overwrite the battle screen's larger tiles

TYPE=SWITCH
TAG=#ENGINE

COMBO=Default|OFF|Fix|FIX

OFF:0x73758=0xC0 0x28 0x00 0x06
OFF:0x73D2C=0x8C 0x22 0x12 0x01
OFF:0x73722=0xA3 0x22

FIX:0x73758=0x00 0x3C 0x00 0x06
FIX:0x73D2C=0x1C 0x22 0x12 0x02
FIX:0x73722=0xF0 0x22
2 Likes

The only one that I may have forgotten to ask about was the fourth one, which allows the player to steal from NPCs. I don’t know if it would conflict with other patches, but the patch file for what I described in the first post should look like this:

NAME.en=Allow the player to steal from NPCs (green units)
INFO.en=Normally blue units can only steal from enemies, but this patch also allows them to steal from NPCs if the other requirements for stealing are met.\r\nNPCs won’t be able to steal from the player even if this is done.\r\n
AUTHOR=Shuusuke [FE7 and FE8] Shuusuke's Simple Sorcery

TYPE=SWITCH
TAG=#ENGINE

COMBO=Default|OFF|Fix|FIX

OFF:0x25BAA=0x08 0x40 0x80 0x28

FIX:0x25BAA=0x09 0x40 0x80 0x42

The others I already asked about previously, and I listed the explanation you gave me for why you didn’t add them to FEBuilder.

Also, I forgot to add GetCurrentlyPressedKeys to the first post, so I’ll be doing that.
EDIT: Done that.
EDIT2: Allow the player to steal from NPCs (green units) was added to FEBuilder’s patches.

1 Like

Updated first post with Allow enemy/NPC dancers/thieves/summoners to gain exp from dancing/stealing/summoning

4 Likes

Made one for FE7U, this enables Augury even on hard mode. It’s still disabled in Lyn mode.
For EA:

PUSH
ORG $9930A
SHORT 0x2001
POP

For FEBuilder

NAME.en=Enable viewing Augury on hard mode [FE7U]
INFO.en=Normally, you can only view Augury on normal mode. This patch lets you change that.
AUTHOR=Shuusuke

TYPE=SWITCH
TAG=#ENGINE

COMBO=Default|OFF|Fix|FIX

OFF:0x9930A=0x00 0x20

FIX:0x9930A=0x01 0x20

Updated first post with this.

3 Likes

Hey there, I had been wanting to make it so that the rescue staff couldn’t be used on NPCs, and thanks to looking through your stuff, I was able to do it, so thank you.

The highlighted value is the one to change for anyone who’s curious.

1 Like

Finally, I venture beyond inline editing. Added Autolevel player units to the first post. Special thanks to Vesly and Contro for helping with making it.

EDIT: Updated the first post with 7743’s fixes to the routine.

1 Like

Made 3 ASMCs a few days ago, they’re all added to FEBuilder as patches but I forgot to make a post on them. Thanks to Contro, Huichelaar, Stan, Sme, Vesly and 7743 for the help in making them.

ClearZombies

This ASMC goes through all units and erases those that have 0 HP or are set to Dead. You can use it to free slots in the player roster by erasing dead units (instead of having to use CHECK_ALIVE and erasing them one-by-one), to ensure that an event battle erased the unit(s) that died in it (particularly convenient if the units involved in it can vary), or if you want something that affects multiple units (say, an event that damages units within an area, or an AoE skill like Savage Blow) to also be able to kill them (since this won’t happen even if said something does get the units HP to 0). Truth be told, I made this as a safeguard to ensure you don’t have any lingering units that shouldn’t be around anymore (which is why I refer to them as zombies, also because I think zombie process sounds funny).

@
@
@Author 7743
@"Zombie" edits by Shuusuke
@
.align 4
.macro blh to, reg=r3
  ldr \reg, =\to
  mov lr, \reg
  .short 0xf800
.endm
.thumb

push {r4,r5,lr}
                    @MemorySlot1 (UnitID)  00=ANY
                    @MemorySlot2 (ClassID) 00=ANY
                    @MemorySlot3 (ItemID)  00=ANY
                    @MemorySlot4 (affiliation)  FF=ANY 00=Player 01=Enemy 02=NPC 03=Purple

@ldr  r4,=0x030004B0 @MemorySlot FE8J
ldr  r4,=0x030004B8 @MemorySlot FE8U

@ldr r0, =0x0202BE48 @UnitRAM FE8J
ldr r0, =0x0202BE4C @UnitRAM FE8U

@ldr r5,=0x85 * 0x48 @Player+Enemy+NPC
ldr r5,=0x99 * 0x48 @Player+Enemy+NPC+Purple 
add r5,r0

sub r0,#0x48        @Because it is troublesome, first subtract

next_loop:
cmp r0,r5
bgt break_loop

add r0,#0x48

ldr r2, [r0]          @unitram->unit
cmp r2, #0x00
beq next_loop         @Check Empty

ldrb r2, [r0,#0xC]    @unitram->status
mov  r3,#0x4          @dead
and  r2,r3
cmp  r2,#0x0          @proceed if unit has the dead state set, else check if current HP == 0
bne  IsZombie

ldrb r2, [r0,#0x13]    @unitram->Current HP        
cmp  r2,#0x00          @proceed if unit has 0 HP, else check next unit
beq  IsZombie
bne next_loop

IsZombie:

check_unit_id:

ldr r3,[r4,#0x01 * 4] @MemorySlot1 (UnitID)
cmp r3,#0x00
beq check_class_id

ldr r2, [r0]          @unitram->unit
ldrb r2, [r2, #0x4]   @unitram->unit->id
cmp  r2, r3
bne  next_loop

check_class_id:
ldr r3,[r4,#0x02 * 4] @MemorySlot2 (ClassID)
cmp r3,#0x00
beq check_item_id

ldr r2, [r0, #0x4]    @unitram->class
cmp r2, #0x00
beq next_loop

ldrb r2, [r2, #0x4]   @unitram->class->id
cmp  r2, r3
bne  next_loop


check_item_id:
ldr r3,[r4,#0x03 * 4]  @MemorySlot3 (ItemID)
cmp r3,#0x00
beq check_affiliation

ldrb r2, [r0, #0x1e]    @unitram->item1
cmp  r2, r3
beq  item_match

mov  r2, #0x20
ldrb r2, [r0, r2]    @unitram->item2
cmp  r2, r3
beq  item_match

mov  r2, #0x22
ldrb r2, [r0, r2]    @unitram->item3
cmp  r2, r3
beq  item_match

mov  r2, #0x24
ldrb r2, [r0, r2]    @unitram->item4
cmp  r2, r3
beq  item_match

mov  r2, #0x26
ldrb r2, [r0, r2]    @unitram->item5
cmp  r2, r3
bne  next_loop

item_match:
check_affiliation:
ldr r3,[r4,#0x04 * 4] @MemorySlot4 (affiliation) 
cmp r3,#0xFF          @FF=ANY
beq affiliation_match

ldrb r2, [r0, #0xb]    @unitram->affiliation

cmp r3,#0x01          @01=Enemy
beq check_affiliation_enemy

cmp r3,#0x02          @02=NPC
beq check_affiliation_npc

cmp r3,#0x03          @03=Purple
beq check_affiliation_purple

check_affiliation_player: @00=Player
                          @Player that did misconfiguration is treated as Player.
cmp r2,#0x40          @if (unit->affiliation >= 0x40){ cotinue; }
bge next_loop
b   affiliation_match

check_affiliation_npc:
cmp r2,#0x40          @if (unit->affiliation < 0x40 || unit->affiliation >= 0x80){ cotinue; }
blt next_loop
cmp r2,#0x80
bge next_loop
b   affiliation_match

check_affiliation_enemy:
cmp r2,#0x80          @if (unit->affiliation < 0x80 || unit->affiliation >= 0xC0){ cotinue; }
blt next_loop
cmp r2,#0xC0
bge next_loop

check_affiliation_purple:
cmp r2,#0xC0          @if (unit->affiliation < 0xC0){ cotinue; }
blt next_loop
@b   affiliation_match


affiliation_match:
found:
	bl Update

b   next_loop

break_loop:
@	blh  0x08019ecc   @RefreshFogAndUnitMaps	@FE8J
@	blh  0x08027144   @SMS_UpdateFromGameData	@FE8J
@	blh  0x08019914   @UpdateGameTilesGraphics	@FE8J
	blh  0x0801a1f4   @RefreshFogAndUnitMaps    @FE8U
	blh  0x080271a0   @SMS_UpdateFromGameData   @FE8U
	blh  0x08019c3c   @UpdateGameTilesGraphics  @FE8U

pop {r4,r5}
pop {r1}
bx r1

@r0 current unit ram
@r1 temp
@r2 temp
@r3 temp
@r4 MemorySlot

Update:
push {r5,lr}
	mov r3, #0x0	@unit ID
	cmp  r3, #0x00            @unit pointer
	beq  set_str
	b Update_Exit

set_str:
	mov r2, #0x00
	str  r2, [r0,r3]
	b   Update_Exit


Update_Exit:

pop {r5}
pop {r1}
bx r1


GetSucessor

This one’s a little weird to explain but the short version is that it determines who should succeed as commander of an army/clan should the current leader die.
There aren’t examples like this in vanilla FE8 so I’ll give two from FE7 (even though this ASMC isn’t for FE7), in Dragon’s Gate, Darin’s successor would be Cameron, and in Battle Before Dawn, Ursula’s successor would be Maxime; this is because both Cameron and Maxime are bosses who have Darin and Ursula respectively set as their commanders. You could use this ASMC when Darin/Ursula die and, should Cameron/Maxime still be alive, make them the commander of the remaining generics.
There are two additional options, which is to enable non-bosses to be the successors (keep in mind that if there are multiple units of the same ID in a map and they get set as commander, there may be problems), as well as enabling female units from being successors (since traditionally, sons had priority over daughters when it came to succession, so I thought it made sense to make this an option should someone want to simulate it in their hack).
I had more plans for this ASMC but got fed up enough with ASM for the time being, so the base functionality will have to do

@Original author: 7743
@Sucessor check added by Shuusuke
.thumb
.align 4
.macro blh to, reg=r3
  ldr \reg, =\to
  mov lr, \reg
  .short 0xf800
.endm
.thumb

push {r4,r5,r6,r7,lr}
@ldr  r4,=0x030004B0 @MemorySlot FE8J
ldr  r4,=0x030004B8 @MemorySlot FE8U

mov r5,#0x00 @r5 = commander ID
mov r6,#0xFF @r6 = commander affiliation 0=P 1=N 2=E 3=F


ldrb r0,[r4,#0x01 * 4] @MemorySlot1 (UnitID) @r0 = commander ID
cmp r0,#0x00
beq exit_commander	@no commander?
mov r5,r0	
bl get_commander_affiliation
cmp r0,#0x03
ble valid_commander	@valid commander
mov r0,#0x00	@invalid commander
b exit_commander

valid_commander:
mov r6,r0
mov r1,r5
mov r2,r6
bl get_sucessor

exit_commander:
mov r7,#0x30
str  r0,[r4,r7]    @MemorySlotC (Result Value)



pop {r4,r5,r6,r7}
pop {r1}
bx r1


get_commander_affiliation:
	
push {r4,r5,r6,r7,lr}
	@r0 = commander ID
	@ldr r4, =0x0202BE48 @UnitRAM FE8J
	ldr r4, =0x0202BE4C @UnitRAM FE8U

@ldr r5,=0x85 * 0x48 @Player+Enemy+NPC
ldr r5,=0x99 * 0x48 @Player+Enemy+NPC+Purple
add r5,r4
mov r3,r0
sub r4,#0x48        @Because it is troublesome, first subtract

next_loop_commander:
@cmp r0,#0xFF
@bne found_affiliation

cmp r4,r5
bgt break_loop_commander

add r4,#0x48

ldr r2, [r4]          @unitram->unit
ldrb r2, [r2, #0x4]   @unitram->unit->id
cmp r2, r3
bne next_loop_commander
ldrb r0, [r4, #0xb]    @r0 = commander->affiliation
cmp r0,#0x40
blt player_commander
cmp r0,#0x80
blt npc_commander
cmp r0,#0xC0
blt enemy_commander
b purple_commander

player_commander:
mov r0,#0x00
b break_loop_commander
npc_commander:
mov r0,#0x01
b break_loop_commander
enemy_commander:
mov r0,#0x02
b break_loop_commander
purple_commander:
mov r0,#0x03
@b break_loop_commander
@r0=commander affiliation 0=P 1=N 2=E 3=F
break_loop_commander:
pop {r4,r5,r6,r7}
pop {r1}
bx r1


get_sucessor:
	
push {r4,r5,r6,r7,lr}
@r0 -> sucessor ID
@r1 = commander ID
@r2 = commander affiliation 0=P 1=N 2=E 3=F

@ldr r4, =0x0202BE48 @UnitRAM FE8J
ldr r4, =0x0202BE4C @UnitRAM FE8U

ldr r3,=0x85 * 0x48 @Player+Enemy+NPC
mov r7,r3
add r7,r4

mov r5, r1 	@r5 = commander ID
mov r6,	r2 	@r6 = commander affiliation 0=P 1=N 2=E 3=F

sub r4,#0x48        @Because it is troublesome, first subtract

next_loop_unit:
cmp r4,r7
ble continue_loop_sucessor
mov r0,#0x00
b get_sucessor_break_loop
continue_loop_sucessor:
add r4,#0x48

mov r3,#0x38
ldrb r2, [r4,r3]    @r2 = unitram->commander
cmp  r2,r5          @commander mismatch
bne  next_loop_unit


ldrb r1, [r4, #0xb]    @r2 = unitram->affiliation
cmp r1,#0x40
blt player_unit
cmp r1,#0x80
blt npc_unit
cmp r1,#0xC0
blt enemy_unit
b purple_unit

player_unit:
mov r1,#0x00
b unit_allegiance_found
npc_unit:
mov r1,#0x01
b unit_allegiance_found
enemy_unit:
mov r1,#0x02
b unit_allegiance_found
purple_unit:
mov r1,#0x03
b unit_allegiance_found

unit_allegiance_found:

cmp r1,r6         
bne next_loop_unit		@affiliation mismatch?
ldr r0, [r4]          @unitram->unit
ldrb r0, [r0, #0x4]    @r0 = unitram->ID


bl validate_restriction
cmp r0,#0x00
beq next_loop_unit	@candidate was found but invalidated due to restrictions
get_sucessor_break_loop:

pop {r4,r5,r6,r7}
pop {r1}
bx r1

validate_restriction:
	
push {r4,r5,r6,lr}
@r0 = unit ID
@MemorySlot 2 = EnableNonBoss
@MemorySlot 3 = EnableFemale
@ldr r4, =0x030004B0	@Slot0	{J}
ldr r4, =0x030004B8	@Slot0	{U}

ldr r1, [r4 , #0x2 * 4]	@Slot2
cmp r1,#0x00
bne test_female
mov r6, r0	@r6 = unit ID
@blh  0x0800bf3c           @UNITIDの解決 GetUnitStructFromEventParameter	{J}
blh  0x0800bc50           @UNITIDの解決 GetUnitStructFromEventParameter	{U}
@cmp  r0,#0x00
@beq  end_test         
mov  r5, r0
mov r0,r6

ldr  r1, [r5, #0x0] @RAMUnit->Unit
ldr  r3, [r5, #0x4] @RAMUnit->Class
ldr  r2, [r1, #0x28]
ldr  r3, [r3, #0x28]
orr  r3 ,r2

mov r2,#0x80
lsl r2,#0x08 @boss ability
and r2,r3
cmp r2,#0x00
bne test_female
mov r0,#0x00 @unit disqualified for not being a boss
b end_test

test_female:
ldr r1, [r4 , #0x3 * 4]	@Slot3
cmp r1,#0x00
bne end_test
@b test_lord
mov r6, r0	@r6 = unit ID
@blh  0x0800bf3c           @UNITIDの解決 GetUnitStructFromEventParameter	{J}
blh  0x0800bc50           @UNITIDの解決 GetUnitStructFromEventParameter	{U}
@cmp  r0,#0x00
@beq  end_test         
mov  r5, r0
mov r0,r6

ldr  r1, [r5, #0x0] @RAMUnit->Unit
ldr  r3, [r5, #0x4] @RAMUnit->Class
ldr  r2, [r1, #0x28]
ldr  r3, [r3, #0x28]
orr  r3 ,r2

mov r2,#0x40
lsl r2,#0x08 @female ability
and r2,r3
cmp r2,#0x00
beq end_test
mov r0,#0x00 @unit disqualified for being female
b end_test




end_test:

pop {r4,r5,r6}
pop {r1}
bx r1
SetUnitStatusCommander

A variation of the Set All Unit Status patch, which takes the commander as an additional parameter. You can use it to change the AI of all units who follow the same commander to simulate them giving orders, or lower/increase stats of all units when their commander dies, etc.

@Original author: 7743
@Commander check added by Shuusuke
.thumb
.align 4
.macro blh to, reg=r3
  ldr \reg, =\to
  mov lr, \reg
  .short 0xf800
.endm
.thumb
.equ GetUnitByEventParameter, 0x800bc50
push {r4,r5,r6,lr}
                    @MemorySlot1 (UnitID)  00=ANY
                    @MemorySlot2 (ClassID) 00=ANY
                    @MemorySlot3 (ItemID)  00=ANY
                    @MemorySlot4 (affiliation)  FF=ANY 00=Player 01=Enemy 02=NPC 03=Purple
		    @MemorySlot5 (Commander)   
                    @MemorySlotA Type
                    @MemorySlotB Value

@ldr  r4,=0x030004B0 @MemorySlot FE8J
ldr  r4,=0x030004B8 @MemorySlot FE8U

@ldr r0, =0x0202BE48 @UnitRAM FE8J
ldr r0, =0x0202BE4C @UnitRAM FE8U

@ldr r5,=0x85 * 0x48 @Player+Enemy+NPC
ldr r5,=0x99 * 0x48 @Player+Enemy+NPC+Purple
add r5,r0

sub r0,#0x48        @Because it is troublesome, first subtract

next_loop:
cmp r0,r5
bgt break_loop

add r0,#0x48

ldr r2, [r0]          @unitram->unit
cmp r2, #0x00
beq next_loop         @Check Empty

ldrb r2, [r0,#0xC]    @unitram->status
mov  r3,#0xC          @dead or not deploy
and  r2,r3
cmp  r2,#0x0          @maybe he is dead
bne  next_loop

check_unit_id:
ldr r3,[r4,#0x01 * 4] @MemorySlot1 (UnitID)
cmp r3,#0x00
beq check_class_id

ldr r2, [r0]          @unitram->unit
ldrb r2, [r2, #0x4]   @unitram->unit->id
cmp  r2, r3
bne  next_loop

check_class_id:
ldr r3,[r4,#0x02 * 4] @MemorySlot2 (ClassID)
cmp r3,#0x00
beq check_item_id

ldr r2, [r0, #0x4]    @unitram->class
cmp r2, #0x00
beq next_loop

ldrb r2, [r2, #0x4]   @unitram->class->id
cmp  r2, r3
bne  next_loop


check_item_id:
ldr r3,[r4,#0x03 * 4]  @MemorySlot3 (ItemID)
cmp r3,#0x00
beq check_affiliation

ldrb r2, [r0, #0x1e]    @unitram->item1
cmp  r2, r3
beq  item_match

mov  r2, #0x20
ldrb r2, [r0, r2]    @unitram->item2
cmp  r2, r3
beq  item_match

mov  r2, #0x22
ldrb r2, [r0, r2]    @unitram->item3
cmp  r2, r3
beq  item_match

mov  r2, #0x24
ldrb r2, [r0, r2]    @unitram->item4
cmp  r2, r3
beq  item_match

mov  r2, #0x26
ldrb r2, [r0, r2]    @unitram->item5
cmp  r2, r3
bne  next_loop

item_match:
check_affiliation:

ldr r3,[r4,#0x04 * 4] @MemorySlot4 (affiliation) 
cmp r3,#0xFF          @FF=ANY
beq affiliation_match

ldrb r2, [r0, #0xb]    @unitram->affiliation

cmp r3,#0x01          @01=Enemy
beq check_affiliation_enemy

cmp r3,#0x02          @02=NPC
beq check_affiliation_npc

cmp r3,#0x03          @03=Purple
beq check_affiliation_purple

check_affiliation_player: @00=Player
                          @Player that did misconfiguration is treated as Player.
cmp r2,#0x40          @if (unit->affiliation >= 0x40){ cotinue; }
bge next_loop
b   affiliation_match

check_affiliation_npc:
cmp r2,#0x40          @if (unit->affiliation < 0x40 || unit->affiliation >= 0x80){ cotinue; }
blt next_loop
cmp r2,#0x80
bge next_loop
b   affiliation_match

check_affiliation_enemy:
cmp r2,#0x80          @if (unit->affiliation < 0x80 || unit->affiliation >=0xC0){ cotinue; }
blt next_loop
cmp r2,#0xC0
bge next_loop
b   affiliation_match

check_affiliation_purple:
cmp r2,#0xC0          @if (unit->affiliation < 0xC0){ cotinue; }
blt next_loop
@b   affiliation_match


affiliation_match:
check_commander:

@ldrb r3,[r4,#0x05 * 4] @MemorySlot5 (Commander)
ldr r3,[r4,#0x05 * 4] @MemorySlot5 (Commander)
cmp r3,#0xFF
ble check_commander_by_ID
mov r6, r0
ldr r0,[r4,#0x05 * 4] @MemorySlot5
blh GetUnitByEventParameter
mov r3, r0
mov r0, r6
check_commander_by_ID:
mov r1, #0x38
ldrb r2, [r0, r1]
cmp r2, r3
beq commander_match
b next_loop




commander_match:
found:

	bl Update

b   next_loop

break_loop:
@	blh  0x08019ecc   @RefreshFogAndUnitMaps	@FE8J
@	blh  0x08027144   @SMS_UpdateFromGameData	@FE8J
@	blh  0x08019914   @UpdateGameTilesGraphics	@FE8J
	blh  0x0801a1f4   @RefreshFogAndUnitMaps    @FE8U
	blh  0x080271a0   @SMS_UpdateFromGameData   @FE8U
	blh  0x08019c3c   @UpdateGameTilesGraphics  @FE8U

pop {r4,r5,r6}
pop {r1}
bx r1

@r0 current unit ram
@r1 temp
@r2 temp
@r3 temp
@r4 MemorySlot

Update:
push {r5,lr}
	ldr  r3,[r4,#0x0A * 4]    @MemorySlotA (Type)
	cmp  r3, #0x00            @unit pointer
	beq  set_str
	cmp  r3, #0x04            @class pointer
	beq  set_str
	cmp  r3, #0x0C            @bad status
	beq  set_str
	cmp  r3, #0x01            @unit id
	beq  set_unit_id
	cmp  r3, #0x05            @class id
	beq  set_class_id
	cmp  r3, #0x47
	ble  set_strb

	cmp  r3, #0x50
	beq  set_1A_lower
	cmp  r3, #0x51
	beq  set_1A_upper

	cmp  r3, #0x52
	beq  set_1D_lower
	cmp  r3, #0x53
	beq  set_1D_upper

	cmp  r3, #0x54
	beq  set_30_lower
	cmp  r3, #0x55
	beq  set_30_upper

	cmp  r3, #0x56
	beq  set_31_lower
	cmp  r3, #0x57
	beq  set_31_upper
	b    Update_Exit

set_str:
	ldr  r2,[r4,#0x0B * 4]    @MemorySlotB (Value)
	str  r2, [r0,r3]
	b   Update_Exit
set_strb:
	ldr  r2,[r4,#0x0B * 4]    @MemorySlotB (Value)
	strb r2, [r0,r3]
	b   Update_Exit
set_1A_lower:
	mov  r3, #0x1A
	b    set_lower
set_1A_upper:
	mov  r3, #0x1A
	b    set_lower
set_1D_lower:
	mov  r3, #0x1D
	b    set_lower
set_1D_upper:
	mov  r3, #0x1D
	b    set_lower
set_30_lower:
	mov  r3, #0x30
	b    set_lower
set_30_upper:
	mov  r3, #0x30
	b    set_lower
set_31_lower:
	mov  r3, #0x31
	b    set_lower
set_31_upper:
	mov  r3, #0x31
	b    set_lower
set_unit_id:
	mov  r5, r0        @unit ram\‘¢‘̂̃|ƒCƒ“ƒ^‚ð•Û‘¶
	ldr  r0,[r4,#0x0B * 4]    @MemorySlotB (Value)  @unit id
@	blh  0x08019108    @GetUnitStruct	@FE8J
	blh  0x08019430    @GetUnitStruct	@FE8U
	cmp  r0, #0x00
	beq  Update_Exit

	str  r0, [r5, #0x00]
	mov  r0, r5
	b   Update_Exit

set_class_id:
	mov  r5, r0        @unit ram\‘¢‘̂̃|ƒCƒ“ƒ^‚ð•Û‘¶
	ldr  r0,[r4,#0x0B * 4]    @MemorySlotB (Value)  @class id
@	blh  0x0801911C    @GetROMClassStruct	@FE8J
	blh  0x08019444    @GetROMClassStruct	@FE8U
	cmp  r0, #0x00
	beq  Update_Exit

	str  r0, [r5, #0x04]
	mov  r0, r5
	b   Update_Exit

set_upper:
	ldrb r2, [r0,r3]    @  ([r0,r3] & 0xf) | r2 << 4
	mov  r1,#0xf
	and  r1,r2

	ldr  r2,[r4,#0x0B * 4]    @MemorySlotB (Value)
	lsl  r2,#0x4

	orr  r2, r1
	strb r2, [r0,r3]
	b   Update_Exit

set_lower:
	ldrb r2, [r0,r3]    @  ([r0,r3] & 0xf0) | r2
	mov  r1,#0xf0
	and  r1,r2

	ldr  r2,[r4,#0x0B * 4]    @MemorySlotB (Value)
	orr  r2,r1
	strb r2, [r0,r3]
@b	Update_Exit

Update_Exit:

pop {r5}
pop {r1}
bx r1


1 Like

Made 12 patches. One of them lets you change the allegiance of the demon king summons, and other 11 let you change the targetting of status staves, restore, warp, rescue, and hammerne.

Demon King Summons Allegiance

Change 0x7B2E8 to 0 for playable, 2 for NPC, 4 for Enemy (default value) or 6 for Fourth Allegiance (requires the patch with the same name to work, otherwise it’ll summon nothing)

image

Staff targetting

There are 11 patches so I’ll just link a .7z file with all of them. https://cdn.discordapp.com/attachments/470029781795078175/1105388951461691484/StaffTargettingPatches.7z

image
image
image

EDIT: Made an ASMC, called CUSF. It changes a unit into the 4th allegiance (like CUSA, CUSE, and CUSN). Put the unit you want to change in Slot1 and call CUSF.

CUSF

.align 4
.macro blh to, reg=r3
ldr \reg, =\to
mov lr, \reg
.short 0xf800
.endm
@author = Shuusuke

.thumb
.equ MemorySlot0, 0x30004B8 @FE8U
@.equ MemorySlot0, 0x30004B8 @FE8J
.equ GetUnitByEventParameter, 0x800bc50
.equ HandleAllegianceChange, 0x08018430 @FE8U
@.equ HandleAllegianceChange, 0x08018144 @FE8J

@s1 = unit

push {r4,lr}

ldr r4,=MemorySlot0
ldr r0,[r4,#0x4]
blh GetUnitByEventParameter
mov r1,#0xC0
blh HandleAllegianceChange

blh 0x0801a1f4 @RefreshFogAndUnitMaps {U}
blh 0x080271a0 @SMS_UpdateFromGameData {U}
blh 0x08019c3c @UpdateGameTilesGraphics {U}

POP {r4}
POP {r0}
BX r0

image
image

5 Likes