Log In  

Cart #drcreep-2 | 2021-11-08 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

A preview version. The game is actually finished, contains all the elements (and is at the token limit). What is still missing are various labs. There are currently only a handful, all are solvable. Compared to the original there are some changes, on the one hand because the layout is different (40x24 vs 16x16), on the other hand because I have defused some "backtracking" and death traps. Nevertheless, please note, the levels are from 1984 - there you have something different design.


So, you're looking for a place to work? Something special, challenging, with a good salary? Well, we have just the thing for you.
Many different options open for your inspection. Just step inside ... Oh? You want to leave already? I'm afraid that's simply not possible ... not until you have taken the complete tour.
You'll notice that we have all the modern conveniences. Electrostatic energy generators to warm things up. Piped-in music which I'm sure you will find quite haunting. Doors galore, and you never know what you will find on the other side. Once the death rays start lining up behind you, however, I know you will be eager to find out.
You may want to step lively over trap doors and through the force fields - we've lost several potential applicants that way. Over there, of course, is mummy's room. Mummy seems to be all wrapped up at the moment, but probably not for long. And a break room? At the Laboratories, all the rooms are restful, although many of the occupants are not.
Neighbours, you ask? I Know you will love them. Frankenstein's Monster just seems to pop up whenever you least expect him.
Well, I really must be leaving now. I'm sure you can find your way around. Don't be alarmed. There's a key in here somewhere. You will find your way out eventually... and if not, Doctor Creep will be back shortly and you can help him with his, ah, experiments.
Goodbye now ... and good luck.

Playing the game

You are captured in a Laboratories and your goal is to escape.
Open a map with 🅾️.
In the pause menu you can save a game state. Note that the status is stored before entering the room.




Doors and Doorbells


One way to open a door is to use the doorbell. Operate the doorbell by standing in front of it and pressing the ❎ button. To go out an open door, stand in front of the door and press ⬆️ or ❎.



To get on a ladder, stand directly behind it and push ⬆️ or ⬇️. You can get off of a ladder whenever your feet are even with the front of a walkway.

Sliding Poles


To get on a sliding pole, stand directly in front of it and pull ⬇️. you cannot climb up the sliding poles. You can get off of a pole whenever your feet are even with the middle of a walkway.

Lightning Machine


Turn the sparks on or off by standing in front of the switch and push ⬆️,⬇️,❎.

Force Field


Turn off the force field by standing in front of the control and pushing ❎. The force field will remain off for a few seconds after the button is released.



When you run in front of the ankh, the mummy slides out of its tomb. Mummies are
too stiff to use ladders or sliding poles.

Locks and Keys


To pick up a key, stand in front of it and push ❎. You can open a lock only after you have picked up a key of matching color. Stand in front of the lock and push ❎.

Ray Gun


Operate the gun by standing in front of the control and using ⬆️ and ⬇️ to aim and ❎ to fire. The gun fires automatically when it is at the same level as a player.

Matter Transmitter


Stand in the booth and hold ⬆️ until the color in the booth matches the color of the desired receiver oval. Push ❎ to transmit.



The trapdoor opens or closes whenever anyone runs in front of the control.

Frankensteins Monster


When you walk in front of his coffin, frankensteins monster awakens and begins to chase you. frankensteins monster is able to use the ladders and sliding poles.

Conveyor Belt


To change the motion of the conveyor belt, stand in front of the control and push ❎.

The exit Door


The door at the right leads out of the laboratory. When you go out this door you have escaped.


https://github.com/GPIforGit/The-Laboratories-of-Dr.-Creep/releases - download the assets

There is a editor, splitted in several files:
creep.p8 - the game - stand-alone
creepbuild.p8 - pack all the data and store it in creep.p8
creepedit.p8 - the level-editor

And some data - no lua code here. Also only parts of the p8 are packed from this files:
creep_endscreen.p8 - the End-Screen, must be placed completely in the shared gfx rom!
creep_levels.p8 - the level-data
creep_mainback.p8 - the main-menu background, must be placed completely in the shared gfx rom
creep_music.p8 - main-menu music.
creep_sprites_sound.p8 - gfx (only 0x0000-0x1000), gfx-flags and sfx are used from here.

