EDIT: This is now postponed while baby is incoming. I'll try my hardest to pick this up in the future but it's not likely to be until at least late 2018. I'm aware that @enargy and @pingo had games in progress, bringing the total potentially to 9. There were also a few others who expressed interest, and I'll probably do one or two more eventually.
If you've already posted a game, thanks for your contribution, and please feel free to withdraw your game if you don't fancy waiting.
Old post begins here:
Let's make a cart of minigames!
Games finished: 6 of 17
Twitter hashtag is #17in1jam
Resources being used: https://www.dropbox.com/s/oca0s4bsr7pe6dp/17-in-1%20memory%20usage.xlsx?dl=0
Help with reducing tokens: https://github.com/seleb/PICO-8-Token-Optimizations
Help with reducing characters: https://pastebin.com/MVhr16td
I've built a space-themed meta-game already (see below). I'm looking for people to make some minigames for the player to explore. The first 16 (serious and functional) submissions that conform the the rules will be added to the cart.
Rules (please read carefully):
-436 tokens each
-3901 chars each
-865 compressed chars (about 5.6%)
-4x4 chunk of sprites from any of the 4 tabs on the Pico-8 editor. See resources spreadsheet for what's being used.
-16x16 section of map from the top half only, to avoid corrupting the sprites. This is flexible, some devs aren't using the map, so ask me and I can give you more. See resources spreadsheet for what's being used.
-4 SFX in a row, aligned to every 4 (0-3, 4-7, 8-11 etc). The shell cart uses 4 too so I guess the last dev to add sound will need to find 4 slots that are left over from the others. Please recycle other people's sounds!
-4 music patterns in a row, aligned to every 4.
-no real limit on cartdata other than check the spreadsheet and consider other devs.
These are rough estimates, and the more that devs come in under budget, the better for all of us.
If we have stuff left over I'll offer it out as required and try to get some fancy transition GFX from some of the tweetjam legends on Twitter.
-Please use update() rather than update60()
-Do not use single-letter variable names, other than h/i/j/k/v/w/z, do what you like with these
-If you need more global variable names, pick a single letter to use as a prefix for all of your names, so if you choose 'f', your variables can be 'fa', 'fb', 'fc', 'fscore' and so on. See the resources spreadsheet to find out which prefixes have already been taken.
-Local variables you should be able to call whatever you like.
-ALL of your global variables need to be declared and initialised inside _init() so that I can just call _init() to reset your game.
-you MUST call my global function ret(n) on win/lose/die/timeout/whatever, so it can switch back out to the meta game. n should be a number 0-128 (inclusive) that represents how well the player did. This number will be used to refuel the player's ship and increase their final score.
Don't use any controls outside of the Pico-8 standard, i.e. no mouse controls etc.
-Use the following function references, defined for you to save chars:
e=all f=flr m=camera p=print r=rnd
- @UncleSporky has provided the following "pretty print" function which I've made global. Feel free to call this in your code:
function pp(h,i,j,k) ?h,i-1,j,0 ?h,i+1,j ?h,i,j-1 ?h,i,j+1 ?h,i,j,k end
-If you turn something on (via fillp(), pal(), etc) be sure to turn it off again. Exceptions are color() (assume this is regularly overwritten) and palt() / camera() (these are reset on game exiting via ret()).
-Please make it clear when you post the cart which resources you have used and where they are.
-Please make something especially for this, rather than posting something you recently completed. Existing ideas are fine.
-There is no need to produce something space-themed, as the "anomalies" (see below) are meant to take the player to random dimensions. In fact, the more eclectic, the better :)
-Make the controls intuitive, or provide tooltips.
-Each game should only play through once before booting the player back out to the meta-game. One playthrough should take max 60-90 secs (remember the aim is to play all the games in a row).
-During gameplay, at (0,123) on the screen, display a string that says "GAMENAME (YOURNAME)", max 32 chars
Make it as polished as you can!
I've made the shell of the cart, and the "meta" game is 99% complete. See below:
In the meta-game you fly around in space looking for "anomalies", each of which takes you to a random minigame. You play the minigame only once and, win or lose, the anomaly closes and you have to find another one. The aim of the game is to close all 16 anomalies and get the highest score. Flying uses up fuel, as does touching the aliens, but you get fuel bonuses (and points) depending on how well you do at each of the games. The anomalies are at fixed positions, but there's no map, so you might want to jot down their locations as you find them (old school!).
This shell cart takes up 1202 tokens, 3112 chars and 1511/15630 compressed chars (about 9.8% of cart), these stats are what I've used to work out your budgets.
I hope you have lots of fun!
Hey FYI anything stored outside the code editor doesn't effect compressed size. So no matter what the built in sprite, map, and music/sfx data is, that figure stays the same. Thing like comments in code do affect compressed size tho.
I have a few tiny things I'd like to contribute.. a small fishing minigame, a keypress/typing game, and a shooting gallery. None should take up much space or graphics. Could we have a global option so we know if the player has access to a keyboard, mouse, or just a joypad?
Questions: how long should a single minigame session last?
Can we save things using dset to have persistent 'stages' when a game is revisited?
Where should we post games?
Hey @enargy thanks for the info. That will help with cart size.
Those ideas sound great, if possible I'll keep it one per dev but if we are low on submissions by all means I'll take multiple games per dev (and I've got some ideas I'd like to add too). I think keep it joypad only to be "pure" Pico-8.
Minigame sessions should be 60-90 secs. Players will only play each game once per run, but it might be nice to have a game that reacts differently based on how many times the player had played... for example, "welcome back, I see you did X last time, let's see how you deal with this". That would be very nice.
Post games on here as standalone carts, be sure to declare all global vars inside _init and don't have any code outside _init _update or _draw.
Looking forward to seeing your work!
Well done for getting this going.
I'm certainly interested - if I can find the time to submit anything!
Have you announced this on Twitter yet?
If not, might be worth tweeting the link (using the #PICO8 hashtag), coz there's a lot of users on there that don't check the BBS as often.
Good luck with the jam! :D
@Liquidream you have time, I can't imagine it filling up that quickly and would be good to have your input. I'd already tweeted with hashtag etc but just did a second one just in case.
@steiff awesome, I'd be happy to help if you get stuck :)
@dollarone thinking more about this, would also be good to know about WIPs so I can keep track of how many we have so far.
If we get loads of games, we can always copy Pokemon and do Red and Blue versions!
I've put a public file on Dropbox for people to claim their sprites and other resources:
Add a comment to claim your stuff and I will keep the spreadsheet up to date.
Are there any open slot in this project?
I made a game for it... sort of.
It's way over the token budget (around 500) so I need to figure it out how to reduce that.
But on the flip side it uses no sprites, nor map, nor music and at the moment no sound either (but I would like to squeeze in a couple sfx just don't know how yet :) )
Should the games implement end screens (win and game over) individually or just call ret() instantly?
@viza - plenty of open slots, just make a gaem! :)
@elneil - can you allocate me some stuff (I can't edit the dropbox spreadsheet):
just need 6 sprites (3 of them next to each other please)
4 sfx entries
4 music "pages"
if there's leftover sfx/music at the end of it I'd be happy to further extend my music
Ok, I made two "gaems". :)
If there is a one/dev limit, just choose what you like most. :)
Is there somewhere I should send the carts/p9 or something?
Anyway, here are the current stats:
Game 1: "close encounter of a kind"
chars and compressed chars way under the limit
Game 2: "alien shootout"
chars and compressed chars way under the limit
3 music pages (well, kind of a stretch to call that music, but I needed something. If somebody wants to create three short pieces ("suspense", "win", and "lose") I would be grateful :) )
Both has win/game over screens, and wait for a keypress to return to the meta game.
I don't know if thats a problem, but none of them using the _draw function - just calls flip() at the end of the update function.
Also, I use _update60.
Are these ok for the cart?
@dollarone I've allocated you the following:
Sprites 212-214, plus 230, 231, 247.
Variable prefix 'd' (in case you need it)
These are all high numbers so let me know if this causes you to go over the character limit and I'll give you some lower ones!
@viza what @dollarone said - loads of room. Afraid I can't budge on the token limit at the moment, this is proving to be the tightest restriction I think. Not sure if you've seen these tips, but might be worth a look:
Two games! Awesome :) They both sound good but do make sure they are fleshed out enough; e.g. if you want to polish the music then do that first. Your "Bean Up" (post compo version) is a good example of the kind of polishedness I had in mind.
There's no need to provide intro and game over screens, this might save you some tokens. As long as the player can tell if they are doing well or not, and that the controls are intuitive (or have tooltips). Feel free to post a WIP on here for feedback too.
_update60() might be a problem, because the shell cart uses _update() as a wrapper and basically says
function _update() doUpdateCode(gameID) end
So if it works in 30fps that would be best.
Using flip() instead of draw() should be fine I guess? I'll let you know when I merge it if there's a problem.
Post carts on here when they are finished, and let me know which resources you've taken up (see spreadsheet in previous post for resources still available).
Looking forward to playing!
PS for guidance here's a game I'm adding to the cart:
@viza both of these could definitely work -
The memory game is a bit easy - maybe speed up the pattern so it's harder to remember and maybe add a twist (for example, after a while, mix up the tones or colours? Or make certain notes audio-only or graphics-only?)
I like the shooting game too. Maybe there could be some kind of push-your-luck aspect? For example, after the third light goes out, the longer you wait the more points you get? Not sure how you'd communicate this to the player though?
EDIT: Forgot to mention, there's no need for it to be space-themed either; the more random the better.
Either way, like I said above, no need to have the "final score" bit: maybe just pause for a second or two and then kick the player out via ret(n).
This is all great so far - thanks for your time!
Thank you for your suggestions!
I got quite a few ideas to add to the games, the problem is mostly (as you already mentioned) is how to communicate the gameplay changes to the player - or more specifically, how to fit the necessary communication to the limited space the mini games have... Both games are on the token limit, so that need to be taken care first.
A couple of ideas though:
To do the push-your-luck thing you suggested the game should provide the player with some "tell" to get something to... push against so to say. The best would be something on the opponent - a glint in the eye, or narrowing the eye. Or preferably more "tells", all over the body of the opponent, so the player has to split his attention - a twitch in the gun-hand finger, the tension of the jaw muscles, etc. Basically what the western movies show in closeup during a duel scene :) Of course most of those would need a higher fidelity graphical representation :) but some of them could be transferred to these retro visuals too (but all would need more tokens and gfx...)
Another way is to do something more abstract representation of the same thing - like a rising bar of the... I don't know... "shooting readiness" of the opponent or something. I'm not sure that would be obvious for the players though.
Maybe I can move to a completely other direction, with two or three bars like in a golf or billiard game?... :-? Like, I don't know, "precision" and "timing", both moving constantly at different rates, and the player has to chose the moment to stop both at the same when it both is in a good position - and do this in a limited time, before the alien shoots... or something akin to Gears of Wars active reload - one button press starts a quick moving bar, the second one stops, the player has to stop at a specified point for a good shoot. If the bar reaches the other end, the alien shoots first, if it is stopped at a wrong position, the shot is not accurate enough. Or something like that, i can refine it to no end. :)
Ok, it is getting too long, so I'll do the memory game ideas in bulletpoint style instead :)
- color: slowly mutate, not suddenly change
- spatial: rotate, preferably showing the rotation. 90 degrees at a time, or constantly rotating during playback
- sound: remove the color and directional clues - gradually, and still keeping some visual feedback to show something is happening
- temporal: simply speed up, or require specific timing to hit (like a rhythm game)
Again, I don't know if any if these can fit in the jam's (or pico8's, or my skills') limitations...
I'll see, when/if I have more time :)
@viza lots of good stuff there. How about for the shooter, once it's time to draw, a crosshair floats around the screen and the player has some clumsy control over it, like in the old darts games? The longer you spend aiming, the more likely you are to get shot. Maybe it randomises a target (left leg / right leg / left arm etc) and you get bonus points for hitting that, or just standard points for hitting him anywhere. Or maybe set amounts of points based on how hard the limbs are to hit.
I had an idea for collision detection but would depend on how pal() works with pget(). If you change a colour value using pal(), and detect that colour on the screen using pget(), does it return the original value or the mapped value? I'm thinking your limbs could be different colours, all converted to the same colour before drawing. Hope that maes sense.
For the memory game I like the idea of gradually losing sound or colour. Also maybe doing things on the beat for bonus points or combo BUT I know from experience that syncing code to music on pico8 is flaky, so you'd have to do it with sfx and code, and you've already used your 4 sfx for the patterns (or maybe you could use 1 sfx slot for 4 tones with an offset?). Have a play and see what happens, I'm sure you can come up with a good solution :)
@dollarone awesome! This is great - I'll merge it in tonight. Not sure what to do about game over screens, as some games will have them and others won't. Do you mind if I change the text as "game over" might be a bit confusing (it's not actually the end of the "game")? Maybe something like "you crashed"?
@dollarone I just went to merge the code and saw that although you're under the token and char limits, you've gone over on the compressed char limit (865). Also, your variable names need to use the prefix I gave you otherwise they could affect the rest of the program - your prefix was 'd' so if you use this plus create some shorter variable names this will go a long way to getting the program crunched. Let me know if I can help at all.
@viza Good work :) Adds that extra challenge.
Some small final things:
Can you make it so "up" is draw and X is shoot, and rather than have the instructions at the start maybe have text that says "draw!" with an up arrow icon, after the third light goes out? Then also have an X icon on the green section of the bar. That way there's no need to explain anything.
We are not using _update60() I'm afraid, can you check it works fine with _update() please.
After that, we're good to go. If you send me the finished .p8 file over Discord (link above) I will look at merging it in asap.
@elneil: Why aren't you using _UPDATE60 ?
(sorry if this has already been covered)
If it's just that you didn't realise it's an option, then it's not too late to switch it in the base cart. The only thing that may happen is that it may effect (read: speed up) existing code (base code + current entries), depends how you wrote it. But the finished result will be much slicker (being at 60 FPS). :o/
@Liquidream yes I probably should have been a bit more decisive / clear at the start. I've learned a lot already...
Basically I was thinking keep it at 30fps otherwise it's even more restrictive than it already is. The token limit is proving difficult already, so people might have to rely on CPU to do things in fewer tokens. I'm not sure the shell cart will run at 60fps either. EDIT: I guess another part of my rationale was that if people accidentally used 60fps it can still run in 30 (with tweaking) but not necessarily the other way round. Also, do all versions of Pico8 run at 60 (even the mobile browser player)?
I'll make the instructions more clear now.
heh, I used a lua minifier to achieve the limit. My code is unreadable now. I hope it works!
also used the p and f shorthands. It's therefore unplayable as a standalone
edit: huh, now its 445 tokens? wtf. will have a look tomorrow...
@dollarone I spotted the following token optimisation chances:
dm=dm+3 dd=dd-0.1 dd=dd+0.1 dx=dx+min(max(dd,-1.5),1.5) dw=dw+308
These could all be replaced with += or -= , saves 2 tokens each IIRC.
While you're there, could you move the word "score" 8px to the left please? Just for neatness ;)
Also if you could update your sprite IDs in the code as I mentioned on Discord:
blue streak = 196
3-sprites in a row = no change
big rock = 215
little rock = 231
Thanks! Then I'll leave you in peace :)
@enargy there are errors because @dollarone is using the function refs I created, which are defined in the shell cart. f=flr() p=print(). Also crashes on game over because cartdata() not called (this is now in the WIP new version of the shell cart).
@viza This looks fine to me! Only one minor thing - could you change the "duel 7/1" so it says "duel 1/7" please? Apart from that we are good to go. You're at/under the token limit but the compressed chars have gone over the limit of 865. There's a ton of whitespace though, and loads of long variable/function names, so this shouldn't be a problem. There are also some handy hints here: https://pastebin.com/MVhr16td
alright, all done! fixed the token limit by reverting the += and if(a)b pico8-specific calls.
I changed back to flr() and print() so the cart can be played - feel free to replace in the collab cart to save another 4 compressed chars :)
You guys could save a few more tokens, overall, if you used ? instead of using print() or p():
print("abc",1,2,3) vs. ?"abc",1,2,3
It does work in source mode, not just command-line mode.
Saves one token per invocation, plus no need to set up the p() alias. You need to put it alone on a line, so alas you don't save the two chars you delete when you get rid of the parens. You might save one in some cases.
@Felice thanks for this - I knew about ? but wasn't sure if it would end up being deprecated. Might as well risk it!
Didn't know you could add extra parameters though. Good call.
Why the letter 'e'? I think it was because of the only letters left it was better than z or whatever. 'a' was being used for the "angle" of the ship in the shell cart. I seem to recall thinking afterwards that 'e' was a good choice, as it could mean "each", but it wasn't a deliberate choice. It's a scintillating life that I lead...
This isn't an official submission yet...it doesn't quite fit into the requirements. Not fully optimized yet. I was wondering if others might have any ideas on how to get it smaller without compromising too much.
Currently comes in at 471 tokens, 1765 chars, 994 compressed chars.
Right now it errors at endgame because it's using the rtn() function as instructed above, it should be feature complete in that respect, it tries to return a score of sorts to feed back into the metagame.
Things that will help size a bit:
- no need for starting comments for the sake of cartridge (16 compressed chars)
- eliminating tabs/whitespace (35 compressed chars)
- change flr and rnd to f and r (4 compressed chars)
I could remove a couple lines of dialogue but I feel like most of it is crucial to understanding the game, simple as it is. I need to include "your health drains over time" so people notice that happening and don't die just walking in the first few seconds. I also want to keep the hint about finding the sword if you don't get it the first time playing.
How the game works: check the player's x and y to see what map tile they're standing on. If they're not on regular tiles like grass or trees, then they're going to be in a dialogue screen in an infinite loop waiting for input ("press O to continue"). Then we determine which screen to show. If they're on a village, generate a little village scene, write some dialogue and refill health. If they're standing on the lich, end the game. If their health has run out, they'll be standing on an invalid location (x=128) in order to also trigger this check and end the game. From a village, pressing O bumps the player down one space which should place them back in a regular map tile. Then the map is drawn. If the player is ever standing on an enemy, the enemy is killed, the map tile is replaced by the one below it and the player's level goes up by 1. Moving checks for collisions and if there is none, then the player moves and their health goes down a little.
There is also a pp() function included ("pretty print") that gives text a nice border to make it more readable, which is usable by all games on the multicart! This function takes up 37 tokens and 48 compressed chars. Without it, it puts me right under the token limit...and I could also change my print functions to the "?" format and save even more tokens. But text becomes completely unreadable, and even with this and some of the above changes, that only puts me at 892 compressed chars.
I dunno. Thoughts on further optimizations?
@UncleSporky I just killed the lich too - great game.
Couple of bits of feedback:
- you could probably use \n to minimise the separate print calls you have? Save a few tokens etc.
- the heal screen is a bit disorientating, is there any way to just have a text bubble above the player's head? Either that or show the two people in a differently-backgrounded screen, so it's a bit more obvious they are speaking to you from elsewhere.
- "drains over time" is a bit misleading, maybe something like "drains when moving"?
- I'd be happy to make pp() global but haven't got room, unless future devs come under budget between them...
- I struggled the first few runs because I couldn't see the guy in the bottom left by the rocks. Can you make the people / rocks contrast more?
I can't believe I didn't figure out how to \n earlier. I tried the wrong slash and it didn't work, so I figured escape characters needed to be coded in. >_<
I removed as much whitespace as I could, and this version comes in at 447 tokens, 926 compressed chars, which is a lot better but still not quite there.
If I make a second game that comes in under budget by 11 tokens and 61 compressed chars, then we should be good, right? :)
I liked your change to "drains over time." I don't know why I put that to begin with, I guess I thought "when you move" wouldn't fit onto one line.
I'm not sure what you mean about showing the people in a differently-backgrounded screen. The intent is to show a little village town square, where the hero is greeted by a villager (mayor, innkeeper or something) who has healed them. A big part of it is just showing a town at all, without taking up extra map space. Sort of a hint of old school Final Fantasy or Dragon Quest where you'd normally get to walk around and buy things.
And did you mean you couldn't see your hero, or you missed seeing the lone enemy down there? I tried to make them stand out as well as I could. And you don't actually need to kill every enemy to reach the lich, I think you can be 2 short and make it with a few moves to spare (one of the two probably being the last one on the way to him, though you have time to backtrack to town after grabbing him too).
Uncle: you can do multi-var assignment to save some tokens:
if ss==true then
pp("you have saved the world!",15,29,7)
elseif ss==false then
you can just use else .. end :)
and btnp(4) can be changed to btnp"4" to save an additional token
Oh man that gets it down to 433 tokens and 918 compressed chars...under token budget, baby!!
Thanks, I was being dumb with that elseif. I'd seen about multiple assignment before, don't know why I forgot to do that. I even went over the token optimization notes.
At this point the chars are pretty much related to the strings, and it's tough to cut that like I said. I'll keep working on it. If it's alright I'll see if I can make a second game that comes in under compressed budget, which should be easy without dialogue.
This version comes in at 439 tokens and 945 compressed chars, due to a small change suggested by @elneil to make towns less disorienting/more interesting...a little rectfill rug! But those rectfills are expensive on chars.
Implemented above changes and other optimizations, put all the endgame code in the same place to consolidate and be able to zero out HP at endgame. Also fixed some variables, X and Y to SA and SB, as well as changed HP to SH.
@UncleSporky and I have got the MicroRPG back down to 435 tokens / 939 chars. Work in progress...
@viza's game is finally merged in, had some weird problems copying/pasting sfx in the editor so had to edit the .p8 directly.
We now have 4/17 games done with 1 waiting to be merged and 2 others in progress. Nearly halfway there! Sort of!
Ok, here is Pants Thief! The plot of the game is that you are a pants thief.
Cutting out the floor/rand aliases at the start along with the pp() function already included in Micro RPG, this game clocks in at 428 tokens, 1196 chars, and 791 compressed chars. Somehow, inexplicably, this saves exactly the number of compressed chars needed to make up for the amount Micro RPG went over (74). It's possible that there could be even more savings lurking in the code, this is just the first release.
A couple things that I should point out:
no map or user data used
2 sprites are unused, and I made sure they're at the start of the section (128 and 129)
3 music unused (49, 50, 51)
I forgot about e=all, that'll be one very minor savings.
Didn't swap in all possible single letter variables. UH/UI/UJ/UK are used for one significant chunk of code (aliases for I-I to save tokens and characters) so those 4 could probably be replaced by some singles.
UT counts upward forever. If someone plays this for over 18 minutes for some reason, it will roll over and I'm not sure what sort of weirdness could occur.
UP is the number of pants stolen, and the game returns this value x 3 as the player's score. If somehow the player manages to steal over 42 pants, the value will be higher than 128, and I'm not sure what this would do to the base game. However, no one should be able to steal more than ~27 pants at most, since once you get up to that point the people are spinning so fast that it's basically luck if you manage to steal their pants or not. If it turns out to be an issue we could return a lower value like UP x 2, but then most people will only be scoring about 40.
[Please log in to post a comment]