|⟵ Back||6 min · 2021-11-06|
cel7: a fantasy console-like
We've all seen the popular fantasy consoles like
PICO-8 and its lesser-known
ripoff cousin, TIC-80. These VM-like programs
typically run small scripts that manipulate a display and a rudimentary
sound system to create tiny games with a very retro-ish feel, in imitation
of real consoles like the SNES. To enhance this retro vibe, these consoles
have some severe limitations: a "token limit" (i.e., a limit on the number
of lexical tokens the script can contain) a maximum of 16 colors,
fixed-size pixel display, 4-channel audio, a limited number of sprites, etc.
(Screenshot: Liquid Runner II by technomancy)
These unconventional but relatively severe restrictions may initially make cel7 seem like a toy, useless for writing "serious" games, but in my (brief) period of writing small programs for fun with it, I found these limitations rather enjoyable. But then again, I'm the one who enjoys writing games for the terminal...
demos/snake.fe by rxi for cel7)
Here's a quick dissection of a
hello world demo (a slightly more complex
version is bundled with cel7).
(= title "Hello World!") (= scale 7) (= width 16) (= height 6) (= step (fn () ; clear screen (fill 0 0 width height " ") ; draw "Hello World!" text (color 1) (put 2 2 "Hello") (color 2) (put 8 2 "World!") ; draw divider (color 14) (put 2 3 "............") (color 1) (put (+ 2 (% (ticks) 12)) 3 ".") ))
Firstly, we have some configuration values: the
(= title ...),
(= scale ...), etc statements. When the script is run, cel7 reads these values and sets
the window's scale, size, and title to these values.
Then, we have the
step() function. Like other orthodox fantasy consoles, cel7
also will try to run certain callbacks within the script:
init() when cel7
keydown() when a key is pressed, and
step() about 30 times a second
(these callbacks aren't required to be there; if they aren't present, no action
In this case, the
step() function does a few things:
- Clears the screen by filling it with spaces (
(fill 0 0 width height " ")).
- Sets the color to
1(white) and draws
Helloat the coords
- Sets the color to
2(red) and draws
Worldright after the previous text.
- Sets the color to
14(grey) and draws some dots underneath the text.
- Redraws the nth dot with white, where
n == ticks() % num_of_dots(the
(ticks)API, provided by cel7, returns the number of times
[ unused | palette | sprites | display ...] 0000 4000 4040 52A0
Unfortunately, cel7 seems to be abandoned. No updates have been posted for some time, documentation is very sparse (there's no docs on the sprite or color format), and worst of all, there's no source code -- just binaries for Windows and x86_64 Linux. I had to borrow a friend's Windows machine just to try it out, as the only computer I have access to at present is an ARM machine.
This project intrigued me too much to let it go, though. So, I started an open source reimplementation termed 'cel7ce' (i.e., cel7 community edition) on Shithub. It does everything the organic cel7 does, and some more (it has support for Janet, another obscure minimalistic language) 3 . The goal is to create a more polished, documented version of cel7 that's (almost 4 ) completely backwards-compatible with scripts written for the original.
Reverse-engineering cel7's undocumented implementation details turned out to be
a lot of fun. Since the default cel7 palette was unspecified, I had to
the binary and crawl through the data section looking for specific hex values I
knew were existing colors (extracted from cel7 screenshots), hoping to find the
other colors next to it (I did). I thought I'd have to do something similar for
the sprites and fonts, but happily one of the demos had some code writing a
custom sprite to memory, from which I was able to infer the sprite format after
an hour or so of tearing out my hair.
demos/bonsai.fe by myself for cel7ce)
I had also intended to write a small roguelike in Janet with cel7ce for 2021's Autumn Lisp Jam, but just before the jam started I decided to go on a sabbatical from most of my hobby projects and all internet forums for a few months. Of course this slowed my cel7ce work as well; but hopefully, if I'm still around next year, I'll be able to release v1. I'm almost through with the v1 release -- it just needs a bit more testing and a quite a bit more documentation.
Hence the name,
These slots are set to the default font, so overwriting these slots with game sprites means you have to give up that range of characters. ↩︎
See the README for additional list of new features. ↩︎
cel7ce has some stricter requirements (e.g., sprites cannot be loaded into memory before init() is run). ↩︎
Kiëd Llaentenn © 2019-2022 — CC BY-NC-ND 4.0