I'm not really sure how NES games were coded, whether threads played a role in them or not, and how those threads were handled. The hope is threads could be understood, and by exploiting them the game's natural boundaries could be broken.
No surprise I was playing Zelda 1 when the thought occurred to me. A rare event occurred. An enemy-bomb drop landed on the very tile of the room-placed item drop of bombs in Level 2, (right before the Dodongo). I like to leave that room-placed item drop there, so I could return to it if I was wasteful with bombs when fighting the Dodongo. (I chose to collect the enemy drop before finishing the rest of the enemies for the room drop to appear, but that's besides the point. As a further aside, room-items are slightly different. For one thing, it is preserved even when you leave the room, and you can only get it once. Also, you cannot pick it up with the boomerang.)
Anyway, the general gist of my thoughts were to make bombs drop on each other, or close enough to each other, such that exploiting threading could somehow yield a bomb count greater than the games imposed limit. (8, before upgrades. 12 and 16 after upgrades.)
If the bomb increment goes something like this...
onBombDropPickUp()
{
1. if(bombCount + 4 <= bombLimit)
2. bombCount += 4;
3. else
4. bombCount = bombLimit;
}
then hopefully, suppose you have 3 bombs, by making two threads, timed to switch focus correctly, both threads could be at statement 2, before they finish executing, leaving the player with 11 bombs.
However, if it was programmed more like this:
onBombDropPickUp()
{
1. bombCount += 4;
2. if(bombCount > bombLimit)
3. bombCount = bombLimit;
}
Then it seems the bomb quantity will be checked at the very end, making the check avoidance through thread exploitation... less visibly likely.
Anything worth considering here?
The NES would not have had threads. They could be faked with cooperative threading (more commonly known as coroutines) but no programmer in his right mind would put a yield() right in the middle of critical code. Then again we do have wall jumps.
The NES does have interrupts, which is about as close as you can get. In fact, this is how Mega Man 2's horizontal scrolling bug works. There's something of a race condition when the vertical interrupt NMI goes off the the middle of code.
I read about coroutines, NMI, and the Mega Man 2 scrolling glitch. That NMI stuff seems advanced. I hope I'm not asking something obvious here, but how can we know when such interrupts occur, and whether they could be advantageous?
The vertical sync interrupt occurs 60 times per second (50 on PAL) and will only really cut through running code if the game lags. That's pretty much the definition of lag around here. For anything beyond that, talk to someone who writes emulators.
On the PC end, this is why they invented valgrind.
As far as my knowledge goes, MM2's exploit is the exception, not the rule. Most games seem to be more than capable enough of managing interrupts.
Also, generally, many games will do a value check when adding:
if (value + bonus > max) value = max
The gist of it is that none of the early systems have threading (Genesis, NES, SNES) so your examples are not valid for those, don't bother. The best you're going to get is interrupts (as per DeHackEd) and even then more than likely the game is able to handle those. Sorry, but this idea isn't going anywhere for 99.99% of the games out there.
On the SNES, many RPGs work by interpreting a kind of an object-oriented bytecode on each actor of the scene; those bytecodes are run in cooperative threading mode. I.e. the bytecode contains a variety of Yield opcodes, which will transfer the execution to other actors. (I am talking about Chrono Trigger, but I have heard that CT's approach is very common in RPGs.) In addition, the bytecode interpreter only executes a certain number of opcodes in a row for the given actor, forcing a taskswitch once in a while. I don't remember whether NMI also forces a taskswitch.
However, there is no taskswitching for native code; only for bytecode.