A dumb question regarding skills code

i can answer your second question for you though, about why the hit isn’t being added!

you moved the character struct to r0, and then added 0x5A to it. that’s great, you now have an attack change. but you then proceeded to add 0x60 to r0. while 0x60 is the offset for hit, you forgot to reset your r0. instead of r0+0x60, you’re calling the value at r0+0xBA. best way to solve this? add 0x6 instead of 0x60.

1 Like
add     r0,#0x6    @Move to the attacker's hit

like this? right?
thank you very much for helping

1 Like

Hey okay first of all you are NOT a dummy.
Assembly is difficult to learn, and you’ve jumped straight into it feetfirst. You’re doing pretty well if this is your first try!
Secondly, I made a bad recommendation for asking you to try ForUnitInRange. I misunderstood its behavior, and it’s not what you want. Judging by what you posted, this loops through units in a unit’s actual range. I thought that it may loop through a certain number of tiles around a unit. Sorry! Looks like I’m a dummy too…
If I were you, I’d loop manually. It’d be a good exercise and is probably the best way to do it without silly functions.
I would loop through all player units using GetUnit (this is a function that takes a unit index and returns the pointer to that index’s character struct. Player units run from 1 to 62 iirc), checking to see if their coordinates are within a certain range (namely near the coordinates of the unit you want to check), check if they’re female, then if so break and apply the buff.
My C code for this could look a little something like:

for ( int i = 1 ; i < 62 ; i++ )
{
    Unit* unit = GetUnit(i);
    if ( unit )
    {
        // Check if this unit's X and Y coordinates are within the range of the unit we're trying to check.
            // If unit is female...
                break;
    }
}
// Apply bonus.
2 Likes

I think the confusion has also been caused by the fact that Loyalty does not check if a unit has the lord bit set; it checks if a unit is in classes 1, 2, 3, 4, 3B, and 3C (it’s an SoA skill, so I assume it worked there). The edited code they’ve done seems to just change that to classes 2, 4, 5, 6, 7B, and 7C. To make it actually check for the female bit, I think something like this:

