Breath of Fire(SNES) How to figure out the attack formula?

Started by Venks, September 07, 2019, 04:33:24 PM

Previous topic - Next topic

Venks

To start off, I don't really understand this kind of stuff what so ever. I just like learning about how old games were designed.
I've recently been checking out damage formulas in various JRPGs.

Like in Pokemon it's Damage = ( ( ( (2xLevel)/5+2) x Power x Attack/Defense )/50 +2 )
And in Final Fantasy 1 Damage = (Strength/2 + Weapon) + (Strength/2 + Weapon)*(Random between 0 and 1) - Defense

No matter where I look I can't seem to find the damage formula for Breath of Fire so I tried to look at the game's code myself. Again I don't really get this stuff, but using Bizhawk I was able to find the damage value the player or enemy deals in combat at WRAM address 000F14. I also found what I think is the first Enemy in combat's defense value at address 0015DF.

Using the hex editor I can edit those values. I've found editing the damage value will give the exact value I put in. And editing the 1st enemy's defense value seems to correctly alter their defense and thus change the damage that would normally be dealt. But my goodness there's a lot at play with the defense value and I don't really know what.

Is there someway to figure out how certain addresses connect or a better way altogether to try and figure out the information I seek? Any advice would be appreciated.

Cyneprepou4uk

The easiest way might me to search for a disassembly of your game and read comments in it.

But since you have started to dig in RAM, which is cool, I don't see a problem for finding code if you know address with damage value. Set a write breakpoint to it and look into debugger when it triggers.

Commonly you don't search a damage value in RAM, you wanna search for hp first, which will be easy. Like taking damage and looking for something that is decreasing, or searching for hp value in RAM. Make a savestate 1-2 frames before hp is decreasing, like when enemy is about to kick your ass on the next frame. Set a write breakpoint to hp, pause emulator, launch trace logger, load save, unpause emulator and wait for breakpoint hit. Stop logger and check the log for previous executed instructions, which result in a value that was substracted from hp. That is basically your formula, now you need to guess what are those addresses that were used in code, maybe one of them it is your defence or something.

FAST6191

If you are already poking around in RAM just off your own fiddling, not an amazingly technical feat but definitely shows more initiative than we commonly see around here, then what Cyneprepou4uk said (personally I tend to use stepping rather than logging but that is stylistic at this point and there are advantages and disadvantages to each) but I should also note for older systems you will possibly have a fair bit of bounds correction going on. Sometimes the devs will limit the numbers such that normal play never gets there but not always.

