I'm not really sure I want to flip the order of resistances though, since that begins to enter the territory of fiddling with game balance. Whether it's better one way or the other isn't something I'm in a position to arbitrarily decide, and I'd rather leave that alone. I'm pretty sure the specific elements are chosen based on the types of enemies you'd encounter at the point in the game where you have the spell at a high enough level to get those resists from it.
The more I think about messing up old existing translation patches, the more I realize that it's better that this overhaul patch inspire updated/new projects to account for a fully working version of the game. After a great deal of internal debate, I've decided to leave the Aura/Barrier patch as it is, as well as the Chaos Rush change I'll eventually upload.
I'll also see about fixing that Dispel issue. The thing is, I have no idea how to test whether it works or not. What addresses should I be watching in RAM? Or is it safe to assume that the code will do what it's meant to so long as that STA is inserted? Actually, come to think of it, I could set a break and watch it in the debugger. I keep forgetting that it tells you what address is being referenced as it steps through those instructions.
Oh, this one is a little bit hilarious. The routine loads the target's resistance bits from ($A1),Y into A, clears a bunch of them in A, and then never writes the result back to ($A1),Y. Conveniently, there are 2 useless bytes at $0C:$B807, so shifting $0C:$B809-$0C:$B81C 2 bytes earlier (making sure the BMI still branches to $B83B) and then inserting STA ($A1),Y at $0C:$B81B should do the trick.
"What does your robot do, Sam?"
"It collects data from the surrounding environment, then discards it and drives into walls."
I shouldn't need to worry about the BMI, since it's being shifted up by 2, and then 2 bytes are being added before where it branches to. It should still be $30 $30 in the end. I'm watching RAM now, using WerePanthers (with $50 resist bit, for Body and Death), and already tested that it indeed does nothing. Going to apply the test fix now and see if it gets properly set to $50 (for 4 or less successes), $40 (for 5 or 6 successes), or $00 (for 7+ successes). If that works, I may need to go looking for other monsters with different resistances to fully test this on. That said, even if it always clears all resistances regardless what the messages say, it's still working more than it would have untouched. Doesn't mean I won't be thorough in my fix though.
EDIT: What I assume you meant with your advisory was to ensure that the BPL at $0C:$B81B (which will become $B81D) still points back to $B817, since now there's 2 extra bytes that caused a bug with my fix. I have to change the $10 $FA to a $10 $F8
Well, we've got it removing resists now, though I think there's an issue where it handles checks in the opposite way of Aura and Barrier, and it should be running the highest resist first rather than lowest... I need to test this spell on the PSP version (along with Aura and Barrier) and see how it's handling what resists are considered "higher" or "lower" relative to one another. Cool, PSP version doesn't even tell you what effects you got from the spell success. Simply says "Barrier Lv.16" does the animation, end of story. Frustrating... According to resources as relates to Dawn of Souls version, at least, Dispel and Barrier should handle resists in the same order. So I'd actually need to look at reversing the current order of Dispel's layers. It's treating Matter as the highest and Ice as the lowest. I need to figure out if this is another message issue, or actual behavior... What a headache, these layer-based spells.
EDIT: It appears, at least, that it's just another message reverse issue, as I got "Ice Res.Down" and "Body Res.Down" with level manipulation, but $44 was still set on the Bomb enemy, showing that what had actually been affected was its non-set Matter and Fire resists. Should be an easy fix at least. Since Dispel uses its own routine, in that case rather than changing the pointers, I could simply make the INC instructions for the battle message DEC, and change the first loaded offset from #$52 to #$59, so that it works backwards through the messages. Looking at the gymnastics that would have to be done, however, and the fact that I'm already putting this fix in a position to deprecate existing translations, it would really just be easier for me to change the text pointers.
First post updated with the Japanese-based Dispel fix. I've already made an adjustment to my WIP Chaos Rush translation pointers as well.
So back to Protect, I'm watching the relevant places in RAM and the steps it's taking... I think the reason that only the caster is getting the bonus is because of the fact that $B7CF calls on the target's +$27, but only the caster's +$27 is set. Following all the math it's meant to be doing, it appears that the value stored in the caster's +$27 should be caster's Spirit / 4 / # of targets * number of successes. Also even if you get 0 success at a low level, it still says "Defense up!" rather than "Not effective" which doesn't help with misleading the user into thinking they're getting no bonuses when they should. Anyway, the solution as I see it is to either ensure that we're loading the caster's +$27, or somehow load all targets' +$27 with the same value. Because right now the issue is that the multiplication is happening with a 0 going in, so obviously their bonus is going to be 0.
; handler for Spell ID #$DA: Protect
; indirect control flow target (via $BE9E)
0x0337DA|$0C:$B7CA:20 E9 BD JSR $BDE9
0x0337DD|$0C:$B7CD:A0 27 LDY #$27 ; Battle stat offset for Mystery Battle Stat #$27
0x0337DF|$0C:$B7CF:B1 A1 LDA ($A1),Y ; pointer to target's battle stats
0x0337E1|$0C:$B7D1:85 00 STA $00
0x0337E3|$0C:$B7D3:A9 00 LDA #$00
0x0337E5|$0C:$B7D5:85 01 STA $01
0x0337E7|$0C:$B7D7:A5 48 LDA $48
0x0337E9|$0C:$B7D9:85 02 STA $02
0x0337EB|$0C:$B7DB:A5 49 LDA $49
0x0337ED|$0C:$B7DD:85 03 STA $03
; call to code in a different bank ($0F:$FC98)
0x0337EF|$0C:$B7DF:20 98 FC JSR $FC98 ; 16-bit multiplication (little endian): $00-$01 * $02-$03, product stored in $04-$07; leaves X at #$00, C clear, $00-$01 and Y not changed
0x0337F2|$0C:$B7E2:A0 02 LDY #$02 ; Battle stat offset for Defense
0x0337F5|$0C:$B7E5:B1 A1 LDA ($A1),Y ; pointer to target's battle stats
0x0337F7|$0C:$B7E7:65 04 ADC $04
0x0337F9|$0C:$B7E9:91 A1 STA ($A1),Y ; pointer to target's battle stats
0x0337FB|$0C:$B7EB:90 07 BCC $B7F4
0x0337FD|$0C:$B7ED:A9 FF LDA #$FF
0x0337FF|$0C:$B7EF:91 A1 STA ($A1),Y ; pointer to target's battle stats
0x033801|$0C:$B7F1:4C 73 BE JMP $BE73
I'm going to try changing the LDA ($A1),Y to LDA ($9F),Y instead. That SHOULD be the actor's battle stats rather than the target's. EDIT: ... I CANNOT BELIEVE how simple that fix was. These guys must have been sitting around a table at 3am with no coffee when they were coding this game. Also, it appears that # of successes is calculated for each target rather than before the spell, so a Level 16 Protect from 99 Spirit Guy (99 / 24 / 4 = 6) became 3 successes on Firion (+18), 1 success on Maria (+6), 4 successes on Guy (+24), 6 successes on Char4 (+36). Give this, it seems like Protect is a spell you're much better off using 1 person per turn.
If you're going to make another update to Chaos Rush's translation, it might be worth giving the entire script another pass to check for line wrapping. I've been playing through v1.8 to refresh my memory of this game and noticed the following (in addition to all of Guy's dialogue, which appears to be intentionally bad), which could easily fit into 2 lines instead of 3.
I will definitely be giving it a read-over and seeing about consolidating space, though the changes I've already made to it tried to use the available space without moving so as to avoid changing pointers, so there's some excess spaces here and there. Making it use space as efficiently as possible may become its own separate project down the line.
I'll try to update, test, and then shift the Level Up routine before posting the new mock-up for review with the stat refresh code. I'd really like to get these items out of the way so I can focus 100% of my energy on the other items on our list. As always, thank you for pointing me in the right direction. If you get a chance to sit down and peer review my Level Up Rework mock-up at some point, it would be of great help. That's been kind of looming over me for a while and I'd like to commit that to my stable version if possible.
EDIT: I may have misunderstood precisely where to apply this fix. Doing some experimenting though and will report back my results here. So I turned the original JSR $FA2A into a JSR to my free block for testing, and put those instructions. The stat refresh works, BUT there's a graphical glitch that happens for a second (~60 frames) before it returns to normal. So now it's just a matter of figuring out if it has something to do with that second JSR that mentions waiting for sprite 0 and PPU / VRAM control. I'll try dragging that into the test block and/or working around it.
EDIT2: EGADS, it works! Or rather, changing the JSR $FD46 to my test block (and then having the test block start with JSR $FD46 rather than $FA2A, which already runs beforehand) results in a stat refresh, no graphics bugs... So basically to force a stat refresh, we simply insert between $05:$A711 and $05:$A714:
LDA $9E ; load the current character ID
JSR $FAFB ; swap in bank 0, call the stat refresh code, then swap bank 5 back in
JSR $A992 ; set the NMI vector back to $A9A2
Now assuming this doesn't cause other bugs when there's multiple characters gaining level-ups... I can finally rewrite my Level Up Rework and crunch the code again (with the soon-to-be only 8 free bytes outside the level up routines). Updated the rewrite below. I'm pretty sure I didn't miss anything but I could be wrong. I'd like to commit this to stable soon.https://drive.google.com/open?id=1W-B-13h1aeSUdA4pLN_Nvs400gtRwjcA