zep [Lexaloffle Blog Feed]https://www.lexaloffle.com/bbs/?uid=1 Lovebyte 2023 Intros <p>It's <a href="https://lovebyte.party/">Lovebyte</a> this weekend, and I made a couple of size-coded intros for it. First up is an invite to another <a href="https://en.wikipedia.org/wiki/Demoscene">demoscene</a> party: <a href="https://sessions.frontl1ne.net/">SESSIONS in C4 LAN 2023 SPRING</a>, taking place in Shizuoka / Japan end of April. This one is 512 bytes, around 100 of which are for the music (don't wait for the drop!): </p> <p> <table><tr><td> <a href="/bbs/?pid=125754#p"> <img src="/bbs/thumbs/pico8_sessions_2023-0.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=125754#p"> sessions 2023 invitro</a><br><br> by <a href="/bbs/?uid=1"> zep</a> <br><br><br> <a href="/bbs/?pid=125754#p"> [Click to Play]</a> </td></tr></table> </p> <p>I also tried a bunch of 64 byte intros based on poking semi-structured patterns into ram that could double as audio and visual data. This is the one that I submitted to the 64 byte compo:</p> <p> <table><tr><td> <a href="/bbs/?pid=125754#p"> <img src="/bbs/thumbs/pico8_attack_on_venus-0.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=125754#p"> attack_on_venus</a><br><br> by <a href="/bbs/?uid=1"> zep</a> <br><br><br> <a href="/bbs/?pid=125754#p"> [Click to Play]</a> </td></tr></table> </p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>t=9::_::i=t^4 poke(i,51&amp;(t*(i&gt;&gt;9)*(i%64)/&hearts;)) t+=1/&hearts; sfx(i)goto _</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>Here's a variation that has more of a horror feeling:</p> <p> <table><tr><td> <a href="/bbs/?pid=125754#p"> <img src="/bbs/thumbs/pico8_forest_horror-0.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=125754#p"> forest_horror</a><br><br> by <a href="/bbs/?uid=1"> zep</a> <br><br><br> <a href="/bbs/?pid=125754#p"> [Click to Play]</a> </td></tr></table> </p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>t=19::_::i=t^4 poke(i, 0xdb&amp;(t*(i&gt;&gt;7)*(i%64)/&hearts;)) t+=1/&hearts; sfx(i)goto _ </pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>If you want to try these in a browser, you can copy and paste them into <a href="https://www.pico-8-edu.com">PICO-8 Education Edition</a>.</p> <p>I didn't have time to make 128 byte &amp; 256 byte entries, which happen to be the two compos that have their own dedicated fantasy console sections! But I'll definitely be back next year -- it's great to have a whole party focused on size-limited prods, and that is inspiring so many great pieces of work. There are more events happening tonight (Sunday, UTC) and you can catch them <a href="https://www.twitch.tv/lovebytedemoparty">live on twitch</a> or archived <a href="https://www.youtube.com/@Lovebytedemoparty">on youtube</a>. You can find a schedule on the <a href="https://lovebyte.party">lovebyte website</a>. Good luck to those taking part tonight! &lt;3</p> <p><object width="640" height="400"><param name="movie" value="https://www.youtube.com/v/jQgp5tHx3t4&hl=en&fs=1&rel=0"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="https://www.youtube.com/v/jQgp5tHx3t4&hl=en&fs=1&rel=0" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="400"></embed></object></p> https://www.lexaloffle.com/bbs/?tid=51606 https://www.lexaloffle.com/bbs/?tid=51606 Sun, 12 Feb 2023 13:21:08 UTC PICO-8 0.2.5g <img style="margin-bottom:16px" border=0 src="/media/1/pico8_025f.gif" width=384 height=384 alt="" /> <p>More bugfixin'</p> <p>PICO-8 <span style="text-decoration: line-through;">0.2.5f</span> 0.2.5g is up now up on <a href="https://www.lexaloffle.com/games.php?page=updates">lexaloffle</a>, <a href="https://www.humblebundle.com/home/library">Humble</a>, <a href="https://lexaloffle.itch.io/pico-8">itch.io</a>, and for <a href="https://lexaloffle.com/bbs/?tid=34009">PocketCHIP</a> and web (<a href="https://pico-8-edu.com">Education Edition</a>).</p> <h3>v0.2.5g Changelog:</h3> <p>Fixed: tonum(&quot;123abc&quot;) returns 123 (should return nothing) // also breaks split(). regression in 0.2.5f<br /> Fixed: draw_tabs not listed by CONFIG command</p> <h3>v0.2.5f Changelog:</h3> <p>Added: CONFIG DRAW_TABS 1 to show tab characters in code editor (previously required editing config.txt)<br /> Changed: tokenizer recognises long comments / string using [=<em>[ ]=</em>] e.g. [==[ long string ]==]<br /> Changed: Nested long comments and strings no longer allowed<br /> Changed: x % 0 gives 0 (was x)<br /> Optimised: software blitter now faster when using PocketCHIP, windowed raspi or blit_method 1<br /> Fixed: infinite tokens exploit introduced in 0.2.5d (due to pre-processor changes)<br /> Fixed: &gt;&gt;&gt;= operator is a NOP (bug introduced in 0.2.5d)<br /> Fixed: (raspi 32-bit) window not visible under Gameforce Chi / EmuELEC -- bug introduced in 0.2.5e<br /> Fixed: s=&quot;x&quot;..&quot;=&quot; counts as 4 tokens instead of 5<br /> Fixed: Running a cartridge containing <em>meta</em> data prints a memory allocation warning to stdout<br /> Fixed: Code compressing to &gt;= 32k reports size as (compressed_size &amp; 0x7fff) resulting in corruped exports<br /> Fixed: stat(54) loops when left-most channel is looping (should return total played ticks on current pattern)<br /> Fixed: extcmd(&quot;audio_rec&quot;) maximum length is 2 minutes (meant to be 8 -- and now only applies to web)<br /> Fixed: Frog Home crashes because of (now unsupported) &quot;local x+=..&quot; form. // INSTALL_GAMES for fixed version<br /> Fixed: Starting P8SCII font height affects total line height even when no characters are printed in that font</p> https://www.lexaloffle.com/bbs/?tid=51465 https://www.lexaloffle.com/bbs/?tid=51465 Fri, 03 Feb 2023 20:29:16 UTC Picotron Playground <img style="margin-bottom:16px" border=0 src="/media/1/picotron_playground.gif" alt="" /> <p>A new year, a new fantasy machine! <a href="https://www.lexaloffle.com/picotron.php?page=playground">Picotron Playground</a> is an experimental web version of <a href="https://www.picotron.net">Picotron</a>'s WIP runtime and API, bundled with a terminal and code editor in order to make some toy programs. You can read more about the goals of Picotron and its specifications in the FAQ:</p> <p><a href="https://www.lexaloffle.com/picotron.php?page=faq">https://www.lexaloffle.com/picotron.php?page=faq</a></p> <p>Although I'm still mostly occupied with PICO-8 and Voxatron, I hope this will be a good way to chip away at the project and let future users try out the API in a low-stakes way before it is ready to go into production.</p> <p>Launch Picotron Playground here:</p> <p><a href="https://www.lexaloffle.com/picotron.php?page=playground">https://www.lexaloffle.com/picotron.php?page=playground</a></p> <p>Note: you'll need a US layout keyboard and <strong>there is no permanent storage</strong>, although the clipboard does work if you want to store some snippets. Please work on anything larger than toy programs at your own risk!</p> <h3>Running Demos</h3> <p>Demo programs will appear (and probably disappear!) over time to try out various API functionality. At the moment they are mostly simple graphics demos that can be loaded via the terminal:</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>/$ cd /demos /demos$ ls /demos$ load dots</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>CTRL-R to run it.<br /> ESC ESC to get back into the editor<br /> CTRL-L clears the screen (important!)<br /> The &quot;reset&quot; command can be used to get the default palette back.</p> <h3>Using the API</h3> <p>The most interesting feature of Picotron's runtime is probably the gfx pipeline, which is documented here: <a href="https://www.lexaloffle.com/dl/docs/picotron_gfx_pipeline.html">https://www.lexaloffle.com/dl/docs/picotron_gfx_pipeline.html</a></p> <p>If you'd like a quick way to load sprites, try copying and pasting from PICO-8 gfx editor and pass that as a string to userdata():</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>my_sprite = userdata&quot;[gfx ... /gfx]&quot; spr(my_sprite, 100, 100) </pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>There are some more examples of how to manipulate userdata in the <a href="https://www.lexaloffle.com/picotron.php?page=faq">FAQ</a>.</p> <h3>Limitations</h3> <ul> <li>There's no audio yet.</li> <li>There is provisional cpu cycle counting, but it is incomplete and infinite loops will still crash your browser. You can get the cpu with stat(1), but it currently also includes cycles used by system processes. </li> <li>Some of PICO-8's more forgiving behaviors do not not exist [yet?], including being able to divide by zero, and automatically converting floats to ints.</li> <li>The code editor is still a bit janky. Sorry!</li> <li>btn() works but just for a placeholder P1 6-button layout.</li> </ul> <p>I think that's enough to poke around for now. If you have any questions please post them in this thread or ask me on <a href="https://tinyurl.com/zepfedi">mastodon</a> as there isn't a Picotron sub-forum yet. I hope you enjoy it!</p> https://www.lexaloffle.com/bbs/?tid=50923 https://www.lexaloffle.com/bbs/?tid=50923 Sat, 31 Dec 2022 15:33:43 UTC Wooden Toy Joinery <p> <table><tr><td> <a href="/bbs/?pid=123001#p"> <img src="/bbs/thumbs/pico8_wtj-0.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=123001#p"> Wooden Toy Joinery</a><br><br> by <a href="/bbs/?uid=1"> zep</a> <br><br><br> <a href="/bbs/?pid=123001#p"> [Click to Play]</a> </td></tr></table> </p> <p>Use the dpad to move head pieces around, join them to tiles (only some tiles join, and only on certain sides), and move your creation to the target area to complete each puzzle.</p> <p>A wee game for <a href="https://www.lexaloffle.com/bbs/?tid=50644">Twelve Days of PICO-8 Christmas 2022</a>. To get the full experience, play it from <a href="https://www.lexaloffle.com/bbs/?uid=14839"> @TheTomster</a>'s <a href="https://www.lexaloffle.com/bbs/?tid=50644">menu cart</a>!</p> <p>Some scenes from other games in the collection:</p> <p><img style="margin-bottom:16px" border=0 src="/media/1/mittens_0.gif" alt="" /><img style="margin-bottom:16px" border=0 src="/media/1/freezing knights battle 3_0.gif" alt="" /><img style="margin-bottom:16px" border=0 src="/media/1/puffy coats_0.gif" alt="" /><img style="margin-bottom:16px" border=0 src="/media/1/decigobloopbloop_0.gif" alt="" /></p> <p>Wooden Toy Joinery was a 3 day collaboration with my 9 year-old while visiting my folk's place in the south of New Zealand. Yesterday out of nowhere my Dad produced what looks to be one of the first BASIC programs I ever wrote (maybe.. 1985?). I didn't have access to a computer at the time, and this was before understanding what variables are. I suspect I was imitating a pick-a-path adventure code listing I'd seen, but applied to an action game.</p> <img style="margin-bottom:16px" border=0 src="/media/1/jumping_bug.png" alt="" /> https://www.lexaloffle.com/bbs/?tid=50824 https://www.lexaloffle.com/bbs/?tid=50824 Sun, 25 Dec 2022 12:51:42 UTC PICO-8 0.2.5d <img style="margin-bottom:16px" border=0 src="/media/1/bunny_1.gif" alt="" /> <p>Hey all! Time for some more bugfixes and esoteric features / QOL improvements to finish off 0.2.5*. And thanks to some snippets from <a href="https://www.lexaloffle.com/bbs/?uid=14958"> @samhocevar</a>'s excellent <a href="https://github.com/samhocevar/z8lua">z8lua</a>, some cleaner code parsing. <a href="https://www.pico-8.com">PICO-8</a> 0.2.5d is now up on <a href="https://www.lexaloffle.com/games.php?page=updates">lexaloffle</a>, <a href="https://www.humblebundle.com/home/library">Humble</a>, <a href="https://lexaloffle.itch.io/pico-8">itch.io</a>, and for <a href="https://lexaloffle.com/bbs/?tid=34009">PocketCHIP</a> and web (<a href="https://pico-8-edu.com">Education Edition</a>).</p> <h3>0.2.5e</h3> <p>0.2.5e fixes a bug in the loader that causes uppercase characters to not be loaded as punyfont (e.g. breaking _ENV).</p> <h3>0.2.5d</h3> <p>Added: tline(bits) to set number of bits used for fractional part of mx,my,mdx,mdy (13 by default)<br /> Added: ctrl+mousewheel to scroll code horizontally<br /> Added: current bbs cartridge id shown in window title (config.txt show_cart_id_in_title to disable)<br /> Added: poke(0x5f36, (@0x5f36)|0x80) to enable character wrap by default when printing<br /> Added: blit_method in config.txt // Can use a software blitter by default (slower but more reliable)<br /> Added: reminder when re-locating sprites that only the top half of map is altered by default<br /> Added: draw boot sound as note glyphs on startup when sound is off<br /> Changed: print() returns both max(cur_x), max(cur_y) and includes non-printed characters (e.g. tabs)<br /> Changed: extcmd(&quot;folder&quot;) and extcmd(&quot;set_title&quot;, &quot;foo&quot;) can now be used from bbs carts<br /> Changed: Indexing a string out of range returns nil (was &quot;&quot;)<br /> Changed: Replaced most of pre-processor with Lua parser modifications based on z8lua (fixes various edge cases)<br /> Changed: &quot;a[foo()] += 1&quot; only evaluates foo() once<br /> Changed: out-of-bound tile values can be drawn using map(), tline()<br /> Changed: extcmd(&quot;audio_rec&quot;) can record a maximum of 8 minutes (was no limit previously)<br /> Changed: Rate limits are now per-minute: 10MB of log writes, 64 different files, 10 extcmd(&quot;folder&quot;)'s)<br /> Fixed: Infinite tokens hack (was caused by now-replaced pre-processor)<br /> Fixed: Only 4 controllers mapped to 0x5f00+76<br /> Fixed: h toggles hexadecimal mode in gfx editor (should be ctrl-h -- h is to flip sprite horizontally)<br /> Fixed: out-of-bounds value doesn't respect custom map size<br /> Fixed: cutting or clearing a selection of sprites does not also clear the sprite flags<br /> Fixed: P8SCII repeat-character command fails on zero repetions; ?&quot;a*0bc&quot; should print &quot;ac&quot;, not &quot;abc&quot;<br /> Fixed: pxa code compression inefficient when &gt;= 32k matching triplets (typically &quot;000&quot;)<br /> Fixed: print() return value max(cur_x) returns 0 when max(cur_x &lt; 0)<br /> Fixed: holding menu button to force pause menu to open broken in binary exports<br /> Fixed: copying / pasting in commandline doesn't respect punyfont character encoding<br /> Fixed: (Manual) Steps 1 &amp; 2 on how to move sprites in the map are in the wrong order<br /> Fixed: Unhelpful / no error messages when the wrong format for HELP is used </p> <h3>EDIT: Note for Raspberry Pi Users</h3> <p>0.2.5d/e seem to have a serious issue with the blitter that causes PICO-8 to run, but with a hidden display (i.e. you can hear the boot sound, but not see anything). Unfortunately I won't be able to debug this for another couple of weeks as I'm out of my office -- but in the meantime you can get 0.2.5c from the downloads page under &quot;older versions&quot;. Run it with <code>pico8 -accept_future 1</code> if you want to load splore cartridges authored in 0.2.5d/e (and it will probably still work). Sorry about this!</p> https://www.lexaloffle.com/bbs/?tid=50632 https://www.lexaloffle.com/bbs/?tid=50632 Tue, 13 Dec 2022 15:16:59 UTC aajibi (512b intro) <p> <table><tr><td> <a href="/bbs/?pid=120267#p"> <img src="/bbs/thumbs/pico8_aajibi-0.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=120267#p"> aajibi (512b intro)</a><br><br> by <a href="/bbs/?uid=1"> zep</a> <br><br><br> <a href="/bbs/?pid=120267#p"> [Click to Play]</a> </td></tr></table> </p> <p>Turn on your subwoofer!</p> <p>This is a 512 byte intro I made for <a href="https://2022.inercia.pt/">inercia 2022</a>, a demoparty that took place in Lisbon over the weekend. It's the first time that I put the <a href="https://www.lexaloffle.com/bbs/?tid=41991">no longer secret</a> 0x808 audio channel to use, with around 200 bytes of the (compressed) code spent on generating the music.</p> <p>I was pleased to find that techniques used for golfing down visual effects' code size transfer quite well to audio. There are a lot of expressions in there that change meaning over time in a way that produces some kind of structured progression -- some planned, some not so planned. The whole thing is really a single effect, with a lot of janky math to roll out different audio and gfx layers at different times. I can't completely explain how it works in places, but feel free to ask about anything if you like!</p> <p>This version has commented code in tab 0, but it is probably not a good example to get started with audio synthesis. For anyone game to try using 0x808, here is a simpler example that generates a sine wave at middle C (256Hz)</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>x=0 function _update() -- write one more byte while there -- is still space in the audio buffer while(stat(108) &lt; stat(109)) do v = sin(x)*32 -- max vol:128 x += 256 / 5512 -- middle c poke(0,mid(0,v+128,255)) serial(0x808,0,1) end end</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> https://www.lexaloffle.com/bbs/?tid=50098 https://www.lexaloffle.com/bbs/?tid=50098 Mon, 07 Nov 2022 18:18:16 UTC PICO-8 0.2.5 <img style="margin-bottom:16px" border=0 src="/media/1/boat3b_1.gif" width=384 height=384 alt="" /> <p>Hey All!</p> <p><a href="https://www.pico-8.com">PICO-8</a> 0.2.5 is now up on <a href="https://www.lexaloffle.com/games.php?page=updates">lexaloffle</a>, <a href="https://www.humblebundle.com/home/library">Humble</a>, <a href="https://lexaloffle.itch.io/pico-8">itch.io</a>, and for <a href="https://lexaloffle.com/bbs/?tid=34009">PocketCHIP</a> and web (<a href="https://pico-8-edu.com">Education Edition</a>).</p> <p>Edit: 0.2.5b is now up for Linux users who had trouble connecting to the BBS: <a href="https://www.lexaloffle.com/bbs/?pid=116441#p">https://www.lexaloffle.com/bbs/?pid=116441#p</a></p> <h2>Built-in Help</h2> <p>PICO-8 0.2.5 has built-in documentation on API functions and other topics. Type &quot;HELP&quot; at the prompt to see a list of topics in blue, and then e.g. &quot;HELP GFX&quot; to get more information about that thing.</p> <p>While in the code editor, you can also press CTRL-U to get help on whatever is under the cursor, including operators and Lua keywords.</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>&gt; HELP FILLP</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <img style="margin-bottom:16px" border=0 src="/media/1/help_fillp.png" width=384 height=384 alt="" /> <h2>String Indexing</h2> <p>Single characters can now be grabbed from strings using a familiar str[i] style syntax that means something similar to sub(str, i, i). The index is rounded down to the closest integer, and can be negative to index from the end of the string.</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>S=&quot;ABCDE&quot; S[2.6] -- &quot;B&quot; S[-2] -- &quot;D&quot; S[99] -- &quot;&quot;</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>Strings in Lua are immutable, so this can only be used in an expression (on the right hand side of an assignment). e.g. s[2] = &quot;z&quot; is not allowed.</p> <p>rnd(str) is now also accepted and returns a random character from string str.<br /> // update: this might not be true from 0.2.5c: <a href="https://www.lexaloffle.com/bbs/?pid=116415#p">https://www.lexaloffle.com/bbs/?pid=116415#p</a></p> <p>I've reverted sub() to pre-0.2.4 behaviour, which means that sub(&quot;abcde&quot;,2,_) returns &quot;bcde&quot;. 0.2.4 was returning single characters when the 3rd parameter is non-numeric, which is now much better handled by str[i] style indexing. (Apologies if you were already using this behaviour!)</p> <h3>Editor Features</h3> <p>gfx_grid_lines in config.txt now takes a colour if you'd like super-visible grid lines in the sprite editor:</p> <img style="margin-bottom:16px" border=0 src="/media/1/blue_gridlines.png" width=384 height=384 alt="" /> <p>Map selections are now on a separate floating layer:</p> <img style="margin-bottom:16px" border=0 src="/media/1/floating_selection.gif" alt="" /> <p>Pressing cursor keys in the map when nothing is selected now moves the camera, as I noticed some new users struggling to find/understand the pan tool and instead instinctively reaching for the cursor keys.</p> <h2>PICO1K Tools</h2> <img style="margin-bottom:16px" border=0 src="/media/1/pico1k_2022.png" width=512 height=194 alt="" /> <p>Some changes intended to be useful for <a href="https://itch.io/jam/pico-1k-2022">PICO1K Jam</a> starting in September:</p> <ul> <li> <p>ctrl-click on the compressed code capacity to get a realtime compressed size counter in bytes. This is the same size given with the INFO command, and when storing the cartridge as a tiny (code-only) binary rom with &quot;EXPORT -T FOO.P8.ROM&quot;</p> </li> <li> <p>&quot;EXPORT -T @CLIP&quot; can be used to get a hexdump of that same data written to clipboard. This is not very useful -- just a way to visualise exactly how much data is stored.</p> </li> <li>SAVE @URL saves 3 characters when there is no sprite data included by omitting the redundant &quot;&amp;g=&quot;.</li> </ul> <h2>Web-Exportable Audio</h2> <p>extcmd(&quot;audio_rec&quot;), extcmd(&quot;audio_end&quot;) can be used in web exports. The output file shows up as a downloadable .wav file. I'm hoping this will open the door for some cute sound generation tools.</p> <h2>Variable Width P8SCII Fonts</h2> <p>PICO-8 0.2.5 custom fonts can now specify how wide each character is when printed. This previously handled by doing things like injecting extra P8SCII commands into the output string, but this was cumbersome and meant that such fonts could not be shared as plain data. There were already pixel-wise cursor positioning commands in P8SCII, so I felt it makes sense to make this simpler. Also, I needed it for Picotron 8)</p> <p>To specify a 3-bit width adjustment and 1-bit y offset for character 16..255, the data at 0x5608..0x567f is used. These would otherwise be the bitmap data for characters 1..15 which are all control characters and thus never printed.</p> <p>Each 4-bit nibble in 0x5608..0x567f (low nibbles first) encodes the adjustments for one character:</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>bits 0x7: adjust character width by 0,1,2,3,-4,-3,-2,-1 bit 0x8: when set, draw the character one pixel higher (useful for latin accents)</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>An addition bit must be set at 0x5605 to enable size adjustments: poke(0x5605, 1). Otherwise the data at 0x5608..0x567f is ignored.</p> <p>To test this out, try loading the font snippet generation tool:</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>&gt; LOAD #FONT_SNIPPET</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>And then paste the following after the comment starting with &quot;font attributes&quot;</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>POKE(0x5605,1) -- turn on adjustments POKE(0x5634,0x70) -- set nibble for i to 0x7</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>You can now observe that the big &quot;i&quot; in &quot;quick&quot; near the top of the screen only has 1px of space to the right instead of 2px.</p> <p>Here's a helper function for setting the 4-bit nibble (val) for a given character (c):</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>FUNCTION ADJUST_CHAR(C, VAL) LOCAL ADDR = 0X5600 + ORD(C)\2 LOCAL SHFT = (ORD(C) &amp; 1) * 4 LOCAL MASK = 0XF &lt;&lt; SHFT POKE(ADDR, (PEEK(ADDR) &amp; ~MASK) | (VAL &lt;&lt; SHFT)) END</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <h2>File Listings (for Dev Tool Carts)</h2> <p>Locally running programs can now use ls(path) to get a listing of any local directory. Entries that end with a &quot;/&quot; are directories. Use stat(124) to get the current path.</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>PATH = STAT(124) -- E.G. /FOO/ FILES = LS(PATH) FOR F IN ALL(FILES) DO COLOR(F[-1] == &quot;/&quot; AND 14 OR 6) PRINT(F) END </pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>BBS cartridges are not able to access local file listings -- this is intended for developing tools to use locally. For example: a utility that makes it easier to browser cartridge data and copy between cartridges using reload() / cstore() which are able to read and write any local cartridge file using the 4th parameter.</p> <h2>Keyboard Scancode Remapper</h2> <p>If you're having trouble getting PICO-8 to detect some keys (especially numeric keypad keys / unusual laptop layouts), there is now a built-in tool for mapping those keypresses to something SDL2 understand. Run PICO-8 from commandline with -scancodes:</p> <p>pico8 -scancodes</p> <p>Or use some other tool to find out which scancodes the keys in question are producing, and then map them to something else in config.txt (look for map_scancodes)</p> <h2>Dynamic Libcurl Support (Linux)</h2> <p>The 32-bit and 64-bit linux builds now try to dynamically load libcurl by default in order to make bbs requests (e.g. download carts from splore). This will hopefully make installing on some platforms easier, including Steam Decks. When libcurl.so is not available, it drops down to the old wget behaviour (requires wget to be installed). If this works well, I'll also see about moving to the same scheme for raspi and mac builds.</p> <h2>More Doodlemud</h2> <p>Doodlemud is a toy multiplayer game designed to test the backend services that PICO-8's high score table (and future projects) will be based on. Try it here: <a href="https://www.doodlemud.com/#skatepark">https://www.doodlemud.com/#skatepark</a></p> <p>This version is running on a completely new backend, custom written from scratch as a self-contained program using libwebsockets. My first attempt was built out of opensource components (nchan, redis, openresty, nginx), but because of PICO-8's unusual requirements, this was making customisation, debugging and devops more complex that it needed to be. Sometimes just reinventing the wheel with a bespoke C program is still the right approach even in the world of web services. There are currently 5 nodes running which are selected based on the user's location when making a new room:</p> <img style="margin-bottom:16px" border=0 src="/media/1/130_kurage_map.png" alt="" /> <h2>Next Steps</h2> <p>It looks like PICO-8's 0.2.5 API is unlikely to change now (really, this time!), and the next task is to port the new additions to <a href="https://www.voxatron.com">Voxatron</a> for Voxatron 0.3.7. After that I'll continue working on the BBS functionality needed to log in from PICO-8 and submit high scores. If you're curious, you can see the current plan for the SCORESUB() function by typing HELP SCORESUB.</p> <p>That's all for now -- I hope you enjoy the update and as usual let me know here or in <a href="https://www.lexaloffle.com/bbs/?cat=7#sub=6">bugs/</a> if you find anything spooky going on.</p> <p>Full Changelog:<br /> <div><div><input type="button" value=" Show " onClick="if (this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display != '') { this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = ''; this.innerText = ''; this.value = ' Hide '; } else { this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = 'none'; this.innerText = ''; this.value = ' Show '; }"></div><div><div style="display: none;"><br /> v0.2.5</p> <p>Added: Help topics. Use help command, or ctrl-u in code editor to get help on whatever is at the cursor.<br /> Added: (html exports / bbs) downloadable .wav export using extcmd(&quot;audio_rec&quot;), extcmd(&quot;audio_end&quot;)<br /> Added: inext (to match next). -&gt; can do: for i,v in inext,tbl do ... end<br /> Added: floating selection layer in map editor (solves various bugs and undo / selection issues)<br /> Added: ~ can be used as xor instead of ^^ (same as Lua 5.3/5.4)<br /> Added: When running a program locally, ls() can now take a directory name; use stat(124) to get pwd<br /> Added: Variable width P8SCII fonts<br /> Added: ctrl-click on compressed capcity (bottom right) to get realtime updates of compressed size in bytes<br /> Added: export -t @clip to get a hexdump of compressed code section copied to clipboard<br /> Added: pico8 -scancodes and map_scancodes (config.txt) for manually mapping keys to alternative scancodes<br /> Added: sub(str,pos,pos) can be written as str[pos].<br /> Changed: host_framerate<em>control 1 (config.txt) now means &quot;let PICO-8 decide&quot;; is disabled for Mac/Win/Linux<br /> Changed: in map editor, pan with cursor keys when nothing is selected<br /> Changed: use scancodes for sfx navigation (US:-=</em>+) and spd change (US:,.&lt;&gt;) to avoid azerty collisions<br /> Changed: gfx_grid_lines in config.txt is taken to be a colour for the grid lines (16 for black)<br /> Changed: can ctrl-h in gfx editor to toggle hex mode (sprite index shown in hex; map vals shown)<br /> Changed: '-' allowed in filenames when not first character<br /> Changed: linux builds use libcurl.so for bbs requests, or drops down to wget on failure to dlopen<br /> Changed: increased maximum gif len for web exports to 30 seconds<br /> Changed: peek/poke can now read/write up to 32767 values (was 8192)<br /> Changed: web player default gif len is 16 seconds (was 8)<br /> Changed: sub(str, pos, nil) returns whole string (pre-0.2.4 behaviour). For single chars, can now use str[pos].<br /> Fixed: Windows reserved filenames (lpt1, com1 etc) are accepted<br /> Fixed: Nested coroutines unexpectedly end when interrupted by reaching end of frame<br /> Fixed: print() colour is remapped twice when set in parameter // pal(6,7) pal(7,8) print(&quot;white&quot;,6)<br /> Fixed: circ() breaks on 32-bit builds, with radius &gt; 1024<br /> Fixed: ctrl-c to copy commandline error message does not encode glyphs as unicode<br /> Fixed: LS command not resolving relative paths<br /> Fixed: twitter char count for chr(127) ○ should be 2 (was 1) and chr(149) ˇ should be 1 (was 2)<br /> Fixed: colour parameter not converted from string in rect, rectfill, pset (regression from 0.2.2)<br /> Fixed: ord(&quot;foo&quot;, 1, 0) returns &quot;too many ord results&quot; -- should return nothing<br /> Fixed: save @url includes ?g= when no gfx data (is redundant)<br /> Fixed: (web export) html pause button does not show up as btnp(6) / btn(6)<br /> Fixed: (web export) codo_textarea triggering Mac accent character selector even when cart doesn't use clipboard<br /> Fixed: save @url failing when encoded length is &gt; 2000 chars long instead of &gt; 2040 charss<br /> Fixed: can enter an illegal note (e-5) in sfx editor<br /> </div></div></div></p> https://www.lexaloffle.com/bbs/?tid=49075 https://www.lexaloffle.com/bbs/?tid=49075 Sun, 28 Aug 2022 10:32:51 UTC PICO-8 0.2.4c <p><a href="https://www.pico-8.com">PICO-8</a> 0.2.4c is now up on <a href="https://www.lexaloffle.com/games.php?page=updates">lexaloffle</a>, <a href="https://www.humblebundle.com/home/library">Humble</a>, <a href="https://lexaloffle.itch.io/pico-8">itch.io</a>, and for <a href="https://lexaloffle.com/bbs/?tid=34009">PocketCHIP</a>.</p> <p>This is mostly a bug-fixing update; you can see the main 0.2.4 change notes in the <a href="https://www.lexaloffle.com/bbs/?tid=45538">0.2.4 thread</a>.</p> <h2>URL Cartridges</h2> <p>With the release of <a href="https://www.lexaloffle.com/bbs/?tid=47278">PICO-8 Education Edition</a>, it is now possible to encode cartridges into a 2040-character URL that runs it in a web version of PICO-8's editing tools. Only the code and graphics sections are stored.</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>&gt; SAVE @URL COPIED URL TO CLIPBOARD 265 / 2040 CHARS</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <h2>Tiny Cartridges</h2> <p>When exporting cartridges to .p8.rom format (the raw 32k block of data that is encoded inside .p8.png argb data), 0.2.4c allows only the code section to be stored using the -t (for tiny) switch:</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>&gt; EXPORT -T TINY.P8.ROM WRITING 154 BYTES (CODE ONLY)</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>You should get a file that is exactly as large as the compressed code size reported by INFO. When using LOAD, that file will be loaded into the code section, and the other sections reset to their default states.</p> <p>There isn't much practical use for tiny .P8.ROM files, but I think it is nice to be able to store a tiny program in its true tiny form on disk.</p> <p>On the subject of tiny cartridges, for those making <a href="https://twitter.com/search?q=%23tweetcart&amp;amp;src=typed_query">tweetcarts</a>, you can now ctrl-click on the character count to get a twitter-character count which counts most (but not all!) glyphs as 2 characters.</p> <h2>Metadata</h2> <p>This is another technical one. 0.2.4c introduces a new metadata section to the .p8 file format suggested by <a href="https://www.lexaloffle.com/bbs/?uid=47515"> @SquidLight</a> that can be used by external tool authors. Sections with a heading of <code>\n__meta:somestring__\n</code> are preserved by PICO-8, but not (yet?) utilised by PICO-8 itself. So tool authors can add data to .p8 files by choosing their own meta:label without needing to stuff it into comments, or risk losing data the next time the file is saved by PICO-8 or another tool.</p> <p>More details: <a href="https://www.lexaloffle.com/bbs/?tid=47063">https://www.lexaloffle.com/bbs/?tid=47063</a></p> <h2>Full Changelog</h2> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>v0.2.4c Added: save @url -- stores code + gfx as a URL if it can be encoded in 2040 characters Added: html exports store volume/mute and other settings Added: ctrl-g in sprite editor to toggle grid lines when zoomed in Added: IMPORT -L FOO.PNG to import a 128x128 png to the cartridge label Added: EXPORT -L FOO.PNG to export a 128x128 png of the cartridge label Added: EXPORT -T FOO.P8.ROM to export only code section (t for tiny) Added: ctrl-click on character count (bottom right) to see the twitter count (glyphs count as 2) Added: __meta:*__ section to .p8 format -- can be used by external tools to store custom data Added: extcmd(&quot;audio_rec&quot;) works from exported binaries, and with custom exported filenames Added: read_controllers_in_background in config.txt (0 by default) Changed: .p8.rom files that are 0x3d00 bytes or less are loaded into code section Changed: saved filenames can not include gylphs, or any of !&quot;#$%&amp;'()*+,-:;&lt;=&gt;?[\]^`{|}~ Fixed: can't drag and drop png into sprite editor Fixed: binary exports: ctrl-r causes crash when there is no whitespace at end of source code Fixed: Using -run switch to launch a cart that fails to run -&gt; get stuck in boot screen. Fixed: selection after ctrl-a reports length chars+1 Fixed: draw palette is not observed after changing colours using p8scii control characters Fixed: music playback does not follow cursor after first pattern change (regression in 0.2.4b) Fixed: transform_screen (config.txt) not observed by pause menus and other overlayed elements Fixed: Double-clicking sfx thumbnail (in sfx overview screen) only works after playing music Fixed: Pressing [a] to release looping sfx in sfx editor is broken Fixed: sfx(46)..sfx(56) return -1 immediately after playing music but before host OS has called audio mixer Fixed: Tokens counted as 2 instead of 1: ..= ^= &gt;&gt;&lt;= &lt;&lt;&gt;= Fixed: Negative number counted as 2 tokens instead of one when preceeded by: \ &amp; | ^^ &lt;&lt; &gt;&gt; &gt;&gt;&gt; &gt;&gt;&lt; &lt;&lt;&gt; Fixed: tostr(tbl) / print(tbl) acts like tostr(tbl, 1) when tbl has a metatable Fixed: ?&quot;\tx&quot; does not advance to next tab stop Fixed: ?&quot;a\*5\nb&quot; does not repeat newline 5 times Fixed: exported label alpha is 0 for colour 0</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> https://www.lexaloffle.com/bbs/?tid=47328 https://www.lexaloffle.com/bbs/?tid=47328 Sun, 10 Apr 2022 22:32:30 UTC PICO-8 Education Edition for Web <img style="margin-bottom:16px" border=0 src="/media/1/pico8_edu_release.gif" width=512 height=512 alt="" /> <p>\o/</p> <p>Say hi to the newest member of the <a href="https://www.pico-8.com">PICO-8</a> family! A free, web-based, account-less version of the console making it a more accessible way to learn how to program, push pixels and write chip tunes. It comes with a fully functional set of cartridge editing tools, and can load and save .p8 and .p8.png files to and from your local drive (as well as storing them to a temporary filesystem in the browser's cache).</p> <hr /> <p>Just run it from any browser that has a keyboard + mouse attached:</p> <p><a href="https://www.pico-8-edu.com">www.pico-8-edu.com</a></p> <hr /> <p>If you are new to <a href="https://www.pico-8-com">PICO-8</a> you can find a <a href="https://www.lexaloffle.com/pico-8.php?page=resources">manual and tutorials</a> on the <a href="https://www.pico-8.com">main site</a>, or click on the blue bunny for some tips. Here's a 2-minute GIF showing the creaton of a simple PICO-8 cartridge from scatch:</p> <img style="margin-bottom:16px" border=0 src="/media/1/duck_dance.gif" width=256 height=256 alt="" /> <p>In addition to the standard 32k .p8.png cartridges, PICO-8 Education Edition also comes with a new cartridge format: the URL CARTRIDGE. GFX and CODE can be encoded as a URL string, as long as it fits within 2040 characters. Here's one I prepared earlier:</p> <p><a href="https://bit.ly/3uWP0YF">URL CART DEMO</a></p> <p>// EDIT: changed to a bit.ly url so that the BBS doesn't munge it!</p> <p>To generate a url cartridge, use <code>SAVE @URL</code> and you should see the address bar change. I'm hoping this will make it easier to pass snippets around, and will add a new dimension to code size golfing and <a href="https://twitter.com/search?q=%23tweetcart&amp;amp;src=typed_query">tweetcart</a>'ing. And of course, it is still possible to capture screenshots (ctrl-6) and gifs (ctrl-8, ctrl-9).</p> <p>Although exporters and SPLORE (the built-in cartridge browser) are not included, larger cartridges can also be shared either as .p8.png files or by first uploading to the <a href="https://www.lexaloffle.com/bbs/?cat=7">BBS</a> as usual (publicly listed or semi-private) and then giving students the cartridge id to load directly from their machine:</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>LOAD #MY_TUTORIAL_ID</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>I hope you enjoy it, and I'll be back soon with some 0.2.4c binaries to match the web version!</p> <p>-- zep</p> https://www.lexaloffle.com/bbs/?tid=47278 https://www.lexaloffle.com/bbs/?tid=47278 Wed, 06 Apr 2022 20:21:33 UTC PICO-8 0.2.4b <p>Hi All</p> <p><a href="https://www.pico-8.com">PICO-8</a> 0.2.4b is now up on <a href="https://www.lexaloffle.com/games.php?page=updates">lexaloffle</a>, <a href="https://www.humblebundle.com/home/library">Humble</a>, <a href="https://lexaloffle.itch.io/pico-8">itch.io</a>, and for <a href="https://lexaloffle.com/bbs/?tid=34009">PocketCHIP</a>.</p> <p>This is mostly a bug-fixing update; you can see the main 0.2.4 change notes in the <a href="https://www.lexaloffle.com/bbs/?tid=45538">0.2.4 thread</a>.</p> <p>There are a few handy editor features though; here's a demo of setting animation loops: press l to start and end, and then -,+ or q,w or a,z (for azerty keyboards) to switch frames. This also works at different sprite selection sizes (shift-click and drag a selection from the spritesheet). This gif also shows using ctrl-b to &quot;paste big&quot; multiple times.</p> <img style="margin-bottom:16px" border=0 src="/media/1/jelpi_anim_demo3.gif" alt="" /> <p>Full 0.2.4b changelog:</p> <p>Added: l in sprite sheet navigator to set loop start / end points (then q,w or a,z to navigate)<br /> Added: ctrl-b in gfx editor to paste 2x2 original size (&quot;paste big&quot;)<br /> Added: DEL / backspace to clear selected region in gfx / map editors, and ctrl-x to cut<br /> Added: aggressive_backups option in config.txt (off by default)<br /> Added: transform_screen in config.txt to globally rotate / flip the video output<br /> Added: stat(57) (boolean) true when music triggered by music() is playing or about to start<br /> Changed: memset() faster than using peek4/poke4; now 2 cycles per byte at 8MHz (was 4)<br /> Changed: &quot;running at &lt; 30fps&quot; warning on boot now only for raspi builds, and w/ higher tolerance<br /> Changed: Controller inputs are accepted even when PICO-8 is not the foreground application<br /> Changed: Map can be located at 0x1000 .. 0x2f00 using poke(0x5f56, 0x10) .. poke(0x5f56,0x2f)<br /> Changed: Dotty text mode is now &quot;\^=&quot; (&quot;Stripey&quot;) instead of &quot;\^.&quot; // #gunayawuho #klax #impossible<br /> Fixed: (not confirmed) crash causing 0-byte .p8 when audio mixer is called during save / run<br /> Fixed: preprocessor not counting comments as white space; should allow: &quot;.. end--[[]]if ..&quot;<br /> Fixed: pal(nil) behaving the same way as pal(0); should be same as pal() // broke #rtype-2<br /> Fixed: note entry in sfx tracker is silent after running cartridge until pressing space to playback<br /> Fixed: sub(&quot;abc&quot;, 4, 4) returns &quot;c&quot; (regression in 0.2.4)<br /> Fixed: SPLORE cart update prompt does not appear when server replies too quickly (race condition)<br /> Fixed: SPLORE cart update prompt only checks version once per session (can't refresh until it shows up)<br /> Fixed: EXPORT command does not flatten includes when exporting to .p8.png / .p8.rom format<br /> Fixed: EXPORT command discards source code changes since last run or load<br /> Fixed: printing a one-off glyph using &quot;\^.&quot; terminates the whole string when last byte is a zero<br /> Fixed: Crash when loading a cart with fewer tabs, then creating a new tab and pasting.<br /> Fixed: . command runs at 30fps even for a 60fps cart (-&gt; _update60 is called twice, _draw once)<br /> Fixed: Custom menu items become broken after suspending a cart, entering a lua command, and then resuming<br /> Fixed: memset() with a non-zero value in shared memory region (0x1000..0x1fff) causes garbage corresponding mget() values<br /> Fixed: web player/exports: ctrl-r causes erroneous &quot;external changes reloaded&quot; message and code corruption</p> https://www.lexaloffle.com/bbs/?tid=46333 https://www.lexaloffle.com/bbs/?tid=46333 Thu, 27 Jan 2022 21:01:24 UTC Holiday Jumper <p> <table><tr><td> <a href="/bbs/?pid=103519#p"> <img src="/bbs/thumbs/pico8_jumper-3.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=103519#p"> Holiday Jumper</a><br><br> by <a href="/bbs/?uid=1"> zep</a> <br><br><br> <a href="/bbs/?pid=103519#p"> [Click to Play]</a> </td></tr></table> </p> <p>Happy Holidays, everyone! This cartridge is my addition to the <a href="https://www.lexaloffle.com/bbs/?tid=45525">2021 PICO-8 Advent Calendar</a>, which you should also check out if you haven't already!</p> <img style="margin-bottom:16px" border=0 src="/media/1/holiday jumper_0.gif" alt="" /> <h3>Controls</h3> <ul> <li>LEFT/RIGHT: Slow down or speed up. It is vital to get the right speed for some jumps</li> <li>O (Z/C): Jump. You can get more height by going fast and/or holding the button longer.</li> <li>X: To restart after crashing.</li> </ul> <p>This game gets reasonably tricky; especially from level 3. But if you can reach the end, you'll get a simple ending along with your total time and number of restarts. The randomish elements in the game (you'll see what I mean) are actually deterministic, so it's possible to form strategies and optimise your time, if that's your cup of tea.</p> <p>Anyway, I hope you enjoy it even if only as a crashing-into-trees simulator.</p> <p>This cartridge was heavily inspired by <a href="https://en.wikipedia.org/wiki/SkyRoads_(video_game)">Skyroads</a> and <a href="https://www.lexaloffle.com/bbs/?uid=26764"> @jackson_allen</a>'s most excellent <a href="https://www.lexaloffle.com/bbs/?tid=30417">Christmas Sweater Generator</a></p> <img style="margin-bottom:16px" border=0 src="/media/1/christmas sweater generator 1 0_0.gif" alt="" /> https://www.lexaloffle.com/bbs/?tid=45856 https://www.lexaloffle.com/bbs/?tid=45856 Sat, 25 Dec 2021 11:36:42 UTC PICO-8 0.2.4 <img style="margin-bottom:16px" border=0 src="/media/1/fireflies_024.gif" width=512 height=512 alt="" /> <p><a href="https://www.pico-8.com">PICO-8</a> 0.2.4 is now up on <a href="https://www.lexaloffle.com/games.php?page=updates">lexaloffle</a>, <a href="https://www.humblebundle.com/home/library">Humble</a>, <a href="https://lexaloffle.itch.io/pico-8">itch.io</a>, and for <a href="https://lexaloffle.com/bbs/?tid=34009">PocketCHIP</a>.</p> <p>This update is another attempt at freezing the API before the last feature update (0.3 -- high scores), but let's see how it goes! 0.2.4 also includes an important security update (see below for details), so please do consider updating. Cartridges posted after this release post will only be visible from SPLORE when running 0.2.4 or later.</p> <h2>64k RAM</h2> <p>64K of Base RAM is now enabled by default. In 0.2.4 it is safe to PEEK/POKE/MEMCPY memory 0x8000 and above (i.e. -0x8000 .. -1) without setting the hardware extension bit at 0x5f36.</p> <p>Because PICO-8's numbers only cover 0xFFFF, this means it is impossible to poke or memcpy out of range. The original motivation for having 32k by default was to give new programmers some concept of illegal memory operations, and as an extra form of feedback when code isn't working as expected. But over time, these reasons haven't proved as useful as the benefits of allowing 64k by default. Additionally, 0.2.4 introduces the first feature that explicitly uses the upper 32k section (see Big Maps).</p> <h2>Video Remapping</h2> <p>The video memory sections can now be mapped to each other, allowing the screen to be used as if it were the spritesheet, and/or to draw to the spritesheet as if it were the screen.</p> <p>The mapped address for the spritesheet is stored at 0x5f54, and the mapped address for the screen is stored at 0x5f55. There are only 2 legal values that should be poked to each address: 0x00 (which means map to 0x0000), and 0x60 (map to 0x6000). This gives 4 combinations:</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>0x00, 0x60: default settings 0x60, 0x60: gfx functions (spr, circ..) use the screen as sprite data 0x00, 0x00: gfx functions all draw directly into the spritesheet 0x60, 0x00: swap spritesheet and screen</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>Here's an example of re-colouring and zooming a section of the screen, pasted in at the end of jelpi.p8's _draw() function. This was possible in earlier versions, but required a lot of memcpy()'ing to backup, use and then restore contents of the spritesheet:</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>-- lighter colours; no transparency pal({[0]=1,5,13,13, 9,13,7,7, 14,10,15,11, 6,6,15,15}) palt(0) -- set the screen memory as the spritesheet -- and stretch screen-&gt;screen poke(0x5f54, 0x60) sspr(48,80,32,32, 32,32,64,64) poke(0x5f54, 0x00) pal() -- return to defaults</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <img style="margin-bottom:16px" border=0 src="/media/1/jasper_remapped.gif" alt="" /> <h2>Big Maps</h2> <p>Similar to gfx memory mapping, the map can now be placed at address 0x8000 and above (in increments of 0x100). This gives 4 times as much runtime space as the default map, and an additional POKE is provided to allow customisable map sizes.</p> <p>Legal values are 0x20 (the default) and 0x80 and above. There are two pokes you need:</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>poke(0x5f56, 0x80) -- set the map to 0x80. Default is 0x20 poke(0x5f57, 0) -- set the width of the map (0 means 256). Defaults to 128</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>The height of the map is determined by how much data is available in the memory section. So in this case, there is is 32k available divided by 256, which gives a map height of 128 cels -&gt; 256x128.</p> <p>Note that the map editor still always writes and loads at 0x2000. This feature doesn't come with extra cartridge space to match! So to use 0x8000 and above, you'll need to manually mset() or memcpy() some map data. This feature will be most useful for carts that procedurally generate their maps or have some custom data storage scheme.</p> <p>The map address is observed by all map functions: mget(), mset(), map(), tline()</p> <h2>One-off Characters</h2> <p>P8SCII character data can be specified and printed in-line using &quot;\^.&quot; followed by 8 bytes of raw binary data, or &quot;\^:&quot; followed by 8 2-digit hexadecimal values. The data format is the same as custom fonts; each byte specifies a row of 1-bit pixel values, with the low bit on the left.</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>?&quot;\^.$|へ|&gt;○&sup1;⁶&quot; ?&quot;\^:247cb67c3e7f0106&quot; </pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <img style="margin-bottom:16px" border=0 src="/media/1/one_off_char_3.png" alt="" /> <h2>Audio Sync</h2> <p>STAT(46)..STAT(56) can be used instead of STAT(16)..STAT(26) to query the state of the sound system with more precision. Although there are many carts that managed fine with the old STAT() calls, it required a bit of fiddling and data smoothing to get right, derived from whatever state the mixer is in at the start of each frame (which only changes ~20 times a second, depending on the host platform and phase of the moon).</p> <p>The new version (STAT 46..56) works by storing a history of sound mixer states at each tick, along with timestamps for sound driver mix requests, to estimate which state snapshot is currently audible at any moment in time. It's still not perfect, but requires less to work to get pretty good sync going.</p> <p>Test cart: LOAD #AUDIO_SYNC_TEST</p> <h2>API Changes</h2> <p>Some small conveniences:</p> <p>CHR() can now take multiple arguments to build a string:</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>&gt; ?chr(104,101,108,108,111) hello</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>SUB() can take nil or _ as the last argument to return a single character (instead of the rest of the string). This is useful when the second parameter (the index) is some long expression that you don't really want to repeat in the last parameter, or go to the trouble of assigning a temporary variable to.</p> <p>PAL(N) can be used to reset one of the three palettes to their default state (0 draw palette, 1 display palette, 2 secondary palette).</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>&gt; sub(&quot;hello&quot;, 3, _) l &gt; sub(&quot;hello&quot;, 3) llo</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <h2>Cartridge Formats</h2> <p>The .rom.p8 format (a raw 32k block of cart data) can now be used by CSTORE(), RELOAD() and in multicarts. This should make it easier to generate cartridge data using external tools without needing to jump through the hoops of writing to .p8 / .p8.png format.</p> <p>On a related note, the EXPORT command can now also be used with any cartridge format. So, to convert between cartridge formats from commandline, the -export switch can be used (<code>pico8 foo.p8.png -export foo2.p8.png</code>). From inside PICO-8, it is also a handy way to save a copy of the current working cartridge without altering the current working filename:</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>&gt; EXPORT COPY_TO_UPLOAD_TO_BBS.P8.PNG</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <h2>64-bit Raspberry Pi Builds</h2> <p>The file archive ending _raspi.zip now includes a build for the 64-bit version of Raspberry Pi OS called pico8_64. Exported binaries also have a matching file (e.g. mygame_64).</p> <h2>Security Patch</h2> <p>PICO-8 0.2.3 had quite a serious security flaw affecting Mac OS and Linux machines, that allow arbitrary commands to be injected into LOAD(&quot;#...&quot;) calls and executed on the host machine with the same privileges as PICO-8. PICO-8 0.2.4 fixes this in two places: the illegal cartridge ID is not allowed to be processed in the first place, and the URL used to fetch cartridges / listings is only allowed to contain a limited subset of characters. Earlier versions only had the second check, which was faulty.</p> <p>As far as I can tell, there are no BBS cartridges that have used this exploit, and as a precaution SPLORE will no longer allow cartridges newer than this post to be listed to older versions of PICO-8.</p> <p>So please do update to 0.2.4 to ensure you are not affected by this vulnerability, including for cartridges obtained from somewhere outside of SPLORE.</p> <h2>Server Test: Doodlemud</h2> <p>The last remaining part of PICO-8's api is SCORESUB() -- a simple api function for submitting highscores, but with some internal complexity. I've set up some new infrastructure for this to be reasonably future-proof and scalable, and a simple game for battle-testing it. You can try it here:</p> <p><a href="https://www.doodlemud.com/#p8024">https://www.doodlemud.com/#p8024</a></p> <p>Doodlemud is a multiplayer world-building / exploration game where each player can switch between drawing each room and being a player in it. This test requires a keyboard and mouse (no touch / tablet support); press cursors to move around, and G to toggle gravity for everyone in that room. Feel free to change the url to start new empty worlds (any alphanumeric name after the hash is ok), but keep in mind that it is experimental, and all of the data will be erased when it gets updated!</p> <h2>ASCII Manual</h2> <p>The .txt version of the manual is back! It is included in the archives, and you can find it on the <a href="https://www.lexaloffle.com/pico-8.php?page=resources">Resources Page</a>. The text and html versions of the manual are now both generated from the same source file, so should always be in sync.</p> <h2>Changelog</h2> <p>You can find the full changelog here:</p> <p><a href="https://www.lexaloffle.com/dl/docs/pico-8_changelog.txt">https://www.lexaloffle.com/dl/docs/pico-8_changelog.txt</a></p> https://www.lexaloffle.com/bbs/?tid=45538 https://www.lexaloffle.com/bbs/?tid=45538 Fri, 03 Dec 2021 07:22:25 UTC Squiddy (PICO-1k Jam) <img style="margin-bottom:16px" border=0 src="/media/1/sq_header.png" alt="" /> <p> <table><tr><td> <a href="/bbs/?pid=98017#p"> <img src="/bbs/thumbs/pico8_squiddy-0.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=98017#p"> squiddy (1k jam)</a><br><br> by <a href="/bbs/?uid=1"> zep</a> <br><br><br> <a href="/bbs/?pid=98017#p"> [Click to Play]</a> </td></tr></table> </p> <p><a href="/media/1/sq_cover.png"><img style="margin-bottom:16px" border=0 src="/media/1/sq_cover.png" width=340 height= 340 alt="" /></a><a href="/media/1/squiddy_instructions.jpeg"><img style="margin-bottom:16px" border=0 src="/media/1/squiddy_instructions.jpeg" width=340 height= 340 alt="" /></a></p> <p>(click to expand)</p> <p>Heeey, it's Squiddy! This is a game made in 1017 bytes for <a href="https://itch.io/jam/pico-1k">PICO-1k Jam</a>, co-designed and pixelled by <a href="https://www.lexaloffle.com/bbs/?uid=11378"> @castpixel</a> (<a href="https://twitter.com/castpixel">twitter</a>). This is our second production as pod; you can find the first one <a href="https://www.lexaloffle.com/bbs/?pid=76564">here</a>. Squiddy is also up on <a href="https://castpixel.itch.io/squiddy">itch</a>.</p> <h2>Technical Details</h2> <p>1024 bytes is an interesting size limit for a game; it's large enough to try for some relatively detailed game logic or visuals, but small enough that you need to execute some weird programming tricks and design pivots to get everything to fit. If you found this post because you heard that PICO-8 is a nice introduction to game programming, I apologize for the following code snippets! First up, here is the full source code for the game that includes the graphics and map data. It can be pasted into PICO-8 0.2.3 or later:</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>➡️=0t=8⬇️=7for x=0,3800do ➡️-=1if(➡️&lt;1)➡️=2r=3⬇️=7-⬇️ while r&gt;2do r=ord(&quot;○ュ?\0゜ョヤャ◝◝⁷ツん&sup1;ュ=◝に◝+ンョャヤ○る&sup3;ユ\n &lt;◝エ𝘤ムもにュよ◝トラ⁙⁴よ░&sup2;リムリᵇ&sup3;ト■𝘨○ワ;◝エらョ0\0pクシチ◜◝=ュoれ/ウワ◝モャいユ𝘪ゆ?=0◝cりdオトは⁷ト?⁵\0𝘴リ◆○☉6サ&sup1;6ア?ュ◝❎。。ユユ◝ャヤ2v\0q○&sup1;\0ワw3v\0001よ&sup1;\0◝?𝘰v⁴ャ゜⁴ら█pタp⁵ュ?オ; &lt;○○ヨ◝oに◝𝘰ュ?1░ろヲア◝ᵇp○\0s&sup3;ヲュひ\0|れツ◝リツ𝘰゜6ト⁴ュ?p◜◝モpᶜオん▶○◜ャ\r○𝘣◝▶トリに1◝⁷ョ_ンん゜ョょ737⬇️○ョ&sup1;ュのら◜-エs○ユト⁴らメ\0&sup3;&bull;~◝エろヨ/゜3\0な?𝘯ュ◝よ▮ラヨsクろ?リトンミエセろ⁵ᵇムり3オ◝𝘮rユ⁷ワ&gt;pンᶠ゜シてン&gt;ナレ◝𝘰⁙ュuワ◝シ◝1゛ュ4チ◝?◝◝𝘰\0゜ᵇユ◝エ◝4◀0○ ◝◝◝◝◝\0ら𝘬\0&quot;,t\8)&gt;&gt;t%8&amp;3t+=2➡️+=r end sset(x%95,x\95,⬇️)end o=128w=256f=0r=4128🐱=cos ➡️=0 ❎=64🅾️=r*2s=spr::_::t+=.03camera(❎,🅾️)map()v=0for i=0,t/2do x=i\32y=i%32v/=2v+=sget(r%o+x/4,r\o+y/4-🐱(i/870)/2)&amp;4mset(x,y,v)p=i%4y=i\4*5%31 if(mget(x,y+1)==4)s(0,x*8+🐱(p/4-t),y*8-p*4) if(r%5==2and i&lt;o)s(i&amp;2,-t*i%w,i*i%w+🐱(i/9+t)*3)➡️-=1&gt;&gt;12 end if(r==4136)s(8,92,112,5,5) s(20,o+🐱(t/2)*9,90+r+🐱(t)*5,1.5,2)b=btn()n=b&amp;32f=f/2+n/20k=b%4\2-b%2if(f&gt;n)➡️+=f*k ⬇️-=f f=0 ❎+=➡️ 🅾️+=⬇️ ➡️=-➡️ ⬇️=-⬇️?&quot;ᶜe\^wfin &hearts;&quot;,108,60+r if(mget(❎/4,🅾️/4)&lt;1)➡️*=-.95⬇️=.05-⬇️*.9 r+=(❎\o+🅾️\o*o)*8❎%=o 🅾️%=o s(16+(f&amp;2)+k%2*32,❎*2-8,🅾️*2-8,2,2,k&lt;0)?&quot;⁶1⁶c&quot; goto _</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <h2>Sprite Storage</h2> <p>Here's the 95x40 spritesheet (hidden for spoilers).</p> <p><div><div><input type="button" value=" Show " onClick="if (this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display != '') { this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = ''; this.innerText = ''; this.value = ' Hide '; } else { this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = 'none'; this.innerText = ''; this.value = ' Show '; }"></div><div><div style="display: none;"></p> <img style="margin-bottom:16px" border=0 src="/media/1/nop8_ss.png" alt="" /> <p></div></div></div></p> <p>The sprites and map data is stored in the long string passed to the ord() function. The challenge was to compress the data in a way that the decoder + compressed data would be smaller than the raw uncompressed sprite data. This is hard to do with a small amount of 1-bit graphics!</p> <p>The format we settled on quite early is a variant of RLE (Runtime Length Encoding -- storing the lengths of spans of the same colour) with an interesting constraint: the smallest span length must be 2 pixels. This means that it is impossible to have a single-pixel vertical line, but thin horizontal lines are ok. It is also quite different from using double-width pixels, as spans can stop and start anywhere.</p> <p>Each span length is stored as a sequence of 2-bit values. Each value is added to the span length, and the sequence is finished when the value is not 0b11 (3). This means that that 2-pixel spans take 2 bits to store (the worst case -- same as raw), 4-pixel spans also take 2 bits (the best case -- half the data needed), and for very long spans the data compresses to around 2/3 of the original size. The number of bits needs to store a span length jumps up every 3 values:</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>2 pixel span: 00 3 pixel span: 01 4 pixel span: 10 5 pixel span: 11 00 &lt;- 2 more bits because the first value is 0b11 6 pixel span: 11 01 7 pixel span: 11 10 8 pixel span: 11 11 00 ...</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>The code for the decoder is 106 characters after re-using some game state variables, and the sprite data compresses to 340 bytes, which becomes 358 characters with the required escape codes to store it in the source code (e.g. value 0 becomes &quot;\0&quot;). This gives a total of 464 characters -- around 50 less than using raw data + some code to transfer it to the sprite sheet. Worth it!</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>-- decode sprite data v=0 -- last read 2-bit value l=0 -- length of span i=8 -- input data position in bits c=7 -- current span colour for x=0,3800 do -- for each spritesheet pixel l-=1 -- one less pixel left to draw of the current span -- read the next span length (l) if ran out of pixels to write -- ord() grabs an 8-bit value from the data string if(l&lt;1) l=2 r=3 c=7-c while r&gt;2 do r=ord(data_string,i\8)&gt;&gt;i%8&amp;3 i+=2 l+=r end pset(x%95,x\95,c) -- set a single pixel end</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <h2>Map Data</h2> <p>The map is generated from sprite pixels: each pixel in the spritesheet corresponds to a 4x4 block of map tiles. This allows for a 2x2 screen room to be described by an 8x8 pixel sprite. This produces a very blocky world however, so the sampling position in the spritesheet is also distorted by a sine wave that is chosen to line up between neighboring rooms, so that it is not possible to enter the next room and already be inside a wall. Here is an example of a room without and with distortion:</p> <p><img style="margin-bottom:16px" border=0 src="/media/1/squiddy_5.png" width=384 height=384 alt="" /><img style="margin-bottom:16px" border=0 src="/media/1/squiddy_4.png" width=384 height=384 alt="" /></p> <p>Apart from obscuring the coarse resolution of the source data, using this distortion had some other nice side-effects. It produces local organic details like a single protruding tile at the edge of some 4x4 clusters, and larger features like the raised 'platform' that the statue is sitting on. As the seaweed placement is based on both x and y position, having varying y positions for the ground blocks also means that the seaweed placement test could leverage that to look scattered without using an additional pseudo-random number expression.</p> <p>It is also possible to reuse the structure of regular sprites (that are used as visible graphics) as map shapes. This only ended up happening once: the left side of the last tunnel is shared by the sprite data of the seahorse. But if you're really keen, you can also glitch through a wall to get out of bounds, and then freely explore the spritesheet.</p> <h2>Superloop</h2> <p>When making code-golfed games and tweetcarts, I normally end up having a single large loop that is used by anything that needs to be looped, to avoid the &quot;FOR .. DO .. END&quot; 16-character overhead. Unfortunately (or fortunately) I was unable to merge the sprite unpacking in this way, but the rest of the game uses a single superloop. The map data is fetched from the spritesheet, bubbles are drawn, and segments of seaweed are drawn at random top-of-ground locations, all using the same loop counter.</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>-- time starts around 2722, and t/2 is cheaper than writing a 4-digit number for i=0,t/2 do -- unpack map from the spritesheet in 4x4 map tiles -- Using v = (sget() + v)/2 gives tile values that differ -- based on their vertical neighbour so that viable seaweed -- locations can be identified (top is always 4) x=i\32y=i%32 v/=2 v+=sget(r%o+x/4,r\o+y/4-sin(i/870)/2)&amp;4 mset(x,y,v) -- seaweed p=i%4 -- which segment of seaweed y=i\4*5%31 -- y position of seaweed to test (unevenly scattered) if(mget(x,y+1)==4)spr(0,x*8+sin(p/4-t),y*8-p*4) -- draw bubbes and apply water current to player -- only for 1/5 rooms, and for the first 128 iterations if(r%5==2and i&lt;128)spr(i&amp;2,-t*i%w,i*i%w+cos(i/9+t)*3)player_dx-=1&gt;&gt;12 end</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <h2>Janky Physics</h2> <p>The player uses a coordinate system (0..128 in each room) that is rigged so that the world position of the player is the same as the screen position after adjusting for camera position and scrolling. It also gives nice ranges of values that can be manipulated with expressions containing only small integer values.</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>-- control player -- accumulate force (f) while button X is held, and apply when released b=btn() n=b&amp;32 -- buttons states f=f/2 + n/20 -- f approaches but does not exceed 3 k=b%4\2-b%2 -- -1,1 when LEFT or RIGHT is pressed if(f&gt;n) then -- apply force and reset player_dx += f*k player_dy-=f f=0 end -- add velocity to the player's position player_x += player_dx player_y += player_dy -- invert the velocity before map collision test so that -- bouncing, friction and gravity can all be applied when -- there is /not/ a collision. works out slightly shorter player_dx = -player_dx player_dy = -player_dy if (mget(player_x / 4, player_y / 4) &lt; 1) then -- no collision: invert the velocity to prevent bouncing, -- and apply friction and gravity in the same expression player_dx *= -.95 player_dy = .05-player_dy*.9 end</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <h2>Squiddy Racer</h2> <p>Because there is only a single loop used to generate the map and to do things every frame, it means that map data is generated every frame. This is what it looks like if the map distortion accidentally has a time component given to the sine wave:</p> <img style="margin-bottom:16px" border=0 src="/media/1/squiddy_racer.gif" alt="" /> https://www.lexaloffle.com/bbs/?tid=44826 https://www.lexaloffle.com/bbs/?tid=44826 Thu, 30 Sep 2021 01:22:49 UTC PICO-8 0.2.3 <p><a href="https://www.pico-8.com">PICO-8</a> 0.2.3 is now up on <a href="https://www.lexaloffle.com/games.php?page=updates">lexaloffle</a>, <a href="https://www.humblebundle.com/home/library">Humble</a>, <a href="https://lexaloffle.itch.io/pico-8">itch.io</a>, and for <a href="https://lexaloffle.com/bbs/?tid=34009">PocketCHIP</a>.</p> <p>This update is focused on resolving runtime issues, with a couple of small but handy features thrown in for good measure:</p> <h2>Lucky Draw</h2> <p>To grab 32 random cartridges from the BBS, there is now a 'Lucky Draw' list in SPLORE. It is more likely to select cartridges that have more stars, but even unrated carts have a decent chance of appearing. Perhaps this will be a way to unearth some undiscovered gems, or just to find something new to play without scrolling back through several years of carts.</p> <img style="margin-bottom:16px" border=0 src="/media/1/86_lucky_draw.gif" alt="" /> <p>The list is cached, so it only changes every 2 minutes or so. But you can keep paging through the list to get new items forever.</p> <h2>Live Token / Character Count</h2> <p>Select some text in the code editor to view how many characters or tokens are contained within.</p> <img style="margin-bottom:16px" border=0 src="/media/1/84_selected_tokens.png" alt="" /> <h2>Shorthand Print Statements</h2> <p>The shorthand version of print (?&quot;hello&quot;) used to require no preceding statement be on the same line, but you can now mix it with things like the shorthand IF statement, as long as it is the last thing on the line:</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>-- PLAY A SOUND EFFECT WHEN HIT IF (PGET(X,Y)&gt;0) HIT=1 ?&quot;\ADAF&quot;</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>Thanks to <a href="https://www.lexaloffle.com/bbs/?uid=13822"> @Liquidream</a> for suggesting this. It should be handy for things like tweetcarts and <a href="https://www.lexaloffle.com/bbs/?tid=44237">PICO-1K Jam</a> (which coincidentally is also organized by Liquidream!)</p> <h2>New Manual</h2> <p><a href="https://www.lexaloffle.com/dl/docs/pico-8_manual.html"><img style="margin-bottom:16px" border=0 src="/gfx/pico8_manual_cover.png" width=240 height=320 alt="" /></a></p> <p>The PICO-8 Manual is still a work in progress, but it went through a large update last month, with new formatting, dark mode, linkable headers, and more printer-friendly. You can find it on the resources page:</p> <p><a href="https://www.lexaloffle.com/pico-8.php?page=resources">https://www.lexaloffle.com/pico-8.php?page=resources</a></p> <p>The changelog has been separated into a text file here:</p> <p><a href="https://www.lexaloffle.com/dl/docs/pico-8_changelog.txt">https://www.lexaloffle.com/dl/docs/pico-8_changelog.txt</a></p> <p>The pico-8.txt included in the distributables has changed to a short version that links to the online manual, but later on I'll bring back the full ascii version and keep it in sync with the html version.</p> <h2>.P8.ROM Format</h2> <p>This isn't a very useful feature unless you are manipulating PICO-8 cartridges with external tools, but it has always irked me that it is not possible to write 32k of PICO-8 cartridge to a file that is 32k!</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>&gt; SAVE FOO32K.P8.ROM SAVED FOO32K.P8.ROM &gt; LOAD FOO32K.P8.ROM LOADED FOO32K.P8.ROM (0 CHARS)</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>Majestic.</p> <h2>Large Numbers</h2> <p>tostr() and tonum() now take format flags that make it easier to deal with large numbers.</p> <p><a href="https://www.lexaloffle.com/dl/docs/pico-8_manual.html#TOSTR">https://www.lexaloffle.com/dl/docs/pico-8_manual.html#TOSTR</a></p> <p>PICO-8's numbers are all 16:16 fixed point, which basically means that every number is internally stored as a large 32-bit integer that is divided by 65536 to get the value in Lua. So for example, if you want to use that large integer for something like scores that need to go above the usual maximum of 32767, bit 0x2 can be used to display it in the raw integer form:</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>?TOSTR(3, 0x2) 196608 ?TONUM(&quot;196608&quot;, 0x2) 3</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>To add 10 points to a score stored in this way, you'd need to shift it right 16 bits:</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>SCORE += 10&gt;&gt;16</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <h2>CPU Counting</h2> <p>0.2.3 contains two changed to cpu costs which does not effect many cartridges:</p> <ol> <li> <p>In 0.2.2c, it was cheaper to write &quot;local a=0+b&quot; than &quot;local a=b&quot; and also &quot;local a=0-b&quot; than &quot;local a=-b&quot;. This is because the Lua vm instruction for addition was cheaper than local assignment (OP_MOVE), and for unary minus (OP_UNM). The best solution I could find was simply to reduce the cost of those two instructions to 1 cycle instead of 2, resulting in a slight speed increase in some cases.</p> </li> <li>peeking or poking multiple values in 0.2.2c did not cost any additional cpu, so doing something like: poke4(0,peek4(0x1000,0x1000)) was completely free! The same line in 0.2.3 now costs the same as doing an equivalent memcpy.</li> </ol> <h2>Future Plans</h2> <p>Next up for PICO-8 is a 64-bit Raspberry Pi Build, and also a preview of a web version that is also handy for running PICO-8 on Chromebooks. I'm also still working on online scores, which required developing some bespoke infrastructure that is optimised for PICO-8's usage patterns, and can handle traffic from exported carts without needing to start charging for PICONET subscriptions or anything like that. I'll test it next month with the release of <a href="https://www.doodlemud.com">https://www.doodlemud.com</a>, which is a multiplayer drawing game designed to battletest PICO-8's backend before exposing it to precious cartridge data!</p> <h2>Changelog</h2> <p><div><div><input type="button" value=" Show " onClick="if (this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display != '') { this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = ''; this.innerText = ''; this.value = ' Hide '; } else { this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = 'none'; this.innerText = ''; this.value = ' Show '; }"></div><div><div style="display: none;"><br /> v0.2.3</p> <p>Added: Lucky draw list in splore -- gives a random selection of carts<br /> Added: load/save carts in .p8.rom format (raw binary 32k block)<br /> Added: tostr(), tonum() take format_flags parameter to convert to and from 32-bit signed ints<br /> Added: ord(str, pos, num) returns num results starting from character at pos (similar to peek)<br /> Added: FOLDER takes an optional parameter to open other host directories: BACKUPS | DESKTOP | CONFIG | BBS<br /> Added: Live character / token count of selected text shown at bottom right of code editor<br /> Changed: Removed collaboration list from splore (can still search for sub:collab)<br /> Changed: 0x808 audio has a slight lpf filter on it by default // turn off by setting bit 0x20 at 0x5f36<br /> Changed: tonum(boolean_value) returns 1 or 0 instead of nil<br /> Changed: cursor CR x position set only by print(str,x,y) or cursor(), but not by print(str) (0x5f24)<br /> Changed: character wrap is on by default when using print(str)<br /> Changed: force-pause-menu hold duration is 500ms instead of 300ms to prevent accidentally triggering it<br /> Changed: default gif length for new install is 16 seconds<br /> Changed: ? shorthand can be used anywhere on a line e.g. if (true) ?&quot;yes&quot;<br /> Changed: allow while/if shorthand with no statement, using colon separator: WHILE(BTN()==0);<br /> Changed: added warning to fullscreen_method 2 in config.txt (gives erratic behaviour under some drivers)<br /> Changed: cheaper OP_MOVE, OP_UNM lua vm instructions so that e.g. &quot;local a=0-b&quot; is not faster than &quot;local a=-b&quot;<br /> Fixed: peek<em>() / poke</em>() do not charge extra cpu when reading or writing multiple values<br /> Fixed: fget(n) returns junk when n is out of range (0..255); should return 0 in that case<br /> Fixed: dropped .PNG files not detected as images when filename uses uppercase extension<br /> Fixed: line()/tline() illegal writes caused by faulty clipping when (x1-x0) or (y1-y0) &gt;= 0x8000<br /> Fixed: -accept_future 1 only worked with .p8.png files; now also applies to .p8<br /> Fixed: ?&quot;\a7f&quot; does not play f (happens only when f is the first note)<br /> Fixed: abs(0x8000) return 0x0.0001 (should be 0x7fff.ffff)<br /> Fixed: parameter string (stat(6)) is dropped when passed via RUN command<br /> Fixed: preprocessing of form: &quot;x += x&lt;0 and -1 or 1&quot; broken for operators &lt;, &gt;<br /> Fixed: tab not accepted as whitespace for some preprocessor operations<br /> Fixed: stat(1) wraps around when cpu is &gt;= 2.0 (regression in 0.2.2)<br /> Fixed: pressing SHIFT+ENTER on &quot;local function foo()&quot; or after &quot;if (..) else&quot; doesn't insert &quot;end&quot;<br /> Fixed: pal() does not reset secondary palette to system default<br /> Fixed: 0x808 audio does not respect pausing / volume / is not recorded with extcmd(&quot;audio_rec&quot;)<br /> Fixed: 'h' pressed in sprite editor toggles hex mode in map editor<br /> Fixed: After pressing shift-tab to toggle 128x128 map view, active draw area is still only 128x112<br /> Fixed: Attempt to navigate to non-existant tab after running: function _update60() _update60=nil end<br /> Fixed: stat(101) not returning cart id when running from BBS web player<br /> Fixed: print() wrapping + scrolling; e.g. from commandline: while(true) print(chr(254+rnd(2))..&quot;\0&quot;)<br /> Fixed: integer divide assignment operator (\=) costs 2 tokens instead of 1 </p> <p></div></div></div></p> https://www.lexaloffle.com/bbs/?tid=44512 https://www.lexaloffle.com/bbs/?tid=44512 Mon, 06 Sep 2021 21:26:11 UTC Void Roller <p> <table><tr><td> <a href="/bbs/?pid=93976#p"> <img src="/bbs/thumbs/pico8_void_roller-0.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=93976#p"> Void Roller</a><br><br> by <a href="/bbs/?uid=1"> zep</a> <br><br><br> <a href="/bbs/?pid=93976#p"> [Click to Play]</a> </td></tr></table> </p> <p>My <a href="https://zep.itch.io/void-roller">entry for TweetTweetJam #6</a>: a game in 2 tweets (at 558 characters)</p> <p>Roll right without crashing for a high score (or left for a low score)<br /> CTRL-R to restart<br /> Hold X when landing to jump.</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>o=128x,y,u,v,h,p,s,d=o,0,0,0,0,32,sin,circfill::_:: ?&quot;\^1\^c&quot; for i=-o,384do j,l,b=x\1+i,h,btn()h,a=s(j/o)+s(j/93),p+i/4 line(a,0,a,h*2.1+p)h=p+h*5*max(s(j/3^7)) if(i==0and y&gt;h)then if v&gt;0then u+=v*(h-l)v*=-.7else v+=u*(h-l)end y=h if(b&gt;9)v=-4 end for z=0,2,.2do pset(p+i/z,67+h/z,12+(h-l)*4)end end for i=-o+x&amp;-p,x+o,p do a=-t()/(4+i^2%29)m,n=o+i+cos(a)*p-x,s(i/999)*80+s(a)*p d(m,n,8,7)end v+=.2u*=.7x+=u y+=v if pget(p,64+y)==7then::w::circ(p,64+y,v,v)v+=1 for i=24576,32767do poke(i,@i/1.2)end ?&quot;\^1\^jef&quot;..x\1 goto w end d(p,64+y,2,7)u-=b&amp;1u+=b&amp;2goto _</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> https://www.lexaloffle.com/bbs/?tid=43502 https://www.lexaloffle.com/bbs/?tid=43502 Thu, 24 Jun 2021 16:46:16 UTC Diggleoid <p> <table><tr><td> <a href="/bbs/?pid=91077#p"> <img src="/bbs/thumbs/pico8_diggleoid-2.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=91077#p"> diggleoid</a><br><br> by <a href="/bbs/?uid=1"> zep</a> <br><br><br> <a href="/bbs/?pid=91077#p"> [Click to Play]</a> </td></tr></table> </p> <p>Dig to collect gems, and don't get squashed! A wee game made in a weekend for Ludum Dare #48. You can find the compo entry here: <a href="https://ldjam.com/events/ludum-dare/48/diggleoid">https://ldjam.com/events/ludum-dare/48/diggleoid</a></p> https://www.lexaloffle.com/bbs/?tid=42622 https://www.lexaloffle.com/bbs/?tid=42622 Sun, 25 Apr 2021 20:26:46 UTC PICO-8 0.2.2b <p><a href="https://www.pico-8.com">PICO-8</a> <span style="text-decoration: line-through;">0.2.2b</span> 0.2.2c is now up on <a href="https://www.lexaloffle.com/games.php?page=updates">lexaloffle</a>, <a href="https://www.humblebundle.com/home/library">Humble</a>, <a href="https://lexaloffle.itch.io/pico-8">itch.io</a>, and for <a href="https://lexaloffle.com/bbs/?tid=34009">PocketCHIP</a>.</p> <p>This is a bug-fixing patch for <a href="https://www.lexaloffle.com/bbs/?tid=41544">0.2.2</a> -- see that thread for a summary of recent features.</p> <p>0.2.2b does have a few small features though. You can now use a .lua.png extension with the EXPORT command to get the source code (all tabs) of your cartridge printed out to an image with roughly A4 dimensions. This is intended mostly for visualisation purposes, and lines are cropped to 188 pixels (47 characters) wide. The jelpi demo source code is bigger than I imagined!</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>EXPORT JELPI.LUA.PNG</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <img style="margin-bottom:16px" border=0 src="/media/1/jelpi_src.lua.png" alt="" /> <p>dots3d.p8 is much cuter</p> <img style="margin-bottom:16px" border=0 src="/media/1/dots3d_src.lua.png" alt="" /> <p>There are also some new extcmd() commands for setting screenshot output filenames, and the window title (intended for exported binaries).</p> <p>I've also added a way to force the pause menu to come up, even if the cartridge is blocking it with poke() trickery. Simply hold the pause button for half a second, and the menu should come up no matter what (it's implemented at a low level). This might be useful when using SPLORE from a sofa, and a keyboard isn't available to terminate stubborn cartridges.</p> <p>Full list of changes:</p> <p><div><div><input type="button" value=" Show " onClick="if (this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display != '') { this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = ''; this.innerText = ''; this.value = ' Hide '; } else { this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = 'none'; this.innerText = ''; this.value = ' Show '; }"></div><div><div style="display: none;"></p> <p>v0.2.2c</p> <p>Fixed: ?&quot;\ac0&quot; starts from d#0 instead of c0 (again -- 0.2.2b was still broken)<br /> Fixed: splore local directory navigation fails when using a relative home path set with -home<br /> Fixed: export .lua.png only shows the first 2730 lines</p> <p>v0.2.2b</p> <p>Added: export foo.lua.png to get an image of the cartridge's source code<br /> Added: Pause menu can be forced to appear by holding down pause for 300ms (even if program blocks it)<br /> Added: extcmd(&quot;set_filename&quot;,&quot;foo&quot;) -- set the filename of the next screenshot or gif (can include %d)<br /> Added: extcmd(&quot;set_title&quot;,&quot;foo&quot;) -- set window title (useful for exported binaries)<br /> Added: Can toggle punyfont mode at command prompt w/ ctrl+p (useful for inspecting puny variable names!)<br /> Changed: Default filename is /untitled.p8 instead of no filename (auto-increments to untitled_1.p8 etc.)<br /> Changed: circ/oval that are not visible cost almost nothing, including circles that contain clipping region<br /> Changed: filled circles/ovals that contain clipping region cost the same as the equivalent rectfill<br /> Changed: shift+enter in code editor only auto-completes block for DO, THEN, REPEAT or FUNCTION<br /> Fixed: ?&quot;\ac0&quot; starts from d#0 instead of c0<br /> Fixed: preprocessor regression when using string at end of ..= statement: if (true) then a..=&quot;b&quot; end<br /> Fixed: pressing L / R in paused menu is registered by running program after closing menu<br /> Fixed: printing text in tall mode (?&quot;\^ttall&quot;) via commandline can chop off bottom line before scrolling<br /> Fixed: drag-select text with cursor at bottom or top of screen scrolls too fast<br /> Fixed: spurious stat(0) results when using yield() to exit frame instead of flip()<br /> Fixed: line()/tline() sometimes draws pixels on opposite side of screen (0.2.2 regression)<br /> Fixed: line()/tline() fails to draw lines that have x or y coordinates &gt; 32767 pixels apart<br /> Fixed: can peek() more than 8192 values in single call<br /> Fixed: large fill circles (&gt; radius 900) render incorrectly close to vertical center (32-bit builds, web)<br /> Fixed: even-widthed filled ovals with midpoint &lt; 0 is drawn off by 1<br /> Fixed: black pixels in gif / map export not completely black<br /> Fixed: map and spritesheet exporters do not respect current display palette and 0x5F36:0x8 (draw spr 0)<br /> Fixed: code editor: cursor position off by one when selecting character after glyph (0.2.2 regression)<br /> Fixed: code editor: tab names don't show up when 100% punyfont<br /> Fixed: import spritesheet.png failing under MacOS (0.2.2 regression)<br /> Fixed: export single sfx to .wav crashes when contains sfx instrument references</p> <p></div></div></div></p> https://www.lexaloffle.com/bbs/?tid=41852 https://www.lexaloffle.com/bbs/?tid=41852 Wed, 03 Mar 2021 11:32:58 UTC PICO-8 0.2.2 <img style="margin-bottom:16px" border=0 src="/media/1/bunny4_0.gif" alt="" /> <p>Hey All! <a href="https://www.pico-8.com">PICO-8</a> 0.2.2 is now up on <a href="https://www.lexaloffle.com/games.php?page=updates">lexaloffle</a>, <a href="https://www.humblebundle.com/home/library">Humble</a>, <a href="https://lexaloffle.itch.io/pico-8">itch.io</a>, and for <a href="https://lexaloffle.com/bbs/?tid=34009">PocketCHIP</a>.</p> <p>This release follows a pattern set by previous 0.2.* updates in that I set out to fix a bunch of bugs and resolve design details, but in doing so, went down some deep rabbit holes and came out the other end with brand new features. As a result, some of the new features are on the advanced side, and this post will be likewise be more technical than usual. But I hope everyone can find something fun to mess around with!</p> <h1>SFX Filters</h1> <p>At the bottom of the SFX editor, you can now find 5 switches that alter the characteristics of each instrument. You can get a much wider variety of sounds and textures now, but they're meant to feel like variations on the existing instruments rather than completely new ones. I settled on this scheme after working on <a href="https://www.voxatron.com">Voxatron</a>'s sound system and found that I could boil the set of parameters I wanted down to just 7 bits of information -- which is fortunate because there were only 7 unused bits left in the SFX data!</p> <img style="margin-bottom:16px" border=0 src="https://www.lexaloffle.com/media/1/sfx_filters.png" alt="" /> <p>The 5 switches are:</p> <ul> <li>NOIZ: Generate pure white noise (applies only to instrument 6)</li> <li>BUZZ: Various alterations to the waveform to make it sound more buzzy</li> <li>DETUNE-1: Detunes a second voice to create a flange-like effect</li> <li>DETUNE-2: Various second voice tunings, mostly up or down an octave</li> <li>REVERB: Apply an echo with a delay of 2 or 4 ticks</li> <li>DAMPEN: Low pass filter at 2 different levels</li> </ul> <p>SFX instruments (the green ones) can also use these filters, so it is possible for example to have a detuned square wave in the same SFX as a dampened triangle. When both the parent SFX and the SFX instrument have the same switch set at 2 different levels, the greater of the two is used.</p> <p>Here's <a href="https://www.lexaloffle.com/bbs/?uid=11292"> @Gruber</a> explaining filters, along with a newly added control over the length of each SFX (useful for implementing uneven time signatures):</p> <p><object width="640" height="400"><param name="movie" value="https://www.youtube.com/v/az-C9Wru2mo&hl=en&fs=1&rel=0"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="https://www.youtube.com/v/az-C9Wru2mo&hl=en&fs=1&rel=0" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="400"></embed></object></p> <p>And here's <a href="https://www.lexaloffle.com/bbs/?uid=10162"> @tesselode</a> putting them to good use:</p> <p><blockquote class="twitter-tweet" data-lang="en"><a href="https://twitter.com/lexaloffle/status/1360053700312588288">[tweet <img src="/gfx/load16.gif">]</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></p> <p>The BBS SFX player (copy a range of patterns and paste them as text) works with the new filters, but is still janky on mobile:</p> <p> <iframe src="sfxp.php?id=1_4" width="769" height="97" style="border:none; overflow:hidden"></iframe><a style="cursor:pointer; font-size:8pt" onclick=' var el = document.getElementById("sfxcode_1_4"); if (el.style.display == "none") el.style.display = ""; else el.style.display = "none"; microAjax("/bbs/sfxc/1_4.txt", function (retdata){ var el = document.getElementById("sfxcode_1_4"); el.innerHTML = retdata; el.focus(); el.select(); } ); '> [sfx] </a> <textarea rows=3 class=lexinput id="sfxcode_1_4" style="width:480px;background-color:#fed;display:none;overflow:hidden; font-size:4pt;"></textarea> </p> <h1>P8SCII</h1> <p>In previous versions of PICO-8 there were some characters in the range (0..15) that were sitting around doing nothing useful when you printed them. That's clearly no good, so 0.2.2 has introduced a new control codes that allow control over things like text formatting, cursor position and even sound generation. Along with some kana improvements, 0.2.2 now has complete set of 256 characters -- or P8SCII (PICO-8 Standard Code for Information Interchange).</p> <img style="margin-bottom:16px" border=0 src="https://www.lexaloffle.com/media/1/p8scii_demo.png" alt="" /> <p>An example: the &quot;command&quot; character (6) can be written as &quot;\^&quot; followed by a command character and sometimes a parameter: </p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>cls()cursor(20,20) ?&quot;\^iinvert\n&quot; ?&quot;\^ppinball&quot; ?&quot;\^wwide \^ttall\n&quot; ?&quot;\feset colour\n&quot; ?&quot;\#5solid background\n&quot;</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>Character 7 (&quot;\a&quot;) can be used to play audio using a compact description</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>?&quot;\a&quot; -- beep ?&quot;\asfc3ccbdcbae2ee&quot; -- play a wee ditty </pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>This might be useful for squeezing extra sound effects into a cart (or tweetcart), or for simple sound effects in type-in zine listings.</p> <p>For more details on the P8SCII control characters, see the manual: <a href="https://www.lexaloffle.com/pico-8.php?page=manual">https://www.lexaloffle.com/pico-8.php?page=manual</a></p> <h1>Custom Fonts</h1> <p>A custom font can be enabled using control character 14 (or by setting bits 0x81 at address 0x5f58). A fixed character width and height can be specified at 0x5600,0x5602, followed by 8 bytes per character (8x8 bitmap) starting from 0x5608 (character 1). It can be a little fiddly setting the correct data up, so to get started, here's a wee tool that grabs font characters from the spritesheet and generates a snippet:</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>LOAD #FONT_SNIPPET</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>The output snippet is 7 tokens, and can be pasted into your cartridge. Here are some example fonts and their snippets:</p> <img style="margin-bottom:16px" border=0 src="/media/1/76_example_fonts.png" alt="" /> <p>The one on the right is from <a href="https://www.lexaloffle.com/bbs/?uid=32135"> @thattomhall</a>'s SPRITEFONT cartridge: <a href="https://www.lexaloffle.com/bbs/?pid=75073#p">https://www.lexaloffle.com/bbs/?pid=75073#p</a></p> <p>Snippets: <a href="https://www.lexaloffle.com/dl/files/font_snippets.txt">https://www.lexaloffle.com/dl/files/font_snippets.txt</a></p> <p>(that reminds me, there needs to be a good way of posting long snippets like this on the bbs)</p> <h1>Sprite Fill Patterns</h1> <p>It is now possible to apply fill patterns to sprites, which includes spr(), sspr(), map() and tline(). A special bit (0b0.01) is set when calling fillp() to turn this feature on. Each sprite pixel is mapped to TWO colours using the (previously undocumented!) secondary palette, and these two colours are used to draw the pattern.</p> <p>There are more technical details in the manual, but here's an example:</p> <p>If you add the following fillp call to /demos/jelpi.p8 in init_level() (tab 5):</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>cls()reset() fillp(&hearts;\1|0b.011)</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>The result is:</p> <img style="margin-bottom:16px" border=0 src="/media/1/jelpi_003.png" alt="" /> <p>There's a lot going on here!</p> <ul> <li>I've added the call to fillp() after reset(), as it sets fill pattern state to default values.</li> <li>&hearts;\1 is a fill pattern constant with \1 (integer divide) to remove the alpha bit (0.5)</li> <li>0b.01 (0.25) is the bit that turns on fill patterns for sprites</li> <li>0b.001 (0.125) is another bit that applies the secondary palette mapping to ALL drawing functions, including a rectangle that is drawn at the bottom of the mountains.</li> <li>the default secondary palette is being used, which consists of the original colour + a slightly darker counterpart. For example, 12 (0xc) maps to 0xdc. This could be changed with pal(12,0x78,2).</li> </ul> <p>I think there there will be some interesting unexpected ways to use this feature, but a nice immediate example by <a href="https://www.lexaloffle.com/bbs/?uid=15227"> @johanp</a> is to add dithering to textured polygons drawn with tline:</p> <p><blockquote class="twitter-tweet" data-lang="en"><a href="https://twitter.com/lexaloffle/status/1359937895239450626">[tweet <img src="/gfx/load16.gif">]</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></p> <p>(as the truck turns around, you can see a few frames of checkerboard dithering without destroying the look of the texture)</p> <h1>MULTIPOKE</h1> <p>POKE, POKE2 and POKE4 can be given up to 2048 values to poke into memory in sequence, similar to the DATA statement found in early BASIC variants. Try this to write 6 pixels to video memory:</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>poke(0x7000,8,9,0xac)</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>This can be used with unpack() and split() to dump a bunch of values to ram.:</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>poke(0x7000,unpack(split&quot;8,9,0xac&quot;))</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>Values can be read out in a similar manner:</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>a,b,c=peek(0x7000,3) -- 8,9,0xac</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>There is a limit of 2048 values in both cases, which means you can copy up to 8k in one go using PEEK4/POKE4.</p> <h1>Locked Mouse Pointer</h1> <p>This is a feature in 'devkit' mode which is normally intended for making development tools and exported binaries, but of course you are welcome to use it for whatever you like :)<br /> (but keep in mind that some players using the BBS don't have a mouse or keyboard)</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>POKE(0x5F2D, flags) -- where flags are: 0x1 Enable 0x2 Mouse buttons trigger btn(4)..btn(6) 0x4 Pointer lock (use stat 38..39 to read movements)</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>.. so you need to poke(0x5f2d,0x5) to enable mouse with lock. stat(38),stat(39) will then give the mouse movements in desktop pixels rather than PICO-8 ones, so that the window size is irrelevant; they can be thought of as abstract motion events with a comparitively high sensitivity. PICO-8 attempts to match mouse movement when entering and exiting locked mode, but this requires setting the mouse cursor at the operating system level, which is not supported in web. In any case, you might get more consistent results by setting mouse lock once at the start of your cartridge and leaving it there (other mouse events will still work as usual via stat 32,33,34).</p> <p>You can see it in action in <a href="https://www.lexaloffle.com/bbs/?uid=25532"> @freds72</a> and <a href="https://www.lexaloffle.com/bbs/?uid=29414"> @paranoidcactus</a>'s POOM: <a href="https://freds72.itch.io/poom">https://freds72.itch.io/poom</a></p> <h1>Custom Menu Control</h1> <p>Menu item callbacks added with MENUITEM can now elect to keep the pause menu open by returning TRUE, and can also detect if the left and right buttons were pushed. The callback takes an integer parameter that is a bitfield of left and right button presses. Buttons 4..6 all map to each other (can't tell them apart).</p> <p>For example:</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>function my_menu_item(b) if(b&amp;1 &gt; 0) menuitem(_,&quot;left!&quot;) if(b&amp;2 &gt; 0) menuitem(_,&quot;right!&quot;) if(b&amp;32 &gt; 0) menuitem(_,&quot;selected!&quot;) return true -- stay open end menuitem(1, &quot;select me&quot;, my_menu_item) function _draw() cls(5) print(t()) end </pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>Another example:</p> <img style="margin-bottom:16px" border=0 src="/media/1/custom_menu_0.gif" alt="" /> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>LOAD #CUSTOM_MENU </pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <h1>Web Gamepad Improvements</h1> <p>The default PICO-8 0.2.2 HTML exporter (and the BBS web player) now includes <a href="https://www.lexaloffle.com/bbs/?uid=9816"> <a href="https://www.lexaloffle.com/bbs/?uid=9816"> @weeble</a></a>'s improvements that allow the DPAD mapping, and better hotplugging / controller indexing behaviour. </p> <p>Thread: <a href="https://www.lexaloffle.com/bbs/?tid=41293">https://www.lexaloffle.com/bbs/?tid=41293</a></p> <h1>Optimisation / CPU Changes</h1> <p>PICO-8 0.2.2 underwent a fairly aggressive optimisation pass; heavier cartridges use around 20% or in extreme cases 30% less cpu / battery life. I did some further tweaks of CPU costs to keep the theoretical host cpu ceiling as low as possible, which helps a lot on devices like the Raspberry Pi 2 &amp; 3. Let me know if you have a cart that's running too slow on 0.2.2 -- I don't think there are many affected, and I'd be happy to help optimise it by swapping in the new binary operators etc. See the changelog for other cpu cost changes.</p> <p>The following are some notes for the curious -- this shouldn't affect performance considerations when making PICO-8 carts. There was/is a lot of potential to change cartridge behaviour in subtle ways however, so as always, please let me know if you see something weird that was working in previous versions, even if it seems like a small thing.</p> <p>There were 5 areas that needed improvement:</p> <p><div><div><input type="button" value=" Show " onClick="if (this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display != '') { this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = ''; this.innerText = ''; this.value = ' Hide '; } else { this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = 'none'; this.innerText = ''; this.value = ' Show '; }"></div><div><div style="display: none;"></p> <ol> <li>The garbage collector until now has been doing a full collect every frame. This isn't as bad as it sounds (PICO-8 carts generally generate a lot of garbage to collect), and the aim was to reduce worst frame times rather than average ones. 0.2.2 does a little better by spreading collection out over several frames, and if it can't keep up with accumulating garbage, defers to full collection every frame.</li> </ol> <p>As a result of this change, stat(0) needs to perform a full collect to preserve the meaning previous versions. But don't worry about performance of the host machine in the odd situation where you want to use stat(0) in a released cart (not just for debugging) -- it's really fine! If you're curious to read the raw, non-garbage collected ram usage, I've added stat(99).</p> <ol start="2"> <li> <p>There were some 64-bit operations that didn't need to be there. The web builds suffer quite severely from 64-bit ops, but didn't seems to benefit from the other optimisations listed here.</p> </li> <li> <p>Miscellaneous API function improvements; For example, sometimes memcpy can map directly onto host memcpy 1:1 and doesn't need to go through an abstracted layer. The kind of thing that makes code messier and harder to maintain, but worth it when it's the end of the project.</p> </li> <li> <p>API function look-ups in Lua. Every time a function like cos,print,spr is called, Lua was performing a table lookup of that function's name. In a cheap, glorious hack, I just made all of them local by default. This shouldn't affect behaviour except when accessing them via _G, and gives quite a decent speed improvement. Lua can handle around 200 locals per scope, and so I used 50 of them -- I don't think any PICO-8 cartridges come close to exhausting the remaining slots.</p> </li> <li>LUA_TLCF (light c function) calls. Lua does quite a lot of call stack manipulation every time a C function is called. But PICO-8 built-in functions are generally quite simple: the heavily used ones take a number or two and return a single number. So I added a new function type to Lua's internals: a LUA_TSLCF (&quot;super-light c function&quot;). This type of function is only allowed to output a single number by clobbering the position in the stack it was called with. Not a very Lua way of doing things, but it works, and saved a lot of call overhead!</li> </ol> <p></div></div></div></p> <h1>Map Export</h1> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>EXPORT FOO.MAP.PNG</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>.. to get a full-scale png of your map!</p> <img style="margin-bottom:16px" border=0 src="https://www.lexaloffle.com/media/1/jelpi.map.png" alt="" /> <h1>Changelog</h1> <p><div><div><input type="button" value=" Show " onClick="if (this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display != '') { this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = ''; this.innerText = ''; this.value = ' Hide '; } else { this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = 'none'; this.innerText = ''; this.value = ' Show '; }"></div><div><div style="display: none;"><br /> v0.2.2</p> <p>Added: SFX filters: noiz (white noise for inst 6), buzz, detune (flange/overtone), reverb, dampen (lpf)<br /> Added: SFX length (leave the second loop value at 0 to use). Can be &gt;= 32.<br /> Added: P8SCII control characters when using print() -- can adjust colour and cursor position etc.<br /> Added: User-defined font at 0x5600, accessible via control character \014<br /> Added: poke(addr, val0, val1, val2 .. valn) -- same for poke2, poke4<br /> Added: can peek multiple values: a,b,c = peek(addr, 3) -- same for peek2, peek4<br /> Added: Locked mouse pointer // poke(0x5f2d, 0x5) and then stat(38),stat(39) to read<br /> Added: right click in sfx pitch mode to grab the instrument of that note<br /> Added: IMPORT command can specify target location in pixels: IMPORT FOO.PNG -X 16 -Y 32<br /> Added: IMPORT -S to shrink the imported image (e.g. -S 3 means shrink from 384x384 -&gt; 128x128)<br /> Added: ctrl-c at empty command prompt to copy the most recent error message<br /> Added: extcmd(&quot;screen&quot;,0,1) / extcmd(&quot;video&quot;,0,1) saves files in same path as cart / exported executable or app.<br /> Added: set bit POKE(0x5F36, 0x8) to treat sprite 0 as opaque when drawn by map(), tline()<br /> Added: shift-tab in gfx/map editor for full-fullscreen mode (with no red menu bars)<br /> Added: extcmd(&quot;rec_frames&quot;) to record each gif frame only when flip() is called regardless of rendering speed<br /> Added: extcmd(&quot;folder&quot;) to open the folder on the host operating system (where printf, extcmd saves files to)<br /> Added: custom menu callbacks can optionally leave the pause menu open, and can read LEFT and RIGHT button presses<br /> Added: ctrl-h hex mode in map / gfx views (displays current sprite in hex, and shows map tile values)<br /> Added: export map as a single image with export foo.map.png<br /> Added: <a href="https://www.lexaloffle.com/bbs/?uid=9816"> <a href="https://www.lexaloffle.com/bbs/?uid=9816"> @weeble</a></a>'s gamepad improvements to the default html shell (dpad layout detection, better mapping / hotplugging)<br /> Added: stack trace on bad memory access e.g. poke(-1,0)<br /> Added: fillp can now be applied to sprite drawing (spr / sspr / map / tline), using colours from the secondary palette<br /> Improved: General optimisation pass; heavy carts use 20~30% less host cpu<br /> Changed: Most api functions are local by default for performance. use &quot;pico8 -global_api 1&quot; if needed for debugging.<br /> Changed: unpack() now has a non-zero cost but still fairly fast<br /> Changed: .. operator has a small cost based on number of characters concatenated<br /> Changed: LOADK vm instruction costs 1 cycles (was 2) // otherwise &quot;c=0&quot; costs more than &quot;c=a+b&quot;!<br /> Changed: removed function cpu refunds; speed-critical calls to bitwise function should use operator counterparts instead.<br /> Changed: Incremental garbage collection each frame for improved performance.<br /> Changed: stat(0) performs garbage collection in order to obtain a meaningful result; use stat(99) for raw value<br /> Changed: options menu always available from pause menu (used to only be available in web exports)<br /> Changed: tostr() returns &quot;&quot; instead of nil<br /> Changed: exporting gif/png from web version now creates a pop-up div that can be dismissed<br /> Changed: print() from commandline automatically wraps long strings<br /> Changed: print() returns the x position of the next character to be printed (can be used to calculate text width)<br /> Changed: glyph constants set only when running cartridge, not when running a command from prompt<br /> Changed: Using printh from exported carts outputs files in the same folder as the .exe / .app<br /> Changed: type() returns nothing instead of causing a runtime error<br /> Changed: fill pattern is cleared when program is suspended by default. Use poke(0x5f2e,0x20) to preserve.<br /> Changed: reset() resets everything from 0x5f00..0x5f7f, same as when program is initialised (including new random seed)<br /> Changed: font tweaks for hiragana, katagana, ampersand characters<br /> Changed: (raspi) separate binaries that support gpio to remove wiringPi dependency and gpio poking-related crashes<br /> Fixed: Diagonal lines in editor contain an incorrect step when snapping to -1:1, 1:-1<br /> Fixed: rnd(tbl) is not random enough when table has 2 elements /bbs/?pid=81092#p<br /> Fixed: add(tbl) causes runtime error. should have no effect and return nothing<br /> Fixed: cursor position in code editor incorrect when changing lines contaning glyphs/tabs<br /> Fixed: CONFIG TAB<em>WIDTH does not take effect until restarting PICO-8<br /> Fixed: Selecting sprites from bottom right -&gt; top left and then pasting only pastes a single sprite<br /> Fixed: Moving map selection around with cursor keys beyond original selection leaves streaks<br /> Fixed: stdout/stdin serial() streams should be binary, not text mode (causes \r chars under Windows)<br /> Fixed: printh(&quot;hello.txt&quot;,fn,true,true) fails to save to desktop when fn has an extention<br /> Fixed: IMPORT FOO.PNG using the current sprite location as target instead of 0,0<br /> Fixed: tonum behaving differently to parser for string numbers out of range. e.g. tonum(&quot;-0x9000&quot;) should be 0x7000<br /> Fixed: Exporting the same zip file multiple times creates duplicate file entries<br /> Fixed: tline / line clipping // sometimes off by 1px, sometimes incorrectly discarded altogether<br /> Fixed: poking values with bit 0x80 to 0x5f28,0x5f30,0x5f3c,0x5f3e clobbers following address<br /> Fixed: deli(tbl,nil) behaves the same as deli(tbl) -- should have no effect<br /> Fixed: stat(13),stat(15) reporting y coordinates of menu with 0 items<br /> Fixed: memory leak when saving gifs (causes web export to crash after a few records)<br /> Fixed: print() linefeeds clobber multi-line text printed at bottom of screen<br /> Fixed: preprocessor can not handle form: &quot;::</em>::a+=1&quot; (regression in 0.2.1)<br /> Fixed: When split() by group size (e.g. split(&quot;ab12&quot;,2,false)), last parameter ignored<br /> Fixed: partial cstore (len &lt; 0x4300) from splore/export clobbering data outside that range on subsequent reload<br /> Fixed: joystick stops responding after unplug and plug back in twice (also happens when some devices sleep / wake up)<br /> Fixed: mkdir(nil) crashes<br /> Fixed: possible to edit an SFX without the cursor visible (confusing)<br /> Fixed: menuitem() callbacks broken when there is no _draw() or _update() defined<br /> Fixed: should only be able to call from commandline: cd mkdir install_games keyconfig info<br /> Fixed: controller menu (pause-&gt;options-&gt;controls) does not show custom key settings<br /> Fixed: -export failing to find files relative from current path<br /> Fixed: -export failing to locate html template path<br /> Fixed: binary export storing multicart cart names with path (should be named &quot;dat1.p8&quot;, not &quot;dat/dat1.p8&quot;)<br /> Fixed: pause menu broken when cartridge is launched from splore and run() is called inside first frame<br /> Fixed: text printing does not respect draw palette (was broken in 0.2) // ref: /bbs/?tid=41428<br /> Fixed: for backwards compatibility, non-numbery colour parameters should be taken to mean zero<br /> Fixed: preprocessor: self assignment with quoted function calls on RHS a+=1+cos&quot;0&quot;<br /> Fixed: ctrl-r during pause menu only takes effect after closing menu<br /> Fixed: (bug in RC1) pack(...).n is zero<br /> Fixed: (bug in RC1) using filters noiz:1, dampen:2, lpf is not applied to melodic instruments (but should be)<br /> </div></div></div></p> https://www.lexaloffle.com/bbs/?tid=41544 https://www.lexaloffle.com/bbs/?tid=41544 Mon, 15 Feb 2021 21:30:17 UTC Santa 1080 <p> <table><tr><td> <a href="/bbs/?pid=85784#p"> <img src="/bbs/thumbs/pico8_santa1080-4.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=85784#p"> Santa 1080</a><br><br> by <a href="/bbs/?uid=1"> zep</a> <br><br><br> <a href="/bbs/?pid=85784#p"> [Click to Play]</a> </td></tr></table> </p> <p>[O] (z/c): Run / Fly<br /> [X] (x/v): Jump<br /> Left / Right: Turn while in mid-air</p> <p>v3 update: [X] also accelerates to make mobile controls easier</p> <img style="margin-bottom:16px" border=0 src="/media/1/santa1080_3.gif" width=256 height=256 alt="" /> <p>This is intended to be mostly a toy rather than a game, but you can get points for doing tricks!</p> <p>Front / back flips (more points for 2x, 3x)<br /> Early Santa: Santa lands early<br /> Sneaky Weasel: Back flip close to the ground<br /> Moon Grazer: Jump High<br /> Glider: Jump Long<br /> Fishtail: Do a bunch of wavey turns in mid-air<br /> Firebird: Dangle Santa like he's the pod from the videogame Thrust<br /> Santa Smash: Santa lands upside down. Don't do that trick.</p> <p>This game is my contribution to the <a href="https://www.lexaloffle.com/bbs/?tid=40701">2020 PICO-8 Advent Calendar</a>. The calendar always surprises me with its sheer variety and depth of joyful creations, and this year is no exception! I encourage you to have a rummage around inside the advent calendar for the Full Experience (here's the <a href="https://www.lexaloffle.com/bbs/?tid=40701">menu cartridge</a>), but to whet your appetite, here is also a partial gif dump:</p> <p><div><div><input type="button" value=" Show " onClick="if (this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display != '') { this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = ''; this.innerText = ''; this.value = ' Hide '; } else { this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = 'none'; this.innerText = ''; this.value = ' Show '; }"></div><div><div style="display: none;"><br /> <img style="margin-bottom:16px" border=0 src="/media/1/winterwood_2.gif" width=256 height=256 alt="" /><img style="margin-bottom:16px" border=0 src="/media/1/xmas_rpg_1.gif" width=256 height=256 alt="" /><img style="margin-bottom:16px" border=0 src="/media/1/eyn_nicecream_0.gif" width=256 height=256 alt="" /><img style="margin-bottom:16px" border=0 src="/media/1/drsanta_0.gif" width=256 height=256 alt="" /><img style="margin-bottom:16px" border=0 src="/media/1/elf mountain rescue_0.gif" width=256 height=256 alt="" /><img style="margin-bottom:16px" border=0 src="/media/1/jigsaw puzzle pack pro xmas edition_1.gif" width=256 height=256 alt="" /><img style="margin-bottom:16px" border=0 src="/media/1/sprint a gift_1.gif" width=256 height=256 alt="" /><img style="margin-bottom:16px" border=0 src="/media/1/ataxxmas_0.gif" width=256 height=256 alt="" /><img style="margin-bottom:16px" border=0 src="/media/1/gof_0.gif" width=256 height=256 alt="" /><img style="margin-bottom:16px" border=0 src="/media/1/stolecoal_0.gif" width=256 height=256 alt="" /><br /> </div></div></div></p> https://www.lexaloffle.com/bbs/?tid=40930 https://www.lexaloffle.com/bbs/?tid=40930 Sat, 26 Dec 2020 02:22:28 UTC Cosmic Painter <p>A couple of carts for <a href="https://twitter.com/search?q=%23tweettweetjam">#tweettweetjam 5</a> that fit in 560 chars or less.</p> <h3>Cosmic Painter</h3> <p>L/R to rotate<br /> O to accelereate<br /> X to paint</p> <p> <table><tr><td> <a href="/bbs/?pid=84075#p"> <img src="/bbs/thumbs/pico8_cosmic_painter-0.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=84075#p"> cosmic_painter</a><br><br> by <a href="/bbs/?uid=1"> zep</a> <br><br><br> <a href="/bbs/?pid=84075#p"> [Click to Play]</a> </td></tr></table> </p> <h3>Comets</h3> <p>Just avoid the comets for as long as you can! My best is 49<br /> Crashing into the score kills you.</p> <p> <table><tr><td> <a href="/bbs/?pid=84075#p"> <img src="/bbs/thumbs/pico8_comets-0.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=84075#p"> comets</a><br><br> by <a href="/bbs/?uid=1"> zep</a> <br><br><br> <a href="/bbs/?pid=84075#p"> [Click to Play]</a> </td></tr></table> </p> https://www.lexaloffle.com/bbs/?tid=40320 https://www.lexaloffle.com/bbs/?tid=40320 Tue, 10 Nov 2020 09:45:28 UTC