546 - bombShield(int a, int script)


Sets the bomb invulnerability flag (a=0 false, a=1 true), the caller's ANM script will change to script when a bomb is active.

Point Item Value Overflow Glitch


Specifications


  • Versions: 1.00a
  • Difficulty: Easy - Normal - Hard - Lunatic - Extra
  • Mode: Main game - Practice mode - Spell practice
  • Shottype: Reimu - Marisa

What happens


The Point Item Value (PIV) is the value used for representing the score value of a Point Item at its maximum value. The PIV is also known as the "Incident Value" in this game, but for simplicity it will be called PIV. This value can range from 0.00 to 200.00.

When the PIV is within [42.95; 85.4] or [128.85; 171.30], the score obtained from collecting a point item will be exactly 10 score. This bug cannot be avoided without the use of any third party tools.

A screenshot showing a bugged value
Figure 1: Screenshot showing a bugged PIV value of 65.70

How it happens


To replicate this bug, simply play the game until your PIV is within [42.95; 85.4] or [128.85; 171.30]. This bug also exists in replays, meaning if you watch a replay that has a PIV within the bugged range any point items will give 10 score.

Why it happens


Within th20.exe, the PIV value is not stored as a value between [0.00; 200.00]. Instead, the PIV is stored as a value between [0; 1,000,000], which I will call the internal PIV. The value that you are seeing on the side is equal to the internal PIV divided by 5,000.

The point item score calculation uses the internal PIV value. The game calculates a point item's score as follows:

item_score = (piv * 10000) / 5000 + 10000 / 2 // if simplified it becomes "item_score = 2 * piv + 5000"
item_score = truncate_to_nearest_ten(item_score)
if (item_score <= 0) {
    item_score = 10
}

For example, if your PIV is 161,803, then item_score is 328,600. If your PIV is 271,828, then item_score should be 548,650, but instead we get a value of 10 meaning that item_score somehow had less than a 1 score. The reason why the if-condition is met is because there is an overflow happening.

Integer overflow


A 32-bit signed integer uses 32 bits to represent integers with one bit reserved for the sign (positive or negative). The value range is [-2,147,483,648; 2,147,483,647]. When a 32-bit signed integer exceeds its maximum value (2,147,483,647), it wraps around due to fixed bit width. For example, adding 1 to 2,147,483,647 results in −2,147,483,648 (this behavior is defined by two's complement arithmetic, which is the standard method for representing signed integers in most computing systems).

The issue arises in the line item_score = (piv * 10000) / 5000 + 10000 / 2, or more specifically, piv * 10000

Let's take the example of piv = 271828. If the game runs this calculation, we get the following result:

piv * 10000 = 271828 * 10000 = -1576687296 (overflowed value of 2718280000)

Continuing the item_score = (piv * 10000) / 5000 + 10000 / 2 calculation results in a negative item_score value, meaning its final value becomes 10 score.

Earlier I stated that this bug happens in the PIV ranges [42.95, 85.4] or [128.85, 171.30]. If we convert the PIV ranges to the internal PIV ranges we obtain [214750, 427000] or [644250, 856500], which checks out with the item score calculation.

Chart


Below a chart is depicted comparing the bugged PIV with the intended PIV.

A plot comparing the bugged PIV value to the intended PIV value
Figure 2: A plot with lines plotting the bugged PIV value and the intended PIV value. The inflection points are at 42.95, 85.4, 128,85, and 171,30. It is clear that this bug reduces the amount of score gained, especially at very high PIV. For example, at the maximum PIV the bugged value gets 7.5x less score than the intended value.


Replays


This section has no content yet. Would you like to add to this section? Contact me if you are interested!

Videos


This section has no content yet. Would you like to add to this section? Contact me if you are interested!

Other