News for hackers. Stuff that matters.
Re:Aztec monks with 1/55 HP no longer die when picking up or... by PhilipRoman on Saturday April 15, 2023 @03:59AM (#35578601)
Aren't rationals subject to exponential blowup in storage/precision? IMO the best approach for business logic values is picking the smallest meaningful unit and representing it with integers. Precision and storage requirements become very easy to reason about.
Re:Aztec monks with 1/55 HP no longer die when picking up or... by DaiPlusPlus on Saturday April 15, 2023 @04:26AM (#35578735)
> IMO the best approach for business logic values is picking the smallest meaningful unit and representing it with integers.

How would you design an RTS unit stats system to avoid this AoE Monk HP bug using only integer types?

Re:Aztec monks with 1/55 HP no longer die when picking up or... by bruce343434 on Saturday April 15, 2023 @05:40AM (#35579052)
How much health precision do you need? Make hp an int. Or like a /64 fixed point.
Re:Aztec monks with 1/55 HP no longer die when picking up or... by account42 on Monday April 17, 2023 @05:36AM (#35598523)
Congratulations, you just introduced a new damage threshold / resistance threshold / etc where things effectively do no damage.

Fixed point would not have helped here. Integer would only have helped because dividing first would break immediately.

Re:Aztec monks with 1/55 HP no longer die when picking up or... by falcor84 on Saturday April 15, 2023 @05:41AM (#35579063)
Well, in this case, if a unit is converted to a different type and back, it would just keep its (absolute) value of HP (in this case 1), no need to scale anything.
Re:Aztec monks with 1/55 HP no longer die when picking up or... by db48x on Saturday April 15, 2023 @06:08AM (#35579175)
You haven’t thought it through yet. In this case, HP _is_ an integer, and so is the MaxHP for the unit type. And yet the bug still occurs! Storing the HP as an integer does not prevent the problem from ever occurring, because fundamentally the user still expects HP to be proportional.

That is, suppose a unit is sitting there at full health, and you research a tech that increases that unit’s max hp? Should the unit now be at less than full health, as if it had been in combat? Users probably don’t like that.

Suppose it is at full health, and then it gets downgraded to a type with less maximum health. Does it stay at it’s current HP? Users probably won’t like being attacked with supercharged units that have extra HP; they’ll think that the other player was cheating somehow.

What if it is damaged and at half health, then gets upgraded. Should it be fully healed? Gain HP equal to the difference between the new and old maximum HP? Or should it gain half of that, so that it stays at half health?

Or perhaps HP is too limiting, and the game should do what Dwarf Fortress does. DF knows the approximate surface area of every body part (based on each creature’s body plan, plus individual stats such as strength, fatness, size, etc), and the size of every weapon. Every attack therefore deals damage to a certain area, measured in square inches, and individual body parts will be destroyed once a sufficient percentage of that surface area is damaged by wounds.

Or maybe you are designing this game in the 90’s, and you have to worry about squeezing unit updates for 200 units per player into the bandwidth provided by the average modem of the day (probably 28.8kbaud), so you stick to one integer because it’s the simplest think that can possibly work, and the number of bytes per update can be calculated in advance. And then some other schmuck gets stuck with the job of handling unit type changes (but be warned that the schmuck might be yourself in six months).

Re:Aztec monks with 1/55 HP no longer die when picking up or... by ilyt on Saturday April 15, 2023 @06:31AM (#35579303)
>That is, suppose a unit is sitting there at full health, and you research a tech that increases that unit’s max hp? Should the unit now be at less than full health, as if it had been in combat? Users probably don’t like that.

>Suppose it is at full health, and then it gets downgraded to a type with less maximum health. Does it stay at it’s current HP? Users probably won’t like being attacked with supercharged units that have extra HP; they’ll think that the other player was cheating somehow.

>What if it is damaged and at half health, then gets upgraded. Should it be fully healed? Gain HP equal to the difference between the new and old maximum HP? Or should it gain half of that, so that it stays at half health?

     if (oldHP == maxOldHP) { newHP = newMaxHP }
     else { newHP = max(1,scale(oldHP,oldMaxHP,newMaxHP))
not exactly complex
Re:Aztec monks with 1/55 HP no longer die when picking up or... by ghusbands on Saturday April 15, 2023 @07:18AM (#35579564)
Sure, if you fully predict all bugs in advance and compensate for them, nothing is complex, but that's not really feasible.
Re:Aztec monks with 1/55 HP no longer die when picking up or... by mrguyorama on Monday April 17, 2023 @02:33PM (#35604630)
>Sure, if you fully predict all bugs in advance and compensate for them, nothing is complex, but that's not really feasible.

Uhh, last time I checked, that was literally my job, and specifically what I went to school for!

Re:Aztec monks with 1/55 HP no longer die when picking up or... by db48x on Saturday April 15, 2023 @08:05AM (#35579842)
Not exactly complex, but you posted too quickly to have found the best solution.

A better solution is to kill the unit when it drops below zero HP, not when it drops below 1.0; scaling will never move the current HP past zero in either direction. Having 0.9999994 HP instead of 1.0 HP would not cause any problems then; the unit is still one hit away from death in either case.

The best solution is probably to store the current HP as a percentage of the max, because then you never have to rescale it in the first place.

Re:Aztec monks with 1/55 HP no longer die when picking up or... by InitialLastName on Saturday April 15, 2023 @10:42AM (#35581029)
> The best solution is probably to store the current HP as a percentage of the max, because then you never have to rescale it in the first place.

Doesn't this solution make the more common calculations more expensive, complicated, and error-prone to make one rare calculation easier? It seems like far more of the operations on the unit's current HP will be "gets damaged by X hp" or "gets healed by X hp", both of which would require the equivalent of the above conversion to establish a result.

Re:Aztec monks with 1/55 HP no longer die when picking up or... by db48x on Saturday April 15, 2023 @12:00PM (#35581835)
If you’ve changed HP to a percentage, why wouldn’t you also change the damage and other related numbers (such as damage reduction and so on) to percentages as well? Nobody would be dumb enough to store them in different units and then convert every time they manipulate them.
Re:Aztec monks with 1/55 HP no longer die when picking up or... by mlyle on Saturday April 15, 2023 @12:53PM (#35582319)
> why wouldn’t you also change the damage and other related numbers (such as damage reduction and so on) to percentages as well?

Because a sword might do 5HP of damage, not 10% of anyone's damage (whether they've got 50 or 5000HP). Otherwise, hit points are meaningless: 10 attacks with a 10%-damage weapon kills a lowly serf or a mighty dragon.

And because damage reduction might reduce a fixed amount of damage from an attack. Etc.

Re:Aztec monks with 1/55 HP no longer die when picking up or... by db48x on Saturday April 15, 2023 @01:53PM (#35582875)
Obviously a dragon doesn’t get damaged at all by a puny little sword. You can’t just say that hitting a dragon with a sword a thousand times would kill it, when none of the attacks can get through the dragon’s armored hide. On the other hand, it will die immediately if pierced by an arrow provided that arrow hits the one spot where the hide is missing a scale. The dragon has 100% DR, except in that one spot.
Re:Aztec monks with 1/55 HP no longer die when picking up or... by account42 on Monday April 17, 2023 @05:42AM (#35598573)
> Obviously a dragon doesn’t get damaged at all by a puny little sword. You can’t just say that hitting a dragon with a sword a thousand times would kill it, when none of the attacks can get through the dragon’s armored hide.

https://www.youtube.com/watch?v=9VDvgL58h_Y

Re:Aztec monks with 1/55 HP no longer die when picking up or... by db48x on Tuesday April 18, 2023 @04:30PM (#35619620)
:D
Re:Aztec monks with 1/55 HP no longer die when picking up or... by mlyle on Saturday April 15, 2023 @11:58AM (#35581816)
> A better solution is to kill the unit when it drops below zero HP

Then you have the situation where units are displayed as having 0 HP but are still alive.

Re:Aztec monks with 1/55 HP no longer die when picking up or... by db48x on Saturday April 15, 2023 @12:23PM (#35582039)
So what? The players already know that attacks deal fractional HP damage.
Re:Aztec monks with 1/55 HP no longer die when picking up or... by mlyle on Saturday April 15, 2023 @12:50PM (#35582292)
> The players already know that attacks deal fractional HP damage.

Top-end players who analyze the engine enough do.

Otherwise, they shrug and say "sometimes 1, sometimes 2 HP"

And even so, we're used to seeing 0/50HP and it meaning "dead" across many games. Seeing 0/50HP and it meaning "just a small amount of HP left" isn't ideal.

Not to mention that weird situations with 5.551115123125783e-17 HP remaining aren't great either (where a player may end up with effectively an "extra" hit point).

Re:Aztec monks with 1/55 HP no longer die when picking up or... by db48x on Saturday April 15, 2023 @02:01PM (#35582952)
Again I say “so what?”. The unit is one hit away from death either way, and the player will know it.
Re:Aztec monks with 1/55 HP no longer die when picking up or... by mlyle on Saturday April 15, 2023 @02:07PM (#35583015)
At this point, with your Smaug-related comment, etc-- I've become convinced you're trolling.

But just to humor you: the desire is to have a system where floating point neither surprisingly kills nor gives characters extra hit points. There's a lot of subtlety in this. Schemes where all damage are percents don't preserve the essential pieces of RPG combat systems. Moving the threshold from 1 to 0 HP violates the conventions of the art and doesn't eliminate the problems (you can still end up with hit points epsilon away from 0, instead of 1).

Re:Aztec monks with 1/55 HP no longer die when picking up or... by db48x on Sunday April 16, 2023 @04:28AM (#35588220)
The problem isn’t hitpoints that are an epsilon away from 1, it’s that an operation which looked innocuous moved the HP to an epsilon _below_ 1. That would never happen with 0, however, as multiplication and division of positive numbers always gives a positive result.

And in D&D, incapacitation happens when a character drops below 0 HP, and death happens once they drop below -10HP. There is no grand convention that all RPG games follow here; each game is making things up as they go. They picked badly when they designed Age of Empires, and that’s ok. It’s not the end of the world. Just know that we can do better if we are paying attention.

And I am serious when I ask “so what?”. Why is it so bad if the game displays 0/55HP? The players all know that fractional HP damage exists, and they can see that their unit is still alive, so what is the problem? They will be at least as amazed that their unit survived as they currently are when they see a unit at 1/55HP.

I am likewise serious about Smaug; there is no way that combat makes any sense if Smaug has a large number of hitpoints or that any weapon at all can damage him. Using hitpoints as an abstraction completely loses all of the flavor of Tolkien’s original descriptions. A better model is one using damage reduction and sensible internal organs; a strike that pierces the heart will kill even a dragon.

Re:Aztec monks with 1/55 HP no longer die when picking up or... by mlyle on Sunday April 16, 2023 @12:52PM (#35591704)
> however, as multiplication and division of positive numbers always gives a positive result.

Depends on what you do with subnormals and underflow, etc.

> There is no grand convention that all RPG games follow here

Computer RPGs have shown 0/812 for dead for ... forever.

> The players all know that fractional HP damage exists

I think most players will be confused. And for what, to make it "safe" doing floating point operations in the wrong order? (I doubt it's still safe, overall).

> I am likewise serious about Smaug; there is no way that combat makes any sense if Smaug has a large number of hitpoints or that any weapon at all can damage him.

Common mechanisms: an armor class that makes it hard to hit; a fixed amount of damage reduction so that a needle does nothing; a lot of hitpoints.

> and sensible internal organs;

It gets excessively complicated and annoying. Battletech is already excessively complicated, and doesn't go quite as far as you're advocating for here.

Re:Aztec monks with 1/55 HP no longer die when picking up or... by CodesInChaos on Saturday April 15, 2023 @06:26AM (#35579273)
`(new_maxhp * old_hp) / old_maxhp` avoids the original problem when using integers. Though you still need to make sure your type is big enough to not overflow.

Or using fixed-point (which are a relatively simple abstraction over integers): `old_hp * (new_maxhp * old_maxhp)`.

Re:Aztec monks with 1/55 HP no longer die when picking up or... by rvnx on Saturday April 15, 2023 @03:05PM (#35583569)
They probably just added: return ROUND()... and went back to play
Re:Aztec monks with 1/55 HP no longer die when picking up or... by ilyt on Saturday April 15, 2023 @06:27AM (#35579276)

     max(1,...
Re:Aztec monks with 1/55 HP no longer die when picking up or... by rini17 on Saturday April 15, 2023 @06:29AM (#35579292)
Did this exponential blowup ever prove troublesome in practice? I think it can be easily solved by strategically placed rounding steps. But explicit rounding is advisable in many cases anyway.
Re:Aztec monks with 1/55 HP no longer die when picking up or... by jrochkind1 on Saturday April 15, 2023 @09:12AM (#35580332)
But strategically placed rounding was in fact the solution to the original problem that in this thread Rationals were proposed as solving...

Rational types are not super popular and don't get used that much, most (not all) people that end up using them do it very intentionally and consciously and know what they're dealing with -- if they were more ubiquitious, I suspect more trouble would be seen "in practice".

While it's probably true that any digital number format will have edge cases that in fact come up in practice, my personal choice of "Why the heck isn't this more popular, why doesn't every language support it, why isn't it in fact the default representation of a numeric literal" -- is floating point "decimal" types, like ruby (or I think Java?) BigDecimal, rather than rational. I think they mostly work matching programmer's mental models of numbers, and for many/most common uses on 2023 platforms the performance is just fine. (this would not have been true 30 years ago).

Re:Aztec monks with 1/55 HP no longer die when picking up or... by rini17 on Saturday April 15, 2023 @09:26AM (#35580442)
Or it's vendors that don't care about correctness, like providing decimals by default and high performance floating point as an "optimized" option. Python did something like that by using bigints as a default for integers.

What would not have been true 30 years ago? I remember "real" fixed-point type built-in in Turbo Pascal and explicitly documented as suitable for money. Common Lisp has had first class fractions support since the start.

Re:Aztec monks with 1/55 HP no longer die when picking up or... by jrochkind1 on Saturday April 15, 2023 @09:29AM (#35580472)
I meant to suggest that 30 years ago the performance difference between "floats" (floating-point binary) and "BigDecimal"-style arbitrary-precision floating-point decimal would have been much more significant to many more real-world use cases, compared to now. So that may have been a reason not to make them the default when you simply write a literal `5.4` in code, but that argument is less now.
Re:Aztec monks with 1/55 HP no longer die when picking up or... by GreymanTheGrey on Saturday April 15, 2023 @11:21AM (#35581423)
Slight correction, from a former Turbo Pascal (and subsequent Delphi) programmer...

"Real" types were platform-dependent floating-point types, not suitable for monetary calculations whatsoever. and would map to either Single or Double depending on the underlying CPU architecture. Sort of like a C-style "int" that would map to an 8-bit, 16-bit, 24-bit, 32-bit, 36-bit, 60-bit, 64-bit etc integer, depending on the compiler and the compile target.

Turbo Pascal did have an 8-byte, fixed point, "Currency" type suitable for monetary calculations, however using it was very, very slow compared to pure floating point ops - just as the comment you replied to suggested. If that weren't enough, library support (both built-in and 3rd-party) for math and other utility functions was either limited or non-existent.

Re:Aztec monks with 1/55 HP no longer die when picking up or... by fm77 on Saturday April 15, 2023 @06:22PM (#35585200)
Slight correction from an Turbo Pascal expert ;-)

Turbo Pascal did NOT have an 8-byte fixed point "currency" type suitable for monetary calculations. It did have an int64 type called "comp" though which was handled by the FPU and hence not slower than the types "single" (f32), "double" (f64) or "extended" (f80).

IIRC, "currency" came with Delphi V2.0 (or even later), but then still it wasn't slower than other floats when you did heavy calculations with it as it was also handled by the FPU. Only reads and writes from and to such variables were expensive as there was always a scaling (multiplication by 1e4 and 1e-4) involved — internally it was that int64 "comp" type. (But here I might be wrong, I never used "currency" and my Delphi knowledge is quite fuzzy).

Re:Aztec monks with 1/55 HP no longer die when picking up or... by MobiusHorizons on Saturday April 15, 2023 @01:47PM (#35582809)
Fun fact many processors actually support decimal types in hardware. I believe you can use them in c with _Decimal. Worked on my Ryzen 3700x and (if memory serves) my M1 mac
Re:Aztec monks with 1/55 HP no longer die when picking up or... by MobiusHorizons on Tuesday April 18, 2023 @11:12PM (#35623835)
Due to the downvotes I looked into this again. You can use _Decimal32 etc in GCC on x86, but it is a soft implementation. I believe it is in hardware on some ibm platform, but definitely not on the M1