Users browsing this thread: 1 Guest(s)

Items with stat bonuses +28? DO WE DARE???

02-13-2016, 02:02 AM
(This post was last modified: 02-20-2016, 02:45 PM by ReturnerScum.)

There was a time where it was widely believed that we, mere mortals, could not possibly have items that give stat bonuses greater than the pitiful, pittance of +/- 7 as the original game provides. But in the course of human events it may be said that many impossibilities are doomed from erosion by the curious effects of human attention. This isn't one of those days, but the beginning of reaching them.

At first it might seem worthwhile to change the values on the items themselves. Unfortunately, there is only one byte for this information on an item, and expanding that to two bytes would mean rearranging the whole series of item data that is packed tightly together, one after the other.

It's possible that there is a much better way. The bonus values of an item have to be added to a character's stats. If the computer makes a calculation to do this, then it might be possible to make a subroutine that increases the amount added, after the item values have already been loaded.

Here is the code for where item stat bonuses are loaded and added to the hero's stats:

This uses binary math (reliant on where the 0s and 1s are physically in each byte) to calculate a 16 bit positive or negative value, then it adds the hero's stat to the accumulator and stores that value.

First we have $D85010,X loaded which I don't exactly know what it is, but I'm guessing it's the stat for the hero we're using. The value of X is linked to which hero we want to update and points the stats of that hero.

Then we load 6 into Y which will be understood at the end, because we're using this as a counting device for the code routine. So when one stat is changed the code decreases this 6 value by 2 and then starts the code again for the next stat, until the value is 0. (BPL = "branch if plus", which takes us to 0FCF if the zero flag is not set, meaning no zeroes happened do to our calculations.)

Now we "push" the A value onto the stack via PHA but this really only copies it to the stack, A hasn't changed. We then only keep the bottom part of the bits in A by doing an AND comparison with #$000F which is 00001111, so any 1's that our A value might have on the last four bits are kept and the others bits are discarded. Then we see if the first digit is a 0 or a 1 via BIT #$0008. If it's a 1 then we use it to signal a negative stat bonus, which means we do an EOR #$FFF7 to get the "two's complement" (a confusing term) and flip the value around into what can then be seen as a negative value of the stat bonus. EOR means that whatever bits are 1 in the operand (FFF7), then the value of A is flipped from 0 to 1 or from 1 to 0. So because we are using EOR with FFF7, it looks like this:

Stat

Bonus 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 1

EOR function

FFF7 = 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1

Result 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0

This A result is the opposite, except for where FFF7 was 0, and only the last four bits matter. The 4th bit from the right ("bit 3") is only used to signal the code to perform this EOR function, so now we don't have to look at it either. This leaves us with the last 3 bits on the right. We started with 0 1 1, which in binary means a value of 3. The items stat bonus is +3, but we're turning it negative. To do this we use a number scheme where we use the range of possible values to either be positive or negative, with 0 in the middle of possible values. So for all the values that could happen here, (1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 = 65535, or two full bytes) we have the middle point (32767 = 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1) and make that zero, and anything above it starts counting negative while anything below it starts counting positive. Because the middle point is zero, when we get the inverse of the original number, we have to add 1 to make up for that extra number (the zero) which first must be crossed before going into negative territory.

What I don't know is why only the right 4 bits matter. We have been manipulating the bits solely based on those last 4 bits and it's unclear to me what we're doing with the other bits. I believe it's because later we LSR 4 bits out of the field, so we're looking at this data 4 bits at a time for 16 bits, which would mean each stat bonus is one of these 4 bits, probably starting with vigor on the right.

So now we have 65532 which is the opposite of 00003 in a range of 65535, and then we INC to add 1 to compensate for the 0 midpoint value. Now we have what will be interpreted as a -3 bonus (65533 = -3, 65534 = -2, 65535 = -1).

Then we clear any carry flags so we can add with carry via ADC indexed by Y. I believe the $11A0, Y is where the stats are from the hero, but I don't know how we know which hero we're looking at, or even if it works differently than that. The Y index is what determines which stat is being added to. The 6th value (Y is currently 6) after 11A0 is going to be vigor, then 2 less than that will be speed, then stamina, then magic. Now we combined the the bonus with the stats and we store it back via STA.

Now we're just trying to get to the other stat bonuses. We pull from the stack via PLA to retrieve our original A value with the stat bonuses, then we LSR four times to get the 12 bits from the left which are now shoved all the way to the right (this means there are 4 new bits all the way to the left, which are 0s). Now we have the next block of information for the next stat bonus, so we decrease our Y index by two via DEY, which we use to count which stat we're boosting. Then we're back to the start of the code routine!

My Changes

Here's the subroutine I created to multiply this calculation by 4, making items give +/- 28. Unfortunately, when you inspect an item in your item menu, it will only say +/- 7 as before.

Does this work perfectly? I'm not sure, but it doesn't seem to crash the game, and all we're doing is multiplying a value by 4. Currently some of my heroes that were wearing items that decreased stats, now have less than 0 for that stat, because they had low base values for their hero. This initial effect on the heroes, when loaded into a previous save state, seems to be permanent, but I think that's only just a problem of playing with a save state after you've changed the game.

And the menu graphics still aren't changed in the item menu, which I don't know how or where to look to change that....but is it still worth it?

Well, you can have your +/- 7 items, or you can have +/- 28 that say +/- 7.

Boom, big game items now!

At first it might seem worthwhile to change the values on the items themselves. Unfortunately, there is only one byte for this information on an item, and expanding that to two bytes would mean rearranging the whole series of item data that is packed tightly together, one after the other.

It's possible that there is a much better way. The bonus values of an item have to be added to a character's stats. If the computer makes a calculation to do this, then it might be possible to make a subroutine that increases the amount added, after the item values have already been loaded.

Here is the code for where item stat bonuses are loaded and added to the hero's stats:

Code:

`C2/0FC8: BF 10 50 D8 LDA $D85010,X (Vigor+ / Speed+ / Stamina+ / MagPwr+ , by ascending address)`

C2/0FCC: A0 06 00 LDY #$0006

C2/0FCF: 48 PHA

C2/0FD0: 29 0F 00 AND #$000F (isolate bottom nibble)

C2/0FD3: 89 08 00 BIT #$0008 (if top bit of stat boost is set, adjustment will be negative)

C2/0FD6: F0 04 BEQ $0FDC (if not, branch)

C2/0FD8: 49 F7 FF EOR #$FFF7 (create a signed 16-bit negative value)

C2/0FDB: 1A INC

C2/0FDC: 18 CLC

C2/0FDD: 79 A0 11 ADC $11A0,Y

C2/0FE0: 99 A0 11 STA $11A0,Y (make adjustment to stat, ranging from -7 to +7)

($11A6 = Vigor, 11A4 = Speed, 11A2 = Stamina, 11A0 = Mag Pwr)

C2/0FE3: 68 PLA

C2/0FE4: 4A LSR

C2/0FE5: 4A LSR

C2/0FE6: 4A LSR

C2/0FE7: 4A LSR (get next highest nibble)

C2/0FE8: 88 DEY

C2/0FE9: 88 DEY

C2/0FEA: 10 E3 BPL $0FCF (loop for all 4 stats)

First we have $D85010,X loaded which I don't exactly know what it is, but I'm guessing it's the stat for the hero we're using. The value of X is linked to which hero we want to update and points the stats of that hero.

Then we load 6 into Y which will be understood at the end, because we're using this as a counting device for the code routine. So when one stat is changed the code decreases this 6 value by 2 and then starts the code again for the next stat, until the value is 0. (BPL = "branch if plus", which takes us to 0FCF if the zero flag is not set, meaning no zeroes happened do to our calculations.)

Now we "push" the A value onto the stack via PHA but this really only copies it to the stack, A hasn't changed. We then only keep the bottom part of the bits in A by doing an AND comparison with #$000F which is 00001111, so any 1's that our A value might have on the last four bits are kept and the others bits are discarded. Then we see if the first digit is a 0 or a 1 via BIT #$0008. If it's a 1 then we use it to signal a negative stat bonus, which means we do an EOR #$FFF7 to get the "two's complement" (a confusing term) and flip the value around into what can then be seen as a negative value of the stat bonus. EOR means that whatever bits are 1 in the operand (FFF7), then the value of A is flipped from 0 to 1 or from 1 to 0. So because we are using EOR with FFF7, it looks like this:

Stat

Bonus 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 1

EOR function

FFF7 = 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1

Result 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0

This A result is the opposite, except for where FFF7 was 0, and only the last four bits matter. The 4th bit from the right ("bit 3") is only used to signal the code to perform this EOR function, so now we don't have to look at it either. This leaves us with the last 3 bits on the right. We started with 0 1 1, which in binary means a value of 3. The items stat bonus is +3, but we're turning it negative. To do this we use a number scheme where we use the range of possible values to either be positive or negative, with 0 in the middle of possible values. So for all the values that could happen here, (1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 = 65535, or two full bytes) we have the middle point (32767 = 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1) and make that zero, and anything above it starts counting negative while anything below it starts counting positive. Because the middle point is zero, when we get the inverse of the original number, we have to add 1 to make up for that extra number (the zero) which first must be crossed before going into negative territory.

What I don't know is why only the right 4 bits matter. We have been manipulating the bits solely based on those last 4 bits and it's unclear to me what we're doing with the other bits. I believe it's because later we LSR 4 bits out of the field, so we're looking at this data 4 bits at a time for 16 bits, which would mean each stat bonus is one of these 4 bits, probably starting with vigor on the right.

So now we have 65532 which is the opposite of 00003 in a range of 65535, and then we INC to add 1 to compensate for the 0 midpoint value. Now we have what will be interpreted as a -3 bonus (65533 = -3, 65534 = -2, 65535 = -1).

Then we clear any carry flags so we can add with carry via ADC indexed by Y. I believe the $11A0, Y is where the stats are from the hero, but I don't know how we know which hero we're looking at, or even if it works differently than that. The Y index is what determines which stat is being added to. The 6th value (Y is currently 6) after 11A0 is going to be vigor, then 2 less than that will be speed, then stamina, then magic. Now we combined the the bonus with the stats and we store it back via STA.

Now we're just trying to get to the other stat bonuses. We pull from the stack via PLA to retrieve our original A value with the stat bonuses, then we LSR four times to get the 12 bits from the left which are now shoved all the way to the right (this means there are 4 new bits all the way to the left, which are 0s). Now we have the next block of information for the next stat bonus, so we decrease our Y index by two via DEY, which we use to count which stat we're boosting. Then we're back to the start of the code routine!

My Changes

Here's the subroutine I created to multiply this calculation by 4, making items give +/- 28. Unfortunately, when you inspect an item in your item menu, it will only say +/- 7 as before.

Code:

`C2/0FDD: 20 80 67 JSR $6780 Jump to subroutine`

C2/0FE0: EA EA EA NOP Cancel obsolete code

C2/6780: 3A DEC Decrease the increase from before

C2/6781: 0A ASL Double A value

C2/6782: 0A ASL Double A value (x4 now)

C2/6783: 1A INC Increase A by 1

C2/6784: 18 CLC Clear carry before loading

C2/6785: 79 A0 11 ADC $11A0,Y

C2/6788: 99 A0 11 STA $11A0,Y (make adjustment to stat, ranging from -28 to +28)

($11A6 = Vigor, 11A4 = Speed, 11A2 = Stamina, 11A0 = Mag Pwr)

C2/678B: 60 RTS

And the menu graphics still aren't changed in the item menu, which I don't know how or where to look to change that....but is it still worth it?

Well, you can have your +/- 7 items, or you can have +/- 28 that say +/- 7.

Boom, big game items now!

i think you wanna keep the "INC" before the "JSR $6780" instead of moving it.

02-20-2016, 02:44 PM

I can't get it to work any way other than the inefficient way I first tried it---I have no idea why.

Instead of moving the INC +1 and the CLC, I have to DEC -1 then INC and CLC after the ASL ASL. When I look at how the bits should be effected, it seems like I should instead put the INC before the ASL, and I'm not even sure why we CLC.

Instead of moving the INC +1 and the CLC, I have to DEC -1 then INC and CLC after the ASL ASL. When I look at how the bits should be effected, it seems like I should instead put the INC before the ASL, and I'm not even sure why we CLC.

02-20-2016, 10:44 PM

to be sure, keep the INC at C2/0FDB, and NOP the CLC at C2/0FDC. get rid of the DEC and INC in your added function.

i should probably add this comment:

though based on this (and your earlier paragraph):

, you already grasp it.

i should probably add this comment:

Code:

`C2/0FDB: 1A INC (A = 65536 - bottom 3 bits. iow, negation of the`

3-bit value.)

though based on this (and your earlier paragraph):

Quote:So now we have 65532 which is the opposite of 00003 in a range of 65535, and then we INC to add 1 to compensate for the 0 midpoint value. Now we have what will be interpreted as a -3 bonus (65533 = -3, 65534 = -2, 65535 = -1).

, you already grasp it.

02-21-2016, 02:20 PM

What's the difference between INC before the JSR and after the JSR opcode is used? And I'm still unsure why we CLC at all. It works so everything's fine but these are pretty strange unknowns to me.

Quote:What's the difference between INC before the JSR and after the JSR opcode is used?

that's not the issue. the issues are:

- needing the INC before the ASLs.

- only executing the INC if we had a negative boost, staying true to the original game.

Quote:And I'm still unsure why we CLC at all.

CLC ensures we don't have an extra +1 in our addition.

« Next Oldest | Next Newest »

Users browsing this thread: 1 Guest(s)