Log In  
[back to top]

[ :: Read More :: ]

Note: @zep, please have patience reading this, as I think there's more than one thing going on here.

I had to fix @Reload's "Pico-Sprint" cart here.

For whatever reason, they were choosing to make empty-arg func() calls as func"", possibly in an obsolete attempt to save a token.

The problem is, the call to clip"" screwed up the clip rectangle, because apparently clip() is interpreting the single blank string argument instead of ignoring it. I'm not sure if that qualifies as a bug, since Lua and PICO-8 expect strings to be coerced into numbers in many instances, so it may just be expected behavior that wasn't previously working as expected. I checked to see if maybe the single-argument format was meant to work with a table, e.g. clip{0,0,128,128}, but that did not seem to work.

However, there's more...and here begins the second thing

In the process of debugging this, I tried getting the existing clip rectangle from clip()'s return value. I tried these:

x,y,w,h = clip""
x,y,w,h = clip()
x,y,w,h = clip(0,0,128,128)

In each case, only 'x' received a value. On examination, it seemed to be all four x,y,w,h values encoded into one 32-bit value: 0xhhww.yyxx. This is at least valid in a way, but it made me wonder if that's why clip() is now accepting a single argument: is it possible to pass a value like that back into clip to set the rectangle with a single value?

Well, no, it isn't, at least not in the version I have.

So, is this an incomplete feature? Should clip() be returning a 4-tuple or the single value? Or maybe a 4-tuple if called with 4 args, and a single all-in-one value if called with one arg? But then which type should no args return? Right now it always just returns the single all-in-one value.

Personally I expected it to be a 4-tuple, and I suspect most people would. That would also make it much easier to manipulate the resulting values. Anyone using the all-in-one value might as well just poke4 or peek4/$ the corresponding memory registers directly.


TL;DR:

Report #1: clip("") does something, possibly the equivalent of clip(0,0,0,0). This may or may not be expected behavior for a single improper argument.

Report #2: clip() returns an encoded tuple in one value instead of a proper lua tuple, which while useful, cannot be fed back into clip().

P#75172 2020-04-22 20:03 ( Edited 2020-04-22 20:04)

[ :: Read More :: ]

If the first thing you do after loading a cart is to to delete some source code, you can't undo the deletion.

I suspect this is as simple as needing an undo state/fence at load time.

P#75165 2020-04-22 15:40

[ :: Read More :: ]

It's not critical since its only real use is in debugging, but I think tostr(f, true) should probably emit hex addresses with standard PICO-8 uppercase hex digits, not smallcaps:

P#75005 2020-04-19 19:52

[ :: Read More :: ]

I was tinkering with the custom key repeat settings in 0x5f5c and 0x5f5d and I realized that they always seem to be expressed in 30ths of a second. Shouldn't this depend on whether or not the game has _update60(), or for games with custom loops, whether or not they've called _set_fps(60)?

I guess it's not a critical problem if it stays this way, it just seems like it ought to track the fps setting.

P#74999 2020-04-19 19:07

[ :: Read More :: ]

Hey @zep, me again. ;)

I looked through the rather comprehensive list at https://rosettacode.org/wiki/Bitwise_operations and couldn't spot anyone at all who had an operator for rotation, let alone find some kind of standard for it. Most languages use either a function or a textual operator (e.g. a ror b), but those end up making your expressions a lot larger and/or filled with whitespace.

WE COULD BE THE ONES TO SET THE STANDARD! :D

I'll just propose a few ideas. Note that I bring the "|" operator into some of them because normally people have to do rotates by or'ing together two shifted values.

   rotl         rotr
----------   ----------
 a <<<< b     a >>>> b
  a <<> b     a <>> b    -- I like these best, personally
  a >|> b     a <|< b
  a |>> b     a <<| b
  a >>| b     a |<< b

I like <<> and <>> because they imply that part of the shift wraps back around. I also find them aesthetically pleasing.

Also, if this happens, please remember assignment operators and metamethods? :)

P#74985 2020-04-19 16:52 ( Edited 2020-04-19 16:55)

[ :: Read More :: ]

I was going through my old posts, gleefully marking bug after bug "resolved" (THANKS ZEP!:D), and ran across one I hadn't actually posted in the support section.

I know the chat section sees a lot of traffic and moves quickly, so I'm worried it was never seen, and I want to try posting it again in the right section, in hopes of seeing it added to 0.2.0 or a later version:


@zep

I'm trying to write a tool that has text editing, and I find that the devkit keyboard doesn't return a lot of the special keys that it easily could.

You're returning a string, so there's no reason why it has to be just one character. So pressing the Home key could simply return the string "home". No need for special characters, escape sequences, etc., since these verbose names would all be distinct from any single regular typed character.

I'm mainly thinking of the standard navigation cluster: up, down, left, right, ins, del, home, end, pgup, pgdn, but I'm sure there are others.

It'd also be nice if there were a second stat() value that had a bitmask of the modifier keys that are currently pressed, if the host has them. Like, left/right shift, left/right alt/cmd, maybe left/right win/opt, altgr, maybe capslock. Not crucial, but definitely helpful. It'd be nice to be able to support things like ^Z for undo in my tool.

I say all this because one of the things I love about PICO-8 is working entirely within PICO-8, so it's nice to write tools that work inside of the platform, but the devkit functionality is a little limited in this department.

P#74953 2020-04-19 01:45 ( Edited 2020-04-22 20:44)

[ :: Read More :: ]

There's currently no way to get the existing random seed, since srand() doesn't return anything.

Test/demo:

Cart #yudodekegi-0 | 2020-03-29 | Code ▽ | Embed ▽ | No License
2

Could it return the existing seed so we can temporarily change to a sub-system's ongoing seed, then restore it? Like this, for instance:

function handle_ai(ai)
  local old_seed=srand(ai.seed)
  ⋮
  (stuff)
  ⋮
  srand(old_seed)
end

It's minor, since you can always keep your seeds in shadow values from the outset and manually set them each time, but it'd still be handy.

Thanks! :)

P#74306 2020-03-29 13:02 ( Edited 2020-03-29 14:03)

[ :: Read More :: ]

EDIT: I just realized run already takes an argument to serve as the breadcrumb from another cart. So this isn't an option. Never mind, nothing to see here.


Presently, to load+run you literally have to load blahblah.p8 and then run.

Would it be a bother to run the "run" code through the same line parsing that handles "load", and then auto-run it afterward?

I ask because I was running a bunch of local carts from the command line and it was a tiny bother to have to do two steps each time.

...YES, I realize this is a very minor thing, but hey, why not mention it? The worst that happens is that it doesn't get implemented, right? XD

... uh... r—right...?

P#74191 2020-03-25 14:49 ( Edited 2022-04-16 10:18)

[ :: Read More :: ]

@zep

If we type "x = -6", the "-6" part requires two tokens, which I assume is because the version of Lua you use was still internally treating negative literals as positive literals with a unary-minus operation applied to them, e.g. "x = unm(6)".

However, using a negative literal in PICO-8 appears to have the same cycle cost as using a positive literal, as far as I can tell with my benchmarks. For instance, "x = y / -6" costs the same as "x = y / 6".

So basically we're being charged a token for an operation that doesn't actually seem to occur, and really shouldn't need to occur anyway.

Would it be possible to delete the token cost for unary-minus if it's being applied to a literal?

The alternative is that people in dire token straits will write "x = y / 0xfffa", which is just gross. :P

P#74149 2020-03-23 17:49

[ :: Read More :: ]

I think it's too late to suggest this, since you appear to have completely filled the printable characters with the kana glyphs, but just in case there's something to spare somewhere:

I just used one of the unicode thumb glyphs (👎,👍) and realized it'd be handy to have such glyphs in the PICO-8 character set.

I drew up some possible 7x5 PICO-8 glyphs for them:

You could type them with -/+ in glyph mode.

Even if they can't be fit into PICO-8 itself, the thumb-up might be good for the BBS, because I think a lot of people don't realize that's what the ★ glyph on BBS posts is for, given how seldom it seems to be used.

(I guess it's not a big deal if this isn't possible, though, since we can obviously just draw them manually.)

P#74023 2020-03-18 01:48 ( Edited 2020-03-18 02:49)

[ :: Read More :: ]

@zep

Bug #1:

The built-in tuple "..." seems to confuse the syntax highlighter. Notice "END" isn't pink:

Not a big deal, but I figured you'd want to know.

Bug? #2:

