I joined the itch.io 'Secret Santa Jam' this year, where you get anonymously paired with a random stranger and create a small game for them based on a letter about their interests.
Part of my giftee's prompt was "I like playing games that make me think and involve some kind of strategy e.g. card games like Magic the Gathering [...] I am a huge football fan. I support Manchester United in England and Borussia Dortmund in Germany. I have a rubbish Windows laptop, so any game that can run in browser works best for me.".
I let inspiration guide me from there and here's the small puzzle / tactics game I came up with.
Sadly, there are no sound effects or background music as I ran out of time and wanted to ensure I gave them something playable by the deadline, but maybe I'll come back to it some day...
p.s. I used this free pack of 16x16 sprites as a starting point for the character sprites and animations: https://route1rodent.itch.io/16x16-rpg-character-sprite-sheet, thanks!
I was editing a new cart (no code, only SFX) yesterday for an hour or two, and saved it a handful of times along the way. Then PICO-8 (0.2.4) hard-crashed and popped up the Mac "an application has stopped" window. I think it hard-crashed the moment I hit Cmd-S to save the cart again, but I'm not 100% sure.
These things happen, that's why I save regularly-- but when I went to reload the program, I discovered the .p8 file on disk was now 0 bytes / empty (with a timestamp matching the crash time) which was more concerning. And there were no backups of this cart in the backups/ folder.
Here's some text from the Mac (OS 11.6) crash notification that sounds relevant (I can copy the full text somewhere if that's useful, or let me know if there's any other info I could provide):
Crashed Thread: 0 Dispatch queue: com.apple.main-thread
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x00000011cf9d7620
Exception Note: EXC_CORPSE_NOTIFY
Termination Signal: Segmentation fault: 11
Termination Reason: Namespace SIGNAL, Code 0xb
Terminating Process: exc handler 
VM Regions Near 0x11cf9d7620:
mapped file 11423e000-11483e000 [ 6144K] rw-/rwx SM=COW Object_id=7ba0bc93
MALLOC_NANO 600000000000-600008000000 [128.0M] rw-/rwx SM=PRV
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 com.lexaloffle.pico8 0x000000010b7fb354 codo_save_pico8_cart_to_file + 292
1 com.lexaloffle.pico8 0x000000010b7fc147 codo_save_pico8_cart + 55
2 com.lexaloffle.pico8 0x000000010b71cd4a save_working_cart + 954
3 com.lexaloffle.pico8 0x000000010b71e59b do_quick_save + 155
4 com.lexaloffle.pico8 0x000000010b7691d6 process_editor_keypresses + 982
5 com.lexaloffle.pico8 0x000000010b71a89f codo_main_update + 3007
6 com.lexaloffle.pico8 0x000000010b7b00ae codo_main + 366
7 com.lexaloffle.pico8 0x000000010b70fb94 start + 52
Usage (requires keyboard): Type text including control codes (\n, \f, \^, #, and more) live in your terminal and see the result displayed on screen...
You could also just edit a print() statement in a dummy cart and reload... but there's something about being able to edit color/spacing/etc 'live', especially for codes like + and \^v that can take a lot of trial-and-error tweaking.
In the comments below I have a larger utility cart version of this that includes help, save/load/export, and so on. But this first post is trying to pack a subset of that into 560 characters for TweetTweetJam.
p.s. The tweetcart it doesn't quite support all the P8SCII codes (no \a, |, -, and likely more), but the full cart in the comments supports most of them (still not \a).
[updated from WIP post]
I saw the announcement for this week's TweetTweetJam #7 and here's a barely-roguelike in 560 characters.
Feedback, or suggestions for other character shaving welcome!
- Use arrow keys and try to get as high a score or level as possible (my personal records are 140 points and level 8, but it's hard)
- Hitting two arrow keys at once lets you move diagonally (but requires some skill+luck on a keyboard!)
- Every heart (♥) you collect raises your score
- Every step you take or spike (∧) you step on lowers your score
- The house (⌂) transports you to a new more challenging level (and raises your score)
- The game ends if you are eaten by the dragon(🐱) or your score drops to 0...
- To restart the game you'll need to reload
Note: the game is definitely unfair in that it can generate a level where it's impossible to reach the goal or avoid the dragon (though note the diagonal-move trick above) and you'll have to reload and try again.
If I find time I will come back to it based on @dw817's comment below and figure out if I can cut some functionality (maybe level progression) and add in a way to organically generate a known-solvable map layout.
side note: I had a question about flip() but couldn't reproduce it, so removed it
PICOhaven is a tactical card-based dungeon crawler / light solo RPG for PICO-8, inspired by the board game Gloomhaven. It adopts a modified & simplified version of the mechanics used in that game, to fit within constraints of the PICO-8 environment (code size, resolution, etc), and to streamline solo play.
The story includes 16 playable scenarios (some are optional side quests), 8 levels of ability upgrade choices, and multiple items that also affect gameplay.
Note: This is just a free, solo-fan-made project and has no affiliation with Gloomhaven. If you like this type of game I recommend checking out Gloomhaven (and its official video game adaptation) for a game with a lot of tactical depth from multi-character cooperative play!
Play PICOhaven here: (desktop or mobile)
Quick Gameplay Overview
(for those who like to jump straight in and figure it out as you go)
- Use the arrow keys and the 🅾️ button ('Z' if using a keyboard) to explore, select cards, and fight.
- The other button occasionally used is ❎ ('X' on a keyboard) to cancel/undo.
- Defeat all enemies to advance the story and unlock new scenarios, as well as upgrades to your ability and modifier decks.
- You are 'exhausted' and fail a scenario if you take too much damage, or if your deck runs out of cards (each time you've played all the cards in your deck you reshuffle them, but a random card is 'burned' and not available for the rest of the scenario).
- If you would take fatal damage but have cards in hand, you will instead 'burn' a random card to block the damage, but beware: this shrinks your deck so you'll have limited turns left to win the scenario before becoming exhausted.
- The game should automatically save your progress after each scenario, success or failure, allowing you to come back to it later on the same device (you can retry the same scenario multiple times and earn XP even on failure).
- If you're not sure what happened in combat because a lot of text scrolled by quickly, at the end of any round you can press ❎ to scroll back through the message log.
- Let me know what you think, and if you run into any issues or questions...
How-To-Play, with screenshots
PICOhaven is a tactical turn-based dungeon crawler / light RPG. You win each scenario and unlock new ones by defeating all enemies in all rooms (unless otherwise specified) before you are exhausted.
PICOhaven is card-based in that at the beginning of each round, you choose two action cards you'll use. These include Movement, Attacks, and other actions:
After you select your cards, enemies will draw random action cards, and you will see an overview of what each character will do that round (the white numbers indicate the initiative: characters with lower numbers will act earlier).
When it is your turn, you get to play these two actions (in either order)... or instead use either of them as a default "move 2" or "attack 2" action if that's more useful.
At the end of the round, you discard those two action cards, and will have to choose different actions the next turn. When you've played through your entire deck, you will automatically 'short rest': you redraw your discard pile but randomly burn one of those cards, meaning you can no longer use it during this scenario. This means you have a finite number of rounds of play before your deck runs out of cards. Some more powerful cards are burned rather than discarded when you play them, so they can only be used once per scenario.
You become exhausted and lose a scenario if you either run out of health (HP), or if you run out of cards in your deck.
At the end of each scenario (success or failure), you return to town and all of your cards, HP, and items are restored, in preparation for your next adventure-- you can try any scenario as many times as needed. The game should automatically save your progress each time you return to town and allow you to return to it later (on the same device/browser-- data is saved locally).
See the next section for some additional details...
More Details on How-To-Play
You will discover additional details, special cards, powers, items, and rules by playing, but a few other notable rules:
You open a door by ending your movement on it. Monsters revealed in the next room will not act until the next round.
- Your initiative in each round (how early or late you act relative to the monsters) is set by the initiative value of the first of the two cards you selected before the round (shown in a circle in the upper right corner of the card in the card-selection screen):
So even once you know what two cards you want to play this round, by choosing which card you select first in that 'choose cards' view, you can choose whether you will act earlier or later in the round. When your turn comes in the round, you can still choose to play those cards (or the default move 2 / attack 2 actions) in any order.
A "burn when used" card is only burned if you actually play it. If you select it as one of your two cards for the round, but when your turn comes you use a default Move 2 / Attack 2 action instead of playing it, that card is only discarded, and you'll have another chance to use it the next time you redraw your hand.
You collect treasure or coins by ending the turn on them (or by using certain cards or items). You do not need to collect treasure (and rarely will have enough time to collect all of it without running out of cards and failing a scenario), but it will eventually allow you to buy items that enhance your powers. Note that once you defeat the last enemy in a scenario (or achieve some other special scenario objective) the scenario is over and you return to town, so if you want to pick up treasure you have to do it before completing the scenario... that may not make sense fantasy-dungeon thematically :), but the game's balanced around only being able to afford a few items over the course of the entire campaign.
- Whenever you attack, you draw a random modifier card from your deck of modifiers which is applied to the damage from your attack card. Most modifiers are -1, +0, or +1, but there are some that are larger, including a "*2" and a "/2". When you first get to town, try "View Profile" to see your current modifier deck. You'll have opportunities to upgrade this deck over the course of the campaign, whether that's by removing negative modifiers or adding additional positive modifier cards.
Enemies do not have modifier decks and always do the damage shown on their card for the round.
If you would take damage that would reduce you to 0hp, you will instead randomly burn a card from your deck to negate that damage, though this reduces the number of rounds you have until you are exhausted by running out of cards. If you have no cards in your hand (i.e. all of them are already discarded or burned) when you are reduced to 0hp, you cannot burn a card and are exhausted as above.
There are a few special conditions that attacks (yours or monsters) can apply, including stun and wound. Stun makes the recipient skip their next turn. Wound makes the recipient lose 1HP at the end of every round (until healed).
- Some monsters, actions, and items may provide a Shield, which negates the first N points of damage from every attack.
Strategy Tips (minor spoilers)
Look at upcoming enemy actions for the turn and try to avoid taking unnecessary damage. While you are a warrior, a few mighty blows can bring you to your knees, and healing is in short supply. Winning many scenarios involves more tactical positioning than 'tanking' damage.
Don't be afraid to fail a scenario-- you gain some small amount of XP for the actions you take during a scenario, and you keep any gold you collected even if you fail, and you can try again.
Sometimes it's advantageous to choose a slow initiative, to let yourself react to monster actions or let a monster move closer so you can dart in and attack it without getting counterattacked. Remember that you can use the default Attack 2 / Move 2 actions, so you can select a slow-initiative card such as "Loot 1" as your first card, to use its slow initiative... but then when your turn comes, play it as a Move 2 or Attack 2 instead.
Using too many "burn when used" cards early in the scenario will reduce the number of turns you have until you are exhausted by running out of cards-- you may want to save them for important moments (by using them as Move 2 / Attack 2 defaults the first time through your deck).
Collecting treasure can help you buy items, but is not required-- if you spend too many turns doing that you'll run out of cards before you can complete the scenario...
There are 16 playable scenarios, though about one third of them are optional 'side quests'.
You do not need to use the 'long rest' action-- you will automatically 'short rest' to redraw cards each round. The 'long rest' can be useful when you critically need healing, an item refresh (for a few specific items), or access to a specific card quickly, but it uses up a turn and burns a card so there's a cost to it...
'Long rest' is the one action you can still perform while stunned.
- Add your own Q&A in the comments below!
- v0 (July 2021): concept and screen mockups (no code)
- v0.1 (Aug): first playable prototype of concept
- v0.2 (Sep): add story, enemies, music, special actions, items, iterate on game
- v0.9 (Oct 12): feature-and-content complete? release to a few playtesters
- v1.0 (Oct 20): integrate first feedback, improve enemy pathfinding, first public release on BBS!
- v1.0b: add more tutorial-related messages, improve hand selection UI
- v1.0d (Oct 28): based on feedback, add more tutorial-related messages, "undo" for move/attacks before confirmed, screen shake on "*2" modifier, and refactor to free up tokens for these.
- v1.0f (Dec 9): add a few more tutorial-ish notes during the early levels (initiative + dmg mods) -- not uploaded yet, some 0.2.4 compatibility / #includes issue?
General Experiences + Learning
I've just played around with small games (mostly tweetcarts) in PICO-8 previously, so this was a good opportunity to learn more about the platform and Lua, experiment, and plan something larger out.
I ran into platform limits many times and had to step back and simplify or find a more efficient way to structure code and data to free up "just the 100 more tokens I need"... but I found this resource optimization a fun challenge. And frankly, if I hadn't been working within the PICO-8 resource constraints I might never have released anything-- in the absence of external deadlines it's useful to have some constraints that keep scope in check.
ipairs(), foreach(), and especially P8SCII were new to me and useful for both saving tokens and making it easier to think about code. Amusingly, I implemented my own subset of P8SCII in a mixed-font-and-sprites print routine, but misunderstood its API so I implemented something that behaves differently. To clean up some day...
Using nested calls to split to convert long strings into 2d-4d arrays of key-value game data was essential (I eventually maintained a separate spreadsheet of level/card/enemy/upgrade data that was easier to edit and which compiled all the values together into these long "database strings" which I would copy and paste into the code).
I built a simple "dev support cart" using poke+cstore to move some game data (long story text strings) into unused sprite/sfx cart space, even without enough tokens to include data compression routines or use something like PX9.
This is the first project I didn't develop primarily in the PICO-8 editor-- I used VScode to edit one monolithic .lua file that was #included in a .p8 cart that held all the sprite/map/sfx data. I usually developed with two editor panes open side by side-- one focused on whatever I was working on, and the other to search/scroll through the code for related functions / variables / context.
Debugging unexpected pathfinding behavior (even with the benefit of someone else's A* code, see note below) and figuring out what behavior I wanted when enemies were clustered around chokepoints was delightfully frustrating. This is the one area I ended up building a completely separate test cart I could populate with enemies and obstacles, just to visualize multiple pathfinding approaches.
The source code available in the cart above has comments and whitespace stripped because I was running into Compressed Size limits. I have a fully-commented version of the source code I'll plan to clean up and upload somewhere in the future...
- Like many games, I had to strike a balance between 'building an engine' (which could lead to unnecessary generality and resource use not needed for this game) and hard-coding behaviors that make sense for a specific enemy/item/card. I think I kept it general enough to make a "Chapter 2" some day with new characters/abilities/items/enemies.
- Thanks to SH, SF, and DW for playtesting and feedback.
- Thanks HB for support and sfx feedback.
- I adapted morgan3d's A* pathfinding routine from https://github.com/morgan3d/misc/tree/master/p8pathfinder .
- I watched some of the LazyDevAcademy "developing a roguelike" videos in the past and they were educational, even if this isn't a roguelike (I used their example of actor.ox/actor.sox + animation timer for animating sprite motions between player input cycles).
For fun, I recently prototyped a little 'PICO-8 micro-console' (compact enclosure with a Raspberry Pi and square display that boots directly into SPLORE):
It's certainly less practical than commercial off-the-shelf handhelds that support PICO-8 -- it has no battery or keypad (you pair a bluetooth controller to it), but practical wasn't really the goal-- I wanted to build something designed around a high-quality square display.
Internals being tested (Pi Zero W, Pimoroni Hyperpixel 720x720 screen (used pixel-perfect with 5x5 pixels and a minimal 40px black border), USB DAC -> speaker, etc):
I plan to make a smoother white enclosure, this was just a 3D printed first pass with a lot of hand-filing to get everything to fit and figure out hardware. Maybe some day I'll make an extended-case version with a custom PCB to add battery / charging / integrated buttons... but it's nice to call a prototype "done enough to use and share".
I saw someone post a suggestion for SPLORE to add a "play random cart" feature (especially for new game exploration on a handheld without keyboard/web browser, once you get past the list of Featured and New loaded in SPLORE). I liked that idea.
While having that in SPLORE would be cleanest and would stay up to date, I hacked together a quick prototype for myself that loads a random Featured Cart (from a scraped list of the 340 carts on the Featured board as of June 2021) to play around with.
If using it on a handheld it requires an internet connection, of course.
It also adds a Select/Enter menu option to each cart that lets you chain to a new random cart.
[ edit: see follow-up post for updated cart ]
For the newest #tweettweetjam I made a very basic space shooter (layout inspired by Gyruss/Tempest) in <560 characters. It even includes a bit of sound via poke-ing to the sfx memory, since the jam rules say "code only" without separate gfx/sfx assets.
Use ⬅️/➡️ to move, ❎ to fire.
(I may write up a commented / uncompressed version of the code at some point...)
On the last evening of #tweettweetjam I was playing around with free body motion, made a prototype... it evolved into a ~1000 character toy... and I managed to squeeze it down to 560 just before the deadline. The math is buggy when paths get too close to centers, but I sort of like the look so I didn't even try to "fix" it...
Arrow keys move the attractor, 🅾️/Z switches control, ❎/X resizes.
My entry in #TweetTweetJam, in 554 characters.
Cross four levels of increasingly busy traffic, using only the up and down arrow keys!
This was my first time trying a minimal-code jam-- I read various forum tips but I'm sure there's still some compression to be had. Since the jam rules were to use source code only, no spritesheet/map/sfx data, I had the idea of Poke-ing a basic sprite into memory and then using sspr() and palt() to reuse it in different forms... and a little game evolved from that.
Years ago while bored on a train with a deck of cards, I made up this solitaire game (for all I know, it may already exist under another name). So I've turned it into a little Pico-8 cart, my first "finished" game.
(as sounds common, I've started at least 4 other ideas... all in various WIP / playing-around stages, it's just too much fun to try new things...)
Arrange cards to make as many good poker hands as possible. For an extra challenge, play in "Perfectionist" mode where you only score points if you make a pair or better in all 12 hands (across, down, and diagonal), which takes some careful play and a bit of luck.
My personal best score for some time was 44, though I recently managed a 57 when the stars aligned.
Program a tiny virtual console, the "Turtle-2", with increasing levels of capability at your fingertips.
This isn't "done" (there isn't a lot of error checking so there are various ways to make it crash, and I want to add more SFX and animations and maybe figure out custom background music), but it's a playable version of the core ideas. If anyone checks this out I'm curious what you think, whether you find it fun to play around with, and whether you create any interesting designs (share screenshots!)
I'm on the fence about trying to extend it to challenges / puzzles or just leave it as this open sandbox.
I just came across Pico-8, did a few tutorials last weekend, and here's my first cart-- a spaceship flying over an endless 2D parallax scrolling background (with more layers that get added in over time).
The whole experience was a lot of fun for someone who rarely writes software-- just poking around within the tool and trying things out. Thank you to everyone who developed Pico-8 and posted tutorials and tips!
I didn't plan to share anything because this isn't a "game" and I expect the code has all sorts of ugly parts I should clean up. But I saw a talk about how part of the concept is just encouraging sharing in any form. So why not... feedback welcome.
p.s. thanks to @Gruber for the music shared in the Pico-8 Tunes #1 cart.