46
RGME Article #28: Hidden Albino Structures
cohost.orgI was replaying Super Mario Bros. 3 again recently and was trying to get all of the White Mushroom Houses to spawn. You need to collect a certain number of coins in certain levels to make one appear. I was curious how they were actually implemented in the game, so I had a little look. It's fairly straight forward, but there are a couple fun things about it that I figure I'd share.
Hello! You found my shop of strange and wonderful things! [https://rgmechex.com/articles/2023-09-25/img/toadhouse.png]Unlocking the White Mushroom Houses is way more exciting than getting the items they contain.
----------------------------------------
First, let me share what levels the White Mushroom House can spawn in, and how many coins you need to get each of them:
LevelCoins Required 1-444 2-230 3-844 4-224 5-528 6-778 7-246
My first assumption about how this system worked was this: after each level is completed, the game checks if the current level is in this list, and if it is, check if that number of coins were collected. If so, spawn the House. While it does check at the end of the level (as opposed to say, setting a flag the moment the last required coin is collected), the method it does so is a bit different.
The White Mushroom House check is actually built into a special sprite object. That is, it is stored within the level data along with other sprites, such as Goombas, Koopas, moving platforms, and so on. There is no hardcoded list of which levels can produce Houses, it's just that these are the only seven levels in the game that include this sprite. It's still by design that there's only one per world (and the item you get is based on what world you are in), but there's nothing in the game engine that prevents any level from producing a House.
Every sprite in the level data takes up three bytes worth of data: normally, its identifier (which kind of sprite it is), its X position within the level, and its Y position within the level. The White Mushroom House spawner sprite, being non-tangible and all, doesn't really need a position within the level to exist. So these two bytes are free to be used for whatever!
; PRG06, $C538: Level 1-1 sprite data
db $72, $0E, $19 ; goomba
db $A6, $16, $17 ; red fire piranha plant
db $72, $21, $19 ; goomba
db $6D, $24, $16 ; red koopa
db $72, $34, $18 ; goomba
db $72, $37, $18 ; goomba
db $73, $3B, $18 ; paragoomba
db $6E, $53, $13 ; green parakoopa
db $6E, $56, $13 ; green parakoopa
db $6E, $59, $13 ; green parakoopa
db $6C, $5C, $19 ; green koopa
db $A0, $70, $18 ; piranha plant
db $A4, $74, $17 ; green fire piranha plant
db $6D, $83, $17 ; red koopa
db $41, $A8, $15 ; end level card
db $FF
Due to how the sprite spawning algorithm works, it's important that each sprite has an X position, since this property is used to tell when sprites should spawn in the first place. But the Y position for this sprite is completely unused. Therefore, this sprite uses the byte meant for the Y position within the level to encode how many coins you need to make the House appear.
For example, in 1-4, the White Mushroom House spawner is the second sprite in the level's sprite data (the first being the autoscroll trigger). It's located at X position $01 in the level, and has a "Y position" of $2C. This is 44 in decimal, which is exactly how many coins you need to spawn the House!
; PRG06, $CC44: Level 1-4 sprite data
db $D3, $00, $00 ; autoscroller
db $D4, $01, $2C ; white mushroom house trigger
db $36, $17, $14 ; platform
db $36, $23, $16 ; platform
db $36, $25, $13 ; platform
db $36, $27, $19 ; platform
db $36, $2F, $15 ; platform
db $6D, $43, $15 ; red koopa
db $36, $44, $18 ; platform
db $36, $4B, $14 ; platform
db $36, $56, $16 ; platform
db $36, $58, $15 ; platform
db $36, $61, $13 ; platform
db $36, $6D, $18 ; platform
db $36, $6F, $15 ; platform
db $36, $70, $1A ; platform
db $6F, $75, $13 ; red parakoopa
db $6D, $7C, $16 ; red koopa
db $FF
If the "Y position" for the White Mushroom House sprite *were* treated like a real Y position, it would be way below the bottom of the screen.
----------------------------------------
But how does the sprite actually work? What does it do? Well there are three bytes in memory that are related to the White Mushroom House. The first is just the trigger flag. When this sprite is loaded, this flag gets set to 1. Otherwise it stays zero. This is what the game checks at the end of the level to see if it should even attempt to check for the coin requirement in the first place.
The second byte is the coin threshold. The "Y position" of the sprite gets copied to this memory location. It holds how many coins you need to get. Interestingly, this value is AND'd with $7F before the copy though, so the range of coins that can be specified for a House to spawn is only from 0 to 127.
The third byte is not used by the sprite, but at the check at the end of the level. It just keeps track of how many coins you have collected in this level alone. It gets compared to the coin threshold at the end of the level! This actually increments in every level regardless if the House sprite exists. It also overflows at 255 back to 0, so it is possible to collect "too many" coins and not have the House spawn, even if you get 256+ coins.
So when the sprite spawns, it sets the trigger flag and the coin threshold. Throughout the level, the coin counter goes up as you collect coins. Then at the end of the level, if the flag is not zero and the coin counter is greater or equal to the threshold, the White Mushroom House spawns! Easy enough.
A White Mushroom House appearing after Mario clears 1-4 [https://rgmechex.com/articles/2023-09-25/img/house.gif]The House will always spawn on the last map tile Mario was on (in other words, where he would respawn if he died).
(Side note: since the House sprite has to actually load in order for it to trigger, it is possible that the sprite could be placed in a sublevel, so that its effects only occur if Mario were to visit that area. The coin threshold can also be set to zero, meaning that there would be no coin requirement. Fun!)
----------------------------------------
Of course there's more to it though! Notice how I said the game checks if the trigger flag is not zero instead of just one. This flag can also be set to 2 to trigger a different effect, which was unused in the original game! When the flag is set to 2 and the coin threshold is met, the game spawns a White Airship on the map instead of a White Mushroom House.
A White Airship flying on top of the first fortress in world 1 [https://rgmechex.com/articles/2023-09-25/img/world1.png]This Airship uses the same graphics as the fast Airship autoscroller in world 8.
The Airship always spawns at the same location in the world map, whether there is a path there or not. Entering it just takes you straight to level 7-5 (the actual underground level part too, not the above ground entrance). Clearly this was meant to be some sort of secret level (perhaps only available in a certain world given the hardcoded position).
But how was it supposed to trigger the flag? Well actually, all of the code to trigger the White Airship is still in the game, but none of the levels actually use it. The lowest bit of the House spawner sprite's Y position is used to determine whether the sprite should spawn a White Mushroom House or White Airship. If the bit is 0, a House, if the bit is a 1, an Airship. Since this bit is also part of the coin threshold amount, this means that even numbered coin thresholds will spawn Houses, and odd numbered thresholds will spawn Airships. All of the spawner sprites in each of the seven levels that have one use an even coin threshold, which is why they only spawn Houses.
(It's possible that it was meant for the highest bit to be used instead, which is why the coin threshold is limited to 7 bits, but that's just a theory.)
----------------------------------------
Finally, I wanted to see how this changed in Super Mario All-Stars and Super Mario Advance 4. Well in Super Mario All-Stars, it's pretty much exactly the same. The only difference is that the White Airship is no longer white (and the White Mushroom House is now blue).
In Super Mario All-Stars, a Blue Mushroom House and normal brown Airship on the world 1 map [https://rgmechex.com/articles/2023-09-25/img/smas.png]They still spawn in the same places! The Airship's coordinates are well-defined; as in, the location it appears in is deliberate instead of being some glitched value.
Super Mario Advance 4 is a little bit more interesting. After you beat the game, you are allowed to go back to any world and play any of the levels again. Additionally, every level that can spawn a White Blue Mushroom House comes with a little coin block that lets you see exactly how many coins you need to make the House spawn (instead of it just being a secret).
Mario hitting the bonus coin block and the number 44 appearing at the bottom of the screen [https://rgmechex.com/articles/2023-09-25/img/sma4_coins.gif]This bonus block is actually based off of the similar item introduced into Super Mario Advance 2: Super Mario World. The bonuses in that game just give you a bunch of lives once you collect all of the coins.
I thought maybe that this sprite was the trigger sprite updated so that it actually appears in the level (after you beat the game). Which means that it has a defined X and Y position, and would need another way to keep track of the coin threshold. Well, each sprite in the level data does take up four bytes now, but that's likely just due to the architecture of the GameBoy Advance (ARM likes everything aligned to 4-byte offsets). However, the House trigger sprite is no different than before. The new coin block sprite is an additional sprite that was inserted into the level data. It doesn't set any special values or anything, it only looks at the coin threshold memory location, subtracts how many coins you've collected in the level, and displays the result.
; $08157AF0: Level 1-4 sprite data
db $01, $A7, $00, $00 ; autoscroller
db $01, $A8, $01, $2C ; white mushroom house trigger
db $00, $CD, $07, $12 ; bonus coin block
db $00, $36, $17, $14 ; platform
db $00, $36, $23, $16 ; platform
db $00, $36, $25, $13 ; platform
db $00, $36, $27, $19 ; platform
db $00, $36, $2F, $15 ; platform
db $00, $6D, $43, $15 ; red koopa
db $00, $36, $44, $18 ; platform
db $00, $36, $4B, $14 ; platform
db $00, $36, $56, $16 ; platform
db $00, $36, $58, $15 ; platform
db $00, $36, $61, $13 ; platform
db $00, $36, $6D, $18 ; platform
db $00, $36, $6F, $15 ; platform
db $00, $36, $70, $1A ; platform
db $00, $6F, $75, $13 ; red parakoopa
db $00, $6D, $7C, $16 ; red koopa
db $FF, $01
The Airship still spawns in this game too, though instead of going to 7-5, it just locks up the game instead. Fun!
Mario entering the Airship in world 5 and the game locks up on the MARIO START! screen [https://rgmechex.com/articles/2023-09-25/img/sma4_crash.gif]More investigation will be needed to figure out why this locks up.
----------------------------------------
You can support Retro Game Mechanics Explained on Patreon here [http://patreon.rgmechex.com]! Any and all support is greatly appreciated!
TL;DR:
You need to collect a certain number of coins in certain levels to make one appear (…), but there are a couple fun things about it
Wow, I never knew. That was so fascinating. Thank you for sharing!
Ditto! I’ve been playing with 8-bit assembly programming and it’s fascinating how this mechanic was implemented in just a couple bytes of level data.