Feb 23, 2021

Axe Armor in CV3 had FATAL Logic

This isn't a significant post, but if anyone reading this is actually planning on using the original game code, at least in the Japanese version (I haven't verified if this bug was retained in the US version), it is worth noting. Also, I do have some "good" info about Axe Armors at the end. I've taken to task rewriting my CV3 enemy codes from scratch in order to match the original code structure. In doing so, I noticed something in the Axe Armor code that I had missed in my original draft(s). 

The original code stores the ID of the axe inside the same variable that tracks the state of the throwing animation. Instance IDs are reused and axes are allowed to spawn with any available ID. This has two perks: it's nearly impossible for an axe not to spawn and you can have up to 11 axes on-screen at a time (ignoring sprite flickering, more on this later).

NEARLY impossible. Anyone astute in enemy placement and manipulating the game code (through ReVamp, for example), coupled with a gamer who doesn't kill anything for some reason, could potentially create a scenario in which 12 enemies and their projectiles are on screen at the exact moment an Axe Armor tries to throw an axe.

Normally, when an axe is thrown, the ID of the axe is stored temporarily in byte $0008, then byte $0008 & #0f is saved to the Axe Armor. Byte $0008 is frequently used as a temp variable in many other routines, thus if no axe was thrown, $0008 is for all intents and purposes a random value. From that point until the next attempt to throw another axe, everything is an axe to that Axe Armor.

What does it mean to be an axe? The Axe Armor will not throw a new axe until the axe with the saved ID is gone; if the axe is another enemy, the Axe Armor will not throw a new axe until that enemy is destroyed off-screen or killed. More importantly, an Axe Armor will instantly destroy the axe with the saved ID when the axe's x-coordinate is within 4 pixels of the Armor; if the saved ID is another enemy, the Axe Armor will destroy that enemy as soon as it is within 4 pixels horizontally. Or worse yet, if the saved ID points right back to the Axe Armor itself, it will commit suicide.

The player can be affected by this as well, assuming $0008 has a value like #10, #20, #30, etc. The player won't actually be destroyed, since the Axe Armor simply sets the axe's object_index to 0, effectively removing it from the room; for the player, object_index 0 is Trevor. Unfortunately, if memory serves, the allies have an object_index other than 0, so an ally coming within 4 pixels of the Armor horizontally would be instantly reverted to Trevor. Since this only affects the object_index and not the swap flag, the player would have to swap characters twice in order to get back to the ally. Maybe I'm mistaken about this and the player is completely unphased.


Now for the "good" info. Like I said, the Axe Armor will only throw a new axe if the axe with the saved ID has been destroyed (either by the player, the Armor, or moving off-screen). If you wanted, with some simple code rework, you could adjust the value of the saved ID. If the saved ID no longer points to a valid instance, the Axe Armor will throw a new axe. Unfortunately, this has one small drawback: the axe will never be destroyed by the Armor (unless the saved ID becomes the ID of the axe). What happens when an axe doesn't get destroyed? It just keeps looping around the room indefinitely. I'm sure someone out there can find a way to have fun with that.

©TheouAegis Productions™. Powered by Blogger.