Maybe a bug, maybe not. I just noticed that Ctrl+H goes to the start of the document (as with Ctrl+Home). On the other hand Ctrl+E goes to the end of the current line (as with plain End). Is this difference in behavior intentional? If so, no big deal. I just wanted to be sure it was intended vs. accidentally calling the wrong internal "home" or "end" function for one of them.

EDIT: Just as I posted this, I noticed that it's ^W/^E for line home/end, so I guess this probably isn't a bug. Disregard #2.

P#73996 2020-03-16 22:11 ( Edited 2020-03-16 22:14)

[ :: Read More :: ]

Repro:

  • fire up PICO-8
  • switch to code editor
  • type something like 123456789 and hit enter
  • copy and paste that line few times to give yourself something to cursor through
  • using the keyboard, navigate to the middle of one of these lines
  • cursor up and down: should work normally
  • click near the start or end of the line
  • cursor up or down: will change the row properly but maintain the column from before the click

Demo:

This is probably as easy to fix as just setting both the current and virtual column on mouse clicks.

P#73943 2020-03-15 08:42 ( Edited 2020-03-15 08:42)

[ :: Read More :: ]

@zep

Right now if you want to draw a line loop with the cool line(x,y) continuation method, you still have to do at least one line(x0,y0,x1,y1) first to make it work:

-- draw a simple triangle
line(32,96,96,96) -- base
line(64,32)       -- right side
line(32,96)       -- left side

This isn't so bad if you're drawing the figure manually as I just did. But if you're, say, drawing an algorithmic figure's loop, you have to handle that first line conditionally within the loop:

-- draw a simple segmented circle
local cx,cy,r=64,64,32
for a=0,1,0x.01 do
  local x,y=cx+cos(a)*r,cy+sin(a)*r
  if a==0 then
    line(x,y,x,y) -- sets the continuation point
  else
    line(x,y)     -- continued from the last point
  end
end

Or (not shown) you can remove the condition from the loop, but it requires doing math to get the first point outside of the loop and then calling line(x,y,x,y) as above before looping over the subsequent points.

All in all, neither is really better in terms of code than just drawing a series of distinct line(xi,yi,xj,yj) segments.

However, let's say line() with no args invalidates the last position. Let's also say that trying to continue via line(x,y) from an invalid position draws either nothing or just the one pixel, but it does update the last position. Suddenly everything gets a heck of a lot more concise and elegant:

-- draw a simple segmented circle
local cx,cy,r=64,64,32
line()
for a=0,1,0x.01 do
  line(cx+cos(a)*r,cy+sin(a)*r)
end

This should be safe in terms of backcompat, because line() with no args doesn't currently do anything useful, and in fact I'd consider it an undocumented usage that would have been ill-advised to use anyway. Similarly, since there was no such thing as an invalid last point in the past, no one would have written line-continuation code that didn't first update it explicitly in a way that would still work with this change in place.

P#73895 2020-03-13 23:51

[ :: Read More :: ]

This call, with only one arg after the string:

print("hello world", anything_even_a_table_or_function_or_nil)

Behaves oddly and in a way that is not documented in the manual. It renders the string at the cursor and then exits without updating the cursor. It doesn't seem to use the extra argument at all.

The only thing I can see this being useful for is a text countup display, as seen in oldschool memory tests during BIOS startup on PCs. I can't imagine anyone has ever actually used it this way, though.

It'd be far better if this case were treated as if the user wanted the text colored, but didn't want to specify x,y coordinates because they wanted it to work like a regular, scrolling print():

print("I'm blue, da ba dee, da ba die", 12)
P#73626 2020-03-03 05:27

[ :: Read More :: ]

We had some back-and-forth on Discord about row-shifting effects and whether to do them with the CPU or by copying to sprite ram and using sspr. I came up with a pretty good function at the time for the CPU to do it in place, but I've since iterated on that to bring down the token count and also to optimize certain types of shifts.

This is a little demo wrapper built around that function. If anyone's interested in effects like this, I offer this up to them. Take a look at the full-fat version of the function in tab 1, and also at a low-fat version in tab 2, which is a little slower and lacks the edge-clamping feature, but uses about 2/3 of the tokens. You should be able to drop either version as-is into a game or demo and just use it right out of the box.

Performance: The full-fat version can apply a sine wave to the full screen at a cost of about 8-9% of a 30fps frame, while the low-fat version requires about 10-11%.

Token cost: The full-fat version is 155 tokens. The low-fat version is 96 tokens.

