Uncompressed Source Code: https://paste.ee/p/5KOG5 (warning: it's pretty gross)
Late last year (2017) I started work on a port of Super Mario Bros [NES] to Pico-8. The goal was to be authentic as possible to the original game, while working within the Pico-8 limitations. Something like Super Mario Bros Deluxe [GBC] (https://www.mariowiki.com/Super_Mario_Bros._Deluxe).
In the end I was able to get 1-1 and 1-2 mostly complete before starting to hit serious memory limits which make it seem near impossible to ship the full game.
With that in mind, I'm releasing it as-is for now so that people can check it out and see where it was headed.
If you are curious, the biggest factor for memory is the level data which is quite huge. At some point I'd like to document how my level authoring process worked, but for now you can check out this twitter thread of me slowly wittling down the level data size:
Update: I have managed to squeeze in all for World 1 now!
Music by: https://twitter.com/gruber_music
I'm not sure if you're already doing this or not, but as for level data goes in a mario game. It seems reasonable that you could just need to have the floor be a solid rectangle of tiles, so basically the only info you need is the tile type and then the location of the pits, which you just cut out. Then all that's just is the location of objects. It would be reasonable to assume you're already doing it this way. I haven't taken a look, but if you ever wanna bounce ideas on reducing data size, hit me up. I love that stuff. Maybe we could work out something cool.
Really good job! Never played it on actual hardware but this works quite well. I don't remember goombas chasing you though.
P.S. If you released multiple cartridges on the same thread with different level data, you might be able to do all the levels. I don't know how well it would work, but it is an idea.
Trying out your MARIO, MH. Spot on graphics and feel.
I noticed when you are on a pipe, in the original game if you press down, Mario will crouch down. Does not do that in here - if you're going for authenticity. And - no castle to enter at the end of the level ?
Marvelous work what I've seen so far.
Run Length was my first idea but then when I got to thinking about how the floors are in mario levels, it made more sense to just have teh floor be a constant repeated single tile so no data is needed except for the type of tile and the location of pits. Then for other objects or groups there of you could story their values and positions and have a lot less data on your hands and then frmo there you could FURTHER compress with some RLE stuff.
@hw2002: The goombas don't chase you. They just walk forward and change direction when they hit stuff.
Releasing multiple carts is probably how I would do it. I can fit about 10 levels per cart right now but there are still some additional objects to implement which may reduce that number.
I'm not sure about going back to Mushroom when you get hit. I thought I checked what the original did and copied that but I might be mistaken. Confirmed: Mario always returns to small Mario when hit by an enemy in the original game.
@dw817: Thanks! You are correct. Duck and end castles are 2 things I cut for space.
@Cabledragon: if I come back to the project I probably give that repeating floor idea a try to see how it affects memory and token counts.
IIRC the original SMB game uses a "templating" strategy for its levels: the tile data is defined as large objects like "pipe", "stairs", etc. and then pasted into the scene at the appropriate x scroll position. The levels are actually tiny when using that strategy since so much template content gets shared, and it explains the existence of the "minus world" and similar invalid yet playable levels.
However, the original cart is also 256kb so that probably still won't get you to the full game.
Edit: Actually, it's 32kb so maybe? SMB3 was 256kb.
@triplefox: yes, the compression on Super Mario is like that but even more complex. The X,Y coordinate of the object also defines the object type, and what all the bits mean.
So an object of Type 1 at Y position 0 might be a coin, but object of Type 1 at Y position 32 might be a flag pole. It's all very clever and based on all the mutually exclusive information the designers knew about the game (eg. you can't place a coin below the floor, so we can use that limitation to say "coin below floor" means "flag pole" and flag poles are always at the same y position so we can ignore the fact that it is positioned below the floor).
It goes a step further to break up the meaning of each bit of the object such that the first few are the page, the next few are position on that page, and then the last few can mean different stuff depending on the object type.
I did dig into that quite a bit and implemented a first pass. It saved good chunk of compressed memory, but added a huge amount of tokens to handle all those cases. It was pretty neat though: being about the copy raw Hex data out of the ROM, and into Pico-8, and see it load the level. :)
@mhugson I have a working version that use my good ol' json parser. It clocks at ~7300 tokens (started from the pastebin version).
note: I didn't dig too much into it, but the whole hex to map thing could eventually be replaced by a json number array + RLE encoding (as the json parser already supports hex&number string to values)
Hi Matt, really enjoyed playing this. I appreciate the design choices you have made, particularly the white look-out circles, and the sound effects (I think the shell kicking sound is more similar to the later games?). Here are a few of things I noticed that seem out-of-place:
- At the end of the level intro, there is a frame displaying the actual level in the wrong place
- The mushroom/fireflower blocks yield a coin if you hit them again (I quite like this one!)
- Mario's collision dimensions are larger than the original game (in SMB Small Mario is 12x12px, not sure about Super Mario, maybe 12x24px)
- The small coin at the top is distorted (sspr?)
- The controls are inverted (may be a matter of preference, but on my 360 pad, I expect the bottom face-button to jump)
Really impressed at how faithful this recreation is.
@Lafolie: Thanks for the thoughtful critique!
"At the end of the level intro, there is a frame displaying the actual level in the wrong place"
Yah, I know what you're talking about. Looks like a frame hitch while it loads the level or something. I'll get to it some day... :)
"The mushroom/fireflower blocks yield a coin if you hit them again (I quite like this one!)"
A bug for sure, but I like it, so I think I will keep it!
"Mario's collision dimensions are larger than the original game (in SMB Small Mario is 12x12px, not sure about Super Mario, maybe 12x24px)"
I'll need to double check but I thought I made sure this was accurate to the original.
"The small coin at the top is distorted (sspr?)"
Yup, it is the regular coin scaled down with sspr. Gotta save sprite memory wherever I can!
"The controls are inverted (may be a matter of preference, but on my 360 pad, I expect the bottom face-button to jump)"
I use "A" and "B" which is correct, but if you use "X" and "A" it's backwards. I'd like to do some so of key config if possible. But i'm sure i won't have the tokens for it!
WORLD 1 IS COMPLETE!
The latest version of the game now includes:
- All 4 levels of World 1
- All enemies of World 1 (incl. Bowser!)
- All Power-ups!
I had to remove some features to fit it all in, but I think it feel pretty complete at this point.
Give it a play-through, and let me know what you think!
[Please log in to post a comment]