News:

11 March 2016 - Forum Rules

Main Menu

Changing how Multi-targeting works in FF3 (NES)

Started by Maeson, September 02, 2022, 02:47:54 AM

Previous topic - Next topic

Maeson

Hello.

I've been working on a new version of my FF3 Hack, and I've been trying to modify the way Spells that can be multi-targeted work.

The original function is to divide the damage you would cause normally to one enemy between the number of targets. So if an Spell would do 1.000 points of damage against one, it would do a paltry 200 points targeting five.

The change I intend to make is to simply divide damage by 2 if the player targets 2 or more enemies.

I know very, very little about 6502. I've been learning some things thanks to Everything8215's disassembly of the game and managed to do other changes I wanted but after trying to do this one by myself for a couple days, I asked Everything8215 for a bit of help.

This is the related code:

31/B009: A2 08     LDX #$08
31/B00B: A0 00     LDY #$00
31/B00D: AD 99 7E  LDA $7E99          ; targets
31/B010: 0A        ASL
31/B011: 90 01     BCC $B014
31/B013: C8        INY
31/B014: CA        DEX
31/B015: D0 F9     BNE $B010
31/B017: 84 2A     STY $2A            ; number of targets (for dividing damage)
31/B019: A0 30     LDY #$30

This is the proposed changes:
31/B009: A0 01     LDY #$01           ; set the divider to one
31/B00B: AD 99 7E  LDA $7E99          ; targets mask
31/B00E: 0A        ASL                ; find and shift the first target
31/B00F: 90 FD     BCC $B00E
31/B011: F0 04     BEQ $B017          ; branch if there are no more targets
31/B013: C8        INY                ; set divider to two
31/B014: EA        NOP
31/B015: EA        NOP
31/B016: EA        NOP                ; Fill unused bytes
31/B017: 84 2A     STY $2A            ; number of targets (for dividing damage)
31/B019: A0 30     LDY #$30

Here's the asm file in case it helps.

At first it seems to work, but now if a character targets a single enemy with magic and that enemy gets defeated before that character attacks, the game crashes, instead of making the action ineffective and continue the battle. Also, healing magic ignores these instructions and doesn't divide if you're restoring HP. Dealing damage to undead works as intended though.

I would like some help on this, as getting the mechanic changed or not impacts the rest of how I make the hack. Maybe I'm changing too much, and there's a simpler way.

Thanks, and have a good day.
I'm off for some time. If for some weird, strange, and important reason, you need to talk to me, just send me a PM and probably I'll read it whenever I come back.

Cyneprepou4uk

You can leave original calculations unmodified and work with the result instead. Check Y before writing it to 2A. If it's >= 03, overwrite result with 02, otherwise write result.

CPY #$03
BCC skip
LDY #$02
skip:
STY $2A

Maeson

Thank you for your answer! Bear with me because to me it's still like trying to reading old English in Wingdings font for the most part.

So, each individual code in hex should look like this:

CPY #$03  C0 03
BCC skip  90 02 > 02 If it only needs to skip LDY #$02
LDY #$02  A0 02
STY #$2A  84 2A

Now the part that makes me confused is what exactly do I replace with it.
Seeing how STY #$2A remains unchanged, I'm still using the one in the original code then?

I'm off for some time. If for some weird, strange, and important reason, you need to talk to me, just send me a PM and probably I'll read it whenever I come back.

Cyneprepou4uk

Bytes are correct. Although
STY #$2A  84 2Ashould be
STY $2A  84 2Abecause you write to an address.

You need to replace original STY 2A with these new instructions.

Maeson

Okay, now I understood you.

So what I did was...

31/B009: A2 08     LDX #$08
31/B00B: A0 00     LDY #$00
31/B00D: AD 99 7E  LDA $7E99          ; targets
31/B010: 0A        ASL
31/B011: 90 01     BCC $B014
31/B013: C8        INY
31/B014: CA        DEX
31/B015: D0 F9     BNE $B010
31/B017: 4C C7 B7  JMP $B7C7          ; jump to unused code
31/B01A: EA        NOP                ; filler
31/B01B: B1 6E     LDA ($6E),Y        ; code works as usual after this point

