Current state
This commit is contained in:
parent
27c866f26b
commit
db29d89cbf
|
|
@ -0,0 +1,74 @@
|
||||||
|
# Size optimization backlog
|
||||||
|
|
||||||
|
Flash budget is **16 KB**. Read the real usage with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
riscv-none-elf-size tama.elf # flash = text+data, RAM = data+bss
|
||||||
|
```
|
||||||
|
|
||||||
|
(Ignore `.elf`/`.hex` *file* sizes — they include debug info / ASCII framing and
|
||||||
|
are not the flashed image. `tama.bin` is the true image.)
|
||||||
|
|
||||||
|
Current state (after the printf removal below): **~11.9 KB / 16 KB (~73%)**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## DONE
|
||||||
|
|
||||||
|
### ✅ Drop printf/snprintf — saved ~1.4 KB
|
||||||
|
Replaced every `snprintf` with tiny `s_cat`/`u_cat` string builders (in `tama.c`),
|
||||||
|
disabled both printf backends in `funconfig.h`
|
||||||
|
(`FUNCONF_USE_DEBUGPRINTF`/`FUNCONF_USE_UARTPRINTF` = 0), and stubbed the SSD1306
|
||||||
|
I2C driver's lone `printf` with `#define printf(...) ((void)0)` before its include.
|
||||||
|
Result: `mini_vpprintf` + `mini_itoa` + `mini_pad` + `_write` fully garbage-collected.
|
||||||
|
**Readability:** neutral/positive. No behaviour change (the stubbed printf only
|
||||||
|
logged an I2C timeout we can't recover from anyway).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## TODO — ranked by value vs. effort
|
||||||
|
|
||||||
|
### 1. Crop sprite frames — ~0.5–0.7 KB · low risk
|
||||||
|
Every creature frame is stored as **32×32 = 128 bytes**, but the art only fills
|
||||||
|
roughly the middle ~28 rows; the top/bottom rows are empty padding. `ssd1306_drawImage`
|
||||||
|
already takes explicit width/height, so we can store shorter frames.
|
||||||
|
- **How:** in `sprites_gen.py`, crop each frame to e.g. 32×28 (width must stay a
|
||||||
|
multiple of 8; height is free). Emit the real height and adjust the draw `y`.
|
||||||
|
- **Savings:** ~4 rows × 4 bytes × ~18 frames ≈ 0.3–0.7 KB.
|
||||||
|
- **Readability:** art stays editable as ASCII; only the generator changes.
|
||||||
|
|
||||||
|
### 2. Alias more Panko frames — ~0.13–0.26 KB · trivial
|
||||||
|
Shell/Tmux already reuse 4 frames across the 7 expression slots. Panko (the panda)
|
||||||
|
still has 7 distinct frames. `EXP_BLINK` and `EXP_EAT` could alias `idle`/`happy`
|
||||||
|
with little visible loss.
|
||||||
|
- **How:** in the `species_frames[SP_PANKO]` row of `sprites_gen.py`, point the
|
||||||
|
blink/eat slots at `pana_idle`/`pana_happy` and delete the now-unused frames.
|
||||||
|
- **Savings:** 128 B per dropped frame (1–2 frames).
|
||||||
|
- **Readability:** neutral. (Trade-off: loses the dedicated blink/eat animation.)
|
||||||
|
|
||||||
|
### 3. Table-drive the beep jingles — ~0.1–0.2 KB · low risk
|
||||||
|
Many multi-call `beep(...) beep(...) beep(...)` sequences inline a lot of immediates.
|
||||||
|
- **How:** store jingles as small `{freq,ms}` arrays and add a `play(jingle, n)`
|
||||||
|
helper; replace the inline sequences with one call each.
|
||||||
|
- **Savings:** modest, scales with number of jingles (~8 today).
|
||||||
|
- **Readability:** arguably improves it (named jingles).
|
||||||
|
|
||||||
|
### 4. Trim the font table — up to ~1.5 KB · NOT recommended
|
||||||
|
`fontdata` in `ssd1306.h` is a full 256-char × 8-byte table = **2048 B**; we only
|
||||||
|
use ASCII ~0x20–0x7A.
|
||||||
|
- **Why not:** requires editing the *vendored* `ch32v003fun/extralibs/ssd1306.h`,
|
||||||
|
which is fragile across library updates and hurts ease-of-use. Only worth it if
|
||||||
|
we're truly out of space. If done, keep a local patched copy and document it.
|
||||||
|
|
||||||
|
### 5. RLE-compress sprites — ~1 KB · NOT recommended
|
||||||
|
Sprites are mostly runs of 0x00/0xFF and would compress well, but this needs a
|
||||||
|
decoder in the draw path and makes the art opaque (no more ASCII editing).
|
||||||
|
Net readability loss; only revisit under severe pressure.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Already optimal — don't bother
|
||||||
|
- **Compiler flags:** already `-Os -flto -ffunction-sections -fdata-sections
|
||||||
|
-Wl,--gc-sections`. GCC has no `-Oz`.
|
||||||
|
- **RAM:** ~55% used, not the constraint. The 1 KB `ssd1306_buffer` is mandatory
|
||||||
|
(full framebuffer); don't touch.
|
||||||
Binary file not shown.
2
flash.sh
2
flash.sh
|
|
@ -11,7 +11,7 @@ TARGET=tama
|
||||||
# Regenerate sprites.h from the editable art generator (if python3 is present).
|
# Regenerate sprites.h from the editable art generator (if python3 is present).
|
||||||
if command -v python3 >/dev/null 2>&1; then
|
if command -v python3 >/dev/null 2>&1; then
|
||||||
echo ">> Generating sprites.h..."
|
echo ">> Generating sprites.h..."
|
||||||
python3 sprites_gen.py > sprites.h
|
#python3 sprites_gen.py > sprites.h
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# --- Toolchain (xpack riscv-none-elf-gcc, bundles a ch32fun-compatible newlib) ---
|
# --- Toolchain (xpack riscv-none-elf-gcc, bundles a ch32fun-compatible newlib) ---
|
||||||
|
|
|
||||||
|
|
@ -4,4 +4,10 @@
|
||||||
// Configuration overrides go here. Defaults in ch32fun/ch32fun.h are fine for blink.
|
// Configuration overrides go here. Defaults in ch32fun/ch32fun.h are fine for blink.
|
||||||
#define FUNCONF_USE_HSI 1 // internal 24 MHz RC oscillator (no external crystal needed)
|
#define FUNCONF_USE_HSI 1 // internal 24 MHz RC oscillator (no external crystal needed)
|
||||||
|
|
||||||
|
// We do no console I/O, so disable both printf backends. This drops the
|
||||||
|
// debug-interface output path; combined with stubbing the I2C driver's lone
|
||||||
|
// printf (see tama.c) it lets the linker discard the ~1 KB printf formatter.
|
||||||
|
#define FUNCONF_USE_DEBUGPRINTF 0
|
||||||
|
#define FUNCONF_USE_UARTPRINTF 0
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
673
sprites.h
673
sprites.h
|
|
@ -9,254 +9,108 @@
|
||||||
|
|
||||||
// pana_idle: 32x32
|
// pana_idle: 32x32
|
||||||
static const unsigned char pana_idle[] = {
|
static const unsigned char pana_idle[] = {
|
||||||
0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x80, 0x00, 0x00, 0x10, 0x88, 0x00, 0x00, 0x11, 0x88, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00,
|
0x00, 0x31, 0x8C, 0x00, 0x00, 0x39, 0xDC, 0x00, 0x00, 0x3B, 0xDC, 0x00,
|
||||||
0x01, 0x00, 0x00, 0x80,
|
0x00, 0x7F, 0xFE, 0x00, 0x00, 0x7F, 0xFE, 0x00, 0x00, 0xF8, 0x3F, 0x00,
|
||||||
0x0f, 0xe0, 0x07, 0xf0,
|
0x00, 0xE7, 0xC7, 0x00, 0x00, 0xDF, 0xFB, 0x00, 0x01, 0xBF, 0xFD, 0x80,
|
||||||
0x1f, 0xf0, 0x0f, 0xf8,
|
0x01, 0xFF, 0xFF, 0x80, 0x03, 0xFF, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0xC0,
|
||||||
0x1f, 0xf0, 0x0f, 0xf8,
|
0x03, 0xE7, 0xE7, 0xC0, 0x03, 0xE7, 0xE7, 0xC0, 0x03, 0xFF, 0xFF, 0xC0,
|
||||||
0x1f, 0xf0, 0x0f, 0xf8,
|
0x03, 0xFF, 0xFF, 0xC0, 0x01, 0xFF, 0xFF, 0x80, 0x01, 0xFC, 0x3F, 0x80,
|
||||||
0x3f, 0xf8, 0x9f, 0xfc,
|
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x7F, 0xFE, 0x00, 0x01, 0xFF, 0xFF, 0xC0,
|
||||||
0x1f, 0xff, 0xff, 0xf8,
|
0x01, 0xFF, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0xE0, 0x03, 0xFF, 0xFF, 0xE0,
|
||||||
0x1f, 0xff, 0xff, 0xf8,
|
0x03, 0xFF, 0xFF, 0xE0, 0x07, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0xF0,
|
||||||
0x1f, 0xff, 0xff, 0xf8,
|
0x0F, 0xFF, 0xFF, 0xF8, 0x0F, 0xFF, 0xFF, 0xF8,
|
||||||
0x0f, 0xff, 0xff, 0xf0,
|
|
||||||
0x03, 0xff, 0xff, 0xe0,
|
|
||||||
0x07, 0xff, 0xff, 0xf0,
|
|
||||||
0x07, 0xef, 0xfb, 0xf0,
|
|
||||||
0x0f, 0x83, 0xe0, 0xf8,
|
|
||||||
0x0f, 0x93, 0xe4, 0xf8,
|
|
||||||
0x0f, 0x11, 0xc4, 0x78,
|
|
||||||
0x0f, 0x83, 0xe0, 0xf8,
|
|
||||||
0x1f, 0x83, 0xe0, 0xfc,
|
|
||||||
0x0f, 0xef, 0x7b, 0xf8,
|
|
||||||
0x0f, 0xfc, 0x1f, 0xf8,
|
|
||||||
0x0f, 0xff, 0x7f, 0xf8,
|
|
||||||
0x0f, 0xff, 0xff, 0xf8,
|
|
||||||
0x07, 0xf8, 0x0f, 0xf0,
|
|
||||||
0x07, 0xff, 0xff, 0xf0,
|
|
||||||
0x03, 0xff, 0xff, 0xe0,
|
|
||||||
0x01, 0xff, 0xff, 0xc0,
|
|
||||||
0x00, 0xff, 0xff, 0x80,
|
|
||||||
0x00, 0x7f, 0xff, 0x00,
|
|
||||||
0x00, 0x1f, 0xfc, 0x00,
|
|
||||||
0x00, 0x00, 0x80, 0x00,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// pana_blink: 32x32
|
// pana_blink: 32x32
|
||||||
static const unsigned char pana_blink[] = {
|
static const unsigned char pana_blink[] = {
|
||||||
0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x80, 0x00, 0x00, 0x10, 0x88, 0x00, 0x00, 0x11, 0x88, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00,
|
0x00, 0x31, 0x8C, 0x00, 0x00, 0x39, 0xDC, 0x00, 0x00, 0x3B, 0xDC, 0x00,
|
||||||
0x01, 0x00, 0x00, 0x80,
|
0x00, 0x7F, 0xFE, 0x00, 0x00, 0x7F, 0xFE, 0x00, 0x00, 0xF8, 0x3F, 0x00,
|
||||||
0x0f, 0xe0, 0x07, 0xf0,
|
0x00, 0xE7, 0xC7, 0x00, 0x00, 0xDF, 0xFB, 0x00, 0x01, 0xBF, 0xFD, 0x80,
|
||||||
0x1f, 0xf0, 0x0f, 0xf8,
|
0x01, 0xFF, 0xFF, 0x80, 0x03, 0xFF, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0xC0,
|
||||||
0x1f, 0xf0, 0x0f, 0xf8,
|
0x03, 0xFF, 0xFF, 0xC0, 0x03, 0xC3, 0xC3, 0xC0, 0x03, 0xFF, 0xFF, 0xC0,
|
||||||
0x1f, 0xf0, 0x0f, 0xf8,
|
0x03, 0xFF, 0xFF, 0xC0, 0x01, 0xFF, 0xFF, 0x80, 0x01, 0xFC, 0x3F, 0x80,
|
||||||
0x3f, 0xf8, 0x9f, 0xfc,
|
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x7F, 0xFE, 0x00, 0x01, 0xFF, 0xFF, 0xC0,
|
||||||
0x1f, 0xff, 0xff, 0xf8,
|
0x01, 0xFF, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0xE0, 0x03, 0xFF, 0xFF, 0xE0,
|
||||||
0x1f, 0xff, 0xff, 0xf8,
|
0x03, 0xFF, 0xFF, 0xE0, 0x07, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0xF0,
|
||||||
0x1f, 0xff, 0xff, 0xf8,
|
0x0F, 0xFF, 0xFF, 0xF8, 0x0F, 0xFF, 0xFF, 0xF8,
|
||||||
0x0f, 0xff, 0xff, 0xf0,
|
|
||||||
0x03, 0xff, 0xff, 0xe0,
|
|
||||||
0x07, 0xff, 0xff, 0xf0,
|
|
||||||
0x07, 0xff, 0xff, 0xf0,
|
|
||||||
0x0f, 0xff, 0xff, 0xf8,
|
|
||||||
0x0f, 0xff, 0xff, 0xf8,
|
|
||||||
0x0f, 0x01, 0xc0, 0x78,
|
|
||||||
0x0f, 0xff, 0xff, 0xf8,
|
|
||||||
0x1f, 0xff, 0xff, 0xfc,
|
|
||||||
0x0f, 0xff, 0x7f, 0xf8,
|
|
||||||
0x0f, 0xfc, 0x1f, 0xf8,
|
|
||||||
0x0f, 0xff, 0x7f, 0xf8,
|
|
||||||
0x0f, 0xff, 0xff, 0xf8,
|
|
||||||
0x07, 0xf8, 0x0f, 0xf0,
|
|
||||||
0x07, 0xff, 0xff, 0xf0,
|
|
||||||
0x03, 0xff, 0xff, 0xe0,
|
|
||||||
0x01, 0xff, 0xff, 0xc0,
|
|
||||||
0x00, 0xff, 0xff, 0x80,
|
|
||||||
0x00, 0x7f, 0xff, 0x00,
|
|
||||||
0x00, 0x1f, 0xfc, 0x00,
|
|
||||||
0x00, 0x00, 0x80, 0x00,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// pana_happy: 32x32
|
// pana_happy: 32x32
|
||||||
static const unsigned char pana_happy[] = {
|
static const unsigned char pana_happy[] = {
|
||||||
0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x80, 0x00, 0x00, 0x10, 0x88, 0x00, 0x00, 0x11, 0x88, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00,
|
0x00, 0x31, 0x8C, 0x00, 0x00, 0x39, 0xDC, 0x00, 0x00, 0x3B, 0xDC, 0x00,
|
||||||
0x01, 0x00, 0x00, 0x80,
|
0x00, 0x7F, 0xFE, 0x00, 0x00, 0x7F, 0xFE, 0x00, 0x00, 0xF8, 0x3F, 0x00,
|
||||||
0x0f, 0xe0, 0x07, 0xf0,
|
0x00, 0xE7, 0xC7, 0x00, 0x00, 0xDF, 0xFB, 0x00, 0x01, 0xBF, 0xFD, 0x80,
|
||||||
0x1f, 0xf0, 0x0f, 0xf8,
|
0x01, 0xFF, 0xFF, 0x80, 0x03, 0xFF, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0xC0,
|
||||||
0x1f, 0xf0, 0x0f, 0xf8,
|
0x03, 0xEF, 0xF7, 0xC0, 0x03, 0xE7, 0xEB, 0xC0, 0x03, 0xDB, 0xDB, 0xC0,
|
||||||
0x1f, 0xf0, 0x0f, 0xf8,
|
0x03, 0xFF, 0xFF, 0xC0, 0x01, 0xFF, 0xFF, 0x80, 0x01, 0xF7, 0xEF, 0x80,
|
||||||
0x3f, 0xf8, 0x9f, 0xfc,
|
0x00, 0xF7, 0xEF, 0x00, 0x00, 0x7B, 0xDE, 0x00, 0x01, 0xFC, 0x3F, 0xC0,
|
||||||
0x1f, 0xff, 0xff, 0xf8,
|
0x01, 0xFF, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0xE0, 0x03, 0xFF, 0xFF, 0xE0,
|
||||||
0x1f, 0xff, 0xff, 0xf8,
|
0x03, 0xFF, 0xFF, 0xE0, 0x07, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0xF0,
|
||||||
0x1f, 0xff, 0xff, 0xf8,
|
0x0F, 0xFF, 0xFF, 0xF8, 0x0F, 0xFF, 0xFF, 0xF8,
|
||||||
0x0f, 0xff, 0xff, 0xf0,
|
|
||||||
0x03, 0xff, 0xff, 0xe0,
|
|
||||||
0x07, 0xff, 0xff, 0xf0,
|
|
||||||
0x07, 0xff, 0xff, 0xf0,
|
|
||||||
0x0f, 0xff, 0xff, 0xf8,
|
|
||||||
0x0f, 0xef, 0xfb, 0xf8,
|
|
||||||
0x0f, 0xd7, 0xf5, 0xf8,
|
|
||||||
0x0f, 0xff, 0xff, 0xf8,
|
|
||||||
0x1f, 0xff, 0xff, 0xfc,
|
|
||||||
0x0f, 0xff, 0xff, 0xf8,
|
|
||||||
0x0f, 0xf8, 0x0f, 0xf8,
|
|
||||||
0x0f, 0xfb, 0xef, 0xf8,
|
|
||||||
0x0f, 0xf7, 0xf7, 0xf8,
|
|
||||||
0x07, 0xfc, 0x1f, 0xf0,
|
|
||||||
0x07, 0xff, 0xff, 0xf0,
|
|
||||||
0x03, 0xff, 0xff, 0xe0,
|
|
||||||
0x01, 0xff, 0xff, 0xc0,
|
|
||||||
0x00, 0xff, 0xff, 0x80,
|
|
||||||
0x00, 0x7f, 0xff, 0x00,
|
|
||||||
0x00, 0x1f, 0xfc, 0x00,
|
|
||||||
0x00, 0x00, 0x80, 0x00,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// pana_sad: 32x32
|
// pana_sad: 32x32
|
||||||
static const unsigned char pana_sad[] = {
|
static const unsigned char pana_sad[] = {
|
||||||
0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x80, 0x00, 0x00, 0x10, 0x88, 0x00, 0x00, 0x11, 0x88, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00,
|
0x00, 0x31, 0x8C, 0x00, 0x00, 0x39, 0xDC, 0x00, 0x00, 0x3B, 0xDC, 0x00,
|
||||||
0x01, 0x00, 0x00, 0x80,
|
0x00, 0x7F, 0xFE, 0x00, 0x00, 0x7F, 0xFE, 0x00, 0x00, 0xF8, 0x3F, 0x00,
|
||||||
0x0f, 0xe0, 0x07, 0xf0,
|
0x00, 0xE7, 0xC7, 0x00, 0x00, 0xDF, 0xFB, 0x00, 0x01, 0xBF, 0xFD, 0x80,
|
||||||
0x1f, 0xf0, 0x0f, 0xf8,
|
0x01, 0xFF, 0xFF, 0x80, 0x03, 0x9F, 0xF9, 0xC0, 0x03, 0xE7, 0xE7, 0xC0,
|
||||||
0x1f, 0xf0, 0x0f, 0xf8,
|
0x03, 0xFF, 0xFF, 0xC0, 0x03, 0xE7, 0xE7, 0xC0, 0x03, 0xE7, 0xE7, 0xC0,
|
||||||
0x1f, 0xf0, 0x0f, 0xf8,
|
0x03, 0xFF, 0xFF, 0xC0, 0x01, 0xFF, 0xFF, 0x80, 0x01, 0xFF, 0xFF, 0x80,
|
||||||
0x3f, 0xf8, 0x9f, 0xfc,
|
0x00, 0xFC, 0x3F, 0x00, 0x00, 0x7B, 0xDE, 0x00, 0x01, 0xF7, 0xEF, 0xC0,
|
||||||
0x1f, 0xff, 0xff, 0xf8,
|
0x01, 0xFF, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0xE0, 0x03, 0xFF, 0xFF, 0xE0,
|
||||||
0x1f, 0xff, 0xff, 0xf8,
|
0x03, 0xFF, 0xFF, 0xE0, 0x07, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0xF0,
|
||||||
0x1f, 0xff, 0xff, 0xf8,
|
0x0F, 0xFF, 0xFF, 0xF8, 0x0F, 0xFF, 0xFF, 0xF8,
|
||||||
0x0f, 0xff, 0xff, 0xf0,
|
|
||||||
0x03, 0xff, 0xff, 0xe0,
|
|
||||||
0x07, 0xff, 0xff, 0xf0,
|
|
||||||
0x07, 0xff, 0xff, 0xf0,
|
|
||||||
0x0f, 0xef, 0xfb, 0xf8,
|
|
||||||
0x0f, 0x83, 0xe0, 0xf8,
|
|
||||||
0x0f, 0x93, 0xe4, 0xf8,
|
|
||||||
0x0f, 0x11, 0xc4, 0x78,
|
|
||||||
0x1f, 0x83, 0xe0, 0xfc,
|
|
||||||
0x0f, 0x83, 0x60, 0xf8,
|
|
||||||
0x0f, 0xec, 0x1b, 0xf8,
|
|
||||||
0x0f, 0xff, 0x7f, 0xf8,
|
|
||||||
0x0f, 0xfc, 0x1f, 0xf8,
|
|
||||||
0x07, 0xf7, 0xf7, 0xf0,
|
|
||||||
0x07, 0xfb, 0xef, 0xf0,
|
|
||||||
0x03, 0xff, 0xff, 0xe0,
|
|
||||||
0x01, 0xff, 0xff, 0xc0,
|
|
||||||
0x00, 0xff, 0xff, 0x80,
|
|
||||||
0x00, 0x7f, 0xff, 0x00,
|
|
||||||
0x00, 0x1f, 0xfc, 0x00,
|
|
||||||
0x00, 0x00, 0x80, 0x00,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// pana_eat: 32x32
|
// pana_eat: 32x32
|
||||||
static const unsigned char pana_eat[] ={
|
static const unsigned char pana_eat[] ={
|
||||||
0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x80, 0x00, 0x00, 0x10, 0x88, 0x00, 0x00, 0x11, 0x88, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00,
|
0x00, 0x31, 0x8C, 0x00, 0x00, 0x39, 0xDC, 0x00, 0x00, 0x3B, 0xDC, 0x00,
|
||||||
0x01, 0x00, 0x00, 0x80,
|
0x00, 0x7F, 0xFE, 0x00, 0x00, 0x7F, 0xFE, 0x00, 0x00, 0xF8, 0x3F, 0x00,
|
||||||
0x0f, 0xe0, 0x07, 0xf0,
|
0x00, 0xE7, 0xC7, 0x00, 0x00, 0xDF, 0xFB, 0x00, 0x01, 0xBF, 0xFD, 0x80,
|
||||||
0x1f, 0xf0, 0x0f, 0xf8,
|
0x01, 0xFF, 0xFF, 0x80, 0x03, 0xFF, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0xC0,
|
||||||
0x1f, 0xf0, 0x0f, 0xf8,
|
0x03, 0xE7, 0xE7, 0xC0, 0x03, 0xE7, 0xE7, 0xC0, 0x03, 0xFF, 0xFF, 0xC0,
|
||||||
0x1f, 0xf0, 0x0f, 0xf8,
|
0x03, 0xFF, 0xFF, 0xC0, 0x01, 0xFC, 0x3F, 0x80, 0x01, 0xFD, 0x3F, 0x80,
|
||||||
0x3f, 0xf8, 0x9f, 0xfc,
|
0x00, 0xFC, 0xBF, 0x00, 0x00, 0x7C, 0x3E, 0x00, 0x01, 0xFF, 0xFF, 0xC0,
|
||||||
0x1f, 0xff, 0xff, 0xf8,
|
0x01, 0xFF, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0xE0, 0x03, 0xFF, 0xFF, 0xE0,
|
||||||
0x1f, 0xff, 0xff, 0xf8,
|
0x03, 0xFF, 0xFF, 0xE0, 0x07, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0xF0,
|
||||||
0x1f, 0xff, 0xff, 0xf8,
|
0x0F, 0xFF, 0xFF, 0xF8, 0x0F, 0xFF, 0xFF, 0xF8,
|
||||||
0x0f, 0xff, 0xff, 0xf0,
|
|
||||||
0x03, 0xff, 0xff, 0xe0,
|
|
||||||
0x07, 0xef, 0xfb, 0xf0,
|
|
||||||
0x07, 0x83, 0xe0, 0xf0,
|
|
||||||
0x0f, 0x93, 0xe4, 0xf8,
|
|
||||||
0x0f, 0x11, 0xc4, 0x78,
|
|
||||||
0x0f, 0x83, 0xe0, 0xf8,
|
|
||||||
0x0f, 0x83, 0xe0, 0xf8,
|
|
||||||
0x1f, 0xef, 0xfb, 0xfc,
|
|
||||||
0x0f, 0xff, 0x7f, 0xf8,
|
|
||||||
0x0f, 0xfc, 0x1f, 0xf8,
|
|
||||||
0x0f, 0xfc, 0x1f, 0xf8,
|
|
||||||
0x0f, 0xf8, 0x0f, 0xf8,
|
|
||||||
0x07, 0xfc, 0x1f, 0xf0,
|
|
||||||
0x07, 0xfc, 0x1f, 0xf0,
|
|
||||||
0x03, 0xff, 0x7f, 0xe0,
|
|
||||||
0x01, 0xff, 0xff, 0xc0,
|
|
||||||
0x00, 0xff, 0xff, 0x80,
|
|
||||||
0x00, 0x7f, 0xff, 0x00,
|
|
||||||
0x00, 0x1f, 0xfc, 0x00,
|
|
||||||
0x00, 0x00, 0x80, 0x00,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// pana_sleep: 32x32
|
// pana_sleep: 32x32
|
||||||
static const unsigned char pana_sleep[] = {
|
static const unsigned char pana_sleep[] = {
|
||||||
0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x80, 0x00, 0x00, 0x10, 0x88, 0x00, 0x00, 0x11, 0x88, 0xF0,
|
||||||
0x00, 0x00, 0x00, 0x00,
|
0x00, 0x31, 0x8C, 0x20, 0x00, 0x39, 0xDC, 0x40, 0x00, 0x3B, 0xDC, 0xF0,
|
||||||
0x01, 0x00, 0x00, 0x80,
|
0x00, 0x7F, 0xFE, 0x00, 0x00, 0x7F, 0xFE, 0x00, 0x00, 0xF8, 0x3F, 0x00,
|
||||||
0x0f, 0xe0, 0x07, 0xf0,
|
0x00, 0xE7, 0xC7, 0x00, 0x00, 0xDF, 0xFB, 0x00, 0x01, 0xBF, 0xFD, 0x80,
|
||||||
0x1f, 0xf0, 0x0f, 0xf8,
|
0x01, 0xFF, 0xFF, 0x80, 0x03, 0xFF, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0xC0,
|
||||||
0x1f, 0xf0, 0x0f, 0xf8,
|
0x03, 0xFF, 0xFF, 0xC0, 0x03, 0xC3, 0xC3, 0xC0, 0x03, 0xFF, 0xFF, 0xC0,
|
||||||
0x1f, 0xf0, 0x0f, 0xf8,
|
0x03, 0xFF, 0xFF, 0xC0, 0x01, 0xFF, 0xFF, 0x80, 0x01, 0xFE, 0x7F, 0x80,
|
||||||
0x3f, 0xf8, 0x9f, 0xfc,
|
0x00, 0xFF, 0xFF, 0x00, 0x00, 0x7F, 0xFE, 0x00, 0x01, 0xFF, 0xFF, 0xC0,
|
||||||
0x1f, 0xff, 0xff, 0xf8,
|
0x01, 0xFF, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0xE0, 0x03, 0xFF, 0xFF, 0xE0,
|
||||||
0x1f, 0xff, 0xff, 0xf8,
|
0x03, 0xFF, 0xFF, 0xE0, 0x07, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0xF0,
|
||||||
0x1f, 0xff, 0xff, 0xf8,
|
0x0F, 0xFF, 0xFF, 0xF8, 0x0F, 0xFF, 0xFF, 0xF8,
|
||||||
0x0f, 0xff, 0xff, 0xf0,
|
|
||||||
0x03, 0xff, 0xff, 0xe0,
|
|
||||||
0x07, 0xff, 0xff, 0xf0,
|
|
||||||
0x07, 0xff, 0xff, 0xf0,
|
|
||||||
0x0f, 0xff, 0xff, 0xf8,
|
|
||||||
0x0f, 0xff, 0xff, 0xf8,
|
|
||||||
0x0f, 0xff, 0xff, 0xf8,
|
|
||||||
0x0f, 0x01, 0xc0, 0x78,
|
|
||||||
0x1f, 0xff, 0xff, 0xfc,
|
|
||||||
0x0f, 0xff, 0xff, 0xf8,
|
|
||||||
0x0f, 0xff, 0x7f, 0xf8,
|
|
||||||
0x0f, 0xfc, 0x1f, 0xf8,
|
|
||||||
0x0f, 0xff, 0x7f, 0xf8,
|
|
||||||
0x07, 0xff, 0xff, 0xf0,
|
|
||||||
0x07, 0xff, 0xff, 0xf0,
|
|
||||||
0x03, 0xff, 0xff, 0xe0,
|
|
||||||
0x01, 0xff, 0xff, 0xc0,
|
|
||||||
0x00, 0xff, 0xff, 0x80,
|
|
||||||
0x00, 0x7f, 0xff, 0x00,
|
|
||||||
0x00, 0x1f, 0xfc, 0x00,
|
|
||||||
0x00, 0x00, 0x80, 0x00,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// pana_dead: 32x32
|
// pana_dead: 32x32
|
||||||
static const unsigned char pana_dead[] = {
|
static const unsigned char pana_dead[] = {
|
||||||
0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x80, 0x00, 0x00, 0x10, 0x88, 0x00, 0x00, 0x11, 0x88, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00,
|
0x00, 0x31, 0x8C, 0x00, 0x00, 0x39, 0xDC, 0x00, 0x00, 0x3B, 0xDC, 0x00,
|
||||||
0x01, 0x00, 0x00, 0x80,
|
0x00, 0x7F, 0xFE, 0x00, 0x00, 0x7F, 0xFE, 0x00, 0x00, 0xF8, 0x3F, 0x00,
|
||||||
0x0f, 0xe0, 0x07, 0xf0,
|
0x00, 0xE7, 0xC7, 0x00, 0x00, 0xDF, 0xFB, 0x00, 0x01, 0xBF, 0xFD, 0x80,
|
||||||
0x1f, 0xf0, 0x0f, 0xf8,
|
0x01, 0xFF, 0xFF, 0x80, 0x03, 0xFF, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0xC0,
|
||||||
0x1f, 0xf0, 0x0f, 0xf8,
|
0x03, 0xDB, 0xDB, 0xC0, 0x03, 0xE7, 0xE7, 0xC0, 0x03, 0xE7, 0xE7, 0xC0,
|
||||||
0x1f, 0xf0, 0x0f, 0xf8,
|
0x03, 0xDB, 0xDB, 0xC0, 0x01, 0xFD, 0xDF, 0x80, 0x01, 0xFA, 0xBF, 0x80,
|
||||||
0x3f, 0xf8, 0x9f, 0xfc,
|
0x00, 0xF7, 0x7F, 0x00, 0x00, 0x7F, 0xFE, 0x00, 0x01, 0xFF, 0xFF, 0xC0,
|
||||||
0x1f, 0xff, 0xff, 0xf8,
|
0x01, 0xFF, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0xE0, 0x03, 0xFF, 0xFF, 0xE0,
|
||||||
0x1f, 0xff, 0xff, 0xf8,
|
0x03, 0xFF, 0xFF, 0xE0, 0x07, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0xF0,
|
||||||
0x1f, 0xff, 0xff, 0xf8,
|
0x0F, 0xFF, 0xFF, 0xF8, 0x0F, 0xFF, 0xFF, 0xF8,
|
||||||
0x0f, 0xff, 0xff, 0xf0,
|
|
||||||
0x03, 0xff, 0xff, 0xe0,
|
|
||||||
0x07, 0xff, 0xff, 0xf0,
|
|
||||||
0x07, 0xff, 0xff, 0xf0,
|
|
||||||
0x0f, 0xbb, 0xee, 0xf8,
|
|
||||||
0x0f, 0xd7, 0xf5, 0xf8,
|
|
||||||
0x0f, 0xef, 0xfb, 0xf8,
|
|
||||||
0x0f, 0xd7, 0xf5, 0xf8,
|
|
||||||
0x1f, 0xbb, 0xee, 0xfc,
|
|
||||||
0x0f, 0xff, 0xff, 0xf8,
|
|
||||||
0x0f, 0xff, 0xff, 0xf8,
|
|
||||||
0x0f, 0xff, 0xff, 0xf8,
|
|
||||||
0x0f, 0xf0, 0x07, 0xf8,
|
|
||||||
0x07, 0xff, 0xff, 0xf0,
|
|
||||||
0x07, 0xff, 0xff, 0xf0,
|
|
||||||
0x03, 0xff, 0xff, 0xe0,
|
|
||||||
0x01, 0xff, 0xff, 0xc0,
|
|
||||||
0x00, 0xff, 0xff, 0x80,
|
|
||||||
0x00, 0x7f, 0xff, 0x00,
|
|
||||||
0x00, 0x1f, 0xfc, 0x00,
|
|
||||||
0x00, 0x00, 0x80, 0x00,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum { EXP_IDLE, EXP_BLINK, EXP_HAPPY, EXP_SAD, EXP_EAT, EXP_SLEEP, EXP_DEAD, EXP_COUNT };
|
enum { EXP_IDLE, EXP_BLINK, EXP_HAPPY, EXP_SAD, EXP_EAT, EXP_SLEEP, EXP_DEAD, EXP_COUNT };
|
||||||
|
|
@ -264,6 +118,305 @@ static const unsigned char *const pana_frames[EXP_COUNT] = {
|
||||||
pana_idle, pana_blink, pana_happy, pana_sad, pana_eat, pana_sleep, pana_dead,
|
pana_idle, pana_blink, pana_happy, pana_sad, pana_eat, pana_sleep, pana_dead,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// shell_idle: 32x32
|
||||||
|
static const unsigned char shell_idle[] = {
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x07, 0xff, 0xff, 0xe0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xef, 0xf7, 0xf0,
|
||||||
|
0x0f, 0xc7, 0xe3, 0xf0,
|
||||||
|
0x0f, 0x83, 0xc1, 0xf0,
|
||||||
|
0x0f, 0xc7, 0xe3, 0xf0,
|
||||||
|
0x0f, 0xef, 0xf7, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0x7f, 0xff, 0xf0,
|
||||||
|
0x0f, 0xbf, 0xff, 0xf0,
|
||||||
|
0x0f, 0xdf, 0xff, 0xf0,
|
||||||
|
0x0f, 0xbf, 0xff, 0xf0,
|
||||||
|
0x0f, 0x78, 0x0f, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x07, 0xff, 0xff, 0xe0,
|
||||||
|
0x00, 0x07, 0xe0, 0x00,
|
||||||
|
0x00, 0x07, 0xe0, 0x00,
|
||||||
|
0x00, 0x07, 0xe0, 0x00,
|
||||||
|
0x00, 0x7f, 0xfe, 0x00,
|
||||||
|
0x00, 0x7f, 0xfe, 0x00,
|
||||||
|
0x00, 0x7f, 0xfe, 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
// shell_happy: 32x32
|
||||||
|
static const unsigned char shell_happy[] = {
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x07, 0xff, 0xff, 0xe0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xdf, 0xef, 0xf0,
|
||||||
|
0x0f, 0xaf, 0xd7, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xc7, 0xe3, 0xf0,
|
||||||
|
0x0f, 0xf8, 0x1f, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x07, 0xff, 0xff, 0xe0,
|
||||||
|
0x00, 0x07, 0xe0, 0x00,
|
||||||
|
0x00, 0x07, 0xe0, 0x00,
|
||||||
|
0x00, 0x07, 0xe0, 0x00,
|
||||||
|
0x00, 0x7f, 0xfe, 0x00,
|
||||||
|
0x00, 0x7f, 0xfe, 0x00,
|
||||||
|
0x00, 0x7f, 0xfe, 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
// shell_sad: 32x32
|
||||||
|
static const unsigned char shell_sad[] = {
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x07, 0xff, 0xff, 0xe0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xef, 0xf7, 0xf0,
|
||||||
|
0x0f, 0xc7, 0xe3, 0xf0,
|
||||||
|
0x0f, 0x83, 0xc1, 0xf0,
|
||||||
|
0x0f, 0xc7, 0xe3, 0xf0,
|
||||||
|
0x0f, 0xef, 0xf7, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xf8, 0x1f, 0xf0,
|
||||||
|
0x0f, 0xc7, 0xe3, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x07, 0xff, 0xff, 0xe0,
|
||||||
|
0x00, 0x07, 0xe0, 0x00,
|
||||||
|
0x00, 0x07, 0xe0, 0x00,
|
||||||
|
0x00, 0x07, 0xe0, 0x00,
|
||||||
|
0x00, 0x7f, 0xfe, 0x00,
|
||||||
|
0x00, 0x7f, 0xfe, 0x00,
|
||||||
|
0x00, 0x7f, 0xfe, 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
// shell_sleep: 32x32
|
||||||
|
static const unsigned char shell_sleep[] = {
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x07, 0xff, 0xff, 0xe0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0x01, 0x80, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xf8, 0x0f, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x0f, 0xff, 0xff, 0xf0,
|
||||||
|
0x07, 0xff, 0xff, 0xe0,
|
||||||
|
0x00, 0x07, 0xe0, 0x00,
|
||||||
|
0x00, 0x07, 0xe0, 0x00,
|
||||||
|
0x00, 0x07, 0xe0, 0x00,
|
||||||
|
0x00, 0x7f, 0xfe, 0x00,
|
||||||
|
0x00, 0x7f, 0xfe, 0x00,
|
||||||
|
0x00, 0x7f, 0xfe, 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
// tmux_idle: 32x32
|
||||||
|
static const unsigned char tmux_idle[] = {
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x1f, 0xff, 0xff, 0xf8,
|
||||||
|
0x3f, 0xff, 0xff, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xbf, 0x7e, 0xfc,
|
||||||
|
0x3f, 0x1f, 0x7c, 0x7c,
|
||||||
|
0x3e, 0x0f, 0x78, 0x3c,
|
||||||
|
0x3f, 0x1f, 0x7c, 0x7c,
|
||||||
|
0x3f, 0xbf, 0x7e, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3c, 0x07, 0x70, 0x1c,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0xff, 0xfc,
|
||||||
|
0x20, 0x00, 0x00, 0x04,
|
||||||
|
0x27, 0xdf, 0x00, 0x04,
|
||||||
|
0x27, 0xdf, 0x00, 0x04,
|
||||||
|
0x20, 0x00, 0x00, 0x04,
|
||||||
|
0x1f, 0xff, 0xff, 0xf8,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
// tmux_happy: 32x32
|
||||||
|
static const unsigned char tmux_happy[] = {
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x1f, 0xff, 0xff, 0xf8,
|
||||||
|
0x3f, 0xff, 0xff, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0x5f, 0x7d, 0x7c,
|
||||||
|
0x3e, 0xaf, 0x7a, 0xbc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3c, 0x03, 0x60, 0x1c,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0xff, 0xfc,
|
||||||
|
0x20, 0x00, 0x00, 0x04,
|
||||||
|
0x27, 0xdf, 0x00, 0x04,
|
||||||
|
0x27, 0xdf, 0x00, 0x04,
|
||||||
|
0x20, 0x00, 0x00, 0x04,
|
||||||
|
0x1f, 0xff, 0xff, 0xf8,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
// tmux_sad: 32x32
|
||||||
|
static const unsigned char tmux_sad[] = {
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x1f, 0xff, 0xff, 0xf8,
|
||||||
|
0x3f, 0xff, 0xff, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xbf, 0x7e, 0xfc,
|
||||||
|
0x3f, 0x1f, 0x7c, 0x7c,
|
||||||
|
0x3e, 0x0f, 0x78, 0x3c,
|
||||||
|
0x3f, 0x1f, 0x7c, 0x7c,
|
||||||
|
0x3f, 0xbf, 0x7e, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xbf, 0x7e, 0xfc,
|
||||||
|
0x3c, 0x07, 0x70, 0x1c,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0xff, 0xfc,
|
||||||
|
0x20, 0x00, 0x00, 0x04,
|
||||||
|
0x27, 0xdf, 0x00, 0x04,
|
||||||
|
0x27, 0xdf, 0x00, 0x04,
|
||||||
|
0x20, 0x00, 0x00, 0x04,
|
||||||
|
0x1f, 0xff, 0xff, 0xf8,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
// tmux_sleep: 32x32
|
||||||
|
static const unsigned char tmux_sleep[] = {
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x1f, 0xff, 0xff, 0xf8,
|
||||||
|
0x3f, 0xff, 0xff, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3c, 0x07, 0x70, 0x1c,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0x7f, 0xfc,
|
||||||
|
0x3f, 0xff, 0xff, 0xfc,
|
||||||
|
0x20, 0x00, 0x00, 0x04,
|
||||||
|
0x27, 0xdf, 0x00, 0x04,
|
||||||
|
0x27, 0xdf, 0x00, 0x04,
|
||||||
|
0x20, 0x00, 0x00, 0x04,
|
||||||
|
0x1f, 0xff, 0xff, 0xf8,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SPECIES_COUNT 3
|
||||||
|
enum { SP_SHELL, SP_PANKO, SP_TMUX };
|
||||||
|
static const char *const species_names[SPECIES_COUNT] = {
|
||||||
|
"Shell", "Panko", "Tmux",
|
||||||
|
};
|
||||||
|
static const unsigned char *const species_frames[SPECIES_COUNT][EXP_COUNT] = {
|
||||||
|
{ shell_idle, shell_idle, shell_happy, shell_sad, shell_happy, shell_sleep, shell_sad },
|
||||||
|
{ pana_idle, pana_blink, pana_happy, pana_sad, pana_eat, pana_sleep, pana_dead },
|
||||||
|
{ tmux_idle, tmux_idle, tmux_happy, tmux_sad, tmux_happy, tmux_sleep, tmux_sad },
|
||||||
|
};
|
||||||
|
|
||||||
// spr_grave: 32x32
|
// spr_grave: 32x32
|
||||||
static const unsigned char spr_grave[] = {
|
static const unsigned char spr_grave[] = {
|
||||||
0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
|
@ -312,6 +465,78 @@ static const unsigned char spr_poop[] = {
|
||||||
0x00,
|
0x00,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// spr_claude: 32x32
|
||||||
|
static const unsigned char spr_claude[] = {
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x20,
|
||||||
|
0x00, 0x00, 0x00, 0x20,
|
||||||
|
0x04, 0x00, 0x00, 0xa8,
|
||||||
|
0x0e, 0x00, 0x00, 0x20,
|
||||||
|
0x04, 0x00, 0x03, 0xfe,
|
||||||
|
0x00, 0x00, 0x00, 0x20,
|
||||||
|
0x00, 0x00, 0x80, 0xa8,
|
||||||
|
0x00, 0x0f, 0xf8, 0x20,
|
||||||
|
0x00, 0x3f, 0xfe, 0x20,
|
||||||
|
0x00, 0x7f, 0xff, 0x00,
|
||||||
|
0x00, 0xff, 0xff, 0x80,
|
||||||
|
0x01, 0xff, 0xff, 0xc0,
|
||||||
|
0x01, 0xff, 0xff, 0xc0,
|
||||||
|
0x03, 0xff, 0xff, 0xe0,
|
||||||
|
0x03, 0xf7, 0xf7, 0xe0,
|
||||||
|
0x03, 0xf7, 0xf7, 0xe0,
|
||||||
|
0x03, 0xe3, 0xe3, 0xe0,
|
||||||
|
0x07, 0xf7, 0xf7, 0xf0,
|
||||||
|
0x03, 0xf7, 0xf7, 0xe0,
|
||||||
|
0x03, 0xff, 0xff, 0xe0,
|
||||||
|
0x03, 0xff, 0xff, 0xe0,
|
||||||
|
0x03, 0xe7, 0xf3, 0xe0,
|
||||||
|
0x01, 0xf8, 0x0f, 0xc0,
|
||||||
|
0x01, 0xff, 0xff, 0xc0,
|
||||||
|
0x00, 0xff, 0xff, 0x80,
|
||||||
|
0x00, 0x7f, 0xff, 0x00,
|
||||||
|
0x00, 0x3f, 0xfe, 0x00,
|
||||||
|
0x00, 0x0f, 0xf8, 0x00,
|
||||||
|
0x00, 0x00, 0x80, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
// spr_glitch: 32x32
|
||||||
|
static const unsigned char spr_glitch[] = {
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x02,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x80, 0x00, 0x80, 0x00,
|
||||||
|
0x00, 0x0f, 0xf8, 0x00,
|
||||||
|
0x00, 0x15, 0x54, 0x00,
|
||||||
|
0x00, 0xff, 0xff, 0x80,
|
||||||
|
0x01, 0xff, 0xff, 0xc0,
|
||||||
|
0x03, 0xff, 0xff, 0xe0,
|
||||||
|
0x01, 0x11, 0x44, 0x41,
|
||||||
|
0x07, 0xd7, 0xf5, 0xf0,
|
||||||
|
0x07, 0xef, 0xfb, 0xf0,
|
||||||
|
0x07, 0xd7, 0xf5, 0xf0,
|
||||||
|
0x05, 0x11, 0x44, 0x50,
|
||||||
|
0x0f, 0xff, 0xff, 0xf8,
|
||||||
|
0x07, 0xff, 0xff, 0xf0,
|
||||||
|
0x07, 0xff, 0xff, 0xf0,
|
||||||
|
0x05, 0x55, 0x55, 0x50,
|
||||||
|
0x07, 0xea, 0xab, 0xf0,
|
||||||
|
0x43, 0xff, 0xff, 0xe0,
|
||||||
|
0x03, 0xff, 0xff, 0xe0,
|
||||||
|
0x01, 0x55, 0x55, 0x40,
|
||||||
|
0x00, 0xff, 0xff, 0x80,
|
||||||
|
0x00, 0x3f, 0xfe, 0x00,
|
||||||
|
0x00, 0x0f, 0xf8, 0x04,
|
||||||
|
0x20, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
// icon_feed: 16x16
|
// icon_feed: 16x16
|
||||||
static const unsigned char icon_feed[] = {
|
static const unsigned char icon_feed[] = {
|
||||||
0x00, 0x00,
|
0x00, 0x00,
|
||||||
|
|
|
||||||
161
sprites_gen.py
161
sprites_gen.py
|
|
@ -25,6 +25,11 @@ def fill_ellipse(g, cx, cy, rx, ry, v=1):
|
||||||
if dx * dx + dy * dy <= 1.0:
|
if dx * dx + dy * dy <= 1.0:
|
||||||
g[y][x] = v
|
g[y][x] = v
|
||||||
|
|
||||||
|
def fillrect(g, x0, y0, x1, y1, v=1):
|
||||||
|
for y in range(y0, y1 + 1):
|
||||||
|
for x in range(x0, x1 + 1):
|
||||||
|
px(g, x, y, v)
|
||||||
|
|
||||||
def hline(g, x0, x1, y, v=1):
|
def hline(g, x0, x1, y, v=1):
|
||||||
if x0 > x1:
|
if x0 > x1:
|
||||||
x0, x1 = x1, x0
|
x0, x1 = x1, x0
|
||||||
|
|
@ -153,6 +158,96 @@ def panda_dead():
|
||||||
hline(g, 12, 20, 23, 0) # flat mouth
|
hline(g, 12, 20, 23, 0) # flat mouth
|
||||||
return g
|
return g
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------- species: SHELL
|
||||||
|
# A friendly CRT terminal. Its mouth is a command prompt "> _".
|
||||||
|
def shell_base():
|
||||||
|
g = grid(32, 32)
|
||||||
|
fillrect(g, 4, 3, 27, 25) # monitor screen (lit)
|
||||||
|
for cx, cy in [(4, 3), (27, 3), (4, 25), (27, 25)]:
|
||||||
|
px(g, cx, cy, 0) # round the corners
|
||||||
|
fillrect(g, 13, 26, 18, 28) # neck
|
||||||
|
fillrect(g, 9, 29, 22, 31) # base
|
||||||
|
return g
|
||||||
|
|
||||||
|
def shell_prompt(g): # the "> _" signature, dark on screen
|
||||||
|
px(g, 8, 18, 0); px(g, 9, 19, 0); px(g, 10, 20, 0)
|
||||||
|
px(g, 9, 21, 0); px(g, 8, 22, 0)
|
||||||
|
hline(g, 13, 19, 22, 0)
|
||||||
|
|
||||||
|
def shell_idle():
|
||||||
|
g = shell_base()
|
||||||
|
fill_ellipse(g, 11, 11, 2, 2, 0)
|
||||||
|
fill_ellipse(g, 20, 11, 2, 2, 0)
|
||||||
|
shell_prompt(g)
|
||||||
|
return g
|
||||||
|
|
||||||
|
def shell_happy():
|
||||||
|
g = shell_base()
|
||||||
|
px(g, 9, 11, 0); px(g, 10, 10, 0); px(g, 11, 11, 0) # ^ ^
|
||||||
|
px(g, 18, 11, 0); px(g, 19, 10, 0); px(g, 20, 11, 0)
|
||||||
|
for x in range(10, 22):
|
||||||
|
y = 19 + (1 if 13 <= x <= 18 else 0)
|
||||||
|
px(g, x, y, 0)
|
||||||
|
return g
|
||||||
|
|
||||||
|
def shell_sad():
|
||||||
|
g = shell_base()
|
||||||
|
fill_ellipse(g, 11, 12, 2, 2, 0)
|
||||||
|
fill_ellipse(g, 20, 12, 2, 2, 0)
|
||||||
|
for x in range(10, 22):
|
||||||
|
y = 23 - (1 if 13 <= x <= 18 else 0)
|
||||||
|
px(g, x, y, 0)
|
||||||
|
return g
|
||||||
|
|
||||||
|
def shell_sleep():
|
||||||
|
g = shell_base()
|
||||||
|
hline(g, 8, 14, 12, 0)
|
||||||
|
hline(g, 17, 23, 12, 0)
|
||||||
|
hline(g, 13, 19, 20, 0)
|
||||||
|
return g
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------- species: TMUX
|
||||||
|
# A split terminal window: a central pane divider and a status bar of tabs.
|
||||||
|
def tmux_base():
|
||||||
|
g = grid(32, 32)
|
||||||
|
fillrect(g, 2, 3, 29, 28)
|
||||||
|
for cx, cy in [(2, 3), (29, 3), (2, 28), (29, 28)]:
|
||||||
|
px(g, cx, cy, 0)
|
||||||
|
vline(g, 16, 5, 22, 0) # pane divider
|
||||||
|
fillrect(g, 3, 24, 28, 27, 0) # dark status strip
|
||||||
|
fillrect(g, 5, 25, 9, 26, 1) # window tab 0
|
||||||
|
fillrect(g, 11, 25, 15, 26, 1) # window tab 1
|
||||||
|
return g
|
||||||
|
|
||||||
|
def tmux_idle():
|
||||||
|
g = tmux_base()
|
||||||
|
fill_ellipse(g, 9, 12, 2, 2, 0) # one eye per pane
|
||||||
|
fill_ellipse(g, 23, 12, 2, 2, 0)
|
||||||
|
hline(g, 6, 12, 18, 0) # mouth, split by divider
|
||||||
|
hline(g, 20, 26, 18, 0)
|
||||||
|
return g
|
||||||
|
|
||||||
|
def tmux_happy():
|
||||||
|
g = tmux_base()
|
||||||
|
px(g, 7, 12, 0); px(g, 8, 11, 0); px(g, 9, 12, 0); px(g, 10, 11, 0); px(g, 11, 12, 0)
|
||||||
|
px(g, 21, 12, 0); px(g, 22, 11, 0); px(g, 23, 12, 0); px(g, 24, 11, 0); px(g, 25, 12, 0)
|
||||||
|
hline(g, 6, 13, 19, 0); hline(g, 19, 26, 19, 0)
|
||||||
|
return g
|
||||||
|
|
||||||
|
def tmux_sad():
|
||||||
|
g = tmux_base()
|
||||||
|
fill_ellipse(g, 9, 13, 2, 2, 0)
|
||||||
|
fill_ellipse(g, 23, 13, 2, 2, 0)
|
||||||
|
hline(g, 6, 12, 20, 0); hline(g, 20, 26, 20, 0)
|
||||||
|
px(g, 9, 19, 0); px(g, 23, 19, 0)
|
||||||
|
return g
|
||||||
|
|
||||||
|
def tmux_sleep():
|
||||||
|
g = tmux_base()
|
||||||
|
hline(g, 6, 12, 13, 0)
|
||||||
|
hline(g, 20, 26, 13, 0)
|
||||||
|
return g
|
||||||
|
|
||||||
# ---------------------------------------------------------------- props
|
# ---------------------------------------------------------------- props
|
||||||
def grave():
|
def grave():
|
||||||
art = [
|
art = [
|
||||||
|
|
@ -204,6 +299,42 @@ def poop():
|
||||||
]
|
]
|
||||||
return from_art(art)
|
return from_art(art)
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------- evolved forms
|
||||||
|
# The pet "ascends" once fully grown. Good care -> Claude (a serene sparkle
|
||||||
|
# being); neglect -> a corrupted glitch. Both are 32x32 like the panda frames.
|
||||||
|
def claude():
|
||||||
|
g = grid(32, 32)
|
||||||
|
fill_ellipse(g, 16, 19, 11, 11) # round, friendly body
|
||||||
|
fill_ellipse(g, 12, 18, 1, 2, 0) # calm eyes
|
||||||
|
fill_ellipse(g, 20, 18, 1, 2, 0)
|
||||||
|
for x in range(11, 22): # serene smile
|
||||||
|
y = 23 + (1 if 13 <= x <= 19 else 0)
|
||||||
|
px(g, x, y, 0)
|
||||||
|
# signature 4-point sparkle, upper-right
|
||||||
|
sx, sy = 26, 6
|
||||||
|
vline(g, sx, sy - 4, sy + 4)
|
||||||
|
hline(g, sx - 4, sx + 4, sy)
|
||||||
|
px(g, sx - 2, sy - 2); px(g, sx + 2, sy - 2)
|
||||||
|
px(g, sx - 2, sy + 2); px(g, sx + 2, sy + 2)
|
||||||
|
# tiny twinkle, upper-left
|
||||||
|
px(g, 5, 5); px(g, 5, 4); px(g, 5, 6); px(g, 4, 5); px(g, 6, 5)
|
||||||
|
return g
|
||||||
|
|
||||||
|
def glitch():
|
||||||
|
g = grid(32, 32)
|
||||||
|
fill_ellipse(g, 16, 19, 12, 11)
|
||||||
|
for d in range(-2, 3): # X_X eyes
|
||||||
|
px(g, 11 + d, 16 + d, 0); px(g, 11 + d, 16 - d, 0)
|
||||||
|
px(g, 21 + d, 16 + d, 0); px(g, 21 + d, 16 - d, 0)
|
||||||
|
for x in range(10, 23): # jagged mouth
|
||||||
|
px(g, x, 22 + (x % 2), 0)
|
||||||
|
for y in range(10, 31, 4): # scanline corruption
|
||||||
|
for x in range(2, 30, 2):
|
||||||
|
px(g, x, y, 0)
|
||||||
|
for (x, y) in [(0, 8), (2, 30), (31, 14), (29, 29), (1, 24), (30, 4)]:
|
||||||
|
px(g, x, y, 1) # stray noise pixels
|
||||||
|
return g
|
||||||
|
|
||||||
# ---------------------------------------------------------------- 16x16 icons
|
# ---------------------------------------------------------------- 16x16 icons
|
||||||
def icon_feed(): # apple
|
def icon_feed(): # apple
|
||||||
g = grid(16, 16)
|
g = grid(16, 16)
|
||||||
|
|
@ -295,8 +426,38 @@ def main():
|
||||||
print("};")
|
print("};")
|
||||||
print()
|
print()
|
||||||
|
|
||||||
|
# other starter species (Panko = the panda frames above)
|
||||||
|
species_extra = [
|
||||||
|
("shell_idle", shell_idle()),
|
||||||
|
("shell_happy", shell_happy()),
|
||||||
|
("shell_sad", shell_sad()),
|
||||||
|
("shell_sleep", shell_sleep()),
|
||||||
|
("tmux_idle", tmux_idle()),
|
||||||
|
("tmux_happy", tmux_happy()),
|
||||||
|
("tmux_sad", tmux_sad()),
|
||||||
|
("tmux_sleep", tmux_sleep()),
|
||||||
|
]
|
||||||
|
for n, g in species_extra:
|
||||||
|
emit(n, g)
|
||||||
|
|
||||||
|
# species frame tables, indexed [species][EXP_*]. Shell/Tmux reuse their
|
||||||
|
# four frames across the seven expression slots.
|
||||||
|
print("#define SPECIES_COUNT 3")
|
||||||
|
print("enum { SP_SHELL, SP_PANKO, SP_TMUX };")
|
||||||
|
print("static const char *const species_names[SPECIES_COUNT] = {")
|
||||||
|
print(' "Shell", "Panko", "Tmux",')
|
||||||
|
print("};")
|
||||||
|
print("static const unsigned char *const species_frames[SPECIES_COUNT][EXP_COUNT] = {")
|
||||||
|
print(" { shell_idle, shell_idle, shell_happy, shell_sad, shell_happy, shell_sleep, shell_sad },")
|
||||||
|
print(" { pana_idle, pana_blink, pana_happy, pana_sad, pana_eat, pana_sleep, pana_dead },")
|
||||||
|
print(" { tmux_idle, tmux_idle, tmux_happy, tmux_sad, tmux_happy, tmux_sleep, tmux_sad },")
|
||||||
|
print("};")
|
||||||
|
print()
|
||||||
|
|
||||||
emit("spr_grave", grave())
|
emit("spr_grave", grave())
|
||||||
emit("spr_poop", poop())
|
emit("spr_poop", poop())
|
||||||
|
emit("spr_claude", claude())
|
||||||
|
emit("spr_glitch", glitch())
|
||||||
|
|
||||||
icons = [
|
icons = [
|
||||||
("icon_feed", icon_feed()),
|
("icon_feed", icon_feed()),
|
||||||
|
|
|
||||||
267
tama.c
267
tama.c
|
|
@ -14,7 +14,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ch32fun.h"
|
#include "ch32fun.h"
|
||||||
#include <stdio.h>
|
|
||||||
|
// The bundled I2C driver calls printf() only to log a timeout we can't act on
|
||||||
|
// (by then the display is dead). Stub it to a no-op so the ~1 KB printf
|
||||||
|
// formatter is never referenced and the linker discards it. We format our own
|
||||||
|
// numbers with the tiny s_cat/u_cat helpers below.
|
||||||
|
#define printf(...) ((void)0)
|
||||||
|
|
||||||
#define SSD1306_128X64 // 128x64 panel (see pinout.md / OLED size)
|
#define SSD1306_128X64 // 128x64 panel (see pinout.md / OLED size)
|
||||||
#include "ssd1306_i2c.h"
|
#include "ssd1306_i2c.h"
|
||||||
|
|
@ -37,7 +42,7 @@
|
||||||
// a need empties in ~20 min, after which health bleeds down over ~10 more.
|
// a need empties in ~20 min, after which health bleeds down over ~10 more.
|
||||||
|
|
||||||
// ----------------------------------------------------------------- state
|
// ----------------------------------------------------------------- state
|
||||||
enum { SCR_MAIN, SCR_STATS, SCR_DEAD, SCR_SETTINGS };
|
enum { SCR_SELECT, SCR_MAIN, SCR_STATS, SCR_DEAD, SCR_SETTINGS };
|
||||||
|
|
||||||
// notification thresholds: gentle chirp at <50%, urgent at <20%
|
// notification thresholds: gentle chirp at <50%, urgent at <20%
|
||||||
enum { N_FOOD, N_FUN, N_ENGY, N_WASH, N_COUNT };
|
enum { N_FOOD, N_FUN, N_ENGY, N_WASH, N_COUNT };
|
||||||
|
|
@ -49,11 +54,26 @@ typedef struct {
|
||||||
int8_t hygiene; // 0..100
|
int8_t hygiene; // 0..100
|
||||||
int8_t health; // 0..100
|
int8_t health; // 0..100
|
||||||
uint16_t age_min; // age in game-minutes (one per tick)
|
uint16_t age_min; // age in game-minutes (one per tick)
|
||||||
|
uint16_t xp; // experience earned by good care
|
||||||
|
uint8_t species; // SP_* starter type chosen on the welcome screen
|
||||||
|
uint8_t level; // 1..MAX_LEVEL
|
||||||
|
uint8_t form; // FORM_* (display + life stage), derived from level
|
||||||
|
uint8_t ascend; // 0 undecided, 1 Claude, 2 glitch (latched at max lvl)
|
||||||
uint8_t poop; // 0..3 piles on the floor
|
uint8_t poop; // 0..3 piles on the floor
|
||||||
uint8_t sleeping; // 1 while napping
|
uint8_t sleeping; // 1 while napping
|
||||||
uint8_t alive;
|
uint8_t alive;
|
||||||
} Pet;
|
} Pet;
|
||||||
|
|
||||||
|
// Hacker privilege-escalation life stages: proc -> user -> root, then the pet
|
||||||
|
// either ascends to "Claude" (well-tended) or rots into a glitch.
|
||||||
|
enum { FORM_PROC, FORM_USER, FORM_ROOT, FORM_CLAUDE, FORM_GLITCH, FORM_COUNT };
|
||||||
|
static const char *const form_names[FORM_COUNT] = {
|
||||||
|
"proc", "user", "root", "Claude", "glitch",
|
||||||
|
};
|
||||||
|
#define MAX_LEVEL 4
|
||||||
|
// cumulative XP required to reach level (index = level-1)
|
||||||
|
static const uint16_t level_xp[MAX_LEVEL] = { 0, 45, 120, 240 };
|
||||||
|
|
||||||
static Pet pet;
|
static Pet pet;
|
||||||
static uint8_t screen;
|
static uint8_t screen;
|
||||||
static uint8_t cursor; // selected menu icon 0..ICON_COUNT-1
|
static uint8_t cursor; // selected menu icon 0..ICON_COUNT-1
|
||||||
|
|
@ -63,11 +83,13 @@ static uint32_t frame; // free-running frame counter
|
||||||
static uint16_t tick_acc; // frames since last stat tick
|
static uint16_t tick_acc; // frames since last stat tick
|
||||||
static uint8_t warn_flag[N_COUNT]; // already chirped a <50% warning
|
static uint8_t warn_flag[N_COUNT]; // already chirped a <50% warning
|
||||||
static uint8_t crit_flag[N_COUNT]; // already chirped a <20% warning
|
static uint8_t crit_flag[N_COUNT]; // already chirped a <20% warning
|
||||||
|
static uint8_t evo_anim; // frames remaining for an evolution banner
|
||||||
|
|
||||||
// settings
|
// settings
|
||||||
static uint8_t sound_on = 1;
|
static uint8_t sound_on = 1;
|
||||||
static uint8_t timeout_idx = 1; // index into screen_timeout_opts (default 30 s)
|
static uint8_t timeout_idx = 1; // index into screen_timeout_opts (default 30 s)
|
||||||
static uint8_t set_sel = 0; // highlighted row on the settings screen
|
static uint8_t set_sel = 0; // highlighted row on the settings screen
|
||||||
|
static uint8_t sel_species = 0; // highlighted species on the welcome screen
|
||||||
|
|
||||||
// screen-off-on-inactivity options, in frames (0 = never sleep the display)
|
// screen-off-on-inactivity options, in frames (0 = never sleep the display)
|
||||||
static const uint16_t screen_timeout_opts[] = { 250, 500, 1000, 0 };
|
static const uint16_t screen_timeout_opts[] = { 250, 500, 1000, 0 };
|
||||||
|
|
@ -85,6 +107,20 @@ enum { ACT_FEED, ACT_PLAY, ACT_SLEEP, ACT_CLEAN, ACT_HEAL, ACT_STATS, ACT_SETTIN
|
||||||
// ----------------------------------------------------------------- helpers
|
// ----------------------------------------------------------------- helpers
|
||||||
static int8_t clamp100(int v) { return v < 0 ? 0 : (v > 100 ? 100 : v); }
|
static int8_t clamp100(int v) { return v < 0 ? 0 : (v > 100 ? 100 : v); }
|
||||||
|
|
||||||
|
// Tiny string builders used instead of snprintf: we only ever paste short
|
||||||
|
// strings and small unsigned ints, and avoiding <stdio.h> keeps the whole
|
||||||
|
// printf machinery (~1 KB) out of the image. Each returns the new end pointer
|
||||||
|
// so calls chain; remember to NUL-terminate the final buffer yourself.
|
||||||
|
static char *s_cat(char *p, const char *s) { while (*s) *p++ = *s++; return p; }
|
||||||
|
static char *u_cat(char *p, unsigned v)
|
||||||
|
{
|
||||||
|
char tmp[5];
|
||||||
|
int n = 0;
|
||||||
|
do { tmp[n++] = '0' + v % 10; v /= 10; } while (v);
|
||||||
|
while (n) *p++ = tmp[--n];
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
// short square-wave beep on the passive piezo (blocking, ms-scale only)
|
// short square-wave beep on the passive piezo (blocking, ms-scale only)
|
||||||
static void beep(uint16_t freq, uint16_t ms)
|
static void beep(uint16_t freq, uint16_t ms)
|
||||||
{
|
{
|
||||||
|
|
@ -115,14 +151,53 @@ static void pet_reset(void)
|
||||||
pet.hygiene = 100;
|
pet.hygiene = 100;
|
||||||
pet.health = 100;
|
pet.health = 100;
|
||||||
pet.age_min = 0;
|
pet.age_min = 0;
|
||||||
|
pet.xp = 0;
|
||||||
|
pet.species = sel_species;
|
||||||
|
pet.level = 1;
|
||||||
|
pet.form = FORM_PROC;
|
||||||
|
pet.ascend = 0;
|
||||||
pet.poop = 0;
|
pet.poop = 0;
|
||||||
pet.sleeping = 0;
|
pet.sleeping = 0;
|
||||||
pet.alive = 1;
|
pet.alive = 1;
|
||||||
screen = SCR_MAIN;
|
screen = SCR_MAIN;
|
||||||
cursor = 0;
|
cursor = 0;
|
||||||
|
evo_anim = 0;
|
||||||
for (int i = 0; i < N_COUNT; i++) { warn_flag[i] = 0; crit_flag[i] = 0; }
|
for (int i = 0; i < N_COUNT; i++) { warn_flag[i] = 0; crit_flag[i] = 0; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Map the current level (and, at the top, care quality) to a display form.
|
||||||
|
static void compute_form(void)
|
||||||
|
{
|
||||||
|
switch (pet.level) {
|
||||||
|
case 1: pet.form = FORM_PROC; break;
|
||||||
|
case 2: pet.form = FORM_USER; break;
|
||||||
|
case 3: pet.form = FORM_ROOT; break;
|
||||||
|
default: // max level: branch once, latched
|
||||||
|
if (!pet.ascend) pet.ascend = (pet.health >= 60) ? 1 : 2;
|
||||||
|
pet.form = (pet.ascend == 1) ? FORM_CLAUDE : FORM_GLITCH;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Award XP; promote (and trigger the evolution banner) when a tier is reached.
|
||||||
|
static void add_xp(uint8_t n)
|
||||||
|
{
|
||||||
|
if (!pet.alive) return;
|
||||||
|
if (pet.xp < 60000) pet.xp += n;
|
||||||
|
|
||||||
|
uint8_t nl = 1;
|
||||||
|
for (uint8_t i = 1; i < MAX_LEVEL; i++)
|
||||||
|
if (pet.xp >= level_xp[i]) nl = i + 1;
|
||||||
|
|
||||||
|
if (nl > pet.level) {
|
||||||
|
pet.level = nl;
|
||||||
|
compute_form();
|
||||||
|
evo_anim = 30; // ~1.8 s celebratory banner
|
||||||
|
beep(784, 60); beep(988, 60); beep(1175, 60); beep(1568, 140);
|
||||||
|
led_blink();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Chirp once when a need first drops below 50% (gentle) or 20% (urgent),
|
// Chirp once when a need first drops below 50% (gentle) or 20% (urgent),
|
||||||
// re-arming only after it recovers. Audible even while the screen is off,
|
// re-arming only after it recovers. Audible even while the screen is off,
|
||||||
// so it works as a "tend to me" reminder.
|
// so it works as a "tend to me" reminder.
|
||||||
|
|
@ -177,6 +252,7 @@ static void do_action(uint8_t act)
|
||||||
react(EXP_EAT);
|
react(EXP_EAT);
|
||||||
beep(880, 60); beep(1175, 80);
|
beep(880, 60); beep(1175, 80);
|
||||||
led_blink();
|
led_blink();
|
||||||
|
add_xp(4);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ACT_PLAY:
|
case ACT_PLAY:
|
||||||
|
|
@ -186,6 +262,7 @@ static void do_action(uint8_t act)
|
||||||
react(EXP_HAPPY);
|
react(EXP_HAPPY);
|
||||||
beep(988, 60); beep(1319, 60); beep(1568, 90);
|
beep(988, 60); beep(1319, 60); beep(1568, 90);
|
||||||
led_blink();
|
led_blink();
|
||||||
|
add_xp(6);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ACT_SLEEP:
|
case ACT_SLEEP:
|
||||||
|
|
@ -198,12 +275,14 @@ static void do_action(uint8_t act)
|
||||||
pet.hygiene = 100;
|
pet.hygiene = 100;
|
||||||
pet.happy = clamp100(pet.happy + 5);
|
pet.happy = clamp100(pet.happy + 5);
|
||||||
beep(1319, 50); beep(1047, 50);
|
beep(1319, 50); beep(1047, 50);
|
||||||
|
add_xp(3);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ACT_HEAL:
|
case ACT_HEAL:
|
||||||
pet.health = clamp100(pet.health + 35);
|
pet.health = clamp100(pet.health + 35);
|
||||||
beep(784, 60); beep(1047, 60); beep(1319, 90);
|
beep(784, 60); beep(1047, 60); beep(1319, 90);
|
||||||
led_blink();
|
led_blink();
|
||||||
|
add_xp(4);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ACT_STATS:
|
case ACT_STATS:
|
||||||
|
|
@ -255,6 +334,9 @@ static void game_tick(void)
|
||||||
if (lo < 15) pet.health = clamp100(pet.health - 3);
|
if (lo < 15) pet.health = clamp100(pet.health - 3);
|
||||||
else if (lo > 50) pet.health = clamp100(pet.health + 2);
|
else if (lo > 50) pet.health = clamp100(pet.health + 2);
|
||||||
|
|
||||||
|
// a well-kept pet matures: passive XP while every need stays healthy
|
||||||
|
if (lo > 50 && !pet.sleeping) add_xp(3);
|
||||||
|
|
||||||
check_notifications();
|
check_notifications();
|
||||||
|
|
||||||
if (pet.health <= 0) {
|
if (pet.health <= 0) {
|
||||||
|
|
@ -285,14 +367,79 @@ static void draw_menu_bar(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Per-species eye geometry, so the shades land on the right spot.
|
||||||
|
static const uint8_t eye_cy[SPECIES_COUNT] = { 11, 17, 12 }; // SP_SHELL,PANKO,TMUX
|
||||||
|
static const uint8_t eye_lx[SPECIES_COUNT] = { 11, 11, 9 };
|
||||||
|
static const uint8_t eye_rx[SPECIES_COUNT] = { 20, 21, 23 };
|
||||||
|
|
||||||
|
// Hacker garb earned as the pet levels up, drawn dark over the lit body so it
|
||||||
|
// reads as black gear.
|
||||||
|
static void draw_accessories(int x, int y)
|
||||||
|
{
|
||||||
|
uint8_t sp = pet.species;
|
||||||
|
uint8_t cy = eye_cy[sp], lx = eye_lx[sp], rx = eye_rx[sp];
|
||||||
|
|
||||||
|
if (pet.form >= FORM_USER) { // shades
|
||||||
|
ssd1306_fillRect(x + lx - 3, y + cy - 2, 7, 4, 0);
|
||||||
|
ssd1306_fillRect(x + rx - 3, y + cy - 2, 7, 4, 0);
|
||||||
|
if (rx - lx > 7)
|
||||||
|
ssd1306_drawFastHLine(x + lx + 4, y + cy - 1, rx - lx - 7, 0);
|
||||||
|
}
|
||||||
|
if (pet.form >= FORM_ROOT) { // gaming headset + mic boom
|
||||||
|
ssd1306_drawLine(x + 3, y + 10, x + 9, y + 2, 0);
|
||||||
|
ssd1306_drawLine(x + 9, y + 2, x + 23, y + 2, 0);
|
||||||
|
ssd1306_drawLine(x + 23, y + 2, x + 29, y + 10, 0);
|
||||||
|
ssd1306_fillRect(x + 1, y + 12, 4, 7, 0);
|
||||||
|
ssd1306_drawLine(x + 3, y + 18, x + 10, y + 24, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void draw_creature(int x, int y)
|
||||||
|
{
|
||||||
|
const unsigned char *spr;
|
||||||
|
if (pet.form == FORM_CLAUDE) spr = spr_claude;
|
||||||
|
else if (pet.form == FORM_GLITCH) spr = spr_glitch;
|
||||||
|
else spr = species_frames[pet.species][current_expression()];
|
||||||
|
|
||||||
|
ssd1306_drawImage(x, y, spr, PANA_W, PANA_H, 0);
|
||||||
|
|
||||||
|
// growing forms wear gear; the ascended/glitched forms speak for themselves
|
||||||
|
if (spr != spr_claude && spr != spr_glitch && !pet.sleeping)
|
||||||
|
draw_accessories(x, y);
|
||||||
|
|
||||||
|
// Claude radiates: a few twinkling pixels that shift each frame
|
||||||
|
if (pet.form == FORM_CLAUDE) {
|
||||||
|
ssd1306_drawPixel(x - 2 + (frame & 3), y + 4, 1);
|
||||||
|
ssd1306_drawPixel(x + PANA_W + (frame & 1), y + 10, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void draw_evo_banner(void)
|
||||||
|
{
|
||||||
|
ssd1306_fillRect(6, 18, SSD1306_W - 12, 24, 0);
|
||||||
|
ssd1306_drawRect(6, 18, SSD1306_W - 12, 24, 1);
|
||||||
|
draw_center_str(21, ">> evolving");
|
||||||
|
char b[17], *p = b;
|
||||||
|
p = s_cat(p, "[ ");
|
||||||
|
p = s_cat(p, form_names[pet.form]);
|
||||||
|
p = s_cat(p, " ]");
|
||||||
|
*p = 0;
|
||||||
|
draw_center_str(31, b);
|
||||||
|
}
|
||||||
|
|
||||||
static void draw_main(void)
|
static void draw_main(void)
|
||||||
{
|
{
|
||||||
ssd1306_setbuf(0);
|
ssd1306_setbuf(0);
|
||||||
|
|
||||||
// top bar: action label, with a tiny low-health warning
|
// top bar: action label + level badge, with a tiny low-health warning
|
||||||
draw_center_str(0, menu_labels[cursor]);
|
draw_center_str(0, menu_labels[cursor]);
|
||||||
if (pet.alive && pet.health < 30 && (frame & 8))
|
if (pet.alive && pet.health < 30 && (frame & 8))
|
||||||
ssd1306_drawstr(0, 0, "!", 1);
|
ssd1306_drawstr(0, 0, "!", 1);
|
||||||
|
char badge[6], *bp = badge;
|
||||||
|
*bp++ = 'L';
|
||||||
|
bp = u_cat(bp, pet.level);
|
||||||
|
*bp = 0;
|
||||||
|
ssd1306_drawstr(SSD1306_W - 2 * 8, 0, badge, 1);
|
||||||
ssd1306_drawFastHLine(0, 10, SSD1306_W, 1);
|
ssd1306_drawFastHLine(0, 10, SSD1306_W, 1);
|
||||||
|
|
||||||
// pet: gentle horizontal stroll + vertical bob (still while asleep)
|
// pet: gentle horizontal stroll + vertical bob (still while asleep)
|
||||||
|
|
@ -306,8 +453,7 @@ static void draw_main(void)
|
||||||
px = (t < 40) ? 30 + t : 30 + (80 - t); // 30..70..30
|
px = (t < 40) ? 30 + t : 30 + (80 - t); // 30..70..30
|
||||||
py = 14 + ((frame % 16) < 8 ? 0 : 1);
|
py = 14 + ((frame % 16) < 8 ? 0 : 1);
|
||||||
}
|
}
|
||||||
ssd1306_drawImage(px, py, pana_frames[current_expression()],
|
draw_creature(px, py);
|
||||||
PANA_W, PANA_H, 0);
|
|
||||||
|
|
||||||
// floor + poop piles
|
// floor + poop piles
|
||||||
ssd1306_drawFastHLine(0, 46, SSD1306_W, 1);
|
ssd1306_drawFastHLine(0, 46, SSD1306_W, 1);
|
||||||
|
|
@ -315,6 +461,7 @@ static void draw_main(void)
|
||||||
ssd1306_drawImage(8 + i * 12, 38, spr_poop, 8, 8, 0);
|
ssd1306_drawImage(8 + i * 12, 38, spr_poop, 8, 8, 0);
|
||||||
|
|
||||||
draw_menu_bar();
|
draw_menu_bar();
|
||||||
|
if (evo_anim) draw_evo_banner(); // celebratory overlay on top
|
||||||
ssd1306_refresh();
|
ssd1306_refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -330,16 +477,26 @@ static void draw_bar(int y, const char *label, int8_t val)
|
||||||
static void draw_stats(void)
|
static void draw_stats(void)
|
||||||
{
|
{
|
||||||
ssd1306_setbuf(0);
|
ssd1306_setbuf(0);
|
||||||
draw_center_str(0, "-- STATUS --");
|
draw_center_str(0, "~/pet $ stat");
|
||||||
draw_bar(10, "FOOD", pet.satiety);
|
draw_bar(10, "FOOD", pet.satiety);
|
||||||
draw_bar(19, "FUN ", pet.happy);
|
draw_bar(19, "HAPPY", pet.happy);
|
||||||
draw_bar(28, "ENGY", pet.energy);
|
draw_bar(28, "ENERGY", pet.energy);
|
||||||
draw_bar(37, "WASH", pet.hygiene);
|
draw_bar(37, "CLEAN", pet.hygiene);
|
||||||
draw_bar(46, "HLTH", pet.health);
|
draw_bar(46, "HEALTH", pet.health);
|
||||||
|
|
||||||
char line[17];
|
// no form name here: keep room for the XP-to-next-level readout
|
||||||
snprintf(line, sizeof(line), "Age %u %s", pet.age_min,
|
char line[17], *p = line;
|
||||||
pet.sleeping ? "Zzz" : "");
|
*p++ = 'L';
|
||||||
|
p = u_cat(p, pet.level);
|
||||||
|
p = s_cat(p, " xp ");
|
||||||
|
if (pet.level < MAX_LEVEL) {
|
||||||
|
p = u_cat(p, pet.xp);
|
||||||
|
*p++ = '/';
|
||||||
|
p = u_cat(p, level_xp[pet.level]);
|
||||||
|
} else {
|
||||||
|
p = s_cat(p, "MAX");
|
||||||
|
}
|
||||||
|
*p = 0;
|
||||||
ssd1306_drawstr(0, 56, line, 1);
|
ssd1306_drawstr(0, 56, line, 1);
|
||||||
ssd1306_refresh();
|
ssd1306_refresh();
|
||||||
}
|
}
|
||||||
|
|
@ -347,11 +504,35 @@ static void draw_stats(void)
|
||||||
static void draw_dead(void)
|
static void draw_dead(void)
|
||||||
{
|
{
|
||||||
ssd1306_setbuf(0);
|
ssd1306_setbuf(0);
|
||||||
ssd1306_drawImage(48, 8, spr_grave, 32, 32, 0);
|
ssd1306_drawImage(48, 2, spr_grave, 32, 32, 0);
|
||||||
draw_center_str(44, "R.I.P.");
|
draw_center_str(36, pet.ascend == 2 ? "** CORRUPTED **" : "SEGFAULT (11)");
|
||||||
char line[17];
|
char line[17], *p = line;
|
||||||
snprintf(line, sizeof(line), "lived %u min", pet.age_min);
|
p = s_cat(p, "core dumped L");
|
||||||
draw_center_str(52, line);
|
p = u_cat(p, pet.level);
|
||||||
|
*p = 0;
|
||||||
|
draw_center_str(46, line);
|
||||||
|
draw_center_str(56, "OK: respawn");
|
||||||
|
ssd1306_refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
// welcome screen: choose a starter species before booting the pet
|
||||||
|
static void draw_select(void)
|
||||||
|
{
|
||||||
|
ssd1306_setbuf(0);
|
||||||
|
draw_center_str(0, "~ $ adopt --pet");
|
||||||
|
ssd1306_drawFastHLine(0, 10, SSD1306_W, 1);
|
||||||
|
|
||||||
|
// big idle preview of the highlighted species (no gear at level 1)
|
||||||
|
ssd1306_drawImage(48, 13, species_frames[sel_species][EXP_IDLE],
|
||||||
|
PANA_W, PANA_H, 0);
|
||||||
|
|
||||||
|
char line[17], *p = line;
|
||||||
|
p = s_cat(p, "< ");
|
||||||
|
p = s_cat(p, species_names[sel_species]);
|
||||||
|
p = s_cat(p, " >");
|
||||||
|
*p = 0;
|
||||||
|
draw_center_str(47, line);
|
||||||
|
draw_center_str(56, "L/R pick OK go");
|
||||||
ssd1306_refresh();
|
ssd1306_refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -362,9 +543,9 @@ static void draw_settings(void)
|
||||||
ssd1306_drawFastHLine(0, 10, SSD1306_W, 1);
|
ssd1306_drawFastHLine(0, 10, SSD1306_W, 1);
|
||||||
|
|
||||||
char rows[SETTINGS_ROWS][17];
|
char rows[SETTINGS_ROWS][17];
|
||||||
snprintf(rows[0], 17, "Screen off:%s", screen_timeout_names[timeout_idx]);
|
*s_cat(s_cat(rows[0], "Screen off:"), screen_timeout_names[timeout_idx]) = 0;
|
||||||
snprintf(rows[1], 17, "Sound: %s", sound_on ? "On" : "Off");
|
*s_cat(s_cat(rows[1], "Sound: "), sound_on ? "On" : "Off") = 0;
|
||||||
snprintf(rows[2], 17, "Back");
|
*s_cat(rows[2], "Back") = 0;
|
||||||
|
|
||||||
for (uint8_t r = 0; r < SETTINGS_ROWS; r++) {
|
for (uint8_t r = 0; r < SETTINGS_ROWS; r++) {
|
||||||
int y = 18 + r * 12;
|
int y = 18 + r * 12;
|
||||||
|
|
@ -412,13 +593,24 @@ static void gpio_setup(void)
|
||||||
|
|
||||||
static void splash(void)
|
static void splash(void)
|
||||||
{
|
{
|
||||||
|
// fake terminal boot sequence, revealed line by line
|
||||||
|
static const char *const boot[] = {
|
||||||
|
"panagotchi v2",
|
||||||
|
"booting kernel..",
|
||||||
|
"mount /pet ok",
|
||||||
|
"spawn shell ok",
|
||||||
|
"> ./tamagotchi_",
|
||||||
|
};
|
||||||
ssd1306_setbuf(0);
|
ssd1306_setbuf(0);
|
||||||
draw_center_str(4, "PANAGOTCHI");
|
for (uint8_t i = 0; i < 5; i++) {
|
||||||
ssd1306_drawImage(48, 16, pana_idle, PANA_W, PANA_H, 0);
|
ssd1306_drawstr(0, i * 10, boot[i], 1);
|
||||||
draw_center_str(52, "press any key");
|
|
||||||
ssd1306_refresh();
|
ssd1306_refresh();
|
||||||
|
beep(1200 + i * 120, 25);
|
||||||
beep(659, 80); beep(784, 80); beep(988, 120);
|
Delay_Ms(220);
|
||||||
|
}
|
||||||
|
draw_center_str(54, "press any key");
|
||||||
|
ssd1306_refresh();
|
||||||
|
beep(988, 120);
|
||||||
|
|
||||||
// wait until a button is pressed (or ~4 s timeout)
|
// wait until a button is pressed (or ~4 s timeout)
|
||||||
for (int i = 0; i < 200; i++) {
|
for (int i = 0; i < 200; i++) {
|
||||||
|
|
@ -441,8 +633,8 @@ int main(void)
|
||||||
}
|
}
|
||||||
ssd1306_init();
|
ssd1306_init();
|
||||||
|
|
||||||
pet_reset();
|
|
||||||
splash();
|
splash();
|
||||||
|
screen = SCR_SELECT; // pick a species before a pet is born
|
||||||
|
|
||||||
Buttons prev = {0, 0, 0};
|
Buttons prev = {0, 0, 0};
|
||||||
|
|
||||||
|
|
@ -464,6 +656,22 @@ int main(void)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switch (screen) {
|
switch (screen) {
|
||||||
|
case SCR_SELECT:
|
||||||
|
if (left_edge) {
|
||||||
|
sel_species = (sel_species + SPECIES_COUNT - 1) % SPECIES_COUNT;
|
||||||
|
beep(1047, 25);
|
||||||
|
}
|
||||||
|
if (right_edge) {
|
||||||
|
sel_species = (sel_species + 1) % SPECIES_COUNT;
|
||||||
|
beep(1047, 25);
|
||||||
|
}
|
||||||
|
if (ok_edge) { // born! boot the chosen species
|
||||||
|
pet_reset(); // sets screen = SCR_MAIN, species = sel_species
|
||||||
|
beep(659, 80); beep(988, 120);
|
||||||
|
}
|
||||||
|
draw_select();
|
||||||
|
break;
|
||||||
|
|
||||||
case SCR_MAIN:
|
case SCR_MAIN:
|
||||||
if (left_edge) {
|
if (left_edge) {
|
||||||
cursor = (cursor + ICON_COUNT - 1) % ICON_COUNT;
|
cursor = (cursor + ICON_COUNT - 1) % ICON_COUNT;
|
||||||
|
|
@ -507,8 +715,8 @@ int main(void)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SCR_DEAD:
|
case SCR_DEAD:
|
||||||
if (ok_edge) { // start a new pet
|
if (ok_edge) { // back to the welcome screen to re-pick
|
||||||
pet_reset();
|
screen = SCR_SELECT;
|
||||||
beep(659, 80); beep(988, 120);
|
beep(659, 80); beep(988, 120);
|
||||||
}
|
}
|
||||||
draw_dead();
|
draw_dead();
|
||||||
|
|
@ -524,6 +732,7 @@ int main(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (anim_timer) anim_timer--;
|
if (anim_timer) anim_timer--;
|
||||||
|
if (evo_anim) evo_anim--;
|
||||||
|
|
||||||
// advance game time independent of screen / display state
|
// advance game time independent of screen / display state
|
||||||
if (pet.alive && ++tick_acc >= TICK_FRAMES) {
|
if (pet.alive && ++tick_acc >= TICK_FRAMES) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue