PDA

View Full Version : Script Counters Roll Over to Max Int When Going Below Zero



ywkls
01-19-2017, 03:32 PM
Something I noted in some of my scripts. (I don't know if this applies to just script counters, but that's where I saw this happen.)

When the counter drops below zero for whatever reason, it rolls over to 65,535.

ZoriaRPG
01-19-2017, 04:00 PM
Something I noted in some of my scripts. (I don't know if this applies to just script counters, but that's where I saw this happen.)

When the counter drops below zero for whatever reason, it rolls over to 65,535.

Please post a tiny sample quest that attempts to do this using whatever methods you know that have this issue, for each counter, so that we know which counters it affects, and precisely what is causing it.

I mentioned this in the past, but everyone assured me that it was fixed?

It should not be hard to write a handler to resolve this problem, although for the record, I think counters would be better as individual 32-bit width longs instead of 16-bit width ints.(This is to keep them in the same mathematical context as other ZC values.)

Check also MCounter[] and DCounter[] please, as well as Link->MP and Link->HP, which IIRC should not do this because they do have handlers to prevent that sort of thing.

Saffith
01-19-2017, 05:13 PM
I don't know if we would consider this a problem. Counters are uint16_t; that's just what they do. It's not unreasonable behavior. Maybe it's unexpected that the range is different than other numbers, but plenty of built-in things have different ranges.

ZoriaRPG
01-19-2017, 11:36 PM
I don't know if we would consider this a problem. Counters are uint16_t; that's just what they do. It's not unreasonable behavior. Maybe it's unexpected that the range is different than other numbers, but plenty of built-in things have different ranges.

Sure, but when scripts modify them without checking if the post-modufied sum exceeds their value limit, then they generate bus.

The real problem is that ADDR/V don't care what they are writing here. AFAIK increasing a fix to > 214749.9999 doesn't roll it over to -214747.9999, does it?

For a an int 16, it is normal, but in their application, rolling over is irrational, and only scripta can do it. Picking up counter ref items does not.

I could add a check to prevent this behaviour in ZASM. Need to check if this will be problematic.

SUCCESSOR
01-20-2017, 12:05 AM
Sure, but when scripts modify them without checking if the post-modufied sum exceeds their value limit, then they generate bus.

The real problem is that ADDR/V don't care what they are writing here. AFAIK increasing a fix to > 214749.9999 doesn't roll it over to -214747.9999, does it?

For a an int 16, it is normal, but in their application, rolling over is irrational, and only scripta can do it. Picking up counter ref items does not.

I could add a check to prevent this behaviour in ZASM. Need to check if this will be problematic.

o.O I don't know if I am tired from school and work but sometimes when you talk I can't wrap my head around what you are trying to say. Longs, Zscript variables, do indeed wrap if you exceed them. I know they have a funniness about them with the whole decimal thing it does, but... that's another bag of WTF. I don't know what behavior you'd want counters to have that would change the way they behave. I don't believe it would happen in game besides through scripting.

If you are coding and setting a value to a variable without concern for what that variable can contain or what you are writing to it then you aren't coding very well.

ZoriaRPG
01-20-2017, 12:29 AM
o.O I don't know if I am tired from school and work but sometimes when you talk I can't wrap my head around what you are trying to say. Longs, Zscript variables, do indeed wrap if you exceed them. I know they have a funniness about them with the whole decimal thing it does, but... that's another bag of WTF. I don't know what behavior you'd want counters to have that would change the way they behave. I don't believe it would happen in game besides through scripting.

If you are coding and setting a value to a variable without concern for what that variable can contain or what you are writing to it then you aren't coding very well.

(Emphasis, mine.)

Absolutely true. I check for these sorts of things whenever possible, but when people have a script like this:



item script foo{
void run(int ctr){
Game->Counter[ctr]++;
}
}


...and trust me, these about in the database...

...then it can cause rollover. It's illogical for a counter to roll over anyway. That's my real point. That, and the behaviour doesn't match internal counter ref behaviour from items, IIRC.

ZScript fix values do indeed wrap, although the values generated are bizarre.

214747 += 1 goes to 214748, and ++ again wraps to -214747.7296. ??? What?

9999 - 3647 = 6352, not 7296. What is happening there?

214748.3647 += .0001 wraps to -214748.3648.

Gleeok
01-20-2017, 12:30 AM
Rpgs have this problem. A base value is always expected to be in range 0:N, but modifiers are valid if < 0 or > N. Finally, final derived values are again expected to be within range of 0 to N when the dust settles. (This is not the case with statistical values but ZC doesn't have those. :P) I would assume that setting a counter (with implicit positive range) to -1 would set it to 0 and not 65535.

What are all the counters affected by this?

SUCCESSOR
01-20-2017, 12:46 AM
(Emphasis, mine.)
...then it can cause rollover. It's illogical for a counter to roll over anyway. That's my real point. That, and the behaviour doesn't match internal counter ref behaviour from items, IIRC.


Rpgs have this problem. A base value is always expected to be in range 0:N, but modifiers are valid if < 0 or > N. Finally, final derived values are again expected to be within range of 0 to N when the dust settles. (This is not the case with statistical values but ZC doesn't have those. :P) I would assume that setting a counter (with implicit positive range) to -1 would set it to 0 and not 65535.

What are all the counters affected by this?

I would expect setting the counter directly through script for it to behave like the variable it is. I would expect that letting the game handle adjusting the counter to behave as it should.

That's what we have drain counters, right?

Grayswandir
01-20-2017, 07:54 AM
I just want to point out the one "common" case in which allowing negative hp would be beneficial, since I don't believe anybody's mentioned it:

I've set up an elemental damage system where I encode the damage in the ones digit of the decimal damage number, and the actual damage in the higher digits. Then, every frame, you compare Link's hp to his hp in the previous frame. If he took damage, you can tell exactly what element it was, and adjust his hp to the correct amount based on weaknesses, etc.

The problem hits when your hp gets too low to take the full damage from an attack. To get around this I add around 1000 hp to link to make sure it never goes negative - but this messes up the built-in hp meter, and the save file, and a whole bunch of other things, meaning you need custom scripts to handle all of them.

Of course, my specific case is a bit complicated. But I've seen several other people (attempt to) use the "compare hp to last frame and then do something" strategy, that disallowing negative hp makes difficult. Ideally, the game would allow hp to go negative, but all the built-in aspects like the health meter and such would treat it as 0.

I understand if y'all don't want to do that, though. :shrug:

ZoriaRPG
01-20-2017, 09:18 AM
I would expect setting the counter directly through script for it to behave like the variable it is. I would expect that letting the game handle adjusting the counter to behave as it should.

That's what we have drain counters, right?

THat's true. I wish that people used them, but one reason they do not, is that say, you want to write Game->DCounter[CR_RIUPEES] -= 10000;

Who long do you want to head that sound and watch the counter go down? Writing to Game->counter instantly applies the change.

Let me try this: Who can make a case for rollover being useful, or beneficial, in the context of counters?
DarkDragon, Grayswandir, and I all seem to agree that rollover in the counters is irrational.

We can always make it a rule or setting. I could put it in ffrules[], or add a global bit for it. I just don;t see the point of doing that, unless there is a very good reason for it.

Likewise, I would like to see cases against both longs as counters, and signed values; as I do not see an issue with any of these, based on what we now have. We already trim bits off of the word to make counters work with DCounter, which is signed.

DarkDragon
01-20-2017, 12:53 PM
There are two issues here we should disentagle:
- preventing scripts from decrementing a counter, if doing so would cause it to wrap around to a positive value;
- supporting negative values for counters that are currently unsigned.

Both issues have some merit, but the former is much easier and self-contained than the latter (check in the appropriate ZASM interpreter code before applying a change, vs. go through all places where the game engine uses a counter and make sure nothing breaks badly when the counter is negative.)

Are any old scripts relying on the counter-wrapping behavior? It seems unlikely, but I might as well ask.

SUCCESSOR
01-20-2017, 08:46 PM
Are any old scripts relying on the counter-wrapping behavior? It seems unlikely, but I might as well ask.

Unlikely, but possible. I have used Counters as global variables is the past because, well they are there and I didn't need them for anything else. I have at least once used a counter as a timer of sorts that incremented every frame and expected it to wrap and keep going. We are talking about fixing a non-issue and creating potential issues for any scripts in the last ~10 years that expect a variable to act like a variable.

I'll ask this plainly this time. Why is the way it is now an issue?

ZoriaRPG
01-23-2017, 06:11 AM
You know what... i was adding ffrules[] to ZScript. I can just make the behaviour a script-set rule, given that it only affects counters modified by script, and whatever guards we set can be set per counter, or globally.

Is that sufficient to prevent concerns?

The same could potentially work for allowing negative counters, and even long counters. We can make counters longs, and artificially roll them at the old values, unless a quest rule 'large counters' is set, and allow negative by quest or script rule. This would emulate the old behaviour for existing quests.

ZoriaRPG
09-25-2018, 09:09 AM
I'll try to punch this one out tomorrow. It might only go into 2.55.