#11408·wesnoth

#11311 changed the Reduced RNG semantics skewing chances

Author: DiscontinuumCreated Jul 22, 2026Updated Sep 16, 2026
LabelsBugBlocker: New StableEngineBlocker: Point

Reduced RNG used to work in the following way (code in, for example, current 1.18 https://github.com/wesnoth/wesnoth/blob/92ed54d4b552a66e3b9cde2a470487b020bd1841/src/actions/attack.cpp#L973):

Before the start we calculate the expected value EXP = cth * attacks. Then we guarantee int(EXP) strikes and make a coinflip with chance fractional_part(EXP) = EXP - int(EXP) for an extra strike. The order of hits and misses is random.

So a Dark Adept has 0.7 * 2 = 1.4 expected value of hits, so it gets 1 hit guaranteed and 1 more with 0.4 probability ( 40% chance).

This semantics reduces randomness to one strike (or zero, if the fractional part is zero) and respects the expected value (it's the same as in the standard RNG, 1.4 in the case of Dark Adept). One little shortcoming of it is that it doesn't really work with rare abilities that change chance-to-hit mid-attack: the calculation of the number of hits and misses is made before the start of the attack as a whole, so these abilities just have no effect).

#11311 was intended to fix that, but it uses a completely different semantics compared to what it used to be, and my calculations and demos show that it's not equivalent to what it used to be for generic units without such weird abilities.

https://github.com/Discontinuum/BiasedRNGTest Here's a test addon with a campaign, in which Dark Adept attacks a wose 10k times (turn off "Show Combat" in Preferences > Advanced to not wait animations forever).

Running it in Biased RNG in 1.18.5 shows this:

Image

And in 1.19.25 ( 10bd5f8ab27bd2470b1b66ec7f5ec22c3d90afa5) it shows this

Image

My pen-on-paper calculation of odds for Dark Adept with the new code gives:

  • 0 hits - 0
  • 1 hits - 0.3 + 0.7 * 0.6 = 0.72
  • 2 hits - 0.7 * 0.4 = 0.28
  • EV = 0.72 * 1 + 0.28 * 2 = 1.28

compared to

with regular RNG:

  • 0 hits - 0.09
  • 1 hit - 0.42
  • 2 hits - 0.49
  • EV = 1.4

with Reduced RNG as before:

  • 0 hits - 0
  • 1 hit - 0.6
  • 2 hits - 0.4
  • EV = 1.4

I think it wasn't really intended and now I can't reasonably explain and calculate how new Reduced RNG works