Bounds correction then. If your registers are 16 bits you can only reliably represent 2^16 values, 2^8 for 8 bit and so on, less if you swipe a bit from that to note some kind of status, hence all the max value is 255, 511, 1023.... type setups you will have seen in games over the years.
In normal conversation it does not matter if we are talking numbers we can count on one hand or numbers greater than the universe has atoms ( https://www.youtube.com/watch?v=FaEkdQiweVE ) as the maths still holds. Computers however will add in a whole bunch more things that limit numbers to a range, or round things up as dealing with fractional values is a pain, to say nothing of older systems sometimes lacking fundamental mathematical operations*. Also just because it appears there does not mean the devs will use it even if it makes "logical" sense to do so within the game -- several of those pokemon analysis pages will probably state what is not used, and final fantasy has some absolute howlers in terms of things it omits from calculations.
This will increase the apparent complexity of such a calculation when you are looking at the code compared to what the maths will eventually describe. At times and when you get better at it you can sort of filter it out in your head** but there are other times when devs will write it such that if the power levels are that different that it will automatically round things up or down. This is in addition to the older systems not having as many registers it is free to use so will have to shuffle things into and out of the CPU for the purposes of operations where some later ones can afford to leave things in longer; for the DS I have examples of things staying in the registers/stack for long enough that conventional memory cheats don't work, something which is basically never going to happen on a NES and only might happen on a SNES if a dev went out of their way (and almost crippled their options for coding) to do it.

*the NES does not have subtract for instance, a proper divide was a kind of BIOS only extra even as late as the GBA (the divide or multiply by 2 thing is just a logical shift in binary -- much like multiplying by 10 shifts the decimal place/"adds a 0 at the end" then multiplying or dividing by two is a basic shift operation, though you will get some rounding issues) and for the sake of polite conversation we will skip the floating point precision discussion entirely.
Such things also influence what the devs will do for a given system either as a quick and dirty way of doing things or something more fundamental. You can probably skip contemplating that at first though -- eventually it might be useful but for starters I would go with just knowing what the opcodes mean and their basic operation and notable limitations.

**also where logging might be easier if you can see it all happening at once and not have the translating a sentence one word at a time where a later word could completely change the meaning problem.

Venks

It would be nice if I understood more of this code. I feel so close to the answers I'm looking for, but I just don't understand Assembly what so ever.

When using cheat editors I've been able to find the address for the first monster in a battle's defense. Using different cheat editors I've found the addresses 0015df and 7e15df. The two addresses end the same, but start differently but seem to net me the same results. I don't really understand why they both work.

But anyways if I use the defense address in my cheat editor I can see a monster's actual defense stat. But when I use the defense address in my debugger I can't seem to find the values I'm looking for. Instead I've found that when I set 0015df or 7e15df as a breakpoint the game will pause after choosing an attack target, as the player character slashes their sword into the enemy. My debugger has a "X Field" which displays certain values. During this moment, which is the same as the image posted down below, the X field expresses a value of 6. This isn't exactly the monster's defense as Slime enemies have a defense stat of 12. But without a doubt this value is used in damage calculations.

In my tests I've noticed the player character dealing different damage depending on the value expressed in this X field.
0 will equate to 15 damage.
2 to 14.
4 to 12.
6 to 11.
8 to 10.

I've only seen the X field spit out those 5 values during my tests, but there could possibly be more. For a moment it might seem like a 0 value expressed in the X Field means the player character deals their full damage, but that isn't the case. The player character's attack stat with default equipment is indeed 15, but I tried fighting other enemies as well. The Gloom enemy has a 22 defense stat. When the player character attacks this enemy and the X field expresses a 0 value the damage comes out to 8. So there's a difference of 10 defense between the two enemies, but a damage difference of 7. The Gloom also doesn't have the same differences in reduced damage for a higher value expressed in the X field. I'm pretty certain this value expressed in the X field is either a random number meant to add some variance in damage dealt to enemies. That or it is the end result of a defense stat that has gone through some calculation with a random number. Regardless it is clear that this number is important.

I've also noticed that when the player character gets a "Slam", the critical hit in this game, damage seems to double. I assume that critical hits double the damage dealt at or near the end of damage calculation as it seems to me that the double damage takes into account the x field variable.

Everything I've deduced so far has been simply from playing the game, looking at the listed stats, seeing the number that pops up in the x field when the breakpoint triggers for the 0015df or 7e15df addresses, and the damage number displayed in game. I haven't really read any of the assembly code because I don't understand it. As far as I can tell all these lines of code are loading memory or something for literally hundreds of steps. I was hoping I could go from line to line and eventually find a line of code that showed some sort of calculation. Maybe adding or subtracting something, but I can't find anything like that or know how to look for it.

Any advice or insight would be greatly appreciated!

https://i.imgur.com/hU4ZwrW.png


Cyneprepou4uk

#4
You definitely need to know what these instructions are in order to understand the code. Use this reference for example. Explaining to you simple instructions every time you post them here will be tedious.

Lets analyze your debugger screenshot to get you started. Your read breakpoint triggered at LDA $005F,Y instruction, because code was trying to read from $15DF. LDA means load something to register A. Register is a CPU location that holds some value. LDA,Y means loading from address + value from register Y, which is = #1580 at the moment. So $005F + #1580 = $15DF, this address is displayed in debugger to the right of LDA,Y [8115DF]. LDA wasn't executed yet, it is waiting to be executed, that's why you don't see defense value in A yet. If you press "Step" button in debugger, defense value will be loaded to A from $15DF. Press the button one more time, and A will be written to $0006 by STA instruction (set A to address). Then comes JSR $DE78 (jump to subroutine), I guess your defense, which copy is stored in $0006 now, will participate in some calculation. Check that subroutine out, perhaps you will also see a usage of value from X register there.

QuoteI've found the addresses 0015df and 7e15df

Maybe SNES has a memory mirroring, that's why you have found 2 same addresses. I'm not really into SNES technical stuff, but I know NES assembly, which is basically the same shit