mov r3,#0x48
ldr r5,CharData
sub r2,#0x1
mul r3,r2
add r5,r3
ldr r0, [r5] @char
ldr r0, [r0, #0x28] @char abilities
ldr r1, [r5,#4] @class
ldr r1, [r1,#0x28] @class abilities
orr r0, r1
mov r1, #0x40
lsl r1, #8 @0x4000 IsFemale
tst r0, r1
bne Final

would work.

2 Likes

thank you very much for your help, to both of you! :smile:, give me a moment to digest what you wrote because I’m not good with English :sweat_smile:
EDIT (1): @knabepicer I tried your code, and it seems to work from the quick test I did! thank you so much!
SkillsTest.emulator-7 SkillsTest.emulator-8 SkillsTest.emulator-9 SkillsTest.emulator-10
EDIT(2) @Snakey1 your idea would be this here? or could it be done in another way? I’m curious
to thank you for the help you have given me I would like to share the skill code to others it’s the least I can do, how can I do it?
EDIT(3) now i understand, your code, but can i use C to create skill codes?
and the Chek unit X and Y coordinates is AuraSkillCheck? this, right?

CheckSkill:
@now check for the skill
ldr r0, AuraSkillCheck
mov lr, r0
mov r0, r4 @attacker
ldr r1, ForLadyID
mov r1, #0x0
mov r2, #0 @can_trade
mov r3, #2 @range
.short 0xf800
cmp r0, #0
beq Done
1 Like

I wouldn’t use the aura skill checker to check for this. It checks for nearby units to see if one of them has a skill you’re looking for. You want to check for an ability bit for nearby units.

You can compile C code to insertable assembly with here. I just wrote it that way because it was quick. For code this small, though, I’d recommend writing in assembly.

So it is not convenient to use C for this case, because it would have helped me to understand the logic better, because now with the university I started programming in c, before I never did it in any language.
Ah right, Aura Skill Check, aptly named, only checks the possession of an ability, not if a character has an activated flag, in this case the byte number 40.
now my new dumb question is: how to write your idea with the assembly language, I know that the other user was very kind and solved the problem for me, but I would like to understand how to do it in another way too, not for anything, but just for the fun of learning new things

I hope I have explained myself correctly, and thanks again for the help

if this were true it means that I have no hope haahhaha
but fortunately the condition is false

1 Like

Yeah loops can be especially tricky. I recommend taking a shot at it, and the worst case scenario is we show you how to improve your code. (I promise we try to be friendly.)
It looks like you’ve already got the bit checking logic for whether a unit is female, so that tricky part should be good to go.

you have been more than friendly, you have endured my mad questions and problems :sweat_smile:
even if I don’t know in the least where to start to create a loop I try to invent something (even if crazy)
and thanks again for the help

> mov r4, #0x01 @int i=1
> Loop:
> cmp r4, #0x62 @i<62
> bne Done @if is false, go to Done
> add r4, #0x01 @i++
> ldr r4, GetUnit 
>  
> @now check for unit range? 
>  
> CheckGender:
> mov r3,#0x48
> ldr r5,CharData
> sub r2,#0x1
> mul r3,r2
> add r5,r3
> ldr r0, [r5] @char
> ldr r0, [r0, #0x28] @char abilities
> ldr r1, [r5,#4] @class
> ldr r1, [r1,#0x28] @class abilities
> orr r0, r1
> mov r1, #0x40
> lsl r1, #8 @0x4000 IsFemale
> tst r0, r1
> bne Final
> b Loop

I tried to create the “for” … but I honestly don’t know :sweat_smile:
I don’t know how to take the coordinates of a unit and then compare them

1 Like

Good so far! But your loop first off isn’t quite right. I would start with…

mov r4, #0x00
LoopStart:
cmp r4, #0x62
add r4, r4, #0x01
beq Done
mov r0, r4
blh GetUnit, r1
@ Our unit struct is in r0.
@ To reiterate, branch to LoopStart.

Next, we know that the first word of the character struct is a pointer to character data, and the second is a pointer to class data. So all we need to do to get the combined ability bitfield is…

@ Let the unit pointer be in r0.
ldr r1, [ r0 ]
ldr r1, [ r1, #0x28 ]
ldr r2, [ r0, #0x04 ]
ldr r2, [ r2, #0x28 ]
orr r1, r1, r2 @ Combined ability bitfields.
@ Now you can check for the IsFemale bit.

I think both ability words are at 0x28, right?
Now for the coordinates, I’d like you to try to code this first, but your unit should be in range of the unit if the difference in x coordinates plus the difference in y coordinates is less than or equal to your range.

1 Like

I didn’t think you could put it after a cmd something other than a bne or beq (in this case an add), I must have misunderstood the glossary of the guide, better this way, because now it makes more sense to me :grin: :laughing:
silly question, is it really necessary the add r4, r4, #0x01?
in the sense I thought it should only increase by 1 byte… I didn’t quite understand this part
obviously I got confused between bne and beq
now we use mov r0, r4 to save the value of r4 in r0? right?
Oh to call a macro, use blh, I must not have seen it, from the glossary

ldr r1, [ r1, #0x28 ]
ldr r2, [ r0, #0x04 ]
ldr r2, [ r2, #0x28 ]

with these we are loading, something for sure … we load at once all the hypothetical flags / bytes that Mr X can possess

orr r1, r1, r2 @ Combined ability bitfields.

ah ok, I think yes
so later I can do the … “division” for the ISfemale byte…i think, and i can’t find a way to say it in english even with google translate :sweat_smile:
ok, tomorrow I try to invent some other madness for the radius of a unit, because if I start now tomorrow I can’t wake up to go to class :sweat_smile: :laughing:
Thank you so much once again @Snakey1 to follow me in my crazy adventure in the depths of my mind

Ah sorry made a small mistake. It should really be

add r4, r4, #0x01
cmp r4, #0x62
beq Done

what add r4, r4, #0x01 does is it takes the value in r4, adds it to 0x01, and puts the result in r4. It’s equivalent to add r4, #0x01.

1 Like

I finally figured out a way to find the coordinates, it came to me while I was doing physics, but let’s forget it
this is my creation:

> @now check for unit range? 
> @0x10	Byte	X coordinate (0xFF if undeployed)
> @0x11	Byte	Y coordinate
> Unit range:
> add r0,#0x10 @move to x cordinate?
> add r1,#0x10 @same but for defender?
> ldr r0, [r0, #0x10] @take x cordinate of the attacker
> ldr r1, [r1, #0x10] @take x cordinate of the defender
> sub r2, r1, r0  @difference of the two x coordinates and store the result in r2
> add r0,#0x11 @move to y?
> add r1,#0x11 @dsame but for defender?
> ldr r0, [r0, #0x11] @take y cordinate of the attacker
> ldr r1, [r1, #0x11] @take y cordinate of the defender
> sub r3, r1, r0 @difference of the two y coordinates and store the result in r3
> add r2, r2, r3 @sum of the two difference and store the result in r2, why? I dont know
> cmp r2 #0x03 @I want the radius to be 2, so it must be less than 3, I think
> bne Loop  @I am sure I was wrong here

Now, my perplexity is that this calculation mathematically and or physically, in reality would be wrong, because we consider all real numbers, if I’m not mistaken
while, I create, the game code only recognizes whole numbers, there will never be a distance of 2.5 boxes a unit can only be in an integer coordinate penso, ma non ho mai visto in nessun fire emblem un unita alle cordinate (esempio X:6,4 Y:1,8)
and then, what is even more stupid, I don’t know how to make the power or the root, to be honest I thought for the power to multiply the register by itself, in the end that isbut with the root, I really don’t know, but the problem is that if I succeed, the values ​​might not be integers So would I break the game

what add r4, r4, #0x01 does is it takes the value in r4, adds it to 0x01, and puts the result in r4. It’s equivalent to add r4, #0x01 .
[/quote]

> .equ AuraSkillCheck, SkillTester+4
> .equ ForLadyID, AuraSkillCheck+4
> .thumb
> push {r4-r7,lr}
> @goes in the battle loop.
> @r0 is the attacker
> @r1 is the defender
> mov r4, r0
> mov r5, r1
> 
> @has ForLady
> ldr r1, SkillTester
> mov lr, r1
> mov r1, r5 @Attacker data
> ldr r0, ForLadyID
> .short 0xf800
> cmp r1, #0 
> beq Done
> 
> CheckSkill:
> @now check for the skill
> ldr r0, AuraSkillCheck
> mov lr, r0
> mov r0, r4 @attacker
> ldr r1, ForLadyID
> mov r1, #0x0
> mov r2, #0 @can_trade
> mov r3, #2 @range
> .short 0xf800
> cmp r0, #0
> beq Done
> 
> mov r4, #0x01 @int i=1
> Loop:
> add r4, r4, #0x01
> cmp r4, #0x62
> beq Done
> mov r0, r4
> blh GetUnit, r1
> @ Our unit struct is in r0.
> @ To reiterate, branch to LoopStart.
>  
> @now check for unit range? 
> @0x10	Byte	X coordinate (0xFF if undeployed)
> @0x11	Byte	Y coordinate
> Unit range:
> add r0,#0x10 @move to x cordinate?
> add r1,#0x10 @same but for defender?
> ldr r0, [r0, #0x10] @take x cordinate of the attacker
> ldr r1, [r1, #0x10] @take x cordinate of the defender
> sub r2, r1, r0  @difference of the two x coordinates and store the result in r2
> add r0,#0x11 @move to y?
> add r1,#0x11 @dsame but for defender?
> ldr r0, [r0, #0x11] @take y cordinate of the attacker
> ldr r1, [r1, #0x11] @take y cordinate of the defender
> sub r3, r1, r0 @difference of the two y coordinates and store the result in r3
> add r2, r2, r3 @sum of the two difference and store the result in r2, why? I dont know
> cmp r2 #0x03 @I want the radius to be 2, so it must be less than 3, I think
> bne Loop  @I am sure I was wrong here
> 
> CheckGender:
> mov r3,#0x48
> ldr r5,CharData
> sub r2,#0x1
> mul r3,r2
> add r5,r3
> ldr r1, [r0] @char
> ldr r1, [r1, #0x28] @char abilities
> ldr r2, [r0,#4] @class
> ldr r2, [r2,#0x28] @class abilities
> orr r1, r1, r2 @combined ability bitfields
> mov r1, #0x40
> lsl r1, #8 @0x4000 IsFemale
> tst r0, r1
> bne Final
> b Loop
> 
> CheckGender:
> mov r3,#0x48
> ldr r5,CharData
> sub r2,#0x1
> mul r3,r2
> add r5,r3
> ldr r0, [r5] @char
> ldr r0, [r0, #0x28] @char abilities
> ldr r1, [r5,#4] @class
> ldr r1, [r1,#0x28] @class abilities
> orr r0, r1
> mov r1, #0x40
> lsl r1, #8 @0x4000 IsFemale
> tst r0, r1
> bne Final
> 
> Final:
> mov r0, r4
> add     r0,#0x5A    @Move to the attacker's damage.
> ldrh    r3,[r0]     @Load the attacker's damage into r3.
> add     r3,#2    @add 2 damage.
> strh    r3,[r0]     @Store dmg.
> 
> add     r0,#0x6    @Move to the attacker's hit.
> ldrh    r3,[r0]     @Load the attacker's hit into r3.
> add     r3,#10    @add 10 hit.
> strh    r3,[r0]     @Store.
> 
> Done:
> pop {r4-r7}
> pop {r0}
> bx r0
> .align
> .ltorg
> CharData:
> .long 0x202be4c
> MovementPoin:
> .long 0x880bb96
> SkillTester:
> @POIN SkillTester
> @ POIN AuraSkillCheck
> @ WORD ForLadyID

for now, this is the complete code

I’m dumb, forget the question and the others from my old post, I wrote them when my brain was completely asleep

When we talk about range, we don’t worry about roots and powers and bla bla. That’s too complicated for the player, and the engine doesn’t really handle decimals as well. Range between two units is just counting the tile difference.

add r0,#0x10 @move to x cordinate?
add r1,#0x10 @same but for defender?

One of the biggest things we have to worry about in ASM is knowing what’s currently in our registers. Generally really, this code doesn’t mean much in a vacuum because it depends on what’s in r0 and r1. I’m thinking you’re going to want this code within your unit loop, and that’s not what those registers hold.
Also for defender, we need to think about what two units we want the distance between. Know that the pre-battle calc loop is looped twice for each battle calculation. Once where the attacker is passed in as r0, and the defender is passed in as r1; and again when the defender is r0, and the attacker is r1. Comments in these skill sources are pretty deceptive in this way, but this is how it works.

I’m going to move to look at your other code block and show you how I would integrate each part of your code.

> mov r1, r5 @Attacker data
> ldr r0, ForLadyID
> .short 0xf800
> cmp r1, #0 
> beq Done

You’re comparing r1 to 0 here. Remember that convention dictates that function return values are returned in r0.

> CheckSkill:
> @now check for the skill
> ldr r0, AuraSkillCheck
> mov lr, r0
> mov r0, r4 @attacker
> ldr r1, ForLadyID
> mov r1, #0x0
> mov r2, #0 @can_trade
> mov r3, #2 @range
> .short 0xf800
> cmp r0, #0
> beq Done

You shouldn’t still have the Aura skill checker in here. Remember that it’s only good for checking whether nearby units have skills.

> mov r4, #0x01 @int i=1
> Loop:
> add r4, r4, #0x01

When we loop, it’s good to think about a few important cases in the loop. Think about the first case for example. When we first run this code, r4 is set to 1 and then immediately incremented to 2. This means that the 1 case is skipped! We have a problem. To remedy this, I would just do

> mov r4, #0x00
> Loop:
> add r4, r4, #0x01

lol I’m going to assume that the double gender check is a mistake.
Here’s how I would take each piece and implement them together.

.thumb
.equ AuraSkillCheck, SkillTester+4
.equ ForLadyID, AuraSkillCheck+4
push { r4, r5, lr } @ I only push r4 and r5 because it's unnecessary to push r6 and r7. Pushing/popping is relatively time-consuming!
mov r4, r0 @ We only need to store one battle struct pointer.

@ Does this unit have the skill?
ldr r0, ForLadyID
mov r1, r4
blh SkillTester, r2
cmp r0, #0x00
beq Done

@ Now we need to start looping through player units.
mov r5, #0x00
StartLoop:
add r5, r5, #0x01
cmp r5, #0x63
beq Done
    mov r0, r5
    blh GetUnit, r1 @ Unit we want to test is in r0.
    cmp r0, #0x00
    beq StartLoop
    ldr r1, [ r0 ]
    cmp r0, #0x00
    beq StartLoop @ Does this unit exist?
    ldr r1, [ r1, #0x28 ] @ Character abilities.
    ldr r2, [ r0, #0x04 ]
    ldr r2, [ r2, #0x28 ] @ Class abilities.
    orr r1, r1, r2
    mov r2, #0x40
    lsl r2, r2, #0x08 @ IsFemale.
    tst r1, r2
    beq LoopStart @ Reiterate if this unit is male.
    
    @ We should probably check if this unit is dead too.
    ldr r1, [ r0, #0x0C ]
    lsr r1, r1, #2
    lsl r1, r1, #31
    cmp r1, #0x00
    bne StartLoop @ Reiterate if this unit is dead.

    @ Now let's check the ranges.
    ldrb r1, [ r4, #0x10 ] @ Main unit X.
    ldrb r2, [ r0, #0x10 ] @ This unit X.
    sub r1, r1, r2
    cmp r1, #0x00
    bge NotNegativeX @ Aaaaa we have to account for the differences being negative.
        mov r2, #0x01
        neg r2, r2
        mul r1, r2 @ Multiply by -1. There may be a more efficient way to do this but eh.
    NotNegativeX:
    ldrb r2, [ r4, #0x11 ] @ Main unit Y.
    ldrb r3, [ r4, #0x11 ] @ This unit Y.
    sub r2, r2, r3
    cmp r2, #0x00
    bge NotNegativeY
        mov r3, #0x01
        neg r3, r3
        mul r2, r3
    NotNegativeY:
    @ r1 has |XDifference|, and r2 has |YDifference|.
    add r1, r1, r2 @ Total distance between these units.
    cmp r1, #0x03 @ I think 3 is your range?
    bgt StartLoop @ This unit is outside the range.

@ We've passed all of the conditions.  Let's apply the bonus!
mov r1, #0x5A
ldrh r2, [ r4, r1 ] @ Attacker's damage.
add r2, r2, #2 @ Add 2 damage.
strh r2, [ r4, r1 ]

mov r1, #0x60
ldrh r2, [ r4, r1 ] @ Attacker's hit.
add r2, r2, #10 @ Add 10 hit.
strh r2, [ r4, r1 ]

Done:
pop { r4, r5 }
pop { r0 }
bx r0

.align
.ltorg
CharData:
.long 0x202be4c
MovementPoin:
.long 0x880bb96
SkillTester:
@POIN SkillTester
@ POIN AuraSkillCheck
@ WORD ForLadyID

Untested, and I probably made mistakes, but this is how I would do this.

A problem with this methodology occurred to me while writing this, though. This only works for player units. When we write skills, we want them to work for all allegiances. This means that we need to find a way to loop through units of a given allegiance matching the passed in unit’s. This is only if you want the bonus to be applied if a female unit of the same allegiance is within the range. All units could just be looped through if you want this to not be allegiance-specific.

1 Like

I don’t know what words to describe this message, apart from telling you that you are a genius I don’t know what to say, and it would really surprise me if it didn’t work,

I had suspected it but I was not sure

Ah, I didn’t know

therefore, after any cmp check the result is automatically put in r0, so it’s best to avoid using too much r0, right?

I forgot to delete it :laughing:
(and yes the double check gender is an error probably while copying and pasting from another file)
and it is better to start a loop with 0, i don’t know why i put one
the things that completely upset me, were checking if a coordinate could be negative, I thought the code would automatically transform any byte into positive
and checking if a unitcould be dead … I didn’t think it could cause any problems but now that I think about it …I think this post has made how I am bad

I think so :laughing:
I believe that to solve the problem, when we take the united id there will surely be a byte in the structure that indicates the faction to which it belongs
I think… :face_with_monocle:
(something tells me I’m wrong)

Sain would appreciate
apart from my bad jokes, this would not create problems at the level … I don’t know … of the speed of reading? I speak completely ignorant in the matter
anyway now I try to assemble it and see if it works
EDIT:
cattura1
it seems to report an error about perhaps some unrecognized commands
do I have to have something wrong in the configuration? the only thing i did, was copy paste the code to a new file
then asks for an .elf
I always think because he didn’t recognize something
EDIT(2): regarding unit alliances I found that 202E4D8 Unit map (allegiance byte)

The result of a cmp is evaluated using 4 status flags, which different conditional branches then reference to see if their required condition is true or false. What’s being referred to here is the result of function calls. When you call a function, you should assume that the values in your scratch registers (r0-r3) will not be the same once it returns. These are also the registers functions take arguments in and return values to, with the first argument or return value in r0, then r1, etc. At least in vanilla functions rarely return more than 1 value, so said value is going to be returned in r0.

I know Snakey said not to use AuraSkillChecker, but it may actually be useful here. If you call AuraSkillChecker with a skill ID of 0 it will just count every unit within the given range matching the given restriction. It then returns both the unit count in r0 and a pointer to a list of allegiance bytes for each unit it found in r1. If you want a list of all units of the same allegiance within a certain range, give AuraSkillChecker a skill ID of 0, the desired range, and the restriction 0 for same allegiance only. Then, iterate through the list it returns a pointer to in r1 to check each unit for the bitflag you’re looking for. This is more or less how Armor March works when checking for nearby armor units, if you want an example of this idea in effect.

1 Like

ah ok, depending on the number of values ​​it must return, it will go to r0, r1, r2 up to r3

CheckSkill:
@now check for the skill
ldr r0, AuraSkillCheck
mov lr, r0
mov r0, r4 @attacker
ldr r1, ForLadyID
mov r1, #0x0
mov r2, #0 @can_trade
mov r3, #2 @range
.short 0xf800
cmp r0, #0
beq Done

like that? because it would be as I originally wrote the code (which with the new IS female control code, works perfectly)
I think Snakey is trying to make me independent of this code, I think, to look for new ways to solve the problem, this is my idea (which is what I want, in the sense of learning new things)
I don’t know if I made myself clear

Hey please you’re not bad. Everyone is bad at assembly when they start out. There are so many conventions and whatnot that make it seem overwhelming, but you’re doing pretty well!

Ah sorry I should have included this macro in the function writeup:

.macro blh to, reg
    ldr \reg, =\to
    mov lr, \reg
    .short 0xF800
.endm

This can go anywhere near the top of your file.

You can use what I wrote or the aura skill checker. Use whatever you think is best. It’s your code!

Just remember that you need to decide on the intended behavior of your code. You can either have the effect apply to within a single allegiance (requiring you to selectively loop through a single allegiance pool) or have the effect be allegiance-independent (just requiring changing the limits of the loop to cover all units and not just player units).

1 Like

Right now I don’t know what I’m going to use, but, a big but, I am grateful to you for helping me solve the problem in an alternative way, because I believe that whatever I learn will always be useful in the endeven though i completed the goal of creating a new skill i didn’t complete the main quest, learn as much as possible about assembly.
I don’t know if I made myself clear, I hope this is just a start, I would like to try to do different things, right now I’m starting to recreate the mount unit system like Tellius game

Ah, great, now i see if it works
now when I assemble the code, it does not report any errors, but when I am in play, and I try to open the least of the units, to see skills, statistics, name etc …but the game crashes with a simple black screen for safety I also did a test on a clean buildfile but it always seems to
I would not like it if it was for how I entered the new library

.thumb
.equ AuraSkillCheck, SkillTester+4
.equ ForLadyID, AuraSkillCheck+4
push { r4, r5, lr }
mov r4, r0 @ We only need to store one battle struct pointer.
.macro blh to, reg
    ldr \reg, =\to
    mov lr, \reg
    .short 0xF800
.endm

I also tried to put it on top, line after the

> .thumb

but same thing

I’d put the macro right below the .thumb, but it shouldn’t matter.
Make sure you’re writing to free space! Can we see how you’re installing the skill in your EA script?