zep [Lexaloffle Blog Feed]https://www.lexaloffle.com/bbs/?uid=1 Squiddy (PICO-1k Jam) <img style="" 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="" border=0 src="/media/1/sq_cover.png" width=340 height= 340 alt="" /></a><a href="/media/1/squiddy_instructions.jpeg"><img style="" 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 style="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="" 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 style="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 style="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="" border=0 src="/media/1/squiddy_5.png" width=384 height=384 alt="" /><img style="" 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 style="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 style="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="" 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="" 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="" 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 style="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="" 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 style="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 style="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 style="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 style="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 style="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="" border=0 src="/media/1/jelpi_src.lua.png" alt="" /> <p>dots3d.p8 is much cuter</p> <img style="" 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="" 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="" 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="" 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 style="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 style="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 style="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="" 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 style="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="" 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 style="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 style="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 style="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 style="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 style="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="" border=0 src="/media/1/custom_menu_0.gif" alt="" /> <div> <div style="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 style="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="" 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="" 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="" border=0 src="/media/1/winterwood_2.gif" width=256 height=256 alt="" /><img style="" border=0 src="/media/1/xmas_rpg_1.gif" width=256 height=256 alt="" /><img style="" border=0 src="/media/1/eyn_nicecream_0.gif" width=256 height=256 alt="" /><img style="" border=0 src="/media/1/drsanta_0.gif" width=256 height=256 alt="" /><img style="" border=0 src="/media/1/elf mountain rescue_0.gif" width=256 height=256 alt="" /><img style="" border=0 src="/media/1/jigsaw puzzle pack pro xmas edition_1.gif" width=256 height=256 alt="" /><img style="" border=0 src="/media/1/sprint a gift_1.gif" width=256 height=256 alt="" /><img style="" border=0 src="/media/1/ataxxmas_0.gif" width=256 height=256 alt="" /><img style="" border=0 src="/media/1/gof_0.gif" width=256 height=256 alt="" /><img style="" 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 Wobblepaint <p> <table><tr><td> <a href="/bbs/?pid=83422#p"> <img src="/bbs/thumbs/pico8_wobblepaint-6.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=83422#p"> Wobblepaint 1.6</a><br><br> by <a href="/bbs/?uid=1"> zep</a> <br><br><br> <a href="/bbs/?pid=83422#p"> [Click to Play]</a> </td></tr></table> </p> <p>Wobblepaint started as a secret cartridge in my <a href="https://www.lexaloffle.com/bbs/?pid=71381">2019 Advent Calendar entry</a>, but I think it's time for a proper release! This version has some extra controls and nicer, less crinkly wobble.</p> <h3>Instructions</h3> <p>Your brush has a <strong>size</strong>, <strong>colour</strong>, <strong>pattern</strong> and <strong>shape</strong> that can be adjusted separately. There are 4 presets you can select and modify using keyboard shortcuts, or by clicking and dragging the top menu bar down to reveal a palette of attributes.</p> <img style="" border=0 src="/media/1/wobble_brushes.gif" alt="" /> <h3>Instructions</h3> <p>CTRL-Z, CTRL-Y (or S,F) to undo/redo<br /> CTRL-C, CTRL-V to copy and paste between doodles<br /> W,R to switch between doodles (or use the menu buttons)<br /> TAB to toggle menu<br /> Mouse wheel (or e,d) to change brush size<br /> RMB to pick up a colour<br /> RMB in menu colour palette to select secondary colour (used for patterns)<br /> LMB+RMB in menu colour palette to set the background colour</p> <p>To save all doodles, use the cartridge icon button in the pull-down menu.</p> <p>Wobblepaint saves data to itself. <strong>To start a new wobble cart</strong>, type LOAD #WOBBLEPAINT from inside PICO-8 and then save it as something. The data storage is reasonably efficient so you can get around 20~100 doodles to a cart depending on complexity.</p> <p><strong>To save a gif to desktop</strong>, use the gif button to record a second of looping wobble. If you want to record multiple doodles (e.g. for an animation or story), press tab to hide menu, CTRL-8 to start a gif, W,R to flip through the doodles, and then CTRL-9 to save the gif.</p> <h3>Gamepad controls</h3> <p>Turn off the devkit input in the options menu (&quot;turn off mouse&quot;) and use a gamepad:</p> <p>LRUD to move the cursor<br /> [X] to paint<br /> [O] + L/R to undo/redo<br /> [O] + U/D to adjust brush size<br /> In the menu, [X] and [O] behave the same as LMB,RMB</p> <h3>Using Wobblepaint doodles in your cartridges</h3> <p>CTRL-C copies doodles in a text format that can be pasted into code (or bbs posts)</p> <p>Paste the code from tab 5 into your cartridge to load and draw them:</p> <div> <div style="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>wobdat=&quot;1f00514302d06ee1179c8d34a74033b359e834319ba6504fa4690ade340000&quot; str_to_mem(wobdat, 0x4300) mywob = wob_load(0x4300) function _draw() cls(mywob.back_col) wob_draw(mywob) 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>Or alternatively, copy the binary data straight out of the spritesheet and use load_library (tab 2) to load all of the doodles into a table.</p> <img style="" border=0 src="/media/1/wobblepaint_4.gif" width=256 height=256 alt="" /> <h3>Changes</h3> <p>v1.5: fixed uneven frame times when recording gif and increased length to 2 seconds (was 1)</p> https://www.lexaloffle.com/bbs/?tid=40058 https://www.lexaloffle.com/bbs/?tid=40058 Thu, 29 Oct 2020 03:14:01 UTC PICO-8 0.2.1 <img style="" border=0 src="/media/1/ovals_0.gif" alt="" /> <p>Hi All! PICO-8 0.2.1b 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>. This update started as a continuation of 0.2.0 bug-fixing work, but I also relaxed my position on API minimalism just enough to add some new features :D</p> <p>UPDATE: 0.2.1b is now live and fixes <a href="https://www.lexaloffle.com/bbs/?tid=38667">the print() bug</a>, and a few other things. See the changelog below for details.</p> <h3>Ovals</h3> <p>You can draw ovals (technically, ellipses) both when running a cartridge, and when using the shape tools in the graphics/map editors. Ovals are specified by their boundary rectangle, and follow the usual draw state rules.</p> <div> <div style="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> pattern={[0]= &hellip;,&and;,░,⧗,▤,✽,★,✽, ˇ,░,▤,♪,░,✽,★,☉, ░,▤,♪,░,✽,★,☉,&hellip;, &and;,░,⧗,▤,✽,★,✽,★ } function _draw() cls(1) for i=0,31/32,1/32 do local x=64+cos(i+t()/8)*48 local y=64+sin(i+t()/8)*44 local w=8+cos(i*2+t()/2)*6 local h=8+sin(i*3+t()/2)*6 fillp(pattern[i*32]) ovalfill(x-w,y-h,x+w,y+h, (i*32)%8+8) end print(&quot;pico-8 0.2.1&quot;,40,62,13) end </pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <h3>Serial I/O</h3> <p>To make it easier to set up workflows for getting data in and out of carts during development, some new serial() channels are available. You can turn a file on your host machine into a binary stream, or drag and drop it into the running cartridge to do the same. From the manual:</p> <div> <div style="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> Additional channels are available for bytestreams to and from the host operating system. These are intended to be most useful for UNIX-like environments while developing toolchains, and are not available while running a BBS or exported cart. Maximum transfer rate in all cases is 64k/sec (blocks cpu). 0x800 dropped file // stat(120) returns TRUE when data available 0x802 dropped image // stat(121) returns TRUE when data available 0x804 stdin 0x805 stdout 0x806 file specifed with: pico8 -i filename 0x807 file specifed with: pico8 -o filename Image files dropped into PICO-8 show up on channel 0x802 as a bytestream: The first 4 bytes are the image's width and height (2 bytes each little-endian, like PEEK2), followed by the image in reading order, one byte per pixel, colour-fitted to the display palette at the time the file was dropped. </pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <h3>Drag and Drop</h3> <p>On a related note, you can also now drop .p8.png cartridges into PICO-8 to open them. If there is a cartridge with unsaved changes, it will prompt before continuing. You can also drop .png files into the spritesheet, by first selecting the sprite that should be the top-left corner location. </p> <h3>API Changes</h3> <p>add() now comes with an optional 3rd parameter: an integer that specifies the location in the table that the new value should be inserted at. Similarly, a new variation of del() is available: deli(tbl, index) (&quot;delete by index&quot;) allows deleting from a given location in the table rather than by value.</p> <p>split() is also new. It complements the common strategy of storing data as strings. From the manual:</p> <div> <div style="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> split str [separator] [convert_numbers] Split a string into a table of elements delimited by the given separator (defaults to &quot;,&quot;). When convert_numbers is true, numerical tokens are stored as numbers (defaults to true). Empty elements are stored as empty strings. split(&quot;1,2,3&quot;) -- returns {1,2,3} split(&quot;one:two:3&quot;,&quot;:&quot;,false) -- returns {&quot;one&quot;,&quot;two&quot;,&quot;3&quot;} split(&quot;1,,2,&quot;) -- returns {1,&quot;&quot;,2,&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> <h3>Binary Storage</h3> <p>It is now also more efficient to store 8-bit binary data in the source code section, by encoding it as a binary string. The .p8.png format stores uncompressable sequences as a raw block of data, effectively allowing cart authors to choose how much of the code section to trade for raw binary storage.</p> <p>Binary strings can be encoded by escaping characters that can't appear in the source code. For example:<br /> 0 should become &quot;\000&quot; (or &quot;\0&quot; when not followed by another number), etc. To make this easier, previously invisible characters C1..C15 have font entries, and also unicode replacements when copying and pasting. I'm working on a snippet for converting between data strings and raw binary data, to make this process easier. UPDATE: <a href="https://www.lexaloffle.com/bbs/?tid=38692">here's the snippet</a>.</p> <h3>HTML Touch Support under iOS</h3> <p>Touch controls for HTML exports is now a little smoother, and works when running from inside an iFrame (including itch.io game pages). I removed the mobile buttons menu by default (the buttons along the top: fullscreen, sound, close) as they aren't very useful and are messy, but they can be turned back on in the options near the top of the exported html.</p> <h3>Changelog // added 0.2.1b</h3> <p>There are many other bug fixes in this update, but I haven't gotten around to replying to the BBS threads yet. For now, please check the complete changelog:</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.1b</p> <p>Added: split(str,&quot;&quot;) splits by single characters<br /> Updated: Tower of Archeos 1.1 via INSTALL GAMES<br /> Fixed: print(num,x,y) always prints numbers num in hexidecimal<br /> Fixed: .p8.png decoder can enter an infinite loop (caused exports to freeze on boot)<br /> Fixed: Can't save screenshot/gif when running a BBS cart with illegal characters in title.<br /> Fixed: INSTALL_GAMES is broken<br /> Fixed: Mouse is broken in HTML exports</p> <p>v0.2.1</p> <p>Added: oval() ovalfill() split()<br /> Added: circle drawing tool is now an oval tool (hold shift for circle)<br /> Added: hold shift with line tool to snap to 22.5 degree angles from origin (0:1, 1:1, 2:1 gradients)<br /> Added: serial() channels for stdin,stdout<br /> Added: raw binary and image files dropped in to PICO-8 also become byte streams readable w/ serial()<br /> Added: add(tbl, val, index) -- insert val into table at index<br /> Added: deli(tbl, index) -- delete element from table by index (index defaults to last element)<br /> Added: show progress while exporting binaries (can be slow now that generating zip files)<br /> Added: -e to add an extra file to exported binaries zip files // export -e manual.txt foo.bin<br /> Added: RESET command to reset the runtime / draw state<br /> Added: drag and drop cartridges into PICO-8 window to load them<br /> Added: hash stored in .p8.png so that cartridges corrupted by image quantization can show a specific error<br /> Added: raw data blocks in compressed code format (useful for storing long binary strings efficiently)<br /> Added: clip(x,y,w,h,true): 5th parameter indicates that the clipping region should be clipped by the old one<br /> Added: -export switch can be used to convert .p8 files to .p8.png from commandline. // pico8 foo.p8 -export foo.p8.png<br /> Added: extcmd(&quot;screen&quot;,scale) and extcmd(&quot;video&quot;,scale) to override the default scale (e.g. scale 2 means 256x256)<br /> Added: printh(str, filename, overwrite, save_to_desktop) -- 4th parameter to save output file to desktop<br /> Changed: add(), del() no longer implemented with Lua snippet; lower cpu cost.<br /> Changed: line(),rect() cost the same as rectfill() when drawing equivalent shapes<br /> Changed: all drawing operations in sprite editor now observe fill pattern state<br /> Changed: numbers can be immediately followed by identifiers (a=1b=2) // lexaloffle.com/bbs/?tid=38038<br /> Changed: Sprite editor shows only active area after shift-selecting sprites<br /> Changed: copy/paste in the code editor treats uppercase ascii characters as puny font only when puny mode (ctrl+p) enabled<br /> Changed: C0 Controls characters (except for 0x0,0x9,0xa,0xd) encoded in .p8 / clipboard with unicode replacements<br /> Changed: stat(4) converts characters to PICO-8 format (P -&gt; puny p, hiragana unicode -&gt; single character etc.)<br /> Changed: serial() returns number of bytes processed (1/8ths included for partial bytes)<br /> Changed: IMPORT SPRITESHEET.PNG now uses the current sprite as the destination coordinate instead of 0,0.<br /> Changed: Standardized name of the display palette to &quot;display palette&quot; (was sometimes referred to as &quot;screen palette&quot;).<br /> Changed: tostr() returns nil (used to return &quot;[nil]&quot;)<br /> Changed: don't need to set bit 0x40 at address 0x5f2c to use secondary palette.<br /> Improved: exported binary's data.pod file 90% smaller (~870k -&gt; ~85k)<br /> Fixed: pack(...).n is shifted right 16 bits<br /> Fixed: ctrl-r doesn't reload external changes for carts which are over compressed code capacity<br /> Fixed: false positives when detecting external changes for some older cart versions<br /> Fixed: .p8.png carts saved with dense code (compressed size &gt; raw size, including very small carts) stores junk<br /> Fixed: error message duplication when loading future version of .p8.png carts<br /> Fixed: Illegal colours can enter spritesheet via serach-replace after setting with color()<br /> Fixed: Preprocessor: &quot;foo():a().x+=1&quot; &quot;a=b[1]c+=1&quot;<br /> Fixed: hex numbers written with punyfont characters breaks syntax high-lighting<br /> Fixed: shift+- in sprite editor jumps too vertically when zoomed in<br /> Fixed: clicking a note in sfx editor creates a selection (-&gt; backspace clears without moving rows)<br /> Fixed: print()/printh()/stop() doesn't respect __tostring metatable method (regression)<br /> Fixed: time() and btnp() speed changes after stopping program, typing a command and then resuming.<br /> Fixed: phantom drag &amp; drop events sent to unused music channels causing them to occasionally unmute themselves<br /> Fixed: undo after moving sprites in map mode only undoes the changes to the map and not the spritesheet.<br /> Fixed: inconsistent token counting for negative or bnot'ed numbers <a href="https://www.lexaloffle.com/bbs/?tid=38344">https://www.lexaloffle.com/bbs/?tid=38344</a><br /> Fixed: Crash when INSTALL_GAMES / INSTALL_DEMOS without a writeable disk<br /> Fixed: stat(4) (clipboard contents) does not convert unicode to corresponding glyphs<br /> Fixed: (MacOS) Using discrete GPU ~ drains battery. Now using integrated GPU when available.<br /> Fixed: screensaver is blocked while PICO-8 is running (needed to set SDL_HINT_VIDEO_ALLOW_SCREENSAVER: &quot;1&quot;)<br /> Fixed: screen glitches after running for 25 days<br /> Fixed: (HTML Exports) touch controls not registering when running under iOS from an iframe (e.g. on an itch.io page)<br /> Fixed: (HTML Exports) tap and hold brings up the select menu under iOS<br /> Fixed: (HTML Exports) button blocked by canvas when overlapping on small screens</p> <p></div></div></div></p> https://www.lexaloffle.com/bbs/?tid=38665 https://www.lexaloffle.com/bbs/?tid=38665 Sat, 04 Jul 2020 00:59:34 UTC Shibuya Pixel Art 2020 <p><object width="640" height="400"><param name="movie" value="https://www.youtube.com/v/Q7vLVjRfbqk&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/Q7vLVjRfbqk&hl=en&fs=1&rel=0" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="400"></embed></object></p> <p>// Promo video by <a href="https://twitter.com/m7kenji">m7kenji</a> with music by <a href="https://twitter.com/kyoheifujita">Kyohei Fujita</a></p> <p><a href="https://pixel-art.jp/">Shibuya Pixel Art 2020</a> is accepting submissions until the end of June, and this year there is a new category for 128x128 games! Lexaloffle is sponsoring the game category with a prize (a <a href="https://shop.pimoroni.com/products/picade">Picade Cabinet</a>), and by offering a limited number of PICO-8 licenses <a href="https://www.lexaloffle.com/shibuya_pixel">to participants</a>.</p> <p>Similar to a game jam, entries should be based on one or more of the following themes: <strong>Shibuya</strong>, <strong>AI</strong>, <strong>Humanity</strong>, <strong>Game</strong> and/or <strong>Landscape</strong>. Unlike typical game jams, existing work can be adapted or reused, as long as it did not win a previous contest. You can find previous winning entries for <a href="https://pixel-art.jp/02/contest/">2018</a> and <a href="https://pixel-art.jp/03/contest">2019</a>.</p> <p><strong>To enter</strong>: simply post the image on twitter or instagram with the hashtag: <a href="https://twitter.com/hashtag/shibuyapixelart2020">#shibuyapixelart2020</a>. It is possible to submit more than one entry. For game submissions, post an image of the titlescreen along with a link to the playable game (this BBS / itch.io etc). I suppose for images you'd also want to post a link to the original non-compressed version if needed. Also note that previous years' selections also included gifs/mp4s that also work as still images.</p> <p>Apart from a Grand Prize (300k yen + a Wacom tablet), there are also 4 special category awards for: <strong>Limited Pixel Art</strong>, <strong>Analogue Pixel Art</strong>, <strong>Beyond Pixel Art</strong> and <strong>Pixel Art Game</strong>. Winning entries are announced in early August, with an exhibition and awards ceremony in September. But you don't need to be in Japan to enter!</p> <p>For more information, and to read the full terms &amp; conditions of entries, please visit the official contest homepage: <a href="https://pixel-art.jp/">https://pixel-art.jp/</a> (there is an automatic English translation button near the top of the main content).</p> <p>UPDATE: I'm not sure if there are restrictions on team projects yet, but will update this thread with any news.</p> <img style="" border=0 src="/media/1/yacoyon_2019.png" width=567 height=597 alt="" /> <p>SHIBUYA GIRLS by <a href="https://twitter.com/yacoyon">@yacoyon</a> 2019</p> <img style="" border=0 src="/media/1/44_m7kenji_2019.jpg" width=429 height=600 alt="" /> <p>生まれ変わる町 by <a href="https://twitter.com/m7kenji"><a href="https://www.lexaloffle.com/bbs/?uid=15250"> @m7kenji</a></a> 2019</p> https://www.lexaloffle.com/bbs/?tid=37971 https://www.lexaloffle.com/bbs/?tid=37971 Fri, 15 May 2020 16:12:34 UTC Orbys <p> <table><tr><td> <a href="/bbs/?pid=76564#p"> <img src="/bbs/thumbs/pico8_orbys-0.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=76564#p"> Orbys</a><br><br> by <a href="/bbs/?uid=1"> zep</a> <br><br><br> <a href="/bbs/?pid=76564#p"> [Click to Play]</a> </td></tr></table> </p> <p>Back to 2016! This is a demo <a href="https://www.lexaloffle.com/bbs/?uid=11378"> @castpixel</a> (also <a href="https://twitter.com/castpixel">on twitter</a> ) and I made in the weeks leading up to Tokyo Demo Fest 2016, as newly formed group: POD. Because it was made in a hurry, I felt I should tidy up the code before posting it. But that's never going to happen, so here's an even messier post-compo version with a few extra details added instead! The rotating orbycube effect can now be found in /demos though if you'd like to see roughly how it works. Also, if you're curious you can find the compo version with: load #orbys_compo</p> https://www.lexaloffle.com/bbs/?tid=37948 https://www.lexaloffle.com/bbs/?tid=37948 Thu, 14 May 2020 15:42:02 UTC PICO-8 0.2 (Beta!) <img style="" border=0 src="/media/1/020e_postcard.png" width=720 height=540 alt="" /> <p>Download 0.2.0i at <a href="https://www.lexaloffle.com/games.php?page=updates">lexaloffle</a> or via <a href="https://www.humblebundle.com/home/library">Humble</a>, or for <a href="https://lexaloffle.com/bbs/?tid=34009">PocketCHIP</a>.</p> <p>Alright, let's do this! PICO-8's core specification is complete, and it appears to do what it says on the tin. So I'm calling it: </p> <h3>PICO-8 is in Beta!</h3> <p>The main purpose of 0.2 is to finish freezing the core of PICO-8 -- the api, cpu counting, specs, cart format, memory layout, program behavior, backwards and future-compatibility should no longer change.</p> <p>Earlier attempts at settling on a fixed core in 0.1.11 and 0.1.12 failed because of technical issues creeping in and also some design decisions that just didn't sit right. It has only been due to the ongoing process of users like <a href="https://www.lexaloffle.com/bbs/?uid=12874"> @Felice</a>, <a href="https://www.lexaloffle.com/bbs/?uid=10844"> @electricgryphon</a>, <a href="https://www.lexaloffle.com/bbs/?uid=30542"> @jobe</a>, <a href="https://www.lexaloffle.com/bbs/?uid=25532"> @freds72</a>, <a href="https://www.lexaloffle.com/bbs/?uid=31258"> @Eniko</a>, <a href="https://www.lexaloffle.com/bbs/?uid=14958"> @samhocevar</a>, and many others prodding at the boundary of what PICO-8 can do -- and what it <em>should</em> do -- that all of those nooks and corners finally took shape. I'm really happy with the way the last pieces of PICO-8 have snapped together, and I think it has reached a point where it feels not only like it should never need to change, but that it never could have been any other way.</p> <p>To make this happen required some jolting changes and a string of patches to get right, and the last few weeks PICO-8 has been in an uncomfortably liquid state. My apologies to everyone who was riding that bumpy update train (but thanks so much for the bug reports!). There might be one or two emergency patches in the next weeks, but I think any left-over quirks and design flaws will simply become part of the machine.</p> <h1>New Features and Changes</h1> <h2>Character Set</h2> <p>PICO-8 now has a full 8-bit character set that can be accessed with CHR() to get a character by index, and ORD() to get the index from a character.</p> <div> <div style="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; PRINT(ORD(&quot;A&quot;)) 97 &gt; PRINT(CHR(97)) A </pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>All characters from 0..255 (0..15 are control characters and are not visible)</p> <img style="" border=0 src="/media/1/pico-8_font_020.png" width=256 height=256 alt="" /> <p>All of the new characters 16..255 can now be typed directly into the code editor. There are 3 modes that can be toggled on and off:</p> <ul> <li><a href="https://en.wikipedia.org/wiki/Katakana">Katakana</a> (ctrl-k) // type in romanji: ka ki ku ke ko</li> <li><a href="https://en.wikipedia.org/wiki/Hiragana">Hiragana</a> (ctrl-j) // ditto</li> <li>Puny Font (ctrl-p) // shift-letter gives you regular font</li> </ul> <p>Additional characters can be accessed in the 2 kana modes with shift-0..9</p> <h2>SFX / Music Organiser</h2> <p>These can be accessed in the music editor, and give you a cart-wide view of all of the patterns or SFXes in a cart. They can be selected by shift-clicking, copied and pasted, or moved around (with ctrl-x, ctrl-v), and can also be used to visualize which SFXes are being used while music is playing.</p> <img style="" border=0 src="/media/1/pattern_organiser.png" width=256 height=256 alt="" /> <img style="" border=0 src="/media/1/sfx_organiser.png" width=256 height=256 alt="" /> <h2>Operators</h2> <p>Bitwise functions can now instead be expressed with operators. The function versions are still useful if you want nil arguments to default to 0, or just as as matter of style. But the operator versions are a little faster and often more token-efficient.</p> <div> <div style="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> BAND(A,B) A &amp; B BOR(A,B) A | B BXOR(A,B) A ^^ B SHL(A,B) A &lt;&lt; B SHR(A,B) A &gt;&gt; B LSHR(A,B) A &gt;&gt;&gt; B ROTL(A,B) A &lt;&lt;&gt; B ROTR(A,B) A &gt;&gt;&lt; B BNOT(A) ~A </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's also a handy integer divide, and operators to peek (but not poke)</p> <div> <div style="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> FLR(A/B) A \ B PEEK(A) @A PEEK2(A) %A PEEK4(A) $A </pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <h2>Capacity Adjustments</h2> <h3>CPU</h3> <p>Bitwise functions (BAND, BOR..) and PEEK functions are now a little more expensive. They can be replaced with operators counterparts to improve speed, but even they are not as fast as the 0.1.11 bitwise functions, especially when used in deeply nested expressions.</p> <p>This change was necessary because I badly miscalculated how much real-world CPU load would be required to run the most bitwise-heavy carts. Lua functions cost a lot of (real) CPU compared to vm operators, and the result was carts that could completely obliterate a web-browser or real-world CPU on an older machine. This is a problem because a central goal of PICO-8 is to allow authors to forget about real-world CPUs across platforms, and just focus on the PICO-8 one.</p> <p>Unfortunately, another central goal is to not mess with or break existing carts! So this was a hard choice to make. I've tried to balance this change somewhat with the introduction of native operators, tline(), and by adjusting the vm costs in a way that feels natural but also frees up some extra cycles. Along with bitwise and peek operators, the add and subtract vm instructions now also cost half as much as other vm instructions. So if you consider PICO-8 to be running at 8MHz, they cost 1 cycle per instruction, while most vm instructions cost 2.</p> <h3>CPU: Coroutines</h3> <p>Previous versions of PICO-8 handled CPU counting inside coroutines very badly. It was easy to accidentally (or intentionally) get 'free' cpu cycles when running a coroutine over a frame boundary, and in some versions the opposite could sometimes happen -- a coroutine or garbage collection would incorrectly yield the whole program causing unnecessary frame skipping. 0.2 contains a much cleaner implementation of cpu counting -- you can wrap anything in coresume(cocreate(function() ... end)), and get exactly the same result (minus the overhead of the wrapping). As a nice by-product, this has also made better STOP() / RESUME behaviour possible (see below).</p> <h3>Tokens and Code Compression</h3> <p>There is still a 8192 token limit (of course!), but negative numbers now count as a single token. This seemingly small fix, along with the new character set and bitwise operators, ultimately resulted in the code compression also improving. The result is that you can squeeze in around 10% more code.</p> <p>If you want to peek behind the curtain, here's the story behind that:<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;"></p> <p>The first version of PICO-8 had only a single limit for code side: 15360 characters. You can still see the remnants of this when you load a cartridge (&quot;loaded foo.p8 (1049 chars)&quot;). Soon after, tokens were introduced as the new limit, so that there was less incentive to bother minifying code except for really heavy carts. For this to work, the character limit was increased to 64k (so that you can get more than 2 characters per token), and the code became compressed so that it could still fit in the same 15360 byte block of a 32k cartridge.</p> <p>The idea was to introduce compression that was just good enough so that you'd normally hit the token limit before you hit the compressed size limit. It favored characters that were commonly used, and was intended to compress code rather than data. By virtue of being simple, it was also fast enough to compress up to 64k of code every key press, so that as you approach the compressed limit you can be altered as soon as you surpass it (which is still true).</p> <p>It held up pretty well, but over time, things changed. Token counting was adjusted to solve common problems, and generally allowed more code to fit within the limit. Carts included more data stuffed into the code section, often containing characters the compressor wasn't intended for. As a result, the compressed code size limit started to become as much of a pressing concern a the token limit. Carts packed to the brim would often use both to capacity.</p> <p>So, these 3 changes (in token counting, character set, and bitwise operators that cost less tokens), have put even more pressure on the compressor, and the old one just wasn't cutting it anymore. I really want to keep the token limit as the one that normally matters the most, and so better compression was in order. 0.2.0e features a code compressor that does about as well with any character subset, is decent at compressing byte-wise structured data stored in hex strings, and compresses around 10% better than previous versions.<br /> </div></div></div></p> <p>Also, and this is a little embarrassing, I found some unused space in the 32k cartridge format that has been sitting dormant since its creation in 2014. It has been given to the code section, which is now 0x3d00 bytes instead of 0x3c00.</p> <h2>TLINE</h2> <p>The tline() function (&quot;Textured Line&quot;) is a mixture of line(), sspr(), and map().</p> <p>You can use it to draw a line of pixels (same as line()), where each colour is sampled linearly from an arbitrary line on the map. It's not much use out of the box, but can be used as a low-level primitive for many purposes including polygon rendering, DOOM-style floors and walls, sprite rotation, map scaling, drawing gradients, customized gradients and fill pattern schemes. I've only played with it a little bit so far, but it's really fun, and I'm looking forward to seeing what it winds up being used for.</p> <h2>API Changes</h2> <h3>RND(TBL)</h3> <p>Give rnd() a table as an argument, and it will return a random item in that table.</p> <h3>BTNP Custom Repeat Delays</h3> <p>From the manual:</p> <div> <div style="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> Custom delays (in frames @ 30fps) can be set by poking the following memory addresses: POKE(0x5F5C, DELAY) -- set the initial delay before repeating. 255 means never repeat. POKE(0x5F5D, DELAY) -- set the repeating delay. In both cases, 0 can be used for the default behaviour (delays 15 and 4) </pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <h3>Fill Patterns Constants</h3> <p>Use the glyphs (shift-a..z) with fillp() to get some pre-defined fill patterns.</p> <div> <div style="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> fillp(★) circfill(64,64,16,0x7) -- transparent white </pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>They are defined with the transparency bit set. You can use flr(★) or ★\1 to get 2-colour patterns.</p> <div> <div style="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> fillp(★\1) circfill(64,64,16,0x7c) -- white and blue </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="" border=0 src="/media/1/fill_patterns_020.png" width=256 height=256 alt="" /> <h2>Demo Carts</h2> <p>Most of the demos have been updated, including Jelpi which now has a few more monsters and tilesets to play with! Use INSTALL_DEMOS to get the new versions. 0.2 also features 2 extra pre-installed games: 8 Legs to Love by <a href="https://www.lexaloffle.com/bbs/?uid=16414"> @bridgs</a>, and Embrace by <a href="https://www.lexaloffle.com/bbs/?uid=11047"> @TRASEVOL_DOG</a>. You can install them with INSTALL_GAMES.</p> <img style="" border=0 src="/media/1/demos_020.gif" alt="" /> <h2>Tabs and Tabs</h2> <p>Tab characters are now optionally visible (but off by default). You can turn them on in config.txt<br /> Press shift-enter to automatically add an END and indent.</p> <p>Also, there are 8 more code tabs. Click the right or left-most visible tab to scroll.</p> <img style="" border=0 src="/media/1/tabs_and_tabs.gif" alt="" /> <h2>Shape Drawing Tools</h2> <p>Both the map and sprite editors now have circle, line, and rectangle drawing tools. Click the tool button to cycle through those 3 modes, and hold ctrl to toggle filled vs. outline circles and rectangles.</p> <img style="" border=0 src="/media/1/shapes_020.gif" alt="" /> <h2>Map Tile Moving</h2> <p>It's now a little easier to move sprites around that are referenced by the map. In the map editor, select the sprites you'd like to move, use ctrl-x and ctrl-v to move them, and the map cell data will also be updated to avoid broken references. This operation applies to the selected region on the map (ctrl-a to select half, and ctrl-a again to select the whole map including shared memory).</p> <p>This operation is a little tricky, because it adds items to both the spritesheet undo stack and the map undo stack, so you need to manually undo both if desired. Back up first!</p> <img style="" border=0 src="/media/1/move_map_sprites.gif" alt="" /> <h2>Splore</h2> <p>Every time you launch a BBS cartridge, PICO-8 will now ping the server to check for a newer version and prompt you to update if it exists. You can turn this off in config.txt</p> <p>There's also a 'search thread' option in splore's cart menu, which will be useful for long jam-style threads in the future. And is already great for browsing the tweetjam thread! (You can go to the search tab in splore, and search for &quot;thread:tweetjam&quot;)</p> <img style="" border=0 src="/media/1/bbs_thread_020.gif" alt="" /> <h2>Exporters</h2> <h3>HTML</h3> <p>The HTML exports now run a lot smoother on older machines, and with more reliable page formatting and mobile controls.</p> <h3>.zip File Output</h3> <p>A common problem when exporting cross-platform binaries, is that the machine you're generating files from doesn't necessarily support the file attributes needed to run programs on other operating system. This was especially problematic for Mac and Linux binaries exported from Windows, which had no way to store the executable bit (and so end-users would have to manually fix that). To get around this problem, the EXPORT command now produces ready-to-distribute .zip files, that store the needed file attributes when unzipped on any other operating system. As a bonus, you also don't need to bother manually zipping up each platform folder! There's currently no way to add other files (e.g. documentation) though, so in that case you might need to zip the .zip along with any other desired files.</p> <h3>Options menu</h3> <p>Binary exports now come with an OPTIONS menu that shows up when a cart is paused, and includes the same settings available in HTML exports (sound, fullscreen, controls).</p> <h2>Activity Log</h2> <p>Have you ever wondered how much time you've spent in PICO-8 editors or carts? Or which carts you've played the most? 0.2 now logs your activity to activity_log.txt (in the same folder as config.txt) once every 3 seconds (unless the PICO-8 is left idle for 30 seconds). There aren't any tools to process this data yet, but it is human-readable. I should clarify: this information is not transmitted anywhere! You can turn this off in config.txt (record_activity_log 0)</p> <h2>Frame Advance</h2> <p>PICO-8 can now be resumed from exactly the point that code stopped running. For example, if you put a STOP() in your code, and then type RESUME from the commandline, the program will continue as if the STOP() had not occurred. It's possible to type in commands before resuming to modify the state of the program though, which is useful for debugging.</p> <p>A common debugging tool is to slow a game down and advancing frame by frame. You can do this by stopping suspending a program with escape, and then typing . and pressing enter. This will run the program until the next flip() call and then stop again. You can get subsequent frames in the same way, or just keep pressing enter after the first one. To add additional debugging behaviour, you can use stat(110), which returns true when running in frame-by-frame mode.</p> <img style="" border=0 src="/media/1/frame_by_frame.gif" alt="" /> <hr /> <p>That's all for now -- I hope you enjoy 0.2 and I'll catch you soon!</p> <p>-- zep</p> <hr /> <p>Full Changelog: (scroll down to 0.2.0 for the main changes)<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;"></p> <p>v0.2.0i</p> <p>Added: pack(), unpack()<br /> Changed: bitplane read/write mask only reset after finished running program<br /> Fixed: tline() doesn't draw anything when the layers argument is not given</p> <p>v0.2.0h</p> <p>Added: tline() takes an optional layers parameter, similar to map()<br /> Added: high bits of 0x5f5e taken as colour read mask, low taken to be colour write mask<br /> Added: Double-click in the sfx tracker to select all attributes of a single note.<br /> Fixed: assignment shorthand RHS scope wrong when contains certain operators. e.g. a+=1&amp;127<br /> Fixed: while/if shorthands fail when &quot;do&quot; or &quot;then&quot; appears on the same line as part of an identifier<br /> Fixed: ctrl-c copies the wrong sfx after clicking pencil button (next to pattern #) in organiser view<br /> Fixed: spinning cart icon present in video memory when cart boots from splore</p> <p>v0.2.0g</p> <p>Added: Window title shows current cartridge filename while editing<br /> Changed: ~ preceeding a numerical constant (e.g. ~1) counts as a single token<br /> Fixed: &gt;&gt;&gt; operator behaviour does not match lshr(a,b) when b &gt;= 32 (again)<br /> Fixed: PICO-8 freezes when shift by -0x8000<br /> Fixed: .p8 format does not store extpal label colours<br /> Fixed: Can not save screenshot when filename contains &quot;:&quot;</p> <p>v0.2.0f</p> <p>Changed: @@ operator (peek2) to %<br /> Fixed: Exported wasm crashes on boot when code contains a numerical constant out of range.<br /> Fixed: HTML Shell treats controller shoulder buttons as MENU; easy to accidentally bump.<br /> Fixed: shift operators behaviour undefined for negative values of n (now: x &lt;&lt; n means x &gt;&gt; -(n\1))<br /> Fixed: &gt;&gt;&gt; operator behaviour does not match lshr(a,b) when b &gt;= 32<br /> Fixed: INFO crashes when code is close to 64k of random characters<br /> Fixed: Code editor undo step not stored when starting to edit a new line (hard to see what happened)</p> <p>v0.2.0e</p> <p>Added: zip file creation (with preserved file attributes) when exporting binaries<br /> Added: cpu working animation when cpu usage &gt; 120 skipped frames<br /> Improved: stop() / resume now works at the instruction level<br /> Fixed: tline clipping broken (from 0.2.0d)<br /> Fixed: cpu counting is wrong inside coroutines<br /> Fixed: coroutines interrupted by garbage collection<br /> Fixed: code compression suddenly much worse for carts &gt; 32k chars<br /> Fixed: code compression ratio can be less than 1 in extreme cases<br /> Fixed: pasting a string ending in '1' into the command prompt opens the editor<br /> Fixed: html export can run out of pre-allocated heap when doing heavy string operations<br /> Fixed: hex memory addresses displayed in puny font on windows<br /> Fixed: devkit mouse message shown once per cart -- should be once per chain of carts<br /> Fixed: can't paste sfx notes after moving to another sfx via keyboard<br /> Fixed: copying note select vs. sfx vs. pattern range is ambiguous<br /> Fixed: crash after redefining type()</p> <p>v0.2.0d</p> <p>Added: rnd(x) when x is an array-style table, returns a random item from that table<br /> Added: gif_reset_mode (in config.txt / CONFIG command). Defaults to 0.1.12c behaviour<br /> Added: print(str, col) form behaves the same as: color(col) print(str)<br /> Added: Operators: &lt;&lt;&gt; &gt;&gt;&lt; &lt;&lt;&gt;= &gt;&gt;&lt;=<br /> Changed: tline now also observes an offset (0x5f3a, 0x5f3b)<br /> Changed: tline rounds down to integer screen coordinates (same as line)<br /> Changed: Final cpu adjustments (see release post)<br /> Changed: Removed experimental &quot;!&quot;-&gt;&quot;this&quot; shorthand<br /> Changed: clip() returns previous state as 4 return values<br /> Fixed: Included files remain locked (and can not be edited by external editors)<br /> Fixed: Carts loaded as plaintext .lua fail to handle BOM / DOS characters<br /> Fixed: palt() returns previous state of bitfield as a boolean instead of a number<br /> Fixed: CPU speed on widget doesn't exactly match stat(1)<br /> Fixed: stat(1) occasionally reports garbage values when above 1.0<br /> Fixed: Custom btnp repeat rates (0x5f5c, 0x5f5d) speed up when skipping frames<br /> Fixed: gif_scale setting not read from config.txt<br /> Fixed: tline: texture references are incorrect when sy1 &lt; sy0<br /> Fixed: tline: single pixel spans are drawn as two pixels<br /> Fixed: binary exports' controls menu always shows 0 joyticks connected<br /> Fixed: Pressing DEL on first row of tracker doesn't do anything<br /> Fixed: host framerate regulation is slow (~1/sec) when PICO-8 frame takes &lt; 1ms to execute<br /> Fixed: fillp() return value (previous state) does not include transparency bit<br /> Fixed: clip&quot;&quot; setting all clip values to 0 (should be ignored)<br /> Fixed: Raspberry Pi static build / static export requires GLIBC 2.0.29 (now .16)<br /> Fixed: stop(nil) crashes<br /> Fixed: print(), printh(), stop() prints &quot;nil&quot; with no arguments (should have no output)<br /> Fixed: trace() can not be used with coroutines</p> <p>v0.2.0c</p> <p>Changed: Compressed size limit now 0x3d00 bytes (reclaimed an unused 0x100 byte block)<br /> Fixed: &gt;&gt;&gt;= operator (was doing a &gt;&gt;= replacement instead)<br /> Fixed: #including large .lua files causes crashes, weird behaviour<br /> Fixed: Sandboxed CSTORE: writing partial data to another embedded cart clobbers the remaining data.<br /> Fixed: Multicart code storing regression introduced in 0.2.0 (code from head cart stored in other carts)<br /> Fixed: Can not edit spritesheet after panning<br /> Fixed: Junk error messages when syntax error contains one of the new operators<br /> Fixed: Crash with: 0x8000 / 1 </p> <p>v0.2.0b</p> <p>Changed: #include directive can be preceeded by whitespace<br /> Changed: Activity logger records nothing after idle for 30 seconds<br /> Fixed: Mouse cursor movement in editor is not smooth<br /> Fixed: Screen palette doesn't reset after exiting splore<br /> Fixed: PALT() returns 0 instead of previous state as bitfield<br /> Fixed: Rectangle and line tools broken when used in map editor<br /> Fixed: INSTALL_GAMES under Windows produces broken cart files<br /> Fixed: Stored multicart sometimes has code section truncated (fails to load())</p> <p>v0.2.0</p> <p>Added: 8-bit character set with kana, alt font<br /> Added: ord(), chr()<br /> Added: SFX / Pattern organiser view<br /> Added: SFX edit buttons on pattern channels<br /> Added: tline // textured line drawing<br /> Added: SPLORE automatically updates BBS carts when online<br /> Added: Search for similar (shared tags) cartridges, or by thread<br /> Added: predefined fillp() pattern values assigned to glyphs<br /> Added: btnp() custom delays (poke 0x5f5c, 0x5f5d)<br /> Added: &quot;.&quot; shorthand command for advancing a single frame (calls _update, _draw if they exist)<br /> Added: Current editor/cart view is recorded every 3 seconds to [app_data]/activity_log.txt<br /> Added: Cutting (ctrl-x) and pasting selected sprites while in map view to also adjust map references to those sprites<br /> Added: Clipboard is supported in the html exports (with some limitations) // load #wobblepaint for an example.<br /> Added: Can load .lua files as cartridges<br /> Added: Operators: ..= ^= \ \= &amp; | ^^ &lt;&lt; &gt;&gt; &gt;&gt;&gt; ~ &amp;= |= ^^= &lt;&lt;= &gt;&gt;= &gt;&gt;&gt;= @ @@(update: @@ replaced with %) $<br /> Added: New demo carts: waves.p8 dots3d.p8 automata.p8 wander.p8 cast.p8 jelpi.p8 (use INSTALL_DEMOS)<br /> Added: Extra pre-installed games: Embrace, 8 Legs to Love (use INSTALL_GAMES)<br /> Added: Splore cart labels for .p8 files<br /> Added: Now 16 code tabs (click on the rightmost ones to scroll)<br /> Added: ipairs()<br /> Added: SAVE from commandline to quick-save current cartridge (same as ctrl-s)<br /> Added: BACKUP from commandline to save a backup of current cartridge<br /> Added: CPU usage widget (ctrl-p while running cartridge)<br /> Added: Button / dpad states exposed in memory at 0x5f4c (8 bytes)<br /> Added: Random number generator state exposed at 0x5f44 (8 bytes)<br /> Added: pico8_dyn version is included when exporting to Raspberry Pi<br /> Added: allow_function_keys option in config.txt (CTRL 6..9 are now preferred -- will phase out F6..F9 if practical)<br /> Added: Visible tab characters (draw_tabs in config.txt)<br /> Added: pal({1,2,3..}) means: use the value for each key 0..15 in a table<br /> Added: palt(bitfield) means: set the colour transparency for all 16 colours, starting with the highest bit<br /> Added: Options menu for binary exports (sound / fullscreen / controls)<br /> Added: Shape drawing tools in sprite and map editor<br /> Improved: Miscellaneous HTML shell / player optimisations and adjustments<br /> Improved: Lower cpu usage for small foreground_sleep_ms values (changed host event loop &amp; fps switching strategy)<br /> Changed: This update is called 0.2.0, not 0.1.12d! (grew into plans for 0.2.0, and bumped cart version number)<br /> ChangeD: Reverted cheaper 0.1.12* costs on bitwise operators &amp; peek (recommend replacing with operators if need)<br /> Changed: negative numbers expressed with a '-' count as a single token<br /> Changed: glitchy reset effect does not leave residue in base RAM (but maybe on screen when using sprites / tiles)<br /> Changed: sset() with 2 parameters uses the draw state colour as default<br /> Changed: line() or line(col) can be used to skip drawing and set the (line_x1, line_y1) state on the next call to line(x1,y1)<br /> Changed: vital system functions (load, reboot etc.) can only be overwritten during cartridge execution<br /> Changed: sqrt(x) is now more accurate, and a little faster than x^.5<br /> Changed: sqrt(x) returns 0 for negative values of x<br /> Changed: btnp() delay and repeats now work independently per-button<br /> Changed: pairs(nil) returns an empty function<br /> Changed: Default screenshot scale (now 4x), gif scale (now 3x)<br /> Changed: gif_len now means the length when no start point is specified (used to be the maximum recordable length)<br /> Changed: (Multicarts) When loading data from many different carts, the swap delay maxes out at ~2 seconds<br /> Changed: (Raspberry Pi) removed support for (and dependency on) libsndio<br /> Changed: camera(), cursor(), color(), pal(), palt(), fillp(), clip() return their previous state<br /> Changed: Can not call folder() from a BBS cart running under splore<br /> Changed: F9 resets the video, so that multiple presses results in a sequence of clips that can be joined to together<br /> Changed: color() defaults to 6 (was 0)<br /> Changed: Backed up filenames are prefixed with a timestamp.<br /> Changed: Automatically start on the (host's) current path if it is inside PICO-8's root path<br /> Changed: tostr(x,true) can also be used to view the hex value of functions and tables (uses Lua's tostring)<br /> Changed: Can hold control when clicking number fields (spd, pattern index etc.) to increment/decrement by 4 (was shift)<br /> Fixed: HTML exports running at 60fps sometimes appear to repeatedly speed up and slow down<br /> Fixed: HTML export layout: sometimes broken -- option buttons overlapping in the same place<br /> Fixed: __tostring metatable methods not observed by tostr() / print() / printh()<br /> Fixed: Mac OSX keyboard permissions (fixed in SDL2 0.2.12)<br /> Fixed: Audio mixer: SFX with loop_end &gt; 32 would sometimes fail to loop back<br /> Fixed: btn() firing a frame late, and not on the same frame as stat(30)<br /> Fixed: #include can not handle files saved by some Windows text editors in default format (w/ BOM / CRLF)<br /> Fixed: Exports do not flatten #include'd files<br /> Fixed: Default window size has too much black border (now reverted to previous default)<br /> Fixed: Functions yielded inbetween frames occasionally push an extra return value (type:function) to the stack<br /> Fixed: can't load png-encoded carts with code that starts with a :<br /> Fixed: .gif output unnecessarily large<br /> Fixed: .gif recording skipping frames when running at 15fps<br /> Fixed: printh does not convert to unicode when writing to console or to a file<br /> Fixed: cart data sometimes not flushed when loading another cart during runtime<br /> Fixed: Can not navigate patterns with -,+ during music playback<br /> Fixed: Mouse cursor not a hand over some buttons<br /> Fixed: Laggy mouseover messages (e.g. showing current colour index, or map coordinates)<br /> Fixed: Can't paste glyphs into search field<br /> Fixed: Tab spacing always jumps config.tab_spaces instead of snapping to next column<br /> Fixed: -p switch name is wrong (was only accepting &quot;-param&quot; in 0.12.*<br /> Fixed: Code editor highlighting goes out of sync after some operations<br /> Fixed: Multicart communication problem (affecting PICOWARE)<br /> Fixed: time() speeds up after using the RESUME command<br /> Fixed: Audio state is clobbered when using the RESUME command<br /> Fixed: Audio glitch when fading out music containing slide effect (1)<br /> Fixed: Toggling sound from splore cart-&gt;options menu has no effect<br /> Fixed: Devkit keyboard works when paused<br /> Fixed: &quot;-32768 % y&quot; gives wrong results<br /> Fixed: Replacing all text in code editor breaks undo history<br /> Fixed: Double click to select last word in code does not include the last character<br /> Fixed: Weird block comment behavior in code editor<br /> Fixed: HTML export: cart names can not contain quotes<br /> Fixed: HTML export: menu button layout under chromium<br /> Fixed: HTML export: Adding content above cartridge breaks mobile layout<br /> Fixed: HTML export: Can touch-drag PICO-8 screen around (breaks simulated mouse input)<br /> Fixed: LOAD(&quot;#ABC&quot;) does not always immediately yield<br /> Fixed: Infinite RUN() loop crashes PICO-8<br /> Fixed: Mouse cursor is not a finger on top of most &quot;pressable&quot; button-style elements<br /> Fixed: CD command fails when root_path is relative (e.g. &quot;pico8 -root_path .&quot;)<br /> Fixed: poke in fill pattern addresses (0x5f31..0x5f33) discards some bits<br /> Fixed: After using ctrl-click in map editor, can not modify map outside that region<br /> Fixed: Shift-selecting sprites from bottom right to top left selects wrong region<br /> Fixed: Changing GIF_LEN from PICO-8 commandline sometimes breaks gif saving<br /> Fixed: pget() sometimes returns values with high bits set<br /> Fixed: Preprocessor: unary operator lhs is not separated in some cases (e.g. x=1y+=1)<br /> Fixed: Preprocessor: ? shorthand prevents other preprocess replacements on same line<br /> Fixed: Preprocessor: fails when multiple shorthand expressions + strings containing brackets appear on the same line<br /> Fixed: Loading a .p8 file with too many tabs discards the excess code.<br /> Fixed: Map editor's stamp tool wraps around when stamping overlapping the right edge.<br /> Fixed: Very quick/light tap events sometimes do not register<br /> Fixed: SFX tracker mode: can't copy notes with shift-cursors before clicking (whole sfx is copied instead)<br /> Fixed: &quot;...&quot; breaks syntax highlighting<br /> Fixed: Click on text, press up/down -&gt; cursor reverts to previous horizontal position<br /> Fixed: CTRL-[a..z] combinations processed twice under some linux window managers<br /> Fixed: ctrl-up/down to jump to functions in the code editor breaks when &quot;function&quot; is followed by a tab<br /> Fixed: map &amp; gfx drawing selection is not applied consistently between tools<br /> Fixed: Using right mouse button to pick up a colour / tile value sometimes also applies current tool</p> <p></div></div></div></p> https://www.lexaloffle.com/bbs/?tid=37695 https://www.lexaloffle.com/bbs/?tid=37695 Fri, 08 May 2020 19:49:41 UTC A Perfect Snowflake <p> <table><tr><td> <a href="/bbs/?pid=71381#p"> <img src="/bbs/thumbs/pico8_aps-6.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=71381#p"> A Perfect Snowflake</a><br><br> by <a href="/bbs/?uid=1"> zep</a> <br><br><br> <a href="/bbs/?pid=71381#p"> [Click to Play]</a> </td></tr></table> </p> <p>Merry Christmas and Happy Holidays everyone!</p> <p>This is my cartridge for the <a href="https://www.lexaloffle.com/bbs/?tid=36076">2019 Advent Calendar</a>. It is a simple toy/game with no secret endings at all. Nope.</p> <p>There are 26 (or more! wink wink) carts available now, and you can get the full experience by playing from <a href="https://www.lexaloffle.com/bbs/?uid=16975"> @enargy</a>'s <a href="https://www.lexaloffle.com/bbs/?tid=36076">main cart</a>. It is a truly joyful collection!</p> <p><img style="" border=0 src="/media/1/katamari_christmassy_0.gif" width=256 height=256 alt="" /><img style="" border=0 src="/media/1/polarpanic_6.gif" width=256 height=256 alt="" /><img style="" border=0 src="/media/1/deersanta_0.gif" width=256 height=256 alt="" /><img style="" border=0 src="/media/1/snowman builder_0.gif" width=256 height=256 alt="" /><img style="" border=0 src="/media/1/freds72_snow_0.gif" width=256 height=256 alt="" /><img style="" border=0 src="/media/1/christmas in the coral caves_0.gif" width=256 height=256 alt="" /><img style="" border=0 src="/media/1/snowfight_0.gif" width=256 height=256 alt="" /><img style="" border=0 src="/media/1/myrrhs_edge_1.gif" width=256 height=256 alt="" /></p> https://www.lexaloffle.com/bbs/?tid=36360 https://www.lexaloffle.com/bbs/?tid=36360 Wed, 25 Dec 2019 11:40:37 UTC GIFDUMP Jam [Heavy Data Warning] <p>The BBS's media storage system has recently been updated, and image attachments are now sent to a cloud bucket. Let's stress-test it with some gifs!</p> <h1>Rules:</h1> <ul> <li>No gif, no post!</li> <li>No explanation of the gif is required.</li> <li>No quality required.</li> </ul> <hr /> <p>To save these, I used &quot;CONFIG GIF_SCALE 3&quot; from the PICO-8 command prompt, but any size is ok.</p> <p>Some of these are doodles, some are unfinished carts, some are abandoned projects that will only live on as gifs.</p> <img style="" border=0 src="/media/1/contours_0.gif" alt="" /> <img style="" border=0 src="/media/1/water_bicycle_0.gif" alt="" /> <img style="" border=0 src="/media/1/11_nights_b_1.gif" alt="" /> <img style="" border=0 src="/media/1/nights_b_0.gif" alt="" /> https://www.lexaloffle.com/bbs/?tid=36117 https://www.lexaloffle.com/bbs/?tid=36117 Thu, 05 Dec 2019 17:30:41 UTC Blocks For Life <p> <table><tr><td> <a href="/bbs/?pid=64066#p"> <img src="/bbs/thumbs/pico8_blocks_for_life-0.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=64066#p"> Blocks for Life</a><br><br> by <a href="/bbs/?uid=1"> zep</a> <br><br><br> <a href="/bbs/?pid=64066#p"> [Click to Play]</a> </td></tr></table> </p> <p>At the start of each level there is a shop. You can spend hearts on 3 things:</p> <ul> <li>Blocks: use these to build bridges, barriers, and to clobber monsters.</li> <li>Jetpack fuel: press and hold jump while in mid-air to use your jetpack.</li> <li>Gems: become your final score.</li> </ul> <p>Life is replenished on completing each level.<br /> Monsters also drop fuel and blocks sometimes.<br /> You can modify your block placement with up+left/right etc.</p> <p>Ludum Dare page: <a href="https://ldjam.com/events/ludum-dare/44/blocks-for-life">https://ldjam.com/events/ludum-dare/44/blocks-for-life</a></p> https://www.lexaloffle.com/bbs/?tid=34088 https://www.lexaloffle.com/bbs/?tid=34088 Tue, 30 Apr 2019 00:58:39 UTC PX9 Data Compression <p> <table><tr><td> <a href="/bbs/?pid=63989#p"> <img src="/bbs/thumbs/pico8_px9-8.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=63989#p"> PX9 Data Compression v.7b</a><br><br> by <a href="/bbs/?uid=1"> zep</a> <br><br><br> <a href="/bbs/?pid=63989#p"> [Click to Play]</a> </td></tr></table> </p> <p>PX9 is a lightweight gfx &amp; map compression library, intended to replace <a href="https://www.lexaloffle.com/bbs/?tid=3930">PX8</a>. It uses the same ideas and interface as px8, but is smaller (<span style="text-decoration: line-through;">297</span> <span style="text-decoration: line-through;">292</span> <span style="text-decoration: line-through;">274</span> <span style="text-decoration: line-through;">262</span> <span style="text-decoration: line-through;">258</span> 254 tokens to decompress), and requires zero configuration.</p> <p>To compress some data:</p> <div> <div style="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>px9_comp(x,y,w,h, dest_addr, vget) returns the number of bytes written x,y,w,h is the source rectangle (e.g. on the spritesheet or map) dest_addr is where to write it in memory vget is a function for reading values (e.g. sget when compressing from spritesheet)</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 decompress it again:</p> <div> <div style="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>px9_decomp(x,y,src_addr,vget,vset) x,y where to decompress to src_addr is a memory address where compressed data should be read from vget, vset are functions for reading and writing the decompressed data (e.g. pget and pset when decompressing to the 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>Unlike px8, the vget function does not need to return 0 when x,y are outside the destination rectangle</p> <h2>Workflow</h2> <p>You can use px9.p8 as a utility for compressing other carts' data by replacing _init() with something like this:</p> <div> <div style="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>reload(0x0, 0x0, 0x2000, &quot;mycart.p8&quot;) clen = px9_comp(0, 0, 128, 128, 0x2000, sget) cstore(0x0, 0x2000, clen, &quot;mycart_c.p8&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>This would compress the spritesheet from mycart.p8 and store it in the spritesheet of mycart_c.p8, using memory from 0x2000.. as a temporary buffer. See the <a href="https://www.lexaloffle.com/pico-8.php?page=resources">PICO-8 Manual</a> for more information about reload() and cstore().</p> <p>In the release cartridge, you only need the code from tab 1 (px9_decomp) in order to decompress, which should be 292 tokens.</p> <h2>The Algorithm</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;"></p> <p>PX9 tries to predict the colour of each pixel based on the values of its top and left neighbours (this is why vget() as well as vset() is needed in the decompression function). For each combination of top and left values, a list of values is stored in the order they were last encountered (a &quot;vlist&quot;). This means than only an index into the vlist is required to specify the output colour (or an index into a single global vlist if there are no predictions for that neighbour combination yet). Furthermore, PX9 alternates between storing spans of successfully predicted values (index==0) or unsuccessfully (index&gt;0). For the predicted spans, only the length of the span is needed. For non-predicted spans, the length of the span, and then a prediction list index for each pixel is stored.</p> <p>Both span lengths and indices are stored in the same way: a sequence of n-bit little-endian integers where n = {1,2,3..}. The stored value is taken to be the sum of these integers, and the list is terminated when the last integer has at least one bit that is not set. i.e. is less than (2^num_bits)-1</p> <p>So, values are stored in the bit stream like this:</p> <p>0: 0<br /> 1: 1 00<br /> 2: 1 10<br /> 3: 1 01<br /> 4: 1 11 000<br /> 5: 1 11 100<br /> 6: 1 11 010<br /> ..</p> <p>This distribution of encoded lengths works well for pixel&amp;map values and span lengths, as both predictions and near-predictions (index==1) can be stored with single bits, and typical source data roughly produces a log2n distribution in most cases otherwise.</p> <p></div></div></div></p> <h2>Slideshow Cart</h2> <p>I'd like to make a pixel art slideshow cart using PX9, with around 5~10 images -- if you have any 64x64 ~ 128x128 pico-8 palette images kicking around that you would like to include, or if you'd like to make one, please email them to me! (hey at lexaloffle dot com).</p> <hr /> <p>v3:<br /> felice's getval() replacement<br /> fixed px9_comp() return value (was returning one larger than needed when aligned to 8bit boundary)</p> <p>v4: // More improvements by <a href="https://www.lexaloffle.com/bbs/?uid=12874"> <a href="https://www.lexaloffle.com/bbs/?uid=12874"> @Felice</a></a> &amp; <a href="https://www.lexaloffle.com/bbs/?uid=8336"> @Catatafish</a><br /> Fixed the bit-flushing bug at EOF<br /> Perf should be better in 0.2.0<br /> Down to 274 tokens</p> <p>v5:<br /> Fixed: output is skewed when x != 0<br /> Down to 262 tokens for px9_decomp</p> <p>v6:<br /> smaller vlist_val() by <a href="https://www.lexaloffle.com/bbs/?uid=28958"> @p01</a><br /> -&gt; 258 tokens</p> <p>v7b:<br /> smaller vlist_val() by <a href="https://www.lexaloffle.com/bbs/?uid=12874"> <a href="https://www.lexaloffle.com/bbs/?uid=12874"> @Felice</a></a><br /> -&gt; 254 tokens</p> https://www.lexaloffle.com/bbs/?tid=34058 https://www.lexaloffle.com/bbs/?tid=34058 Fri, 26 Apr 2019 18:34:35 UTC Ludum Dare #44 <p>A thread for <a href="https://ldjam.com/">Ludum Dare 44</a> this weekend. Feel free to post any updates, WIPs or meet-ups here!</p> <p>Theme voting: <a href="https://ldjam.com/events/ludum-dare/44/theme">https://ldjam.com/events/ludum-dare/44/theme</a></p> <img style="" border=0 src="https://www.lexaloffle.com/bbs/files/1/invite63_0.gif" alt="" /> <p>For anyone in Tokyo, <a href="http://www.picopicocafe.com">Pico Pico Cafe</a> will be open both days for ludumdarers, 10am Saturday ~ late Sunday. If you'd like to join, there is an <a href="https://twitter.com/gaemzmu/status/1119470108483526656?s=19">rsvp form</a>. (Note there is an overlapping <a href="http://www.picotachi.com">picotachi</a> from 7pm~ on Saturday)</p> https://www.lexaloffle.com/bbs/?tid=34042 https://www.lexaloffle.com/bbs/?tid=34042 Wed, 24 Apr 2019 08:21:02 UTC PICO-8 For PocketCHIP <img style="" border=0 src="https://www.lexaloffle.com/bbs/files/1/pocketchip3_0.gif" alt="" /> <p>Update: Download 0.2.3 for CHIP and PocketCHIP here: <a href="https://lexaloffle.com/dl/chip/pico-8_0.2.3_chip.zip">pico-8_0.2.3_chip.zip</a></p> <p>You can just unzip it somewhere and run it, but if you want to install over the default location so that the launcher buttons still works, open Terminal and type the following:</p> <div> <div style="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> wget www.lexaloffle.com/dl/chip/pico-8_0.2.3_chip.zip sudo unzip pico-8_0.2.3_chip.zip -d /usr/lib </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 default password is: chip)</p> <p>Update: I've seen instances of the launcher button pointing to both /usr/lib/pico-8 and /usr/lib/pico8. If you're still getting some older version when using the launcher button (check the boot screen), use:</p> <div> <div style="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> sudo mv /usr/lib/pico-8 /usr/lib/pico8 </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 is the first time I've released a build for CHIP, as they were previously handled by the late Next Thing Co. In 2016 I spent a week at their workshop in Oakland, hacking out a proof of concept along with the first version of SPLORE, so that we could see how it would all fit together. It was not a large company, but everyone I met there were stand-up hackers driven to make something new and interesting. It's remarkable what they were able to achieve, and I'm glad to be able to contribute to the legacy a little by continuing support for these devices.</p> <p>Unfortunately, it seems NTC fell into insolvency with a lot of paid-for but yet-to-be-shipped PocketCHIPs sitting in storage somewhere. I know as much as the next person about this, but for what it's worth, it certainly wasn't for lack of caring about customers. If you were one of the people that got caught out, feel free to mail me (hey at lexaloffle dot com) with a screenshot of your order (and 'PocketCHIP' somewhere in the subject), and I'll send you some virtual hardware instead. </p> <p>-- zep</p> https://www.lexaloffle.com/bbs/?tid=34009 https://www.lexaloffle.com/bbs/?tid=34009 Mon, 22 Apr 2019 16:05:10 UTC PICO-8 0.1.12 <p> <table><tr><td> <a href="/bbs/?pid=63583#p"> <img src="/bbs/thumbs/pico8_pico8_0112-0.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=63583#p"> PICO-8 0.1.12</a><br><br> by <a href="/bbs/?uid=1"> zep</a> <br><br><br> <a href="/bbs/?pid=63583#p"> [Click to Play]</a> </td></tr></table> </p> <p>Hey PICO-8 people! Builds for 0.1.12 are now live on <a href="https://www.lexaloffle.com/games.php?page=updates">Lexaloffle</a> and <a href="https://www.humblebundle.com/home/library">Humble</a>. UPDATE: PocketCHIP users can get it <a href="https://lexaloffle.com/bbs/?tid=34009">here</a>.</p> <p>If you just want to see what's new, please scroll down a bit. But first of all, I should issue a..</p> <h3>Breakage Warning!</h3> <p><strong>Future Compatibility</strong>: You'll need to update to 0.1.12 to play cartridges made in 0.1.12 or later. This update is another attempt at eternal future compatibility (can handle any future carts). There were a few bugs in 0.1.11g that needed a cart version bump to fix, and so I also took the chance to tweak the API (more on that below).</p> <p><strong>Backwards Compatibility</strong>: The time() function (also aliased as t() for tweetjammers) now always means time in seconds even at 60fps. This breaks a couple of 60fps carts that I know of (sorry <a href="https://www.lexaloffle.com/bbs/?uid=556"> @rez</a> and <a href="https://www.lexaloffle.com/bbs/?uid=30542"> @jobe</a>!) but I think it's worth biting the bullet now to be more consistent and to match Voxatron's t() behaviour. With any luck this will also be the last backwards compatibility breakage.</p> <p>A less disruptive change is in the music mixer: both the drop (3) and vibrato (2) effects are observed when playing an SFX-instrument. This only affects carts using SFX instruments, and which happen to have those (previously) dormant values sitting around, but I couldn't find any examples in the wild yet.</p> <h2>Unlimited Undo</h2> <img style="" border=0 src="https://www.lexaloffle.com/bbs/files/1/undo_0112.gif" alt="" /> <p>The gfx, map and audio editors now have unlimited undo stack. Unlike the code editor which has one undo stack per tab, the other undo stacks are global to the cartridge. It also works during audio playback, so it's possible to make a bunch of changes to various SFX and/or song patterns, and then roll the changes back and forth while it is playing.</p> <h2>#INCLUDE</h2> <p>As well as diving code into tabs, it's now also possible to insert code from external text files each time a cartridge is run. This is particularly useful when using an external text editor (no need to modify the .p8 file directly), and also to share code across cartridges while still being able to modify it in one place. Note that this does not make a difference to size limits -- it is just a convenience when working with .p8 files. (When saving .p8.png, the external code is injected). From the manual:</p> <div> <div style="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> Source code can be injected into a program at cartridge boot (but not during runtime), using `#INCLUDE FILENAME`, where FILENAME is either a plaintext file (containing Lua code), a tab from another cartridge, or all tabs from another cartridge: #INCLUDE SOMECODE.LUA #INCLUDE ONETAB.P8:1 #INCLUDE ALLTABS.P8 When the cartridge is run, the contents of each included file is treated as if it had been pasted into the editor in place of that line. Normal character count and token limits apply. </pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <h2>SFX Snippets</h2> <p>Copying a range of SFXes or song patterns will now copy them into the text clipboard in a format that can pasted into other cartridges, or into a BBS post (similar to GFX snippets). To select a range of SFX or patterns, click the first one you want, and then shift click the last one before using CTRL-C. When pasted into a post, it will show up like this: (doesn't work on mobile yet)</p> <p> <iframe src="sfxp.php?id=1_2" width="769" height="97" style="border:none; overflow:hidden"></iframe><a style="cursor:pointer; font-size:8pt" onclick=' var el = document.getElementById("sfxcode_1_2"); if (el.style.display == "none") el.style.display = ""; else el.style.display = "none"; microAjax("/bbs/sfxc/1_2.txt", function (retdata){ var el = document.getElementById("sfxcode_1_2"); el.innerHTML = retdata; el.focus(); el.select(); } ); '> [sfx] </a> <textarea rows=3 class=lexinput id="sfxcode_1_2" style="width:480px;background-color:#fed;display:none;overflow:hidden; font-size:4pt;"></textarea> </p> <p>You can copy the snippet back into a cartridge by pressing the [ sfx ] button, CTRL-C, click the destination sfx or song pattern, and then CTRL-V. Note that songs that use SFX instruments will probably not work if you paste into a cartridge that already has data in SFX 0..7.</p> <h2>Exporters</h2> <h3>HTML Template</h3> <p>The default HTML template used for exporting now includes:</p> <ul> <li>Adaptive layout that also works on mobile</li> <li>Touch controls</li> <li>Gamepad support</li> <li>A controls help menu</li> <li>A start button with embedded preview image </li> <li>Fixed sound under iOS</li> <li>Integrated pause button / pause menu</li> </ul> <p>The default shell and upload also works a bit smoother with itch.io now -- see the manual for uploading instructions.</p> <p><a href="https://www.lexaloffle.com/bbs/files/1/jelpi_export.png" target=_view_image><img style="" border=0 src="https://www.lexaloffle.com/bbs/files/1/jelpi_export.png" width=640 height=304 alt="" /></a></p> <h3>WASM support</h3> <p>Instead of exporting a .js and .html pair, it is now possible to also generate a Web Assembly (.wasm) file which contains the main player code.</p> <p><span style=" display:inline-block; background-color:#eee; padding:2px; margin: 4px; padding-left: 8px; padding-right: 8px; color:#222">EXPORT -W FOO.HTML</p> <p>Web assembly is supported by almost all browsers and servers now, and is more compact and in theory faster to load. CPU cost seems around the same for PICO-8, but the total exported filesize when zipped is around 300k instead of 400k. This hasn't been tested much yet though, so it's not the default and is marked experimental for now.</p> <h3>Raspberry Pi Binary</h3> <p>The binary exporter now generates a Raspberry Pi binary. It is the version with statically linked SDL2 and dynamically linked WiringPi, that I believe works for most Raspberry Pi users. But let me know if you need to generate the equivalent of pico8_dyn.</p> <h3>-export switch</h3> <p>To export cartridges from commandline, you can use the new -export switch, and operate on cartridges outside of PICO-8's filesystem. The parameters to the EXPORT command are passed as a single string:</p> <p><span style=" display:inline-block; background-color:#eee; padding:2px; margin: 4px; padding-left: 8px; padding-right: 8px; color:#222">pico8 jelpi.p8 -export &quot;-i 48 jelpi.bin&quot;</p> <h2>Raspberry Pi</h2> <h3>SERIAL()</h3> <p>Serial() allows you to communicate with other devices via the Raspberry Pi's data pins (the things sticking out that various hats also connect to). There are 2 supported for now: raw GPIO accesss, and WiringPi's spi interface (not tested!). Accessing GPIO via SERIAL() is useful when higher precision timing is needed than manually POKE()ing the gpio memory addresses; transactions including delay instructions are added to a queue that is executed at the end of each frame.</p> <p>Here's an example, controlling a string of 40 LEDs inside Pimoroni's plasma button kit for Picade:</p> <p><blockquote class="twitter-tweet" data-lang="en"><a href="https://twitter.com/lexaloffle/status/1111242321566171136">[tweet <img src="/gfx/load16.gif">]</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></p> <p>Incidentally, 0.1.12 is also optimized to run well out of the box on a Picade, but more on that later!</p> <h3>Windowed Mode</h3> <p>You can now used Windows mode under Raspbian's desktop environment; Just hit alt-enter to toggle as usual. This only works in software blitting mode, so if you use &quot;pico8 -pixel_perfect 0&quot; it will force the the rpi driver to be used instead of x11. Running under the default driver (x11) now also resolves the issue of leaking keypresses and clicks to the desktop, but it is still present when using rpi.</p> <h2>Editors</h2> <h3>Code Editor Shortcuts</h3> <p>CTRL-B to toggle commenting of a <strong>B</strong>lock of lines<br /> CTRL-W to jump to the start (the sta<strong>W</strong>t?) of a line (CTRL-E for <strong>E</strong>nd of line)<br /> CTRL-H for <strong>H</strong>yper search -- search across tabs</p> <h3>Code Editor CPU</h3> <p>The code editor now uses less cpu by caching code highlighting information, so is noticeable when editing long files on older machines or devices with limited battery life. Napkin calculation: after 250k hours of combined use, this will save enough electricity to drive a Chevrolet EV around the circumference of the Earth once.</p> <h3>Blue Background</h3> <p>The default code editor background is now blue! If you'd like to (permanently) change it back, you can now alter it from inside PICO-8 (instead of using config.txt):</p> <p><span style=" display:inline-block; background-color:#eee; padding:2px; margin: 4px; padding-left: 8px; padding-right: 8px; color:#222">&gt; CONFIG THEME CLASSIC</p> <p>Themes only control the background of the code editor at present, but might do more in future.</p> <img style="" border=0 src="https://www.lexaloffle.com/bbs/files/1/evol.png" width=482 height=262 alt="" /> <h3>Blue Dots</h3> <p>When cel values in the map editor have corresponding sprites with only black pixels, or when only black pixels are visible when zoomed out, there is no way to see which tiles have a non-zero value. So for these cases, PICO-8 0.1.12 now displays a single blue dot for that cel to indicate this.</p> <h2>API Changes</h2> <p>API changes that required a cart version bump:</p> <ul> <li>divide and abs sign flipping for 0x8000.0000</li> <li>sqrt(0x0000.0001) freezes</li> <li>&quot;-1&quot;+0 evaluates to 0xffff.0001</li> </ul> <p>I took the opportunity to make some final adjustments to the API and CPU counting:</p> <ul> <li>cursor(x,y,col) can set the draw state colour</li> <li>t() / time() always means seconds even at 60fps</li> <li>line(x1,y1) can be used to draw from the end of the last line</li> <li>next() can be used to write custom iterators // core Lua thing</li> <li>Raw metatable operations: rawset rawget rawlen rawequal</li> <li>peek2() poke2() for writing/reading 16-bit values</li> </ul> <h3>CPU Costs</h3> <p>all(), foreach() are now not much slower than pairs() or manually iterating with integer indexes. The CPU usage reporting is also slightly more accurate, but it will will never be very precise, because keeping track of virtual CPU cost can be expensive itself! And also the PICO-8 CPU costs are made up and essentially silly when looked at too closely.</p> <h2>Display Blitting</h2> <p>PICO-8 0.1.12 is now a bit better at managing scaling to different screen sizes. You probably don't need to know any of this, but here's how it works..</p> <p>When possible, PICO-8 uses &quot;pixel perfect&quot; scaling, which means it chooses the highest possible scaling factor that is a whole number for which the PICO-8 display will fit on the screen. This means that PICO-8 pixels are a nice regular size and without blurry scaling artifacts, but for smaller screen resolutions it means you can get quite wide black boundaries.</p> <p>0.1.12 addresses this by automatically choosing when to run in pixel perfect mode by default. If the size of the margins is more than 10% of the smallest screen axis, it will turn pixel perfect off. You can still force pixel perfect with &quot;pico8 -pixel_perfect 0&quot;.</p> <p>0.1.12 also introduces another setting: preblit_scale. Instead of doing a filtered scale from a 128x128 image (super-blurry), PICO-8 first performs a non-filtered scale up to something like 384x384, and then lets the platform-specific blitter stretch <em>that</em> instead. The default value of preblit_scale is set to automatic, which attempts to find the best trade-off between regular pixel size and pixel crispness.</p> <p>On a related note, PICO-8 is now better at deciding when it is running in the foreground. There was a bug in 0.1.11g and earlier under Windows that caused PICO-8 to think it was in the background and so sleep() longer each frame. So some Windows users might notice improvement when running 60fps cartridges under 0.1.12 using a desktop-sized window (the default fullscreen method).</p> <h2>Search for Author</h2> <p><strong>Search for carts by the same author</strong>. You can find this option under the per-cart menu (hit the menu button while the cartridge you want is selected). It will send you over to the search list, with a search phrase of &quot;by:authorname&quot;. This also works in the BBS search bar.</p> <h2>Road Ahead</h2> <p>This will be the last major update for PICO-8's alpha, apart from some stray bug fixing. Later this year PICO-8 will go into beta with one last feature: online scores. It will take a while though, as I'm hoping to make the architecture scalable and flexible, and will take some time to get it right. The high score tables allow an extra small blob of data that can be abused to do interesting things that might not even be related to keeping track of scores :p</p> <p>Until then, I hope you enjoy 0.1.12, and please post any bugs if you find them!</p> <p>-- zep</p> <h3>Changelog</h3> <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.1.12</p> <p>Added: #include a text file, or a tab from another cartridge<br /> Added: Unlimited undo for gfx,map,sfx<br /> Added: [sfx] snippets: copy and paste sound &amp; music between PICO-8 instances and BBS posts<br /> Added: (BBS) sfx snippet player<br /> Added: CTRL-G in code editor to repeat search across all tabs<br /> Added: Splore search text entry with cursor key button presses<br /> Added: Custom tab widths (tab_width in config.txt)<br /> Added: Web exporter template: joystick &amp; touch support, preview image, menu buttons, adaptive size, controls screen<br /> Added: .wasm exporter (use -w)<br /> Added: Raspberry Pi binary exporter<br /> Added: -export // run the EXPORT command from host commandline<br /> Added: Toggle flags on multiple sprites at once by selecting them first<br /> Added: Confirmations when loading/saving with unsaved changes<br /> Added: Windowed mode support for Raspberry Pi<br /> Added: serial() interface for Raspberry Pi // serial() -- spi, ws281x, direct bit banging<br /> Added: api: peek2 poke2 rawset rawget rawlen rawequal next<br /> Added: Comment/uncomment selected block with CTRL-B<br /> Added: Can save screenshots and gifs from exported binaries via EXTCMD<br /> Added: Can exit exported binaries after runtime error / stop(), and also via EXTCMD(&quot;SHUTDOWN&quot;)<br /> Added: SHUTDOWN menu item added to pause menu when running via &quot;-run cartfile&quot;<br /> Added: -kiosk to run in kiosk mode: boot into splore, favourites menu only, no cart menu<br /> Added: -root_path to set root cartridges folder from commandline<br /> Added: shift+space in song view to play from the current quarter of the selected channel<br /> Added: CTRL-W, CTRL-E in code editor to jump to start / end of line<br /> Added: -accept_future to load cartides made with future versions of PICO-8<br /> Added: -preblit_scale (default: auto) for less blurry scaling with -pixel_perfect 0<br /> Added: -pixel_perfect -1 (auto) only uses pixel perfect scaling when &lt; 10% of the containing screen axis is wasted<br /> Added: highlight all occurances when searching for text in code editor<br /> Added: tab completion across directories<br /> Added: In map editor, non-zero cels that are drawn all black are marked with a single blue dot<br /> Changed: all(), foreach() cpu cost is now much cheaper (but still a little more than using a for loop)<br /> Changed: cursor() can also set the current color with a third parameter<br /> Changed: stat 24..26 return -1 when no music is playing<br /> Changed: 3x4 font characters (uppercase in ascii) allowed in code editor (but not pasteable/editable)<br /> Changed: time() / t() always means seconds since run (but still updated once per _update() / _update60)<br /> Changed: line(x1,y1) can be used to draw from the end of the last line<br /> Changed: del() returns the item deleted on success<br /> Changed: single setting for audio volume (-volume switch, &quot;volume&quot; in config.txt)<br /> Changed: allow '-' in cartdat() names<br /> Changed: 8 and - only map to buttons 4 and 5 by default for CHIP build<br /> Changed: Raspberry Pi pico8_dyn build does not support gpio/serial (and so does not require wiringPi)<br /> Changed: Default theme is 1 (blue background in code editor)<br /> Changed: When loading a cart from commandline, automatically set the current path if inside PICO-8's filesystem<br /> Fixed: Code editor uses too much cpu / battery power<br /> Fixed: cstore() with an external cart name broken when run from exported cart or as bbs cart<br /> Fixed: Undoing changes to SFX after using pitch drawing tool clears SFX data<br /> Fixed: Running headless scripts under Windows / Mac OSX crashes<br /> Fixed: Running headless scripts with no video driver fails<br /> Fixed: Can not load BBS carts in headless script mode (without auto-running)<br /> Fixed: (Web exporter) mouse cursor doesn't work in fullscreen<br /> Fixed: (Web exporter) mouse button 2 brings up context menu<br /> Fixed: (Web exporter) Clusters of FS.syncfs calls causing error messages (and inefficient?)<br /> Fixed: (Windows) PICO-8 behaves as if it is not the foreground application<br /> Fixed: divide and abs sign flipping for 0x8000.0000<br /> Fixed: sqrt(0x0000.0001) freezes<br /> Fixed: &quot;-1&quot;+0 evaluates to 0xffff.0001<br /> Fixed: shift-tabbing to unindent alters selection range<br /> Fixed: background_sleep_ms reverts to default value<br /> Fixed: &quot;open in thread&quot; option appears for local carts<br /> Fixed: (code editor) undo markers in unexpected places<br /> Fixed: root_path, desktop_path in config.txt doesn't work without trailing slash<br /> Fixed: Audio sampling rate is wrong when device/driver doesn't support 22050MHz<br /> Fixed: Loading cart with less than 5 pixel rows of gfx does not clear default white cross sprite<br /> Fixed: cpu cycle exploit using peek4 with no parameters<br /> Fixed: SFX keyboard editing operations (e.g. SPD +/-) sometimes applied to the wrong SFX<br /> Fixed: Cursor behaviour when moving between song and sfx view, and when playing music<br /> Fixed: Selecting SFX notes with shift + home/end/pgup/pgdown<br /> Fixed: Vibrato (2) and drop (3) effects in SFX instruments not observed<br /> Fixed: Can not place note at C-0 in pitch mode<br /> Fixed: CTRL-F search in code skips matches that are close together<br /> Fixed: (Mac) warning about unoptimized program (built with SDL 2.0.9, + now 64-bit)<br /> Fixed: (Raspberry Pi) Keypresses leaking to desktop<br /> Fixed: (Raspberry Pi) Keyboard layout fixed to US<br /> Fixed: printh(nil) prints [false] instead of [nil]<br /> Fixed: toggling audio mute twice returns to maximum volume<br /> Fixed: alt+cursors moves cursor in code editor<br /> Fixed: del does not work on first character of code or commandline<br /> Fixed: preprocessor breaks on double slash in string s=&quot;\&quot;<br /> Fixed: sometimes code executing a little after point of runtime error<br /> Fixed: Token count reported in editor is more than 0 after rebooting<br /> Fixed: &quot;Removed empty tabs&quot; message displayed when loading cart with fewer tabs<br /> Fixed: Member variables highlighted when same as API function names (e.g. actor.spr)<br /> Fixed: Hot-plugged joysticks not recognized</p> <p>v0.1.12b</p> <p>Added: config command (e.g. CONFIG THEME CLASSIC)<br /> Fixed: Windows sound resampling artifacts (moved to SDL2 2.0.9 audio:directsound)<br /> Fixed: Glyphs stored as unicode can not load when #include'd<br /> Fixed: Code highlighting is wrong after select and delete a line<br /> Fixed: Last line endpoint not present in draw state memory<br /> Fixed: Ubuntu 16.04 can not run because requires glibc 2.27 (reduced dependency to 2.14)<br /> Fixed: stat(102) returns nil when run from binary instead of 0 (now 0)<br /> Fixed: Loading cartridge from commandline fails when path contains &quot;../&quot;<br /> Fixed: (OSX) Crash when reloading external changes with CTRL-R<br /> Fixed: (Windows) Crash when running cart with included code<br /> Fixed: Can not export or include extra cartridges outside of current directory<br /> Fixed: Off by 1 when search for line 1 (affected ctrl-b, ctrl-l)<br /> Fixed: html template -- mouse cursor showing over canvas (now hidden by default)</p> <p>v0.1.12c</p> <p>Fixed: CPU usage reported by stat(1) is higher than actual value<br /> Fixed: Fail to load .p8 cartridges w/ BOM marker / CRLF endlines<br /> Fixed: Syntax errors / crash caused by #including files containing BOM / CRLFs<br /> Fixed: Can not save .p8 when contains unresolved #includes<br /> Fixed: Can't open pico-8.txt in Notepad.exe (added CRLFs)<br /> Fixed: Can delete null terminator at end of code (revealing previously deleted code)</p> <p></div></div></div></p> <p>_</p> https://www.lexaloffle.com/bbs/?tid=33883 https://www.lexaloffle.com/bbs/?tid=33883 Tue, 16 Apr 2019 21:40:18 UTC