Limitations: To reduce token count and because this was written for someone to do a subtle water effect, I have no logic for shifting beyond +/-8 pixels (32 bits). It could be modified pretty easily to do so, it just doesn't right now. It would probably add maybe 1-2 dozen tokens to do so.

Cart #rowshift-0 | 2020-03-01 | Code ▽ | Embed ▽ | No License
6

P#73574 2020-03-01 06:33 ( Edited 2020-03-01 06:33)

[ :: Read More :: ]

Hey @zep,

Is holdframe() intended to be a peer/complementary function to flip()?

I had it pointed out that I'd erroneously marked flip() as undocumented on the wiki, even though it is documented—I just suck at searching the manual. That reminded me to check holdframe(), to see if it was still undocumented, and it still is. It is, however, overtly called out in the changelog as having been added, so it's simultaneously documented and undocumented.

Is it intended that we're allowed to use it for custom game loops, or no? If we are, it'd be nice to have it documented in the manual. Otherwise I'll leave it in the nebulous wiki category of Undocumented API.

Thanks! :)

P#73543 2020-02-28 16:28 ( Edited 2020-02-28 16:31)

[ :: Read More :: ]

I discovered this while trying to reduce someone's not-quite-tweetcart, and I boiled it down to a simple repro case.

These compact lines both parse and function correctly:

x+=1y-=1
y+=1x-=1

But these don't:

x-=1y+=1
y-=1x+=1

Variable names don't seem to matter. I included versions with variable names swapped just so you know it's not the variable order at fault somehow.

Same thing happens both when executing editor/app code and at the shell prompt.

I tried on the BBS and the parser here isn't able to work it either.

I didn't try other operators, like *, /, or %.

Side note: On the same subject, would you mind adding ..= and ^= operators? I think that would make the set orthogonally-complete.

P#71615 2019-12-31 23:58 ( Edited 2020-01-01 00:05)

[ :: Read More :: ]

I was playing around with the slide effect on the volume for white noise and I realized that there was an awful lot of sputtering while it would ramp up the volume, but not while ramping down. It sounded as if maybe the waveform was being doubled in amplitude and thus clipping, or maybe something was messing up the randomizer. I really don't know. That's for @zep to figure out.

Here's a repro case, seems to work the same on the BBS as it did in the executable.

Pretty sure it's not local to my machine's audio hardware, but I'd appreciate others trying it and saying whether or not they hear the same issue.

Edit: Yeah, just checked out this post on my phone, it does the same thing there too. Definitely a bug.

Cart #buwihinuye-0 | 2019-12-26 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA
2

P#71419 2019-12-26 14:54 ( Edited 2019-12-27 02:02)

[ :: Read More :: ]

Edit: Never mind, I think the sound driver on my system has some kind of volume compression enabled.


There seems to be something amiss with the SFX player code.

The cart below simply plays a single SFX. The SFX is a constant sine wave tone with a stepped volume envelope. The envelope steps up each half second, from 0 to 7, and then back down each half second, to 0.

On my PC, this results in the SFX immediately being nearly full volume, stepping up once, maybe twice, until it's actually full volume, and then remaining full volume almost until the end, when it then steps back down four times to medium volume and then abruptly turns off.

On the web player, it seems to be more symmetrical. I'm hearing it start at medium volume and step up four, maybe five times before holding steady for a while and then stepping back down four times to medium volume and abruptly turning off.

Cart #bikitetazo-1 | 2019-11-09 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

P#69745 2019-11-09 09:04 ( Edited 2019-11-09 09:35)

[ :: Read More :: ]

There was a discussion on twitter about not being able to get the stack trace for a dead coroutine, which is understandably frustrating. However, I was sure that I once figured out a way to do it, and I said so, but the code to do so is on a dead PC at the moment, so I had to spend some time figuring it out again.

This sample basically runs a coroutine that waits for 5 seconds and then does something fatal. Each frame it displays the known status and stack trace. Run it, you'll see.

I tried to set up the code to be as simple and understandable as possible, but if you have questions, please feel free to ask.

EDIT! For a VERY simple coroutine exception stack trace dump, see my follow-up post here

Cart #tehuyajiso-7 | 2019-10-19 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA
5

P#69033 2019-10-18 23:43 ( Edited 2019-10-19 07:45)

View Older Posts