Author Topic: [Suggestion] Primary stats award rounding  (Read 86 times)

Offline Delian

  • Commander
  • *****
  • Posts: 658
    • View Profile
[Suggestion] Primary stats award rounding
« on: March 12, 2025, 07:50:59 pm »
After a mission ends, the player's units have their stats increased based on the amount of exp they got in that particular stat.

In the OG, the primary accuracy stat awards are split into 4 buckets:
Code: [Select]
exp: award:
1-2 0.5-1.5
3-5 1.0-3.0
6-10 1.5-4.5
11- 2.0-6.0

Which is the result of the following formula from the original game:

award = 1 + (exp > 2) + (exp > 5) + (exp > 10); // 1 or 2 or 3 or 4
award = award / 2 + random(award);

However, due to a rounding bug (perhaps compiler-dependant) in the OG, the 1st and 3rd bucket erroneously give less stats than they should.
The 1st bucket, instead of giving on average 1 point, gives 0.5, and the 3rd bucket, instead of 3, gives on average 2.5.

I would appreciate it if there existed an option which corrected the rounding error, so that the 1st and 3rd bucket would give 1 and 3 stat points on average respectively.
« Last Edit: March 12, 2025, 09:34:50 pm by Delian »

Offline Meridian

  • Global Moderator
  • Commander
  • *****
  • Posts: 9415
    • View Profile
Re: [Suggestion] Secondary stats award rounding
« Reply #1 on: March 12, 2025, 09:03:54 pm »
I have no idea what you're talking about.

Your description vaguely resembles the primary stats increase, but the numbers are not correct.
See description here: https://www.ufopaedia.org/index.php?title=Experience#Primary_Stats
or OXC source code.

The secondary stats increase works completely differently and is described here: https://www.ufopaedia.org/index.php?title=Experience#Secondary_Stats


PS: in any case, I have zero reason, desire or motivation to change any of these OG algorithms, unless a big mod asks for it and gives a good justification for the change. And even then it would just be exposed to scripting, so you can abuse it to your exact liking.

Offline Delian

  • Commander
  • *****
  • Posts: 658
    • View Profile
Re: [Suggestion] Primary stats award rounding
« Reply #2 on: March 12, 2025, 09:47:04 pm »
Oops, I meant primary stats.

Yes, as I mentioned, due to rounding error, what the 1st bucket awards is 0-1, which is 0.5-1.5 rounded down, and the 3rd bucket awards 1-4, which is 1.5-4.5 rounded down.

The OXC stat award code doesn't match the OG code. If you want the precise OG code, it's this:
Code: [Select]
exp = cur_unitref->MeleeAccuracy_exp_cnt;
 if ( exp )
  {
   if ( exp <= 10u )
    {
     if ( exp <= 5u )
       val = ( exp > 2u) + 1;
     else
       val = 3;
    }
   else
    {
     val = 4;
    }
   soldier_addr->ImproveMeleeAcc += val / 2 + xc_RandMod(val);
  }

Can you see the rounding error now?

Hmm. Is this problem something that can be solved with scripting right now?

Offline Meridian

  • Global Moderator
  • Commander
  • *****
  • Posts: 9415
    • View Profile
Re: [Suggestion] Primary stats award rounding
« Reply #3 on: March 12, 2025, 09:52:03 pm »
For primary stats, here's the decompiled example for firing accuracy:

Code: [Select]
              if ( soldier_addr->ImproveFireAcc + soldier_addr->BaseFireAcc < 120 )
              {
                v20 = v5->FireAccuracy_exp_cnt;
                if ( v20 )
                {
                  if ( (unsigned __int8)v20 <= 10u )
                  {
                    if ( (unsigned __int8)v20 <= 5u )
                      v21 = ((unsigned __int8)v20 > 2u) + 1;
                    else
                      v21 = 3;
                  }
                  else
                  {
                    v21 = 4;
                  }
                  soldier_addr->ImproveFireAcc += (_WORD)v21 / 2 + xc_RandMod(v21);
                }
              }

Same in a more human readable format:

Code: [Select]
bucket 4 (11+): 2 + rng(0, 4)
bucket 3 (6-10): 1 + rng(0, 3)
bucket 2 (3-5): 1 + rng(0, 2)
bucket 1 (1-2): 0 + rng(0, 1)

And OXC equivalent (100% matching OG):

Code: [Select]
int BattleUnit::improveStat(int exp) const
{
if      (exp > 10) return RNG::generate(2, 6);
else if (exp > 5)  return RNG::generate(1, 4);
else if (exp > 2)  return RNG::generate(1, 3);
else if (exp > 0)  return RNG::generate(0, 1);
else               return 0;
}

...
if (_exp.firing && stats->firing < caps.firing)
{
stats->firing += improveStat(_exp.firing);
}
...


There is no rounding error, it is a normal integer division.
« Last Edit: March 12, 2025, 09:54:03 pm by Meridian »

Offline Delian

  • Commander
  • *****
  • Posts: 658
    • View Profile
Re: [Suggestion] Primary stats award rounding
« Reply #4 on: March 12, 2025, 11:46:46 pm »
I'm not saying there's a bug in OXC or OXCE. I'm saying this was a bug in OG, which OXC copied. That integer division should've been a float division.

Let me explain. At some point the OG developers decided to add stat increases to the game. 1, 2, 3 or 4. See the variable v21? That was supposed to be the amount the stat increased. 1 exp -> 1 stat, 3 exp -> 2 stat, 6 exp -> 3 stat, 11 exp -> 4 stat. It's a simple formula with diminishing returns. But after testing, they got feedback that predictable increases felt a bit unrealistic, so later they added some RNG to it. They copied the same algorithm with integer division that they used in other places, like damage range. But this integer division, with its floor rounding, changed the average stat increase from [1.0, 2.0, 3.0, 4.0] to [0.5, 2.0, 2.5, 4.0]. The main problem here is that this change ruined the "diminishing returns" part. 1 exp -> 0.5 stats, 3 exp -> 2 stats. The 2nd bucket is more efficient than the 1st bucket? That makes no sense. This is why I'm convinced that the integer division is a bug in the OG and if the OG developers weren't in a rush to release the game and looked at this part of the code again, they would've noticed the problem and changed the floor to a precise round.

Anyway, I noticed that stat awards are scriptable, so it should be possible to check if exp falls in 1st or 3rd bucket, and add roll for 0-1 extra stats if it does, which would correct the diminishing rewards curve. I'll post it here once I figure it out.

Offline Meridian

  • Global Moderator
  • Commander
  • *****
  • Posts: 9415
    • View Profile
Re: [Suggestion] Primary stats award rounding
« Reply #5 on: March 12, 2025, 11:51:48 pm »
Maybe it happened the way you think, maybe not.
There's no way for me to know.