Log In  

@Oli414

Follow
Follow

Cart [#47025#] | Code | 2017-12-04 | No License | Embed
30

Intro

What if there was a fantasy console in a fantasy console? That's a question that I never got. Instead, I was curious to see if I could come up with a way to get some form of programming on Pico-8.

Well, here you go. The language resembles CPU instructions. The fantasy console allows up to 256 instructions in ROM and has 256 byte RAM which can be viewed at runtime.

The console itself comes with a 16x16 1-bit display and 6 buttons. All IO can be directly accessed and manipulated through RAM. For convenience, it's marked with green (display) and yellow (input) in the editor.

Also, I came up with this idea due to the Ludum Dare theme "The more you have, the worse it is". I actually did it during Ludum Dare and finished it in time. I guess it's an unofficial Ludum Dare entry :-)

Usage

Navigating the editor can be done using the D-pad (arrow keys). Most interactions are done using X.
The available interactions can be seen at the bottom of the editor.

For the sake of space I decided to use binary to display numbers. This might require a bit of getting used to but most values can be found in decimal at the bottom of the screen when interacting with a number.

Writing Code

Pressing X on an empty line will display all the available instructions.
After choosing one the editor might prompt for additional parameters.
Parameters always come with a value represented as an 8-bit number.
A prompt will appear to set the value of the parameter.

To remove a line of code hold the O button and press X.

To move a line of code hold the O button and move it up or down using the D-pad.

Once you're ready to try out your program navigate to the console in the bottom right using the D-pad.
The play button will start to blink. Pressing X will now start the program.
The play button will start blinking again once the program reaches the end.
To terminate the program (for example to get out of an infinite loop) press X and O at the same time.

Saving the program can be done by pressing left twice when in the rom section.
Please note that there's a limit to the size of the program which is smaller then 256 instructions. each instructions takes between 3 and 5 byte to save and a maximum of 256 bytes are saved.

Instructions

Set (address value)
Sets value at address to value.

Add (address, value)
Adds value to the value at address.

Subtract
Subtracts value to the value at address.

Jump (rom address)
Jumps the program count to rom address.

Jump if zero (rom address, value)
Jumps the program count to rom address if value equals zero.

Jump if not zero (rom address, value)
Jumps the program count to rom address if value equals zero (higher than zero).

Or (ram address, value)
Bitwise or value to the value at address.

And (ram address, value)
Bitwise and value to the value at address.

Not (ram address, value)
Bitwise not for value and stores value at address.

Bit shift left (ram address, value)
Shift bits to left at address value times.

Bit shift right (ram address, value)
Shift bits to right at address value times.

Call (rom address)
Jumps the program count to rom address and adds the current rom address to the program stack.

Return
Jumps the program count the the last rom address that was added to the program stack.

End

Well, I hope that you folks can have a bit of fun with it. Let me know if you were patient enough to make anything!
Also, feel free to make suggestions. There's plenty of space left for more instructions if needed.


Version 0.11a
Cart [#47024#] | Code | 2017-12-04 | No License | Embed
30

Version 0.10

Cart [#47015#] | Code | 2017-12-04 | No License | Embed
30

Version 0.9:

Cart [#46974#] | Code | 2017-12-04 | No License | Embed
30

P#46975 2017-12-03 20:31 ( Edited 2018-11-19 05:02)

Recently I've worked on 2 little libraries. However, I'm not sure how I feel about the token count in these cases and I'd love to discuss that with the community.

Libraries can provide a piece of functionality that they would have otherwise programmed themselves. Someone creates a library and other people can use it in their games.

But unfortunately I feel like it's simply not worth it to ever use a library with Pico-8. Why? Because of the token count.

In pretty much every instance you're better off writing a piece of code yourself then using someone else's library. You may not need specific features from a library but using this library will still cost you those tokens.

What are your thoughts about this? Would you use a library? Or maybe you have a smart idea of dealing with this limitation.

P#36466 2017-01-23 08:36 ( Edited 2017-01-24 06:11)

Cart [#36108#] | Code | 2017-01-19 | No License | Embed
10

Walk around with WASD. You can enter the house near the old lady.

Pico Crossing is (as the name implies) inspired by games like Animal Crossing and My Sims.

I've been working on this game for a few days now and a lot of the basic systems are in place now.

If everything goes to plan I have a pretty sweet never-seen-before feature high on my priority list which will allow players to interact with other players which should keep the game interesting to play for a longer period of time than a single play session.
More on this later in the future.

Planned Features

  • Buy furniture for your very own home.
  • Collect/harvest items to trade with other villagers.
  • ??Super cool secret feature??

I'm really hoping that everything will fit in the token limit. These features really are the bare minimum of what I'd like to add so hopefully there will still be some space left to flesh it out more.

Let me know what you think!

P#36110 2017-01-19 18:39 ( Edited 2017-01-22 02:06)

Cart [#35123#] | Code | 2017-01-06 | License: CC4-BY-NC-SA | Embed
29

Dialogue Text Box Library (DTB)

DTB is a code snippet that you can use to implement a dialogue text box to any game in just seconds.
Setting it up goes as follows:

  • Add the dtb code to the top of your own code.
  • Call dtb_init in your initialization.
  • Call dtb_update in your update.
  • Call dtb_draw function in your draw.
    And that all there is! You can now simply call "dtb_disp" wherever you want.

Usage

dtb_init(numlines)

Call this to initialize all dtb's variables. Takes an optional parameter which defines the maximum number of lines that will be displayed. Defaults to 3.

dtb_update()

Call this every update. All logic is contained within dtb.

dtb_draw()

Call this every time the screen gets drawn. Preferably at the end so the textbox always appears at the top.

dtb_disp(txt, callback)

Call this to display txt in a textbox. The text is added to a queu so this function can be called multiple times after each other without interfering with the previous text.
Takes an optional callback parameter (function) which is called when this particular piece of text is done displaying.

The actual snippet

Here is the minimized snippet. 1370 characters and 447 tokens:

-- dialogue text box library by oli414. minimized.
function dtb_init(n) dtb_q={}dtb_f={}dtb_n=3 if n then dtb_n=n end _dtb_c() end function dtb_disp(t,c)local s,l,w,h,u s={}l=""w=""h=""u=function()if #w+#l>29 then add(s,l)l=""end l=l..w w=""end for i=1,#t do h=sub(t,i,i)w=w..h if h==" "then u()elseif #w>28 then w=w.."-"u()end end u()if l~=""then add(s,l)end add(dtb_q,s)if c==nil then c=0 end add(dtb_f,c)end function _dtb_c()dtb_d={}for i=1,dtb_n do add(dtb_d,"")end dtb_c=0 dtb_l=0 end function _dtb_l()dtb_c+=1 for i=1,#dtb_d-1 do dtb_d[i]=dtb_d[i+1]end dtb_d[#dtb_d]=""sfx(2)end function dtb_update()if #dtb_q>0 then if dtb_c==0 then dtb_c=1 end local z,x,q,c z=#dtb_d x=dtb_q[1]q=#dtb_d[z]c=q>=#x[dtb_c]if c and dtb_c>=#x then if btnp(4) then if dtb_f[1]~=0 then dtb_f[1]()end del(dtb_f,dtb_f[1])del(dtb_q,dtb_q[1])_dtb_c()sfx(2)return end elseif dtb_c>0 then dtb_l-=1 if not c then if dtb_l<=0 then local v,h v=q+1 h=sub(x[dtb_c],v,v)dtb_l=1 if h~=" " then sfx(0)end if h=="." then dtb_l=6 end dtb_d[z]=dtb_d[z]..h end if btnp(4) then dtb_d[z]=x[dtb_c]end else if btnp(4) then _dtb_l()end end end end end function dtb_draw()if #dtb_q>0 then local z,o z=#dtb_d o=0 if dtb_c<z then o=z-dtb_c end rectfill(2,125-z*8,125,125,0)if dtb_c>0 and #dtb_d[#dtb_d]==#dtb_q[1][dtb_c] then print("\x8e",118,120,1)end for i=1,z do print(dtb_d[i],4,i*8+119-(z+o)*8,7)end end end

A readable/editable version can be found in this demo's code.

Feel free to use and customize this code in your own projects! I'd love to see it being used!

P#35126 2017-01-06 19:00 ( Edited 2017-07-12 14:30)

Cart [#34878#] | Code | 2017-01-03 | License: CC4-BY-NC-SA | Embed
8

Demo Controls:
Position the pointer in one of the 4 quarters using the arrow keys to change the music.

The music will change depending on which quarter you're in. The check marks in these quarters show which channels are enabled for each quarter.

The changes will go into effect as soon as the pattern ended.

Background Story:
I came up with the idea of having the music chance depending on where you are while still keeping the same song. I quickly ran into an issue. I realized that there was no way to make this happen using just the "music" function.

Later that day I found out about the "peek" and "poke" functions: allowing you to directly read and write to ram. I found out where to find the music pattern section and started mapping it out to get more control over it.

Music in RAM:
Let's take a look at how the music patterns are mapped out in RAM:

Start: 0x3100:
64 patterns (256 byte).

pattern (4-byte):
0x0 [1-bit loopStart][1-bit active][6-bit soundIndex]
0x1 [1-bit loopEnd  ][1-bit active][6-bit soundIndex]
0x2 [1-bit advance  ][1-bit active][6-bit soundIndex]
0x3 [1-bit unused?  ][1-bit active][6-bit soundIndex]

As you can see each pattern takes up 4 bytes, 1 for each channel minus 1-bit per channel which is used to store whether or not this pattern is the start of a loop, the end of a loop or simply the end of a song.

Of course writing the code for this is a little tedious. This is where the music library comes in!
enableSalesManVoice()

The Music Library!
The music library is a small library that you can use to manipulate the flow of your music on runtime!

This means that you can for example dynamically chance your music based on where the player is or what the player is doing.

The music library only consists of 6 functions which can be used to manipulate the music patterns. Everything that you can do from within the editor can be done at runtime.

Features:

  • Enable and disable a pattern channel.
  • Change the sound that a pattern channel plays.
  • Full control over the way your music loops and when it stops just like with the 3 blue buttons in the editor.

Changes made to a pattern that is currently playing will only go into effect the next time it plays. This means that you can easily change out the patterns without having to worry about it changing abruptly.

-- Music Library by Oli414

-- returns the full byte that represents a channel including the pattern flag.
-- mainly for internal use.
function m_getchannelbyte(pattern,channel)
    return peek(12544+pattern*4+channel)
end

-- sets the full byte that represents a channel including the pattern flag.
-- mainly for internal use.
function m_setchannelbyte(pattern,channel,value)
    poke(12544+pattern*4+channel,value)
end

-- returns wether or not the channel is active.
function m_getchannelactive(pattern,channel)
    return band(m_getchannelbyte(pattern,channel),64)~=0
end

-- sets wether or not the channel is active.
function m_setchannelactive(pattern,channel,active)
    local val=m_getchannelbyte(pattern,channel)
    if active then
        val=band(val,191)
    else
        val=bor(val,64)
    end
    m_setchannelbyte(pattern,channel,val)
end

-- returns the pattern flags (loop and stop).
-- return bool:loopstart,bool:loopend,bool:advance
function m_getpatternflags(pattern)
    return band(m_getchannelbyte(pattern,0),128)~=0,band(m_getchannelbyte(pattern,1),128)~=0,band(m_getchannelbyte(pattern,2),128)~=0
end

-- sets the pattern flags (loop and stop).
-- params bool:loopstart,bool:loopend,bool:advance
function m_setpatternflags(pattern,loopstart,loopend,advance)
    local flags={}
    flags[0]=loopstart
    flags[1]=loopend
    flags[2]=advance
    for i=0,3 do
        local val=m_getchannelbyte(pattern,i)
        if flags[i] then
            val=bor(val,128)
        else
            val=band(val,127)
        end
        m_setchannelbyte(pattern,i,val)
    end
end

Feel free to use it in your own game!

In case you're wondering, the song is a sped up, edited version of a song I made a few years ago:
https://www.youtube.com/watch?v=W8ZKLQeQOSM

P#34879 2017-01-03 18:29 ( Edited 2017-01-03 23:29)

About | Contact | Updates | Terms of Use
Follow Lexaloffle:        
Generated 2019-09-22 22:42 | 0.081s | 4194k | Q:74