Because I did not have space for fit any of it, I had to look around for some free space, which there wasn't. Fortunately there's some unused code in the same area dealing with Status Effects for... something that apparently doesn't do anything? Eh, works for me.

I took "31/B015: D0 F9 BNE $B010" and "31/B017: 84 2A STY $2A" made a JMP to B7C7 instruction and went to the "free" space. I added the code you shared with the BNE and STY codes at the end, and another JMP back to the original magic code.

31/B7C7: C0 03
31/B7C9: 90 02
31/B7CB: A0 02
31/B7CD: 84 2A                       ; these are the new instructions you provided.
31/B7DF: A0 30                       ; this was part of the original code that didn't fit.
31/B7D1: 4C 1B B0  JMP $B01B         ; jump back to the magic effect code

It might be a bit too soon to celebrate, but it seems like... Everything works?

At first I was using JST instead of JMP and I was getting crazy stuff (like Spells that did blow up my enemies and my team, which is if nothing else, amusing because I thought it wasn't possible) but I've tried, and offensive magic does seem to do the intended damage, it gets divided by 2 if multi-targeted, the game does not hang up if someone casts a single-target spell on an enemy that dies before the character does the action, and healing seemingly works fine too, it divides its effect by two if multi-targeting.



I honestly didn't have much faith on being able to make it work, but it seems like it does! I still need to make more tests, just in case.

Thank you so much, Cyneprepou4uk!


I'm off for some time. If for some weird, strange, and important reason, you need to talk to me, just send me a PM and probably I'll read it whenever I come back.

Cyneprepou4uk

Quote from: Maeson on September 02, 2022, 08:57:01 AM31/B015: D0 F9     BNE $B010
31/B017: 4C C7 B7  JMP $B7C7          ; jump to unused code
31/B01A: EA        NOP                ; filler

Quote from: Maeson on September 02, 2022, 08:57:01 AMI took "31/B015: D0 F9 BNE $B010" and "31/B017: 84 2A STY $2A" made a JMP to B7C7 instruction and went to the "free" space.

These two quotes conflict with each other. But I guess you went with the first one in the end, which is a correct move.

Good thing you've figure out how to insert this code, I thought I would need to explain it to you.

By the way, when using JSR (not JST), you need RTS at the end of your routine. But 2 JMPs work 6 cycles faster than this combo (but use 2 more bytes).

Maeson

Oops, you're correct, I meant I took 84 2A STY $2A" and "A0 30 LDY $30". A dumb mistake on my part, true!

Well as I said, it's pretty tough to me still. It's not the first time I do insert a code, but I never had to do something also involving damage calculations, I did not know where to make the cut for the JMP, thankfully I found the better spot.

Great to know that 2 JMPs work faster. Because the code I partially replaced is not used I didn't have much to lose with two less bytes.

Again, thank you. I hope I don't bother you anymore and all testing goes well. Have a nice day.
I'm off for some time. If for some weird, strange, and important reason, you need to talk to me, just send me a PM and probably I'll read it whenever I come back.

KingMike

For learning purposes, I see a flaw with your original code idea.
The original code suggests to me that $7E99 is a bitmask of which of the 8 enemy slots have enemies in them.
(the code would iterate through all 8 bits of that byte, to check how many "1" bits were found)
So your code would have set the target count to 2 after the FIRST enemy was found. Probably related to the problems you were experiencing.
"My watch says 30 chickens" Google, 2018

Maeson

Yes, $7E99 is used a lot for enemy targeting code in many places. I suppose that if it's as you say, the way it counted targets would totally screw things up so much as it did when there was a change on the number of enemies throughout the course of a battle. 

Thank you for your input, KingMike! Also, thanks for all your work, now that I have the chance.

The code proposed by Cyneprepo4uk has been working perfectly, making multi-targeting this way really has helped polishing my hack; it won't take much longer to have this new version finished, or at least I hope.
I'm off for some time. If for some weird, strange, and important reason, you need to talk to me, just send me a PM and probably I'll read it whenever I come back.