I am currently developing my second PICO-8 game. I'm considering adding an option to load my first game directly from the new cart, if the player wants to give it a try.
Both games are single carts, and there is no sort of communication between them. It's a simple load call with a breadcrumb parameter.
I was concerned about cartdata though. Both games use cartdata to store progress, each using its own ID. And the PICO-8 User Manual states, in section 6.11, that "CARTDATA can be called once per cartridge execution".
The wording on the manual indicates that my approach was OK, but I decided to test it anyway, just to make sure.
Only once
First, I simply called cartdata twice to see how PICO-8 would enforce the single call.
cartdata("test_load_1") cartdata("test_load_2") |
This is the error message:

Simulating carts
I created two simple test carts. Below is the code for test_load_1.p8, which simulates cartdata and load behaviour in my new game.
function _init() cartdata("test_load_1") n = peek(0x5e00) end function _update() if btnp(4) then n += 1 if (n > 9) n = 1 poke(0x5e00,n) end if btnp(5) then load("test_load_2","load test_load_1") end end function _draw() cls() color(7) print("test_load_1 - n = "..n) print("") print("press 🅾️ to add 1 to n (max 9)") print("") print("press ❎ to load test_load_2") end |
There is a vaiable, n, that starts at 0 if there is no save data. You press 🅾️ to increment it by 1 (up to 9, then it loops back to 1). Whenever you do that, the new value is persistent in cartdata (ID = "test_load_1").
You press ❎ to load test_load_2.p8, which simulates cartdata behaviour in my old game. The code for that follows below.
function _init() cartdata("test_load_2") n = peek(0x5e00) end function _update() if btnp(4) then n += 10 if (n > 90) n = 10 poke(0x5e00,n) end end function _draw() cls() color(7) print("test_load_2 - n = "..n) print("") print("press 🅾️ to add 10 to n (max 90)") print("") print("use pause menu to go back") end |
Here you press 🅾️ to increment n by 10 (up to 90, then it loops back to 10). Whenever you do that, the new value is persistent in cartdata (ID = "test_load_2").
To go back to test_load_1, you must use the last option in the pause menu to follow the breadcrumb.

Results
There were no surprises in my tests. Both carts were able to update their save data independently, no matter how many times I switched back and forth between them. I even checked the .txt files in pico-8\cdata and everything was properly persisted.
This may seem obvious and unnecessary, but I just wanted to make sure before implementing the feature in my new game. I searched the forums and couldn't find a definitive answer, so I decided to test for myself.
I made this post hoping this might be useful for someone. Happy coding!



Interesting read.
I'd like to add another related trick I found :
you can call
cartdata(game1)
then
extcmd("reset")
then peek the data into variables (not dget since cartdata hasn't been called yet in the current execution), and finally call
cartdata(game2)
This allows things like special unlocks in game2 based on your accomplishments in game1.
To know where you are in the sequence, you can poke the step number in high memory. Like the cartdata memory space, high memory isn't cleared when you call extcmd("reset")



Wow, neat, @RealShadowCaster !
This allows things like special unlocks in game2 based on your accomplishments in game1.
I hadn't thought about that possibility! Will definitely consider if I ever make a sequel to either game (my two games are completely unrelated).
I assumed extcmd()
would be unsupported when running carts in certain situations (like BBS or HTML export). I'd better read that section of the manual again, paying more attention...
Thanks for the tip!
[Please log in to post a comment]