"Cursed Balloons"
I have no idea if this has been posted before, so apologies if I'm sharing old info...
For all of my years playing this game, I've always wondered what's up with the balloons. Sometimes a guest will let go of one, and it'll float up into the sky... where you can click it to satisfyingly pop it.
...usually.
But once in a while, there's one- JUST ONE- that flat out refuses to pop. You click, it dodges your cursor. You click again, it dodges again. It's like this thing KNOWS you're trying to pop it and it's just gleefully rage-baiting you along. Ever since I was a kid, I've wondered: is this a bug? Is it intentional? Was it accidental behavior that Chris Sawyer just left in for laughs?? WHY??
While exploring the codebase this morning, I stumbled across this little gem... it's 100% intentional, and it's straight from Chris Sawyer's original code (OpenRCT2 ported it faithfully). Here's the actual function, Balloon::Press() (entity/Balloon.cpp:73):
void Balloon::Press()
{
if (popped != 1)
{
// There is a random chance that pressing the balloon will not pop it
// and instead shift it slightly
uint32_t random = ScenarioRand();
if ((id.ToUnderlying() & 7) || (random & 0xFFFF) < 0x2000)
{
Pop(true);
}
else
{
int16_t shift = ((random & 0x80000000) ? -6 : 6);
moveTo({ x + shift, y, z });
}
}
}
There's even a comment spelling it out. But the mechanism is the beautiful part, and it's hilariously sneaky:
The dodge is keyed to the balloon's identity, NOT the click!
The pop condition is (id & 7) || (random & 0xFFFF) < 0x2000. Read that as two kinds of balloon:
- id & 7 != 0 → 7 out of 8 balloons. The first term is already true, the || short-circuits, and it pops on the very first click, guaranteed, forever. These balloons can never dodge.
- id & 7 == 0 → 1 out of 8 balloons (the ones whose entity sprite-index happens to be a multiple of 8). For these, the first term is false, so it falls through to the coin flip: (random & 0xFFFF) < 0x2000 is 8192 / 65536 = 1/8. So a "cursed" balloon has only a 1-in-8 chance to pop on each click, meaning it dodges 7 out of 8 clicks.
So it's not that any balloon randomly resists sometimes. A balloon is born either instantly-poppable or stubborn, decided by which entity slot it got allocated (its id). The stubborn one will fight you every single time you meet it; because you're not up against a 5% fluke, you're up against a 1/8-per-click coin that keeps landing the wrong way!
When it resists, moveTo({ x + shift, y, z }) literally jumps it ±6 units sideways (the sign is pulled from the random's high bit). So it doesn't just refuse... it hops left or right out from under your pointer. Combine that with Balloon::Update() drifting it up a step every 3 ticks, and a cursed balloon you can't land your 1/8 on will jitter sideways and float off the top of the map (z >= maxZ → Pop(true)) before you ever get it, escaping clean.
For a stubborn balloon, pop-chance is 1/8 per click → a geometric distribution with expected 8 clicks, but a fat tail: getting 15–20 dodges in a row is entirely normal. That's exactly the "click over and over and it keeps dodging" experience.
So: not a bug that survived, not an accident... it's a deliberate little cruelty Sawyer baked in, preserved bit-for-bit ~30 years later. Some balloons are just built to get away :) 🎈