smogon / pokemon-showdown

Pokémon battle simulator.
https://pokemonshowdown.com
MIT License
4.71k stars 2.75k forks source link

GSC spikes faint bug #6162

Open FredrIQ opened 4 years ago

FredrIQ commented 4 years ago

I don't know how accurate PS tries to be to cartridge, but I think this bug, discovered just now by me, @Rangi42 and @itsdarsh during development of a ROMhack, might be of some interest.

In certain circumstances in GSC, a Pokémon who switched into Spikes and then immediately fainted may still be active in battle. This is because GSC doesn't force a switch-in loop as a result of a Spikes faint, so it will only try so many times until the game ends up in the main loop during move selection again.

The easiest way to reproduce this is to have a Pokémon faint due to Perish Song, and then switch into something that faints to Spikes. The post-Perish Song faint check is the very last check done before the game ends up back in move selection again.

See this for context: https://github.com/pret/pokecrystal/blob/master/engine/battle/core.asm#L249

Zarel commented 4 years ago

Interesting. Do you have a YouTube video of this behavior?

itsdarsh commented 4 years ago

Here's a video, glitch begins at 1:25: https://www.youtube.com/watch?v=1IiPWw5fMf8

The video is on an emulator and more info is in the description but the easiest way to replicate this in-game is by challenging Koga with a Misdreavus that knows Perish song (and presumably can take on Will and Koga's first few pokemon) and a second Pokemon in a party with less than 1/8 of its HP remaining.

FredrIQ commented 4 years ago

Ok, so here is GSC's endturn sequence. Note that the side order depends on who is the host, not Speed like later generations. Host goes first, then client:

Each "faint checks" pass will check first if the host is fainted, then if the client is, fainting them in turn (host, then client) if appropriate. If both fainted their last Pokémon, the host is declared the loser (similar to current gen except it doesn't use Speed checks to see who to proc first). If then prompts for the host to switch in a new mon, then the client. This is where the bug is -- if the switched in Pokémon faints (again), it will not restart the process. Instead it will simply go to the next endturn action as if the new mon didn't faint to Spikes. This is harmless (Future Sight and Sandstorm might hit fainted Pokémon, but nothing actually goes wrong here beyond that), except that if this happened after the last checkfaint pass, the side in question will be left with fainted Pokémon after the end of the turn is complete who will last until the next time the game process faint checks (generally after an used move).