@zep Thanks for the clarification on PCM! For streaming via wavetable nodes - will there be some form of synchronization available to make sure timing lines up?
@zep That's great, thanks!
By the way, I saw what you said about split. Here's an implementation that has a convert
parameter akin to PICO-8:
function split(str, sep, convert) -- Based on https://stackoverflow.com/a/7615129 local t = {} str = tostring(str) sep = sep or "," convert = (convert == nil and true) or convert for v in gmatch(str, "([^" .. sep .. "]+)") do insert(t, (convert and tonumber(v)) or v) end return t end |
I'm working on a complete re-implementation of the PICO-8 API within Picotron. If there are any PICO-8 functions you'd like help bringing over, let me know!
Hi @zep.
Glad to help. Another problem though. The screen seems a bit small now.
This is the frame I get running on Google Chrome, with no option to make the work screen bigger.
Is anyone else getting this small size ?
Bug report: crash when copy/pasting a huge block of text/code (> 1mb).
p64_playground_7.js:1 exception thrown: RuntimeError: memory access out of bounds,RuntimeError: memory access out of bounds at wasm://wasm/0020d80a:wasm-function[640]:0x6b6e9 at wasm://wasm/0020d80a:wasm-function[496]:0x5badc at wasm://wasm/0020d80a:wasm-function[857]:0x7e841 at Module.dynCall_v (https://www.lexaloffle.com/play/p64_playground_7.js:1:1225527) at browserIterationFunc (https://www.lexaloffle.com/play/p64_playground_7.js:1:1154454) at Object.runIter (https://www.lexaloffle.com/play/p64_playground_7.js:1:1157507) at Browser_mainLoop_runner (https://www.lexaloffle.com/play/p64_playground_7.js:1:1155976) |
Hey @zep. I found a temporary solution for the small frame in Google Chrome.
Press CTRL and the "=" key (next to the backspace) until you get a perfect double-triple pixel size that fits your screen.
If you guys are experimenting, press CTRL and 0 (zero) to reset your viewing size.
I recently started having an issue with the code editor, about 3 days ago.
I am unable to paste in code that is more than roughly 20 lines or so.
When I open the playground and try pasting in my code, it instead pastes in zxc
.
If i delete that, then it changes to pasting in nothing.
Whenever I press Ctrl+V I see the mouse cursor flicker and lag from about a frame, which indicates that something is definitely happening, but nothing actually gets pasted in.
I checked the Firefox dev console to see if it shows me anything, and this is what I see.
https://gyazo.com/9aa01dcf2bec802f72b1524c4105b5f7
After that, pasting in anything (both small or big) adds 2 new lines to the console.
They are @@ navigator.clipboard.readText not found -- reading from codo_textarea
and @@ get_clipboard_text called
.
The only difference between pasting in small and big is that the second line appears once when successful, but 10 times when not.
Other than that, I've also noticed that Ctrl + Key combinations are pretty wack sometimes.
Ctrl+R sometimes also does Ctrl+V before running the application, which modifies code and crashes it.
Ctrl+V sometimes pastes my clipboard 4 times instead of only once, and a few times it didn't paste in anything at all (even when my clipboard was small).
Ctrl+A also runs Ctrl+V and/or Ctrl+R from time to time.
I checked both Firefox and Chrome, and everything is the same between them.
If you want to debug stuff with me to possibly find the issues, then you can contact me on Discord or by email.
My tag is SoundsDotZip#1143 and my email address is [email protected].
@zep said:
> There is still a difference with PICO-8 though: once a colour has been made transparent with palt(col, true), any remapping for that colour is lost and so palt(col, false) will revert to mapping to itself (i.e. palt(col, false) is the same as pal(col, col)).
I was kind of worried this sort of issue would arise from merging color writing and transparency into the blend tables.
I wonder if it would be better to have both the blend table and a single 64-bit hardware register somewhere that basically acted as a palette colorkey. This would be synonymous with the old PICO-8 palt() booleans. You could still technically accomplish 100% transparency / 100% opacity with the blend tables, but palt() would toggle bits in this register instead of rewriting a row in the table.
It'd make handling transparency changes more efficient host-side, though it'd necessitate one extra test/branch per pixel of course, but the savings of not having to run the src/dst through the 2D lookup table and then having to re-write the pixel as the same color it already is might offset that. It's basically an early-out, a stencil based on color, just like modern GPUs early out if the depth stencil (aka z-buffer) test fails and they don't bother doing the fragment shading for the pixel.
@Felice The thing I'm more irritated by is when you try to draw a black shape and it does nothing. The palt
issue is a minor one and I can see how it can trip you up if you're used to it remembering the previous pal
setting, but I don't see the need for it myself. (Usually, when I want to draw black on a sprite, I use pal(i,0)
rather than making a different color transparent and black opaque, as I think it's more token efficient.) But whereas in PICO-8 it would ignore palt
for shape statements, rather often in Picotron, I draw a black circle and then wonder for half an hour trying to figure out why the ₣¥€₭ doesn't it work??? before I figure out that I might as well have been dipping my digital paintbrush with nothing before wiping it on the virtual canvas. Of course, now that I'm used to it I now know to use color #32 instead, but it still tripped me up far more than palt
destroying the previous color ever could. (Though, I'll admit that I am an amateur programmer so take my opinion with a grain of salt.)
MINESWEEPER
I have done it! I have made a recreation of Minesweeper in Picotron, meaning this is technically the first game for Picotron.
{-EDIT: As has been pointed out below, this may not be the first game made for Picotron. It is, however, as far as I (and others) can tell the first game released for Picotron. While I was editing this post, I also added some comments next to the adjustables to recreate the difficulty settings for the original game.-}
{-ANOTHER EDIT: I have now updated the game to version 3, so this post will remain for the old version only. If you want to play or talk about version 3, go to this thread.-}
To load it in Picotron:
- Paste the following code into the code editor:
[hidden]-- Minesweeper (v2) -- By: Kai -- -- GFX decoder function decode(str) return userdata(chr(91,103,102,120,93)..str..chr(91,47,103,122,120,93)) end -- -- GFX: faces smile=decode"101077777777777777767666666666666665766660000006666576660aaaaaa066657660aaaaaaaa0665760aa00aa00aa065760aa00aa00aa065760aa00aa00aa065760aaaaaaaaaa065760aaaaaaaaaa065760aa0aaaa0aa0657660aa0000aa066576660aaaaaa06665766660000006666576666666666666656555555555555555" curious=decode"101077777777777777767666666666666665766660000006666576660aaaaaa066657660aaaaaaaa0665760aa00aa00aa065760aa00aa00aa065760aa00aa00aa065760aaaaaaaaaa065760aaaaaaaaaa065760aaaa00aaaa0657660aaa00aaa066576660aaaaaa06665766660000006666576666666666666656555555555555555" frown=decode"101077777777777777767666666666666665766660000006666576660aaaaaa066657660aaaaaaaa0665760aa0aaaa0aa065760aaa0aa0aaa065760aa0aaaa0aa065760aaaaaaaaaa065760aaa0000aaa065760aa0aaaa0aa0657660aaaaaaaa066576660aaaaaa06665766660000006666576666666666666656555555555555555" cool=decode"101077777777777777767666666666666665766660000006666576660aaaaaa066657660aaaaaaaa0665760a000aa000a0657600000000000065760a000aa000a065760aaaaaaaaaa065760aa0aaaa0aa065760aaa0000aaa0657660aaaaaaaa066576660aaaaaa06665766660000006666576666666666666656555555555555555" -- GFX: tiles boom=decode"08088888888m8686868m8855588m8656568m8855588m8686868m8888888mmmmmmmmm" block=decode"08087777776m7666665m7666665m7666665m7666665m7666665m6555555mmmmmmmmm" empty=decode"0808kkkkkkkmk444444mk444444mk444444mk444444mk444444mk444444mmmmmmmmm" flag=decode"08087777776m7668665m7688665m7888665m766i665m76iii65m6555555mmmmmmmmm" mine=decode"0808kkkkkkkmk646464mk455544mk656564mk455544mk646464mk444444mmmmmmmmm" falseflag=decode"08087777778m7662685m7622865m7228665m768i665m78iii65m8555555mmmmmmmmm" -- GFX: numbers numbercols={12,27,24,16,2,17,13,32} numbers={ decode"08080077700007777000777770000077700000777000007770007777777000000000", decode"08087777777077000770000007707777777077000000777777707777777000000000", decode"08087777777077000770000007700077777000000770770007707777777000000000", decode"08087000077070000770700007707777777000000770000007700000077000000000", decode"08087777777077000000770000007777777000000770000007707777777000000000", decode"08087777777077000000770000007777777077000770770007707777777000000000", decode"08087777777000000770000007700000077000000770000007700000077000000000", decode"08087777777070000770700007707777777070000770700007707777777000000000"} -- -- adjustables -- beginner: 9x9/10 -- intermediate: 16x16/40 -- expert: 30x16/99 width=10 -- min: 7 | max: 59-60 height=10 -- min: 1 | max: 31-32 mines=10 -- idealy ~10-20% of total tiles -- -- other setup lmb=0 dead=false won=false start=true remainingmines=mines timer=0 -- -- data format: -- bit 0: mine -- bit 1: uncovered -- bit 2: flagged -- bit 3: unused (?) -- bit 4: unused (?) -- bit 5: unused (?) -- bit 6: unused (?) -- bit 7: unused (?) -- minefield=userdata("u8",width,height) -- -- debug: randomized test board --for x=0,width-1 do --for y=0,height-1 do --set(minefield,x,y,flr(rnd(2))) --end --end --dead=true -- /debug -- function place_mines(cx,cy) local candidates={} for x=0,width-1 do for y=0,height-1 do if (abs(x-cx)>1 or abs(y-cy)>1) add(candidates,{x,y}) end end for i=1,mines do local position=candidates[flr(rnd(#candidates))+1] set(minefield,position[1],position[2],1) del(candidates,position) end end -- function bit(n,b,c) if type(c)=="boolean" then return c and n|2^b or n&255-2^b else return n&2^b>0 end end -- function uncover(tx,ty) if (bit(get(minefield,tx,ty),1)) return set(minefield,tx,ty,get(minefield,tx,ty)+2) local nearbymine for xdelta=-1,1 do for ydelta=-1,1 do if (bit(get(minefield,tx+xdelta,ty+ydelta),0)) nearbymine=true end end if not nearbymine then for xdelta=-1,1 do for ydelta=-1,1 do local x=tx+xdelta local y=ty+ydelta if (x==mid(0,x,width-1) and y==mid(0,y,height-1) and not bit(get(minefield,x,y),1) and not bit(get(minefield,x,y),2)) uncover(x,y) end end elseif bit(get(minefield,tx,ty),0) then dead=true end end -- function _draw() mx,my,mb=get_mouse() mbp=mb&~lmb -- mb pressed lmb=mb -- last mb if (not (dead or won or start)) timer=min(timer+1/60,999) local tx=(mx-1)\8 local ty=(my-20)\8 if tx==mid(0,tx,width-1) and ty==mid(0,ty,height-1) and not dead and not won then -- on grid if bit(mbp,0) and not bit(get(minefield,tx,ty),1) and not bit(get(minefield,tx,ty),2) then if (start) place_mines(tx,ty) start=false --set(minefield,tx,ty,bit(get(minefield,tx,ty),1,true)) uncover(tx,ty) if not dead then local coveredtiles=0 for x=0,width-1 do for y=0,height-1 do if (not bit(get(minefield,x,y),1)) coveredtiles+=1 end end if (coveredtiles==mines) won=true end elseif bit(mbp,2) and not bit(get(minefield,tx,ty),1) and not start then set(minefield,tx,ty,get(minefield,tx,ty)^^4) remainingmines+=bit(get(minefield,tx,ty),2) and -1 or 1 end elseif mx==mid(width*8/2-8,mx,width*8/2+7) and my==mid(2,my,17) and bit(mbp,0) then -- clicked on face -- reset puzzle dead=false won=false start=true remainingmines=mines timer=0 for x=0,width-1 do for y=0,height-1 do set(minefield,x,y,0) end end end
-- draw game
cls()
rectfill(0,0,width8,19,22)
--rectfill(0,19,width8,height8+19,20)
palt(0,false)
local emote=dead and frown or won and cool or bit(mb,0) and curious or smile
spr(emote,width8/2-8,2)
palt(0,true)
for x=0,width-1 do
for y=-0,height-1 do
local tile
local tdata=get(minefield,x,y)
local showneighbors
if bit(tdata,1) then -- uncovered
if bit(tdata,0) then -- mine
tile=boom
else -- no mine
tile=empty
showneighbors=true
end
else -- covered
if bit(tdata,2) or won then -- flag
if bit(tdata,0) or not dead then -- correct or still playing
tile=flag
else -- game over correction
tile=falseflag
end
else -- no flag
if bit(tdata,0) and dead then -- game over clairvoyence
tile=mine
else -- nothing special
tile=block
end
end
end
spr(tile,x8+1,y8+20)
if showneighbors then
local closemines=0
for xdelta=-1,1 do
for ydelta=-1,1 do
if (bit(get(minefield,x+xdelta,y+ydelta),0)) closemines+=1
end
end
pal(7,numbercols[closemines])
spr(numbers[closemines],x8+1,y8+20)
pal(7,7)
end
end
end
--rect(0,0,width8,19,1)
rect(0,19,width8,height*8+19,17)
rectfill(1,5,16,13,2)
local str=mid(-99,flr(remainingmines),999)
if str<-9 then
-- do nothing
elseif str<0 then
str="-".."0"..-str
elseif str<10 then
str="00"..str
elseif str<100 then
str="0"..str
else
-- do nothing
end
print(str,2,6,8)
rectfill(width8-16,5,width8-1,13,2)
local str=mid(-99,flr(timer),999)
if str<-9 then
-- do nothing
elseif str<0 then
str="-".."0"..-str
elseif str<10 then
str="00"..str
elseif str<100 then
str="0"..str
else
-- do nothing
end
print(str,width*8-15,6,8)
-- debug: display mouse statistics
--print("mx: "..mx,width*8+2,1,27)
--print("my: "..my)
--print("mb: "..mb)
--print("mbp: "..mbp)
--print("tx: "..tx)
--print("ty: "..ty)
-- /debug
end
[/hidden] - Optionally, edit the adjustable variables `width`, `height` and `mines` to change the difficulty. - Either hit Ctrl+R or, for the optimal experience, continue reading. - Type `save minesweeper` and hit enter. - Type `terminal` and hit enter to go to the desktop. - In the desktop terminal, type or paste in `run_program_inside_terminal"minesweeper.p64/main.lua"` and hit enter. - Adjust the size of the window to make it fit perfectly. - Play! Use the left mouse button to uncover a tile, and the right mouse button to place a flag where you think a mine is. Click the smiley face to restart. Numbers indicate how many mines are in the eight surrounding tiles. The number in the top left is an estimation of how many mines you have left to find, based on the total number of mines and how many flags you have placed down, and the number in the top-right shows your current time in seconds. Uncovering a mine leads to a game over, while uncovering all non-mine tiles causes you to win. Enjoy! |
Very cool work @Kaius 👍
(with great, clear instructions!)
As for first Picotron game - quite possibly.
I saw a couple others making games on the Pico8 Discord, but don't think they've posted the code yet.
Also, I did see this posted on Twitter on Jan 16th
But again, they don't appear to have posted any source - so unable to verify if they're just abusing the hashtag:
https://twitter.com/seimon___/status/1614926407972564993
Moar Picotron games FTW! 😉
Okay so the "bug" I reported before (it's above this by a few posts) was actually on my end.
One of my antivirus' settings made me unable to paste anything too big.
I tweaked the options and now it works fine.
Certainly not the first program posted for Picotron in Lexaloffle, @Kaius. :) I made my demo and set it so others can use the graphics in it.
https://www.lexaloffle.com/bbs/?tid=50942
Still ... it's not good there are so many shortcomings in Picotron. I may wait a-while for some bugs to be fixed before I build anything more in it.
congrats on the first game Kaius!
(not the first doodle, experiment or cart, but the first published game)
[- edit to avoid going more off-thread here: wth is that reply? people on the forum can point out incorrect or obnoxious messages. I will post carts when I want to. -]
Indeed @merwok. You've certainly been with us for over 3-years now. I look forward to you writing and posting in lexaloffle your very first Pico-8 program.
Congrats go to you too, @Kaius for writing the first fully-functional game in Picotron. Well done !
I'm not going to code in Picotron again though until some of the bugs are worked out - yet I am always glad to code and share my code in Pico-8. :)
Grand cheers for @zep who is always looking to the future !
Bug report: set_draw_target breaks _draw
Example:
function _init() _screen=userdata("u8",240,135) end function _draw() set_draw_target(_screen) cls(6) for i=0,240-1 do for j=0,135-1 do pset(i,j,(i+j)%32) end end set_draw_target() -- bug: cls & print are not displayed cls(2) print(stat(0),2,2,8) end |
moving set_draw_target (+ render to memory) to _update restores correct behavior.
Can you post your fixed code? I put all my code in update but it's still not displaying anything after I change the draw target:
function _init() scr1 = userdata("u8", 480, 270) end function _update() set_draw_target(scr1) set_draw_target() -- bug: cls is not displayed cls(12) end |
@freds72 @rilden From testing, it seems that set_draw_target()
does NOT reset the draw target as it is (seemingly) supposed to. It is only reset between _update
and _draw
calls, so once you use set_draw_target
, there is no going back until the end of the _update
/_draw
function. This program shows this bug by printing the working function(s).
function _init() cls() -- erase anything from all the previous testing. (just in case) end function _draw() set_draw_target() -- note that we don't reset this, nor do we set it TO anything at all in the first place! print("_draw",10,20,11) -- this fails... end function _update() print("_update",10,10,8) -- ...but this works! end |
Yep, what I've been doing is storing the draw target via draw_target = get_draw_target()
and using set_draw_target(draw_target)
@HTV04 Thanks! I didn't know that get_draw_target()
existed. Here's a program I made while testing this function, utilizing the ability to make procedural sprites:
function _draw() cls() mx,my=get_mouse() spr(proc_gen_spr(12,17,28,16),mx-7,my-7) end function proc_gen_spr(col,shade,shine,size) local last_dt=get_draw_target() local procedural_sprite=userdata("u8",size,size) set_draw_target(procedural_sprite) circfill(size/2,size/2,size/2-1,shade) circfill(size/2-1,size/2,size/2-1,shade) circfill(size/2,size/2-1,size/2-1,shade) circfill(size/2-1,size/2-1,size/2-1,col) circfill(size/4,size/4,size/8,shine) set_draw_target(last_dt) return procedural_sprite end |
Also, here's a better version of set_draw_target
that resets the draw target when no argument is supplied:
-- on startup dscr=get_draw_target() -- the original display screen. -- new function function set_dt(dt) -- shorter name for the original function. set_draw_target(dt or dscr) -- literally all that's needed. end -- ...and that's it. -- testing --set_dt(userdata("u8",128,128)) -- a simulated PICO-8 screen perhaps? cls(7) -- you WOULD notice this, but you don't, 'cause it ain't there! set_dt() -- resetting the draw target. circfill(240,135,100,8) -- you DO notice this, however. |
(Note to self: I need to be looking into pancelor's function-lister some more.)
thanks for the investigations but I still see that as a bug :)
@freds72 Oh, it's definitely a bug. I mean, even zep thought that set_draw_target()
worked the way it should. Need proof?
function _init() b = userdata("u8",8,8) set_draw_target(b) circ(3,3,1,7) set_draw_target() sx = 20 sy = 20 end |
That code snippet above comes from the fillp
demo, specifically the _init
function which draws the initial fill pattern consisting of a small, hollow circle. To do this, the draw target is set to the fill pattern, and then set back... but, we obviously know that's not what happens. Instead, set_draw_target()
seems to do nothing, as evidenced by what happens if you add in a cls(28)
line or other drawing function after the draw target is supposedly reset, but before the end of the _init
function.
this is so very very cool.
[8x8] | |
i'm really excited by this. i'm playing around with it a bunch as it is, regardless of the current limitations, and can't wait for a desktop release.
i absolutely love how much of the system is exposed and hackable via the system/ subdirectory. it was really fun to edit system/terminal.lua, hit ctrl+s, ctrl+r the terminal, and see my changes take effect. immediately excited to mod the system to fill in some gaps, even though my work is likely to be redundant in future releases.
i really like playing around with building little games and programs in pico-8, it's a really great experience, but this workstation concept is so up my alley it's crazy. i really love building tooling and hacking on little system things. i sate my need to do so with my linux systems now but this is just so much cozier and friendlier with your little-systems charm, zep.
would drop money on this to fund development in a heartbeat, even in its current state, btw. but hopefully not too much development, got to leave some for the rest of us old systems hackers
[17x8] | |
I had to make an account just to say woah. This thing has so much potential! I love that the system source code is accessible from within the system, really cool concept can't wait to see more from this project in the future :D
Picotron Minesweeper v.3
I have now posted a new version of Picotron Minesweeper! The new version is in this thread if you want to see it or discuss it.
This is super cool! Will/could Picotron have access to the internet allowing for multiplayer?
@Johste Sooo... um... wow. I was literally juuuuuust thinking about a game concept I had that would have REQUIRED internet access to play as part of its central gimmick. For those who are curious, here's a brief explanation:
If you didn't read that, don't worry, it's not that important, and I'm still mulling over the details of it in my head so some of what was said there is subject to change. What IS important is that this concept simply would NOT work on a single screen. The game revolves around you not knowing what the other players are up to, and that breaks down if you all share a single screen.
But then, as I'm doodling a few sprites related to it in PICO-8 out of boredom, I look back to the Picotron thread (also out of boredom) and see somebody else asking for network capability! I thought I might have been the only one who might have wanted something like this, but I'm glad I'm not.
Even if full online capability isn't implemented, I would still like at the very least LAN capability to allow for things like what I just described without having to resort to really weird hacks that are undocumented for a reason.
@Sosasees I also like the thought of having a program as a desktop background, although I couldn't get it to work quite like I wanted it to... edit
ing /system/wm.lua
directly just doesn't work because the window manager appears to already be loaded and running, even before the desktop view is actually open. The only way I've found to actually have an effect is to run the code in the terminal, but I haven't found a way to get a window in a desktop running from a terminal, so this approach isn't ideal either. The best way to do this would be to edit /system/wm.lua
directly and then restart Picotron, but this isn't possible in Playground at the moment due to the lack of permanent data storage. Still if you want to see the program I cooked up for use as a desktop background, then just follow these steps:
I call this background 'Ripples', due to... well, what it looks like. Anyways, this program both has interactivity in the form of making a ripple whenever you click, while also doing its own thing by occasionally creating ripples randomly. It even has a bit of utility, as how many random ripples are created depends on the CPU load; by default it will make very few ripples, but if you insert while stat(1)<.5 do end
just before local chance=stat(1)
, significantly more ripples appear. I would love to test out how it looks on my Minesweeper program, but, as stated above, that doesn't seem to be possible in Playground yet. :(
Hey speaking of audio, can you elaborate on what you mean by "64-node synth"? Just from the sound of it, it almost sounds like some sort of modular design??
@IMLXH I guess that's like custom instruments in PICO-8. In other words, PICO-8 custom instrument is a kind of 32-node synth.
Possible bug with large numbers?...
poke8(0x5500,~0xFFFFFFFFFFFFFFFF) --works poke8(0x5500,~18446744073709551615) --errors rectfill(0,0,63,63,8) |
Trying to invert a large decimal produces an error. (The same value works as a hexadecimal).
> <pre>
RUNTIME ERROR: _draw
:38: number has no integer representation
</pre>
Try reposting this in part 2 on Zep's blog. You might have a better chance of getting a response there.
part 2 of zep's blog:
https://www.lexaloffle.com/bbs/?tid=52692
Got random crashes when using (a lot?) userdata (code runs fine and then crash):
p64_playground_11.js:1 Uncaught RuntimeError: memory access out of bounds at 00276a26:0x1943b at 00276a26:0x1a7ec at 00276a26:0x27e1d at 00276a26:0x16ce9 at 00276a26:0x98a8f at Module.dynCall_vii (p64_playground_11.js:1:1761334) at invoke_vii (p64_playground_11.js:1:1755776) at 00276a26:0x15735 at 00276a26:0x16930 at 00276a26:0x75bac |
see https://www.lexaloffle.com/picotron.php?page=faq
note that this thread is inactive, you can use the second one
> ### How Much will Picotron Cost?
>
> $20 (One time fee, DRM-free, cross platform, future updates included). When purchased with PICO-8 or Voxatron, it is only $12 (existing customers will be able to upgrade to this deal when 0.1 is released).
— Picotron FAQ
[Please log in to post a comment]