You need all the files to edit levels, for playing only the creep.p8

Note that when you save the level data, it is stored in "creep_levels.p8". When you want to test your level, you must run creepbuild.p8 or choose in the pause-menu "build".

There is a limit of 31 rooms and 15 of every object. First select a object with the keys, than place it with the left mouse button.

A switch can operate more than one machine. After placing a switch you can link the switch to a machine by simple click left on the machine. Right-click will quit link mode. To relink right click on a switch.

Doorbells and locks work the same, link them with doors.

When you place a door, you must set an connected door. Move the room with + - < > or switch room over the map (tab) and place there the second door. When you place the second door in the same room you create an exit-door.

With tab you enter map mode. Move the cursor over one map and press tab again to enter the room. With left-click on a room you can move it, right click to resize it.

The best way to edit the labs is to open pico8 twice, once the editor and once the game. If you want to try something out, select "build" in the editor pause menu and then ctrl+r in the game to reload the changes.

Working with the editor

Important - keyboard is only detected, when the pico8-window is activ and the mouse cursor is in the window!

left mouse button --- set object or move the object under the cursor

right mouse button --- change size of object under the cursor or go through a door or start/stop linking object (switches, door bells or locks)

0-9 * / . , --- change state/color of the object, for example the color of the walk ways, active/deactivate, change direction and so on

backspace --- delete the active selected object. Important, when you delete a lightning machine or a door, you should check every machine, switch and doorbells - they may be invalid.

space -- walk through door

w -- walkway
l -- ladder
s -- sliding poles
d -- door
b -- doorbell
o -- lock
k -- key
c -- conver belts
m -- lightning machine
i -- switch for lightning machine
f -- force field
t -- trapdoor
x -- matter transmitter booth
v -- transmitter destination
u -- mummy
r -- frankenstein monster
g -- ray gun

  • > -- next room
  • < -- previous room

shift+r -- rename lab when you empty the name, the lab will be deleted.

shift+s -- save (but not build!) the level data.

shift+e shift+1 -- start position player 1

shift+w shift+2 -- start position player 2

tab -- enter map mode

ctrl+c shift+c -- export lab as clipboard-string

ctrl+v shift+v -- import lab from clipboard

behind the scenes

Some may have guessed it already, the game is a "The Castle of Dr. Creep" clone. A classic on the C64 from 1984 and was quite unique at the time.

The original game is relatively complex and uses a complete floppy disk. The problem here is that I wanted to insert as many of the castles as possible. To put them "classically" in the map data does not work, much too large, so a level editor had to be created. Writing it in Pico8 was not so easy, it is almost more complex than the game.

A special feature of the level data is that I do not save byte wise, but bit wise. For example, to save the status of a trapdoor, I need exactly one bit. This method is also used for the game saves, otherwise it would be partly impossible to accommodate this in 256 bytes. However, I had to cheat a bit, for example, a round position of the creatures is stored. It is possible that a loaded game does not always remain solvable. But I think I've solved the problem.

In addition, I use the lzw logarithm to store even more data. it is possible to place data in source code via string, but somehow I find that inelegant. The packed data also has the advantage that it can be edited more easily with tools without changing the lua code.

Compared to the original castle, there are some changes, on the one hand because the layout is different (40x24 vs 16x16), on the other hand because I have defused some "backtracking" and death traps. Nevertheless, please note, the levels are from 1984 - there you have something different design.

The game should be similar to the original, but not just copy it. I've made some changes. The monsters, for example, always go at the closer player (in the original it was always player one). Likewise the map, in the original it appears after each level and you have to confirm it, I immediately switch here to the next room. This increases the game speed enormously.

The story text is a variant of the text on the back of the box. The object descriptions are variants of original tutorial.


P#99419 2021-10-31 16:09 ( Edited 2021-11-08 15:36)

by GPI
Cart #lzw-1 | 2021-10-30 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

I have translated and extend the lua code from here
I tried to reduce the token count, but I wouldn't surprised when someone will shrink it more.

