#6657 closed defect (fixed)

Elite units small discrepancy between maxHitpoints and hitpoints

Reported by: Langbart Owned by: Freagarach
Priority: If Time Permits Milestone: Alpha 27
Component: Simulation Keywords:
Cc: Patch:

Description (last modified by Langbart)

to reproduce

  • start the units_demo map
pyrogenesis -autostart="scenarios/units_demo" -autostart-victory="endless"
  • seek the Mauryan Hero Healer Acharya Chanakya, somewhere in the back rows. You will find him, because he is the only one walking around .

  • the Healer is going to some Elite units to heal them, for example the Cretan Mercenary Archer
  • select the Cretan Mercenary Elite Archer, toggle the Developer Overlay Alt+D and the option Display selection state
    • the difference between hitpoints and maxHitpoints is only 0.00000000000001 == 1E-14

Line 
66 </TrainingRestrictions>
67 <Vision>
68 <Range>100</Range>
69 </Vision>
70</Entity>
Line 
53 </Sound>
54 <Vision>
55 <Range>30</Range>
56 </Vision>
57</Entity>

minimal amount of units to reproduce the issue

  • change the units_demo.js to only show three units. the combo is enough to create the discrepancy in health points.
    • binaries/data/mods/public/maps/scenarios/units_demo.js

      a b let maxh = 0;  
      3131let gap = 14;
      3232
      3333let cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
      34 for (let template of cmpTemplateManager.FindAllTemplates(actors))
       34for (let template of ["units/mace/hero_pyrrhus_i", "units/iber/catafalque", "units/maur/elephant_archer_e"])
      3535{
      3636    print(template + "...\n");

intended behavior

  • the hitpoints for all elite units should be the same as the maxHitpoints when the game starts

cause of the issue

See the comment by Stan suggesting floating point math

❯ node
Welcome to Node.js v19.1.0.
> 0.1+0.2
0.30000000000000004

possible solution

one-line change, there is a calculation being made in the Health.js file.

example units/maur/elephant_archer_e

# this.hitpoints * newMaxHitpoints / oldMaxHitpoints
❯ node
Welcome to Node.js v19.1.0.
> 233.75000000000003*292.18750000000006/233.75000000000003
# 292.1875
  • binaries/data/mods/public/simulation/components/Health.js

    a b Health.prototype.RecalculateValues = function()  
    465465    let newMaxHitpoints = ApplyValueModificationsToEntity("Health/Max", +this.template.Max, this.entity);
    466466    if (oldMaxHitpoints != newMaxHitpoints)
    467467    {
    468         let newHitpoints = this.hitpoints * newMaxHitpoints/oldMaxHitpoints;
     468        let newHitpoints = (this.hitpoints === oldMaxHitpoints) ? newMaxHitpoints : this.hitpoints * newMaxHitpoints / oldMaxHitpoints;
    469469        this.maxHitpoints = newMaxHitpoints;
    470470        this.SetHitpoints(newHitpoints);
    471471    }

Attachments (3)

Chanakya.jpg (13.1 KB ) - added by Langbart 18 months ago.
hitpoint_diff.jpg (569.6 KB ) - added by Langbart 18 months ago.
maur_ele.png (177.9 KB ) - added by Langbart 18 months ago.

Download all attachments as: .zip

Change History (11)

by Langbart, 18 months ago

Attachment: Chanakya.jpg added

by Langbart, 18 months ago

Attachment: hitpoint_diff.jpg added

comment:1 by Stan, 18 months ago

Might be float imprecision

comment:2 by Langbart, 18 months ago

Description: modified (diff)

comment:3 by phosit, 18 months ago

Yes moast propably it is float imprecision: Bigger values are (absolute) more imprecise. Elite Vachii Gaia (Elephant Archer) have 292.18750000000006.

The imprecision alone is not a problem the difference between hitpoints and maxHitpoints is. For Advanced Vachii Gaia (Elephant Archer) maxHitpoints does round to 233.75000000000003 but hitpoints does that to. There is no difference and they need no heal.

Typeing 187 * 1.25 in to the in game console results in 233.75 an not 233.75000000000003

comment:4 by Freagarach, 18 months ago

It was reported by @wowgetoffyourcellphone before as well. Maybe even this: https://github.com/JustusAvramenko/delenda_est/commit/cd88bed66168a0366ac816dcdd8a841de8e536fc.

in reply to:  3 comment:5 by Langbart, 18 months ago

Replying to phosit:

Typeing 187 * 1.25 in to the in game console results in 233.75 an not 233.75000000000003


Source: ESLINT rule: no-loss-of-precision

In JS, Numbers are stored as double-precision floating-point numbers according to the IEEE 754 standard. Because of this, numbers can only retain accuracy up to a certain amount of digits. If the programmer enters additional digits, those digits will be lost in the conversion to the Number type and will result in unexpected behavior.

example - node.js

the second calculation has one more zero

node
Welcome to Node.js v19.1.0.
> 58.43750000000001 * 1.25
# 73.04687500000001
> 58.437500000000001 * 1.25
# 73.046875

comment:6 by Langbart, 18 months ago

Description: modified (diff)

by Langbart, 18 months ago

Attachment: maur_ele.png added

comment:7 by Langbart, 18 months ago

Description: modified (diff)

adding possible solution section

comment:8 by Freagarach, 16 months ago

Owner: set to Freagarach
Resolution: fixed
Status: newclosed

In 27425:

Fix discrepancy between max hitpoints and actual hitpoints due to floats in JS.

Patch by: @Langbart
Fixes #6657

Note: See TracTickets for help on using tickets.