lzw is the codec that for example gif use, it was patented, but it expired 2004.
more information:

I tested the code with the JELPI-Graphic&Sound data - and it will compress it to 6094 Bytes (from 17152 - ~36%).

With the next update the high-memory above 0x8000 will be useable (at the moment only with a undocumented poke), my plan is to place there 32kbit of graphic and sound data. The problem is, that this memory is not saved and I don't want to store it in the source-code because it is too big.

With this code I can compress the 32kbit and store it in the "rom" (the lower 0x4300 bytes). Create a "build"-cart which fill the 32kbit (for example with the reload()-function from other carts), compress the data and cstore() the compressed data.
Copy the compressed data to the the "game-cart", on start decompress the data in the high-memory-area and copy then the part currently needed in the map/sprite-memory.

About the tape_()-function: Think about it like a "punched tape" - it can be used to store datas with variable bit-size. You can use it also for the "Persistent cart data". Normaly you can place 256 Bytes. When you want for example to save if a door is open or closed, you need only one bit. With this routines you can easily store 256*8 = 2048 Doors. The routine should handle 1 to 16 bit values.

P#99373 2021-10-30 13:10 ( Edited 2021-10-30 18:27)

it would be nice, when the poke() would return the address after the poke, like print() does.

for example:


should do the same as




instead of



adr = poke(adr,ord(str,1,#str))


P#99326 2021-10-29 18:14

it would be nice to select where the pause menu should appear. Also the possiblity to draw a custom background for the pause.

For example for a RPG. It would be useful to draw the player-status on screen and the pause-menu on the right button of the screen. In combination with the menuitem-command it would be an easy and "cheap" possibility to create a status-menu. Or display a map of the current level, an inventory and so on.



position could be 0=top left, 1=top, 2 top right, 3 left, 4 center (default), 5 right, 6 bottom left, 7 bottom, 8 bottem right
And draw-function is a function which is called direct before the pause-menu appears.

P#99173 2021-10-26 18:26

When you want to use the shared part of the worldmap, you can only definied 127 Sprites. In Map-Editor the high-bit 0x80 is completly unused.

It would be nice to set a "Map mode" to use this "wasted" bit. Possible solutions would be one of this

  • Flip X
  • Flip Y
  • Use second palette / apply fill pattern

With Flip you can simple reduce the needed sprites with flipping:

Also second palette you can reuse sprites like here (cloud/bush)

oh, and of course a combination would be nice:

It would be nice to set all effects for every cell, but we only have one bit....

Maybe an additional mode would be nice

  • flip depending on screen quarter

    But this could be a little bit confusing. It should orientate on Map-Values, not display.
P#98122 2021-10-02 13:12

by GPI
Cart #picman-1 | 2021-10-02 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA


It is a Pac-Man close, so simple use the direction-buttons to control Pic-Man.



You control Pic and your goal is to eat all pills to win the maze.

Don't touch the ghosts, they will kill you.

When you eat a power pill you become strong enough to eat the ghosts.

In every maze two fruit will appear in the middle of the maze, don't miss them.

Every 1000,2000,4000,... points you get a extra live.

Behind The Scenes

I watched URL Game Maker's Toolkit and was amazed, how "complex" the ai of the ghost are. Since Pic-Man was my first PICO8-Project I decide to re-program Pac-Man. And so many problem started.
First problem, the maze, with a 8x8 tile size it is simple to big for the 128x128 screen. 6x6 would fit, but the map-system is not flexible enough. And so I remembered, that on the old classic c64 you often used the print-command. And again a new problem, how to design the font and how to store it? So hours later a created a URL CharSet Editor and this problem was solved. So the maze is on the screen, now place the pills. First I tried to place the pill exact like the original, but it doesn't work, since my maze is compacter. So i placed more pills and between the "tiles". First I used sprites to draw the pills-dot, in other systems it is nearly always better to use a sprite/texture instead of drawing direct. Big mistake, it will consume around 90% of the virtual cpu - so I changed it to pset()-commands and now I only consume around 50%.
Next step: The main character. Not difficult, he simple runs in tiles and can only change the direction on every tile. The first version couldn't go backwards, but because in the first levels Pic-Man is faster then the Ghost, I changed this. Also the Original could do this. To draw Pic-Man I used 4 sprites, since I only draw a quarter of Pic-Man and use the flip options of the spr-command.
I wanted as less sprites as possible.
The ghost AI was also many try and errors. My ghost react a little different from the original, they have similar behave, but the ghost go more randomized. Also one Ghost really like the fruits. One Problem was, that it could happen, that two ghosts are run exact the same way and nearly the exact same position. So now when two ghost touch each other and go to the same direction, I forced to change one to choose a different direction at the next possible tile. Same as Pic-Man, the ghost are 4 Sprites. Two for the top, one for the bottom (because of the wave-animation) and the eyes.
So now how to create the title-screen. I don't find that the original looks nice, so I searched for artwork. And the next problem - how can I got a picture to a PICO8-rom? Again hours later a new tool was born: URL GFXedit. I used only the the shared part of the spritesheet to save the graphic for the title screen. My plan was to use more artwork and replace the shared part. At the end I only add a game over screen, because I run out of space.
So next big problem Music. I'm not a musician and have no idea of music work. I don't like the original wakka-wakka sound of Pac-Man, I like more the Pac-Mania-Music, but how transfer this to PICO8? Midi-files would maybe a solution, but PICO8 can't open it and I have no idea, how the midi-files work. By accident I found MuseScore 3 and the possibility to export to musicxml, a text-based format. So again hours later a wrote a little program to convert the musicxml to pico8 (Sorry unpublished at the moment, because it miss any interface). I'm not really happy with it, but it work.
In the first version I only add one Level, the original one. But since I draw 12 Fruits, I want more than one level. This was first a problem, because I added the pill-position as static data, now I must phrase the level-data to generate the Borders, add the pills, where the fruit appears and where the ghosts and Pic-Man starts. You can edit the mazes in the source-code and more, if you like.
Since the music used much more than 64 sfx-sounds, I placed the sound-date in the sourcecode. I have optimized the data-format (first one was a big hex-string [[0000a0e01002]], second improve the format [[,,a0,e0,10,2]] and the third uses a special-char-format, so it used nearly everywhere only one char per byte. BTW. one song is too long, it has more than 64 sfx. When the first part is finished, I poke new sfx and music-data in the memory and play part 2.
I had planed to add a third song, but he doesn't sound good and I had again a Problem: over 100% compression. Sadly I must delete the first tab of the code - a big comment with the global variables and what they do.
Now the project is complete - It missed the Intermission from the original, but I have no place any more. I also don't have a good idea to add new ones...
And finally I add a volume-control. It live-patch the sfx-data to reduce the volume.

Very long text - did someone read it complete?


Used Tools

URL CharSet Editor
MuseScore 3
Corel PaintShop Pro X7

Used resources

URL Pac-Man Wiki - Pac-Man Gallery
URL Pac-Man Maze Generation
URL Pac-Man by MineWarz
URL Pac Man Death by YaketyGrass
URL Block Town / Sequenced by: Oedipus / Originally Composed by: Ben Daglish
URL Pacman's Park / Sequenced by: Oedipus / Originally Composed by: Ben Daglish

P#98065 2021-09-30 22:02 ( Edited 2021-10-02 19:11)

It is possible to write a string (for example for a hiscore-table) to the memory with:


but this:

? chr(peek(0x5e00,5))

doesn't work, because chr only accept one value.

P#97989 2021-09-29 17:11

GFXedit for Pico8


GFXedit is a small tool to handle the sprite, map und label data from a p8-file with many features, like export and import as png or lua-data, copy&paste, display the usage of sprite and many more.


github.com - GFXedit

Sprite-Overview (left side)

You can simple select an sprite with a left click. If you hold down the mouse button, you can select a group of sprites.
With a right click you can Copy the current selected sprite to the "red border" place. When you have selected only one sprite, shift + right click will replace every appearance in the map.
Over/Under the Sprite overviews are Tabs. "Low" to show the sprites <= 127, "High" for sprites >=128 and "Minimap" to activate the minimap.
Under the Sprite-overview you can find the coordinates in the world (if the cursor is in the Worldmap, the ID of the sprite under the cursor and the flags of the ID under the cursor. You can also sets flags of the current selected sprite here.
Below that you find some views:

"Flags" activate a small bar under every sprite with small indicators which flag is activ.

"ID" show the HEX-Id over every Sprite

"Count" show of often a sprite is used.

"Grid" activate a small grid

Editor-Overview (right side)

You can select between "Map" - the world editor, "Sprite" - the sprite editor and "Label" a label-viewer of the p8-file. Map and Sprite can be edit, labels only displayed (but in- and exported).
With left click you draw in the map/sprite, with right-click you select a current object under the cursor. You can select multiply objects with the rubber band to copy complete structures. You can even select multiply objects in the map and switch to the sprite-mode to edit this object.
Under the editor field you find some options:

"Stamp" - simple draw in the map / sprite

"Line" - draw a line

"Box" - draw a box

"Ellipse" - draw a ellipse

"Fill" - fill (on map it is clipped by the current visible screen)

"Filled Box" - a filled box

"Smart Box" - a variant of box, when you select an 3x3 pattern in the sprite sheet, it will then draw a box in the editor, it will more "stretch" the selection to the draw box.
For Example, when you right-select something like this:

And draw a Box, it will look like this:

"Filled Ellipse" - a filled ellipse

"ID" - display the id over every tile in the editor.

"Grid" - display a grid over the editor

"Copy 00" - when active (default) sprite-id 00 and color 0 is draw with stamp/box. Otherwise it will be ignored / transparent.

"Find Sel." - the current objects blinks now in the editor and minimap.

"Hi as Hex" - A special and experimental mode. Since "Sprite High" and "Map High" use the same memory, many prefer the map data. Now the high bit is completed unused in the map data. The idea here is, that you can use the useless High-Sprites as indicators in the world. For example place a sign the world (from the lower sprites), activate the "Hi as Hex"-mode, now select a high-sprite (for example "80") and place it over the sign in the map. The sign-ID is now copied to the Sprite-flag of "80" and the editor shows a sign with an 80 over it.
Of course PICO8 can't handle this, you must write a code that scan the map-data for sprites over 128, store the places in a table and replace the map-data with the sprite-flag of the high-byte-sprite.

"Colorfield" - in map mode you can select a background color, in sprite mode the current color.

"1" to "10" - a zoom level.

"Load Cart" - load data from an p8-file. Only graphics, sound and lua data are ignored.

"Merge Cart" - select an p8-file and it will replace the graphic-data in this file.


You have here multiply options to export any kind of data.
You can export as image:

"Sprite complete" - export the complete sprite-sheet (128x128 pixels)

"Sprites low" - export the sprites 0-127 (128x64 pixels)

"Sprites high" - export the sprites 128-255 in the shared memory (128x64 pixels)

"Map complete" - export the complete world map (1024x512 pixels)

"Map low" - export the "upper" part of the map (1024x256 pixels)

"Map high" - export the "lower" part of the map in shared memory (1024x256 pixels)

"Label" - export the label used for cartridge-export of pico8

"Map screen" - the middle 16x16 tile big screen in the map-editor as image (128x128 pixels)

"Sprite selection" - the current selected sprite (vary in size)

You can also export as lua-data. You can then copy this data in the pico8 code editor and switch dynamical between diffrent sprite oder mapdata. You can also use this to exchange maps between p8-files.

"complete" - contains all map, sprite and spriteflags.

"sprites complete" - contains low and high sprites

"sprites low " - contains sprites with id <= 127

"Map low " - the upper part of the map

"Shared" - the shared part the sprite/map data

"Sprites-flags" - the flag data of the spritesheet

"label" - the cart-label - it use address 0x6000 (Screen data), when you want for example a title-screen.

To load the data you need some additional code:

    function str2mem(data)
        local t,a,i,c,d,str,m = split(data)
        for a = 1,#t,2 do  
            while i <= #str do
                c,d= ord(str,i,2)
                i+=c==255 and 2 or 1
                if (c>16) poke(m, c==255 and d or c^^0x80) m+=1

    data = [[
    --some funny chars from the export



Almost the same as the export. You can import any image. Colours are automatic translated to the pico8 colour palette. When a image is too big, it can be cropped or resized.
Something special is "Map screen (center)" for images. It will split the image in 8x8 tiles and try to find this tiles in the Sprite sheet. If it not exist, it will replace the first free tile (complete black ones) with this tile.
When you import text/lua, the exported destination is ignored. You can for example import a label as sprite sheet.


Mouse wheel - change selection of sprite (map) or color (sprite)

ctrl + wheel - change zoom

0-8/ shift + 0-8 - change current/background color

Num0 - Num9 - change zoom level

Cursor keys / asdw - change selected sprite (map) or color ( sprite)

shift + cursor keys / asdw - move world map

ctrl + cursor keys / asdw - move world map screen wide

ctrl + z - undo

ctrl + y - redo

ctrl + c - copy/export menu

ctrl + v - pate/import menu

ctrl + o - open

ctrl + s - merge/save

alt + cursor - Sprite-editor: shift sprite

alt+shift + cursor - Sprite-editor: flip sprite

R - Sprite-editor: rotate sprite

About the string format

Graphic data are too big for a string in "", but enclose it with [[]] has the disadvantage that escape-sequenzes are not possible. Also chars lower 16 are not printable.
Chars lower than code 16 must be encode in a special form. Also some special characters like "[]," must be encoded to prevent conflicts.
Because chars lower than code 16 are very common (especially code zero), I first flip the high-bit of the char (m = char ^^ 0x80). If m is now lower 16 or one of the special characters, I store the in the string a sequenz of "chr(0xff)..chr(m ^^ 0x80)" otherwise a simple "chr(m)".


Icon made by https://www.freepik.com from https://www.flaticon.com/

P#97892 2021-09-27 19:19 ( Edited 2021-10-02 18:41)

CharSet Editor for Pico 8


github.com - CharsetEditor_Pico8

Short manual

A simple tool to create fonts for the virtual console pico8.

Left click on the charset to edit this char. Right click will copy the current char to this position.

Left click on the char will set a dot, right click will delete it. With the cursor keys you can shift the current char. "Set Default" will reset the current charater to the default.

"Lo Width" are for chars with a code <= 127, "Hi Width" for code >=128.

With "Copy" and "Paste" you can copy the complete Charset to the clipboard as a string embeded in [[ ]]. Don't indent the string, it could change the font! In pico 8 you need the following code to transfer the string to the memory:

    function str2mem(data)
        local t,a,i,c,d,str,m = split(data)
        for a = 1,#t,2 do  
            while i <= #str do
                c,d= ord(str,i,2)
                i+=c==255 and 2 or 1
                if (c>16) poke(m, c==255 and d or c^^0x80) m+=1

    myfont = [[0x5600,
    --some funny chars


With "Load" and "Save" you can load/save the current font as ascii-file with the extension ".lua". It is the same format as the clipboard routines.

About the string format

A Font is too big for a string in "", but enclose it with [[]] has the disadvantage that escape-sequenzes are not possible. Also chars lower 16 are not printable.

Chars lower than code 16 must be encode in a special form. Also some special characters like "[]," must be encoded to prevent conflicts.

Because chars lower than code 16 are very common (especially code zero), I first flip the high-bit of the char (m = char ^^ 0x80). If m is now lower 16 or one of the special characters, I store the in the string a sequenz of "chr(0xff)..chr(m ^^ 0x80)" otherwise a simple "chr(m)".

Example code

load #customfont_example-0

Cart #customfont_example-0 | 2021-09-26 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

P#97849 2021-09-26 11:12 ( Edited 2021-09-26 11:16)

I had written a small tool for pico8, but it is written in pure basic and the resulting program is a nativ windows application.

Is it allowed to present this tool here with a link to a github-page, including the source code, the binary and how to use it with pico8?

P#97842 2021-09-26 08:54

Follow Lexaloffle:        
Generated 2022-08-19 07:36:08 | 0.071s | Q:31