Compare commits
@@ -41,6 +41,7 @@ dos2
|
||||
!/projects/template
|
||||
!/projects/template_msx2
|
||||
!/projects/mazegame
|
||||
!/projects/kissaten_yugure
|
||||
|
||||
/projects/samples/datasrc
|
||||
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
# Kissaten Yūgure — MSX2 cozy game
|
||||
|
||||
## Project overview
|
||||
A cozy coffee-shop (kissaten) simulation for MSX2, set in a provincial Japanese
|
||||
town in 1987. Target audience: adult retro gamers who love Japanese art and
|
||||
computers. Written in C using the MSXgl library. Working title: "Kissaten Yūgure"
|
||||
(Twilight Coffee Shop).
|
||||
|
||||
Read `docs/DESIGN.md` before making any design or architecture decisions.
|
||||
Read `docs/CONVERSATION.md` for the original design discussion and rationale.
|
||||
|
||||
## Design pillars (never violate)
|
||||
- Cozy contract: no fail states, no bankruptcy, no time pressure outside the
|
||||
brew minigame. Progression is always forward.
|
||||
- Atmosphere over mechanics: palette work, music, and character writing carry
|
||||
the game.
|
||||
- Static-heavy rendering: no scrolling. Only sprites and small blits move.
|
||||
- Small, finishable scope. When in doubt, cut.
|
||||
|
||||
## Tech stack
|
||||
- Target: MSX2, SCREEN 5 (G4, 256×212, 16 colors from 512)
|
||||
- ROM format: ASCII16 MegaROM (banked) — plan bank layout from day one
|
||||
- Library: MSXgl (C) — https://github.com/aoineko-fr/MSXgl
|
||||
- Compiler: SDC C via MSXgl build system
|
||||
- Music: **unresolved — this line is stale.** It describes a PSG / MML → NDP
|
||||
pipeline, but the working pipeline used for `projects/mazegame` is the
|
||||
`msx-music-generator` repo emitting lVGM + ayFX, on MSX-Music (YM2413).
|
||||
This project targets plain MSX2, where FM is not standard hardware.
|
||||
Decision deferred to M9; see `docs/PLAN.md` §8 item 15.
|
||||
- Dialogue: authored in YAML/JSON, compiled to C arrays / binary banks by
|
||||
`tools/compile_dialogue.js` (Node.js)
|
||||
- Emulator for testing: openMSX (also verify on real hardware profiles)
|
||||
|
||||
## Build & test
|
||||
- Build: `./build.sh` (MSXgl build_tool; ROM → `out/` and `emul/rom/kissaten.rom`)
|
||||
- Run: `./build.sh run` → builds and launches openMSX
|
||||
- Requires `node` on PATH, else build.sh falls back to the bundled
|
||||
Windows/Linux binary and dies: `export PATH="/opt/homebrew/opt/node@24/bin:$PATH"`
|
||||
- Headless verification: drive openMSX with a Tcl script —
|
||||
`openmsx -machine C-BIOS_MSX2 -carta emul/rom/kissaten.rom -script test.tcl`
|
||||
using `after time <s> {screenshot f.png}` and `keymatrixdown 8 1` (SPACE).
|
||||
Add `set throttle off` to the script: emulated time then runs many times
|
||||
faster than wall clock, so a 200-second play-through takes a couple of
|
||||
seconds. `after time` still counts emulated seconds, so timings hold.
|
||||
- **Boot is slow — budget for it.** `ROMDelayBoot = true` (needed for disk
|
||||
access, see below) means the game only appears at roughly 40-90s of
|
||||
emulated time. Screenshots before that show a blue BASIC screen, which
|
||||
looks exactly like a hang and is not one. Test with a disk machine:
|
||||
`openmsx -machine Philips_NMS_8250 -carta emul/rom/kissaten.rom -diska save.dsk`
|
||||
- Dialogue data (stage 3): `node tools/compile_dialogue.js data/dialogue/*.yaml`
|
||||
- Music data (stage 3+): `node tools/generate_mml.js` → NDP compiler → `data/music/`
|
||||
|
||||
## Platform gotchas (learned the hard way)
|
||||
- **Keyboard:** read the matrix row inside `DisableInterrupt()`/`EnableInterrupt()`.
|
||||
`Keyboard_Read()` is an `out` (row select) then `in`; the BIOS ISR scans the
|
||||
matrix too, and if it lands between the two you get phantom keypresses.
|
||||
`INPUT_KB_UPDATE` (buffered mode) is *not* a fix — it reads the BIOS
|
||||
NEWKEY/OLDKEY area, which C-BIOS does not maintain in the standard format.
|
||||
- **`BankedCall = true` is off until banked code actually exists.** With it on
|
||||
and nothing banked, RAM globals were corrupted at runtime (state machine
|
||||
ran wild, counters garbage). Re-enable deliberately at stage 3.
|
||||
- Erase blits must repaint the *actual* background at that spot — the counter
|
||||
area has three bands (wainscot / counter top highlight / counter top).
|
||||
|
||||
## Disk saving from a cartridge ROM — WORKING
|
||||
|
||||
Saves go to a real file on a real disk: `KISSAT00.SAV` in the root of the
|
||||
disk in drive A. The disk stays a normal FAT disk you can inspect and copy.
|
||||
|
||||
**Use `engine/src/tool/disk_save.h`.** MSXgl v1.3.0 added this module
|
||||
specifically for "save to disk from a ROM application". Do not hand-roll
|
||||
sector I/O — an earlier attempt using PHYDIO (Main ROM 0144h) and a direct
|
||||
CALSLT to DSKIO (4010h) had both entry points return carry-clear *while
|
||||
transferring nothing*, proven with a sentinel that survived the call intact.
|
||||
|
||||
Four things are required, none of them obvious:
|
||||
|
||||
1. **`LibModules` must include both `"tool/disk_save"` and `"dos"`.** The
|
||||
module alone will not link. See `projects/samples/s_save.js` for the
|
||||
reference configuration, and `s_save.c` for usage.
|
||||
2. **`ROMDelayBoot = true`.** A cartridge's INIT normally runs during the BIOS
|
||||
slot scan and MSXgl never returns from it, so the Disk ROM's own INIT never
|
||||
happens and there is no disk system to talk to. This option installs an
|
||||
H.STKE hook and returns to the scan instead.
|
||||
3. **Boot becomes slow.** The game appears at roughly 40-90s of *emulated*
|
||||
time. Screenshots before that show a blue BASIC screen and look exactly
|
||||
like a hang. Use `set throttle off` in the test script so this costs
|
||||
seconds of wall clock, not minutes.
|
||||
4. **`DiskSave_Check()` returns `SAVEDATA_UNSIGNED` for perfectly good
|
||||
files.** With `AppSignature = true` (`-DAPPSIGN`), `DiskSave_Check()`
|
||||
requires the file's first four bytes to equal `g_AppSignature` — but
|
||||
`DiskSave_Save()` writes the payload raw and never adds it. Treat
|
||||
`SAVEDATA_UNSIGNED` as success; `SaveState` carries its own magic, version
|
||||
and checksum, which is a stronger check regardless.
|
||||
|
||||
**Save timing:** written in `AdvanceDay()` *after* the day counter increments,
|
||||
so the file always describes the morning the player wakes to. Saving during
|
||||
the evening instead makes a reload replay the day just finished and
|
||||
double-count its cups.
|
||||
|
||||
Absent or unusable disk is not an error the player has to handle — it just
|
||||
means nothing persists, and the morning card says so.
|
||||
|
||||
Test:
|
||||
```
|
||||
openmsx -machine Philips_NMS_8250 -carta emul/rom/kissaten.rom -diska save.dsk
|
||||
```
|
||||
Create a blank 720K disk with `tools/build/msxtar/msxtar -cf save.dsk --dos1 --size=720K`.
|
||||
|
||||
**RTC CMOS is not an alternative** for a save this size, despite
|
||||
`RTC_USE_SAVEDATA` being TRUE in `msxgl_config.h`. Block 3 of the RP-5C01 is
|
||||
13 nibbles and MSXgl's `RTC_SaveData()` stores exactly **6 bytes**, against a
|
||||
~40-byte `SaveState`. (MSXgl has no cartridge-SRAM mapper target either; the
|
||||
`PAC` module's FM-PAC SRAM, 8 x 1024 bytes, is the other real option.)
|
||||
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 537 B |
|
After Width: | Height: | Size: 610 B |
|
After Width: | Height: | Size: 6.9 KiB |
|
After Width: | Height: | Size: 310 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
@@ -0,0 +1,20 @@
|
||||
GIMP Palette
|
||||
Name: Kissaten Yugure (full)
|
||||
Columns: 16
|
||||
#
|
||||
0 0 0 transparent
|
||||
36 36 36 outline
|
||||
73 36 36 dark wood
|
||||
146 73 36 mid wood
|
||||
182 109 73 light wood
|
||||
255 182 73 lamp glow
|
||||
255 219 146 cream
|
||||
109 73 73 muted wall
|
||||
73 36 146 dusk deep
|
||||
146 73 182 dusk violet
|
||||
219 109 109 dusk rose
|
||||
255 146 73 horizon amber
|
||||
109 36 0 coffee
|
||||
73 109 182 coat blue
|
||||
255 182 146 skin
|
||||
255 255 219 warm white
|
||||
|
After Width: | Height: | Size: 650 B |
|
After Width: | Height: | Size: 1.3 KiB |
@@ -0,0 +1,15 @@
|
||||
GIMP Palette
|
||||
Name: Kissaten Yugure (portrait)
|
||||
Columns: 11
|
||||
#
|
||||
36 36 36 outline
|
||||
73 36 36 dark wood
|
||||
146 73 36 mid wood
|
||||
182 109 73 light wood
|
||||
255 182 73 lamp glow
|
||||
255 219 146 cream
|
||||
109 73 73 muted wall
|
||||
109 36 0 coffee
|
||||
73 109 182 coat blue
|
||||
255 182 146 skin
|
||||
255 255 219 warm white
|
||||
|
After Width: | Height: | Size: 474 B |
|
After Width: | Height: | Size: 103 B |
@@ -0,0 +1,12 @@
|
||||
:: ____________________________
|
||||
:: ██▀▀█▀▀██▀▀▀▀▀▀▀█▀▀█ │ ▄▄▄ ▄▄
|
||||
:: ██ ▀ █▄ ▀██▄ ▀ ▄█ ▄▀▀ █ │ ▀█▄ ▄▀██ ▄█▄█ ██▀▄ ██ ▄███
|
||||
:: █ █ █ ▀▀ ▄█ █ █ ▀▄█ █▄ │ ▄▄█▀ ▀▄██ ██ █ ██▀ ▀█▄ ▀█▄▄
|
||||
:: ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀────────┘ ▀▀
|
||||
:: by Guillaume 'Aoineko' Blanchard under CC BY-SA license
|
||||
::────────────────────────────────────────────────────────────────────
|
||||
@echo off
|
||||
|
||||
cls
|
||||
|
||||
..\..\tools\build\Node\node.exe ..\..\engine\script\js\build.js %1 %2 %3 %4 %5 %6 %7 %8 %9
|
||||
@@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
# ____________________________
|
||||
# ██▀▀█▀▀██▀▀▀▀▀▀▀█▀▀█ │ ▄▄▄ ▄▄
|
||||
# ██ ▀ █▄ ▀██▄ ▀ ▄█ ▄▀▀ █ │ ▀█▄ ▄▀██ ▄█▄█ ██▀▄ ██ ▄███
|
||||
# █ █ █ ▀▀ ▄█ █ █ ▀▄█ █▄ │ ▄▄█▀ ▀▄██ ██ █ ██▀ ▀█▄ ▀█▄▄
|
||||
# ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀────────┘ ▀▀
|
||||
# by Guillaume 'Aoineko' Blanchard under CC BY-SA license
|
||||
#────────────────────────────────────────────────────────────────────
|
||||
clear
|
||||
|
||||
if type -P node; then
|
||||
node ../../engine/script/js/build.js $1 $2 $3 $4 $5 $6 $7 $8 $9
|
||||
else
|
||||
../../tools/build/Node/node ../../engine/script/js/build.js $1 $2 $3 $4 $5 $6 $7 $8 $9
|
||||
fi
|
||||
@@ -0,0 +1,252 @@
|
||||
# Kissaten Yūgure — Art brief
|
||||
|
||||
## Pipeline — export SVG, not PNG
|
||||
|
||||
**Generate at high resolution, export as SVG, drop it in `art/`, and run:**
|
||||
|
||||
```
|
||||
python3 tools/svg2portrait.py art/aki-neutral.svg
|
||||
```
|
||||
|
||||
That writes `art/aki-neutral-48.png` (the real asset) and
|
||||
`art/aki-neutral-48-x6.png` (a 6× preview for judging).
|
||||
|
||||
**Export SVG, never a resized bitmap.** This was learned the hard way. A
|
||||
48×48 PNG produced by resizing in Photoshop came back with **1330 unique
|
||||
colours** in 2304 pixels — bicubic resampling turns every flat region into a
|
||||
gradient, and reducing *that* to 11 colours speckles horribly, worst on large
|
||||
flat areas like the blazer and background.
|
||||
|
||||
The SVG from Magnific is flat-shaded vector: ~550 paths, solid fills, a
|
||||
handful of gradients. The converter rasterises it at 768×768 (16× the target)
|
||||
via `qlmanage`, then takes the **most common colour in each 16×16 block** —
|
||||
a true pixelate with no blending at all. Measured on Aki: 19 colours after
|
||||
the pixelate, 10 after the palette reduction, and the two are nearly
|
||||
indistinguishable. **The 11-colour portrait palette is sufficient for this
|
||||
art** — that was the open question and it's settled.
|
||||
|
||||
If you must work from bitmaps, the same logic applies: resize only by exact
|
||||
integer factors with nearest-neighbour, never bicubic.
|
||||
|
||||
---
|
||||
|
||||
## 1. The palette — read this before generating anything
|
||||
|
||||
Everything in the game shares **one 16-colour palette**. It is already in
|
||||
`kissaten.c` as `g_Palette` and is what the current build renders with.
|
||||
|
||||
- `art/palette.png` — 16×1 px, one pixel per entry. Machine-readable; use it
|
||||
wherever PixelLab accepts a palette image.
|
||||
- `art/palette_ref.png` — 512×64 swatch strip, same order, for eyeballing.
|
||||
|
||||
| # | Hex | Role | Notes |
|
||||
|---|---|---|---|
|
||||
| 0 | `#000000` | transparent | **Never paint with this.** It is the transparent index. |
|
||||
| 1 | `#242424` | outline | near-black; outlines, dark hair |
|
||||
| 2 | `#492424` | dark wood | deep shadow, dark brown hair |
|
||||
| 3 | `#924924` | mid wood | wall panels, doors, deep skin shadow |
|
||||
| 4 | `#B66D49` | light wood | counter top, **skin shadow** |
|
||||
| 5 | `#FFB649` | lamp glow | warm light |
|
||||
| 6 | `#FFDB92` | cream | glassware, **skin highlight** |
|
||||
| 7 | `#6D4949` | muted wall | upper wall, muted cloth |
|
||||
| 8 | `#492492` | dusk deep | **sky only** |
|
||||
| 9 | `#9249B6` | dusk violet | **sky only** |
|
||||
| 10 | `#DB6D6D` | dusk rose | **sky only** |
|
||||
| 11 | `#FF9249` | horizon amber | **sky only** |
|
||||
| 12 | `#6D2400` | coffee | coffee, dark red-brown cloth |
|
||||
| 13 | `#496DB6` | coat blue | uniforms, coats |
|
||||
| 14 | `#FFB692` | skin | **skin base** |
|
||||
| 15 | `#FFFFDB` | warm white | highlights, cup rims, eye whites |
|
||||
|
||||
### The one non-negotiable rule
|
||||
|
||||
**Slots 8–11 are sky. Slots 4–7 are wood and warm interior.** Nothing else may
|
||||
use 8–11.
|
||||
|
||||
This is what makes seasons and time-of-day free: the background bitmap is
|
||||
authored once, and each season/hour is a 32-byte palette swap. If a character's
|
||||
jacket is painted in slot 9, that jacket changes colour every time the sun
|
||||
moves. Getting this wrong is not a cosmetic issue — it silently destroys the
|
||||
whole seasonal system, and you don't find out until M7.
|
||||
|
||||
### Skin, specifically
|
||||
|
||||
There is only one literal "skin" entry, which is too thin for a face. Use
|
||||
these three as a ramp — they're hue-compatible:
|
||||
|
||||
- highlight `#FFDB92` (6) → base `#FFB692` (14) → shadow `#B66D49` (4)
|
||||
- deepest shadow / hair: `#924924` (3), `#492424` (2), `#242424` (1)
|
||||
|
||||
---
|
||||
|
||||
## 2. What I need back
|
||||
|
||||
| Asset | Size | Count |
|
||||
|---|---|---|
|
||||
| Character portrait | **48×48** | 3 per character (neutral / happy / troubled) |
|
||||
| Shop background | **256×212** | 1 |
|
||||
| Customer sprite | **16×16** | 2 layers per character (fill + outline) |
|
||||
|
||||
**PNG, generated natively at the target size — do not downscale a larger
|
||||
image.** Downscaling pixel art produces half-pixels and anti-aliased edges
|
||||
that cannot be quantised cleanly.
|
||||
|
||||
No anti-aliasing, no gradients, no dithering unless it's deliberate hard
|
||||
checkerboard. If PixelLab can be constrained to the 16 colours, do that; if
|
||||
not, generate close and I'll quantise — but the sky/wood slot rule above
|
||||
still has to hold visually or the quantiser can't fix it.
|
||||
|
||||
**48×48 is very small** — roughly 6 pixels of eye. Faces need a strong
|
||||
silhouette and simplified features. Detail that reads at 200×200 will turn to
|
||||
mud. If a generation looks great zoomed out and illegible at 1:1, it's wrong.
|
||||
|
||||
---
|
||||
|
||||
## 3. Prompts — Aki (needed now, for M3)
|
||||
|
||||
Hoshino Aki, 17, studying for Tokyo entrance exams, cream soda drinker.
|
||||
Character notes in `SCRIPT.md` §1. Written as a girl there; that's one word to
|
||||
change if you'd rather — the dialogue beats themselves use no gendered
|
||||
pronouns.
|
||||
|
||||
### Portrait palette block — paste into every portrait prompt
|
||||
|
||||
Portraits never show sky, so the four sky slots are simply absent from the
|
||||
list. That is safer than asking the generator to avoid them.
|
||||
|
||||
```
|
||||
Use only these 11 colours and no others:
|
||||
#242424 #492424 #924924 #B66D49 #FFB649 #FFDB92 #6D4949 #6D2400
|
||||
#496DB6 #FFB692 #FFFFDB
|
||||
Skin: #FFDB92 highlight, #FFB692 base, #B66D49 shadow, #924924 deep shadow.
|
||||
Hair and outlines: #242424 or #492424.
|
||||
Eye whites and highlights: #FFFFDB.
|
||||
Fill the entire background behind the head with flat #492424.
|
||||
Do not use pure black #000000 anywhere.
|
||||
```
|
||||
|
||||
**Common style stem** — prepend to all three, then append the palette block:
|
||||
|
||||
> 48x48 pixel art portrait, 1987 Japanese anime style as drawn for MSX2 or
|
||||
> PC-88 games, head and shoulders, three-quarter view, hard-edged pixels, no
|
||||
> anti-aliasing, flat cel shading, simple readable silhouette, flat single
|
||||
> colour background
|
||||
|
||||
**Aki — neutral**
|
||||
> ...17 year old Japanese high school student, straight dark bob-length hair,
|
||||
> tired but polite expression, calm eyes, slight shadows under the eyes,
|
||||
> looking slightly off to one side
|
||||
|
||||
**Aki — happy**
|
||||
> ...17 year old Japanese high school student, straight dark bob-length hair,
|
||||
> small genuine smile, eyes softened and slightly narrowed, faint blush,
|
||||
> looking toward the viewer
|
||||
|
||||
**Aki — troubled**
|
||||
> ...17 year old Japanese high school student, straight dark bob-length hair,
|
||||
> eyes cast downward, faint frown, tense mouth, weary
|
||||
|
||||
---
|
||||
|
||||
## 4. Prompts — the rest of the cast (M8, not urgent)
|
||||
|
||||
Same style stem and the **same portrait palette block from §3**, swapping the
|
||||
clothing line. Note the clothing colours available are only `#496DB6` (blue),
|
||||
`#6D4949` (muted brown-grey), `#6D2400` (dark red-brown), `#492424` and
|
||||
`#242424` — so give each character a distinct one or they'll blur together in
|
||||
the dialogue box.
|
||||
|
||||
**Ōta-san** — retired stationmaster, ~70, black coffee, punctual.
|
||||
> elderly Japanese man in his seventies, close-cropped grey hair, deeply
|
||||
> lined face, upright bearing, plain dark jacket buttoned to the collar
|
||||
- *neutral:* composed, formal · *happy:* faint dignified smile, eyes crinkled
|
||||
- *troubled:* jaw set, looking past the viewer
|
||||
|
||||
**Fujimoto** — manga artist, ~30, exhausted, funny about it.
|
||||
> Japanese manga artist in their thirties, messy shoulder-length hair, heavy
|
||||
> shadows under the eyes, round glasses, rumpled shirt with sleeves pushed up
|
||||
- *neutral:* wired, sleepless · *happy:* crooked grin, animated
|
||||
- *troubled:* hollow stare, hand near face
|
||||
|
||||
**Nakajima-san** — widow, ~65, orders two coffees.
|
||||
> Japanese woman in her mid-sixties, silver hair pinned back neatly, soft
|
||||
> composed face, high-collared blouse under a plain cardigan, small pearl
|
||||
> earrings
|
||||
- *neutral:* serene, self-possessed · *happy:* warm gentle smile
|
||||
- *troubled:* distant, looking at something not in the room
|
||||
|
||||
---
|
||||
|
||||
## 5. Prompt — the shop background (M6, longest lead time)
|
||||
|
||||
256×212. This one carries the game's whole look and is the hardest to redo,
|
||||
so it's worth several attempts.
|
||||
|
||||
Composition is fixed by the code — see `DESIGN.md` §4 and `DrawScene()`:
|
||||
|
||||
- Top **16px** is the status bar (drawn over) — keep it empty/dark.
|
||||
- **y=16–148** is the shop scene.
|
||||
- Bottom **64px** is the dialogue window (drawn over) — keep it empty/dark.
|
||||
- Window on the **left** (~x16–88), showing dusk sky in slots 8–11 only.
|
||||
- Door on the **right** (~x208–244).
|
||||
- Counter running horizontally at **y≈98**, its top edge level.
|
||||
- Hanging lamp above the counter, centre.
|
||||
- Siphon coffee rig sits on the counter left of centre — I can keep drawing
|
||||
this procedurally if it's easier to leave out.
|
||||
|
||||
> 256x212 pixel art interior of a small 1987 Japanese kissaten coffee shop at
|
||||
> dusk, viewed straight on, static single-screen game background, wooden
|
||||
> counter running across the lower third, tall window on the left showing a
|
||||
> violet and amber dusk sky, wooden door on the right, hanging lamp with warm
|
||||
> glow above the counter, wood panelling, shelves with glassware, cosy and
|
||||
> quiet, 1987 MSX2 game art, hard-edged pixels, no anti-aliasing, flat cel
|
||||
> shading
|
||||
|
||||
### Background palette block — this one is split by region
|
||||
|
||||
Unlike the portraits, the background needs all 15 colours — but **which
|
||||
colours may appear is decided by where you are in the image**. This is the
|
||||
constraint that makes seasons free, and it is the easiest one to get wrong.
|
||||
|
||||
```
|
||||
Use only these 15 colours and no others.
|
||||
|
||||
For the sky visible through the window, use ONLY these four:
|
||||
#492492 #9249B6 #DB6D6D #FF9249
|
||||
|
||||
For everything else — walls, floor, counter, door, window frame, lamp,
|
||||
shelves, glassware, every object in the room — use ONLY these eleven:
|
||||
#242424 #492424 #924924 #B66D49 #FFB649 #FFDB92 #6D4949 #6D2400
|
||||
#496DB6 #FFB692 #FFFFDB
|
||||
|
||||
The four sky colours must appear nowhere except inside the window opening.
|
||||
The window frame, mullions and sill are wood and use the interior colours.
|
||||
Do not use pure black #000000 anywhere.
|
||||
Leave the top 16 rows and the bottom 64 rows flat #242424 — the game draws
|
||||
its own status bar and dialogue box over them.
|
||||
```
|
||||
|
||||
**Why this one rule matters more than the rest of this document:** each season
|
||||
and hour of day is a 32-byte palette swap on the same bitmap. Repaint slots
|
||||
8–11 and the sky goes from dusk to noon to rain for free. But if a chair leg
|
||||
or a coffee cup is painted in `#9249B6`, that chair leg changes colour every
|
||||
time the sun moves — and you won't find out until M7, long after the art is
|
||||
finished.
|
||||
|
||||
---
|
||||
|
||||
## 6. Sprites (M6)
|
||||
|
||||
16×16, two layers per customer: a **fill** layer and an **outline** layer that
|
||||
is the same silhouette dilated by one pixel, drawn behind. Sprite mode 2, so
|
||||
each layer is a single colour — these are shapes, not shaded art. Current
|
||||
placeholders are in `kissaten.c` as `g_SprCustFill` / `g_SprCustLine`.
|
||||
|
||||
**Palette does not apply here in the usual sense.** These are hardware
|
||||
sprites, not bitmap art: each layer is one flat colour chosen at runtime by
|
||||
the code, so the image only needs to define *shape*. Draw them as pure
|
||||
black-on-white silhouettes and I'll assign colours — currently `#496DB6` for
|
||||
the fill layer and `#242424` for the outline, per customer.
|
||||
|
||||
Worth doing by hand rather than generating; a 16×16 single-colour silhouette
|
||||
is faster to draw than to prompt for.
|
||||
@@ -0,0 +1,115 @@
|
||||
# Design conversation record — Kissaten Yūgure
|
||||
|
||||
A record of the original brainstorm and design discussion (Claude ↔ Jurjen,
|
||||
July 2026) that led to this project. Kept for rationale and context; the
|
||||
distilled result lives in `DESIGN.md`.
|
||||
|
||||
---
|
||||
|
||||
## 1. The brief
|
||||
|
||||
Jurjen wanted a new MSX2 game idea: **a cozy game targeted mainly at male
|
||||
adults who love Japanese art and retro games**, built with MSXgl.
|
||||
|
||||
Claude's read on the audience: nostalgia for late-80s Japan, quiet melancholy,
|
||||
craftsmanship, and pixel art in the style of MSX magazine covers / Konami and
|
||||
Compile titles. The MSX2 itself is a Japanese cultural artifact, so the
|
||||
platform is part of the appeal. Reference vibe: *A Short Hike* energy,
|
||||
rendered like an MSX2 classic.
|
||||
|
||||
## 2. Four concepts pitched
|
||||
|
||||
1. **Showa-era shopkeeper sim** — run a tiny kissaten, sento, or ramen stall
|
||||
in a sleepy 1980s town. Regulars with small stories, seasons change the
|
||||
palette (SCREEN 5 palette swaps per season = big atmosphere, low cost).
|
||||
Simple state machines + dialogue, MSXgl-friendly; PSG/NDP pipeline fits
|
||||
gentle city-pop-adjacent loops. Hits the demographic dead center.
|
||||
|
||||
2. **Bonsai / garden tending game** — shape a tree or karesansui garden over
|
||||
in-game years via a simple L-system-ish growth model. Minimal input,
|
||||
maximal zen, sumi-e visuals, persistent growth via save. Smallest and most
|
||||
distinctive option; nobody has made it on MSX.
|
||||
|
||||
3. **Rural train journey game** — conductor/passenger on a one-car local
|
||||
line; each station is a vignette. Landscapes are the star, but horizontal
|
||||
scrolling is work on MSX2 (vertical scroll register is free), so it would
|
||||
need screen-by-screen scenes or parallax-lite. Densha + inaka nostalgia.
|
||||
|
||||
4. **Yokai postman / errand game** — cozy-spooky letter delivery between
|
||||
friendly yokai at dusk. Iconic character material, light fetch-quest
|
||||
structure, Ghibli / Mizuki Shigeru vibe.
|
||||
|
||||
**Recommendation:** #1 or #2, because scope kills hobby projects. #1 had the
|
||||
strongest emotional hook and marketing appeal ("run a coffee shop on real
|
||||
MSX2 hardware"); #2 was the most achievable and distinctive.
|
||||
|
||||
**Cross-cutting principles:** lean into palette work (MSX2's superpower),
|
||||
keep text minimal or bilingual-friendly for the Japanese retro community,
|
||||
and let the MML → NDP music pipeline carry the mood.
|
||||
|
||||
## 3. Decision
|
||||
|
||||
Jurjen picked **#1, the kissaten sim**. Working title: **Kissaten Yūgure**
|
||||
("Twilight Coffee Shop") — you inherit a small kissaten in a fictional
|
||||
provincial town, 1987.
|
||||
|
||||
## 4. Design deep-dive (summary — full detail in DESIGN.md)
|
||||
|
||||
- **Core loop:** one day ≈ 5–10 real minutes. Morning prep (menu focus,
|
||||
radio weather, stock) → open hours (serve + siphon-brew timing minigame +
|
||||
dialogue with regulars) → evening close (till, journal, save).
|
||||
- **Cozy contract:** no fail states, no bankruptcy; money gates cosmetic and
|
||||
menu upgrades (grinder, jazz records, a cat). Progression = story + seasons.
|
||||
- **Regulars:** 6–8 characters (retired stationmaster, exam student, manga
|
||||
artist, widow...), each with 12–20 short scenes triggered by day count,
|
||||
season, weather, or what you serve. Right order at the right moment
|
||||
advances arcs.
|
||||
- **Screen layout (SCREEN 5, 256×212):** 16 px status bar (day/season,
|
||||
clock, ¥) · 132 px shop scene (door, counter with customer sprites,
|
||||
siphon rig) · 64 px dialogue window (48×48 portrait, 3 lines × 26 chars,
|
||||
typewriter reveal). Static-heavy on purpose: only sprites move — no
|
||||
scrolling — the biggest scope-saver in the design.
|
||||
- **Hardware mapping:** VRAM page 0 = scene bitmap, page 1 = asset warehouse
|
||||
blitted via HMMM/HMMV. Seasonal palette trick: one background authored
|
||||
around palette slots (sky in 8–11, wood tones in 4–7); each season/time of
|
||||
day is a 32-byte palette table, optionally lerped across the day. Sprite
|
||||
mode 2, two layered 16×16 sprites per customer. Portraits 48×48 × 3
|
||||
expressions — where the pixel-art budget goes.
|
||||
- **Data model:** tiny `SaveState` (~40 bytes) with day, season, weather,
|
||||
money, unlock bitmask, and 8 `Regular` structs (arc_stage, affinity,
|
||||
last_visit_day). Dialogue as data: YAML/JSON compiled by a Node.js tool to
|
||||
C arrays / binary banks. ASCII16 MegaROM layout from day one.
|
||||
- **Visitor logic:** weighted table per tick, filtered by season / weather /
|
||||
time / days-since-last-visit — tunable in a spreadsheet, produces
|
||||
noticeable patterns ("the stationmaster always comes when it rains").
|
||||
- **Music:** 6–8 short cozy PSG loops via the existing MML → NDP →
|
||||
`ndp_player` pipeline (`generate_mml.js` for AI-assisted MML). Diegetic
|
||||
jukebox upgrade lets the player pick the shop's track.
|
||||
- **Scope ladder:** (1) scene + one customer + brew + serve → (2) day cycle
|
||||
+ save + money → (3) dialogue engine + two regulars ← real milestone →
|
||||
(4) seasons/weather/palettes → (5) full cast, upgrades, endings. Every
|
||||
stage playable.
|
||||
|
||||
## 5. Moving to Claude Desktop / Claude Code
|
||||
|
||||
Jurjen asked about continuing the project in Claude Desktop with context
|
||||
files. Plan:
|
||||
|
||||
- Put a lean **CLAUDE.md** in the project root — Claude Code reads it at the
|
||||
start of every session. It holds build commands, toolchain quirks (SDCC,
|
||||
MSXgl paths, openMSX), conventions, and design pillars; kept under ~200
|
||||
lines, referencing deeper docs instead of duplicating them.
|
||||
- Full design lives in **docs/DESIGN.md**; this file (**CONVERSATION.md**)
|
||||
preserves the original discussion and rationale.
|
||||
- Claude Code's auto memory will additionally accumulate learned corrections
|
||||
(e.g. bank layout details) over time.
|
||||
- The dialogue compiler (`compile_dialogue.js`) will live in `tools/` next to
|
||||
the existing `generate_mml.js`.
|
||||
|
||||
## 6. Open threads (not yet designed)
|
||||
|
||||
- Dialogue script format spec + compiler implementation
|
||||
- Brew minigame detailed design
|
||||
- Palette / day-cycle system implementation details
|
||||
- Character roster finalization and story arcs
|
||||
- Bank layout plan for the ASCII16 MegaROM
|
||||
@@ -0,0 +1,175 @@
|
||||
# Kissaten Yūgure — Design document
|
||||
|
||||
Working title: **Kissaten Yūgure** ("Twilight Coffee Shop")
|
||||
Platform: MSX2 · Library: MSXgl (C) · ROM: ASCII16 MegaROM
|
||||
|
||||
> **Amendments.** This document still describes the game's intent and is the
|
||||
> place to start. A few specifics have since been decided differently — where
|
||||
> they conflict, the documents below win:
|
||||
>
|
||||
> - **Cast size: four, not six to eight** (§3). The four examples in §3 became
|
||||
> the entire roster. Rationale in `PLAN.md` §6; full arcs in `SCRIPT.md`.
|
||||
> - **Endings: one**, not several (§8 stage 5). `PLAN.md` §6.
|
||||
> - **Saving: a real save disk** (`.dsk`), not yet working — see the disk
|
||||
> section in `../CLAUDE.md`. Note the RP-5C01 CMOS holds only 6 bytes
|
||||
> through MSXgl, so it is not an alternative for a ~40-byte `SaveState`.
|
||||
> - **Music (§7) is out of date.** It describes a PSG / MML → NDP pipeline;
|
||||
> the working pipeline is `msx-music-generator` → lVGM + ayFX. Which chip
|
||||
> this game targets is still open — `PLAN.md` §8 item 15.
|
||||
> - **The brew minigame is coffee-only.** Aki's cream soda is poured, not
|
||||
> brewed, so her visits skip it — `SCRIPT.md` §8.
|
||||
>
|
||||
> Build order and per-stage requirements live in `PLAN.md`, which supersedes
|
||||
> the scope ladder in §8 below with a finer eleven-milestone breakdown.
|
||||
|
||||
## 1. Concept
|
||||
|
||||
You inherit a small kissaten (coffee shop) in a fictional provincial Japanese
|
||||
town in 1987. A cozy, no-fail-state game about serving regulars, learning
|
||||
their stories, and watching the town and seasons change.
|
||||
|
||||
**Audience:** adult retro gamers with a love of Japanese art, computers, and
|
||||
late-80s Japan nostalgia. The MSX2 itself is part of the fantasy — the game
|
||||
should look like it came off an MSX magazine cover.
|
||||
|
||||
**Tone references:** A Short Hike (pace and warmth), Konami/Compile-era MSX2
|
||||
pixel art, Showa-era kissaten culture, gentle city-pop-adjacent PSG music.
|
||||
|
||||
**The cozy contract:** no fail states. You cannot go bankrupt. Money gates
|
||||
cosmetic and menu upgrades (better grinder, jazz records, a cat), not
|
||||
survival. Progression = unlocking regulars' stories and seasonal change.
|
||||
|
||||
## 2. Core loop
|
||||
|
||||
One in-game day ≈ 5–10 real minutes, in three phases:
|
||||
|
||||
1. **Morning (prep):** choose today's menu focus (coffee blend, toast set,
|
||||
curry), check the radio for weather (weather affects who visits), buy stock.
|
||||
2. **Open hours (the heart):** customers arrive one or two at a time. Take
|
||||
orders, brew/cook via a timing minigame, and — most importantly — talk.
|
||||
Regulars have multi-day story arcs told in short dialogue beats.
|
||||
3. **Evening (close):** count the till, journal entry summarizing the day, save.
|
||||
|
||||
**Brew minigame:** a siphon coffee brew with a "release at the right moment"
|
||||
mechanic. One-button friendly, thematic, satisfying to master. Quality result
|
||||
feeds into customer affinity slightly (never punishingly).
|
||||
|
||||
## 3. The regulars
|
||||
|
||||
Six to eight recurring characters; this is where the game lives. Examples:
|
||||
|
||||
- The retired stationmaster
|
||||
- A high-schooler studying for entrance exams
|
||||
- A manga artist missing deadlines
|
||||
- A widow who orders the same thing daily
|
||||
|
||||
Each has a story arc of ~12–20 short scenes, triggered by day count, season,
|
||||
weather, or what you serve them. Serving the *right* thing at the right moment
|
||||
advances arcs — the player learns preferences by paying attention, which
|
||||
mechanically rewards the "regulars at my shop" fantasy.
|
||||
|
||||
**Visitor logic per open-hours tick:** roll against a weighted table filtered
|
||||
by (season, weather, time-of-day, days-since-last-visit). Simple, tunable in
|
||||
a spreadsheet, and it naturally produces patterns players notice and love
|
||||
("the stationmaster always comes when it rains").
|
||||
|
||||
## 4. Screen layout — SCREEN 5 (256×212)
|
||||
|
||||
| Region | Height | Contents |
|
||||
|---|---|---|
|
||||
| Status bar | 16 px | Day + season · clock · money (¥) |
|
||||
| Shop scene | 132 px | Tile/bitmap background: window, shelves, radio. Door zone (customer entry), counter zone (16×16 layered customer sprites), siphon rig zone (brew minigame). |
|
||||
| Dialogue window | 64 px | 48×48 portrait left; 3 lines × 26 chars text with typewriter reveal; choice cursor on line 3 when needed. |
|
||||
|
||||
Deliberately static-heavy: only sprites move, so the MSX2's weak scrolling is
|
||||
sidestepped entirely. Status bar and dialogue window redraw rarely — only the
|
||||
scene needs per-frame attention. This is the single biggest scope-saver.
|
||||
|
||||
## 5. Hardware / MSXgl mapping
|
||||
|
||||
**Video.** SCREEN 5 (G4), 16 colors from 512.
|
||||
- VRAM page 0: visible shop background bitmap.
|
||||
- VRAM page 1: asset warehouse — customer sprite frames, portraits, UI tiles,
|
||||
blitted with VDP commands (HMMM); dialogue box open/close is HMMV rectangle
|
||||
fill + font rendering, never touching the scene.
|
||||
|
||||
**Seasonal palette trick.** Author the background once, designed around
|
||||
palette slots: sky-through-window colors in slots 8–11, wood/warm tones in
|
||||
4–7. Each season *and* time of day is then just a 32-byte palette table —
|
||||
morning spring light vs. rainy autumn dusk on the same bitmap, basically
|
||||
free. Optionally lerp between palettes across the in-game day for a slow
|
||||
ambient shift. This is the most atmospheric feature in the game.
|
||||
|
||||
**Sprites.** Sprite mode 2 (per-line colors on 16×16). Two layered sprites
|
||||
per customer (outline + fill) for the classic MSX2 look. Max two customers
|
||||
on screen plus player hands/steam effects — nowhere near the 8-per-line limit.
|
||||
|
||||
**Portraits.** 48×48 with three expressions per character (neutral, happy,
|
||||
troubled), copied from page 1 into the dialogue box. Portraits are where the
|
||||
pixel-art budget goes; they sell the characters.
|
||||
|
||||
**ROM.** ASCII16 MegaROM from day one — dialogue, portraits, and music banks
|
||||
will not fit in 32KB. MSXgl supports banked ROMs well.
|
||||
|
||||
## 6. Data model
|
||||
|
||||
```c
|
||||
typedef struct {
|
||||
u8 id;
|
||||
u8 arc_stage; // progress through their story
|
||||
u8 affinity; // 0-255, raised by right orders
|
||||
u8 last_visit_day;
|
||||
} Regular;
|
||||
|
||||
typedef struct {
|
||||
u16 day;
|
||||
u8 season; // derives palette set
|
||||
u8 weather; // affects visitor table
|
||||
u16 money;
|
||||
u8 unlocked_items; // bitmask: grinder, records, cat...
|
||||
Regular regulars[8];
|
||||
} SaveState; // ~40 bytes → trivial to save
|
||||
```
|
||||
|
||||
**Dialogue** is the biggest data mass. Scenes stored in a flat script format:
|
||||
|
||||
```
|
||||
(trigger conditions) → (portrait id, expression, text lines,
|
||||
optional choice, effects)
|
||||
```
|
||||
|
||||
Authored in YAML/JSON; a small Node.js compiler (`tools/compile_dialogue.js`)
|
||||
emits C arrays or a binary blob for a MegaROM bank. Budget: ~8 characters ×
|
||||
~15 scenes plus ambient lines.
|
||||
|
||||
## 7. Music
|
||||
|
||||
PSG via the MML → NDP compiler → `ndp_player` pipeline, with AI-assisted MML
|
||||
generation through `tools/generate_mml.js` (Anthropic API).
|
||||
|
||||
Needs: 6–8 short cozy loops rather than driving action tracks — morning,
|
||||
afternoon, evening, rain, plus one theme per major story beat.
|
||||
|
||||
**Diegetic jukebox:** the record-player upgrade lets the player choose the
|
||||
shop's background track — a feature and a home for all generated music in one.
|
||||
|
||||
## 8. Scope ladder
|
||||
|
||||
Build in this order so every stage is a playable game:
|
||||
|
||||
1. Shop scene + one customer + brew minigame + serve loop, no story
|
||||
2. Day/night + save + money
|
||||
3. Dialogue engine + two regulars with short arcs ← **the real milestone**
|
||||
4. Seasons/weather/palettes
|
||||
5. Remaining cast, upgrades, endings
|
||||
|
||||
If serving the exam student his usual and getting one new line of his story
|
||||
feels good at stage 3, the game works.
|
||||
|
||||
## 9. Other principles
|
||||
|
||||
- Lean hard into palette work — the MSX2's superpower.
|
||||
- Keep text minimal or bilingual-friendly; the Japanese retro community is a
|
||||
big chunk of the real audience.
|
||||
- Let the soundtrack carry the mood — cozy games live or die on music.
|
||||
- Marketing hook: "run a coffee shop on real MSX2 hardware."
|
||||
@@ -0,0 +1,559 @@
|
||||
# Kissaten Yūgure — Production plan
|
||||
|
||||
Companion to `DESIGN.md` (what the game is) and `CONVERSATION.md` (why).
|
||||
This document is **how it gets built**: milestone order, the cast, the story
|
||||
architecture, and what has been deliberately cut.
|
||||
|
||||
Status at time of writing: **M1 complete** (scope ladder stage 1).
|
||||
|
||||
---
|
||||
|
||||
## 1. Organizing principle
|
||||
|
||||
The code in this project is small. Stage 1 — shop scene, customer, brew
|
||||
minigame, full serve loop — took one sitting and fits in 17KB of a 128KB ROM.
|
||||
Every remaining *system* is comparably small.
|
||||
|
||||
The risk is content. Four characters with real arcs is roughly 60 scenes of
|
||||
writing and 12 portraits of pixel art. The failure mode for a project like
|
||||
this is producing all of that before discovering the core moment doesn't land.
|
||||
|
||||
So the plan is ordered by one rule:
|
||||
|
||||
> **Reach the emotional test on the least content possible, then build the
|
||||
> machinery around what you learned.**
|
||||
|
||||
`DESIGN.md` §8 states the test directly: *if serving the exam student his
|
||||
usual and getting one new line of his story feels good, the game works.*
|
||||
Everything before M3 exists only to make that test possible. Everything after
|
||||
M3 is scaling something already proven.
|
||||
|
||||
---
|
||||
|
||||
## 2. Milestones
|
||||
|
||||
Each milestone has an exit criterion. Don't advance without meeting it.
|
||||
|
||||
Each also lists **what it requires** — split into what I need *from you*
|
||||
(decisions, writing, art) and what must be *in place* technically. Anything
|
||||
under "from you" is a hard block: I can't guess my way past it, and guessing
|
||||
wrong is expensive to unwind later.
|
||||
|
||||
### M1 — Serve loop ✅ *(complete)*
|
||||
|
||||
Shop scene, one customer, siphon brew minigame, serve loop, no story.
|
||||
|
||||
**Exit:** ✅ A customer arrives, orders, is served a brew of variable quality,
|
||||
reacts, and leaves; the counter increments and the next arrives.
|
||||
|
||||
### M2 — The day spine
|
||||
|
||||
The thin half of scope-ladder stage 2. Day counter, three phase transitions
|
||||
(morning prep → open hours → evening close), save/restore, clock and day in
|
||||
the status bar.
|
||||
|
||||
Money is deliberately **not** built here beyond a displayed number. It gates
|
||||
nothing until M9, and a value that gates nothing isn't worth debugging yet.
|
||||
|
||||
This milestone exists because the day counter is the spine every dialogue
|
||||
trigger hangs from — arc pacing, `last_visit_day`, "he always comes when it
|
||||
rains" patterns.
|
||||
|
||||
**Requires — from you:**
|
||||
- **Save medium.** My recommendation: **RTC CMOS**. Every MSX2 has it, it
|
||||
holds ~50 bytes, the `SaveState` in `DESIGN.md` §6 is ~40, and
|
||||
`msxgl_config.h` already enables `RTC_USE_SAVEDATA` + `RTC_USE_SAVESIGNED`.
|
||||
Alternatives are cartridge SRAM (needs mapper support, better capacity) or
|
||||
the FM-PAC's SRAM (needs the cartridge present). Say the word if you'd
|
||||
rather not depend on CMOS.
|
||||
- **Day length.** `DESIGN.md` says 5–10 real minutes. I need one number to
|
||||
tune against, plus a rough customers-per-day count (I'd start at 4–6).
|
||||
- **Clock model:** does time advance in real seconds, or one tick per customer
|
||||
served? Event-driven is more forgiving of a player who walks away — which
|
||||
suits the cozy contract — and it's what I'd pick.
|
||||
|
||||
**Requires — in place:** nothing beyond M1.
|
||||
|
||||
**Produces:** `SaveState` struct, phase state machine, save/load module.
|
||||
|
||||
**Status: ✅ complete.** Day counter, three phases, journal line, `SaveState`
|
||||
and disk persistence all working. Verified by playing a day, cold-booting, and
|
||||
resuming at day 2 with the served count intact.
|
||||
|
||||
**Pacing dial, revisited at the end.** `CUSTOMERS_PER_DAY` in `kissaten.c` is
|
||||
the only number that sets day length. Worth reconsidering at **M10** as a
|
||||
player-facing choice — the slot screen is already a boot-time front-end, so
|
||||
"how long should a day be?" has a natural home there, asked once when a new
|
||||
shop is started. A game with no fail states can afford to let the player set
|
||||
its own tempo, and it costs one saved byte.
|
||||
Not worth building before the content exists: the right default only becomes
|
||||
obvious once days have stories in them.
|
||||
|
||||
### M3 — Vertical slice ← **the milestone that matters**
|
||||
|
||||
One regular. Six beats. **Hardcoded in C.** No YAML, no compiler, no engine,
|
||||
no data format.
|
||||
|
||||
Build the exam student (§3 below) because their arc is the most legible: the
|
||||
"usual" is visually distinct (cream soda, not coffee), the want is stated
|
||||
early, and the change is a single order switch the player can *see*.
|
||||
|
||||
Also needed: order recognition — the customer asks for something specific, and
|
||||
serving it (vs. not) advances or holds the arc.
|
||||
|
||||
**Requires — from you:**
|
||||
- **Aki's six beats, as written text.** 6 × 3 lines × 26 chars. This is the
|
||||
hard block on M3 — there is no version of this milestone without it. Either
|
||||
you write them, or you tell me to draft them and review. If I draft: I need
|
||||
a tone sample you like (a scene from a game or book that hits the register
|
||||
you want) so the first pass isn't a guess.
|
||||
- **The item list at this point.** Minimum coffee + cream soda, but tell me if
|
||||
the toast set or curry from `DESIGN.md` §2 should exist yet.
|
||||
- **A scratch portrait for Aki — 48×48, three expressions.** Crude is fine;
|
||||
ugly is fine. But M3's exit criterion is an *emotional* judgement, and
|
||||
judging it with a blank brown rectangle where a face belongs stacks the deck
|
||||
against the test. This is the one place art work moves earlier than M6, and
|
||||
it's worth it.
|
||||
|
||||
**Requires — in place:** M2's day counter (arc beats are paced by day).
|
||||
|
||||
**Produces:** hardcoded arc, order-recognition logic, "the usual" concept.
|
||||
|
||||
**Exit:** The `DESIGN.md` test. Serve the student their usual, get the next
|
||||
beat of their story, and want to come back tomorrow to see the following one.
|
||||
If this is flat, stop and fix the *writing*, not the code.
|
||||
|
||||
### M4 — Dialogue engine and compiler
|
||||
|
||||
Now — and only now — extract the engine from what M3 taught. Scene data model,
|
||||
trigger evaluation, `tools/compile_dialogue.js` emitting a binary bank, and
|
||||
`BankedCall = true` re-enabled (see §7 hazards).
|
||||
|
||||
Port the student's hardcoded arc to data and prove it plays identically.
|
||||
|
||||
**Requires — from you:**
|
||||
- **Sign-off on the scene schema before I write the compiler.** I'll propose
|
||||
the YAML shape as a one-page sample; reviewing it costs ten minutes and
|
||||
changing it after 60 scenes are authored costs a rewrite.
|
||||
- **The string-ID decision** from §4 — whether to route text through IDs now
|
||||
for a possible Japanese pass later. Cheap today, expensive to retrofit.
|
||||
|
||||
**Requires — in place:**
|
||||
- M3 proven (the schema should be derived from real content, not imagined).
|
||||
- `node` on PATH for the compiler — already working, documented in
|
||||
`../CLAUDE.md`.
|
||||
- `BankedCall = true` re-enabled, carefully. See §7.
|
||||
|
||||
**Produces:** `tools/compile_dialogue.js`, `data/dialogue/*.yaml`, the banked
|
||||
dialogue blob, and the bank layout that everything after M4 slots into.
|
||||
|
||||
**Exit:** Adding a scene requires editing a YAML file and rebuilding. Zero C
|
||||
changes.
|
||||
|
||||
### M5 — Second regular and visitor logic
|
||||
|
||||
Add the stationmaster. Build the weighted arrival table from `DESIGN.md` §3 —
|
||||
roll per open-hours tick, filtered by season, weather, time-of-day, and
|
||||
days-since-last-visit.
|
||||
|
||||
**Requires — from you:**
|
||||
- **Ōta's full arc** (~15 beats). Same authoring question as M3 — yours or
|
||||
mine to draft.
|
||||
- **Initial arrival weights**, or approval of a table I propose.
|
||||
`DESIGN.md` §3 wants this tunable in a spreadsheet; I'd rather hand you a
|
||||
starting table to react to than ask you to invent numbers cold.
|
||||
- **How visible the pattern should be.** "The stationmaster always comes when
|
||||
it rains" only lands if it's *nearly* deterministic. My instinct is to make
|
||||
weather-driven arrivals much stronger than feels statistically tasteful,
|
||||
because the player needs to notice.
|
||||
|
||||
**Requires — in place:** M4 engine and compiler.
|
||||
|
||||
**Produces:** visitor weight table, arrival roll, multi-arc scheduling.
|
||||
|
||||
**Exit:** Two arcs interleave over a week of play without colliding, and the
|
||||
arrival pattern is legible enough that you can predict who's coming.
|
||||
|
||||
### M6 — Art pass
|
||||
|
||||
The real background bitmap on the palette-slot layout already reserved in
|
||||
code (sky 8–11, wood/warm 4–7), plus 12 portraits (4 characters × 3
|
||||
expressions). Retire the placeholder `HMMV` rectangles.
|
||||
|
||||
**Requires — from you:** generated in **PixelLab** from the prompts in
|
||||
`ART.md` — one 256×212 background and 12 portraits (48×48, three expressions
|
||||
× four regulars), returned as PNGs in `art/`.
|
||||
|
||||
The palette spec and the sky/wood slot rule are written up in `ART.md` §1,
|
||||
with machine- and human-readable references at `art/palette.png` and
|
||||
`art/palette_ref.png`. **That rule is the whole of M7 riding on one
|
||||
constraint**, and a generator will not respect it unprompted.
|
||||
|
||||
**Requires — in place:**
|
||||
- A PNG → SC5 conversion path. `projects/mazegame` already has working
|
||||
`convert_screens.py` / `convert_tiles.py` precedent to adapt, plus MSXtk.
|
||||
|
||||
**Produces:** converted asset banks, page-1 warehouse layout, blit routines.
|
||||
|
||||
**Exit:** No procedural placeholder fills remain in the shop scene.
|
||||
|
||||
### M7 — Seasons, weather, palettes
|
||||
|
||||
Scope-ladder stage 4. Palette tables per season × time-of-day, optional lerp
|
||||
across the in-game day, weather affecting the arrival table.
|
||||
|
||||
Deliberately placed *after* the art pass and *after* two working arcs. See §7.
|
||||
|
||||
**Requires — from you:**
|
||||
- **How many palette sets.** 4 seasons × 3 times of day = 12 tables at 32
|
||||
bytes each (384 bytes — trivial). But that's 12 moods to *art-direct*, which
|
||||
is the real cost. Fewer, done well, beats twelve done mechanically.
|
||||
- **Mood direction** for each: I can propose the RGB tables, but "rainy
|
||||
autumn dusk" needs your eye to confirm it feels right, not mine.
|
||||
|
||||
**Requires — in place:** **M6 must be done.** This milestone is a no-op
|
||||
without a background authored on the palette-slot layout — that dependency is
|
||||
the entire reason M7 sits after the art pass instead of before it.
|
||||
|
||||
**Produces:** palette tables, time-of-day lerp, weather → arrival hookup.
|
||||
|
||||
**Exit:** A spring morning and a rainy autumn dusk are visibly different moods
|
||||
on identical bitmap data.
|
||||
|
||||
### M8 — Remaining cast
|
||||
|
||||
The manga artist and the widow, full arcs. This is the largest pure-writing
|
||||
block in the project — roughly 30 scenes.
|
||||
|
||||
**Requires — from you:**
|
||||
- **Fujimoto's and Nakajima's arcs** — ~30 beats total, the single largest
|
||||
writing block in the project.
|
||||
- **A ruling on Nakajima's reveal.** Her second coffee is the best hook in the
|
||||
cast precisely because the player solves it unaided. I need to know how far
|
||||
you're willing to go without confirming it — my instinct is *very* far, and
|
||||
that it should never be stated outright by anyone but her.
|
||||
|
||||
**Requires — in place:** M4 engine, M6 portraits.
|
||||
|
||||
**Exit:** All four arcs complete and reachable in one playthrough.
|
||||
|
||||
### M9 — Music and upgrades
|
||||
|
||||
6–8 cozy loops via the existing `msx-music-generator` pipeline. The
|
||||
record-player upgrade turns the jukebox into both a feature and a home for
|
||||
every generated track. Money finally gates something.
|
||||
|
||||
**Requires — from you:**
|
||||
- **Which sound chip.** This needs settling, because the docs and your actual
|
||||
toolchain disagree: `DESIGN.md` §7 and `CLAUDE.md` describe a PSG / MML →
|
||||
NDP pipeline, but the working pipeline you built for `mazegame` is
|
||||
`msx-music-generator` → **lVGM + ayFX**, using MSX-Music (YM2413) on an
|
||||
MSX2+. This project targets plain MSX2, where FM is *not* standard — it
|
||||
needs an FM-PAC. Options: PSG-only (universal, thinner), FM with PSG
|
||||
fallback (best sound, more work), or retarget to MSX2+. I'd take **PSG-only
|
||||
through the lVGM pipeline you already have**, and treat FM as a bonus path.
|
||||
Either way `DESIGN.md` §7 should be updated to match reality.
|
||||
- **Briefs for 6–8 tracks:** mood, rough tempo, loop length. Morning,
|
||||
afternoon, evening, rain, plus a theme or two for story beats.
|
||||
- **Upgrade list and prices** — the point at which money finally means
|
||||
something.
|
||||
|
||||
**Requires — in place:** money economy from M2 promoted to actually gating.
|
||||
|
||||
**Exit:** Music changes with time-of-day and weather; the player can choose a
|
||||
record.
|
||||
|
||||
### M10 — Save slots (multi-file)
|
||||
|
||||
Several shops on one disk. `tool/disk_save` is already built for this: every
|
||||
call takes an `entry` index, so slots become `KISSAT00.SAV`, `KISSAT01.SAV`
|
||||
and so on with no change to the save format. `DiskSave_Check(entry)` reports
|
||||
each slot's state, `DiskSave_GetFreeEntries()` counts the free ones, and
|
||||
`DiskSave_Delete(entry)` removes one. **The storage side is nearly free.**
|
||||
|
||||
The actual work is front-end: a slot screen at boot showing what's in each
|
||||
one, and a confirm step before overwriting or deleting. That is also why this
|
||||
milestone sits late — it touches the boot flow, and it is much easier to
|
||||
design once there is real save content to display.
|
||||
|
||||
Worth framing in-fiction rather than as a file manager. A slot is not "Save
|
||||
1", it is a shop with days behind it — *"Day 34 · 210 cups"* tells the player
|
||||
which one is theirs better than a filename does.
|
||||
|
||||
**Requires — from you — all deferred to M10 (§8 items 16–20):** how many
|
||||
slots; whether they are named; whether a slot presents as a shop or a save
|
||||
file; what guards deletion; and whether the day-length dial surfaces here as a
|
||||
player-facing choice. Recommendations are recorded in the decision queue, but
|
||||
none of these should be settled before the screen exists to judge them
|
||||
against — they are cheap to decide late and awkward to unpick if fixed early.
|
||||
|
||||
**Requires — in place:** M2's save layer (done). Nothing else technically —
|
||||
this could be built any time, and is late only because the design benefits
|
||||
from real content.
|
||||
|
||||
**Produces:** slot selection screen, per-slot summary, delete with confirm,
|
||||
`SAVE_ENTRY` becoming a runtime value rather than the `#define` it is now.
|
||||
|
||||
**Exit:** Three shops can be run in parallel from one disk, each resuming to
|
||||
its own day and cast state, and no single keypress can destroy one.
|
||||
|
||||
### M11 — Ending, polish, hardware
|
||||
|
||||
One quiet ending (see §6). Real-hardware verification, 50/60Hz check, timing
|
||||
pass on the brew minigame.
|
||||
|
||||
**Requires — from you:**
|
||||
- **The ending text**, and what triggers it — my recommendation is a day count
|
||||
reached *after* all four arcs resolve, so it can never cut a story short.
|
||||
- **Real hardware, or the machine profiles you care about.** I can only verify
|
||||
against openMSX here; C-BIOS has already shown behavioural differences from
|
||||
real BIOS during M1, so emulator-passing is not hardware-passing.
|
||||
- **50Hz or 60Hz as the primary target** (PAL vs NTSC timing for the brew
|
||||
minigame's feel).
|
||||
|
||||
---
|
||||
|
||||
## 3. The cast
|
||||
|
||||
`DESIGN.md` §3 suggests six to eight regulars and offers four examples. **Take
|
||||
the four examples as the entire cast.** Reasoning in §6.
|
||||
|
||||
Each has a **want**, a **secret**, and a **change**. The want is stated early.
|
||||
The secret is never announced — it's inferred from behaviour, then eventually
|
||||
confirmed in one quiet line. The change is small and late.
|
||||
|
||||
### Hoshino Aki — the exam student
|
||||
|
||||
- **Usual:** cream soda float. A child's order they're faintly embarrassed by.
|
||||
- **Rhythm:** weekday evenings, then scarcer as exams approach.
|
||||
- **Want:** to pass the Tokyo entrance exams.
|
||||
- **Secret:** the course is their parent's choice. They want to study
|
||||
something else and haven't said so to anyone.
|
||||
- **Change:** orders coffee instead — once, without comment. The player will
|
||||
notice before they understand it.
|
||||
- **Why first:** the arc is legible, the usual is visually distinct from every
|
||||
other order, and the change is expressible entirely through the serve
|
||||
mechanic.
|
||||
|
||||
### Ōta-san — the retired stationmaster
|
||||
|
||||
- **Usual:** black coffee, no sugar. Arrives at the same minute daily.
|
||||
- **Rhythm:** early hours; rain makes him certain to appear.
|
||||
- **Want:** to have somewhere to be at a fixed time.
|
||||
- **Secret:** the line he worked was cut back before he retired. The precision
|
||||
he still keeps is for a timetable that no longer exists.
|
||||
- **Change:** stops apologising for lingering.
|
||||
|
||||
### Fujimoto — the manga artist
|
||||
|
||||
- **Usual:** strongest coffee available, endless refills, toast set when
|
||||
reminded to eat.
|
||||
- **Rhythm:** very late; a monthly deadline cycle drives their frequency and
|
||||
their panic.
|
||||
- **Want:** to finish the chapter.
|
||||
- **Secret:** the series is ending, and they come here to be somewhere that
|
||||
isn't the desk.
|
||||
- **Change:** the shop appears in the manga. They show you the page.
|
||||
|
||||
### Nakajima-san — the widow
|
||||
|
||||
- **Usual:** two coffees. Always two.
|
||||
- **Rhythm:** slow, seasonal, tied to specific weather and dates.
|
||||
- **Want:** to keep a routine that belonged to two people.
|
||||
- **Secret:** the second coffee is his order, and it goes cold every time.
|
||||
- **Change:** one day she orders one. No speech about it.
|
||||
- **Note:** her hook is the strongest in the cast because it's **visible in
|
||||
the serve mechanic before it is ever explained**. The player solves it
|
||||
themselves. Protect that — do not have anyone explain her early.
|
||||
|
||||
---
|
||||
|
||||
## 4. Story architecture
|
||||
|
||||
### Arc shape
|
||||
|
||||
Twelve to eighteen beats per character. A beat is three lines of 26
|
||||
characters — a *moment*, not a scene.
|
||||
|
||||
| Beats | Function |
|
||||
|---|---|
|
||||
| 1–3 | Establish the routine. Player learns the usual. |
|
||||
| 4–8 | A crack. Mentioned in passing, never explained. |
|
||||
| 9–14 | It develops. Serving choices nudge; they never gate. |
|
||||
| 15+ | Resolution — quiet, undramatic, small. |
|
||||
|
||||
Cozy resolves **gently**. No reveals, no tragedy delivered as a twist. Ōta
|
||||
doesn't confess a catastrophe; he admits the house is too quiet now. Restraint
|
||||
is the genre, and it's also cheaper to write well than melodrama is.
|
||||
|
||||
### Authoring order
|
||||
|
||||
Write **one arc completely** before starting the next. Writing everyone's
|
||||
first three beats produces four strangers and no one you know.
|
||||
|
||||
### Trigger vocabulary
|
||||
|
||||
The scene format is `(conditions) → (portrait, expression, text, effects)`.
|
||||
The condition language is the real design work — keep it minimal:
|
||||
|
||||
```
|
||||
day >= N season == S
|
||||
arc_stage == N weather == W
|
||||
affinity >= N phase == P
|
||||
served == ITEM absent >= N days
|
||||
```
|
||||
|
||||
Eight condition types cover every behaviour described in `DESIGN.md`.
|
||||
**Resist adding a ninth.** Every addition multiplies the authoring surface and
|
||||
the testing burden, and the temptation will be strongest exactly when the
|
||||
writing is hardest.
|
||||
|
||||
### Effects
|
||||
|
||||
Scenes may raise affinity, advance `arc_stage`, set a flag, or unlock an item.
|
||||
Nothing else. No arbitrary state mutation — that path ends in a scripting
|
||||
language nobody asked for.
|
||||
|
||||
### Text and localisation
|
||||
|
||||
Current font is ASCII at 26 characters per line. `DESIGN.md` §9 flags the
|
||||
Japanese retro community as a real slice of the audience.
|
||||
|
||||
**Recommendation:** don't build kana support now, but route every player-facing
|
||||
string through an ID from the start. A Japanese pass then becomes a font and a
|
||||
table swap rather than re-authoring the entire script. This costs almost
|
||||
nothing today and is expensive to retrofit.
|
||||
|
||||
---
|
||||
|
||||
## 5. Budgets
|
||||
|
||||
### ROM — not a constraint
|
||||
|
||||
| Item | Size |
|
||||
|---|---|
|
||||
| Stage 1 code | ~17 KB |
|
||||
| All dialogue text (~8,000 chars) | ~8 KB |
|
||||
| Portraits (4 × 3 × 48×48 @ 4bpp) | ~14 KB |
|
||||
| Background bitmap (256×212 @ 4bpp) | ~27 KB |
|
||||
| Music (6–8 lVGM loops) | ~20 KB |
|
||||
|
||||
Comfortably inside 128 KB with room for a second background or seasonal
|
||||
variants if they ever prove necessary. **ROM size will not be what limits this
|
||||
project.**
|
||||
|
||||
### Writing — the actual constraint
|
||||
|
||||
Four characters × ~15 beats = **~60 scenes**. At three beats per sitting that
|
||||
is twenty writing sessions. This is the single largest line item in the
|
||||
project and it does not compress.
|
||||
|
||||
**Status: a complete first draft exists** in `SCRIPT.md` — all 60 beats, plus
|
||||
order lines, per-character brew reactions and ambient lines, every line
|
||||
checked against the 26-character box. What remains is your edit pass, which is
|
||||
a different and much smaller job than writing from nothing.
|
||||
|
||||
### Art — the long pole
|
||||
|
||||
12 portraits and one background. Tractable at four characters; at eight it
|
||||
roughly doubles and becomes the thing that stalls the project.
|
||||
|
||||
**Open question:** who draws these? The plan assumes 12 portraits exist by M6.
|
||||
If that's commissioned or AI-assisted work, it needs starting well before M6,
|
||||
since it's the only item here with external lead time.
|
||||
|
||||
---
|
||||
|
||||
## 6. Deliberate cuts
|
||||
|
||||
| `DESIGN.md` says | Plan says | Why |
|
||||
|---|---|---|
|
||||
| 6–8 regulars | **4** | 8 × 15 scenes and 24 portraits is where this project dies. Four in a small provincial kissaten is also *more* intimate — the cut serves the atmosphere pillar rather than fighting it. |
|
||||
| Money economy | Minimal until M9 | Gates nothing before the record player. |
|
||||
| "Endings" (plural) | **One** quiet ending | Per-character arc completions already provide the sense of closure. Multiple endings multiply testing for a game with no fail state to contrast against. |
|
||||
| Morning menu planning | Deferred, possibly cut | Adds a decision phase before the loop that carries the game. Revisit only if open hours feel thin. |
|
||||
| Branching dialogue choices | Defer to M4 | M3 will reveal whether they're needed at all. My expectation: rarely. |
|
||||
|
||||
"Small, finishable scope. When in doubt, cut." — `CLAUDE.md`, design pillars.
|
||||
|
||||
---
|
||||
|
||||
## 7. Risks and known hazards
|
||||
|
||||
**Seasons are procrastination.** M7 is the most enjoyable thing on this list —
|
||||
palette work produces beautiful results in minutes with no writing involved.
|
||||
It will call loudly every time the script gets difficult. It also adds nothing
|
||||
to whether the game is *good*. Keep it as the reward after two arcs work.
|
||||
|
||||
**Engine-before-content.** The reason M3 is hardcoded. Dialogue systems get
|
||||
over-built when designed before any dialogue exists; you end up supporting
|
||||
features nothing uses and discovering the one thing you need is awkward.
|
||||
|
||||
**Cast creep.** Four will feel thin around M5, when two arcs exist and the
|
||||
shop seems empty. It won't feel thin at M8. Do not add a fifth regular before
|
||||
all four are complete.
|
||||
|
||||
**`BankedCall = true` is a known hazard.** Enabling it with nothing actually
|
||||
banked corrupted RAM globals — the state machine ran wild. It's off, and M4 is
|
||||
the deliberate point to turn it back on, with the banked data that justifies
|
||||
it. See the platform gotchas in `../CLAUDE.md`.
|
||||
|
||||
**Keyboard reads need interrupt protection.** Documented in `../CLAUDE.md`;
|
||||
applies to every new input added.
|
||||
|
||||
---
|
||||
|
||||
## 8. Decision queue
|
||||
|
||||
Everything the milestones above need from you, in the order it becomes
|
||||
blocking. Items marked **lead time** should be started well before the
|
||||
milestone that consumes them; items marked **defer** are parked on purpose —
|
||||
captured so the reasoning survives, but not to be decided until their
|
||||
milestone arrives.
|
||||
|
||||
| # | Needed for | Decision | My recommendation |
|
||||
|---|---|---|---|
|
||||
| 1 | M2 | ~~Save medium~~ → **save disk (.dsk)** | ✅ working, via MSXgl's `tool/disk_save` module. Saves `KISSAT00.SAV` to drive A. Four non-obvious requirements — see the disk section in `../CLAUDE.md` |
|
||||
| 2 | M2 | ~~Day length~~ → **5 min / 5 customers** | ✅ done. One constant, `CUSTOMERS_PER_DAY` in `kissaten.c` |
|
||||
| 3 | M2 | ~~Clock model~~ → **event-driven** | ✅ done. Customers are the clock |
|
||||
| 4 | M3 | ~~Who writes the dialogue~~ → **drafted by me, you edit** | ✅ resolved |
|
||||
| 5 | M3 | ~~Aki's six beats~~ | ✅ drafted — all four arcs are in `SCRIPT.md`, awaiting your edit |
|
||||
| 6 | M3 | Scratch portrait for Aki | Crude is fine, but *something* — the test needs a face |
|
||||
| 7 | M3 | Item list at slice stage | Coffee + cream soda only |
|
||||
| 8 | M6 | ~~Who makes the art~~ → **PixelLab, from my prompts** | ✅ resolved. Prompts, palette spec and return format in `ART.md`; palette reference images in `art/` |
|
||||
| 9 | M4 | Scene schema sign-off | Ten-minute review, saves a rewrite |
|
||||
| 10 | M4 | String IDs for future JP text | Yes — nearly free now, expensive later |
|
||||
| 11 | M5 | Arrival weights | React to a table I propose |
|
||||
| 12 | M6 | Palette spec to artist **before** drawing | Non-negotiable if M7 is to stay cheap |
|
||||
| 13 | M7 | Number of palette sets | Fewer, art-directed well |
|
||||
| 14 | M8 | How overt Nakajima's reveal gets | Never stated by anyone but her |
|
||||
| 15 | M9 | Sound chip: PSG / FM / retarget | PSG-only via your existing lVGM pipeline |
|
||||
| 16 | M10 · **defer** | How many save slots | 3 — the limit is screen space, not disk room |
|
||||
| 17 | M10 · **defer** | Whether slots are named | Skip naming. Text entry on a machine with no line editor is real work; "Day 34 · 210 cups" identifies a shop better than a filename anyway |
|
||||
| 18 | M10 · **defer** | Slot presentation: shops, or save files | Shops. A slot is somewhere with days behind it, not a numbered file |
|
||||
| 19 | M10 · **defer** | Deletion guard | Two-step confirm. This is the only unrecoverable action in a game with no fail states — the cozy contract applies to the save screen too |
|
||||
| 20 | M10 · **defer** | Day length as a player-facing choice | Ask once when a new shop is started, on the slot screen. One saved byte |
|
||||
| 21 | M11 | Hardware access + 50/60Hz target | — |
|
||||
|
||||
**Deferred items (16–20)** are recorded so the thinking isn't lost, but they
|
||||
are deliberately *not* being decided now. They only bite at M10, and every one
|
||||
of them is easier to judge with real save content on screen than in the
|
||||
abstract. Don't let them pull scope forward.
|
||||
|
||||
With 8 resolved, nothing on the live list is externally blocked — the
|
||||
remaining items are all things I can propose and you can react to.
|
||||
|
||||
## 9. Immediate next actions
|
||||
|
||||
1. ✅ **M2 day spine** — day counter, three phases, journal line. Done and
|
||||
playable. **Persistence still blocked**; see the disk section in
|
||||
`../CLAUDE.md` for everything established so far.
|
||||
2. ✅ **Aki's beats as prose** — done, along with the other three arcs, in
|
||||
`SCRIPT.md`. Awaiting your edit pass.
|
||||
3. ⬜ **M3 vertical slice** — Aki's first six beats, hardcoded, with a scratch
|
||||
portrait. The next real milestone, and the one that decides whether the
|
||||
game works (§2, M3).
|
||||
4. ⬜ **Generate Aki's three portraits** from the prompts in `ART.md`, so M3
|
||||
can be judged against a real face rather than a brown rectangle.
|
||||
|
||||
3 and 4 are independent, and 4 unblocks the honest version of 3.
|
||||
@@ -0,0 +1,492 @@
|
||||
# Kissaten Yūgure — Script
|
||||
|
||||
First draft of all four character arcs, plus order lines, brew reactions and
|
||||
ambient lines. Written as prose-first per `PLAN.md` §9 — no data format yet.
|
||||
|
||||
**This is a draft to edit, not to approve.** The characters are yours; if
|
||||
anyone's voice is wrong, it's wrong now and cheap to fix.
|
||||
|
||||
---
|
||||
|
||||
## How to read this
|
||||
|
||||
Every beat is one dialogue box: **3 lines × 26 characters**, ASCII, as laid
|
||||
out in `DESIGN.md` §4. Every line here has been checked against that limit.
|
||||
|
||||
```
|
||||
**B4 · the crack** — `day>=7` — troubled
|
||||
Mock exam results came.
|
||||
Law faculty. Tokyo.
|
||||
Father framed the sheet.
|
||||
```
|
||||
|
||||
- **B4** — beat number. Beats fire in order; a beat's trigger is *also*
|
||||
gated on the previous beat having played (`arc_stage`).
|
||||
- **Trigger** — conditions from the vocabulary in `PLAN.md` §4.
|
||||
- **Expression** — `neutral` / `happy` / `troubled`. Three per character, per
|
||||
`DESIGN.md` §5.
|
||||
|
||||
Triggers are deliberately loose. Tighten them once pacing is playable —
|
||||
day numbers here assume roughly one visit per character per 2 days.
|
||||
|
||||
---
|
||||
|
||||
## 1. Hoshino Aki — the exam student
|
||||
|
||||
> Cream soda. Weekday evenings, scarcer as exams approach.
|
||||
> **Want:** pass the Tokyo entrance exams.
|
||||
> **Secret:** the course is her father's choice. She wants astronomy, at a
|
||||
> small college in Sendai with an observatory on the roof.
|
||||
> **Change:** orders coffee instead of the soda.
|
||||
|
||||
The dusk sky through the shop window is her arc's spine — she is the reason
|
||||
that window is there. **Beats 1–6 are the M3 vertical slice.**
|
||||
|
||||
**B1** — `day>=2, phase=evening` — neutral
|
||||
Cream soda, please.
|
||||
The big one, if that's
|
||||
all right.
|
||||
|
||||
**B2** — `day>=3` — neutral
|
||||
Exams in the spring.
|
||||
They say third year goes
|
||||
fast. It hasn't.
|
||||
|
||||
**B3** — `day>=5, served=CREAM_SODA` — happy
|
||||
You remembered.
|
||||
Nobody at home remembers
|
||||
what I like.
|
||||
|
||||
**B4 · the crack** — `day>=7` — troubled
|
||||
Mock exam results came.
|
||||
Law faculty. Tokyo.
|
||||
Father framed the sheet.
|
||||
|
||||
**B5** — `day>=9, weather=rain` — neutral
|
||||
Can't see the sky today.
|
||||
...Sorry. That was a
|
||||
strange thing to say.
|
||||
|
||||
**B6 · slice ends** — `day>=11, served=CREAM_SODA` — neutral
|
||||
Master, do you ever look
|
||||
out that window and think
|
||||
about anything else?
|
||||
|
||||
**B7** — `day>=13` — troubled
|
||||
Father's friend teaches
|
||||
at the Tokyo faculty.
|
||||
It's arranged, basically.
|
||||
|
||||
**B8** — `day>=15, absent>=3` — troubled
|
||||
Sorry I haven't come.
|
||||
Cram school added hours.
|
||||
I missed this place.
|
||||
|
||||
**B9** — `day>=17, affinity>=60` — neutral
|
||||
There's a small college
|
||||
in Sendai. They have an
|
||||
observatory on the roof.
|
||||
|
||||
**B10** — `day>=19` — happy
|
||||
I wrote for a prospectus.
|
||||
It came in a brown
|
||||
envelope. I hid it.
|
||||
|
||||
**B11** — `day>=21, weather=clear, phase=evening` — happy
|
||||
Look - that's Vega.
|
||||
You can see it even from
|
||||
town, if you know where.
|
||||
|
||||
**B12** — `day>=23` — troubled
|
||||
Applications close on
|
||||
the twentieth.
|
||||
I haven't told them.
|
||||
|
||||
**B13 · the change** — `day>=25, served=COFFEE` — neutral
|
||||
Not the soda today.
|
||||
Coffee. Black, like you
|
||||
make for Ota-san.
|
||||
|
||||
**B14** — `day>=27` — troubled
|
||||
I told them.
|
||||
Mother cried. Father
|
||||
hasn't spoken since.
|
||||
|
||||
**B15 · resolution** — `day>=30` — happy
|
||||
Sendai. I posted it.
|
||||
Father drove me to the
|
||||
post office. Said nothing.
|
||||
|
||||
---
|
||||
|
||||
## 2. Ōta-san — the retired stationmaster
|
||||
|
||||
> Black coffee, no sugar. Early mornings. Rain makes him certain.
|
||||
> **Want:** somewhere to be at a fixed time.
|
||||
> **Secret:** the ten-fifteen was cut in his last spring. His precision keeps
|
||||
> a timetable that no longer exists.
|
||||
> **Change:** stops apologising for lingering; orders a second cup.
|
||||
|
||||
**B1** — `day>=1, phase=morning` — neutral
|
||||
Coffee. Black.
|
||||
Seven forty. You open
|
||||
at seven forty.
|
||||
|
||||
**B2** — `day>=3, phase=morning` — neutral
|
||||
Your father opened at
|
||||
seven forty as well.
|
||||
I never asked him why.
|
||||
|
||||
**B3** — `day>=5, weather=rain` — neutral
|
||||
Rain. I always came in
|
||||
the rain. The platform
|
||||
had no roof at the end.
|
||||
|
||||
**B4** — `day>=7, served=COFFEE` — happy
|
||||
Thirty-one years I
|
||||
poured tea on that
|
||||
platform. Never coffee.
|
||||
|
||||
**B5 · the crack** — `day>=9` — troubled
|
||||
They cut the ten-fifteen
|
||||
in my last spring.
|
||||
Nobody came to say so.
|
||||
|
||||
**B6** — `day>=11` — neutral
|
||||
I still wake at five.
|
||||
The body keeps a
|
||||
timetable of its own.
|
||||
|
||||
**B7** — `day>=13, absent>=2` — troubled
|
||||
Forgive me. I'm keeping
|
||||
your counter. I'll go.
|
||||
...No. Not yet.
|
||||
|
||||
**B8** — `day>=15, affinity>=50` — neutral
|
||||
The house is not small.
|
||||
That is the trouble.
|
||||
It was sized for four.
|
||||
|
||||
**B9** — `day>=17` — neutral
|
||||
My daughter telephones
|
||||
on Sundays. Eleven a.m.
|
||||
She is very punctual.
|
||||
|
||||
**B10** — `day>=19, weather=rain` — happy
|
||||
You knew I'd come.
|
||||
The pot was already on.
|
||||
That is a fine thing.
|
||||
|
||||
**B11** — `day>=21` — neutral
|
||||
The station is a
|
||||
convenience store now.
|
||||
I have not gone in.
|
||||
|
||||
**B12** — `day>=23` — troubled
|
||||
I went in. For batteries.
|
||||
The ticket window is
|
||||
where the freezers are.
|
||||
|
||||
**B13** — `day>=25, affinity>=80` — neutral
|
||||
You keep good time,
|
||||
Master. That is not a
|
||||
small compliment from me.
|
||||
|
||||
**B14 · the change** — `day>=27` — happy
|
||||
I'll have a second cup.
|
||||
I am not going anywhere
|
||||
in particular today.
|
||||
|
||||
**B15 · resolution** — `day>=30` — happy
|
||||
Seven forty.
|
||||
Tomorrow also, I think.
|
||||
That is all I wanted.
|
||||
|
||||
---
|
||||
|
||||
## 3. Fujimoto — the manga artist
|
||||
|
||||
> Strongest coffee, endless refills, toast set when reminded to eat.
|
||||
> Very late. Frequency and panic follow a monthly deadline cycle.
|
||||
> **Want:** finish the chapter.
|
||||
> **Secret:** the series is being cancelled. Comes here to be anywhere that
|
||||
> isn't the desk.
|
||||
> **Change:** the shop appears in the final chapter.
|
||||
|
||||
Fujimoto carries the comedy. A cozy game with four sad people is not cozy —
|
||||
it's a wake. Let them be funny about their own misery.
|
||||
|
||||
**B1** — `day>=2, phase=evening` — neutral
|
||||
Strongest you have.
|
||||
No, stronger. I have
|
||||
eleven pages by Friday.
|
||||
|
||||
**B2** — `day>=4` — troubled
|
||||
Do you know how long
|
||||
eleven pages is?
|
||||
Neither do I anymore.
|
||||
|
||||
**B3** — `day>=6, served=COFFEE` — neutral
|
||||
Refill. And again after.
|
||||
I'll pay for the pot.
|
||||
Cheaper by the hour.
|
||||
|
||||
**B4** — `day>=8` — troubled
|
||||
Editor called me
|
||||
'reliable' today. That's
|
||||
what they say before.
|
||||
|
||||
**B5** — `day>=10, absent>=4` — troubled
|
||||
Four days at the desk.
|
||||
I have drawn one hand.
|
||||
It's a bad hand.
|
||||
|
||||
**B6 · the crack** — `day>=12` — troubled
|
||||
I don't come here to
|
||||
work, Master.
|
||||
I come here to not.
|
||||
|
||||
**B7** — `day>=14, served=TOAST` — happy
|
||||
When did I last eat?
|
||||
Don't answer that.
|
||||
...Thank you for this.
|
||||
|
||||
**B8** — `day>=16` — neutral
|
||||
Thirty-two volumes.
|
||||
Nine years. My whole
|
||||
twenties, in a drawer.
|
||||
|
||||
**B9 · the secret** — `day>=18, affinity>=50` — troubled
|
||||
They're ending it.
|
||||
Two more chapters.
|
||||
I asked for three.
|
||||
|
||||
**B10** — `day>=20` — troubled
|
||||
Nine years and I get
|
||||
two chapters to say
|
||||
goodbye properly.
|
||||
|
||||
**B11** — `day>=22` — neutral
|
||||
I've been drawing this
|
||||
counter. Not for work.
|
||||
Just drawing it.
|
||||
|
||||
**B12** — `day>=24, weather=rain` — neutral
|
||||
Rain's good for pages.
|
||||
Nobody expects you
|
||||
anywhere in the rain.
|
||||
|
||||
**B13 · the change** — `day>=26, affinity>=70` — happy
|
||||
The last chapter is
|
||||
set in a coffee shop.
|
||||
I hope that's all right.
|
||||
|
||||
**B14** — `day>=28` — happy
|
||||
Here. Page forty.
|
||||
That's your counter.
|
||||
That's your lamp.
|
||||
|
||||
**B15 · resolution** — `day>=31` — happy
|
||||
It's done. Nine years.
|
||||
I'm starting something
|
||||
new. Set here, I think.
|
||||
|
||||
---
|
||||
|
||||
## 4. Nakajima-san — the widow
|
||||
|
||||
> Two coffees. One with milk, one black. Slow, seasonal, weather-tied.
|
||||
> **Want:** keep a routine that belonged to two people.
|
||||
> **Secret:** the second coffee is his. It goes cold every time.
|
||||
> **Change:** one day she orders one.
|
||||
|
||||
**Handle with care.** Her hook is the strongest in the game because the
|
||||
player solves it unaided — the order is visible in the serve mechanic long
|
||||
before anything is said. Per `PLAN.md` §8 item 14: **no one but Nakajima-san
|
||||
ever explains it**, and she does so obliquely, at B4, and never apologises
|
||||
for it. Do not let another character mention her situation.
|
||||
|
||||
Her arc runs on a slower day scale than the others by design — she should
|
||||
feel like someone you see less often.
|
||||
|
||||
**B1** — `day>=4` — neutral
|
||||
Two coffees, please.
|
||||
One with milk.
|
||||
The other black.
|
||||
|
||||
**B2** — `day>=8` — neutral
|
||||
The same, please.
|
||||
You remember which is
|
||||
which. That's good.
|
||||
|
||||
**B3** — `day>=12, served=TWO_COFFEE` — neutral
|
||||
No, don't clear it yet.
|
||||
Leave it a while.
|
||||
I'm not finished.
|
||||
|
||||
**B4 · the crack** — `day>=16, season=autumn` — neutral
|
||||
He liked the autumn.
|
||||
Said the town looked
|
||||
better in brown.
|
||||
|
||||
**B5** — `day>=20` — neutral
|
||||
Forty-one years of
|
||||
two coffees.
|
||||
It's a hard habit.
|
||||
|
||||
**B6** — `day>=24, weather=rain` — troubled
|
||||
He'd have hated today.
|
||||
He walked everywhere.
|
||||
Never once took a bus.
|
||||
|
||||
**B7** — `day>=28, affinity>=40` — neutral
|
||||
Your father served us
|
||||
at that end table.
|
||||
We were young then.
|
||||
|
||||
**B8** — `day>=32` — neutral
|
||||
I know it goes cold.
|
||||
That isn't the point
|
||||
of it, Master.
|
||||
|
||||
**B9** — `day>=36, season=winter` — troubled
|
||||
Three years this month.
|
||||
People stop asking after
|
||||
the second one.
|
||||
|
||||
**B10** — `day>=40` — neutral
|
||||
My son says it's time
|
||||
I stopped. He means
|
||||
well. He means well.
|
||||
|
||||
**B11** — `day>=44, season=spring` — neutral
|
||||
The cherry by the
|
||||
station is out.
|
||||
He'd have said it's early.
|
||||
|
||||
**B12** — `day>=48, affinity>=70` — neutral
|
||||
I don't cry about it.
|
||||
I just like ordering
|
||||
for two. It's an hour.
|
||||
|
||||
**B13** — `day>=52` — neutral
|
||||
You never asked me why.
|
||||
That's why I come here
|
||||
and not the new place.
|
||||
|
||||
**B14 · the change** — `day>=56` — neutral
|
||||
One coffee today.
|
||||
...With milk.
|
||||
Just the one.
|
||||
|
||||
**B15 · resolution** — `day>=60, affinity>=90` — happy
|
||||
One, please.
|
||||
I'll take the window
|
||||
seat. He never liked it.
|
||||
|
||||
---
|
||||
|
||||
## 5. Order lines
|
||||
|
||||
Spoken on arrival, before the brew. Rotate at random within a character;
|
||||
they're texture, not story.
|
||||
|
||||
**Aki**
|
||||
Cream soda, please.
|
||||
The usual, Master.
|
||||
Soda. I've earned it.
|
||||
|
||||
**Ōta-san**
|
||||
Coffee. Black.
|
||||
The usual, if you please.
|
||||
Coffee. No sugar. Ever.
|
||||
|
||||
**Fujimoto**
|
||||
Coffee. Keep it coming.
|
||||
Something that will hurt.
|
||||
Strongest. And toast.
|
||||
|
||||
**Nakajima-san**
|
||||
Two coffees, please.
|
||||
The same as always.
|
||||
Two. Milk in one.
|
||||
|
||||
---
|
||||
|
||||
## 6. Brew reactions
|
||||
|
||||
Replaces the generic quality lines currently hardcoded in `kissaten.c`.
|
||||
Quality bands as implemented: 3 = perfect, 2 = good, 1 = fair, 0 = off
|
||||
(thin or over-strong depending on which side of centre you locked).
|
||||
|
||||
| | Aki | Ōta-san | Fujimoto | Nakajima-san |
|
||||
|---|---|---|---|---|
|
||||
| **3** | The ice is just right. | That is correct coffee. | Oh, that's cruel. Good. | He'd have liked that one. |
|
||||
| **2** | Mm. That's a good one. | Good. Very good. | That'll do damage. | Very good, Master. |
|
||||
| **1** | Thank you, Master. | Thank you. | Fine. It's wet. | Thank you, dear. |
|
||||
| **0 thin** | It's a bit flat today. | A little pale today. | Is this tea? | A little weak today. |
|
||||
| **0 strong** | Ooh. That's a lot. | Strong. I'll manage. | Perfect. Awful. Perfect. | Oh my. That's bracing. |
|
||||
|
||||
---
|
||||
|
||||
## 7. Ambient lines
|
||||
|
||||
Shown while the shop is empty. The four currently in `kissaten.c` are
|
||||
placeholders; these replace them. Weather- and season-gated where marked.
|
||||
|
||||
**Any time**
|
||||
The radio hums softly.
|
||||
The kettle ticks as it
|
||||
cools.
|
||||
Steam on the window glass.
|
||||
A bicycle bell, outside.
|
||||
The lamp buzzes, once.
|
||||
|
||||
**Rain** — `weather=rain`
|
||||
Rain taps at the window.
|
||||
Someone runs past under
|
||||
a newspaper.
|
||||
The gutter is singing.
|
||||
|
||||
**Clear evening** — `weather=clear, phase=evening`
|
||||
Dusk settles over the
|
||||
street.
|
||||
The sky goes orange, then
|
||||
nothing.
|
||||
|
||||
**Autumn** — `season=autumn`
|
||||
A leaf is stuck to the
|
||||
door.
|
||||
|
||||
**Winter** — `season=winter`
|
||||
The window fogs faster
|
||||
than you can wipe it.
|
||||
|
||||
---
|
||||
|
||||
## 8. Notes and open questions
|
||||
|
||||
**Aki's soda doesn't fit the brew minigame.** The siphon minigame is
|
||||
coffee-specific, but her usual is a cream soda. My recommendation: **soda
|
||||
skips the minigame entirely** — it's poured, not brewed. That's not a
|
||||
workaround, it's an improvement: her visits get a different, lighter rhythm
|
||||
than the three coffee drinkers, which suits a teenager dropping in after cram
|
||||
school. Her B13 switch to coffee then means she enters the minigame for the
|
||||
first time, which is a lovely mechanical echo of the story beat.
|
||||
|
||||
**Nakajima-san's two coffees imply a two-brew serve.** Simplest reading: one
|
||||
minigame, both cups. Making the player brew twice would be tedious and would
|
||||
also make the second cup feel like a chore rather than a small sadness.
|
||||
|
||||
**Cross-references are deliberate.** Aki's B13 names Ōta-san; Ōta's B2 and
|
||||
Nakajima's B7 both reference your father running the shop before you. These
|
||||
cost nothing and make the cast feel like one place rather than four
|
||||
unrelated visitors. Add more of these freely — but never let anyone discuss
|
||||
Nakajima-san's second cup.
|
||||
|
||||
**Nobody dies during the game, nobody is cured.** All four arcs resolve by
|
||||
someone deciding something small. That is the genre working correctly.
|
||||
|
||||
**Beat count is 60.** At three beats per sitting that's the twenty writing
|
||||
sessions budgeted in `PLAN.md` §5 — already spent, if this draft survives
|
||||
editing.
|
||||
@@ -0,0 +1,828 @@
|
||||
// Kissaten Yūgure — stage 1 of the scope ladder (see docs/DESIGN.md §8):
|
||||
// shop scene + one customer + siphon brew minigame + serve loop. No story,
|
||||
// no money, no day cycle yet. All "art" is procedural placeholder fills;
|
||||
// real bitmaps will replace the scene drawing and sprite data later.
|
||||
|
||||
//=============================================================================
|
||||
// INCLUDES
|
||||
//=============================================================================
|
||||
#include "msxgl.h"
|
||||
#include "tool/disk_save.h"
|
||||
|
||||
// Fonts data
|
||||
#include "font/font_mgl_sample6.h"
|
||||
|
||||
//=============================================================================
|
||||
// DEFINES
|
||||
//=============================================================================
|
||||
|
||||
// Screen layout (DESIGN.md §4): 16px status bar, 132px shop scene, 64px dialogue
|
||||
#define STATUS_Y 0
|
||||
#define STATUS_H 16
|
||||
#define SCENE_Y 16
|
||||
#define SCENE_H 132
|
||||
#define DLG_Y 148
|
||||
#define DLG_H 64
|
||||
|
||||
// Palette slots (DESIGN.md §5: sky in 8-11, wood/warm in 4-7, so seasons and
|
||||
// time-of-day can later be palette swaps without touching the bitmap)
|
||||
#define C_OUTLINE 1 // near black
|
||||
#define C_WOOD_D 2 // dark wood / floor / shadow
|
||||
#define C_WOOD_M 3 // mid wood (wall panels, door)
|
||||
#define C_WOOD_L 4 // light wood (counter top)
|
||||
#define C_LAMP 5 // warm lamp glow
|
||||
#define C_CREAM 6 // cream (glassware, cup)
|
||||
#define C_WALL 7 // muted upper wall
|
||||
#define C_SKY1 8 // dusk sky, deep
|
||||
#define C_SKY2 9 // dusk violet
|
||||
#define C_SKY3 10 // dusk rose
|
||||
#define C_SKY4 11 // horizon amber
|
||||
#define C_COFFEE 12 // coffee brown
|
||||
#define C_COAT 13 // customer coat blue
|
||||
#define C_SKIN 14 // skin
|
||||
#define C_TEXT 15 // warm white
|
||||
|
||||
// G4 mode: one byte = two pixels of the same palette index
|
||||
#define PX(c) (u8)(((c) << 4) | (c))
|
||||
|
||||
// Shop scene landmarks
|
||||
#define COUNTER_TOP_Y 98
|
||||
#define DOOR_X 216 // where the customer appears/exits
|
||||
#define SEAT_X 104 // where the customer stands at the counter
|
||||
#define CUST_Y 84 // sprite top: bottom edge rests on the counter top
|
||||
#define SIPHON_X 32 // siphon rig center
|
||||
#define CUP_X 86 // served cup position on the counter
|
||||
|
||||
// Sprites (mode 2 is implicit in SCREEN 5; two layers per customer)
|
||||
#define SPR_CUST_FILL 0 // front layer
|
||||
#define SPR_CUST_LINE 1 // outline layer behind
|
||||
#define SPR_STEAM 2
|
||||
#define PAT_CUST_FILL 0 // 16x16 patterns: indices are multiples of 4
|
||||
#define PAT_CUST_LINE 4
|
||||
#define PAT_STEAM_A 8
|
||||
#define PAT_STEAM_B 12
|
||||
|
||||
// Day length. Event-driven clock: customers *are* the clock, so this single
|
||||
// constant is the whole pacing dial (PLAN.md §8 items 2-3).
|
||||
#define CUSTOMERS_PER_DAY 5
|
||||
|
||||
// Brew minigame gauge (drawn in the dialogue window)
|
||||
#define GAUGE_X 64
|
||||
#define GAUGE_Y 186
|
||||
#define GAUGE_W 148
|
||||
#define GAUGE_H 10
|
||||
#define GAUGE_CENTER (GAUGE_W / 2)
|
||||
|
||||
// Dialogue text layout: 48px portrait zone left, 3 text lines right
|
||||
#define DLG_TEXT_X 64
|
||||
#define DLG_LINE_Y(n) (u8)(156 + (n) * 14)
|
||||
|
||||
//=============================================================================
|
||||
// READ-ONLY DATA
|
||||
//=============================================================================
|
||||
|
||||
// Palette: u16 = G<<8 | R<<4 | B, components 0-7
|
||||
#define RGB(r, g, b) (u16)(((g) << 8) | ((r) << 4) | (b))
|
||||
const u16 g_Palette[16] = {
|
||||
RGB(0, 0, 0), // 0 (transparent)
|
||||
RGB(1, 1, 1), // 1 outline
|
||||
RGB(2, 1, 1), // 2 dark wood
|
||||
RGB(4, 2, 1), // 3 mid wood
|
||||
RGB(5, 3, 2), // 4 light wood
|
||||
RGB(7, 5, 2), // 5 lamp glow
|
||||
RGB(7, 6, 4), // 6 cream
|
||||
RGB(3, 2, 2), // 7 muted wall
|
||||
RGB(2, 1, 4), // 8 dusk deep
|
||||
RGB(4, 2, 5), // 9 dusk violet
|
||||
RGB(6, 3, 3), // 10 dusk rose
|
||||
RGB(7, 4, 2), // 11 horizon amber
|
||||
RGB(3, 1, 0), // 12 coffee
|
||||
RGB(2, 3, 5), // 13 coat blue
|
||||
RGB(7, 5, 4), // 14 skin
|
||||
RGB(7, 7, 6), // 15 warm white
|
||||
};
|
||||
|
||||
// 16x16 sprite patterns: 32 bytes each, left column rows 0-15 then right column.
|
||||
// Customer silhouette, fill layer
|
||||
const u8 g_SprCustFill[32] = {
|
||||
0x07, 0x0F, 0x1F, 0x1F, 0x1F, 0x0F, 0x07, 0x1F, // left, rows 0-7
|
||||
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x1F, 0x0E, 0x0E, // left, rows 8-15
|
||||
0xE0, 0xF0, 0xF8, 0xF8, 0xF8, 0xF0, 0xE0, 0xF8, // right, rows 0-7
|
||||
0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xF8, 0x70, 0x70, // right, rows 8-15
|
||||
};
|
||||
// Customer silhouette dilated by 1px: black outline layer drawn behind the fill
|
||||
const u8 g_SprCustLine[32] = {
|
||||
0x1F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x7F,
|
||||
0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x3F, 0x1F,
|
||||
0xF8, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFE,
|
||||
0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFC, 0xF8,
|
||||
};
|
||||
// Steam wisps, two animation frames
|
||||
const u8 g_SprSteamA[32] = {
|
||||
0x01, 0x03, 0x07, 0x0E, 0x1C, 0x1E, 0x0F, 0x07,
|
||||
0x03, 0x03, 0x07, 0x0E, 0x06, 0x00, 0x00, 0x00,
|
||||
0x80, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
|
||||
0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
const u8 g_SprSteamB[32] = {
|
||||
0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x80, 0xC0, 0xE0, 0x70, 0x38, 0x78, 0xF0, 0xE0,
|
||||
0xC0, 0xC0, 0xE0, 0x70, 0x60, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
// Ambient lines shown while the shop is empty
|
||||
const c8* const g_Ambient[4] = {
|
||||
"The radio hums softly.",
|
||||
"Rain taps at the window.",
|
||||
"The kettle ticks as it cools.",
|
||||
"Dusk settles over the street.",
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// GAME STATE
|
||||
//=============================================================================
|
||||
|
||||
enum State
|
||||
{
|
||||
STATE_WAIT, // shop empty, waiting for the next customer
|
||||
STATE_ARRIVE, // customer walks from door to counter
|
||||
STATE_ORDER, // order shown, waiting for SPACE
|
||||
STATE_BREW, // siphon minigame running
|
||||
STATE_SERVE, // reaction to the brew
|
||||
STATE_DRINK, // quiet moment with the cup
|
||||
STATE_LEAVE, // customer walks back to the door
|
||||
};
|
||||
|
||||
// Day phases (DESIGN.md §2). The open-hours phase holds the STATE_* loop above.
|
||||
enum Phase
|
||||
{
|
||||
PHASE_MORNING, // prep — day title card, waiting to open
|
||||
PHASE_OPEN, // the serve loop runs
|
||||
PHASE_EVENING, // close — tally, journal line, save
|
||||
};
|
||||
|
||||
u8 g_State = STATE_WAIT;
|
||||
u16 g_Timer = 120; // frames left in timed states
|
||||
u8 g_CustX = DOOR_X; // customer sprite X
|
||||
u16 g_Served = 0; // cups served, lifetime
|
||||
u8 g_Ambience = 0; // rotating ambient line index
|
||||
i16 g_Needle = 0; // brew gauge needle position
|
||||
i8 g_NeedleDir = 3;
|
||||
u8 g_Quality = 0; // 0 weak/overdone .. 3 perfect
|
||||
bool g_Overdone = FALSE; // which side of center the lock landed on
|
||||
u8 g_Frame = 0;
|
||||
bool g_SpaceHit = FALSE; // SPACE pressed this frame (edge, sampled after Halt)
|
||||
u8 g_SpacePrev = 0;
|
||||
|
||||
u8 g_Phase = PHASE_MORNING;
|
||||
u8 g_DayServed = 0; // customers served so far today
|
||||
u8 g_DayQuality = 0; // summed brew quality today, for the journal line
|
||||
bool g_SaveOk = TRUE; // did the last write succeed (shown next morning)
|
||||
|
||||
//=============================================================================
|
||||
// SAVE STATE (DESIGN.md §6)
|
||||
//=============================================================================
|
||||
|
||||
// Bumped whenever the layout below changes; a mismatch is treated as "no save"
|
||||
// rather than migrated — there is no shipped version to be compatible with yet.
|
||||
#define SAVE_MAGIC 0x594B // 'KY'
|
||||
#define SAVE_VERSION 1
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 id;
|
||||
u8 arc_stage; // progress through their story
|
||||
u8 affinity; // 0-255, raised by right orders
|
||||
u8 last_visit_day;
|
||||
} Regular;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u16 magic;
|
||||
u8 version;
|
||||
u16 day;
|
||||
u8 season; // derives palette set
|
||||
u8 weather; // affects visitor table
|
||||
u16 money;
|
||||
u16 served;
|
||||
u8 unlocked_items; // bitmask: grinder, records, cat...
|
||||
Regular regulars[8];
|
||||
u8 checksum; // sum of all preceding bytes, negated
|
||||
} SaveState;
|
||||
|
||||
SaveState g_Save;
|
||||
|
||||
//=============================================================================
|
||||
// DISK SAVE
|
||||
//=============================================================================
|
||||
//
|
||||
// Uses MSXgl's tool/disk_save module (added in v1.3.0, "save to disk from a
|
||||
// ROM application"). It writes a real named file — KISSAT0.SAV — through the
|
||||
// Disk ROM, so the save disk stays a normal, inspectable FAT disk.
|
||||
//
|
||||
// This replaced a hand-rolled PHYDIO/DSKIO sector writer that never worked:
|
||||
// both entry points returned carry-clear without transferring anything. Do
|
||||
// not go back to raw sectors; use this module.
|
||||
//
|
||||
// Requirements, both non-obvious:
|
||||
// - LibModules must include BOTH "tool/disk_save" and "dos".
|
||||
// - ROMDelayBoot = true, or the Disk ROM's INIT never runs (see CLAUDE.md).
|
||||
|
||||
// Save slot. Multiple save files would be entries 1, 2, ... on the same disk.
|
||||
#define SAVE_ENTRY 0
|
||||
|
||||
bool g_HasDisk = FALSE; // a usable save disk was found at boot
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
u8 Save_Checksum(const SaveState* s)
|
||||
{
|
||||
const u8* p = (const u8*)s;
|
||||
u8 sum = 0;
|
||||
for (u8 i = 0; i < sizeof(SaveState) - 1; i++)
|
||||
sum += p[i];
|
||||
return (u8)(0 - sum);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// A missing drive or a blank disk is not an error the player has to deal
|
||||
// with — it just means nothing will persist.
|
||||
void Disk_Init()
|
||||
{
|
||||
DiskSave_SetName("KISSAT"); // 6 chars max
|
||||
DiskSave_SetExtension("SAV"); // 3 chars max
|
||||
g_HasDisk = (DiskSave_Initialize() == SAVEDATA_VALID);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// TRUE if a valid save was loaded; FALSE means "start a new game", which is
|
||||
// also what a blank disk gives us.
|
||||
bool Save_Load()
|
||||
{
|
||||
if (!g_HasDisk)
|
||||
return FALSE;
|
||||
|
||||
// SAVEDATA_UNSIGNED is expected, not an error: with AppSignature on,
|
||||
// DiskSave_Check() wants the file's first 4 bytes to be g_AppSignature,
|
||||
// but DiskSave_Save() writes the payload raw and never adds it — so a
|
||||
// perfectly good file always reports UNSIGNED. Only a genuinely absent or
|
||||
// unreadable file is a reason to bail; the magic and checksum below are a
|
||||
// stronger check than the signature would have been anyway.
|
||||
u8 status = DiskSave_Check(SAVE_ENTRY);
|
||||
if ((status != SAVEDATA_VALID) && (status != SAVEDATA_UNSIGNED))
|
||||
return FALSE;
|
||||
|
||||
if (!DiskSave_Load(SAVE_ENTRY, (u8*)&g_Save, sizeof(SaveState)))
|
||||
return FALSE;
|
||||
|
||||
// Trust nothing that came off a disk
|
||||
if (g_Save.magic != SAVE_MAGIC || g_Save.version != SAVE_VERSION)
|
||||
return FALSE;
|
||||
if (g_Save.checksum != Save_Checksum(&g_Save))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Save_Write()
|
||||
{
|
||||
if (!g_HasDisk)
|
||||
return FALSE;
|
||||
|
||||
g_Save.magic = SAVE_MAGIC;
|
||||
g_Save.version = SAVE_VERSION;
|
||||
g_Save.checksum = Save_Checksum(&g_Save);
|
||||
|
||||
return DiskSave_Save(SAVE_ENTRY, (const u8*)&g_Save, sizeof(SaveState));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void Save_Reset()
|
||||
{
|
||||
Mem_Set(0, &g_Save, sizeof(SaveState));
|
||||
g_Save.day = 1;
|
||||
g_Save.season = 0;
|
||||
g_Save.money = 0;
|
||||
g_Save.served = 0;
|
||||
for (u8 i = 0; i < 8; i++)
|
||||
g_Save.regulars[i].id = i;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// HELPERS
|
||||
//=============================================================================
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Customer sprites: fill layer in front, outline layer behind
|
||||
void Customer_Show(u8 x, u8 y)
|
||||
{
|
||||
VDP_SetSpritePosition(SPR_CUST_FILL, x, y);
|
||||
VDP_SetSpritePosition(SPR_CUST_LINE, x, y);
|
||||
}
|
||||
|
||||
void Customer_Hide()
|
||||
{
|
||||
VDP_HideSprite(SPR_CUST_FILL);
|
||||
VDP_HideSprite(SPR_CUST_LINE);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Steam wisp: alternates two patterns every 16 frames
|
||||
void Steam_Show(u8 x, u8 y)
|
||||
{
|
||||
VDP_SetSpriteExUniColor(SPR_STEAM, x, y,
|
||||
(g_Frame & 16) ? PAT_STEAM_A : PAT_STEAM_B, C_CREAM);
|
||||
}
|
||||
|
||||
void Steam_Hide()
|
||||
{
|
||||
VDP_HideSprite(SPR_STEAM);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Status bar: title left, served count right
|
||||
void DrawStatusBar()
|
||||
{
|
||||
VDP_CommandHMMV(0, STATUS_Y, 256, STATUS_H, PX(C_OUTLINE));
|
||||
VDP_CommandWait();
|
||||
|
||||
Print_SetColor(C_LAMP, C_OUTLINE);
|
||||
Print_SetPosition(4, 4);
|
||||
Print_DrawText("DAY ");
|
||||
Print_DrawInt(g_Save.day);
|
||||
|
||||
// Phase marker sits mid-bar; the clock is the day phase, nothing finer
|
||||
Print_SetColor(C_CREAM, C_OUTLINE);
|
||||
Print_SetPosition(96, 4);
|
||||
switch (g_Phase)
|
||||
{
|
||||
case PHASE_MORNING: Print_DrawText("MORNING"); break;
|
||||
case PHASE_OPEN: Print_DrawText("OPEN"); break;
|
||||
default: Print_DrawText("CLOSED"); break;
|
||||
}
|
||||
|
||||
Print_SetColor(C_TEXT, C_OUTLINE);
|
||||
Print_SetPosition(176, 4);
|
||||
Print_DrawText("SERVED ");
|
||||
Print_DrawInt(g_Save.served);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Shop scene: placeholder fills standing in for the real background bitmap
|
||||
void DrawScene()
|
||||
{
|
||||
// Wall, wood paneling, floor
|
||||
VDP_CommandHMMV(0, SCENE_Y, 256, 60, PX(C_WALL)); // upper wall
|
||||
VDP_CommandHMMV(0, 76, 256, 44, PX(C_WOOD_M)); // wainscot
|
||||
VDP_CommandHMMV(0, 76, 256, 1, PX(C_WOOD_D)); // panel rail
|
||||
VDP_CommandHMMV(0, 120, 256, 28, PX(C_WOOD_D)); // floor
|
||||
VDP_CommandHMMV(0, 120, 256, 1, PX(C_OUTLINE)); // floor edge
|
||||
|
||||
// Window (left): frame + dusk sky gradient in slots 8-11
|
||||
VDP_CommandHMMV(16, 24, 72, 48, PX(C_WOOD_D)); // frame
|
||||
VDP_CommandHMMV(20, 28, 64, 10, PX(C_SKY1));
|
||||
VDP_CommandHMMV(20, 38, 64, 10, PX(C_SKY2));
|
||||
VDP_CommandHMMV(20, 48, 64, 10, PX(C_SKY3));
|
||||
VDP_CommandHMMV(20, 58, 64, 10, PX(C_SKY4));
|
||||
VDP_CommandHMMV(50, 28, 2, 40, PX(C_WOOD_D)); // mullion
|
||||
VDP_CommandHMMV(20, 46, 64, 2, PX(C_WOOD_D)); // transom
|
||||
|
||||
// Door (right)
|
||||
VDP_CommandHMMV(208, 32, 36, 88, PX(C_WOOD_D)); // frame
|
||||
VDP_CommandHMMV(212, 36, 28, 82, PX(C_WOOD_M)); // door
|
||||
VDP_CommandHMMV(218, 40, 16, 18, PX(C_SKY2)); // door pane
|
||||
VDP_CommandHMMV(236, 76, 2, 3, PX(C_LAMP)); // knob
|
||||
|
||||
// Hanging lamp above the counter
|
||||
VDP_CommandHMMV(139, SCENE_Y, 2, 12, PX(C_OUTLINE)); // cord
|
||||
VDP_CommandHMMV(132, 28, 16, 8, PX(C_LAMP)); // shade
|
||||
|
||||
// Counter: top slab + front panel
|
||||
VDP_CommandHMMV(8, COUNTER_TOP_Y, 192, 8, PX(C_WOOD_L));
|
||||
VDP_CommandHMMV(8, COUNTER_TOP_Y + 8, 192, 34, PX(C_WOOD_D));
|
||||
VDP_CommandHMMV(8, COUNTER_TOP_Y, 192, 1, PX(C_CREAM)); // top highlight
|
||||
|
||||
// Siphon rig on the counter (left, kept below the window): stand, globe, flask
|
||||
VDP_CommandHMMV(SIPHON_X + 5, 74, 2, 24, PX(C_OUTLINE)); // stand pole
|
||||
VDP_CommandHMMV(SIPHON_X - 6, 74, 24, 2, PX(C_OUTLINE)); // top arm
|
||||
VDP_CommandHMMV(SIPHON_X - 6, 76, 12, 8, PX(C_CREAM)); // upper globe
|
||||
VDP_CommandHMMV(SIPHON_X - 7, 86, 14, 10, PX(C_CREAM)); // lower flask
|
||||
VDP_CommandWait();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Coffee level in the lower flask, 0-8 px
|
||||
void DrawFlask(u8 level)
|
||||
{
|
||||
VDP_CommandHMMV(SIPHON_X - 6, 87, 12, 8, PX(C_CREAM));
|
||||
if (level > 0)
|
||||
{
|
||||
if (level > 8)
|
||||
level = 8;
|
||||
VDP_CommandHMMV(SIPHON_X - 6, (u16)(95 - level), 12, level, PX(C_COFFEE));
|
||||
}
|
||||
VDP_CommandWait();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Burner flame under the flask (on/off)
|
||||
void DrawFlame(bool on)
|
||||
{
|
||||
VDP_CommandHMMV(SIPHON_X - 3, 96, 6, 2, on ? PX(C_SKY4) : PX(C_WOOD_M));
|
||||
VDP_CommandWait();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Cup on the counter in front of the customer
|
||||
void DrawCup(bool visible)
|
||||
{
|
||||
if (visible)
|
||||
{
|
||||
VDP_CommandHMMV(CUP_X, 91, 10, 7, PX(C_CREAM));
|
||||
VDP_CommandHMMV(CUP_X + 1, 91, 8, 2, PX(C_COFFEE));
|
||||
}
|
||||
else // restore the wainscot the cup stands against, not the counter top
|
||||
VDP_CommandHMMV(CUP_X, 91, 10, 7, PX(C_WOOD_M));
|
||||
VDP_CommandWait();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Dialogue window: dark panel with a portrait placeholder box on the left
|
||||
void Dlg_Clear()
|
||||
{
|
||||
VDP_CommandHMMV(0, DLG_Y, 256, DLG_H, PX(C_WOOD_D)); // border
|
||||
VDP_CommandHMMV(2, DLG_Y + 2, 252, DLG_H - 4, PX(C_OUTLINE)); // panel
|
||||
VDP_CommandHMMV(6, 154, 52, 52, PX(C_WOOD_M)); // portrait frame
|
||||
VDP_CommandHMMV(8, 156, 48, 48, PX(C_WOOD_D)); // portrait (48x48, stage 3+)
|
||||
VDP_CommandWait();
|
||||
}
|
||||
|
||||
void Dlg_Line(u8 line, const c8* text)
|
||||
{
|
||||
Print_SetColor(C_TEXT, C_OUTLINE);
|
||||
Print_SetPosition(DLG_TEXT_X, DLG_LINE_Y(line));
|
||||
Print_DrawText(text);
|
||||
}
|
||||
|
||||
// Prompt line in warm accent color
|
||||
void Dlg_Prompt(const c8* text)
|
||||
{
|
||||
Print_SetColor(C_LAMP, C_OUTLINE);
|
||||
Print_SetPosition(DLG_TEXT_X, DLG_LINE_Y(3));
|
||||
Print_DrawText(text);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Brew gauge: zones repainted whole each frame, then the needle on top
|
||||
void DrawGauge()
|
||||
{
|
||||
// Full band first: the needle sticks out 2px above and below the zones
|
||||
VDP_CommandHMMV(GAUGE_X, GAUGE_Y - 2, GAUGE_W + 2, GAUGE_H + 4, PX(C_OUTLINE));
|
||||
VDP_CommandHMMV(GAUGE_X, GAUGE_Y, GAUGE_W, GAUGE_H, PX(C_WOOD_D));
|
||||
VDP_CommandHMMV(GAUGE_X + GAUGE_CENTER - 10, GAUGE_Y, 20, GAUGE_H, PX(C_LAMP));
|
||||
VDP_CommandHMMV(GAUGE_X + GAUGE_CENTER - 3, GAUGE_Y, 6, GAUGE_H, PX(C_SKY4));
|
||||
VDP_CommandHMMV((u16)(GAUGE_X + g_Needle), GAUGE_Y - 2, 2, GAUGE_H + 4, PX(C_TEXT));
|
||||
VDP_CommandWait();
|
||||
}
|
||||
|
||||
void EraseGauge()
|
||||
{
|
||||
VDP_CommandHMMV(GAUGE_X, GAUGE_Y - 2, GAUGE_W + 2, GAUGE_H + 4, PX(C_OUTLINE));
|
||||
VDP_CommandWait();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// PHASE TRANSITIONS
|
||||
//=============================================================================
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Morning: day title card. No prep decisions yet — those arrive with the menu
|
||||
// system, if it survives the cut (PLAN.md §6).
|
||||
void EnterMorning()
|
||||
{
|
||||
g_Phase = PHASE_MORNING;
|
||||
g_DayServed = 0;
|
||||
g_DayQuality = 0;
|
||||
Customer_Hide();
|
||||
Steam_Hide();
|
||||
DrawStatusBar();
|
||||
DrawScene();
|
||||
Dlg_Clear();
|
||||
Dlg_Line(0, "Morning. The shutters go");
|
||||
Dlg_Line(1, "up, the kettle goes on.");
|
||||
if (!g_HasDisk)
|
||||
Dlg_Line(2, "(no save disk in drive A)");
|
||||
else if (!g_SaveOk)
|
||||
Dlg_Line(2, "(save failed)");
|
||||
Dlg_Prompt("[SPACE] open the shop");
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Evening: tally, one journal line reflecting how the day went, then save.
|
||||
void EnterEvening()
|
||||
{
|
||||
g_Phase = PHASE_EVENING;
|
||||
Customer_Hide();
|
||||
Steam_Hide();
|
||||
DrawStatusBar();
|
||||
Dlg_Clear();
|
||||
|
||||
Dlg_Line(0, "Closing. Cups today: ");
|
||||
Print_DrawInt(g_DayServed);
|
||||
|
||||
// Average quality drives the journal line — no score, just a mood
|
||||
u8 avg = g_DayServed ? (u8)(g_DayQuality / g_DayServed) : 0;
|
||||
if (avg >= 2)
|
||||
Dlg_Line(1, "A good day at the siphon.");
|
||||
else if (avg >= 1)
|
||||
Dlg_Line(1, "An ordinary, decent day.");
|
||||
else
|
||||
Dlg_Line(1, "Tomorrow, a steadier hand.");
|
||||
|
||||
Dlg_Prompt("[SPACE] sleep");
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Save *after* the day rolls over, so the file always describes the morning
|
||||
// the player will wake up to. Saving during the evening instead would make a
|
||||
// reload replay the day just finished and double-count its cups.
|
||||
void AdvanceDay()
|
||||
{
|
||||
g_Save.day++;
|
||||
g_SaveOk = Save_Write();
|
||||
EnterMorning();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// STATE TRANSITIONS
|
||||
//=============================================================================
|
||||
|
||||
void EnterWaitState()
|
||||
{
|
||||
g_State = STATE_WAIT;
|
||||
g_Timer = 120 + Math_GetRandomMax8(180);
|
||||
Dlg_Clear();
|
||||
Dlg_Line(0, g_Ambient[g_Ambience]);
|
||||
g_Ambience = (g_Ambience + 1) & 3;
|
||||
}
|
||||
|
||||
void EnterArrive()
|
||||
{
|
||||
g_State = STATE_ARRIVE;
|
||||
g_CustX = DOOR_X;
|
||||
VDP_SetSpriteExUniColor(SPR_CUST_LINE, DOOR_X, CUST_Y, PAT_CUST_LINE, C_OUTLINE);
|
||||
VDP_SetSpriteExUniColor(SPR_CUST_FILL, DOOR_X, CUST_Y, PAT_CUST_FILL, C_COAT);
|
||||
Dlg_Clear();
|
||||
Dlg_Line(0, "The door chime rings.");
|
||||
}
|
||||
|
||||
void EnterOrder()
|
||||
{
|
||||
g_State = STATE_ORDER;
|
||||
Dlg_Clear();
|
||||
Dlg_Line(0, "\"A coffee, please.\"");
|
||||
Dlg_Prompt("[SPACE] brew");
|
||||
}
|
||||
|
||||
void EnterBrew()
|
||||
{
|
||||
g_State = STATE_BREW;
|
||||
g_Needle = 0;
|
||||
g_NeedleDir = 3;
|
||||
g_Timer = 0;
|
||||
Dlg_Clear();
|
||||
Dlg_Line(0, "Release when the needle");
|
||||
Dlg_Line(1, "crosses the amber mark!");
|
||||
DrawFlame(TRUE);
|
||||
}
|
||||
|
||||
void EnterServe()
|
||||
{
|
||||
g_State = STATE_SERVE;
|
||||
g_Timer = 150;
|
||||
EraseGauge();
|
||||
DrawFlame(FALSE);
|
||||
DrawFlask(0);
|
||||
DrawCup(TRUE);
|
||||
Dlg_Clear();
|
||||
switch (g_Quality)
|
||||
{
|
||||
case 3:
|
||||
Dlg_Line(0, "\"Ah... perfect.\"");
|
||||
Dlg_Line(1, "The evening feels warmer.");
|
||||
break;
|
||||
case 2:
|
||||
Dlg_Line(0, "\"Mm. Nice and rich.\"");
|
||||
break;
|
||||
case 1:
|
||||
Dlg_Line(0, "\"Thank you.\"");
|
||||
break;
|
||||
default:
|
||||
Dlg_Line(0, g_Overdone ? "\"Oh... quite strong.\""
|
||||
: "\"Hm... a little thin.\"");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void EnterDrink()
|
||||
{
|
||||
g_State = STATE_DRINK;
|
||||
g_Timer = 180;
|
||||
Dlg_Clear();
|
||||
Dlg_Line(0, "A quiet moment passes.");
|
||||
}
|
||||
|
||||
void EnterLeave()
|
||||
{
|
||||
g_State = STATE_LEAVE;
|
||||
Steam_Hide();
|
||||
DrawCup(FALSE);
|
||||
Dlg_Clear();
|
||||
Dlg_Line(0, "\"See you tomorrow.\"");
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// STATE UPDATES (one call per frame)
|
||||
//=============================================================================
|
||||
|
||||
void UpdateWait()
|
||||
{
|
||||
if (--g_Timer == 0)
|
||||
EnterArrive();
|
||||
}
|
||||
|
||||
void UpdateArrive()
|
||||
{
|
||||
g_CustX--;
|
||||
// Small walk bob
|
||||
Customer_Show(g_CustX, (g_CustX & 8) ? CUST_Y : CUST_Y - 1);
|
||||
if (g_CustX <= SEAT_X)
|
||||
{
|
||||
Customer_Show(SEAT_X, CUST_Y);
|
||||
EnterOrder();
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateOrder()
|
||||
{
|
||||
if (g_SpaceHit)
|
||||
EnterBrew();
|
||||
}
|
||||
|
||||
void UpdateBrew()
|
||||
{
|
||||
// Needle sweeps back and forth
|
||||
g_Needle += g_NeedleDir;
|
||||
if (g_Needle <= 0) { g_Needle = 0; g_NeedleDir = 3; }
|
||||
if (g_Needle >= GAUGE_W - 2){ g_Needle = GAUGE_W - 2; g_NeedleDir = -3; }
|
||||
DrawGauge();
|
||||
|
||||
// Coffee slowly rises while the needle sweeps
|
||||
g_Timer++;
|
||||
if ((g_Timer & 15) == 0)
|
||||
DrawFlask((u8)(g_Timer >> 4));
|
||||
Steam_Show(SIPHON_X - 8, 58);
|
||||
|
||||
if (g_SpaceHit)
|
||||
{
|
||||
i16 dist = g_Needle + 1 - GAUGE_CENTER;
|
||||
g_Overdone = (dist > 0);
|
||||
if (dist < 0)
|
||||
dist = -dist;
|
||||
if (dist <= 3) g_Quality = 3;
|
||||
else if (dist <= 10) g_Quality = 2;
|
||||
else if (dist <= 24) g_Quality = 1;
|
||||
else g_Quality = 0;
|
||||
g_DayQuality += g_Quality;
|
||||
EnterServe();
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateServe()
|
||||
{
|
||||
Steam_Show(CUP_X - 4, 78);
|
||||
if (--g_Timer == 0)
|
||||
EnterDrink();
|
||||
}
|
||||
|
||||
void UpdateDrink()
|
||||
{
|
||||
Steam_Show(CUP_X - 4, 78);
|
||||
if (--g_Timer == 0)
|
||||
EnterLeave();
|
||||
}
|
||||
|
||||
void UpdateLeave()
|
||||
{
|
||||
g_CustX++;
|
||||
Customer_Show(g_CustX, (g_CustX & 8) ? CUST_Y : CUST_Y - 1);
|
||||
if (g_CustX >= DOOR_X)
|
||||
{
|
||||
Customer_Hide();
|
||||
g_Save.served++;
|
||||
g_DayServed++;
|
||||
DrawStatusBar();
|
||||
|
||||
// Customers are the clock: the day ends when the last one leaves
|
||||
if (g_DayServed >= CUSTOMERS_PER_DAY)
|
||||
EnterEvening();
|
||||
else
|
||||
EnterWaitState();
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// MAIN LOOP
|
||||
//=============================================================================
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Program entry point
|
||||
void main()
|
||||
{
|
||||
VDP_SetMode(VDP_MODE_SCREEN5);
|
||||
VDP_SetColor(C_OUTLINE);
|
||||
VDP_EnableVBlank(TRUE);
|
||||
VDP_ClearVRAM();
|
||||
|
||||
// Palette (skip entry 0: transparent)
|
||||
for (u8 i = 1; i < 16; i++)
|
||||
VDP_SetPaletteEntry(i, g_Palette[i]);
|
||||
|
||||
// Sprites: 16x16, tables above page 1 (page 1 becomes the asset warehouse later)
|
||||
VDP_EnableSprite(TRUE);
|
||||
VDP_SetSpritePatternTable(0x17000);
|
||||
VDP_SetSpriteAttributeTable(0x17A00);
|
||||
VDP_SetSpriteFlag(VDP_SPRITE_SIZE_16);
|
||||
VDP_LoadSpritePattern(g_SprCustFill, PAT_CUST_FILL, 4);
|
||||
VDP_LoadSpritePattern(g_SprCustLine, PAT_CUST_LINE, 4);
|
||||
VDP_LoadSpritePattern(g_SprSteamA, PAT_STEAM_A, 4);
|
||||
VDP_LoadSpritePattern(g_SprSteamB, PAT_STEAM_B, 4);
|
||||
VDP_HideAllSprites();
|
||||
VDP_DisableSpritesFrom(3);
|
||||
|
||||
Print_SetBitmapFont(g_Font_MGL_Sample6);
|
||||
|
||||
// Explicit game-state init: don't rely on C initializers, the mapper
|
||||
// crt0's data-segment setup has proven unreliable here.
|
||||
g_Served = 0;
|
||||
g_Ambience = 0;
|
||||
g_Frame = 0;
|
||||
g_SpaceHit = FALSE;
|
||||
g_SpacePrev = 1; // treat SPACE as held at boot: no phantom first edge
|
||||
// Save disk. A missing or blank disk is not an error the player has to
|
||||
// deal with — it just means today is day one and nothing will persist.
|
||||
Save_Reset();
|
||||
Disk_Init();
|
||||
Save_Load();
|
||||
|
||||
EnterMorning();
|
||||
|
||||
while (1)
|
||||
{
|
||||
Halt(); // Wait V-Blank
|
||||
g_Frame++;
|
||||
|
||||
// Sample input immediately after Halt(): the BIOS ISR drives the PPI
|
||||
// keyboard row selection too, so a read elsewhere in the frame can
|
||||
// race with it and produce phantom edges.
|
||||
// Atomic keyboard read: Keyboard_Read() is a row-select 'out' followed
|
||||
// by an 'in'; if the BIOS ISR lands between them, its own matrix scan
|
||||
// moves the row selection and the read returns garbage (phantom keys).
|
||||
DisableInterrupt();
|
||||
u8 raw = Keyboard_Read(KEY_ROW(KEY_SPACE));
|
||||
EnableInterrupt();
|
||||
u8 space = (raw & KEY_FLAG(KEY_SPACE)) == 0;
|
||||
g_SpaceHit = space && !g_SpacePrev;
|
||||
g_SpacePrev = space;
|
||||
|
||||
// Morning and evening are single-key card screens; only the open
|
||||
// phase runs the serve loop's state machine.
|
||||
if (g_Phase == PHASE_MORNING)
|
||||
{
|
||||
if (g_SpaceHit)
|
||||
{
|
||||
g_Phase = PHASE_OPEN;
|
||||
DrawStatusBar();
|
||||
EnterWaitState();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (g_Phase == PHASE_EVENING)
|
||||
{
|
||||
if (g_SpaceHit)
|
||||
AdvanceDay();
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (g_State)
|
||||
{
|
||||
case STATE_WAIT: UpdateWait(); break;
|
||||
case STATE_ARRIVE: UpdateArrive(); break;
|
||||
case STATE_ORDER: UpdateOrder(); break;
|
||||
case STATE_BREW: UpdateBrew(); break;
|
||||
case STATE_SERVE: UpdateServe(); break;
|
||||
case STATE_DRINK: UpdateDrink(); break;
|
||||
case STATE_LEAVE: UpdateLeave(); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,641 @@
|
||||
// ____________________________
|
||||
// ██▀▀█▀▀██▀▀▀▀▀▀▀█▀▀█ │ ▄▄▄ ▄▄
|
||||
// ██ ▀ █▄ ▀██▄ ▀ ▄█ ▄▀▀ █ │ ▀█▄ ▄▀██ ▄█▄█ ██▀▄ ██ ▄███
|
||||
// █ █ █ ▀▀ ▄█ █ █ ▀▄█ █▄ │ ▄▄█▀ ▀▄██ ██ █ ██▀ ▀█▄ ▀█▄▄
|
||||
// ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀────────┘ ▀▀
|
||||
// Library configuration
|
||||
//─────────────────────────────────────────────────────────────────────────────
|
||||
#pragma once
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// BUILD
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Target
|
||||
// - TARGET_ROM_8K 8 KB ROM in page 1 (4000h ~ 5FFFh)
|
||||
// - TARGET_ROM_8K_P2 8 KB ROM in page 2 (8000h ~ 9FFFh)
|
||||
// - TARGET_ROM_16K 16 KB ROM in page 1 (4000h ~ 7FFFh)
|
||||
// - TARGET_ROM_16K_P2 16 KB ROM in page 2 (8000h ~ BFFFh)
|
||||
// - TARGET_ROM_32K 32 KB ROM in page 1&2 (4000h ~ BFFFh)
|
||||
// - TARGET_ROM_48K 48 KB ROM in page 0-2 (0000h ~ BFFFh)
|
||||
// - TARGET_ROM_48K_ISR 48 KB ROM in page 0-2 (0000h ~ BFFFh) with ISR replacement
|
||||
// - TARGET_ROM_64K 64 KB ROM in page 0-3 (0000h ~ FFFFh)
|
||||
// - TARGET_ROM_64K_ISR 64 KB ROM in page 0-3 (0000h ~ FFFFh) with ISR replacement
|
||||
// - TARGET_ROM_ASCII8 ASCII-8: 8KB segments for a total of 64 KB to 2 MB
|
||||
// - TARGET_ROM_ASCII16 ASCII-16: 16KB segments for a total of 64 KB to 4 MB
|
||||
// - TARGET_ROM_KONAMI Konami MegaROM (aka Konami4): 8 KB segments for a total of 64 KB to 2 MB
|
||||
// - TARGET_ROM_KONAMI_SCC Konami MegaROM SCC (aka Konami5): 8 KB segments for a total of 64 KB to 2 MB
|
||||
// - TARGET_DOS1 MSX-DOS 1 program (starting at 0100h)
|
||||
// - TARGET_DOS2 MSX-DOS 2 program (starting at 0100h)
|
||||
// - TARGET_DOS0 Direct program boot from disk (starting at 0100h)
|
||||
// - TARGET_BIN BASIC binary program (starting at 8000h)
|
||||
// - TARGET_BIN_USR BASIC USR binary driver (starting at C000h)
|
||||
// TARGET is defined by the build tool
|
||||
|
||||
// MSX version
|
||||
// - MSX_1 ........................ MSX1
|
||||
// - MSX_2 ........................ MSX2
|
||||
// - MSX_12 ....................... MSX1 and 2 (support each)
|
||||
// - MSX_2K ....................... Korean MSX2 (SC9 support)
|
||||
// - MSX_2P ....................... MSX2+
|
||||
// - MSX_22P ...................... MSX2 and 2+ (support each)
|
||||
// - MSX_122P ..................... MSX1, 2 and 2+ (support each)
|
||||
// - MSX_0 ........................ MSX0 (MSX2+)
|
||||
// - MSX_TR ....................... MSX turbo R
|
||||
// - MSX_3 ........................ MSX3
|
||||
// MSX_VERSION is defined by the build tool
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// BIOS MODULE
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Default slot BIOS access
|
||||
// - BIOS_CALL_DIRECT ............. Use direct access to Bios routines (ROM slot must be selected in corresponding page)
|
||||
// - BIOS_CALL_INTERSLOT .......... Use inter-slot access to Bios routines (through CALSLT routine)
|
||||
#define BIOS_CALL_MAINROM BIOS_CALL_DIRECT
|
||||
#define BIOS_CALL_SUBROM BIOS_CALL_INTERSLOT
|
||||
#define BIOS_CALL_DISKROM BIOS_CALL_INTERSLOT
|
||||
|
||||
// MAIN-Bios module setting
|
||||
#define BIOS_USE_MAINROM TRUE // Allow use of Main-ROM routines
|
||||
#define BIOS_USE_VDP TRUE // Give access to Main-ROM routines related to VDP
|
||||
#define BIOS_USE_PSG TRUE // Give access to Main-ROM routines related to PSG
|
||||
#define BIOS_USE_SUBROM TRUE // Allow use of Sub-ROM routines (MSX2/2+/turbo R)
|
||||
#define BIOS_USE_DISKROM TRUE // Allow use of Disk-ROM routines
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// VDP MODULE
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// VRAM addressing unit
|
||||
// - VDP_VRAM_ADDR_14 ............. Use 14-bits 16K VRAM addressing for MSX1 (u16)
|
||||
// - VDP_VRAM_ADDR_17 ............. Use 17-bits 128K VRAM addressing for MSX2/2+/turbo R (u32)
|
||||
#define VDP_VRAM_ADDR VDP_VRAM_ADDR_17
|
||||
|
||||
// VDP X/Y units
|
||||
// - VDP_UNIT_U8 .................. X and Y use 8-bits values
|
||||
// - VDP_UNIT_X16 ................. X use 16-bits and Y use 8-bits values
|
||||
// - VDP_UNIT_Y16 ................. X use 8-bits and Y use 16-bits values
|
||||
// - VDP_UNIT_U16 ................. X and Y use 16-bits values
|
||||
#define VDP_UNIT VDP_UNIT_X16
|
||||
|
||||
// VDP screen modes (additionnal limitations come from the selected MSX_VERSION)
|
||||
#define VDP_USE_MODE_T1 TRUE // MSX1 Screen 0 Width 40
|
||||
#define VDP_USE_MODE_G1 TRUE // MSX1 Screen 1
|
||||
#define VDP_USE_MODE_G2 TRUE // MSX1 Screen 2
|
||||
#define VDP_USE_MODE_MC TRUE // MSX1 Screen 3
|
||||
#define VDP_USE_MODE_T2 TRUE // MSX2 Screen 0 Width 80
|
||||
#define VDP_USE_MODE_G3 TRUE // MSX2 Screen 4
|
||||
#define VDP_USE_MODE_G4 TRUE // MSX2 Screen 5
|
||||
#define VDP_USE_MODE_G5 TRUE // MSX2 Screen 6
|
||||
#define VDP_USE_MODE_G6 TRUE // MSX2 Screen 7
|
||||
#define VDP_USE_MODE_G7 TRUE // MSX2/2+ Screen 8, 10, 11 & 12
|
||||
|
||||
#define VDP_USE_VRAM16K TRUE // Use 16K VRAM access functions on MSX2
|
||||
#define VDP_USE_SPRITE TRUE // Use sprite handling functions
|
||||
#define VDP_USE_COMMAND TRUE // Use VDP commands wrapper functions
|
||||
#define VDP_USE_CUSTOM_CMD FALSE // Use custom VDP commands through data buffer
|
||||
#define VDP_AUTO_INIT TRUE // Call VDP_Initialize() at the first call to VDP_SetMode()
|
||||
#define VDP_USE_UNDOCUMENTED TRUE // Allow the use of undocumented screen mode (WIP)
|
||||
#define VDP_USE_VALIDATOR TRUE // Handle some option specific for each VDP mode (highly recommended)
|
||||
#define VDP_USE_DEFAULT_PALETTE FALSE // Add data for default MSX2 palette
|
||||
#define VDP_USE_MSX1_PALETTE FALSE // Add data for default MSX1 palette
|
||||
#define VDP_USE_DEFAULT_SETTINGS TRUE // Auto-initialization of common VDP feature
|
||||
#define VDP_USE_16X16_SPRITE TRUE // Use 16x16 sprites mode
|
||||
#define VDP_USE_RESTORE_S0 TRUE // Do restore of status register pointer to S#0 (needed onlt for default BIOS ISR)
|
||||
#define VDP_USE_PALETTE16 FALSE // Use 16 entries palette (use only 15 entries otherwise)
|
||||
|
||||
// ISR protection while modifiying VDP registers
|
||||
// - VDP_ISR_SAFE_NONE ............ No ISR protection (for program not using VDP interruption)
|
||||
// - VDP_ISR_SAFE_DEFAULT ......... Protect only VDP register pair writing (default behavior; ISR can read/write registers but VRAM ones)
|
||||
// - VDP_ISR_SAFE_ALL ............. Protect all VDP writing process
|
||||
#define VDP_ISR_SAFE_MODE VDP_ISR_SAFE_DEFAULT
|
||||
|
||||
// Initial screen mode setting
|
||||
// - VDP_INIT_OFF ................. Force option to be disable
|
||||
// - VDP_INIT_ON .................. Force option to be enable
|
||||
// - VDP_INIT_AUTO ................ Determining the best value for the context
|
||||
// - VDP_INIT_DEFAULT ............. Keep default value
|
||||
#define VDP_INIT_50HZ VDP_INIT_DEFAULT
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// V9990 MODULE
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// V9990 screen modes support
|
||||
#define V9_USE_MODE_P1 TRUE // Tile mode 0 256x212
|
||||
#define V9_USE_MODE_P2 TRUE // Tile mode 1 512x212
|
||||
#define V9_USE_MODE_B0 TRUE // Bitmap mode 1 192x240 (Undocumented v9990 mode)
|
||||
#define V9_USE_MODE_B1 TRUE // Bitmap mode 1 256x212
|
||||
#define V9_USE_MODE_B2 TRUE // Bitmap mode 2 384x240
|
||||
#define V9_USE_MODE_B3 TRUE // Bitmap mode 3 512x212
|
||||
#define V9_USE_MODE_B4 TRUE // Bitmap mode 4 768x240
|
||||
#define V9_USE_MODE_B5 TRUE // Bitmap mode 5 640x400 (VGA)
|
||||
#define V9_USE_MODE_B6 TRUE // Bitmap mode 6 640x480 (VGA)
|
||||
#define V9_USE_MODE_B7 TRUE // Bitmap mode 7 1024x212 (Undocumented v9990 mode)
|
||||
|
||||
#define V9_INT_PROTECT TRUE // VRAM access protection mode against interruption
|
||||
// Palette input data format
|
||||
// - V9_PALETTE_YSGBR_16 .......... 16 bits RGB + Ys [Ys|G|G|G|G|G|R|R] [R|R|R|B|B|B|B|B]
|
||||
// - V9_PALETTE_GBR_16 ............ 16 bits RGB [0|G|G|G|G|G|R|R] [R|R|R|B|B|B|B|B]
|
||||
// - V9_PALETTE_RGB_24 ............ 24 bits RGB [0|0|0|R|R|R|R|R] [0|0|0|G|G|G|G|G] [0|0|0|B|B|B|B|B]
|
||||
#define V9_PALETTE_MODE V9_PALETTE_RGB_24
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// INPUT MODULE
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Input module setting
|
||||
#define INPUT_USE_JOYSTICK TRUE // Add functions to handle joystick using I/O port
|
||||
#define INPUT_USE_KEYBOARD TRUE // Add functions to handle keyboard using I/O port
|
||||
#define INPUT_USE_MOUSE TRUE // Add support for Mouse handling functions
|
||||
#define INPUT_USE_DETECT TRUE // Add feature to detect device plugged in General purpose ports
|
||||
#define INPUT_USE_ISR_PROTECTION TRUE // Disable interruptions while access PSG registers (needed if you use BIOS or access PSG in your own ISR)
|
||||
#define INPUT_JOY_UPDATE FALSE // Add function to update all joystick states at once
|
||||
#define INPUT_HOLD_SIGNAL FALSE // Determines whether functions that modify signals should keep the state of those they don't need to modify (which slows functions down a bit)
|
||||
// Key update handler
|
||||
// Keep FALSE: the buffered mode stores state in the BIOS NEWKEY/OLDKEY work
|
||||
// area, which C-BIOS does not maintain in the standard matrix format (phantom
|
||||
// key edges). Direct reads are safe if sampled right after Halt() — see main().
|
||||
#define INPUT_KB_UPDATE FALSE // Add function to update all keyboard rows at once
|
||||
#define INPUT_KB_UPDATE_MIN 0 // First row to update
|
||||
#define INPUT_KB_UPDATE_MAX 8 // Last row to update (10 for numerical-pad, 8 otherwise)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// PADDLE MODULE
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Paddle module setting
|
||||
#define PADDLE_USE_CALIB TRUE // Add functions paddle calibration feature
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// MEMORY MODULE
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#define MEM_USE_VALIDATOR FALSE // Activate validator to handle invalide input value
|
||||
#define MEM_USE_FASTCOPY FALSE // Add support for fast-copy function (using unrolled-LDI loop)
|
||||
#define MEM_USE_FASTSET FALSE // Add support for fast-set function (using unrolled-LDI loop)
|
||||
#define MEM_USE_DYNAMIC FALSE // Add support for malloc style dynamic allocator
|
||||
#define MEM_USE_BUILTIN TRUE // Use SDCC built-in memcpy and memset function instead of MSXgl ones
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// MSX-DOS MODULE
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#define DOS_USE_FCB TRUE // Add support for file managment features through FCB structure
|
||||
#define DOS_USE_HANDLE TRUE // Add support for file managment features through file handle
|
||||
#define DOS_USE_UTILITIES TRUE // Add support for file managment features through filename
|
||||
#define DOS_USE_VALIDATOR TRUE // Add support for last error backup and return value validation
|
||||
#define DOS_USE_ERROR_HANDLER TRUE // Add support for MSX-DOS 1 error handler callback
|
||||
#define DOS_USE_BIOSCALL TRUE // Add support for call to BIOS routines
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CLOCK MODULE
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#define RTC_USE_CLOCK TRUE // Add functions to handle date and time
|
||||
#define RTC_USE_CLOCK_EXTRA TRUE // Add extra date and time functions that require additional data
|
||||
#define RTC_USE_SAVEDATA TRUE // Add functions to read/write into the CMOS
|
||||
#define RTC_USE_SAVESIGNED TRUE // Add signature handling to validate CMOS I/O
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// DRAW MODULE
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// PRINT MODULE
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Print module setting
|
||||
#define PRINT_USE_TEXT TRUE // Allow use of Text font (T1-T2, G1-G3)
|
||||
#define PRINT_USE_BITMAP TRUE // Allow use of Bitmap font (G4-G7)
|
||||
#define PRINT_USE_VRAM TRUE // Allow use of VRAM stored font (G4-G7)
|
||||
#define PRINT_USE_SPRITE TRUE // Allow use of Sprite font (G3-G7)
|
||||
#define PRINT_USE_FX_SHADOW TRUE // [Bitmap] Allow use of text shadow
|
||||
#define PRINT_USE_FX_OUTLINE TRUE // [Bitmap] Allow use of text outline
|
||||
#define PRINT_USE_2_PASS_FX FALSE // [Bitmap] Allow use 2-pass FX render to prevent character overlap
|
||||
#define PRINT_USE_GRAPH TRUE // Allow use of character lines and boxes
|
||||
#define PRINT_USE_VALIDATOR TRUE // Add validator character code
|
||||
#define PRINT_USE_UNIT FALSE // Display integer type (h: hexadecimal, b: binary)
|
||||
#define PRINT_USE_FORMAT TRUE // Add printf type function
|
||||
#define PRINT_USE_32B TRUE // Allow to print 32-bits integers
|
||||
#define PRINT_USE_MULTIFONT FALSE // Use multiple fonts (each one with its own data structure)
|
||||
#define PRINT_SKIP_SPACE TRUE // Skill space character
|
||||
#define PRINT_COLOR_NUM 12 // 1 color per line
|
||||
// Character width
|
||||
// - PRINT_WIDTH_1 (text mode)
|
||||
// - PRINT_WIDTH_6
|
||||
// - PRINT_WIDTH_8
|
||||
// - PRINT_WIDTH_X (variable)
|
||||
#define PRINT_WIDTH PRINT_WIDTH_X
|
||||
// Character height
|
||||
// - PRINT_HEIGHT_1 (text mode)
|
||||
// - PRINT_HEIGHT_8
|
||||
// - PRINT_HEIGHT_X (variable)
|
||||
#define PRINT_HEIGHT PRINT_HEIGHT_X
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// SPRITE FX MODULE
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Supported sprite size
|
||||
#define SPRITEFX_USE_8x8 TRUE // Use 8x8 pixels effects
|
||||
#define SPRITEFX_USE_16x16 TRUE // Use 16x16 pixels effects
|
||||
|
||||
// Supported effect
|
||||
#define SPRITEFX_USE_CROP TRUE // Use cropping effect
|
||||
#define SPRITEFX_USE_FLIP TRUE // Use flipping effect
|
||||
#define SPRITEFX_USE_MASK TRUE // Use masking effect
|
||||
#define SPRITEFX_USE_ROTATE TRUE // Use rotating effect
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// GAME MAIN MODULE
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Game state setting
|
||||
#define GAME_USE_STATE TRUE // Add state machine features
|
||||
#define GAME_USE_VSYNC TRUE // Add vertical synchronization features
|
||||
#define GAME_USE_LOOP TRUE // Add game main loop with call to v-synch and state
|
||||
#define GAME_USE_SYNC_50HZ TRUE // Force 50Hz synchronization on 60Hz machine
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// GAME PAWN MODULE
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Pawn setting
|
||||
#define PAWN_ID_PER_LAYER FALSE // Set sprite ID for each layer (otherwise set per pawn)
|
||||
#define PAWN_USE_RT_LOAD TRUE // Load sprite pattern data on the fly (real-time)
|
||||
#define PAWN_USE_SPRT_FX TRUE // Allow sprite effects (crop, flip, mask, rotate)
|
||||
#define PAWN_SPRITE_SIZE 16 // Sprite size mode (8 for 8x8 pixel mode, or 16 for 16x16)
|
||||
#define PAWN_BLEND_OFFSET 12 // Sprite pattern offset for blending mode
|
||||
#define PAWN_USE_PHYSICS TRUE // Add physics and collision features
|
||||
// Pawn coordinate unit
|
||||
// - PAWN_UNIT_SCREEN Default screen (pixel) unit (8-bit unsigned int)
|
||||
// - PAWN_UNIT_QMN(n) Fixed-point (Qm.n) unit (16-bit signed int)
|
||||
#define PAWN_UNIT PAWN_UNIT_SCREEN
|
||||
// Pawn's bound (can be fixed for all pawn, or setable for each one)
|
||||
#define PAWN_BOUND_X PAWN_BOUND_CUSTOM
|
||||
#define PAWN_BOUND_Y PAWN_BOUND_CUSTOM
|
||||
// Collision position options for each pawn's side
|
||||
// - PAWN_COL_0
|
||||
// - PAWN_COL_25
|
||||
// - PAWN_COL_50
|
||||
// - PAWN_COL_75
|
||||
// - PAWN_COL_100
|
||||
#define PAWN_COL_DOWN (PAWN_COL_25|PAWN_COL_75)
|
||||
#define PAWN_COL_UP PAWN_COL_50
|
||||
#define PAWN_COL_RIGHT PAWN_COL_50
|
||||
#define PAWN_COL_LEFT PAWN_COL_50
|
||||
// Options to determine which border collide or trigger events
|
||||
// - PAWN_BORDER_NONE
|
||||
// - PAWN_BORDER_DOWN
|
||||
// - PAWN_BORDER_UP
|
||||
// - PAWN_BORDER_RIGHT
|
||||
// - PAWN_BORDER_LEFT
|
||||
#define PAWN_BORDER_EVENT (PAWN_BORDER_UP|PAWN_BORDER_DOWN|PAWN_BORDER_LEFT|PAWN_BORDER_RIGHT)
|
||||
#define PAWN_BORDER_BLOCK (PAWN_BORDER_UP|PAWN_BORDER_DOWN|PAWN_BORDER_LEFT|PAWN_BORDER_RIGHT)
|
||||
// Top/bottom border position (in pixel)
|
||||
#define PAWN_BORDER_MIN_Y 0 // High border Y coordinade
|
||||
#define PAWN_BORDER_MAX_Y 211 // Low border Y coordinate
|
||||
#define PAWN_TILEMAP_WIDTH 32 // Width of the tiles map
|
||||
#define PAWN_TILEMAP_HEIGHT 27 // Height of the tiles map
|
||||
// Collision tilemap source
|
||||
// - PAWN_TILEMAP_SRC_AUTO ........ Backward compatibility option
|
||||
// - PAWN_TILEMAP_SRC_RAM ......... Tilemap located in a buffer in RAM (best for performance)
|
||||
// - PAWN_TILEMAP_SRC_VRAM ........ Tilemap located in VRAM (slow but don't need additionnal data)
|
||||
// - PAWN_TILEMAP_SRC_V9 .......... Tilemap located in V9990's VRAM
|
||||
#define PAWN_TILEMAP_SRC PAWN_TILEMAP_SRC_RAM
|
||||
// Pawn's sprite mode
|
||||
// - PAWN_SPT_MODE_AUTO ........... Backward compatibility option
|
||||
// - PAWN_SPT_MODE_MSX1 ........... Sprite Mode 1 (MSX1 screens)
|
||||
// - PAWN_SPT_MODE_MSX2 ........... Sprite Mode 2 unicolor (MSX2 screens)
|
||||
// - PAWN_SPT_MODE_MSX2_MULTI ..... Sprite Mode 2 multi-color (MSX2 screens)
|
||||
// - PAWN_SPT_MODE_MSX12 .......... Sprite Mode 1 & 2 unicolor (MSX1 & MSX2 screens)
|
||||
// - PAWN_SPT_MODE_V9_P1 .......... V9990 sprite in P1 mode
|
||||
// - PAWN_SPT_MODE_V9_P2 .......... V9990 sprite in P2 mode
|
||||
#define PAWN_SPT_MODE PAWN_SPT_MODE_MSX2
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// GAME MENU MODULE
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#define MENU_USE_DEFAULT_CALLBACK TRUE // Use default input/print callback
|
||||
#define MENU_SCREEN_WIDTH MENU_VARIABLE // Screen width
|
||||
#define MENU_FRAME_X 0 // Frame position X
|
||||
#define MENU_FRAME_Y 6 // Frame position Y
|
||||
#define MENU_FRAME_WIDTH 32 // Frame width
|
||||
#define MENU_FRAME_HEIGHT 8 // Frame height
|
||||
#define MENU_CHAR_CLEAR '\0' // Clear character
|
||||
#define MENU_CHAR_CURSOR '@' // Cursor character
|
||||
#define MENU_CHAR_TRUE 'O' // True character
|
||||
#define MENU_CHAR_FALSE 'X' // False character
|
||||
#define MENU_CHAR_LEFT '<' // Left edit character
|
||||
#define MENU_CHAR_RIGHT '>' // Right edit character
|
||||
#define MENU_TITLE_X 4 // Title position X
|
||||
#define MENU_TITLE_Y 6 // Title position Y
|
||||
#define MENU_ITEM_X 6 // Item label X position
|
||||
#define MENU_ITEM_Y 8 // Item label X position
|
||||
#define MENU_ITEM_X_GOTO 6 // Goto type item label X position
|
||||
#define MENU_ITEM_ALIGN MENU_ITEM_ALIGN_LEFT // Item label alignment
|
||||
#define MENU_ITEM_ALIGN_GOTO MENU_ITEM_ALIGN_LEFT // Goto type item label alignment
|
||||
#define MENU_VALUE_X 14 // Item value X position
|
||||
// Type of cursor
|
||||
// - MENU_CURSOR_MODE_NONE ........ No cursor
|
||||
// - MENU_CURSOR_MODE_CHAR ........ Character cursor
|
||||
// - MENU_CURSOR_MODE_SPRT ........ Sprite cursor
|
||||
#define MENU_CURSOR_MODE MENU_CURSOR_MODE_CHAR
|
||||
#define MENU_CURSOR_OFFSET (-2) // Cursor X position offset
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// GAME QUEST VARIABLES MODULE
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#define BITFIELD_MAX 64 // Maximum number of quest variables (8 variables per byte)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// STRING MODULE
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Support for integer to ASCII string converter functions
|
||||
#define STRING_USE_FROM_INT8 TRUE // Signed 8-bits integer to string
|
||||
#define STRING_USE_FROM_UINT8 TRUE // Unsigned 8-bits integer to string
|
||||
#define STRING_USE_FROM_INT16 TRUE // Signed 16-bits integer to string
|
||||
#define STRING_USE_FROM_UINT16 TRUE // Unsigned 16-bits integer to string
|
||||
|
||||
// Support for sprintf style formating function
|
||||
#define STRING_USE_FORMAT TRUE
|
||||
#define STRING_USE_INT32 TRUE // Add support for 32-bits integer
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// SCROLL MODULE
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Allow horizontal and/or vertical scrolling
|
||||
#define SCROLL_HORIZONTAL TRUE // Activate horizontal scrolling
|
||||
#define SCROLL_VERTICAL TRUE // Activate vertical scrolling
|
||||
// Source data info
|
||||
#define SCROLL_SRC_X 64 // Start X coordinate of the source data
|
||||
#define SCROLL_SRC_Y 0 // Start Y coordinate of the source data
|
||||
#define SCROLL_SRC_W 128 // Width of the source data
|
||||
#define SCROLL_SRC_H 24 // Height of the source data
|
||||
// Destination data info
|
||||
#define SCROLL_DST_X 0 // Destination x coordinate (in layout table)
|
||||
#define SCROLL_DST_Y 2 // Destination y coordinate (in layout table)
|
||||
#define SCROLL_DST_W 32 // Destination width
|
||||
#define SCROLL_DST_H 20 // Destination height
|
||||
#define SCROLL_SCREEN_W 32 // Screen width in tile number
|
||||
// Allow scroll data looping (only for horizontal scrolling)
|
||||
#define SCROLL_WRAP TRUE
|
||||
// Use screen position adjust register (allow per-pixel scrolling) [MSX2]
|
||||
#define SCROLL_ADJUST TRUE // Global ajustement
|
||||
#define SCROLL_ADJUST_SPLIT TRUE // Destination windows ajustement using screen split
|
||||
// Use sprite mask (allow smooth per-pixel scrolling) [MSX2]
|
||||
#define SCROLL_MASK TRUE // Use sprite to mask
|
||||
#define SCROLL_MASK_ID 0 // First sprite ID to use
|
||||
#define SCROLL_MASK_COLOR COLOR_BLACK // Must be the same than border color
|
||||
#define SCROLL_MASK_PATTERN 0 // Sprite pattern to use
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// TILE
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#define TILE_WIDTH 8 // Tile width
|
||||
#define TILE_HEIGHT 8 // Tile height
|
||||
#define TILE_BPP 4 // Screen bits-per-pixel
|
||||
#define TILE_SCREEN_WIDTH 256 // Screen width
|
||||
#define TILE_SCREEN_HEIGHT 212 // Screen height
|
||||
#define TILE_USE_SKIP TRUE // Skip drawing of a given index
|
||||
#define TILE_SKIP_INDEX 0 // The index tile to skip
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// AUDIO
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// PSG options
|
||||
// - PSG_INTERNAL ................. Use internal PSG chip (port A0-A2)
|
||||
// - PSG_EXTERNAL ................. Use external PSG chip (port 10-12)
|
||||
// - PSG_BOTH ..................... Use both internal and external PSG chips
|
||||
#define PSG_CHIP PSG_INTERNAL
|
||||
// - PSG_DIRECT ................... Function set directly the PSG registers
|
||||
// - PSG_INDIRECT ................. Function set a buffer (Apply() function must be call once a frame)
|
||||
#define PSG_ACCESS PSG_INDIRECT
|
||||
#define PSG_USE_NOTES FALSE // Add notes table to convert note to tone
|
||||
#define PSG_USE_EXTRA TRUE // Add helper functions to handle PSG settings
|
||||
#define PSG_USE_RESUME TRUE // Add function to allow playback pause and resume
|
||||
|
||||
// MSX-Music options
|
||||
#define MSXAUDIO_USE_RESUME TRUE // Add function to allow playback pause and resume
|
||||
|
||||
// MSX-Audio options
|
||||
#define MSXMUSIC_USE_RESUME TRUE // Add function to allow playback pause and resume
|
||||
|
||||
// SCC options
|
||||
#define SCC_USE_EXTA TRUE // Add helper functions to handle PSG settings
|
||||
#define SCC_USE_RESUME TRUE // Add function to allow playback pause and resume
|
||||
// - SCC_SLOT_DIRECT .............. Program on a SCC cartridge
|
||||
// - SCC_SLOT_FIXED ............... Fixed slot-id (non-expanded second cartridge slot)
|
||||
// - SCC_SLOT_USER ................ Defined by the user
|
||||
// - SCC_SLOT_AUTO ................ First auto-detected cartridge
|
||||
#define SCC_SLOT_MODE SCC_SLOT_AUTO
|
||||
|
||||
// VGM supported chip
|
||||
#define VGM_USE_PSG TRUE // Allow PSG data parsing and audio output
|
||||
#define VGM_USE_MSXMUSIC TRUE // Allow MSX-Music data parsing and audio output
|
||||
#define VGM_USE_MSXAUDIO TRUE // Allow MSX-Audio data parsing and audio output
|
||||
#define VGM_USE_SCC TRUE // Allow SCC data parsing and audio output
|
||||
|
||||
// PCM-Encoder supported frequency (more than 1 value allowed)
|
||||
// - PCMENC_NONE, PCMENC_8K, PCMENC_11K, PCMENC_22K and PCMENC_44K
|
||||
#define PCMENC_FREQ PCMENC_8K | PCMENC_11K | PCMENC_22K | PCMENC_44K
|
||||
|
||||
// PCMPlay
|
||||
// - PCMPLAY_8K or PCMPLAY_11K
|
||||
#define PCMPLAY_FREQ PCMPLAY_8K
|
||||
#define PCMPLAY_USE_RESTORE FALSE
|
||||
|
||||
// PT3 options
|
||||
#define PT3_SKIP_HEADER TRUE // Don't use PT3 data header (first 100 bytes must be truncated)
|
||||
#define PT3_AUTOPLAY TRUE // Play music automatically
|
||||
#define PT3_EXTRA TRUE // Add helper functions
|
||||
|
||||
// ayFX options
|
||||
// - AYFX_BUFFER_DEFAULT .......... Use PSG module's PSG registers buffer
|
||||
// - AYFX_BUFFER_PSG2 ............. Use PSG module's 2nd PSG registers buffer (only if PSG_CHIP == PSG_BOTH)
|
||||
// - AYFX_BUFFER_PT3 .............. Use PT3 module's PSG registers buffer
|
||||
#define AYFX_BUFFER AYFX_BUFFER_PT3
|
||||
|
||||
// TriloTracker options
|
||||
#define TRILO_USE_SFXPLAY TRUE // Add SFX playback through Trilo SCC player (ayFX + SCC format)
|
||||
#define TRILO_USE_TREMOLO TRUE // Add support for tremolo effect (little bit expensive)
|
||||
#define TRILO_USE_TAIL FALSE // Add tail to prevent volume to fall to zero
|
||||
|
||||
// LVGM replayer options
|
||||
#define LVGM_USE_PSG TRUE // Add parser for PSG data
|
||||
#define LVGM_USE_MSXMUSIC TRUE // Add parser for MSX-Music data
|
||||
#define LVGM_USE_MSXAUDIO TRUE // Add parser for MSX-Audio data
|
||||
#define LVGM_USE_SCC TRUE // Add parser for Konami SCC data
|
||||
#define LVGM_USE_SCCI FALSE // Add parser for Konami SCC+ data
|
||||
#define LVGM_USE_PSG2 FALSE // Add parser for secondary PSG data
|
||||
#define LVGM_USE_OPL4 FALSE // Add parser for OPL4 data
|
||||
#define LVGM_USE_NOTIFY TRUE // Add parser for PSG data
|
||||
|
||||
// WYZ Tracker replayer options
|
||||
// Channels number
|
||||
// - WYZ_3CH
|
||||
// - WYZ_6CH
|
||||
#define WYZ_CHANNELS WYZ_3CH // Number of supported channels (can be 3 for 1 PSG or 6 for 2 PSG)
|
||||
#define WYZ_USE_DIRECT_ACCESS FALSE // Send data directly to PSG registers (otherwise, write in a RAM buffer)
|
||||
#define WYZ_CHAN_BUFFER_SIZE 0x20 // Size of the channel buffer
|
||||
|
||||
// Arkos Tracker options
|
||||
#define ARKOS_BUFFER_ADDR 0xF000 // Replayer working area address in RAM
|
||||
#define ARKOS_ISR_PROTECTION FALSE // Prevent interruption during audio update
|
||||
#define ARKOS_SFX_START_IDX 0 // Do SFX indexes start at 0 or 1? Default is 0 but Arkos Tracker use 1
|
||||
#define ARKOS_USE_EVENT FALSE // Support for event callback function (AKG replayer only)
|
||||
|
||||
// NDP player options
|
||||
#define NDP_USE_INDERCT FALSE // Output music data into RAM buffer (need to use with ayFX for example)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// MATH MODULE
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Random methods
|
||||
// - RANDOM_8_NONE ................ No 8-bits random
|
||||
// - RANDOM_8_REGISTER ............ R Register value (7-bits)
|
||||
// - RANDOM_8_RACC ................ R Register accumulation (7-bits)
|
||||
// - RANDOM_8_ION ................. Ion Random
|
||||
// - RANDOM_8_MEMORY .............. Memory Peek from R
|
||||
#define RANDOM_8_METHOD RANDOM_8_ION
|
||||
// - RANDOM_16_NONE ............... No 16-bits random
|
||||
// - RANDOM_16_LINEAR ............. Linear congruential
|
||||
// - RANDOM_16_XORSHIFT ........... XOR Shift
|
||||
// - RANDOM_16_LFSR_LCG ........... Combined LFSR/LCG
|
||||
#define RANDOM_16_METHOD RANDOM_16_XORSHIFT
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// COMPRESS
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// RLEp compression
|
||||
#define COMPRESS_USE_RLEP TRUE // Use RLEp unpacker
|
||||
#define COMPRESS_USE_RLEP_DEFAULT TRUE // Data include the default value (0 otherwise)
|
||||
#define COMPRESS_USE_RLEP_FIXSIZE FALSE // Gize the data size as function input (loop up to terminator otherwise)
|
||||
|
||||
// Pletter compression
|
||||
#define PLETTER_LENGTHINDATA FALSE // Is length included in data (first 2 bytes)
|
||||
// Disable interruption mode
|
||||
// - PLETTER_DI_NONE .............. Don't disable interruption
|
||||
// - PLETTER_DI_FULL .............. Disable interruption during the whole function
|
||||
// - PLETTER_DI_LOOP .............. Disable interruption during VRAM write loop
|
||||
#define PLETTER_DI_MODE PLETTER_DI_LOOP
|
||||
// VRAM write timing mode
|
||||
// - PLETTER_WRITE_SAFE ........... Safe VRAM write speed (30 t-states)
|
||||
// - PLETTER_WRITE_NODISPLAY ...... Safe VRAM write speed when screen display disable (22 t-states)
|
||||
// - PLETTER_WRITE_MINIMAL ........ Minimal wait beetween write (17 t-states)
|
||||
// - PLETTER_WRITE_QUICK .......... No wait beetween write (12 t-states)
|
||||
// - PLETTER_WRITE_AUTO ........... Determine the worst case according to selected screen mode (12~30 t-states)
|
||||
#define PLETTER_WRITE_MODE PLETTER_WRITE_SAFE
|
||||
|
||||
// BitBuster compression
|
||||
// VRAM write timing mode
|
||||
// - BITBUSTER_WRITE_SAFE ......... Safe VRAM write speed (include nop between write)
|
||||
// - BITBUSTER_WRITE_QUICK ........ No wait beetween write
|
||||
#define BITBUSTER_WRITE_MODE BITBUSTER_WRITE_SAFE
|
||||
|
||||
// ZX0 compression
|
||||
// Unpack mode
|
||||
// - ZX0_MODE_STANDARD ............ Standard routine: 68 bytes only
|
||||
// - ZX0_MODE_TURBO ............... Turbo routine: 126 bytes, about 21% faster
|
||||
// - ZX0_MODE_FAST ................ Fast routine: 187 bytes, about 25% faster
|
||||
// - ZX0_MODE_MEGA ................ Mega routine: 673 bytes, about 28% faster
|
||||
#define ZX0_MODE ZX0_MODE_STANDARD
|
||||
|
||||
// LZ48 compression
|
||||
// - LZ48_MODE_STANDARD ........... Standard routine
|
||||
// - LZ48_MODE_SPEED .............. Version optimized for speed
|
||||
// - LZ48_MODE_SIZE ............... Version optimized for size
|
||||
#define LZ48_MODE LZ48_MODE_STANDARD
|
||||
|
||||
// MSXi compressor support
|
||||
#define MSXi_USE_COMP_NONE TRUE
|
||||
#define MSXi_USE_COMP_CROP16 TRUE
|
||||
#define MSXi_USE_COMP_CROP32 TRUE
|
||||
#define MSXi_USE_COMP_CROP256 TRUE
|
||||
#define MSXi_USE_COMP_CROPLINE16 TRUE
|
||||
#define MSXi_USE_COMP_CROPLINE32 TRUE
|
||||
#define MSXi_USE_COMP_CROPLINE256 TRUE
|
||||
#define MSXi_USE_COMP_RLE0 TRUE
|
||||
#define MSXi_USE_COMP_RLE4 TRUE
|
||||
#define MSXi_USE_COMP_RLE8 TRUE
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// NINJATAP MODULE
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Supported driver(s)
|
||||
// - NTAP_DRIVER_MSXGL ............ MSXgl custom driver (based on DM-System2 one)
|
||||
// - NTAP_DRIVER_GIGAMIX .......... Original Gigamix's DM-System2 driver
|
||||
// - NTAP_DRIVER_SHINOBI .......... Shinobi Tap driver by Danjovic
|
||||
#define NTAP_DRIVER NTAP_DRIVER_MSXGL | NTAP_DRIVER_GIGAMIX | NTAP_DRIVER_SHINOBI
|
||||
#define NTAP_USE_PREVIOUS TRUE // Backup previous data to allow push/release detection
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// PAC MODULE
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#define PAC_USE_SIGNATURE TRUE // Handle application signature to validate saved data
|
||||
#define PAC_USE_VALIDATOR TRUE // Add code to validate input parameters
|
||||
#define PAC_DEVICE_MAX 4 // Maximum number of supported PAC devices
|
||||
// SRAM access method
|
||||
// - PAC_ACCESS_DIRECT ............ Direct access to SRAM (must be selected in page 1)
|
||||
// - PAC_ACCESS_BIOS .............. Access through BIOS routines
|
||||
// - PAC_ACCESS_SWITCH_BIOS ....... Access through BIOS routines with BIOS switched in
|
||||
// - PAC_ACCESS_SYSTEM ............ Access through MSXgl routine (no need BIOS)
|
||||
#define PAC_ACCESS PAC_ACCESS_BIOS
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// QR CODE MODULE
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#define QRCODE_VERSION_MIN 1 // The minimum version number supported in the QR Code Model 2 standard
|
||||
#define QRCODE_VERSION_MAX 20 // The maximum version number supported in the QR Code Model 2 standard
|
||||
#define QRCODE_VERSION_CUSTOM FALSE // TRUE: Allow to define version using <QRCode_SetVersion>. FALSE: Use hardcoded min/max version
|
||||
#define QRCODE_USE_BYTE_ONLY TRUE // TRUE: Allow only BYTE mode. FALSE allow all mode including NUMERIC, ALPHANUMERIC, KANJI and ECI.
|
||||
#define QRCODE_USE_EXTRA FALSE // TRUE: Add extra function to generate custom data segments.
|
||||
#define QRCODE_BOOST_ECL FALSE // If boostEcl is TRUE, then the ECC level of the result may be higher than the ecl argument if it can be done without increasing the version. QRCODE_PARAM_CUSTOM: Allow to use <QRCode_SetBoostECL> function.
|
||||
|
||||
#define QRCODE_TINY_VERSION 10 // The version number supported in the QR Code Model 2 standard
|
||||
// Error correction level
|
||||
// - QRCODE_ECC_LOW ............... The QR Code can tolerate about 7% erroneous codewords
|
||||
// - QRCODE_ECC_MEDIUM ............ The QR Code can tolerate about 15% erroneous codewords
|
||||
// - QRCODE_ECC_QUARTILE .......... The QR Code can tolerate about 25% erroneous codewords
|
||||
// - QRCODE_ECC_HIGH .............. The QR Code can tolerate about 30% erroneous codewords
|
||||
#define QRCODE_TINY_ECC QRCODE_ECC_LOW
|
||||
// Mask pattern
|
||||
// - QRCODE_MASK_0 ................ (i + j) % 2 = 0
|
||||
// - QRCODE_MASK_1 ................ i % 2 = 0
|
||||
// - QRCODE_MASK_2 ................ j % 3 = 0
|
||||
// - QRCODE_MASK_3 ................ (i + j) % 3 = 0
|
||||
// - QRCODE_MASK_4 ................ (i / 2 + j / 3) % 2 = 0
|
||||
// - QRCODE_MASK_5 ................ (i * j) % 2 + (i * j) % 3 = 0
|
||||
// - QRCODE_MASK_6 ................ ((i * j) % 3 + i * j) % 2 = 0
|
||||
// - QRCODE_MASK_7 ................ ((i * j) % 3 + i + j) % 2 = 0
|
||||
#define QRCODE_TINY_MASK QRCODE_MASK_0
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// DEBUG & PROFILE
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Debugger options
|
||||
// - DEBUG_DISABLE ................ No debug tool
|
||||
// - DEBUG_EMULICIOUS ............. Debug features for Emulicious
|
||||
// - DEBUG_OPENMSX ................ Debug features for openMSX using 'debugdevice' extension
|
||||
// - DEBUG_OPENMSX_P .............. Debug features for openMSX using PVM script (tools/script/openMSX/debugger_pvm.tcl)
|
||||
#define DEBUG_TOOL DEBUG_DISABLE
|
||||
// Profiler options
|
||||
// - PROFILE_DISABLE .............. No profile tool
|
||||
// - PROFILE_OPENMSX_G ............ Profiler features for openMSX using Grauw script (tools/script/openMSX/profiler_grauw.tcl)
|
||||
// - PROFILE_OPENMSX_S ............ Profiler features for openMSX using Salutte script (tools/script/openMSX/profiler_salutte.tcl)
|
||||
#define PROFILE_TOOL PROFILE_DISABLE
|
||||
#define PROFILE_LEVEL 10
|
||||
@@ -0,0 +1,37 @@
|
||||
// Kissaten Yūgure - MSXgl project configuration
|
||||
// MSX2 · SCREEN 5 · ASCII16 MegaROM (see docs/DESIGN.md §5)
|
||||
|
||||
// ASCII-safe name: used for output filenames (ROM, symbols, intermediates)
|
||||
ProjName = "kissaten";
|
||||
ProjModules = [ ProjName ];
|
||||
// "tool/disk_save" needs "dos" alongside it — see projects/samples/s_save.js
|
||||
LibModules = [ "system", "bios", "vdp", "print", "input", "memory", "math",
|
||||
"tool/disk_save", "dos" ];
|
||||
|
||||
Machine = "2";
|
||||
|
||||
// ASCII16 MegaROM from day one: dialogue, portraits and music banks will not
|
||||
// fit in 32KB (DESIGN.md §5). 16KB segments; segments 0-1 are the fixed main
|
||||
// code at 4000h~BFFFh, segments 2+ are banked data (dialogue, art, music).
|
||||
Target = "ROM_ASCII16";
|
||||
ROMSize = 128;
|
||||
ROMMainSegments = 2;
|
||||
// Enable when banked data/code actually lands (stage 3 dialogue banks);
|
||||
// with it on from day one, RAM globals were getting corrupted at runtime.
|
||||
BankedCall = false;
|
||||
|
||||
CheckVersion = true; // MSX2 required (SCREEN 5, V9938 commands)
|
||||
AddROMSignature = true;
|
||||
|
||||
// Required for disk saving. A cartridge's INIT normally runs *during* the BIOS
|
||||
// slot scan and MSXgl never returns from it, so the Disk ROM's own INIT never
|
||||
// happens — NMBDRV stays 0 and the PHYDIO hook is never patched. This option
|
||||
// instead installs an H.STKE hook and returns to the scan, so the game starts
|
||||
// after the disk system is up. Boot takes visibly longer as a result.
|
||||
ROMDelayBoot = true;
|
||||
|
||||
AppSignature = true;
|
||||
AppCompany = "JL";
|
||||
AppID = "KY";
|
||||
|
||||
Verbose = true;
|
||||
@@ -0,0 +1,131 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Emit the Kissaten palette in every format the art tools want.
|
||||
|
||||
python3 tools/make_palettes.py
|
||||
|
||||
.gpl GIMP / Inkscape / Krita / Aseprite
|
||||
.ase Affinity (Photo, Designer, Publisher), Illustrator
|
||||
.aco Affinity, Photoshop
|
||||
.act Photoshop indexed-colour tables
|
||||
.png 16x1 exact + a swatch strip, and a palette reference for generators
|
||||
|
||||
Two sets are written: the full 16 (scene work) and the 11-colour portrait
|
||||
subset with the sky slots and the transparent index removed.
|
||||
"""
|
||||
import struct, os, sys
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
from pixtool import PALETTE, write_png
|
||||
|
||||
NAMES = ["transparent", "outline", "dark wood", "mid wood", "light wood",
|
||||
"lamp glow", "cream", "muted wall", "dusk deep", "dusk violet",
|
||||
"dusk rose", "horizon amber", "coffee", "coat blue", "skin",
|
||||
"warm white"]
|
||||
PORTRAIT_IDX = [1, 2, 3, 4, 5, 6, 7, 12, 13, 14, 15]
|
||||
OUT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "art")
|
||||
|
||||
|
||||
def gpl(path, cols, names, title):
|
||||
L = [f"GIMP Palette", f"Name: {title}", f"Columns: {len(cols)}", "#"]
|
||||
for c, n in zip(cols, names):
|
||||
L.append(f"{c[0]:3d} {c[1]:3d} {c[2]:3d}\t{n}")
|
||||
open(path, "w").write("\n".join(L) + "\n")
|
||||
|
||||
|
||||
def ase(path, cols, names):
|
||||
blocks = b""
|
||||
for c, n in zip(cols, names):
|
||||
nm = n.encode("utf-16-be") + b"\x00\x00"
|
||||
body = (struct.pack(">H", len(n) + 1) + nm + b"RGB "
|
||||
+ struct.pack(">fff", c[0] / 255, c[1] / 255, c[2] / 255)
|
||||
+ struct.pack(">H", 2)) # 2 = normal colour
|
||||
blocks += struct.pack(">HI", 0x0001, len(body)) + body
|
||||
open(path, "wb").write(b"ASEF" + struct.pack(">HHI", 1, 0, len(cols)) + blocks)
|
||||
|
||||
|
||||
def aco(path, cols, names):
|
||||
# v1 then v2 concatenated — v1 for old readers, v2 carries the names
|
||||
v1 = struct.pack(">HH", 1, len(cols))
|
||||
for c in cols:
|
||||
v1 += struct.pack(">HHHHH", 0, c[0] * 257, c[1] * 257, c[2] * 257, 0)
|
||||
v2 = struct.pack(">HH", 2, len(cols))
|
||||
for c, n in zip(cols, names):
|
||||
v2 += struct.pack(">HHHHH", 0, c[0] * 257, c[1] * 257, c[2] * 257, 0)
|
||||
v2 += struct.pack(">I", len(n) + 1) + n.encode("utf-16-be") + b"\x00\x00"
|
||||
open(path, "wb").write(v1 + v2)
|
||||
|
||||
|
||||
def act(path, cols):
|
||||
d = bytearray()
|
||||
for c in cols:
|
||||
d += bytes(c)
|
||||
d += bytes(768 - len(d))
|
||||
open(path, "wb").write(bytes(d))
|
||||
|
||||
|
||||
def swatches(path, cols, sw=32, h=64):
|
||||
write_png(path, [[c for c in cols for _ in range(sw)]] * h)
|
||||
|
||||
|
||||
# 3x5 glyphs, enough for indices and hex codes. No font library here.
|
||||
GLYPHS = {
|
||||
"0": "111101101101111", "1": "010110010010111", "2": "111001111100111",
|
||||
"3": "111001111001111", "4": "101101111001001", "5": "111100111001111",
|
||||
"6": "111100111101111", "7": "111001001001001", "8": "111101111101111",
|
||||
"9": "111101111001111", "A": "111101111101101", "B": "110101110101110",
|
||||
"C": "111100100100111", "D": "110101101101110", "E": "111100111100111",
|
||||
"F": "111100111100100", "#": "101111101111101", " ": "000000000000000",
|
||||
"-": "000000111000000",
|
||||
}
|
||||
|
||||
|
||||
def _text(px, x, y, s, col, scale=2):
|
||||
for ch in s.upper():
|
||||
g = GLYPHS.get(ch, GLYPHS[" "])
|
||||
for gy in range(5):
|
||||
for gx in range(3):
|
||||
if g[gy*3 + gx] == "1":
|
||||
for sy in range(scale):
|
||||
for sx in range(scale):
|
||||
yy, xx = y + gy*scale + sy, x + gx*scale + sx
|
||||
if 0 <= yy < len(px) and 0 <= xx < len(px[0]):
|
||||
px[yy][xx] = col
|
||||
x += 4 * scale
|
||||
|
||||
|
||||
def card(path, cols, names, idx, scale=2):
|
||||
"""Labelled reference: swatch, palette index, hex code, role name."""
|
||||
rowh, sww, pad = 7*scale + 8, 22*scale, 6
|
||||
W = sww + pad*2 + 4*scale*22
|
||||
H = rowh*len(cols) + pad*2
|
||||
bg, fg = (26, 26, 26), (255, 255, 219)
|
||||
px = [[bg]*W for _ in range(H)]
|
||||
for i, (c, n, ix) in enumerate(zip(cols, names, idx)):
|
||||
y = pad + i*rowh
|
||||
for yy in range(y, y + 7*scale):
|
||||
for xx in range(pad, pad + sww):
|
||||
px[yy][xx] = c
|
||||
label = f"{ix:02d} #{c[0]:02X}{c[1]:02X}{c[2]:02X}"
|
||||
_text(px, pad + sww + pad, y + scale, label, fg, scale)
|
||||
write_png(path, px)
|
||||
|
||||
|
||||
def emit(stem, idx, title):
|
||||
cols = [PALETTE[i] for i in idx]
|
||||
names = [NAMES[i] for i in idx]
|
||||
p = lambda ext: os.path.normpath(os.path.join(OUT, f"{stem}.{ext}"))
|
||||
gpl(p("gpl"), cols, names, title)
|
||||
ase(p("ase"), cols, names)
|
||||
aco(p("aco"), cols, names)
|
||||
act(p("act"), cols)
|
||||
swatches(p("png"), cols)
|
||||
card(os.path.normpath(os.path.join(OUT, f"{stem}-card.png")), cols, names, idx)
|
||||
print(f"{stem}: {len(cols)} colours -> .gpl .ase .aco .act .png + -card.png")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
emit("kissaten-full", list(range(16)), "Kissaten Yugure (full)")
|
||||
emit("kissaten-portrait", PORTRAIT_IDX, "Kissaten Yugure (portrait)")
|
||||
# exact 1px-per-entry image, for generators that take a palette image
|
||||
write_png(os.path.normpath(os.path.join(OUT, "palette.png")), [list(PALETTE)])
|
||||
print("palette.png: 16x1 exact")
|
||||
@@ -0,0 +1,117 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Dependency-free PNG read/write plus helpers for the Kissaten art pipeline.
|
||||
|
||||
No Pillow on this machine, so decode/encode are hand-rolled. Supports the
|
||||
colour types PixelLab and friends actually emit: 2 (RGB), 6 (RGBA), 3
|
||||
(palette), 0 (grey), 4 (grey+alpha), 8 bits per channel.
|
||||
"""
|
||||
import zlib, struct, binascii, sys
|
||||
|
||||
|
||||
def read_png(path):
|
||||
"""-> (w, h, pixels) where pixels is a list of rows of (r,g,b,a) tuples."""
|
||||
d = open(path, "rb").read()
|
||||
assert d[:8] == b"\x89PNG\r\n\x1a\x0a", f"{path}: not a PNG"
|
||||
pos, idat, plte, trns = 8, b"", None, None
|
||||
w = h = depth = ctype = None
|
||||
while pos < len(d):
|
||||
ln = struct.unpack(">I", d[pos:pos + 4])[0]
|
||||
typ = d[pos + 4:pos + 8]
|
||||
body = d[pos + 8:pos + 8 + ln]
|
||||
if typ == b"IHDR":
|
||||
w, h, depth, ctype = struct.unpack(">IIBB", body[:10])
|
||||
elif typ == b"PLTE":
|
||||
plte = body
|
||||
elif typ == b"tRNS":
|
||||
trns = body
|
||||
elif typ == b"IDAT":
|
||||
idat += body
|
||||
elif typ == b"IEND":
|
||||
break
|
||||
pos += 12 + ln
|
||||
assert depth == 8, f"{path}: only 8-bit channels supported (got {depth})"
|
||||
|
||||
nch = {0: 1, 2: 3, 3: 1, 4: 2, 6: 4}[ctype]
|
||||
raw = zlib.decompress(idat)
|
||||
stride = w * nch
|
||||
out, prev = [], bytearray(stride)
|
||||
p = 0
|
||||
for _ in range(h):
|
||||
f = raw[p]; p += 1
|
||||
line = bytearray(raw[p:p + stride]); p += stride
|
||||
for i in range(stride):
|
||||
a = line[i - nch] if i >= nch else 0
|
||||
b = prev[i]
|
||||
c = prev[i - nch] if i >= nch else 0
|
||||
if f == 1: line[i] = (line[i] + a) & 255
|
||||
elif f == 2: line[i] = (line[i] + b) & 255
|
||||
elif f == 3: line[i] = (line[i] + (a + b) // 2) & 255
|
||||
elif f == 4:
|
||||
pa, pb, pc = abs(b - c), abs(a - c), abs(a + b - 2 * c)
|
||||
pr = a if (pa <= pb and pa <= pc) else (b if pb <= pc else c)
|
||||
line[i] = (line[i] + pr) & 255
|
||||
prev = line
|
||||
|
||||
row = []
|
||||
for x in range(w):
|
||||
v = line[x * nch:(x + 1) * nch]
|
||||
if ctype == 2: row.append((v[0], v[1], v[2], 255))
|
||||
elif ctype == 6: row.append((v[0], v[1], v[2], v[3]))
|
||||
elif ctype == 0: row.append((v[0], v[0], v[0], 255))
|
||||
elif ctype == 4: row.append((v[0], v[0], v[0], v[1]))
|
||||
else:
|
||||
i = v[0]
|
||||
a = trns[i] if (trns and i < len(trns)) else 255
|
||||
row.append((plte[i * 3], plte[i * 3 + 1], plte[i * 3 + 2], a))
|
||||
out.append(row)
|
||||
return w, h, out
|
||||
|
||||
|
||||
def write_png(path, rows):
|
||||
h, w = len(rows), len(rows[0])
|
||||
raw = b"".join(b"\x00" + bytes(c for px in r for c in px[:3]) for r in rows)
|
||||
|
||||
def chunk(t, b):
|
||||
c = t + b
|
||||
return struct.pack(">I", len(b)) + c + struct.pack(">I", binascii.crc32(c) & 0xffffffff)
|
||||
|
||||
open(path, "wb").write(
|
||||
b"\x89PNG\r\n\x1a\n"
|
||||
+ chunk(b"IHDR", struct.pack(">IIBBBBB", w, h, 8, 2, 0, 0, 0))
|
||||
+ chunk(b"IDAT", zlib.compress(raw, 9))
|
||||
+ chunk(b"IEND", b""))
|
||||
|
||||
|
||||
def zoom(rows, n):
|
||||
"""Nearest-neighbour upscale, so pixels stay square and countable."""
|
||||
return [[px for px in r for _ in range(n)] for r in rows for _ in range(n)]
|
||||
|
||||
|
||||
# The game palette, index-aligned with g_Palette in kissaten.c
|
||||
PALETTE = [
|
||||
(0x00, 0x00, 0x00), (0x24, 0x24, 0x24), (0x49, 0x24, 0x24), (0x92, 0x49, 0x24),
|
||||
(0xB6, 0x6D, 0x49), (0xFF, 0xB6, 0x49), (0xFF, 0xDB, 0x92), (0x6D, 0x49, 0x49),
|
||||
(0x49, 0x24, 0x92), (0x92, 0x49, 0xB6), (0xDB, 0x6D, 0x6D), (0xFF, 0x92, 0x49),
|
||||
(0x6D, 0x24, 0x00), (0x49, 0x6D, 0xB6), (0xFF, 0xB6, 0x92), (0xFF, 0xFF, 0xDB),
|
||||
]
|
||||
SKY = {8, 9, 10, 11}
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
for path in sys.argv[1:]:
|
||||
w, h, rows = read_png(path)
|
||||
flat = [px for r in rows for px in r]
|
||||
cols = {}
|
||||
for px in flat:
|
||||
cols[px[:3]] = cols.get(px[:3], 0) + 1
|
||||
alphas = sorted({px[3] for px in flat})
|
||||
exact = sum(n for c, n in cols.items() if c in PALETTE)
|
||||
print(f"\n{path} {w}x{h}")
|
||||
print(f" unique colours : {len(cols)}")
|
||||
print(f" alpha values : {alphas if len(alphas) < 6 else str(alphas[:5]) + '...'}")
|
||||
print(f" already in our palette: {len(cols) - len([c for c in cols if c not in PALETTE])}"
|
||||
f" of {len(cols)} ({100*exact//len(flat)}% of pixels)")
|
||||
print(" top 8 colours:")
|
||||
for c, n in sorted(cols.items(), key=lambda kv: -kv[1])[:8]:
|
||||
tag = " <- in palette" if c in PALETTE else ""
|
||||
print(f" #{c[0]:02X}{c[1]:02X}{c[2]:02X} {n:5d} px {100*n//len(flat):3d}%{tag}")
|
||||
@@ -0,0 +1,73 @@
|
||||
#!/usr/bin/env python3
|
||||
"""SVG portrait -> 48x48 PNG in the Kissaten palette.
|
||||
|
||||
python3 tools/svg2portrait.py art/aki-neutral.svg [more.svg ...]
|
||||
|
||||
Why this route beats exporting a bitmap and resizing:
|
||||
|
||||
Magnific's SVG export is flat-shaded vector — hundreds of paths, each a solid
|
||||
fill, with only a handful of gradients. Rendering that at an exact multiple of
|
||||
48 and then taking the *most common* colour in each block is a true pixelate:
|
||||
no blending, no half-pixels, no anti-aliased edges. Bicubic resizing of a
|
||||
bitmap averages instead, which turns every flat region into a gradient and
|
||||
makes the later palette reduction speckle badly.
|
||||
|
||||
Requires qlmanage (macOS built-in) to rasterise. No third-party deps.
|
||||
"""
|
||||
import subprocess, sys, os, tempfile
|
||||
from collections import Counter
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
from pixtool import read_png, write_png, zoom, PALETTE
|
||||
|
||||
SIZE = 48
|
||||
SCALE = 16 # render at SIZE*SCALE, then block-reduce
|
||||
PORTRAIT_IDX = [1, 2, 3, 4, 5, 6, 7, 12, 13, 14, 15] # no sky, no index 0
|
||||
PP = [PALETTE[i] for i in PORTRAIT_IDX]
|
||||
|
||||
|
||||
def nearest(c):
|
||||
r, g, b = c[:3]
|
||||
# green weighted heaviest: keeps eyes and mouth from dissolving into skin
|
||||
return min(PP, key=lambda p: 3*(p[0]-r)**2 + 6*(p[1]-g)**2 + (p[2]-b)**2)
|
||||
|
||||
|
||||
def rasterise(svg, px):
|
||||
"""SVG -> PNG at px wide, via Quick Look. Returns decoded pixels."""
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
subprocess.run(["qlmanage", "-t", "-s", str(px), "-o", td, svg],
|
||||
capture_output=True, check=True)
|
||||
out = os.path.join(td, os.path.basename(svg) + ".png")
|
||||
if not os.path.exists(out):
|
||||
raise SystemExit(f"qlmanage produced nothing for {svg}")
|
||||
return read_png(out)
|
||||
|
||||
|
||||
def mode_reduce(rows, n):
|
||||
"""Each n*n block collapses to its most common colour — a real pixelate."""
|
||||
return [[Counter(rows[by*n + y][bx*n + x][:3]
|
||||
for y in range(n) for x in range(n)).most_common(1)[0][0]
|
||||
for bx in range(SIZE)] for by in range(SIZE)]
|
||||
|
||||
|
||||
def convert(svg):
|
||||
w, h, big = rasterise(svg, SIZE * SCALE)
|
||||
if w != SIZE * SCALE:
|
||||
raise SystemExit(f"{svg}: expected {SIZE*SCALE}px render, got {w}")
|
||||
small = mode_reduce(big, SCALE)
|
||||
quant = [[nearest(p) for p in r] for r in small]
|
||||
|
||||
stem = os.path.splitext(svg)[0]
|
||||
write_png(f"{stem}-{SIZE}.png", [[p + (255,) for p in r] for r in quant])
|
||||
write_png(f"{stem}-{SIZE}-x6.png",
|
||||
zoom([[p + (255,) for p in r] for r in quant], 6))
|
||||
print(f"{os.path.basename(svg)}: {len({p for r in small for p in r})} colours "
|
||||
f"after pixelate -> {len({p for r in quant for p in r})} after palette")
|
||||
print(f" wrote {stem}-{SIZE}.png and {stem}-{SIZE}-x6.png (preview)")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
raise SystemExit(__doc__)
|
||||
for f in sys.argv[1:]:
|
||||
convert(f)
|
||||
@@ -7,7 +7,9 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
||||
An MSX2+ maze game written in C against the **MSXgl** library (`../../engine`), built
|
||||
into a 256KB **Konami SCC mapper ROM**. SCREEN 8 (G7, 256 colors), 32×32-pixel tiles,
|
||||
player always centered with smooth easing scroll. The whole game is one translation unit
|
||||
(`mazegame.c`) plus ~24 generated data files holding bitmap assets in banked ROM segments.
|
||||
(`mazegame.c`) plus ~28 generated data files holding bitmap assets and per-screen music in
|
||||
banked ROM segments. Each screen has its own looping **MSX-Music (FM/OPLL)** track, with
|
||||
**ayFX** sound effects layered on the PSG.
|
||||
|
||||
## Build & run
|
||||
|
||||
@@ -33,7 +35,10 @@ at runtime with `SET_BANK_SEGMENT(2, n)` / `GET_BANK_SEGMENT(2)` (from `rom_mapp
|
||||
The `_b2` suffix on the generated files means "bank 2". Always save and restore the
|
||||
previous segment around a bank switch — the existing code does this everywhere.
|
||||
|
||||
Segment allocation (each file is `const u8 g_*[8192]` filling one 8KB segment exactly):
|
||||
Segment allocation. The build auto-discovers any `mazegame_s{N}_b2.c` (N up to 31) and
|
||||
pins its data to the start of segment N at the bank-2 window; the file's one `const u8 g_*`
|
||||
array need not fill the whole 8KB (bitmap assets do; music tracks are smaller and the rest
|
||||
of the segment is zero-padded).
|
||||
|
||||
| Segments | File(s) | Contents |
|
||||
|----------|--------------------------|---------------------------------------------------|
|
||||
@@ -43,10 +48,14 @@ Segment allocation (each file is `const u8 g_*[8192]` filling one 8KB segment ex
|
||||
| 17 | `mazegame_s17_b2.c` | Sprite frames: east + west, frames 0–3 |
|
||||
| 18 | `mazegame_s18_b2.c` | All 8 tile bitmaps (1024 B each, 32×32) |
|
||||
| 19–25 | `mazegame_s19..25_b2.c` | Hint screen image |
|
||||
| 26 | `mazegame_s26_b2.c` | Music: title screen (lVGM, FM) |
|
||||
| 27 | `mazegame_s27_b2.c` | Music: hints screen (lVGM, FM) |
|
||||
| 28 | `mazegame_s28_b2.c` | Music: gameplay/maze (lVGM, FM) |
|
||||
| 29 | `mazegame_s29_b2.c` | Music: victory screen (lVGM, FM) |
|
||||
|
||||
A 256×212 SCREEN 8 image is 53,248 bytes = 7 segments (last one zero-padded). Sprite
|
||||
frames are 24×24 = 576 bytes each, addressed as `0x8000 + (localDir*4 + frame) * 576`.
|
||||
Tiles are addressed as `0x8000 + index*1024`.
|
||||
Segments 30–31 are free. A 256×212 SCREEN 8 image is 53,248 bytes = 7 segments (last one
|
||||
zero-padded). Sprite frames are 24×24 = 576 bytes each, addressed as
|
||||
`0x8000 + (localDir*4 + frame) * 576`. Tiles are addressed as `0x8000 + index*1024`.
|
||||
|
||||
### Asset pipeline (PNG → C, run manually, then rebuild)
|
||||
|
||||
@@ -62,6 +71,70 @@ All converters encode pixels as SCREEN 8 **GRB** (bits 7–5 = G3, 4–2 = R3, 1
|
||||
`to_grb()`. Any new color/asset code must use the same encoding. Sprite segments (16/17)
|
||||
have no checked-in converter — edit them as data directly.
|
||||
|
||||
### Music & sound — per-screen lVGM (MSX-Music / FM) + ayFX (PSG)
|
||||
|
||||
Music and sound effects use **different chips**, so they mix with zero contention: looping
|
||||
**MSX-Music (FM/OPLL)** tracks on the YM2413, and **ayFX** sound effects on the PSG.
|
||||
|
||||
Each screen has its own looping track played by MSXgl's `vgm/lvgm_player`. The tracks are
|
||||
**lVGM** (compact VGM) files in `music/`, all **MSX-Music (YM2413 / OPLL / FM)** — so FM must
|
||||
exist: built into most MSX2+ machines, and `project_config.js` sets `EmulMSXMusic = true`
|
||||
so `./build.sh run` gives openMSX the FM-PAC (`-ext fmpac`). The PSG carries no music.
|
||||
|
||||
- **Source → ROM:** the `.lvgm` files were embedded as the `mazegame_s26..29_b2.c` data
|
||||
files (one track per segment; each is < 8KB so it never crosses a segment boundary). To
|
||||
regenerate after replacing a `.lvgm`, re-run the small embed step (bin2c-style: dump the
|
||||
bytes as `const u8 g_Mus*[N]` in the matching `s{26..29}_b2.c`). See
|
||||
`~/Repositories/msx-music-generator` (the generator + its `msxgl-example/README.md`).
|
||||
- **Decode runs in the VBlank interrupt (this is the key design point).** `MusicVBlank()` is
|
||||
installed as the `H_TIMI` hook (`BIOS_SetHookCallback`) and each VBlank calls `LVGM_Decode()`
|
||||
(music) + `ayFX_Update()` + `PSG_Apply()` (SFX) — so the tempo is **steady regardless of how
|
||||
long a frame's game work takes**. (An earlier design decoded once per `Halt()` in the main
|
||||
loop; the heavy per-step VDP work in `ScrollDraw` could overrun a VBlank, so the decode rate —
|
||||
and the music — slowed *only while moving*. The ISR decouples them.) The game loops therefore
|
||||
contain **no** decode calls; they are plain `Halt()`/busy-waits as before the music existed.
|
||||
- **Banking — why it's race-free:** the tracks are compiled at the bank-2 link address but at
|
||||
runtime `PlayTrack()` maps the current track into the **bank-3 window** (`0xA000-0xBFFF`) and
|
||||
leaves it there for the whole screen. Gameplay only ever switches **bank 2** (`0x8000`) for
|
||||
tiles/sprites, so bank 3 is never touched and the ISR can read `0xA000` at any moment without
|
||||
a bank save/restore and without racing the main code. `PlayTrack(seg)` runs under
|
||||
`DisableInterrupt()`/`EnableInterrupt()` (mute the old track's hanging note → map bank 3 →
|
||||
`LVGM_Play(0xA000, TRUE)`) so `MusicVBlank` can't decode mid-switch. `MSXMusic_Initialize()`
|
||||
and the hook install run once at the top of `main()`; `MusicVBlank` is a no-op until a track
|
||||
is playing (`LVGM_IsPlaying()`).
|
||||
- **Config:** `LibModules` adds `psg`, `msx-music`, `vgm/lvgm_player`, `ayfx/ayfx_player`;
|
||||
`msxgl_config.h` sets `LVGM_USE_PSG`/`LVGM_USE_MSXMUSIC` on (rest off), `PSG_ACCESS =
|
||||
PSG_INDIRECT` and `AYFX_BUFFER = AYFX_BUFFER_DEFAULT` (ayFX writes the PSG buffer that
|
||||
`PSG_Apply` flushes), and `PSG_USE_EXTRA = TRUE`.
|
||||
- The tracks are authored at **60 Hz**; on a 50 Hz (PAL) machine they play a constant ~17 %
|
||||
slower (the decode rate is the display refresh). That's uniform, not movement-specific.
|
||||
|
||||
**Sound effects (ayFX, PSG).** An 8-effect ayFX bank in `sfx/sfx_bank.afb` (with a descriptive
|
||||
`sfx_bank.txt`), embedded as `sfx_bank.h` (`g_SFXBank[]`) in **fixed main ROM** so the interrupt
|
||||
reads it with no bank switching. Trigger with the `PlaySfx(id, prio)` helper; ids and priorities
|
||||
(0 = highest, never interrupted; footsteps lowest so any UI/finish sound cuts over them):
|
||||
|
||||
| id | effect | trigger | prio |
|
||||
|----|--------|---------|------|
|
||||
| 0-2 | cat paws (random) | each move | lowest |
|
||||
| 4 | fanfare | landing on the exit | highest |
|
||||
| 5 | map unfold | press **M** (minimap) | mid |
|
||||
| 6 | laugh | press **C** (cheat) | mid |
|
||||
| 7 | ta-daa | advancing title / hint / finish screen | high |
|
||||
|
||||
(id 3 is unused.) Two interrupt-safety rules make this work — **break either and you get noise
|
||||
and phantom input**:
|
||||
- **All joystick reads go through `ReadJoy()`**, which wraps `Joystick_Read` in
|
||||
`DisableInterrupt()`/`EnableInterrupt()`. `Joystick_Read` polls the PSG directly (R#14/R#15);
|
||||
the ISR's `PSG_Apply` also touches the PSG, so an un-guarded read gets corrupted *and* can
|
||||
misdirect a port-select write into a sound register. (`Keyboard_Read` uses the PPI, not the
|
||||
PSG, so it needs no guard.) `PlaySfx` and `PlayTrack` likewise run under DI/EI.
|
||||
- **The PSG mixer is muted at startup** (`PSG_SetMixer(0); PSG_Apply();` before the hook is
|
||||
installed). The zero-initialized PSG buffer has the mixer at `0` = *all channels enabled*
|
||||
(active-low), which `PSG_Apply` would drive as noise; ayFX re-enables its own channel when it
|
||||
plays an effect. `ayFX_InitBank`/`SetChannel(PSG_CHANNEL_A)`/`SetMode(FIXED)` run once in `main`.
|
||||
- The boot **logo animation is intentionally silent** (no track).
|
||||
|
||||
### VRAM layout (off-screen caches above the visible 256×212)
|
||||
|
||||
`mazegame.c` reserves off-screen VRAM rows in the 128KB space and documents exact
|
||||
@@ -72,30 +145,78 @@ coordinates in the constants block — keep these regions non-overlapping when c
|
||||
Rendering uses VDP commands (HMMV/HMMM, enabled via `VDP_USE_COMMAND` in `msxgl_config.h`)
|
||||
to blit from these caches rather than re-drawing per frame.
|
||||
|
||||
### Scrolling model — VRAM torus (why there is no per-move flash)
|
||||
|
||||
The visible page is treated as a **256×256 VRAM torus**. Two globals, `g_BaseX`/`g_BaseY`,
|
||||
hold the *resting* hardware scroll offset (R#26/27 and R#23); both are always a multiple of
|
||||
64 and cycle through `{0, 64, 128, 192}`. A screen pixel `(sx, sy)` maps to VRAM
|
||||
`((sx+g_BaseX)&255, (sy+g_BaseY)&255)`.
|
||||
|
||||
A move (`ScrollDraw`) animates the scroll register from `base` to `base ± 64` over the 8
|
||||
ease steps, rendering the two newly-exposed tile-rows/cols into the VRAM cells that scroll
|
||||
off the *opposite* edge, then simply keeps the new offset as the resting base. **Nothing is
|
||||
bulk-shifted or blanked afterwards** — the old content is already at the correct torus
|
||||
position, so there is no offset reset, no bulk HMMM, no strip paste, and no display blank.
|
||||
(The earlier "canonicalize after every move" design did all of those behind a
|
||||
`VDP_EnableDisplay(FALSE)`, which was the visible per-move flash.)
|
||||
|
||||
Consequences to respect when editing:
|
||||
- **All gameplay VRAM drawing must go through the base.** `DrawTileData`/`DrawTile` add it
|
||||
to their HMMM/HMMV destination; the `WriteVV` helper does it for per-row CPU writes
|
||||
(sprite, compositors, cat-sense arrow) and **splits a run at the 256-column wrap**. Tiles
|
||||
are 32-aligned and the base is a multiple of 64, so tiles never straddle; the 24px sprite
|
||||
can straddle mid-animation, which is why `WriteVV` exists.
|
||||
- Fill targets in `ScrollDraw` are **base-relative** but the fill *timing* (which animation
|
||||
step is safe to write each row/col) is **base-invariant**; at `base = 0` every expression
|
||||
reduces exactly to the pre-torus code, which is the easy case to reason about.
|
||||
- **Strip fills must respect BOTH axis bases, not just the scroll axis.** The bulk HMMM fills
|
||||
handle the scroll-axis base in their destination, and the orthogonal axis as follows:
|
||||
vertical strips are **pre-rotated by `g_BaseX` in staging** (`PreRenderStrip`), so the
|
||||
full-width row copies stay at destination x=0; horizontal column fills go through
|
||||
`FillStripColumns`, which **splits the 224-row copy at the 256-row wrap** for `g_BaseY`.
|
||||
(Omitting either writes the new edge 2/4/6 tiles rotated whenever the other axis' base is
|
||||
non-zero — the maze *looks* wrong while collision stays right: phantom walls/passages.)
|
||||
- Vertical has only 32px of slack in the 256-row torus, so one new tile-row is pre-filled
|
||||
(off-screen slack) and the other is deferred until it scrolls off; horizontal fills
|
||||
progressively as columns wrap. This is the delicate part — verify long straight runs in
|
||||
each direction (the base crosses its wrap on the 4th move) and the sprite at screen edges.
|
||||
- Anything that draws at **absolute** VRAM coords must zero the scroll offset while shown and
|
||||
restore `g_BaseX`/`g_BaseY` after — the minimap overlay does this.
|
||||
- `main()` game setup resets `g_BaseX = g_BaseY = 0` and the offset registers before the
|
||||
first `DrawFull`.
|
||||
|
||||
### Game flow (`main()`)
|
||||
|
||||
`ShowLogoAnimation()` (SCREEN 5 fade) → loop of: `TitleScreen()` (ordered dissolve from
|
||||
opening to opening+titles using the banked images) → `srand(*0xFC9E)` seed from the BIOS
|
||||
`ShowLogoAnimation()` (SCREEN 5 fade, silent) → loop of: `TitleScreen()` (ordered dissolve
|
||||
from opening to opening+titles using the banked images) → `srand(*0xFC9E)` seed from the BIOS
|
||||
jiffy clock → `GenerateMaze()` (iterative DFS, `g_RW`/`g_DW` wall arrays) → `ShowHints()`
|
||||
→ set up SCREEN 8, preload tiles/minimap into VRAM → inner movement loop.
|
||||
→ set up SCREEN 8, preload tiles/minimap into VRAM → inner movement loop → `ShowWinScreen()`
|
||||
on reaching the exit. Each of these screens starts its own looping track with `PlayTrack()`
|
||||
(see "Music" above); `MSXMusic_Initialize()` runs once before the logo.
|
||||
|
||||
Movement is an 8-step ease-in/out scroll (`g_AO` cumulative offsets summing to 64px = two
|
||||
tiles) implemented with VDP register scroll + strip rendering; input (keyboard + joystick,
|
||||
sampled at the last animation frame) chains directly into the next move if a direction is
|
||||
still held. The player is a 24×24 **software** sprite (`DrawSpriteAt`) drawn into VRAM —
|
||||
hardware sprites are disabled. Hold **M** for the minimap overlay.
|
||||
tiles) implemented as a **VRAM torus** (see "Scrolling model" above) — VDP register scroll
|
||||
plus edge-strip rendering, with no per-move blank/flash. Input (keyboard + joystick, sampled
|
||||
at the last animation frame) chains directly into the next move if a direction is still
|
||||
held. The player is a 24×24 **software** sprite (`DrawSpriteAt`) drawn into VRAM — hardware
|
||||
sprites are disabled. Special keys in the movement loop: hold **M** (or joystick button A)
|
||||
for the minimap overlay; hold **S** for the cat-sense arrow pointing toward the exit;
|
||||
**C** (cheat) teleports to an open neighbour of the exit — one move short, so the final
|
||||
step (and the win) is still the player's.
|
||||
|
||||
### MSXgl configuration
|
||||
|
||||
`msxgl_config.h` is the per-project feature switch for the dynamically-compiled library:
|
||||
SCREEN 5 (G4) and SCREEN 8 (G7) modes, VDP commands, 16×16 sprites, keyboard+joystick
|
||||
input. Enabling a library feature the game starts using generally requires flipping the
|
||||
matching `*_USE_*` define here.
|
||||
input, and the audio stack (lVGM/PSG/MSX-Music replayer + ayFX — see "Music & sound").
|
||||
Enabling a library feature the game starts using generally requires flipping the matching
|
||||
`*_USE_*` define here **and** adding the module to `LibModules` in `project_config.js`.
|
||||
|
||||
## Conventions in this codebase
|
||||
|
||||
- Globals use terse `g_XX` names (documented inline at the top of `mazegame.c`); section
|
||||
banners are `//==== … ====`. Match that style.
|
||||
- `out/` is generated build output (`.asm/.rel/.lst/.sym/.map/.rom`) — never edit by hand.
|
||||
- This directory is **not** a git repository, and MSXgl itself was patched for macOS
|
||||
(see `../../SETUP_MACOS.md`); those edits are untracked, so don't assume version control.
|
||||
- The repo root is `../../` (the whole `MSXgl-1.4.1` tree, pushing to the `mazegame` remote);
|
||||
work happens directly on `main`. MSXgl itself was patched for macOS (see
|
||||
`../../SETUP_MACOS.md`); those engine edits are untracked, so don't assume they're versioned.
|
||||
|
||||
@@ -7,6 +7,12 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "msxgl.h"
|
||||
#include "rom_mapper.h"
|
||||
#include "bios_hook.h"
|
||||
#include "psg.h"
|
||||
#include "msx-music.h"
|
||||
#include "vgm/lvgm_player.h"
|
||||
#include "ayfx/ayfx_player.h"
|
||||
#include "sfx_bank.h" // g_SFXBank[] — ayFX sound-effect bank (fixed main ROM)
|
||||
#include <stdlib.h>
|
||||
|
||||
//=============================================================================
|
||||
@@ -96,6 +102,85 @@ u8 g_VSeed; // per-game seed for tile variant hash
|
||||
u8 g_BaseX; // resting horizontal scroll offset (mult of 64)
|
||||
u8 g_BaseY; // resting vertical scroll offset (mult of 64)
|
||||
|
||||
//=============================================================================
|
||||
// MUSIC (lVGM, MSX-Music / OPLL) — one looping track per screen, in banked ROM
|
||||
//=============================================================================
|
||||
// Each track fills the start of its own ROM segment (the `_b2` files are compiled
|
||||
// at the bank-2 link address, but at runtime the track is mapped into the *bank-3*
|
||||
// window at 0xA000-0xBFFF and left there for the whole screen). Gameplay only ever
|
||||
// switches bank 2 (0x8000) for tiles/sprites, so bank 3 is never disturbed and the
|
||||
// track stays put. Decoding runs in the H_TIMI VBlank interrupt (MusicVBlank), so
|
||||
// the music tempo is rock-steady no matter how long a frame's game work takes — the
|
||||
// scroll animation can overrun a VBlank without dragging the music down with it.
|
||||
// Because the ISR reads only from bank 3, it never races the main code's bank-2
|
||||
// switching, and needs no bank save/restore. Each track is < 8KB (one segment).
|
||||
#define MUS_SEG_TITLE 26 // mazegame_s26_b2.c (g_MusTitle)
|
||||
#define MUS_SEG_HINTS 27 // mazegame_s27_b2.c (g_MusHints)
|
||||
#define MUS_SEG_MAZE 28 // mazegame_s28_b2.c (g_MusMaze)
|
||||
#define MUS_SEG_WIN 29 // mazegame_s29_b2.c (g_MusWin)
|
||||
|
||||
#define MUS_WINDOW ((const u8*)0xA000) // bank-3 window the track is mapped into
|
||||
|
||||
// Sound effects (ayFX on the PSG, mixed over the FM music). Bank ids (see
|
||||
// sfx/sfx_bank.txt): 0-2 cat paws (movement, chosen at random), 4 fanfare (reaching
|
||||
// the exit), 5 map unfold (M / minimap), 6 laugh (C / cheat), 7 ta-daa (advancing a
|
||||
// screen). Priority: 0 = highest (never interrupted); higher number = interrupted
|
||||
// more easily. Footsteps are lowest so any UI/finish sound cuts over them.
|
||||
#define SFX_FINISH 4
|
||||
#define SFX_MINIMAP 5
|
||||
#define SFX_CHEAT 6
|
||||
#define SFX_SCREEN 7
|
||||
#define SFX_PRIO_FINISH 0
|
||||
#define SFX_PRIO_SCREEN 1
|
||||
#define SFX_PRIO_ACTION 2 // M / C
|
||||
#define SFX_PRIO_MOVE 4 // footsteps
|
||||
|
||||
// H_TIMI (VBlank) hook: advance the music one frame (if a track is playing) and the
|
||||
// current sound effect one frame, then flush the PSG buffer. Music reads from the
|
||||
// bank-3 window; SFX reads the bank in fixed main ROM — neither needs bank switching.
|
||||
void MusicVBlank(void)
|
||||
{
|
||||
if (LVGM_IsPlaying())
|
||||
LVGM_Decode();
|
||||
ayFX_Update();
|
||||
PSG_Apply();
|
||||
}
|
||||
|
||||
// Trigger a bank sound effect. ayFX state is set up here (main context) while the
|
||||
// VBlank hook reads it, so disable interrupts across the call.
|
||||
static void PlaySfx(u8 id, u8 prio)
|
||||
{
|
||||
DisableInterrupt();
|
||||
ayFX_PlayBank(id, prio);
|
||||
EnableInterrupt();
|
||||
}
|
||||
|
||||
// Read joystick 1 with interrupts disabled. Joystick_Read drives the PSG directly
|
||||
// (selects/writes R#15, reads R#14); the VBlank hook's PSG_Apply also touches the
|
||||
// PSG. If the hook fired mid-read it would corrupt the returned data AND could
|
||||
// misdirect a port-select write into a sound register (audible noise). All joystick
|
||||
// reads in the game must go through this wrapper. (Keyboard_Read uses the PPI, not
|
||||
// the PSG, so it is race-free and needs no protection.)
|
||||
static u8 ReadJoy(void)
|
||||
{
|
||||
DisableInterrupt();
|
||||
u8 j = Joystick_Read(JOY_PORT_1);
|
||||
EnableInterrupt();
|
||||
return j;
|
||||
}
|
||||
|
||||
// Switch to a looping track: silence the previous track's lingering note (key-off all
|
||||
// 9 FM channels), map the new track into bank 3, and start it. Interrupts are disabled
|
||||
// across the switch so MusicVBlank can't decode from a half-updated pointer or segment.
|
||||
static void PlayTrack(u8 seg)
|
||||
{
|
||||
DisableInterrupt();
|
||||
MSXMusic_Mute();
|
||||
SET_BANK_SEGMENT(3, seg);
|
||||
LVGM_Play(MUS_WINDOW, TRUE);
|
||||
EnableInterrupt();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// MAZE GENERATION (iterative DFS)
|
||||
//=============================================================================
|
||||
@@ -541,7 +626,14 @@ static void PreRenderStrip(i8 dx, i8 dy)
|
||||
for (u8 ty = ya; ty <= yb; ty++) {
|
||||
for (u8 tx = xa; tx <= xb; tx++) {
|
||||
u8 srcX = GetTileSrcX(ox + (i8)tx, oy + (i8)ty);
|
||||
u16 stx = (u16)(tx - xa) * TILE_W;
|
||||
// Vertical strips are pasted by full-width HMMMs at VRAM x=0, so the
|
||||
// staging row must already be rotated by the horizontal torus base:
|
||||
// screen column 0 lives at VRAM column g_BaseX. Tiles are 32-aligned
|
||||
// and the base is a multiple of 64, so no tile straddles the wrap.
|
||||
// Horizontal strips are pasted column-by-column with an explicit
|
||||
// destination x, so their staging stays unrotated (x = 0..63).
|
||||
u16 stx = (dy != 0) ? (u8)(tx * TILE_W + g_BaseX)
|
||||
: (u16)(tx - xa) * TILE_W;
|
||||
u16 sty = STAGING_Y + (u16)(ty - ya) * TILE_W;
|
||||
VDP_CommandHMMM(srcX, TILE_CACHE_Y, stx, sty, TILE_W, TILE_W);
|
||||
VDP_CommandWait();
|
||||
@@ -549,6 +641,22 @@ static void PreRenderStrip(i8 dx, i8 dy)
|
||||
}
|
||||
}
|
||||
|
||||
// Paste a w-wide, 224-tall column of the horizontal staging strip into the
|
||||
// visible torus. Screen row 0 lives at VRAM row g_BaseY, so the copy is split
|
||||
// at the 256-row wrap when the vertical base is non-zero (base 64/128/192 →
|
||||
// 192/128/64 rows before the wrap, remainder continuing at VRAM row 0).
|
||||
static void FillStripColumns(u8 srcX, u8 dstX, u8 w)
|
||||
{
|
||||
u8 by = g_BaseY;
|
||||
if (by == 0) {
|
||||
VDP_CommandHMMM(srcX, STAGING_Y, dstX, 0, w, 224);
|
||||
} else {
|
||||
u16 h1 = 256u - by; // rows before the torus wrap
|
||||
VDP_CommandHMMM(srcX, STAGING_Y, dstX, by, w, h1);
|
||||
VDP_CommandHMMM(srcX, STAGING_Y + h1, dstX, 0, w, (u16)(224u - h1));
|
||||
}
|
||||
}
|
||||
|
||||
// Wrap-around (torus) scroll: animate the hardware scroll register from the
|
||||
// resting base to base±64, rendering the newly exposed edge into the VRAM cells
|
||||
// that scroll off the opposite side. Nothing is bulk-shifted or blanked
|
||||
@@ -574,7 +682,9 @@ u8 ScrollDraw(i8 dx, i8 dy)
|
||||
// tile-rows exactly one is already off-screen (in the slack just past the
|
||||
// viewport) and can be filled now; the other overlaps on-screen VRAM and is
|
||||
// deferred into the loop. At base=0 these reduce to the original rows 224/0
|
||||
// (dy=1) and 224/192 (dy=-1). Staging holds the new tiles at rows 0 / +32.
|
||||
// (dy=1) and 224/192 (dy=-1). Staging holds the new tiles at rows 0 / +32,
|
||||
// already rotated by g_BaseX (see PreRenderStrip), so these full-width
|
||||
// copies stay at destination x=0 regardless of the horizontal base.
|
||||
if (dy == 1) {
|
||||
// New bottom tile-row 5 → VRAM row (base+224) (off-screen slack). Staging row 0.
|
||||
VDP_CommandHMMM(0, STAGING_Y, 0, (u8)(base + 224u), 256, 32); VDP_CommandWait();
|
||||
@@ -633,10 +743,10 @@ u8 ScrollDraw(i8 dx, i8 dy)
|
||||
u8 cur = g_AO[i];
|
||||
u8 w = cur - prev;
|
||||
if (dx == 1) {
|
||||
VDP_CommandHMMM(prev, STAGING_Y, (u8)(base + prev), 0, w, 224);
|
||||
FillStripColumns(prev, (u8)(base + prev), w);
|
||||
} else {
|
||||
u8 fs = (u8)(64u - cur);
|
||||
VDP_CommandHMMM(fs, STAGING_Y, (u8)(base + 192u + fs), 0, w, 224);
|
||||
FillStripColumns(fs, (u8)(base + 192u + fs), w);
|
||||
}
|
||||
u8 new_vx = (u8)((i16)SPR_DRAW_X + (i16)dx * (i16)cur);
|
||||
g_SprFrame = (g_SprFrame + 1) & 3;
|
||||
@@ -650,7 +760,7 @@ u8 ScrollDraw(i8 dx, i8 dy)
|
||||
|
||||
// Read keyboard and joystick at the final animation frame (for chaining).
|
||||
u8 row8 = Keyboard_Read(8);
|
||||
g_Joy = Joystick_Read(JOY_PORT_1);
|
||||
g_Joy = ReadJoy();
|
||||
|
||||
// Commit the new resting base. The newly exposed edge is already in VRAM (from
|
||||
// the fills), the old content is already at the correct torus position, and the
|
||||
@@ -820,7 +930,7 @@ void WriteImgRow(u8 first_seg, u8 y)
|
||||
// Returns 1 if any key (rows 0-8) or any joystick direction/button is active.
|
||||
static u8 AnyInput(void)
|
||||
{
|
||||
u8 joy = Joystick_Read(JOY_PORT_1);
|
||||
u8 joy = ReadJoy();
|
||||
if (JOY_GET_DIR(joy) != 0 ||
|
||||
IS_JOY_PRESSED(joy, JOY_INPUT_TRIGGER_A) ||
|
||||
IS_JOY_PRESSED(joy, JOY_INPUT_TRIGGER_B)) return 1;
|
||||
@@ -834,6 +944,7 @@ static void WaitKeySequence(void)
|
||||
{
|
||||
while (AnyInput());
|
||||
while (!AnyInput());
|
||||
PlaySfx(SFX_SCREEN, SFX_PRIO_SCREEN); // ta-daa on the advancing keypress
|
||||
while (AnyInput());
|
||||
}
|
||||
|
||||
@@ -843,9 +954,13 @@ static void WaitKeySequence(void)
|
||||
static void ShowHints(void)
|
||||
{
|
||||
VDP_EnableDisplay(FALSE);
|
||||
// Drawn at absolute VRAM coords — clear any leftover hardware scroll offset.
|
||||
VDP_SetVerticalOffset(0);
|
||||
VDP_SetHorizontalOffset(0);
|
||||
for (u8 y = 0; y < IMG_ROWS; y++)
|
||||
WriteImgRow(IMG_SEG_HINTS, y);
|
||||
VDP_EnableDisplay(TRUE);
|
||||
PlayTrack(MUS_SEG_HINTS);
|
||||
WaitKeySequence();
|
||||
}
|
||||
|
||||
@@ -857,11 +972,18 @@ void TitleScreen(void)
|
||||
VDP_EnableDisplay(FALSE);
|
||||
VDP_ClearVRAM();
|
||||
|
||||
// This image is drawn at absolute VRAM coords, so clear any hardware scroll
|
||||
// offset left over from a previous game (gameplay rests at g_BaseX/g_BaseY in
|
||||
// {0,64,128,192}); without this the returning title screen appears shifted.
|
||||
VDP_SetVerticalOffset(0);
|
||||
VDP_SetHorizontalOffset(0);
|
||||
|
||||
// Stream image A (no title) to VRAM display area
|
||||
for (u8 y = 0; y < IMG_ROWS; y++)
|
||||
WriteImgRow(IMG_SEG_A, y);
|
||||
|
||||
VDP_EnableDisplay(TRUE);
|
||||
PlayTrack(MUS_SEG_TITLE);
|
||||
|
||||
// Hold image A for ~2 seconds (100 VBlanks at 50Hz)
|
||||
for (u8 i = 0; i < 100; i++) Halt();
|
||||
@@ -877,6 +999,7 @@ void TitleScreen(void)
|
||||
|
||||
// Wait for any key or joystick input, then release
|
||||
while (!AnyInput());
|
||||
PlaySfx(SFX_SCREEN, SFX_PRIO_SCREEN); // ta-daa on the advancing keypress
|
||||
while (AnyInput());
|
||||
}
|
||||
|
||||
@@ -931,6 +1054,7 @@ static void ShowWinScreen(void)
|
||||
Bios_SetCursorPosition(7, 15);
|
||||
Bios_TextPrintString("Press any key to return...");
|
||||
|
||||
PlayTrack(MUS_SEG_WIN);
|
||||
WaitKeySequence();
|
||||
}
|
||||
|
||||
@@ -940,6 +1064,21 @@ static void ShowWinScreen(void)
|
||||
|
||||
void main(void)
|
||||
{
|
||||
// Init the MSX-Music (OPLL) chip, load the ayFX bank onto PSG channel A, then
|
||||
// install the VBlank hook that advances music + SFX every frame (the hook is a
|
||||
// no-op for music until a track plays, and silent for SFX until one is triggered).
|
||||
MSXMusic_Initialize();
|
||||
ayFX_InitBank((void*)g_SFXBank);
|
||||
ayFX_SetChannel(PSG_CHANNEL_A);
|
||||
ayFX_SetMode(AYFX_MODE_FIXED);
|
||||
// Silence the PSG before the per-frame PSG_Apply starts: the zero-initialized
|
||||
// register buffer has the mixer at 0 = all channels ENABLED, which PSG_Apply would
|
||||
// drive as noise. Disable every channel; ayFX re-enables its own channel when it
|
||||
// plays an effect (and drops back to volume 0 when the effect ends).
|
||||
PSG_SetMixer(0);
|
||||
PSG_Apply();
|
||||
BIOS_SetHookCallback(H_TIMI, MusicVBlank);
|
||||
|
||||
ShowLogoAnimation();
|
||||
|
||||
while (1) {
|
||||
@@ -1009,6 +1148,7 @@ void main(void)
|
||||
g_MX = g_SX; g_MY = 0;
|
||||
DrawFull();
|
||||
VDP_EnableDisplay(TRUE);
|
||||
PlayTrack(MUS_SEG_MAZE);
|
||||
|
||||
// Start timer: sample current jiffy clock, reset frame counter.
|
||||
g_PrevTick = *(volatile u8*)0xFC9E;
|
||||
@@ -1029,7 +1169,7 @@ void main(void)
|
||||
do {
|
||||
UpdateTimer();
|
||||
row8 = Keyboard_Read(8);
|
||||
g_Joy = Joystick_Read(JOY_PORT_1);
|
||||
g_Joy = ReadJoy();
|
||||
} while (IS_KEY_PRESSED(row8, KEY_UP) || IS_KEY_PRESSED(row8, KEY_DOWN) ||
|
||||
IS_KEY_PRESSED(row8, KEY_LEFT) || IS_KEY_PRESSED(row8, KEY_RIGHT) ||
|
||||
JOY_GET_DIR(g_Joy) != 0);
|
||||
@@ -1041,16 +1181,27 @@ void main(void)
|
||||
row3 = Keyboard_Read(3);
|
||||
row4 = Keyboard_Read(4);
|
||||
row5 = Keyboard_Read(5);
|
||||
g_Joy = Joystick_Read(JOY_PORT_1);
|
||||
g_Joy = ReadJoy();
|
||||
} while (!IS_KEY_PRESSED(row8, KEY_UP) && !IS_KEY_PRESSED(row8, KEY_DOWN) &&
|
||||
!IS_KEY_PRESSED(row8, KEY_LEFT) && !IS_KEY_PRESSED(row8, KEY_RIGHT) &&
|
||||
!IS_KEY_PRESSED(row3, KEY_C) && !IS_KEY_PRESSED(row4, KEY_M) &&
|
||||
!IS_KEY_PRESSED(row5, KEY_S) &&
|
||||
JOY_GET_DIR(g_Joy) == 0 && !IS_JOY_PRESSED(g_Joy, JOY_INPUT_TRIGGER_A));
|
||||
|
||||
// C: teleport to exit
|
||||
// C: teleport to one move away from the exit (the final step is left
|
||||
// to the player). The exit (g_EX, MAZE_H-1) is a normal maze cell, so
|
||||
// at least one of its up/left/right neighbours has an open passage to
|
||||
// it; drop the player on the first such neighbour.
|
||||
if (IS_KEY_PRESSED(row3, KEY_C)) {
|
||||
g_MX = g_EX; g_MY = MAZE_H - 1;
|
||||
PlaySfx(SFX_CHEAT, SFX_PRIO_ACTION);
|
||||
u8 ey = MAZE_H - 1;
|
||||
if (g_DW[g_EX][ey-1] == 0) { // open above -> step down
|
||||
g_MX = g_EX; g_MY = ey - 1;
|
||||
} else if (g_EX > 0 && g_RW[g_EX-1][ey] == 0) { // open left -> step right
|
||||
g_MX = g_EX - 1; g_MY = ey;
|
||||
} else { // open right -> step left
|
||||
g_MX = g_EX + 1; g_MY = ey;
|
||||
}
|
||||
DrawFull();
|
||||
row8 = 0xFF;
|
||||
continue;
|
||||
@@ -1058,6 +1209,7 @@ void main(void)
|
||||
|
||||
// M key or joystick button A: show minimap while held
|
||||
if (IS_KEY_PRESSED(row4, KEY_M) || IS_JOY_PRESSED(g_Joy, JOY_INPUT_TRIGGER_A)) {
|
||||
PlaySfx(SFX_MINIMAP, SFX_PRIO_ACTION);
|
||||
VDP_EnableDisplay(FALSE);
|
||||
// Minimap is drawn at absolute VRAM (0,0); show it with zero
|
||||
// scroll offset regardless of the current torus base.
|
||||
@@ -1070,7 +1222,7 @@ void main(void)
|
||||
do {
|
||||
Halt();
|
||||
row4 = Keyboard_Read(4);
|
||||
g_Joy = Joystick_Read(JOY_PORT_1);
|
||||
g_Joy = ReadJoy();
|
||||
} while (IS_KEY_PRESSED(row4, KEY_M) || IS_JOY_PRESSED(g_Joy, JOY_INPUT_TRIGGER_A));
|
||||
// Restore game view (DrawFull includes DrawSprite). Put the
|
||||
// scroll offset back to the current torus base first.
|
||||
@@ -1121,10 +1273,12 @@ void main(void)
|
||||
|
||||
g_MX += (u8)dx;
|
||||
g_MY += (u8)dy;
|
||||
PlaySfx((u8)(rand() % 3), SFX_PRIO_MOVE); // random cat-paw footstep (id 0-2)
|
||||
row8 = ScrollDraw(dx, dy);
|
||||
|
||||
// Win condition: reached exit cell
|
||||
if (g_MY == MAZE_H-1 && g_MX == g_EX) {
|
||||
PlaySfx(SFX_FINISH, SFX_PRIO_FINISH); // fanfare over the win screen
|
||||
ShowWinScreen();
|
||||
break; // back to outer loop → title screen → new maze
|
||||
}
|
||||
|
||||
@@ -0,0 +1,334 @@
|
||||
#include "msxgl.h"
|
||||
|
||||
// lVGM music track — title screen.
|
||||
// Occupies the start of banked segment 26 (bank-2 window 0x8000-0x9FFF,
|
||||
// via SET_BANK_SEGMENT(2, 26)). MSX-Music (YM2413/OPLL), 60 Hz, looping.
|
||||
// 5186 bytes; the rest of the 8KB segment is unused padding.
|
||||
// Access: LVGM_Play((const u8*)0x8000, TRUE) with segment 26 banked in.
|
||||
const u8 g_MusTitle[5186] = {
|
||||
0x6C, 0x56, 0x47, 0x4D, 0x06, 0x02, 0xF1, 0x16, 0x20, 0xFE, 0x26, 0x05, 0x17, 0x50, 0x27, 0x05,
|
||||
0x18, 0xC0, 0x28, 0x01, 0x56, 0x00, 0x0E, 0x20, 0x10, 0xB3, 0x20, 0x19, 0x30, 0x42, 0x11, 0x59,
|
||||
0x21, 0x17, 0x31, 0xB6, 0x12, 0x59, 0x22, 0x13, 0x32, 0xE4, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE6,
|
||||
0x21, 0x07, 0x11, 0xB3, 0x21, 0x17, 0xE6, 0x21, 0x07, 0x11, 0x02, 0x21, 0x19, 0x22, 0x03, 0x12,
|
||||
0x02, 0x22, 0x15, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE6, 0x21, 0x09, 0x11, 0xB3, 0x21, 0x17, 0xE6,
|
||||
0x21, 0x07, 0x11, 0x59, 0x21, 0x17, 0x22, 0x05, 0x12, 0x59, 0x22, 0x13, 0x0E, 0x28, 0xE0, 0x0E,
|
||||
0x20, 0xE6, 0x21, 0x07, 0x11, 0xB3, 0x21, 0x17, 0xE6, 0x20, 0x09, 0x10, 0x02, 0x20, 0x1B, 0x21,
|
||||
0x07, 0x11, 0x02, 0x21, 0x19, 0x22, 0x03, 0x12, 0x02, 0x22, 0x15, 0x0E, 0x21, 0xE0, 0x0E, 0x20,
|
||||
0xE6, 0x21, 0x09, 0x11, 0xB3, 0x21, 0x17, 0xE6, 0x20, 0x0B, 0x10, 0x59, 0x20, 0x19, 0x21, 0x07,
|
||||
0x11, 0x83, 0x21, 0x17, 0x22, 0x05, 0x12, 0x83, 0x22, 0x13, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE6,
|
||||
0x21, 0x07, 0x11, 0xCC, 0x21, 0x17, 0xE6, 0x20, 0x09, 0x10, 0x83, 0x20, 0x19, 0x21, 0x07, 0x11,
|
||||
0x22, 0x21, 0x19, 0x22, 0x03, 0x12, 0x22, 0x22, 0x15, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE6, 0x21,
|
||||
0x09, 0x11, 0xCC, 0x21, 0x17, 0xE6, 0x20, 0x09, 0x10, 0xB3, 0x20, 0x19, 0x21, 0x07, 0x11, 0x83,
|
||||
0x21, 0x17, 0x22, 0x05, 0x12, 0x83, 0x22, 0x13, 0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE6, 0x21, 0x07,
|
||||
0x11, 0xCC, 0x21, 0x17, 0xE6, 0x21, 0x07, 0x11, 0x22, 0x21, 0x19, 0x22, 0x03, 0x12, 0x22, 0x22,
|
||||
0x15, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE6, 0x21, 0x09, 0x11, 0xCC, 0x21, 0x17, 0xE6, 0x20, 0x09,
|
||||
0x10, 0x02, 0x20, 0x1B, 0x21, 0x07, 0x11, 0xB3, 0x21, 0x17, 0x22, 0x05, 0x12, 0xB3, 0x22, 0x13,
|
||||
0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0x05, 0xE0, 0x10, 0x02, 0xE0, 0x10, 0xFF, 0x20, 0x19,
|
||||
0xE0, 0x10, 0xFC, 0xE0, 0x21, 0x07, 0x11, 0x02, 0x21, 0x19, 0xE0, 0x10, 0xFF, 0xE0, 0x10, 0x02,
|
||||
0x20, 0x1B, 0xE0, 0x10, 0x05, 0xE0, 0x10, 0x07, 0xE1, 0x10, 0x05, 0xE0, 0x10, 0x02, 0x21, 0x09,
|
||||
0x11, 0x46, 0x21, 0x19, 0x22, 0x03, 0x12, 0x46, 0x22, 0x15, 0x0E, 0x21, 0xE0, 0x10, 0xFF, 0x20,
|
||||
0x19, 0x0E, 0x20, 0xE0, 0x10, 0xFC, 0xE1, 0x10, 0xFF, 0xE0, 0x10, 0x02, 0x20, 0x1B, 0xE0, 0x10,
|
||||
0x05, 0xE0, 0x10, 0x07, 0xE0, 0x21, 0x09, 0x11, 0x02, 0x21, 0x19, 0xE0, 0x10, 0x05, 0xE0, 0x10,
|
||||
0x02, 0xE0, 0x10, 0xFF, 0x20, 0x19, 0xE0, 0x10, 0xFC, 0xE1, 0x10, 0xFF, 0xE0, 0x10, 0x02, 0x20,
|
||||
0x1B, 0x21, 0x09, 0x11, 0xB3, 0x21, 0x17, 0x22, 0x05, 0x12, 0xB3, 0x22, 0x13, 0x0E, 0x28, 0xE0,
|
||||
0x10, 0x05, 0x0E, 0x20, 0xE0, 0x10, 0x07, 0xE1, 0x10, 0x05, 0xE0, 0x10, 0x02, 0xE0, 0x10, 0xFF,
|
||||
0x20, 0x19, 0xE0, 0x10, 0xFC, 0xE0, 0x21, 0x07, 0x11, 0x02, 0x21, 0x19, 0xE0, 0x10, 0xFF, 0xE0,
|
||||
0x10, 0x02, 0x20, 0x1B, 0xE0, 0x10, 0x05, 0xE0, 0x10, 0x07, 0xE1, 0x10, 0x05, 0xE0, 0x10, 0x02,
|
||||
0x21, 0x09, 0x11, 0x46, 0x21, 0x19, 0x22, 0x03, 0x12, 0x46, 0x22, 0x15, 0x0E, 0x21, 0xE0, 0x10,
|
||||
0xFF, 0x20, 0x19, 0x0E, 0x20, 0xE0, 0x10, 0xFC, 0xE1, 0x10, 0xFF, 0xE0, 0x10, 0x02, 0x20, 0x1B,
|
||||
0xE0, 0x10, 0x05, 0xE0, 0x10, 0x07, 0xE0, 0x21, 0x09, 0x11, 0x02, 0x21, 0x19, 0xE0, 0x10, 0x05,
|
||||
0xE0, 0x10, 0x02, 0xE0, 0x10, 0xFF, 0x20, 0x19, 0xE0, 0x10, 0xFC, 0xE1, 0x10, 0xFF, 0xE0, 0x20,
|
||||
0x09, 0x21, 0x09, 0x11, 0x59, 0x21, 0x17, 0x22, 0x05, 0x12, 0x59, 0x22, 0x13, 0x0E, 0x30, 0xE0,
|
||||
0x0E, 0x20, 0xE6, 0x21, 0x07, 0x11, 0xB3, 0x21, 0x17, 0xE6, 0x10, 0xB3, 0x20, 0x19, 0x21, 0x07,
|
||||
0x11, 0x02, 0x21, 0x19, 0x22, 0x03, 0x12, 0x02, 0x22, 0x15, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE2,
|
||||
0x10, 0xB7, 0xE0, 0x10, 0xB3, 0xE0, 0x10, 0xAE, 0xE0, 0x10, 0xAB, 0xE0, 0x21, 0x09, 0x11, 0xB3,
|
||||
0x21, 0x17, 0xE0, 0x10, 0xAE, 0xE0, 0x10, 0xB3, 0xE0, 0x10, 0xB7, 0xE0, 0x10, 0xBA, 0xE1, 0x10,
|
||||
0xB7, 0xE0, 0x20, 0x09, 0x10, 0x02, 0x20, 0x1B, 0x21, 0x07, 0x11, 0x59, 0x21, 0x17, 0x22, 0x05,
|
||||
0x12, 0x59, 0x22, 0x13, 0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0x05, 0xE0, 0x10, 0x02, 0xE0,
|
||||
0x10, 0xFF, 0x20, 0x19, 0xE0, 0x10, 0xFC, 0xE0, 0x21, 0x07, 0x11, 0xB3, 0x21, 0x17, 0xE0, 0x10,
|
||||
0xFF, 0xE0, 0x10, 0x02, 0x20, 0x1B, 0xE0, 0x10, 0x05, 0xE0, 0x10, 0x07, 0xE1, 0x10, 0x05, 0xE0,
|
||||
0x20, 0x0B, 0x10, 0x22, 0x20, 0x1B, 0x21, 0x07, 0x11, 0x02, 0x21, 0x19, 0x22, 0x03, 0x12, 0x02,
|
||||
0x22, 0x15, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0x25, 0xE0, 0x10, 0x22, 0xE0, 0x10, 0x1F,
|
||||
0xE0, 0x10, 0x1D, 0xE0, 0x21, 0x09, 0x11, 0xB3, 0x21, 0x17, 0xE0, 0x10, 0x1F, 0xE0, 0x10, 0x22,
|
||||
0xE0, 0x10, 0x25, 0xE0, 0x10, 0x27, 0xE1, 0x10, 0x25, 0xE0, 0x20, 0x0B, 0x10, 0x02, 0x20, 0x1B,
|
||||
0x21, 0x07, 0x11, 0x22, 0x21, 0x19, 0x22, 0x05, 0x12, 0x22, 0x22, 0x15, 0x0E, 0x30, 0xE0, 0x0E,
|
||||
0x20, 0xE2, 0x10, 0x05, 0xE0, 0x10, 0x02, 0xE0, 0x10, 0xFF, 0x20, 0x19, 0xE0, 0x10, 0xFC, 0xE0,
|
||||
0x21, 0x09, 0x11, 0x59, 0x21, 0x19, 0xE0, 0x10, 0xFF, 0xE0, 0x10, 0x02, 0x20, 0x1B, 0xE0, 0x10,
|
||||
0x05, 0xE0, 0x10, 0x07, 0xE1, 0x10, 0x05, 0xE0, 0x10, 0x02, 0x21, 0x09, 0x11, 0xB3, 0x21, 0x19,
|
||||
0x22, 0x05, 0x12, 0xB3, 0x22, 0x15, 0x0E, 0x21, 0xE0, 0x10, 0xFF, 0x20, 0x19, 0x0E, 0x20, 0xE0,
|
||||
0x10, 0xFC, 0xE1, 0x10, 0xFF, 0xE0, 0x10, 0x02, 0x20, 0x1B, 0xE0, 0x10, 0x05, 0xE0, 0x10, 0x07,
|
||||
0xE0, 0x21, 0x09, 0x11, 0x22, 0x21, 0x19, 0xE0, 0x10, 0x05, 0xE0, 0x10, 0x02, 0xE0, 0x10, 0xFF,
|
||||
0x20, 0x19, 0xE0, 0x10, 0xFC, 0xE1, 0x10, 0xFF, 0xE0, 0x10, 0x02, 0x20, 0x1B, 0x21, 0x09, 0x21,
|
||||
0x19, 0x22, 0x05, 0x12, 0x22, 0x22, 0x17, 0x0E, 0x28, 0xE0, 0x10, 0x05, 0x0E, 0x20, 0xE0, 0x10,
|
||||
0x07, 0xE1, 0x10, 0x05, 0xE0, 0x10, 0x02, 0xE0, 0x10, 0xFF, 0x20, 0x19, 0xE0, 0x10, 0xFC, 0xE0,
|
||||
0x21, 0x09, 0x11, 0x59, 0x21, 0x19, 0xE0, 0x10, 0xFF, 0xE0, 0x10, 0x02, 0x20, 0x1B, 0xE0, 0x10,
|
||||
0x05, 0xE0, 0x10, 0x07, 0xE1, 0x10, 0x05, 0xE0, 0x20, 0x0B, 0x10, 0xB3, 0x20, 0x19, 0x21, 0x09,
|
||||
0x11, 0xB3, 0x21, 0x19, 0x22, 0x07, 0x12, 0xB3, 0x22, 0x17, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE2,
|
||||
0x10, 0xB7, 0xE0, 0x10, 0xB3, 0xE0, 0x10, 0xAE, 0xE0, 0x10, 0xAB, 0xE0, 0x21, 0x09, 0x11, 0x22,
|
||||
0x21, 0x19, 0xE0, 0x10, 0xAE, 0xE0, 0x10, 0xB3, 0xE0, 0x10, 0xB7, 0xE0, 0x10, 0xBA, 0xE1, 0x10,
|
||||
0xB7, 0xE0, 0x20, 0x09, 0x10, 0x83, 0x20, 0x19, 0x21, 0x09, 0x11, 0xCC, 0x21, 0x17, 0x22, 0x07,
|
||||
0x12, 0xCC, 0x22, 0x15, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0x87, 0xE0, 0x10, 0x83, 0xE0,
|
||||
0x10, 0x7F, 0xE0, 0x10, 0x7C, 0xE0, 0x21, 0x07, 0x11, 0x22, 0x21, 0x19, 0xE0, 0x10, 0x7F, 0xE0,
|
||||
0x10, 0x83, 0xE0, 0x10, 0x87, 0xE0, 0x10, 0x8A, 0xE1, 0x10, 0x87, 0xE0, 0x10, 0x83, 0x21, 0x09,
|
||||
0x11, 0x59, 0x21, 0x19, 0x22, 0x05, 0x12, 0x59, 0x22, 0x17, 0x0E, 0x21, 0xE0, 0x10, 0x7F, 0x0E,
|
||||
0x20, 0xE0, 0x10, 0x7C, 0xE1, 0x10, 0x7F, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x87, 0xE0, 0x10, 0x8A,
|
||||
0xE0, 0x21, 0x09, 0x11, 0xCC, 0x21, 0x17, 0xE0, 0x10, 0x87, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x7F,
|
||||
0xE0, 0x10, 0x7C, 0xE1, 0x10, 0x7F, 0xE0, 0x10, 0x83, 0x21, 0x07, 0x21, 0x17, 0x22, 0x07, 0x12,
|
||||
0xCC, 0x22, 0x15, 0x0E, 0x28, 0xE0, 0x10, 0x87, 0x0E, 0x20, 0xE0, 0x10, 0x8A, 0xE1, 0x10, 0x87,
|
||||
0xE0, 0x10, 0x83, 0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x7C, 0xE0, 0x21, 0x07, 0x11, 0x22, 0x21, 0x19,
|
||||
0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x87, 0xE0, 0x10, 0x8A, 0xE1, 0x10, 0x87, 0xE0,
|
||||
0x10, 0x83, 0x21, 0x09, 0x11, 0x59, 0x21, 0x19, 0x22, 0x05, 0x12, 0x59, 0x22, 0x17, 0x0E, 0x21,
|
||||
0xE0, 0x10, 0x7F, 0x0E, 0x20, 0xE0, 0x10, 0x7C, 0xE1, 0x10, 0x7F, 0xE0, 0x10, 0x83, 0xE0, 0x10,
|
||||
0x87, 0xE0, 0x10, 0x8A, 0xE0, 0x21, 0x09, 0x11, 0xCC, 0x21, 0x17, 0xE0, 0x10, 0x87, 0xE0, 0x10,
|
||||
0x83, 0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x7C, 0xE1, 0x10, 0x7F, 0xE0, 0x20, 0x09, 0x21, 0x07, 0x11,
|
||||
0x02, 0x21, 0x19, 0x22, 0x07, 0x12, 0x02, 0x22, 0x17, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE6, 0x21,
|
||||
0x09, 0x11, 0x46, 0x21, 0x19, 0xE6, 0x21, 0x09, 0x11, 0x83, 0x21, 0x19, 0x22, 0x07, 0x12, 0x83,
|
||||
0x22, 0x17, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE6, 0x21, 0x09, 0x11, 0x02, 0x21, 0x19, 0xE6, 0x10,
|
||||
0x59, 0x20, 0x19, 0x21, 0x09, 0x21, 0x19, 0x22, 0x07, 0x12, 0x02, 0x22, 0x17, 0x0E, 0x28, 0xE0,
|
||||
0x0E, 0x20, 0xE2, 0x10, 0x5D, 0xE0, 0x10, 0x59, 0xE0, 0x10, 0x55, 0xE0, 0x10, 0x53, 0xE0, 0x21,
|
||||
0x09, 0x11, 0x46, 0x21, 0x19, 0xE0, 0x10, 0x55, 0xE0, 0x10, 0x59, 0xE0, 0x10, 0x5D, 0xE0, 0x10,
|
||||
0x5F, 0xE1, 0x10, 0x5D, 0xE0, 0x10, 0x59, 0x21, 0x09, 0x11, 0x83, 0x21, 0x19, 0x22, 0x07, 0x12,
|
||||
0x83, 0x22, 0x17, 0x0E, 0x21, 0xE0, 0x10, 0x55, 0x0E, 0x20, 0xE0, 0x10, 0x53, 0xE1, 0x10, 0x55,
|
||||
0xE0, 0x10, 0x59, 0xE0, 0x10, 0x5D, 0xE0, 0x10, 0x5F, 0xE0, 0x21, 0x09, 0x11, 0x02, 0x21, 0x19,
|
||||
0xE0, 0x10, 0x5D, 0xE0, 0x10, 0x59, 0xE0, 0x10, 0x55, 0xE0, 0x10, 0x53, 0xE1, 0x10, 0x55, 0xE0,
|
||||
0x10, 0x59, 0x21, 0x09, 0x21, 0x19, 0x22, 0x07, 0x12, 0x02, 0x22, 0x17, 0x0E, 0x30, 0xE0, 0x10,
|
||||
0x5D, 0x0E, 0x20, 0xE0, 0x10, 0x5F, 0xE1, 0x10, 0x5D, 0xE0, 0x10, 0x59, 0xE0, 0x10, 0x55, 0xE0,
|
||||
0x10, 0x53, 0xE0, 0x21, 0x09, 0x11, 0x46, 0x21, 0x19, 0xE0, 0x10, 0x55, 0xE0, 0x10, 0x59, 0xE0,
|
||||
0x10, 0x5D, 0xE0, 0x10, 0x5F, 0xE1, 0x10, 0x5D, 0xE0, 0x20, 0x09, 0x10, 0x83, 0x20, 0x19, 0x21,
|
||||
0x09, 0x11, 0x83, 0x21, 0x19, 0x22, 0x07, 0x12, 0x83, 0x22, 0x17, 0x0E, 0x21, 0xE0, 0x0E, 0x20,
|
||||
0xE2, 0x10, 0x87, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x7C, 0xE0, 0x21, 0x09, 0x11,
|
||||
0x02, 0x21, 0x19, 0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x87, 0xE0, 0x10, 0x8A, 0xE1,
|
||||
0x10, 0x87, 0xE0, 0x20, 0x09, 0x10, 0xB3, 0x20, 0x19, 0x21, 0x09, 0x21, 0x19, 0x22, 0x07, 0x12,
|
||||
0x02, 0x22, 0x17, 0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0xB7, 0xE0, 0x10, 0xB3, 0xE0, 0x10,
|
||||
0xAE, 0xE0, 0x10, 0xAB, 0xE0, 0x21, 0x09, 0x11, 0x46, 0x21, 0x19, 0xE0, 0x10, 0xAE, 0xE0, 0x10,
|
||||
0xB3, 0xE0, 0x10, 0xB7, 0xE0, 0x10, 0xBA, 0xE1, 0x10, 0xB7, 0xE0, 0x20, 0x09, 0x10, 0x02, 0x20,
|
||||
0x1B, 0x21, 0x09, 0x11, 0x83, 0x21, 0x19, 0x22, 0x07, 0x12, 0x83, 0x22, 0x17, 0x0E, 0x21, 0xE0,
|
||||
0x0E, 0x20, 0xE2, 0x10, 0x05, 0xE0, 0x10, 0x02, 0xE0, 0x10, 0xFF, 0x20, 0x19, 0xE0, 0x10, 0xFC,
|
||||
0xE0, 0x21, 0x09, 0x11, 0x02, 0x21, 0x19, 0xE0, 0x10, 0xFF, 0xE0, 0x10, 0x02, 0x20, 0x1B, 0xE0,
|
||||
0x10, 0x05, 0xE0, 0x10, 0x07, 0xE1, 0x10, 0x05, 0xE0, 0x20, 0x0B, 0x10, 0xB3, 0x20, 0x19, 0x21,
|
||||
0x09, 0x11, 0x59, 0x21, 0x17, 0x22, 0x07, 0x12, 0x59, 0x22, 0x13, 0x0E, 0x30, 0xE0, 0x0E, 0x20,
|
||||
0xE2, 0x10, 0xB7, 0xE0, 0x10, 0xB3, 0xE0, 0x10, 0xAE, 0xE0, 0x10, 0xAB, 0xE0, 0x21, 0x07, 0x11,
|
||||
0xB3, 0x21, 0x17, 0xE0, 0x10, 0xAE, 0xE0, 0x10, 0xB3, 0xE0, 0x10, 0xB7, 0xE0, 0x10, 0xBA, 0xE1,
|
||||
0x10, 0xB7, 0xE0, 0x10, 0xB3, 0x21, 0x07, 0x11, 0x02, 0x21, 0x19, 0x22, 0x03, 0x12, 0x02, 0x22,
|
||||
0x15, 0x0E, 0x21, 0xE0, 0x10, 0xAE, 0x0E, 0x20, 0xE0, 0x10, 0xAB, 0xE1, 0x10, 0xAE, 0xE0, 0x10,
|
||||
0xB3, 0xE0, 0x10, 0xB7, 0xE0, 0x10, 0xBA, 0xE0, 0x21, 0x09, 0x11, 0xB3, 0x21, 0x17, 0xE0, 0x10,
|
||||
0xB7, 0xE0, 0x10, 0xB3, 0xE0, 0x10, 0xAE, 0xE0, 0x10, 0xAB, 0xE1, 0x10, 0xAE, 0xE0, 0x20, 0x09,
|
||||
0x10, 0x83, 0x20, 0x19, 0x21, 0x07, 0x11, 0x59, 0x21, 0x17, 0x22, 0x05, 0x12, 0x59, 0x22, 0x13,
|
||||
0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0x87, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x7F, 0xE0, 0x10,
|
||||
0x7C, 0xE0, 0x21, 0x07, 0x11, 0xB3, 0x21, 0x17, 0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x83, 0xE0, 0x10,
|
||||
0x87, 0xE0, 0x10, 0x8A, 0xE1, 0x10, 0x87, 0xE0, 0x20, 0x09, 0x10, 0x59, 0x20, 0x19, 0x21, 0x07,
|
||||
0x11, 0x02, 0x21, 0x19, 0x22, 0x03, 0x12, 0x02, 0x22, 0x15, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE2,
|
||||
0x10, 0x5D, 0xE0, 0x10, 0x59, 0xE0, 0x10, 0x55, 0xE0, 0x10, 0x53, 0xE0, 0x21, 0x09, 0x11, 0xB3,
|
||||
0x21, 0x17, 0xE0, 0x10, 0x55, 0xE0, 0x10, 0x59, 0xE0, 0x10, 0x5D, 0xE0, 0x10, 0x5F, 0xE1, 0x10,
|
||||
0x5D, 0xE0, 0x20, 0x09, 0x10, 0x46, 0x20, 0x19, 0x21, 0x07, 0x11, 0x83, 0x21, 0x17, 0x22, 0x05,
|
||||
0x12, 0x83, 0x22, 0x13, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0x49, 0xE0, 0x10, 0x46, 0xE0,
|
||||
0x10, 0x42, 0xE0, 0x10, 0x40, 0xE0, 0x21, 0x07, 0x11, 0xCC, 0x21, 0x17, 0xE0, 0x10, 0x42, 0xE0,
|
||||
0x10, 0x46, 0xE0, 0x10, 0x49, 0xE0, 0x10, 0x4B, 0xE1, 0x10, 0x49, 0xE0, 0x10, 0x46, 0x21, 0x07,
|
||||
0x11, 0x22, 0x21, 0x19, 0x22, 0x03, 0x12, 0x22, 0x22, 0x15, 0x0E, 0x21, 0xE0, 0x10, 0x42, 0x0E,
|
||||
0x20, 0xE0, 0x10, 0x40, 0xE1, 0x10, 0x42, 0xE0, 0x10, 0x46, 0xE0, 0x10, 0x49, 0xE0, 0x10, 0x4B,
|
||||
0xE0, 0x21, 0x09, 0x11, 0xCC, 0x21, 0x17, 0xE0, 0x10, 0x49, 0xE0, 0x10, 0x46, 0xE0, 0x10, 0x42,
|
||||
0xE0, 0x10, 0x40, 0xE1, 0x10, 0x42, 0xE0, 0x20, 0x09, 0x10, 0x59, 0x20, 0x19, 0x21, 0x07, 0x11,
|
||||
0x83, 0x21, 0x17, 0x22, 0x05, 0x12, 0x83, 0x22, 0x13, 0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE2, 0x10,
|
||||
0x5D, 0xE0, 0x10, 0x59, 0xE0, 0x10, 0x55, 0xE0, 0x10, 0x53, 0xE0, 0x21, 0x07, 0x11, 0xCC, 0x21,
|
||||
0x17, 0xE0, 0x10, 0x55, 0xE0, 0x10, 0x59, 0xE0, 0x10, 0x5D, 0xE0, 0x10, 0x5F, 0xE1, 0x10, 0x5D,
|
||||
0xE0, 0x10, 0x59, 0x21, 0x07, 0x11, 0x22, 0x21, 0x19, 0x22, 0x03, 0x12, 0x22, 0x22, 0x15, 0x0E,
|
||||
0x21, 0xE0, 0x10, 0x55, 0x0E, 0x20, 0xE0, 0x10, 0x53, 0xE1, 0x10, 0x55, 0xE0, 0x10, 0x59, 0xE0,
|
||||
0x10, 0x5D, 0xE0, 0x10, 0x5F, 0xE0, 0x21, 0x09, 0x11, 0xCC, 0x21, 0x17, 0xE0, 0x10, 0x5D, 0xE0,
|
||||
0x10, 0x59, 0xE0, 0x10, 0x55, 0xE0, 0x10, 0x53, 0xE1, 0x10, 0x55, 0xE0, 0x20, 0x09, 0x10, 0x83,
|
||||
0x20, 0x19, 0x21, 0x07, 0x11, 0xB3, 0x21, 0x17, 0x22, 0x05, 0x12, 0xB3, 0x22, 0x13, 0x0E, 0x30,
|
||||
0xE0, 0x0E, 0x20, 0xE2, 0x10, 0x87, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x7C, 0xE0,
|
||||
0x21, 0x07, 0x11, 0x02, 0x21, 0x19, 0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x87, 0xE0,
|
||||
0x10, 0x8A, 0xE1, 0x10, 0x87, 0xE0, 0x20, 0x09, 0x10, 0xB3, 0x20, 0x19, 0x21, 0x09, 0x11, 0x46,
|
||||
0x21, 0x19, 0x22, 0x03, 0x12, 0x46, 0x22, 0x15, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0xB7,
|
||||
0xE0, 0x10, 0xB3, 0xE0, 0x10, 0xAE, 0xE0, 0x10, 0xAB, 0xE0, 0x21, 0x09, 0x11, 0x02, 0x21, 0x19,
|
||||
0xE0, 0x10, 0xAE, 0xE0, 0x10, 0xB3, 0xE0, 0x10, 0xB7, 0xE0, 0x10, 0xBA, 0xE1, 0x10, 0xB7, 0xE0,
|
||||
0x20, 0x09, 0x10, 0x83, 0x20, 0x19, 0x21, 0x09, 0x11, 0xB3, 0x21, 0x17, 0x22, 0x05, 0x12, 0xB3,
|
||||
0x22, 0x13, 0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0x87, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x7F,
|
||||
0xE0, 0x10, 0x7C, 0xE0, 0x21, 0x07, 0x11, 0x02, 0x21, 0x19, 0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x83,
|
||||
0xE0, 0x10, 0x87, 0xE0, 0x10, 0x8A, 0xE1, 0x10, 0x87, 0xE0, 0x10, 0x83, 0x21, 0x09, 0x11, 0x46,
|
||||
0x21, 0x19, 0x22, 0x03, 0x12, 0x46, 0x22, 0x15, 0x0E, 0x21, 0xE0, 0x10, 0x7F, 0x0E, 0x20, 0xE0,
|
||||
0x10, 0x7C, 0xE1, 0x10, 0x7F, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x87, 0xE0, 0x10, 0x8A, 0xE0, 0x21,
|
||||
0x09, 0x11, 0x02, 0x21, 0x19, 0xE0, 0x10, 0x87, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x7F, 0xE0, 0x10,
|
||||
0x7C, 0xE1, 0x10, 0x7F, 0xE0, 0x10, 0x83, 0x21, 0x09, 0x11, 0x59, 0x21, 0x17, 0x22, 0x05, 0x12,
|
||||
0x59, 0x22, 0x13, 0x0E, 0x30, 0xE0, 0x10, 0x87, 0x0E, 0x20, 0xE0, 0x10, 0x8A, 0xE1, 0x10, 0x87,
|
||||
0xE0, 0x10, 0x83, 0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x7C, 0xE0, 0x21, 0x07, 0x11, 0xB3, 0x21, 0x17,
|
||||
0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x87, 0xE0, 0x10, 0x8A, 0xE1, 0x10, 0x87, 0xE0,
|
||||
0x20, 0x09, 0x10, 0x59, 0x20, 0x19, 0x21, 0x07, 0x11, 0x02, 0x21, 0x19, 0x22, 0x03, 0x12, 0x02,
|
||||
0x22, 0x15, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0x5D, 0xE0, 0x10, 0x59, 0xE0, 0x10, 0x55,
|
||||
0xE0, 0x10, 0x53, 0xE0, 0x21, 0x09, 0x11, 0xB3, 0x21, 0x17, 0xE0, 0x10, 0x55, 0xE0, 0x10, 0x59,
|
||||
0xE0, 0x10, 0x5D, 0xE0, 0x10, 0x5F, 0xE1, 0x10, 0x5D, 0xE0, 0x20, 0x09, 0x10, 0x46, 0x20, 0x19,
|
||||
0x21, 0x07, 0x11, 0x59, 0x21, 0x17, 0x22, 0x05, 0x12, 0x59, 0x22, 0x13, 0x0E, 0x28, 0xE0, 0x0E,
|
||||
0x20, 0xE2, 0x10, 0x49, 0xE0, 0x10, 0x46, 0xE0, 0x10, 0x42, 0xE0, 0x10, 0x40, 0xE0, 0x21, 0x07,
|
||||
0x11, 0xB3, 0x21, 0x17, 0xE0, 0x10, 0x42, 0xE0, 0x10, 0x46, 0xE0, 0x10, 0x49, 0xE0, 0x10, 0x4B,
|
||||
0xE1, 0x10, 0x49, 0xE0, 0x10, 0x46, 0x21, 0x07, 0x11, 0x02, 0x21, 0x19, 0x22, 0x03, 0x12, 0x02,
|
||||
0x22, 0x15, 0x0E, 0x21, 0xE0, 0x10, 0x42, 0x0E, 0x20, 0xE0, 0x10, 0x40, 0xE1, 0x10, 0x42, 0xE0,
|
||||
0x10, 0x46, 0xE0, 0x10, 0x49, 0xE0, 0x10, 0x4B, 0xE0, 0x21, 0x09, 0x11, 0xB3, 0x21, 0x17, 0xE0,
|
||||
0x10, 0x49, 0xE0, 0x10, 0x46, 0xE0, 0x10, 0x42, 0xE0, 0x10, 0x40, 0xE1, 0x10, 0x42, 0xE0, 0x10,
|
||||
0x46, 0x21, 0x07, 0x11, 0x22, 0x21, 0x19, 0x22, 0x05, 0x12, 0x22, 0x22, 0x15, 0x0E, 0x30, 0xE0,
|
||||
0x10, 0x49, 0x0E, 0x20, 0xE0, 0x10, 0x4B, 0xE1, 0x10, 0x49, 0xE0, 0x10, 0x46, 0xE0, 0x10, 0x42,
|
||||
0xE0, 0x10, 0x40, 0xE0, 0x21, 0x09, 0x11, 0x59, 0x21, 0x19, 0xE0, 0x10, 0x42, 0xE0, 0x10, 0x46,
|
||||
0xE0, 0x10, 0x49, 0xE0, 0x10, 0x4B, 0xE1, 0x10, 0x49, 0xE0, 0x10, 0x46, 0x21, 0x09, 0x11, 0xB3,
|
||||
0x21, 0x19, 0x22, 0x05, 0x12, 0xB3, 0x22, 0x15, 0x0E, 0x21, 0xE0, 0x10, 0x42, 0x0E, 0x20, 0xE0,
|
||||
0x10, 0x40, 0xE1, 0x10, 0x42, 0xE0, 0x10, 0x46, 0xE0, 0x10, 0x49, 0xE0, 0x10, 0x4B, 0xE0, 0x21,
|
||||
0x09, 0x11, 0x22, 0x21, 0x19, 0xE0, 0x10, 0x49, 0xE0, 0x10, 0x46, 0xE0, 0x10, 0x42, 0xE0, 0x10,
|
||||
0x40, 0xE1, 0x10, 0x42, 0xE0, 0x20, 0x09, 0x21, 0x09, 0x21, 0x19, 0x22, 0x05, 0x12, 0x22, 0x22,
|
||||
0x17, 0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE6, 0x21, 0x09, 0x11, 0x59, 0x21, 0x19, 0xE6, 0x21, 0x09,
|
||||
0x11, 0xB3, 0x21, 0x19, 0x22, 0x07, 0x12, 0xB3, 0x22, 0x17, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE6,
|
||||
0x21, 0x09, 0x11, 0x22, 0x21, 0x19, 0xE6, 0x10, 0x02, 0x20, 0x1B, 0x30, 0x11, 0x21, 0x09, 0x11,
|
||||
0xCC, 0x21, 0x17, 0x22, 0x07, 0x12, 0xCC, 0x22, 0x15, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE2, 0x10,
|
||||
0x05, 0xE0, 0x10, 0x02, 0xE0, 0x10, 0xFF, 0x20, 0x19, 0xE0, 0x10, 0xFC, 0xE0, 0x21, 0x07, 0x11,
|
||||
0x22, 0x21, 0x19, 0xE0, 0x10, 0xFF, 0xE0, 0x10, 0x02, 0x20, 0x1B, 0xE0, 0x10, 0x05, 0xE0, 0x10,
|
||||
0x07, 0xE1, 0x10, 0x05, 0xE0, 0x10, 0x02, 0x21, 0x09, 0x11, 0x59, 0x21, 0x19, 0x22, 0x05, 0x12,
|
||||
0x59, 0x22, 0x17, 0x0E, 0x21, 0xE0, 0x10, 0xFF, 0x20, 0x19, 0x0E, 0x20, 0xE0, 0x10, 0xFC, 0xE1,
|
||||
0x10, 0xFF, 0xE0, 0x10, 0x02, 0x20, 0x1B, 0xE0, 0x10, 0x05, 0xE0, 0x10, 0x07, 0xE0, 0x21, 0x09,
|
||||
0x11, 0xCC, 0x21, 0x17, 0xE0, 0x10, 0x05, 0xE0, 0x10, 0x02, 0xE0, 0x10, 0xFF, 0x20, 0x19, 0xE0,
|
||||
0x10, 0xFC, 0xE1, 0x10, 0xFF, 0xE0, 0x10, 0x02, 0x20, 0x1B, 0x21, 0x07, 0x21, 0x17, 0x22, 0x07,
|
||||
0x12, 0xCC, 0x22, 0x15, 0x0E, 0x28, 0xE0, 0x10, 0x05, 0x0E, 0x20, 0xE0, 0x10, 0x07, 0xE1, 0x10,
|
||||
0x05, 0xE0, 0x10, 0x02, 0xE0, 0x10, 0xFF, 0x20, 0x19, 0xE0, 0x10, 0xFC, 0xE0, 0x21, 0x07, 0x11,
|
||||
0x22, 0x21, 0x19, 0xE0, 0x10, 0xFF, 0xE0, 0x10, 0x02, 0x20, 0x1B, 0xE0, 0x10, 0x05, 0xE0, 0x10,
|
||||
0x07, 0xE1, 0x10, 0x05, 0xE0, 0x20, 0x0B, 0x10, 0x22, 0x20, 0x1B, 0x21, 0x09, 0x11, 0x59, 0x21,
|
||||
0x19, 0x22, 0x05, 0x12, 0x59, 0x22, 0x17, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0x25, 0xE0,
|
||||
0x10, 0x22, 0xE0, 0x10, 0x1F, 0xE0, 0x10, 0x1D, 0xE0, 0x21, 0x09, 0x11, 0xCC, 0x21, 0x17, 0xE0,
|
||||
0x10, 0x1F, 0xE0, 0x10, 0x22, 0xE0, 0x10, 0x25, 0xE0, 0x10, 0x27, 0xE1, 0x10, 0x25, 0xE0, 0x20,
|
||||
0x0B, 0x10, 0x02, 0x20, 0x1B, 0x21, 0x07, 0x11, 0x02, 0x21, 0x19, 0x22, 0x07, 0x12, 0x02, 0x22,
|
||||
0x17, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0x05, 0xE0, 0x10, 0x02, 0xE0, 0x10, 0xFF, 0x20,
|
||||
0x19, 0xE0, 0x10, 0xFC, 0xE0, 0x21, 0x09, 0x11, 0x46, 0x21, 0x19, 0xE0, 0x10, 0xFF, 0xE0, 0x10,
|
||||
0x02, 0x20, 0x1B, 0xE0, 0x10, 0x05, 0xE0, 0x10, 0x07, 0xE1, 0x10, 0x05, 0xE0, 0x20, 0x0B, 0x10,
|
||||
0xB3, 0x20, 0x19, 0x21, 0x09, 0x11, 0x83, 0x21, 0x19, 0x22, 0x07, 0x12, 0x83, 0x22, 0x17, 0x0E,
|
||||
0x21, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0xB7, 0xE0, 0x10, 0xB3, 0xE0, 0x10, 0xAE, 0xE0, 0x10, 0xAB,
|
||||
0xE0, 0x21, 0x09, 0x11, 0x02, 0x21, 0x19, 0xE0, 0x10, 0xAE, 0xE0, 0x10, 0xB3, 0xE0, 0x10, 0xB7,
|
||||
0xE0, 0x10, 0xBA, 0xE1, 0x10, 0xB7, 0xE0, 0x20, 0x09, 0x10, 0x02, 0x20, 0x1B, 0x21, 0x09, 0x21,
|
||||
0x19, 0x22, 0x07, 0x12, 0x02, 0x22, 0x17, 0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0x05, 0xE0,
|
||||
0x10, 0x02, 0xE0, 0x10, 0xFF, 0x20, 0x19, 0xE0, 0x10, 0xFC, 0xE0, 0x21, 0x09, 0x11, 0x46, 0x21,
|
||||
0x19, 0xE0, 0x10, 0xFF, 0xE0, 0x10, 0x02, 0x20, 0x1B, 0xE0, 0x10, 0x05, 0xE0, 0x10, 0x07, 0xE1,
|
||||
0x10, 0x05, 0xE0, 0x10, 0x02, 0x21, 0x09, 0x11, 0x83, 0x21, 0x19, 0x22, 0x07, 0x12, 0x83, 0x22,
|
||||
0x17, 0x0E, 0x21, 0xE0, 0x10, 0xFF, 0x20, 0x19, 0x0E, 0x20, 0xE0, 0x10, 0xFC, 0xE1, 0x10, 0xFF,
|
||||
0xE0, 0x10, 0x02, 0x20, 0x1B, 0xE0, 0x10, 0x05, 0xE0, 0x10, 0x07, 0xE0, 0x21, 0x09, 0x11, 0x02,
|
||||
0x21, 0x19, 0xE0, 0x10, 0x05, 0xE0, 0x10, 0x02, 0xE0, 0x10, 0xFF, 0x20, 0x19, 0xE0, 0x10, 0xFC,
|
||||
0xE1, 0x10, 0xFF, 0xE0, 0x20, 0x09, 0x10, 0x22, 0x20, 0x1B, 0x21, 0x09, 0x21, 0x19, 0x22, 0x07,
|
||||
0x12, 0x02, 0x22, 0x17, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0x25, 0xE0, 0x10, 0x22, 0xE0,
|
||||
0x10, 0x1F, 0xE0, 0x10, 0x1D, 0xE0, 0x21, 0x09, 0x11, 0x46, 0x21, 0x19, 0xE0, 0x10, 0x1F, 0xE0,
|
||||
0x10, 0x22, 0xE0, 0x10, 0x25, 0xE0, 0x10, 0x27, 0xE1, 0x10, 0x25, 0xE0, 0x10, 0x22, 0x21, 0x09,
|
||||
0x11, 0x83, 0x21, 0x19, 0x22, 0x07, 0x12, 0x83, 0x22, 0x17, 0x0E, 0x21, 0xE0, 0x10, 0x1F, 0x0E,
|
||||
0x20, 0xE0, 0x10, 0x1D, 0xE1, 0x10, 0x1F, 0xE0, 0x10, 0x22, 0xE0, 0x10, 0x25, 0xE0, 0x10, 0x27,
|
||||
0xE0, 0x21, 0x09, 0x11, 0x02, 0x21, 0x19, 0xE0, 0x10, 0x25, 0xE0, 0x10, 0x22, 0xE0, 0x10, 0x1F,
|
||||
0xE0, 0x10, 0x1D, 0xE1, 0x10, 0x1F, 0xE0, 0x10, 0x22, 0x21, 0x09, 0x21, 0x19, 0x22, 0x07, 0x12,
|
||||
0x02, 0x22, 0x17, 0x0E, 0x28, 0xE0, 0x10, 0x25, 0x0E, 0x20, 0xE0, 0x10, 0x27, 0xE1, 0x10, 0x25,
|
||||
0xE0, 0x10, 0x22, 0xE0, 0x10, 0x1F, 0xE0, 0x10, 0x1D, 0xE0, 0x21, 0x09, 0x11, 0x46, 0x21, 0x19,
|
||||
0xE0, 0x10, 0x1F, 0xE0, 0x10, 0x22, 0xE0, 0x10, 0x25, 0xE0, 0x10, 0x27, 0xE1, 0x10, 0x25, 0xE0,
|
||||
0x10, 0x22, 0x21, 0x09, 0x11, 0x83, 0x21, 0x19, 0x22, 0x07, 0x12, 0x83, 0x22, 0x17, 0x0E, 0x21,
|
||||
0xE0, 0x10, 0x1F, 0x0E, 0x20, 0xE0, 0x10, 0x1D, 0xE1, 0x10, 0x1F, 0xE0, 0x10, 0x22, 0xE0, 0x10,
|
||||
0x25, 0xE0, 0x10, 0x27, 0xE0, 0x21, 0x09, 0x11, 0x02, 0x21, 0x19, 0xE0, 0x10, 0x25, 0xE0, 0x10,
|
||||
0x22, 0xE0, 0x10, 0x1F, 0xE0, 0x10, 0x1D, 0xE1, 0x10, 0x1F, 0xE0, 0x20, 0x0B, 0x21, 0x09, 0x11,
|
||||
0x59, 0x21, 0x17, 0x22, 0x07, 0x12, 0x59, 0x22, 0x13, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE6, 0x21,
|
||||
0x07, 0x11, 0xB3, 0x21, 0x17, 0xE6, 0x10, 0x02, 0x20, 0x1B, 0x21, 0x07, 0x11, 0x02, 0x21, 0x19,
|
||||
0x22, 0x03, 0x12, 0x02, 0x22, 0x15, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0x05, 0xE0, 0x10,
|
||||
0x02, 0xE0, 0x10, 0xFF, 0x20, 0x19, 0xE0, 0x10, 0xFC, 0xE0, 0x21, 0x09, 0x11, 0xB3, 0x21, 0x17,
|
||||
0xE0, 0x10, 0xFF, 0xE0, 0x10, 0x02, 0x20, 0x1B, 0xE0, 0x10, 0x05, 0xE0, 0x10, 0x07, 0xE1, 0x10,
|
||||
0x05, 0xE0, 0x20, 0x0B, 0x10, 0xB3, 0x20, 0x19, 0x21, 0x07, 0x11, 0x59, 0x21, 0x17, 0x22, 0x05,
|
||||
0x12, 0x59, 0x22, 0x13, 0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0xB7, 0xE0, 0x10, 0xB3, 0xE0,
|
||||
0x10, 0xAE, 0xE0, 0x10, 0xAB, 0xE0, 0x21, 0x07, 0x11, 0xB3, 0x21, 0x17, 0xE0, 0x10, 0xAE, 0xE0,
|
||||
0x10, 0xB3, 0xE0, 0x10, 0xB7, 0xE0, 0x10, 0xBA, 0xE1, 0x10, 0xB7, 0xE0, 0x20, 0x09, 0x10, 0x83,
|
||||
0x20, 0x19, 0x21, 0x07, 0x11, 0x02, 0x21, 0x19, 0x22, 0x03, 0x12, 0x02, 0x22, 0x15, 0x0E, 0x21,
|
||||
0xE0, 0x0E, 0x20, 0xE2, 0x10, 0x87, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x7C, 0xE0,
|
||||
0x21, 0x09, 0x11, 0xB3, 0x21, 0x17, 0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x87, 0xE0,
|
||||
0x10, 0x8A, 0xE1, 0x10, 0x87, 0xE0, 0x20, 0x09, 0x10, 0x59, 0x20, 0x19, 0x21, 0x07, 0x11, 0x83,
|
||||
0x21, 0x17, 0x22, 0x05, 0x12, 0x83, 0x22, 0x13, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0x5D,
|
||||
0xE0, 0x10, 0x59, 0xE0, 0x10, 0x55, 0xE0, 0x10, 0x53, 0xE0, 0x21, 0x07, 0x11, 0xCC, 0x21, 0x17,
|
||||
0xE0, 0x10, 0x55, 0xE0, 0x10, 0x59, 0xE0, 0x10, 0x5D, 0xE0, 0x10, 0x5F, 0xE1, 0x10, 0x5D, 0xE0,
|
||||
0x10, 0x59, 0x21, 0x07, 0x11, 0x22, 0x21, 0x19, 0x22, 0x03, 0x12, 0x22, 0x22, 0x15, 0x0E, 0x21,
|
||||
0xE0, 0x10, 0x55, 0x0E, 0x20, 0xE0, 0x10, 0x53, 0xE1, 0x10, 0x55, 0xE0, 0x10, 0x59, 0xE0, 0x10,
|
||||
0x5D, 0xE0, 0x10, 0x5F, 0xE0, 0x21, 0x09, 0x11, 0xCC, 0x21, 0x17, 0xE0, 0x10, 0x5D, 0xE0, 0x10,
|
||||
0x59, 0xE0, 0x10, 0x55, 0xE0, 0x10, 0x53, 0xE1, 0x10, 0x55, 0xE0, 0x10, 0x59, 0x21, 0x07, 0x11,
|
||||
0x83, 0x21, 0x17, 0x22, 0x05, 0x12, 0x83, 0x22, 0x13, 0x0E, 0x28, 0xE0, 0x10, 0x5D, 0x0E, 0x20,
|
||||
0xE0, 0x10, 0x5F, 0xE1, 0x10, 0x5D, 0xE0, 0x10, 0x59, 0xE0, 0x10, 0x55, 0xE0, 0x10, 0x53, 0xE0,
|
||||
0x21, 0x07, 0x11, 0xCC, 0x21, 0x17, 0xE0, 0x10, 0x55, 0xE0, 0x10, 0x59, 0xE0, 0x10, 0x5D, 0xE0,
|
||||
0x10, 0x5F, 0xE1, 0x10, 0x5D, 0xE0, 0x20, 0x09, 0x10, 0x46, 0x20, 0x19, 0x21, 0x07, 0x11, 0x22,
|
||||
0x21, 0x19, 0x22, 0x03, 0x12, 0x22, 0x22, 0x15, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0x49,
|
||||
0xE0, 0x10, 0x46, 0xE0, 0x10, 0x42, 0xE0, 0x10, 0x40, 0xE0, 0x21, 0x09, 0x11, 0xCC, 0x21, 0x17,
|
||||
0xE0, 0x10, 0x42, 0xE0, 0x10, 0x46, 0xE0, 0x10, 0x49, 0xE0, 0x10, 0x4B, 0xE1, 0x10, 0x49, 0xE0,
|
||||
0x20, 0x09, 0x10, 0x59, 0x20, 0x19, 0x21, 0x07, 0x11, 0xB3, 0x21, 0x17, 0x22, 0x05, 0x12, 0xB3,
|
||||
0x22, 0x13, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0x5D, 0xE0, 0x10, 0x59, 0xE0, 0x10, 0x55,
|
||||
0xE0, 0x10, 0x53, 0xE0, 0x21, 0x07, 0x11, 0x02, 0x21, 0x19, 0xE0, 0x10, 0x55, 0xE0, 0x10, 0x59,
|
||||
0xE0, 0x10, 0x5D, 0xE0, 0x10, 0x5F, 0xE1, 0x10, 0x5D, 0xE0, 0x10, 0x59, 0x21, 0x09, 0x11, 0x46,
|
||||
0x21, 0x19, 0x22, 0x03, 0x12, 0x46, 0x22, 0x15, 0x0E, 0x21, 0xE0, 0x10, 0x55, 0x0E, 0x20, 0xE0,
|
||||
0x10, 0x53, 0xE1, 0x10, 0x55, 0xE0, 0x10, 0x59, 0xE0, 0x10, 0x5D, 0xE0, 0x10, 0x5F, 0xE0, 0x21,
|
||||
0x09, 0x11, 0x02, 0x21, 0x19, 0xE0, 0x10, 0x5D, 0xE0, 0x10, 0x59, 0xE0, 0x10, 0x55, 0xE0, 0x10,
|
||||
0x53, 0xE1, 0x10, 0x55, 0xE0, 0x10, 0x59, 0x21, 0x09, 0x11, 0xB3, 0x21, 0x17, 0x22, 0x05, 0x12,
|
||||
0xB3, 0x22, 0x13, 0x0E, 0x28, 0xE0, 0x10, 0x5D, 0x0E, 0x20, 0xE0, 0x10, 0x5F, 0xE1, 0x10, 0x5D,
|
||||
0xE0, 0x10, 0x59, 0xE0, 0x10, 0x55, 0xE0, 0x10, 0x53, 0xE0, 0x21, 0x07, 0x11, 0x02, 0x21, 0x19,
|
||||
0xE0, 0x10, 0x55, 0xE0, 0x10, 0x59, 0xE0, 0x10, 0x5D, 0xE0, 0x10, 0x5F, 0xE1, 0x10, 0x5D, 0xE0,
|
||||
0x10, 0x59, 0x21, 0x09, 0x11, 0x46, 0x21, 0x19, 0x22, 0x03, 0x12, 0x46, 0x22, 0x15, 0x0E, 0x21,
|
||||
0xE0, 0x10, 0x55, 0x0E, 0x20, 0xE0, 0x10, 0x53, 0xE1, 0x10, 0x55, 0xE0, 0x10, 0x59, 0xE0, 0x10,
|
||||
0x5D, 0xE0, 0x10, 0x5F, 0xE0, 0x21, 0x09, 0x11, 0x02, 0x21, 0x19, 0xE0, 0x10, 0x5D, 0xE0, 0x10,
|
||||
0x59, 0xE0, 0x10, 0x55, 0xE0, 0x10, 0x53, 0xE1, 0x10, 0x55, 0xE0, 0x20, 0x09, 0x21, 0x09, 0x11,
|
||||
0x59, 0x21, 0x17, 0x22, 0x05, 0x12, 0x59, 0x22, 0x13, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE6, 0x21,
|
||||
0x07, 0x11, 0xB3, 0x21, 0x17, 0xE6, 0x21, 0x07, 0x11, 0x02, 0x21, 0x19, 0x22, 0x03, 0x12, 0x02,
|
||||
0x22, 0x15, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE6, 0x21, 0x09, 0x11, 0xB3, 0x21, 0x17, 0xE6, 0x10,
|
||||
0xB3, 0x20, 0x19, 0x21, 0x07, 0x11, 0x59, 0x21, 0x17, 0x22, 0x05, 0x12, 0x59, 0x22, 0x13, 0x0E,
|
||||
0x28, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0xB7, 0xE0, 0x10, 0xB3, 0xE0, 0x10, 0xAE, 0xE0, 0x10, 0xAB,
|
||||
0xE0, 0x21, 0x07, 0x11, 0xB3, 0x21, 0x17, 0xE0, 0x10, 0xAE, 0xE0, 0x10, 0xB3, 0xE0, 0x10, 0xB7,
|
||||
0xE0, 0x10, 0xBA, 0xE1, 0x10, 0xB7, 0xE0, 0x10, 0xB3, 0x21, 0x07, 0x11, 0x02, 0x21, 0x19, 0x22,
|
||||
0x03, 0x12, 0x02, 0x22, 0x15, 0x0E, 0x21, 0xE0, 0x10, 0xAE, 0x0E, 0x20, 0xE0, 0x10, 0xAB, 0xE1,
|
||||
0x10, 0xAE, 0xE0, 0x10, 0xB3, 0xE0, 0x10, 0xB7, 0xE0, 0x10, 0xBA, 0xE0, 0x21, 0x09, 0x11, 0xB3,
|
||||
0x21, 0x17, 0xE0, 0x10, 0xB7, 0xE0, 0x10, 0xB3, 0xE0, 0x10, 0xAE, 0xE0, 0x10, 0xAB, 0xE1, 0x10,
|
||||
0xAE, 0xE0, 0x10, 0xB3, 0x21, 0x07, 0x11, 0x22, 0x21, 0x19, 0x22, 0x05, 0x12, 0x22, 0x22, 0x15,
|
||||
0x0E, 0x30, 0xE0, 0x10, 0xB7, 0x0E, 0x20, 0xE0, 0x10, 0xBA, 0xE1, 0x10, 0xB7, 0xE0, 0x10, 0xB3,
|
||||
0xE0, 0x10, 0xAE, 0xE0, 0x10, 0xAB, 0xE0, 0x21, 0x09, 0x11, 0x59, 0x21, 0x19, 0xE0, 0x10, 0xAE,
|
||||
0xE0, 0x10, 0xB3, 0xE0, 0x10, 0xB7, 0xE0, 0x10, 0xBA, 0xE1, 0x10, 0xB7, 0xE0, 0x20, 0x09, 0x10,
|
||||
0x83, 0x20, 0x19, 0x21, 0x09, 0x11, 0xB3, 0x21, 0x19, 0x22, 0x05, 0x12, 0xB3, 0x22, 0x15, 0x0E,
|
||||
0x21, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0x87, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x7C,
|
||||
0xE0, 0x21, 0x09, 0x11, 0x22, 0x21, 0x19, 0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x87,
|
||||
0xE0, 0x10, 0x8A, 0xE1, 0x10, 0x87, 0xE0, 0x20, 0x09, 0x10, 0x59, 0x20, 0x19, 0x21, 0x09, 0x21,
|
||||
0x19, 0x22, 0x05, 0x12, 0x22, 0x22, 0x17, 0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0x5D, 0xE0,
|
||||
0x10, 0x59, 0xE0, 0x10, 0x55, 0xE0, 0x10, 0x53, 0xE0, 0x21, 0x09, 0x11, 0x59, 0x21, 0x19, 0xE0,
|
||||
0x10, 0x55, 0xE0, 0x10, 0x59, 0xE0, 0x10, 0x5D, 0xE0, 0x10, 0x5F, 0xE1, 0x10, 0x5D, 0xE0, 0x20,
|
||||
0x09, 0x10, 0x46, 0x20, 0x19, 0x21, 0x09, 0x11, 0xB3, 0x21, 0x19, 0x22, 0x07, 0x12, 0xB3, 0x22,
|
||||
0x17, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0x49, 0xE0, 0x10, 0x46, 0xE0, 0x10, 0x42, 0xE0,
|
||||
0x10, 0x40, 0xE0, 0x21, 0x09, 0x11, 0x22, 0x21, 0x19, 0xE0, 0x10, 0x42, 0xE0, 0x10, 0x46, 0xE0,
|
||||
0x10, 0x49, 0xE0, 0x10, 0x4B, 0xE1, 0x10, 0x49, 0xE0, 0x20, 0x09, 0x10, 0x59, 0x20, 0x19, 0x21,
|
||||
0x09, 0x11, 0xCC, 0x21, 0x17, 0x22, 0x07, 0x12, 0xCC, 0x22, 0x15, 0x0E, 0x30, 0xE0, 0x0E, 0x20,
|
||||
0xE2, 0x10, 0x5D, 0xE0, 0x10, 0x59, 0xE0, 0x10, 0x55, 0xE0, 0x10, 0x53, 0xE0, 0x21, 0x07, 0x11,
|
||||
0x22, 0x21, 0x19, 0xE0, 0x10, 0x55, 0xE0, 0x10, 0x59, 0xE0, 0x10, 0x5D, 0xE0, 0x10, 0x5F, 0xE1,
|
||||
0x10, 0x5D, 0xE0, 0x10, 0x59, 0x21, 0x09, 0x11, 0x59, 0x21, 0x19, 0x22, 0x05, 0x12, 0x59, 0x22,
|
||||
0x17, 0x0E, 0x21, 0xE0, 0x10, 0x55, 0x0E, 0x20, 0xE0, 0x10, 0x53, 0xE1, 0x10, 0x55, 0xE0, 0x10,
|
||||
0x59, 0xE0, 0x10, 0x5D, 0xE0, 0x10, 0x5F, 0xE0, 0x21, 0x09, 0x11, 0xCC, 0x21, 0x17, 0xE0, 0x10,
|
||||
0x5D, 0xE0, 0x10, 0x59, 0xE0, 0x10, 0x55, 0xE0, 0x10, 0x53, 0xE1, 0x10, 0x55, 0xE0, 0x20, 0x09,
|
||||
0x10, 0x83, 0x20, 0x19, 0x21, 0x07, 0x21, 0x17, 0x22, 0x07, 0x12, 0xCC, 0x22, 0x15, 0x0E, 0x28,
|
||||
0xE0, 0x0E, 0x20, 0xE2, 0x10, 0x87, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x7C, 0xE0,
|
||||
0x21, 0x07, 0x11, 0x22, 0x21, 0x19, 0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x87, 0xE0,
|
||||
0x10, 0x8A, 0xE1, 0x10, 0x87, 0xE0, 0x20, 0x09, 0x10, 0xB3, 0x20, 0x19, 0x21, 0x09, 0x11, 0x59,
|
||||
0x21, 0x19, 0x22, 0x05, 0x12, 0x59, 0x22, 0x17, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0xB7,
|
||||
0xE0, 0x10, 0xB3, 0xE0, 0x10, 0xAE, 0xE0, 0x10, 0xAB, 0xE0, 0x21, 0x09, 0x11, 0xCC, 0x21, 0x17,
|
||||
0xE0, 0x10, 0xAE, 0xE0, 0x10, 0xB3, 0xE0, 0x10, 0xB7, 0xE0, 0x10, 0xBA, 0xE1, 0x10, 0xB7, 0xE0,
|
||||
0x20, 0x09, 0x10, 0xCC, 0x20, 0x19, 0x21, 0x07, 0x11, 0x02, 0x21, 0x19, 0x22, 0x07, 0x12, 0x02,
|
||||
0x22, 0x17, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0xD1, 0xE0, 0x10, 0xCC, 0xE0, 0x10, 0xC7,
|
||||
0xE0, 0x10, 0xC4, 0xE0, 0x21, 0x09, 0x11, 0x46, 0x21, 0x19, 0xE0, 0x10, 0xC7, 0xE0, 0x10, 0xCC,
|
||||
0xE0, 0x10, 0xD1, 0xE0, 0x10, 0xD4, 0xE1, 0x10, 0xD1, 0xE0, 0x10, 0xCC, 0x21, 0x09, 0x11, 0x83,
|
||||
0x21, 0x19, 0x22, 0x07, 0x12, 0x83, 0x22, 0x17, 0x0E, 0x21, 0xE0, 0x10, 0xC7, 0x0E, 0x20, 0xE0,
|
||||
0x10, 0xC4, 0xE1, 0x10, 0xC7, 0xE0, 0x10, 0xCC, 0xE0, 0x10, 0xD1, 0xE0, 0x10, 0xD4, 0xE0, 0x21,
|
||||
0x09, 0x11, 0x02, 0x21, 0x19, 0xE0, 0x10, 0xD1, 0xE0, 0x10, 0xCC, 0xE0, 0x10, 0xC7, 0xE0, 0x10,
|
||||
0xC4, 0xE1, 0x10, 0xC7, 0xE0, 0x20, 0x09, 0x10, 0xB3, 0x20, 0x19, 0x21, 0x09, 0x21, 0x19, 0x22,
|
||||
0x07, 0x12, 0x02, 0x22, 0x17, 0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0xB7, 0xE0, 0x10, 0xB3,
|
||||
0xE0, 0x10, 0xAE, 0xE0, 0x10, 0xAB, 0xE0, 0x21, 0x09, 0x11, 0x46, 0x21, 0x19, 0xE0, 0x10, 0xAE,
|
||||
0xE0, 0x10, 0xB3, 0xE0, 0x10, 0xB7, 0xE0, 0x10, 0xBA, 0xE1, 0x10, 0xB7, 0xE0, 0x20, 0x09, 0x10,
|
||||
0x83, 0x20, 0x19, 0x21, 0x09, 0x11, 0x83, 0x21, 0x19, 0x22, 0x07, 0x12, 0x83, 0x22, 0x17, 0x0E,
|
||||
0x21, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0x87, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x7C,
|
||||
0xE0, 0x21, 0x09, 0x11, 0x02, 0x21, 0x19, 0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x87,
|
||||
0xE0, 0x10, 0x8A, 0xE1, 0x10, 0x87, 0xE0, 0x20, 0x09, 0x10, 0x59, 0x20, 0x19, 0x21, 0x09, 0x11,
|
||||
0x59, 0x21, 0x17, 0x22, 0x07, 0x12, 0x59, 0x22, 0x17, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE2, 0x10,
|
||||
0x5D, 0xE0, 0x10, 0x59, 0xE0, 0x10, 0x55, 0xE0, 0x10, 0x53, 0xE0, 0x21, 0x07, 0x11, 0xB3, 0x21,
|
||||
0x17, 0xE0, 0x10, 0x55, 0xE0, 0x10, 0x59, 0xE0, 0x10, 0x5D, 0xE0, 0x10, 0x5F, 0xE1, 0x10, 0x5D,
|
||||
0xE0, 0x10, 0x59, 0x21, 0x07, 0x11, 0x02, 0x21, 0x19, 0x22, 0x07, 0x12, 0x02, 0x22, 0x19, 0x0E,
|
||||
0x21, 0xE0, 0x10, 0x55, 0x0E, 0x20, 0xE0, 0x10, 0x53, 0xE1, 0x10, 0x55, 0xE0, 0x10, 0x59, 0xE0,
|
||||
0x10, 0x5D, 0xE0, 0x10, 0x5F, 0xE0, 0x21, 0x09, 0x11, 0xB3, 0x21, 0x17, 0xE0, 0x10, 0x5D, 0xE0,
|
||||
0x10, 0x59, 0xE0, 0x10, 0x55, 0xE0, 0x10, 0x53, 0xE1, 0x10, 0x55, 0xE0, 0x10, 0x59, 0x21, 0x07,
|
||||
0x11, 0x59, 0x21, 0x17, 0x22, 0x09, 0x12, 0x59, 0x22, 0x17, 0x0E, 0x28, 0xE0, 0x10, 0x5D, 0x0E,
|
||||
0x20, 0xE0, 0x10, 0x5F, 0xE1, 0x10, 0x5D, 0xE0, 0x10, 0x59, 0xE0, 0x10, 0x55, 0xE0, 0x10, 0x53,
|
||||
0xE0, 0x21, 0x07, 0x11, 0xB3, 0x21, 0x17, 0xE0, 0x10, 0x55, 0xE0, 0x10, 0x59, 0xE0, 0x10, 0x5D,
|
||||
0xE0, 0x10, 0x5F, 0xE1, 0x10, 0x5D, 0xE0, 0x20, 0x09, 0x10, 0x83, 0x20, 0x19, 0x21, 0x07, 0x11,
|
||||
0x02, 0x21, 0x19, 0x22, 0x07, 0x12, 0x02, 0x22, 0x19, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE2, 0x10,
|
||||
0x87, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x7C, 0xE0, 0x21, 0x09, 0x11, 0xB3, 0x21,
|
||||
0x17, 0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x87, 0xE0, 0x10, 0x8A, 0xE1, 0x10, 0x87,
|
||||
0xE0, 0xFF,
|
||||
};
|
||||
@@ -0,0 +1,184 @@
|
||||
#include "msxgl.h"
|
||||
|
||||
// lVGM music track — tips/hints screen.
|
||||
// Occupies the start of banked segment 27 (bank-2 window 0x8000-0x9FFF,
|
||||
// via SET_BANK_SEGMENT(2, 27)). MSX-Music (YM2413/OPLL), 60 Hz, looping.
|
||||
// 2792 bytes; the rest of the 8KB segment is unused padding.
|
||||
// Access: LVGM_Play((const u8*)0x8000, TRUE) with segment 27 banked in.
|
||||
const u8 g_MusHints[2792] = {
|
||||
0x6C, 0x56, 0x47, 0x4D, 0x06, 0x02, 0xF1, 0x16, 0x20, 0xFE, 0x26, 0x05, 0x17, 0x50, 0x27, 0x05,
|
||||
0x18, 0xC0, 0x28, 0x01, 0x56, 0x00, 0x0E, 0x20, 0x10, 0x83, 0x20, 0x19, 0x30, 0x71, 0x11, 0x83,
|
||||
0x21, 0x17, 0x31, 0xC6, 0x12, 0x83, 0x22, 0x13, 0x32, 0xE3, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE5,
|
||||
0x21, 0x07, 0x11, 0xCC, 0x21, 0x17, 0xE6, 0x21, 0x07, 0x11, 0x22, 0x21, 0x19, 0x22, 0x03, 0x12,
|
||||
0x22, 0x22, 0x15, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x09, 0x11, 0xCC, 0x21, 0x17, 0xE6,
|
||||
0x21, 0x07, 0x11, 0x83, 0x21, 0x17, 0x22, 0x05, 0x12, 0x83, 0x22, 0x13, 0x0E, 0x28, 0xE0, 0x0E,
|
||||
0x20, 0xE5, 0x21, 0x07, 0x11, 0xCC, 0x21, 0x17, 0xE6, 0x20, 0x09, 0x10, 0xCC, 0x20, 0x19, 0x21,
|
||||
0x07, 0x11, 0x22, 0x21, 0x19, 0x22, 0x03, 0x12, 0xB3, 0x22, 0x13, 0x0E, 0x21, 0xE0, 0x0E, 0x20,
|
||||
0xE5, 0x21, 0x09, 0x11, 0xCC, 0x21, 0x17, 0xE6, 0x20, 0x09, 0x10, 0x22, 0x20, 0x1B, 0x21, 0x07,
|
||||
0x11, 0x83, 0x21, 0x17, 0x22, 0x03, 0x12, 0x83, 0x22, 0x13, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE5,
|
||||
0x21, 0x07, 0x11, 0xCC, 0x21, 0x17, 0xE6, 0x21, 0x07, 0x11, 0x22, 0x21, 0x19, 0x22, 0x03, 0x12,
|
||||
0x22, 0x22, 0x15, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x09, 0x11, 0xCC, 0x21, 0x17, 0xE6,
|
||||
0x20, 0x0B, 0x10, 0x02, 0x20, 0x1B, 0x21, 0x07, 0x11, 0x83, 0x21, 0x17, 0x22, 0x05, 0x12, 0x83,
|
||||
0x22, 0x13, 0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x07, 0x11, 0xCC, 0x21, 0x17, 0xE6, 0x20,
|
||||
0x0B, 0x10, 0xCC, 0x20, 0x19, 0x21, 0x07, 0x11, 0x22, 0x21, 0x19, 0x22, 0x03, 0x12, 0xB3, 0x22,
|
||||
0x13, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x09, 0x11, 0xCC, 0x21, 0x17, 0xE7, 0x20, 0x09,
|
||||
0x10, 0xB3, 0x20, 0x19, 0x21, 0x07, 0x11, 0x12, 0x21, 0x19, 0x22, 0x03, 0x12, 0x12, 0x22, 0x15,
|
||||
0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x09, 0x11, 0x83, 0x21, 0x17, 0xE6, 0x21, 0x07, 0x11,
|
||||
0xCC, 0x21, 0x17, 0x22, 0x05, 0x12, 0x83, 0x22, 0x13, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE5, 0x21,
|
||||
0x07, 0x11, 0x83, 0x21, 0x17, 0xE6, 0x20, 0x09, 0x10, 0x83, 0x20, 0x19, 0x21, 0x07, 0x11, 0x12,
|
||||
0x21, 0x19, 0x22, 0x03, 0x12, 0x12, 0x22, 0x15, 0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x09,
|
||||
0x11, 0x83, 0x21, 0x17, 0xE6, 0x20, 0x09, 0x10, 0xB3, 0x20, 0x19, 0x21, 0x07, 0x11, 0xCC, 0x21,
|
||||
0x17, 0x22, 0x05, 0x12, 0x22, 0x22, 0x15, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x07, 0x11,
|
||||
0x83, 0x21, 0x17, 0xE6, 0x20, 0x09, 0x10, 0xCC, 0x20, 0x19, 0x21, 0x07, 0x11, 0x12, 0x21, 0x19,
|
||||
0x22, 0x05, 0x12, 0x12, 0x22, 0x15, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x09, 0x11, 0x83,
|
||||
0x21, 0x17, 0xE6, 0x21, 0x07, 0x11, 0xCC, 0x21, 0x17, 0x22, 0x05, 0x12, 0x83, 0x22, 0x13, 0x0E,
|
||||
0x21, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x07, 0x11, 0x83, 0x21, 0x17, 0xE6, 0x21, 0x07, 0x11, 0x12,
|
||||
0x21, 0x19, 0x22, 0x03, 0x12, 0x12, 0x22, 0x15, 0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x09,
|
||||
0x11, 0x83, 0x21, 0x17, 0xE6, 0x21, 0x07, 0x11, 0xCC, 0x21, 0x17, 0x22, 0x05, 0x12, 0x22, 0x22,
|
||||
0x15, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x07, 0x11, 0x83, 0x21, 0x17, 0xE6, 0x20, 0x09,
|
||||
0x10, 0x02, 0x20, 0x1B, 0x21, 0x07, 0x11, 0xCC, 0x21, 0x17, 0x22, 0x05, 0x12, 0xCC, 0x22, 0x13,
|
||||
0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x07, 0x11, 0x22, 0x21, 0x19, 0xE6, 0x21, 0x09, 0x11,
|
||||
0x59, 0x21, 0x19, 0x22, 0x03, 0x12, 0x59, 0x22, 0x15, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE5, 0x21,
|
||||
0x09, 0x11, 0x22, 0x21, 0x19, 0xE6, 0x21, 0x09, 0x11, 0xCC, 0x21, 0x17, 0x22, 0x05, 0x12, 0xCC,
|
||||
0x22, 0x13, 0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x07, 0x11, 0x22, 0x21, 0x19, 0xE6, 0x20,
|
||||
0x0B, 0x10, 0xCC, 0x20, 0x19, 0x21, 0x09, 0x11, 0x59, 0x21, 0x19, 0x22, 0x03, 0x12, 0x02, 0x22,
|
||||
0x15, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x09, 0x11, 0x22, 0x21, 0x19, 0xE6, 0x20, 0x09,
|
||||
0x10, 0xB3, 0x20, 0x19, 0x21, 0x09, 0x11, 0xCC, 0x21, 0x17, 0x22, 0x05, 0x12, 0xCC, 0x22, 0x13,
|
||||
0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x07, 0x11, 0x22, 0x21, 0x19, 0xE6, 0x21, 0x09, 0x11,
|
||||
0x59, 0x21, 0x19, 0x22, 0x03, 0x12, 0x59, 0x22, 0x15, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE5, 0x21,
|
||||
0x09, 0x11, 0x22, 0x21, 0x19, 0xE6, 0x20, 0x09, 0x10, 0x59, 0x20, 0x19, 0x21, 0x09, 0x11, 0xCC,
|
||||
0x21, 0x17, 0x22, 0x05, 0x12, 0xCC, 0x22, 0x13, 0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x07,
|
||||
0x11, 0x22, 0x21, 0x19, 0xE6, 0x20, 0x09, 0x10, 0x83, 0x20, 0x19, 0x21, 0x09, 0x11, 0x59, 0x21,
|
||||
0x19, 0x22, 0x03, 0x12, 0x02, 0x22, 0x15, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x09, 0x11,
|
||||
0x22, 0x21, 0x19, 0xE7, 0x20, 0x09, 0x10, 0xB3, 0x20, 0x19, 0x21, 0x09, 0x11, 0x59, 0x21, 0x17,
|
||||
0x22, 0x05, 0x12, 0x59, 0x22, 0x13, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0xB7, 0xE0, 0x10,
|
||||
0xB3, 0xE0, 0x10, 0xAE, 0xE0, 0x10, 0xAB, 0x21, 0x07, 0x11, 0xB3, 0x21, 0x17, 0xE1, 0x10, 0xAE,
|
||||
0xE0, 0x10, 0xB3, 0xE0, 0x10, 0xB7, 0xE0, 0x10, 0xBA, 0xE1, 0x10, 0xB7, 0x21, 0x07, 0x11, 0x02,
|
||||
0x21, 0x19, 0x22, 0x03, 0x12, 0x02, 0x22, 0x15, 0x0E, 0x21, 0xE0, 0x10, 0xB3, 0x0E, 0x20, 0xE0,
|
||||
0x10, 0xAE, 0xE0, 0x10, 0xAB, 0xE1, 0x10, 0xAE, 0xE0, 0x10, 0xB3, 0xE0, 0x10, 0xB7, 0x21, 0x09,
|
||||
0x11, 0xB3, 0x21, 0x17, 0xE0, 0x10, 0xBA, 0xE1, 0x10, 0xB7, 0xE0, 0x10, 0xB3, 0xE0, 0x10, 0xAE,
|
||||
0xE0, 0x10, 0xAB, 0xE0, 0x21, 0x07, 0x11, 0x59, 0x21, 0x17, 0x22, 0x05, 0x12, 0x59, 0x22, 0x13,
|
||||
0x0E, 0x28, 0xE0, 0x10, 0xAE, 0x0E, 0x20, 0xE0, 0x10, 0xB3, 0xE0, 0x10, 0xB7, 0xE0, 0x10, 0xBA,
|
||||
0xE1, 0x10, 0xB7, 0xE0, 0x10, 0xB3, 0x21, 0x07, 0x11, 0xB3, 0x21, 0x17, 0xE0, 0x10, 0xAE, 0xE0,
|
||||
0x10, 0xAB, 0xE1, 0x10, 0xAE, 0xE0, 0x10, 0xB3, 0xE0, 0x10, 0xB7, 0xE0, 0x10, 0xBA, 0x21, 0x07,
|
||||
0x11, 0x02, 0x21, 0x19, 0x22, 0x03, 0x12, 0xB3, 0x22, 0x13, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE0,
|
||||
0x10, 0xB7, 0xE0, 0x10, 0xB3, 0xE0, 0x10, 0xAE, 0xE0, 0x10, 0xAB, 0xE1, 0x10, 0xAE, 0x21, 0x09,
|
||||
0x11, 0xB3, 0x21, 0x17, 0xE0, 0x10, 0xB3, 0xE0, 0x10, 0xB7, 0xE0, 0x10, 0xBA, 0xE1, 0x10, 0xB7,
|
||||
0xE0, 0x10, 0xB3, 0xE0, 0x20, 0x09, 0x21, 0x07, 0x11, 0x59, 0x21, 0x17, 0x22, 0x03, 0x12, 0x59,
|
||||
0x22, 0x13, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x07, 0x11, 0xB3, 0x21, 0x17, 0xE6, 0x21,
|
||||
0x07, 0x11, 0x02, 0x21, 0x19, 0x22, 0x03, 0x12, 0x02, 0x22, 0x15, 0x0E, 0x21, 0xE0, 0x0E, 0x20,
|
||||
0xE5, 0x21, 0x09, 0x11, 0xB3, 0x21, 0x17, 0xE6, 0x10, 0x22, 0x20, 0x1B, 0x30, 0x42, 0x21, 0x07,
|
||||
0x11, 0x59, 0x21, 0x17, 0x22, 0x05, 0x12, 0x59, 0x22, 0x13, 0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE2,
|
||||
0x10, 0x25, 0xE0, 0x10, 0x22, 0xE0, 0x10, 0x1F, 0xE0, 0x10, 0x1D, 0x21, 0x07, 0x11, 0xB3, 0x21,
|
||||
0x17, 0xE1, 0x10, 0x1F, 0xE0, 0x10, 0x22, 0xE0, 0x10, 0x25, 0xE0, 0x10, 0x27, 0xE1, 0x10, 0x25,
|
||||
0x21, 0x07, 0x11, 0x02, 0x21, 0x19, 0x22, 0x03, 0x12, 0xB3, 0x22, 0x13, 0x0E, 0x21, 0xE0, 0x10,
|
||||
0x22, 0x0E, 0x20, 0xE0, 0x10, 0x1F, 0xE0, 0x10, 0x1D, 0xE1, 0x10, 0x1F, 0xE0, 0x10, 0x22, 0xE0,
|
||||
0x10, 0x25, 0x21, 0x09, 0x11, 0xB3, 0x21, 0x17, 0xE0, 0x10, 0x27, 0xE1, 0x10, 0x25, 0xE0, 0x10,
|
||||
0x22, 0xE0, 0x10, 0x1F, 0xE0, 0x10, 0x1D, 0xE0, 0x21, 0x07, 0x11, 0x83, 0x21, 0x17, 0x22, 0x03,
|
||||
0x12, 0x83, 0x22, 0x13, 0x0E, 0x30, 0xE0, 0x10, 0x1F, 0x0E, 0x20, 0xE0, 0x10, 0x22, 0xE0, 0x10,
|
||||
0x25, 0xE0, 0x10, 0x27, 0xE1, 0x10, 0x25, 0xE0, 0x10, 0x22, 0x21, 0x07, 0x11, 0xCC, 0x21, 0x17,
|
||||
0xE0, 0x10, 0x1F, 0xE0, 0x10, 0x1D, 0xE1, 0x10, 0x1F, 0xE0, 0x10, 0x22, 0xE0, 0x10, 0x25, 0xE0,
|
||||
0x20, 0x0B, 0x10, 0x22, 0x20, 0x1B, 0x21, 0x07, 0x11, 0x22, 0x21, 0x19, 0x22, 0x03, 0x12, 0x22,
|
||||
0x22, 0x15, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0x25, 0xE0, 0x10, 0x22, 0xE0, 0x10, 0x1F,
|
||||
0xE0, 0x10, 0x1D, 0x21, 0x09, 0x11, 0xCC, 0x21, 0x17, 0xE1, 0x10, 0x1F, 0xE0, 0x10, 0x22, 0xE0,
|
||||
0x10, 0x25, 0xE0, 0x10, 0x27, 0xE1, 0x20, 0x0B, 0x10, 0x02, 0x20, 0x1B, 0x21, 0x07, 0x11, 0x83,
|
||||
0x21, 0x17, 0x22, 0x05, 0x12, 0x83, 0x22, 0x13, 0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0x05,
|
||||
0xE0, 0x10, 0x02, 0xE0, 0x10, 0xFF, 0x20, 0x19, 0xE0, 0x10, 0xFC, 0x21, 0x07, 0x11, 0xCC, 0x21,
|
||||
0x17, 0xE1, 0x10, 0xFF, 0xE0, 0x10, 0x02, 0x20, 0x1B, 0xE0, 0x10, 0x05, 0xE0, 0x10, 0x07, 0xE1,
|
||||
0x10, 0x05, 0x21, 0x07, 0x11, 0x22, 0x21, 0x19, 0x22, 0x03, 0x12, 0xB3, 0x22, 0x13, 0x0E, 0x21,
|
||||
0xE0, 0x10, 0x02, 0x0E, 0x20, 0xE0, 0x10, 0xFF, 0x20, 0x19, 0xE0, 0x10, 0xFC, 0xE1, 0x10, 0xFF,
|
||||
0xE0, 0x10, 0x02, 0x20, 0x1B, 0xE0, 0x10, 0x05, 0x21, 0x09, 0x11, 0xCC, 0x21, 0x17, 0xE0, 0x10,
|
||||
0x07, 0xE1, 0x10, 0x05, 0xE0, 0x10, 0x02, 0xE0, 0x10, 0xFF, 0x20, 0x19, 0xE0, 0x10, 0xFC, 0xE0,
|
||||
0x20, 0x09, 0x10, 0xCC, 0x20, 0x19, 0x21, 0x07, 0x11, 0x83, 0x21, 0x17, 0x22, 0x03, 0x12, 0x83,
|
||||
0x22, 0x13, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0xD1, 0xE0, 0x10, 0xCC, 0xE0, 0x10, 0xC7,
|
||||
0xE0, 0x10, 0xC4, 0x21, 0x07, 0x11, 0xCC, 0x21, 0x17, 0xE1, 0x10, 0xC7, 0xE0, 0x10, 0xCC, 0xE0,
|
||||
0x10, 0xD1, 0xE0, 0x10, 0xD4, 0xE1, 0x20, 0x09, 0x10, 0xB3, 0x20, 0x19, 0x21, 0x07, 0x11, 0x22,
|
||||
0x21, 0x19, 0x22, 0x03, 0x12, 0x22, 0x22, 0x15, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0xB7,
|
||||
0xE0, 0x10, 0xB3, 0xE0, 0x10, 0xAE, 0xE0, 0x10, 0xAB, 0x21, 0x09, 0x11, 0xCC, 0x21, 0x17, 0xE1,
|
||||
0x10, 0xAE, 0xE0, 0x10, 0xB3, 0xE0, 0x10, 0xB7, 0xE0, 0x10, 0xBA, 0xE1, 0x20, 0x09, 0x10, 0x83,
|
||||
0x20, 0x19, 0x21, 0x07, 0x11, 0x83, 0x21, 0x17, 0x22, 0x05, 0x12, 0x83, 0x22, 0x13, 0x0E, 0x28,
|
||||
0xE0, 0x0E, 0x20, 0xE2, 0x10, 0x87, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x7C, 0x21,
|
||||
0x07, 0x11, 0xCC, 0x21, 0x17, 0xE1, 0x10, 0x7F, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x87, 0xE0, 0x10,
|
||||
0x8A, 0xE1, 0x10, 0x87, 0x21, 0x07, 0x11, 0x22, 0x21, 0x19, 0x22, 0x03, 0x12, 0xB3, 0x22, 0x13,
|
||||
0x0E, 0x21, 0xE0, 0x10, 0x83, 0x0E, 0x20, 0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x7C, 0xE1, 0x10, 0x7F,
|
||||
0xE0, 0x10, 0x83, 0xE0, 0x10, 0x87, 0x21, 0x09, 0x11, 0xCC, 0x21, 0x17, 0xE0, 0x10, 0x8A, 0xE1,
|
||||
0x10, 0x87, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x7C, 0xE1, 0x20, 0x09, 0x10, 0xCC,
|
||||
0x20, 0x19, 0x21, 0x07, 0x11, 0x12, 0x21, 0x19, 0x22, 0x03, 0x12, 0x12, 0x22, 0x15, 0x0E, 0x30,
|
||||
0xE0, 0x0E, 0x20, 0xE2, 0x10, 0xD1, 0xE0, 0x10, 0xCC, 0xE0, 0x10, 0xC7, 0xE0, 0x10, 0xC4, 0x21,
|
||||
0x09, 0x11, 0x83, 0x21, 0x17, 0xE1, 0x10, 0xC7, 0xE0, 0x10, 0xCC, 0xE0, 0x10, 0xD1, 0xE0, 0x10,
|
||||
0xD4, 0xE1, 0x20, 0x09, 0x10, 0x22, 0x20, 0x1B, 0x21, 0x07, 0x11, 0xCC, 0x21, 0x17, 0x22, 0x05,
|
||||
0x12, 0x83, 0x22, 0x13, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0x25, 0xE0, 0x10, 0x22, 0xE0,
|
||||
0x10, 0x1F, 0xE0, 0x10, 0x1D, 0x21, 0x07, 0x11, 0x83, 0x21, 0x17, 0xE1, 0x10, 0x1F, 0xE0, 0x10,
|
||||
0x22, 0xE0, 0x10, 0x25, 0xE0, 0x10, 0x27, 0xE1, 0x20, 0x0B, 0x10, 0x83, 0x20, 0x1B, 0x21, 0x07,
|
||||
0x11, 0x12, 0x21, 0x19, 0x22, 0x03, 0x12, 0x12, 0x22, 0x15, 0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE2,
|
||||
0x10, 0x87, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x7C, 0x21, 0x09, 0x11, 0x83, 0x21,
|
||||
0x17, 0xE1, 0x10, 0x7F, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x87, 0xE0, 0x10, 0x8A, 0xE1, 0x10, 0x87,
|
||||
0x21, 0x07, 0x11, 0xCC, 0x21, 0x17, 0x22, 0x05, 0x12, 0x22, 0x22, 0x15, 0x0E, 0x21, 0xE0, 0x10,
|
||||
0x83, 0x0E, 0x20, 0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x7C, 0xE1, 0x10, 0x7F, 0xE0, 0x10, 0x83, 0xE0,
|
||||
0x10, 0x87, 0x21, 0x07, 0x11, 0x83, 0x21, 0x17, 0xE0, 0x10, 0x8A, 0xE1, 0x10, 0x87, 0xE0, 0x10,
|
||||
0x83, 0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x7C, 0xE0, 0x21, 0x07, 0x11, 0x12, 0x21, 0x19, 0x22, 0x05,
|
||||
0x12, 0x12, 0x22, 0x15, 0x0E, 0x30, 0xE0, 0x10, 0x7F, 0x0E, 0x20, 0xE0, 0x10, 0x83, 0xE0, 0x10,
|
||||
0x87, 0xE0, 0x10, 0x8A, 0xE1, 0x10, 0x87, 0xE0, 0x10, 0x83, 0x21, 0x09, 0x11, 0x83, 0x21, 0x17,
|
||||
0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x7C, 0xE1, 0x10, 0x7F, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x87, 0xE0,
|
||||
0x10, 0x8A, 0x21, 0x07, 0x11, 0xCC, 0x21, 0x17, 0x22, 0x05, 0x12, 0x83, 0x22, 0x13, 0x0E, 0x21,
|
||||
0xE0, 0x0E, 0x20, 0xE0, 0x10, 0x87, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x7C, 0xE1,
|
||||
0x10, 0x7F, 0x21, 0x07, 0x11, 0x83, 0x21, 0x17, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x87, 0xE0, 0x10,
|
||||
0x8A, 0xE1, 0x10, 0x87, 0xE0, 0x10, 0x83, 0xE0, 0x20, 0x0B, 0x10, 0x22, 0x20, 0x1B, 0x21, 0x07,
|
||||
0x11, 0x12, 0x21, 0x19, 0x22, 0x03, 0x12, 0x12, 0x22, 0x15, 0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE2,
|
||||
0x10, 0x25, 0xE0, 0x10, 0x22, 0xE0, 0x10, 0x1F, 0xE0, 0x10, 0x1D, 0x21, 0x09, 0x11, 0x83, 0x21,
|
||||
0x17, 0xE1, 0x10, 0x1F, 0xE0, 0x10, 0x22, 0xE0, 0x10, 0x25, 0xE0, 0x10, 0x27, 0xE1, 0x10, 0x25,
|
||||
0x21, 0x07, 0x11, 0xCC, 0x21, 0x17, 0x22, 0x05, 0x12, 0x22, 0x22, 0x15, 0x0E, 0x21, 0xE0, 0x10,
|
||||
0x22, 0x0E, 0x20, 0xE0, 0x10, 0x1F, 0xE0, 0x10, 0x1D, 0xE1, 0x10, 0x1F, 0xE0, 0x10, 0x22, 0xE0,
|
||||
0x10, 0x25, 0x21, 0x07, 0x11, 0x83, 0x21, 0x17, 0xE0, 0x10, 0x27, 0xE1, 0x10, 0x25, 0xE0, 0x10,
|
||||
0x22, 0xE0, 0x10, 0x1F, 0xE0, 0x10, 0x1D, 0xE0, 0x21, 0x07, 0x11, 0x02, 0x21, 0x19, 0x22, 0x05,
|
||||
0x12, 0x02, 0x22, 0x15, 0x0E, 0x30, 0xE0, 0x10, 0x1F, 0x0E, 0x20, 0xE0, 0x10, 0x22, 0xE0, 0x10,
|
||||
0x25, 0xE0, 0x10, 0x27, 0xE1, 0x10, 0x25, 0xE0, 0x10, 0x22, 0x21, 0x09, 0x11, 0x22, 0x21, 0x19,
|
||||
0x0E, 0x30, 0xE0, 0x10, 0x1F, 0x0E, 0x20, 0xE0, 0x10, 0x1D, 0xE1, 0x10, 0x1F, 0xE0, 0x10, 0x22,
|
||||
0xE0, 0x10, 0x25, 0xE0, 0x20, 0x0B, 0x10, 0x02, 0x20, 0x1B, 0x21, 0x09, 0x11, 0x59, 0x21, 0x19,
|
||||
0x22, 0x05, 0x12, 0x83, 0x22, 0x15, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0x05, 0xE0, 0x10,
|
||||
0x02, 0xE0, 0x10, 0xFF, 0x20, 0x19, 0xE0, 0x10, 0xFC, 0x21, 0x09, 0x11, 0x22, 0x21, 0x19, 0xE1,
|
||||
0x10, 0xFF, 0xE0, 0x10, 0x02, 0x20, 0x1B, 0xE0, 0x10, 0x05, 0xE0, 0x10, 0x07, 0xE1, 0x20, 0x0B,
|
||||
0x10, 0xCC, 0x20, 0x19, 0x21, 0x09, 0x11, 0x02, 0x21, 0x19, 0x22, 0x05, 0x12, 0x02, 0x22, 0x15,
|
||||
0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0xD1, 0xE0, 0x10, 0xCC, 0xE0, 0x10, 0xC7, 0xE0, 0x10,
|
||||
0xC4, 0x21, 0x09, 0x11, 0x22, 0x21, 0x19, 0xE1, 0x10, 0xC7, 0xE0, 0x10, 0xCC, 0xE0, 0x10, 0xD1,
|
||||
0xE0, 0x10, 0xD4, 0xE1, 0x10, 0xD1, 0x21, 0x09, 0x11, 0x59, 0x21, 0x19, 0x22, 0x05, 0x12, 0x22,
|
||||
0x22, 0x15, 0x0E, 0x21, 0xE0, 0x10, 0xCC, 0x0E, 0x20, 0xE0, 0x10, 0xC7, 0xE0, 0x10, 0xC4, 0xE1,
|
||||
0x10, 0xC7, 0xE0, 0x10, 0xCC, 0xE0, 0x10, 0xD1, 0x21, 0x09, 0x11, 0x22, 0x21, 0x19, 0xE0, 0x10,
|
||||
0xD4, 0xE1, 0x10, 0xD1, 0xE0, 0x10, 0xCC, 0xE0, 0x10, 0xC7, 0xE0, 0x10, 0xC4, 0xE0, 0x20, 0x09,
|
||||
0x10, 0xB3, 0x20, 0x19, 0x21, 0x09, 0x11, 0x02, 0x21, 0x19, 0x22, 0x05, 0x12, 0x02, 0x22, 0x15,
|
||||
0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0xB7, 0xE0, 0x10, 0xB3, 0xE0, 0x10, 0xAE, 0xE0, 0x10,
|
||||
0xAB, 0x21, 0x09, 0x11, 0x22, 0x21, 0x19, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE0, 0x10, 0xAE, 0xE0,
|
||||
0x10, 0xB3, 0xE0, 0x10, 0xB7, 0xE0, 0x10, 0xBA, 0xE1, 0x20, 0x09, 0x10, 0x83, 0x20, 0x19, 0x21,
|
||||
0x09, 0x11, 0x59, 0x21, 0x19, 0x22, 0x05, 0x12, 0x83, 0x22, 0x15, 0x0E, 0x21, 0xE0, 0x0E, 0x20,
|
||||
0xE2, 0x10, 0x87, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x7C, 0x21, 0x09, 0x11, 0x22,
|
||||
0x21, 0x19, 0xE1, 0x10, 0x7F, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x87, 0xE0, 0x10, 0x8A, 0xE1, 0x20,
|
||||
0x09, 0x10, 0x83, 0x20, 0x19, 0x21, 0x09, 0x11, 0x02, 0x21, 0x19, 0x22, 0x05, 0x12, 0x02, 0x22,
|
||||
0x15, 0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0x87, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x7F, 0xE0,
|
||||
0x10, 0x7C, 0x21, 0x09, 0x11, 0x22, 0x21, 0x19, 0xE1, 0x10, 0x7F, 0xE0, 0x10, 0x83, 0xE0, 0x10,
|
||||
0x87, 0xE0, 0x10, 0x8A, 0xE1, 0x10, 0x87, 0x21, 0x09, 0x11, 0x59, 0x21, 0x19, 0x22, 0x05, 0x12,
|
||||
0x22, 0x22, 0x15, 0x0E, 0x21, 0xE0, 0x10, 0x83, 0x0E, 0x20, 0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x7C,
|
||||
0xE1, 0x10, 0x7F, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x87, 0x21, 0x09, 0x11, 0x22, 0x21, 0x19, 0xE0,
|
||||
0x10, 0x8A, 0xE1, 0x10, 0x87, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x7C, 0xE1, 0x10,
|
||||
0x7F, 0x21, 0x09, 0x21, 0x19, 0x22, 0x05, 0x22, 0x15, 0x0E, 0x30, 0xE0, 0x10, 0x83, 0x0E, 0x20,
|
||||
0xE0, 0x10, 0x87, 0xE0, 0x10, 0x8A, 0xE1, 0x10, 0x87, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x7F, 0x21,
|
||||
0x09, 0x11, 0x59, 0x21, 0x19, 0x0E, 0x30, 0xE0, 0x10, 0x7C, 0x0E, 0x20, 0xE1, 0x10, 0x7F, 0xE0,
|
||||
0x10, 0x83, 0xE0, 0x10, 0x87, 0xE0, 0x10, 0x8A, 0xE0, 0x21, 0x09, 0x11, 0xB3, 0x21, 0x19, 0x22,
|
||||
0x05, 0x12, 0xB3, 0x22, 0x15, 0x0E, 0x21, 0xE0, 0x10, 0x87, 0x0E, 0x20, 0xE0, 0x10, 0x83, 0xE0,
|
||||
0x10, 0x7F, 0xE0, 0x10, 0x7C, 0xE1, 0x10, 0x7F, 0xE0, 0x10, 0x83, 0x21, 0x09, 0x11, 0x59, 0x21,
|
||||
0x19, 0xE0, 0x10, 0x87, 0xE0, 0x10, 0x8A, 0xE1, 0x10, 0x87, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x7F,
|
||||
0xE0, 0x10, 0x7C, 0x21, 0x09, 0x11, 0x22, 0x21, 0x1B, 0x22, 0x05, 0x12, 0x22, 0x22, 0x15, 0x0E,
|
||||
0x28, 0xE0, 0x0E, 0x20, 0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x87, 0xE0, 0x10, 0x8A,
|
||||
0xE1, 0x10, 0x87, 0x21, 0x0B, 0x11, 0x59, 0x21, 0x1B, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x7F, 0xE0,
|
||||
0x10, 0x7C, 0xE1, 0x10, 0x7F, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x87, 0x21, 0x0B, 0x11, 0xB3, 0x21,
|
||||
0x1B, 0x22, 0x05, 0x12, 0x59, 0x22, 0x15, 0x0E, 0x21, 0xE0, 0x10, 0x8A, 0x0E, 0x20, 0xE1, 0x10,
|
||||
0x87, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x7C, 0xE0, 0x21, 0x0B, 0x11, 0x59, 0x21,
|
||||
0x1B, 0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x87, 0xE0, 0x10, 0x8A, 0xE1, 0x10, 0x87,
|
||||
0xE0, 0x10, 0x83, 0x21, 0x0B, 0x11, 0x22, 0x21, 0x1D, 0x22, 0x05, 0x12, 0x22, 0x22, 0x17, 0x0E,
|
||||
0x30, 0xE0, 0x10, 0x7F, 0x0E, 0x20, 0xE0, 0x10, 0x7C, 0xE1, 0x10, 0x7F, 0xE0, 0x10, 0x83, 0xE0,
|
||||
0x10, 0x87, 0xE0, 0x10, 0x8A, 0x21, 0x0D, 0x11, 0x59, 0x21, 0x1D, 0x0E, 0x30, 0xE0, 0x0E, 0x20,
|
||||
0xE0, 0x10, 0x87, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x7C, 0xE1, 0x10, 0x7F, 0x21,
|
||||
0x0D, 0x11, 0xB3, 0x21, 0x1D, 0x22, 0x07, 0x12, 0xB3, 0x22, 0x17, 0x0E, 0x21, 0xE0, 0x10, 0x83,
|
||||
0x0E, 0x20, 0xE0, 0x10, 0x87, 0xE0, 0x10, 0x8A, 0xE1, 0x10, 0x87, 0xE0, 0x10, 0x83, 0xE0, 0x10,
|
||||
0x7F, 0x21, 0x0D, 0x11, 0x59, 0x21, 0x1D, 0xE0, 0x10, 0x7C, 0xE1, 0x10, 0x7F, 0xE0, 0x10, 0x83,
|
||||
0xE0, 0x10, 0x87, 0xE0, 0x10, 0x8A, 0xE0, 0xFF,
|
||||
};
|
||||
@@ -0,0 +1,215 @@
|
||||
#include "msxgl.h"
|
||||
|
||||
// lVGM music track — gameplay (the maze).
|
||||
// Occupies the start of banked segment 28 (bank-2 window 0x8000-0x9FFF,
|
||||
// via SET_BANK_SEGMENT(2, 28)). MSX-Music (YM2413/OPLL), 60 Hz, looping.
|
||||
// 3290 bytes; the rest of the 8KB segment is unused padding.
|
||||
// Access: LVGM_Play((const u8*)0x8000, TRUE) with segment 28 banked in.
|
||||
const u8 g_MusMaze[3290] = {
|
||||
0x6C, 0x56, 0x47, 0x4D, 0x06, 0x02, 0xF1, 0x16, 0x20, 0xFE, 0x26, 0x05, 0x17, 0x50, 0x27, 0x05,
|
||||
0x18, 0xC0, 0x28, 0x01, 0x56, 0x00, 0x0E, 0x20, 0x10, 0x83, 0x20, 0x19, 0x30, 0x44, 0x11, 0x83,
|
||||
0x21, 0x17, 0x31, 0xC4, 0x12, 0x83, 0x22, 0x15, 0x32, 0xE4, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE5,
|
||||
0x21, 0x07, 0x11, 0xCC, 0x21, 0x17, 0xE6, 0x20, 0x09, 0x10, 0xCC, 0x20, 0x19, 0x21, 0x07, 0x11,
|
||||
0x22, 0x21, 0x19, 0x22, 0x05, 0x12, 0x22, 0x22, 0x17, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE4, 0x21,
|
||||
0x09, 0x11, 0xCC, 0x21, 0x17, 0xE6, 0x20, 0x09, 0x10, 0x22, 0x20, 0x1B, 0x21, 0x07, 0x11, 0x83,
|
||||
0x21, 0x17, 0x22, 0x07, 0x12, 0x83, 0x22, 0x15, 0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x07,
|
||||
0x11, 0xCC, 0x21, 0x17, 0xE6, 0x20, 0x0B, 0x10, 0x83, 0x20, 0x19, 0x21, 0x07, 0x11, 0x22, 0x21,
|
||||
0x19, 0x22, 0x05, 0x12, 0x22, 0x22, 0x17, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x09, 0x11,
|
||||
0xCC, 0x21, 0x17, 0xE6, 0x21, 0x07, 0x11, 0x83, 0x21, 0x17, 0x22, 0x07, 0x12, 0x83, 0x22, 0x15,
|
||||
0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE4, 0x20, 0x09, 0x21, 0x07, 0x11, 0xCC, 0x21, 0x17, 0xE6, 0x10,
|
||||
0x22, 0x20, 0x1B, 0x21, 0x07, 0x11, 0x22, 0x21, 0x19, 0x22, 0x05, 0x12, 0x22, 0x22, 0x17, 0x0E,
|
||||
0x21, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x09, 0x11, 0xCC, 0x21, 0x17, 0xE6, 0x20, 0x0B, 0x10, 0x02,
|
||||
0x20, 0x1B, 0x21, 0x07, 0x11, 0x83, 0x21, 0x17, 0x22, 0x07, 0x12, 0x83, 0x22, 0x15, 0x0E, 0x28,
|
||||
0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x07, 0x11, 0xCC, 0x21, 0x17, 0xE5, 0x20, 0x0B, 0x10, 0xCC, 0x20,
|
||||
0x19, 0x21, 0x07, 0x11, 0x22, 0x21, 0x19, 0x22, 0x05, 0x12, 0x22, 0x22, 0x17, 0x0E, 0x21, 0xE0,
|
||||
0x0E, 0x20, 0xE5, 0x21, 0x09, 0x11, 0xCC, 0x21, 0x17, 0xE6, 0x21, 0x07, 0x11, 0x83, 0x21, 0x17,
|
||||
0x22, 0x07, 0x12, 0x83, 0x22, 0x15, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x07, 0x11, 0xCC,
|
||||
0x21, 0x17, 0xE6, 0x20, 0x09, 0x21, 0x07, 0x11, 0x22, 0x21, 0x19, 0x22, 0x05, 0x12, 0x22, 0x22,
|
||||
0x17, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x09, 0x11, 0xCC, 0x21, 0x17, 0xE5, 0x10, 0xB3,
|
||||
0x20, 0x19, 0x21, 0x07, 0x11, 0x83, 0x21, 0x17, 0x22, 0x07, 0x12, 0x83, 0x22, 0x15, 0x0E, 0x28,
|
||||
0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x07, 0x11, 0xCC, 0x21, 0x17, 0xE6, 0x20, 0x09, 0x10, 0xCC, 0x20,
|
||||
0x19, 0x21, 0x07, 0x11, 0x22, 0x21, 0x19, 0x22, 0x05, 0x12, 0x22, 0x22, 0x17, 0x0E, 0x21, 0xE0,
|
||||
0x0E, 0x20, 0xE5, 0x21, 0x09, 0x11, 0xCC, 0x21, 0x17, 0xE6, 0x20, 0x09, 0x10, 0x83, 0x20, 0x19,
|
||||
0x21, 0x07, 0x11, 0x59, 0x21, 0x17, 0x22, 0x07, 0x12, 0x59, 0x22, 0x15, 0x0E, 0x30, 0xE0, 0x0E,
|
||||
0x20, 0xE4, 0x21, 0x07, 0x11, 0xB3, 0x21, 0x17, 0xE6, 0x21, 0x07, 0x11, 0x02, 0x21, 0x19, 0x22,
|
||||
0x05, 0x12, 0x02, 0x22, 0x17, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE5, 0x20, 0x09, 0x21, 0x09, 0x11,
|
||||
0xB3, 0x21, 0x17, 0xE6, 0x20, 0x19, 0x21, 0x07, 0x11, 0x59, 0x21, 0x17, 0x22, 0x07, 0x12, 0x59,
|
||||
0x22, 0x15, 0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x07, 0x11, 0xB3, 0x21, 0x17, 0xE6, 0x20,
|
||||
0x09, 0x10, 0xB3, 0x20, 0x19, 0x21, 0x07, 0x11, 0x02, 0x21, 0x19, 0x22, 0x05, 0x12, 0x02, 0x22,
|
||||
0x17, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE4, 0x21, 0x09, 0x11, 0xB3, 0x21, 0x17, 0xE6, 0x20, 0x09,
|
||||
0x10, 0xCC, 0x20, 0x19, 0x21, 0x07, 0x11, 0x59, 0x21, 0x17, 0x22, 0x07, 0x12, 0x59, 0x22, 0x15,
|
||||
0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x07, 0x11, 0xB3, 0x21, 0x17, 0xE6, 0x21, 0x07, 0x11,
|
||||
0x02, 0x21, 0x19, 0x22, 0x05, 0x12, 0x02, 0x22, 0x17, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE5, 0x21,
|
||||
0x09, 0x11, 0xB3, 0x21, 0x17, 0xE5, 0x20, 0x09, 0x21, 0x07, 0x11, 0x59, 0x21, 0x17, 0x22, 0x07,
|
||||
0x12, 0x59, 0x22, 0x15, 0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x07, 0x11, 0xB3, 0x21, 0x17,
|
||||
0xE6, 0x21, 0x07, 0x11, 0x02, 0x21, 0x19, 0x22, 0x05, 0x12, 0x02, 0x22, 0x17, 0x0E, 0x21, 0xE0,
|
||||
0x0E, 0x20, 0xE5, 0x21, 0x09, 0x11, 0xB3, 0x21, 0x17, 0xE6, 0x10, 0x59, 0x20, 0x19, 0x21, 0x07,
|
||||
0x11, 0x22, 0x21, 0x17, 0x22, 0x07, 0x12, 0x22, 0x22, 0x15, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE5,
|
||||
0x21, 0x07, 0x11, 0x59, 0x21, 0x17, 0xE5, 0x20, 0x09, 0x10, 0xB3, 0x20, 0x19, 0x21, 0x07, 0x11,
|
||||
0xB3, 0x21, 0x17, 0x22, 0x05, 0x12, 0xB3, 0x22, 0x15, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE5, 0x21,
|
||||
0x07, 0x11, 0x59, 0x21, 0x17, 0xE6, 0x20, 0x09, 0x10, 0x02, 0x20, 0x1B, 0x21, 0x07, 0x11, 0x22,
|
||||
0x21, 0x17, 0x22, 0x05, 0x12, 0x22, 0x22, 0x15, 0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x07,
|
||||
0x11, 0x59, 0x21, 0x17, 0xE6, 0x20, 0x0B, 0x10, 0x59, 0x20, 0x19, 0x21, 0x07, 0x11, 0xB3, 0x21,
|
||||
0x17, 0x22, 0x05, 0x12, 0xB3, 0x22, 0x15, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE4, 0x21, 0x07, 0x11,
|
||||
0x59, 0x21, 0x17, 0xE6, 0x21, 0x07, 0x11, 0x83, 0x21, 0x17, 0x22, 0x05, 0x12, 0x83, 0x22, 0x15,
|
||||
0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE5, 0x20, 0x09, 0x21, 0x07, 0x11, 0xCC, 0x21, 0x17, 0xE6, 0x10,
|
||||
0x02, 0x20, 0x1B, 0x21, 0x07, 0x11, 0x22, 0x21, 0x19, 0x22, 0x05, 0x12, 0x22, 0x22, 0x17, 0x0E,
|
||||
0x21, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x09, 0x11, 0xCC, 0x21, 0x17, 0xE6, 0x20, 0x0B, 0x10, 0xCC,
|
||||
0x20, 0x19, 0x21, 0x07, 0x11, 0x83, 0x21, 0x17, 0x22, 0x07, 0x12, 0x83, 0x22, 0x15, 0x0E, 0x28,
|
||||
0xE0, 0x0E, 0x20, 0xE4, 0x21, 0x07, 0x11, 0xCC, 0x21, 0x17, 0xE6, 0x20, 0x09, 0x10, 0xB3, 0x20,
|
||||
0x19, 0x21, 0x07, 0x11, 0x22, 0x21, 0x19, 0x22, 0x05, 0x12, 0x22, 0x22, 0x17, 0x0E, 0x21, 0xE0,
|
||||
0x0E, 0x20, 0xE5, 0x21, 0x09, 0x11, 0xCC, 0x21, 0x17, 0xE6, 0x21, 0x07, 0x11, 0x59, 0x21, 0x17,
|
||||
0x22, 0x07, 0x12, 0x59, 0x22, 0x15, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x07, 0x11, 0xB3,
|
||||
0x21, 0x17, 0xE5, 0x20, 0x09, 0x21, 0x07, 0x11, 0x02, 0x21, 0x19, 0x22, 0x05, 0x12, 0x02, 0x22,
|
||||
0x17, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x09, 0x11, 0xB3, 0x21, 0x17, 0xE6, 0x10, 0x83,
|
||||
0x20, 0x19, 0x21, 0x07, 0x11, 0x59, 0x21, 0x17, 0x22, 0x07, 0x12, 0x59, 0x22, 0x15, 0x0E, 0x28,
|
||||
0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x07, 0x11, 0xB3, 0x21, 0x17, 0xE6, 0x20, 0x09, 0x10, 0xB3, 0x20,
|
||||
0x19, 0x21, 0x07, 0x11, 0x02, 0x21, 0x19, 0x22, 0x05, 0x12, 0x02, 0x22, 0x17, 0x0E, 0x21, 0xE0,
|
||||
0x0E, 0x20, 0xE5, 0x21, 0x09, 0x11, 0xB3, 0x21, 0x17, 0xE5, 0x20, 0x09, 0x10, 0x59, 0x20, 0x19,
|
||||
0x21, 0x07, 0x11, 0x22, 0x21, 0x17, 0x22, 0x07, 0x12, 0x22, 0x22, 0x15, 0x0E, 0x30, 0xE0, 0x0E,
|
||||
0x20, 0xE5, 0x21, 0x07, 0x11, 0x59, 0x21, 0x17, 0xE6, 0x21, 0x07, 0x11, 0xB3, 0x21, 0x17, 0x22,
|
||||
0x05, 0x12, 0xB3, 0x22, 0x15, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE5, 0x20, 0x09, 0x21, 0x07, 0x11,
|
||||
0x59, 0x21, 0x17, 0xE6, 0x20, 0x19, 0x21, 0x07, 0x11, 0x22, 0x21, 0x17, 0x22, 0x05, 0x12, 0x22,
|
||||
0x22, 0x15, 0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE4, 0x21, 0x07, 0x11, 0x59, 0x21, 0x17, 0xE6, 0x20,
|
||||
0x09, 0x10, 0x46, 0x20, 0x19, 0x21, 0x07, 0x11, 0xB3, 0x21, 0x17, 0x22, 0x05, 0x12, 0xB3, 0x22,
|
||||
0x15, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x07, 0x11, 0x59, 0x21, 0x17, 0xE6, 0x20, 0x09,
|
||||
0x10, 0x22, 0x20, 0x19, 0x21, 0x07, 0x11, 0x83, 0x21, 0x17, 0x22, 0x05, 0x12, 0x83, 0x22, 0x15,
|
||||
0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x07, 0x11, 0xCC, 0x21, 0x17, 0xE6, 0x21, 0x07, 0x11,
|
||||
0x22, 0x21, 0x19, 0x22, 0x05, 0x12, 0x22, 0x22, 0x17, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE4, 0x21,
|
||||
0x09, 0x11, 0xCC, 0x21, 0x17, 0xE6, 0x20, 0x09, 0x21, 0x07, 0x11, 0x83, 0x21, 0x17, 0x22, 0x07,
|
||||
0x12, 0x83, 0x22, 0x15, 0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x07, 0x11, 0xCC, 0x21, 0x17,
|
||||
0xE6, 0x21, 0x07, 0x11, 0x22, 0x21, 0x19, 0x22, 0x05, 0x12, 0x22, 0x22, 0x17, 0x0E, 0x21, 0xE0,
|
||||
0x0E, 0x20, 0xE5, 0x21, 0x09, 0x11, 0xCC, 0x21, 0x17, 0xE5, 0x10, 0x83, 0x20, 0x19, 0x21, 0x07,
|
||||
0x11, 0x83, 0x21, 0x17, 0x22, 0x07, 0x12, 0x83, 0x22, 0x15, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE2,
|
||||
0x10, 0x87, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x7C, 0x21, 0x07, 0x11, 0xCC, 0x21,
|
||||
0x17, 0xE1, 0x10, 0x7F, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x87, 0xE0, 0x10, 0x8A, 0xE1, 0x10, 0x87,
|
||||
0x21, 0x07, 0x11, 0x22, 0x21, 0x19, 0x22, 0x05, 0x12, 0x22, 0x22, 0x17, 0x0E, 0x21, 0xE0, 0x10,
|
||||
0x83, 0x0E, 0x20, 0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x7C, 0xE1, 0x10, 0x7F, 0xE0, 0x10, 0x83, 0xE0,
|
||||
0x10, 0x87, 0x21, 0x09, 0x11, 0xCC, 0x21, 0x17, 0xE0, 0x10, 0x8A, 0xE1, 0x10, 0x87, 0xE0, 0x10,
|
||||
0x83, 0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x7C, 0xE0, 0x21, 0x07, 0x11, 0x83, 0x21, 0x17, 0x22, 0x07,
|
||||
0x12, 0x83, 0x22, 0x15, 0x0E, 0x28, 0xE0, 0x10, 0x7F, 0x0E, 0x20, 0xE0, 0x10, 0x83, 0xE0, 0x10,
|
||||
0x87, 0xE0, 0x10, 0x8A, 0xE1, 0x10, 0x87, 0xE0, 0x10, 0x83, 0x21, 0x07, 0x11, 0xCC, 0x21, 0x17,
|
||||
0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x7C, 0xE1, 0x10, 0x7F, 0xE0, 0x10, 0x83, 0xE0, 0x20, 0x09, 0x10,
|
||||
0xB3, 0x20, 0x19, 0x21, 0x07, 0x11, 0x22, 0x21, 0x19, 0x22, 0x05, 0x12, 0x22, 0x22, 0x17, 0x0E,
|
||||
0x21, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0xB7, 0xE0, 0x10, 0xB3, 0xE0, 0x10, 0xAE, 0xE0, 0x10, 0xAB,
|
||||
0x21, 0x09, 0x11, 0xCC, 0x21, 0x17, 0xE1, 0x10, 0xAE, 0xE0, 0x10, 0xB3, 0xE0, 0x10, 0xB7, 0xE0,
|
||||
0x10, 0xBA, 0xE1, 0x20, 0x09, 0x10, 0xCC, 0x20, 0x19, 0x21, 0x07, 0x11, 0x83, 0x21, 0x17, 0x22,
|
||||
0x07, 0x12, 0x83, 0x22, 0x15, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0xD1, 0xE0, 0x10, 0xCC,
|
||||
0xE0, 0x10, 0xC7, 0xE0, 0x10, 0xC4, 0x21, 0x07, 0x11, 0xCC, 0x21, 0x17, 0xE1, 0x10, 0xC7, 0xE0,
|
||||
0x10, 0xCC, 0xE0, 0x10, 0xD1, 0xE0, 0x10, 0xD4, 0xE1, 0x10, 0xD1, 0x21, 0x07, 0x11, 0x22, 0x21,
|
||||
0x19, 0x22, 0x05, 0x12, 0x22, 0x22, 0x17, 0x0E, 0x21, 0xE0, 0x10, 0xCC, 0x0E, 0x20, 0xE0, 0x10,
|
||||
0xC7, 0xE0, 0x10, 0xC4, 0xE1, 0x10, 0xC7, 0xE0, 0x10, 0xCC, 0x21, 0x09, 0x11, 0xCC, 0x21, 0x17,
|
||||
0xE0, 0x10, 0xD1, 0xE0, 0x10, 0xD4, 0xE1, 0x10, 0xD1, 0xE0, 0x10, 0xCC, 0xE0, 0x10, 0xC7, 0xE0,
|
||||
0x20, 0x09, 0x10, 0xB3, 0x20, 0x19, 0x21, 0x07, 0x11, 0x83, 0x21, 0x17, 0x22, 0x07, 0x12, 0x83,
|
||||
0x22, 0x15, 0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0xB7, 0xE0, 0x10, 0xB3, 0xE0, 0x10, 0xAE,
|
||||
0xE0, 0x10, 0xAB, 0x21, 0x07, 0x11, 0xCC, 0x21, 0x17, 0xE1, 0x10, 0xAE, 0xE0, 0x10, 0xB3, 0xE0,
|
||||
0x10, 0xB7, 0xE0, 0x10, 0xBA, 0xE1, 0x20, 0x09, 0x10, 0x83, 0x20, 0x19, 0x21, 0x07, 0x11, 0x22,
|
||||
0x21, 0x19, 0x22, 0x05, 0x12, 0x22, 0x22, 0x17, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0x87,
|
||||
0xE0, 0x10, 0x83, 0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x7C, 0x21, 0x09, 0x11, 0xCC, 0x21, 0x17, 0xE1,
|
||||
0x10, 0x7F, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x87, 0xE0, 0x10, 0x8A, 0xE1, 0x20, 0x09, 0x10, 0x59,
|
||||
0x20, 0x19, 0x21, 0x07, 0x11, 0x59, 0x21, 0x17, 0x22, 0x07, 0x12, 0x59, 0x22, 0x15, 0x0E, 0x30,
|
||||
0xE0, 0x0E, 0x20, 0xE2, 0x10, 0x5D, 0xE0, 0x10, 0x59, 0xE0, 0x10, 0x55, 0x21, 0x07, 0x11, 0xB3,
|
||||
0x21, 0x17, 0xE0, 0x10, 0x53, 0xE1, 0x10, 0x55, 0xE0, 0x10, 0x59, 0xE0, 0x10, 0x5D, 0xE0, 0x10,
|
||||
0x5F, 0xE0, 0x21, 0x07, 0x11, 0x02, 0x21, 0x19, 0x22, 0x05, 0x12, 0x02, 0x22, 0x17, 0x0E, 0x21,
|
||||
0xE0, 0x10, 0x5D, 0x0E, 0x20, 0xE0, 0x10, 0x59, 0xE0, 0x10, 0x55, 0xE0, 0x10, 0x53, 0xE1, 0x10,
|
||||
0x55, 0xE0, 0x10, 0x59, 0x21, 0x09, 0x11, 0xB3, 0x21, 0x17, 0xE0, 0x10, 0x5D, 0xE0, 0x10, 0x5F,
|
||||
0xE1, 0x10, 0x5D, 0xE0, 0x10, 0x59, 0xE0, 0x10, 0x55, 0xE0, 0x10, 0x53, 0x21, 0x07, 0x11, 0x59,
|
||||
0x21, 0x17, 0x22, 0x07, 0x12, 0x59, 0x22, 0x15, 0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE0, 0x10, 0x55,
|
||||
0xE0, 0x10, 0x59, 0xE0, 0x10, 0x5D, 0xE0, 0x10, 0x5F, 0xE1, 0x10, 0x5D, 0x21, 0x07, 0x11, 0xB3,
|
||||
0x21, 0x17, 0xE0, 0x10, 0x59, 0xE0, 0x10, 0x55, 0xE0, 0x10, 0x53, 0xE1, 0x10, 0x55, 0xE0, 0x20,
|
||||
0x09, 0x10, 0x83, 0x20, 0x19, 0x21, 0x07, 0x11, 0x02, 0x21, 0x19, 0x22, 0x05, 0x12, 0x02, 0x22,
|
||||
0x17, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0x87, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x7F, 0xE0,
|
||||
0x10, 0x7C, 0x21, 0x09, 0x11, 0xB3, 0x21, 0x17, 0xE1, 0x10, 0x7F, 0xE0, 0x10, 0x83, 0xE0, 0x10,
|
||||
0x87, 0xE0, 0x10, 0x8A, 0xE1, 0x20, 0x09, 0x10, 0xB3, 0x20, 0x19, 0x21, 0x07, 0x11, 0x59, 0x21,
|
||||
0x17, 0x22, 0x07, 0x12, 0x59, 0x22, 0x15, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0xB7, 0xE0,
|
||||
0x10, 0xB3, 0xE0, 0x10, 0xAE, 0xE0, 0x10, 0xAB, 0x21, 0x07, 0x11, 0xB3, 0x21, 0x17, 0xE1, 0x10,
|
||||
0xAE, 0xE0, 0x10, 0xB3, 0xE0, 0x10, 0xB7, 0xE0, 0x10, 0xBA, 0xE1, 0x10, 0xB7, 0x21, 0x07, 0x11,
|
||||
0x02, 0x21, 0x19, 0x22, 0x05, 0x12, 0x02, 0x22, 0x17, 0x0E, 0x21, 0xE0, 0x10, 0xB3, 0x0E, 0x20,
|
||||
0xE0, 0x10, 0xAE, 0xE0, 0x10, 0xAB, 0xE1, 0x10, 0xAE, 0xE0, 0x10, 0xB3, 0xE0, 0x10, 0xB7, 0x21,
|
||||
0x09, 0x11, 0xB3, 0x21, 0x17, 0xE0, 0x10, 0xBA, 0xE1, 0x10, 0xB7, 0xE0, 0x10, 0xB3, 0xE0, 0x10,
|
||||
0xAE, 0xE0, 0x20, 0x09, 0x21, 0x07, 0x11, 0x59, 0x21, 0x17, 0x22, 0x07, 0x12, 0x59, 0x22, 0x15,
|
||||
0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x07, 0x11, 0xB3, 0x21, 0x17, 0xE6, 0x10, 0xCC, 0x20,
|
||||
0x19, 0x21, 0x07, 0x11, 0x02, 0x21, 0x19, 0x22, 0x05, 0x12, 0x02, 0x22, 0x17, 0x0E, 0x21, 0xE0,
|
||||
0x0E, 0x20, 0xE2, 0x10, 0xD1, 0xE0, 0x10, 0xCC, 0xE0, 0x10, 0xC7, 0xE0, 0x10, 0xC4, 0x21, 0x09,
|
||||
0x11, 0xB3, 0x21, 0x17, 0xE1, 0x10, 0xC7, 0xE0, 0x10, 0xCC, 0xE0, 0x10, 0xD1, 0xE0, 0x10, 0xD4,
|
||||
0xE1, 0x20, 0x09, 0x10, 0x02, 0x20, 0x1B, 0x21, 0x07, 0x11, 0x83, 0x21, 0x17, 0x22, 0x07, 0x12,
|
||||
0x83, 0x22, 0x15, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0x05, 0xE0, 0x10, 0x02, 0xE0, 0x10,
|
||||
0xFF, 0x20, 0x19, 0x21, 0x07, 0x11, 0xCC, 0x21, 0x17, 0xE0, 0x10, 0xFC, 0xE1, 0x10, 0xFF, 0xE0,
|
||||
0x10, 0x02, 0x20, 0x1B, 0xE0, 0x10, 0x05, 0xE0, 0x10, 0x07, 0xE0, 0x21, 0x07, 0x11, 0x22, 0x21,
|
||||
0x19, 0x22, 0x05, 0x12, 0x22, 0x22, 0x17, 0x0E, 0x21, 0xE0, 0x10, 0x05, 0x0E, 0x20, 0xE0, 0x10,
|
||||
0x02, 0xE0, 0x10, 0xFF, 0x20, 0x19, 0xE0, 0x10, 0xFC, 0xE1, 0x10, 0xFF, 0xE0, 0x10, 0x02, 0x20,
|
||||
0x1B, 0x21, 0x09, 0x11, 0xCC, 0x21, 0x17, 0xE0, 0x10, 0x05, 0xE0, 0x10, 0x07, 0xE1, 0x10, 0x05,
|
||||
0xE0, 0x10, 0x02, 0xE0, 0x10, 0xFF, 0x20, 0x19, 0xE0, 0x10, 0xFC, 0x21, 0x07, 0x11, 0x83, 0x21,
|
||||
0x17, 0x22, 0x07, 0x12, 0x83, 0x22, 0x15, 0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE0, 0x10, 0xFF, 0xE0,
|
||||
0x10, 0x02, 0x20, 0x1B, 0xE0, 0x10, 0x05, 0xE0, 0x10, 0x07, 0xE1, 0x10, 0x05, 0x21, 0x07, 0x11,
|
||||
0xCC, 0x21, 0x17, 0xE0, 0x10, 0x02, 0xE0, 0x10, 0xFF, 0x20, 0x19, 0xE0, 0x10, 0xFC, 0xE1, 0x10,
|
||||
0xFF, 0xE0, 0x10, 0x02, 0x20, 0x1B, 0xE0, 0x20, 0x0B, 0x10, 0xCC, 0x20, 0x19, 0x21, 0x07, 0x11,
|
||||
0x22, 0x21, 0x19, 0x22, 0x05, 0x12, 0x22, 0x22, 0x17, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE2, 0x10,
|
||||
0xD1, 0xE0, 0x10, 0xCC, 0xE0, 0x10, 0xC7, 0x21, 0x09, 0x11, 0xCC, 0x21, 0x17, 0xE0, 0x10, 0xC4,
|
||||
0xE1, 0x10, 0xC7, 0xE0, 0x10, 0xCC, 0xE0, 0x10, 0xD1, 0xE0, 0x10, 0xD4, 0xE0, 0x20, 0x09, 0x10,
|
||||
0xB3, 0x20, 0x19, 0x21, 0x07, 0x11, 0x59, 0x21, 0x17, 0x22, 0x07, 0x12, 0xCC, 0x22, 0x15, 0x0E,
|
||||
0x30, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0xB7, 0xE0, 0x10, 0xB3, 0xE0, 0x10, 0xAE, 0xE0, 0x10, 0xAB,
|
||||
0x21, 0x07, 0x11, 0xB3, 0x21, 0x17, 0xE1, 0x10, 0xAE, 0xE0, 0x10, 0xB3, 0xE0, 0x10, 0xB7, 0xE0,
|
||||
0x10, 0xBA, 0xE1, 0x10, 0xB7, 0x21, 0x07, 0x11, 0x02, 0x21, 0x19, 0x22, 0x05, 0x12, 0x83, 0x22,
|
||||
0x15, 0x0E, 0x21, 0xE0, 0x10, 0xB3, 0x0E, 0x20, 0xE0, 0x10, 0xAE, 0xE0, 0x10, 0xAB, 0xE1, 0x10,
|
||||
0xAE, 0xE0, 0x10, 0xB3, 0xE0, 0x10, 0xB7, 0x21, 0x09, 0x11, 0xB3, 0x21, 0x17, 0xE0, 0x10, 0xBA,
|
||||
0xE1, 0x10, 0xB7, 0xE0, 0x10, 0xB3, 0xE0, 0x10, 0xAE, 0xE0, 0x20, 0x09, 0x10, 0x83, 0x20, 0x19,
|
||||
0x21, 0x07, 0x11, 0x59, 0x21, 0x17, 0x22, 0x05, 0x12, 0x22, 0x22, 0x17, 0x0E, 0x28, 0xE0, 0x0E,
|
||||
0x20, 0xE2, 0x10, 0x87, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x7C, 0x21, 0x07, 0x11,
|
||||
0xB3, 0x21, 0x17, 0xE1, 0x10, 0x7F, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x87, 0xE0, 0x10, 0x8A, 0xE1,
|
||||
0x20, 0x09, 0x10, 0x59, 0x20, 0x19, 0x21, 0x07, 0x11, 0x02, 0x21, 0x19, 0x22, 0x07, 0x12, 0xCC,
|
||||
0x22, 0x15, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0x5D, 0xE0, 0x10, 0x59, 0xE0, 0x10, 0x55,
|
||||
0xE0, 0x10, 0x53, 0x21, 0x09, 0x11, 0xB3, 0x21, 0x17, 0xE1, 0x10, 0x55, 0xE0, 0x10, 0x59, 0xE0,
|
||||
0x10, 0x5D, 0xE0, 0x10, 0x5F, 0xE1, 0x20, 0x09, 0x10, 0x22, 0x20, 0x19, 0x21, 0x07, 0x11, 0x22,
|
||||
0x21, 0x17, 0x22, 0x05, 0x12, 0x59, 0x22, 0x15, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0x25,
|
||||
0xE0, 0x10, 0x22, 0xE0, 0x10, 0x1F, 0xE0, 0x10, 0x1D, 0x21, 0x07, 0x11, 0x59, 0x21, 0x17, 0xE1,
|
||||
0x10, 0x1F, 0xE0, 0x10, 0x22, 0xE0, 0x10, 0x25, 0xE0, 0x10, 0x27, 0xE0, 0x21, 0x07, 0x11, 0xB3,
|
||||
0x21, 0x17, 0x22, 0x05, 0x12, 0x02, 0x22, 0x17, 0x0E, 0x21, 0xE0, 0x10, 0x25, 0x0E, 0x20, 0xE0,
|
||||
0x10, 0x22, 0xE0, 0x10, 0x1F, 0xE0, 0x10, 0x1D, 0xE1, 0x10, 0x1F, 0xE0, 0x10, 0x22, 0x21, 0x07,
|
||||
0x11, 0x59, 0x21, 0x17, 0xE0, 0x10, 0x25, 0xE0, 0x10, 0x27, 0xE1, 0x10, 0x25, 0xE0, 0x10, 0x22,
|
||||
0xE0, 0x10, 0x1F, 0xE0, 0x10, 0x1D, 0x21, 0x07, 0x11, 0x22, 0x21, 0x17, 0x22, 0x07, 0x12, 0x59,
|
||||
0x22, 0x15, 0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE0, 0x10, 0x1F, 0xE0, 0x10, 0x22, 0xE0, 0x10, 0x25,
|
||||
0xE0, 0x10, 0x27, 0xE1, 0x10, 0x25, 0x21, 0x07, 0x11, 0x59, 0x21, 0x17, 0xE0, 0x10, 0x22, 0xE0,
|
||||
0x10, 0x1F, 0xE0, 0x10, 0x1D, 0xE1, 0x10, 0x1F, 0xE0, 0x10, 0x22, 0xE0, 0x20, 0x09, 0x10, 0x59,
|
||||
0x20, 0x19, 0x21, 0x07, 0x11, 0xB3, 0x21, 0x17, 0x22, 0x05, 0x12, 0x02, 0x22, 0x17, 0x0E, 0x21,
|
||||
0xE0, 0x0E, 0x20, 0xE2, 0x10, 0x5D, 0xE0, 0x10, 0x59, 0xE0, 0x10, 0x55, 0x21, 0x07, 0x11, 0x59,
|
||||
0x21, 0x17, 0xE0, 0x10, 0x53, 0xE1, 0x10, 0x55, 0xE0, 0x10, 0x59, 0xE0, 0x10, 0x5D, 0xE0, 0x10,
|
||||
0x5F, 0xE0, 0x20, 0x09, 0x10, 0x83, 0x20, 0x19, 0x21, 0x07, 0x11, 0x22, 0x21, 0x17, 0x22, 0x07,
|
||||
0x12, 0xB3, 0x22, 0x15, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0x87, 0xE0, 0x10, 0x83, 0xE0,
|
||||
0x10, 0x7F, 0xE0, 0x10, 0x7C, 0x21, 0x07, 0x11, 0x59, 0x21, 0x17, 0xE1, 0x10, 0x7F, 0xE0, 0x10,
|
||||
0x83, 0xE0, 0x10, 0x87, 0xE0, 0x10, 0x8A, 0xE1, 0x10, 0x87, 0x21, 0x07, 0x11, 0xB3, 0x21, 0x17,
|
||||
0x22, 0x05, 0x12, 0x59, 0x22, 0x15, 0x0E, 0x21, 0xE0, 0x10, 0x83, 0x0E, 0x20, 0xE0, 0x10, 0x7F,
|
||||
0xE0, 0x10, 0x7C, 0xE1, 0x10, 0x7F, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x87, 0x21, 0x07, 0x11, 0x59,
|
||||
0x21, 0x17, 0xE0, 0x10, 0x8A, 0xE1, 0x10, 0x87, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x7F, 0xE0, 0x10,
|
||||
0x7C, 0xE0, 0x21, 0x07, 0x11, 0x22, 0x21, 0x17, 0x22, 0x05, 0x12, 0x02, 0x22, 0x17, 0x0E, 0x28,
|
||||
0xE0, 0x10, 0x7F, 0x0E, 0x20, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x87, 0xE0, 0x10, 0x8A, 0xE1, 0x10,
|
||||
0x87, 0x21, 0x07, 0x11, 0x59, 0x21, 0x17, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x7C,
|
||||
0xE1, 0x10, 0x7F, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x87, 0x21, 0x07, 0x11, 0xB3, 0x21, 0x17, 0x22,
|
||||
0x07, 0x12, 0xB3, 0x22, 0x15, 0x0E, 0x21, 0xE0, 0x10, 0x8A, 0x0E, 0x20, 0xE1, 0x10, 0x87, 0xE0,
|
||||
0x10, 0x83, 0xE0, 0x10, 0x7F, 0xE0, 0x10, 0x7C, 0xE0, 0x21, 0x07, 0x11, 0x59, 0x21, 0x17, 0xE0,
|
||||
0x10, 0x7F, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x87, 0xE0, 0x10, 0x8A, 0xE1, 0x10, 0x87, 0xE0, 0x20,
|
||||
0x09, 0x21, 0x07, 0x11, 0x83, 0x21, 0x17, 0x22, 0x05, 0x12, 0x22, 0x22, 0x15, 0x0E, 0x30, 0xE0,
|
||||
0x0E, 0x20, 0xE5, 0x21, 0x07, 0x11, 0xCC, 0x21, 0x17, 0xE5, 0x21, 0x07, 0x11, 0x22, 0x21, 0x19,
|
||||
0x22, 0x05, 0x12, 0xB3, 0x22, 0x15, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x09, 0x11, 0xCC,
|
||||
0x21, 0x17, 0xE6, 0x10, 0xCC, 0x20, 0x19, 0x30, 0x64, 0x21, 0x07, 0x11, 0x83, 0x21, 0x17, 0x22,
|
||||
0x05, 0x12, 0x22, 0x22, 0x17, 0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0xD1, 0xE0, 0x10, 0xCC,
|
||||
0xE0, 0x10, 0xC7, 0xE0, 0x10, 0xC4, 0x21, 0x07, 0x11, 0xCC, 0x21, 0x17, 0xE1, 0x10, 0xC7, 0xE0,
|
||||
0x10, 0xCC, 0xE0, 0x10, 0xD1, 0xE0, 0x10, 0xD4, 0xE1, 0x20, 0x09, 0x10, 0x22, 0x20, 0x1B, 0x21,
|
||||
0x07, 0x11, 0x22, 0x21, 0x19, 0x22, 0x07, 0x12, 0xB3, 0x22, 0x15, 0x0E, 0x21, 0xE0, 0x0E, 0x20,
|
||||
0xE2, 0x10, 0x25, 0xE0, 0x10, 0x22, 0xE0, 0x10, 0x1F, 0xE0, 0x10, 0x1D, 0x21, 0x09, 0x11, 0xCC,
|
||||
0x21, 0x17, 0xE1, 0x10, 0x1F, 0xE0, 0x10, 0x22, 0xE0, 0x10, 0x25, 0xE0, 0x10, 0x27, 0xE0, 0x20,
|
||||
0x0B, 0x10, 0x83, 0x20, 0x1B, 0x21, 0x07, 0x11, 0x83, 0x21, 0x17, 0x22, 0x05, 0x12, 0x59, 0x22,
|
||||
0x15, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0x87, 0xE0, 0x10, 0x83, 0xE0, 0x10, 0x7F, 0xE0,
|
||||
0x10, 0x7C, 0x21, 0x07, 0x11, 0xCC, 0x21, 0x17, 0xE1, 0x10, 0x7F, 0xE0, 0x10, 0x83, 0xE0, 0x10,
|
||||
0x87, 0xE0, 0x10, 0x8A, 0xE1, 0x20, 0x0B, 0x10, 0xCC, 0x20, 0x1B, 0x21, 0x07, 0x11, 0x22, 0x21,
|
||||
0x19, 0x22, 0x05, 0x12, 0x22, 0x22, 0x15, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE2, 0x10, 0xD1, 0xE0,
|
||||
0x10, 0xCC, 0xE0, 0x10, 0xC7, 0xE0, 0x10, 0xC4, 0x21, 0x09, 0x11, 0xCC, 0x21, 0x17, 0xE1, 0x10,
|
||||
0xC7, 0xE0, 0x10, 0xCC, 0xE0, 0x10, 0xD1, 0xE0, 0x10, 0xD4, 0xE1, 0x20, 0x0B, 0x10, 0xB3, 0x20,
|
||||
0x1B, 0x21, 0x07, 0x11, 0x83, 0x21, 0x17, 0x22, 0x05, 0x12, 0xB3, 0x22, 0x15, 0x0E, 0x28, 0xE0,
|
||||
0x0E, 0x20, 0xE2, 0x10, 0xB7, 0xE0, 0x10, 0xB3, 0xE0, 0x10, 0xAE, 0x21, 0x07, 0x11, 0xCC, 0x21,
|
||||
0x17, 0xE0, 0x10, 0xAB, 0xE1, 0x10, 0xAE, 0xE0, 0x10, 0xB3, 0xE0, 0x10, 0xB7, 0xE0, 0x10, 0xBA,
|
||||
0xE0, 0x21, 0x07, 0x11, 0x22, 0x21, 0x19, 0x22, 0x05, 0x12, 0x59, 0x22, 0x15, 0x0E, 0x21, 0xE0,
|
||||
0x10, 0xB7, 0x0E, 0x20, 0xE0, 0x10, 0xB3, 0xE0, 0x10, 0xAE, 0xE0, 0x10, 0xAB, 0xE1, 0x10, 0xAE,
|
||||
0xE0, 0x10, 0xB3, 0x21, 0x09, 0x11, 0xCC, 0x21, 0x17, 0xE0, 0x10, 0xB7, 0xE0, 0x10, 0xBA, 0xE1,
|
||||
0x10, 0xB7, 0xE0, 0x10, 0xB3, 0xE0, 0x10, 0xAE, 0xE0, 0xFF,
|
||||
};
|
||||
@@ -0,0 +1,132 @@
|
||||
#include "msxgl.h"
|
||||
|
||||
// lVGM music track — victory screen.
|
||||
// Occupies the start of banked segment 29 (bank-2 window 0x8000-0x9FFF,
|
||||
// via SET_BANK_SEGMENT(2, 29)). MSX-Music (YM2413/OPLL), 60 Hz, looping.
|
||||
// 1966 bytes; the rest of the 8KB segment is unused padding.
|
||||
// Access: LVGM_Play((const u8*)0x8000, TRUE) with segment 29 banked in.
|
||||
const u8 g_MusWin[1966] = {
|
||||
0x6C, 0x56, 0x47, 0x4D, 0x06, 0x02, 0xF1, 0x16, 0x20, 0xFE, 0x26, 0x05, 0x17, 0x50, 0x27, 0x05,
|
||||
0x18, 0xC0, 0x28, 0x01, 0x56, 0x00, 0x0E, 0x20, 0x10, 0x83, 0x20, 0x19, 0x30, 0x44, 0x11, 0x83,
|
||||
0x21, 0x17, 0x31, 0xC4, 0x12, 0x83, 0x22, 0x13, 0x32, 0xE4, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE5,
|
||||
0x21, 0x07, 0x11, 0xCC, 0x21, 0x17, 0xE6, 0x20, 0x09, 0x10, 0xCC, 0x20, 0x19, 0x21, 0x07, 0x11,
|
||||
0x22, 0x21, 0x19, 0x22, 0x03, 0x12, 0x22, 0x22, 0x15, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE4, 0x21,
|
||||
0x09, 0x11, 0xCC, 0x21, 0x17, 0xE6, 0x20, 0x09, 0x10, 0x22, 0x20, 0x1B, 0x21, 0x07, 0x11, 0x83,
|
||||
0x21, 0x17, 0x22, 0x05, 0x12, 0x83, 0x22, 0x13, 0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x07,
|
||||
0x11, 0xCC, 0x21, 0x17, 0xE6, 0x20, 0x0B, 0x10, 0x83, 0x20, 0x19, 0x21, 0x07, 0x11, 0x22, 0x21,
|
||||
0x19, 0x22, 0x03, 0x12, 0x22, 0x22, 0x15, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x09, 0x11,
|
||||
0xCC, 0x21, 0x17, 0xE6, 0x20, 0x09, 0x10, 0x22, 0x20, 0x1B, 0x21, 0x07, 0x11, 0x83, 0x21, 0x17,
|
||||
0x22, 0x05, 0x12, 0x83, 0x22, 0x13, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE4, 0x21, 0x07, 0x11, 0xCC,
|
||||
0x21, 0x17, 0xE6, 0x21, 0x07, 0x11, 0x22, 0x21, 0x19, 0x22, 0x03, 0x12, 0x22, 0x22, 0x15, 0x0E,
|
||||
0x21, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x09, 0x11, 0xCC, 0x21, 0x17, 0xE6, 0x21, 0x07, 0x11, 0x83,
|
||||
0x21, 0x17, 0x22, 0x05, 0x12, 0x83, 0x22, 0x13, 0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x07,
|
||||
0x11, 0xCC, 0x21, 0x17, 0xE5, 0x20, 0x0B, 0x10, 0xCC, 0x20, 0x19, 0x21, 0x07, 0x11, 0x22, 0x21,
|
||||
0x19, 0x22, 0x03, 0x12, 0x22, 0x22, 0x15, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x09, 0x11,
|
||||
0xCC, 0x21, 0x17, 0xE6, 0x20, 0x09, 0x10, 0x02, 0x20, 0x1B, 0x21, 0x07, 0x11, 0x22, 0x21, 0x19,
|
||||
0x22, 0x05, 0x22, 0x15, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x09, 0x11, 0x59, 0x21, 0x19,
|
||||
0xE6, 0x21, 0x09, 0x11, 0xB3, 0x21, 0x19, 0x22, 0x05, 0x12, 0xB3, 0x22, 0x15, 0x0E, 0x21, 0xE0,
|
||||
0x0E, 0x20, 0xE5, 0x21, 0x09, 0x11, 0x59, 0x21, 0x19, 0xE5, 0x20, 0x0B, 0x10, 0xB3, 0x20, 0x19,
|
||||
0x21, 0x09, 0x11, 0x22, 0x21, 0x1B, 0x22, 0x05, 0x12, 0x22, 0x22, 0x17, 0x0E, 0x28, 0xE0, 0x0E,
|
||||
0x20, 0xE5, 0x21, 0x0B, 0x11, 0x59, 0x21, 0x1B, 0xE6, 0x20, 0x09, 0x10, 0x83, 0x20, 0x19, 0x21,
|
||||
0x0B, 0x11, 0xB3, 0x21, 0x1B, 0x22, 0x07, 0x12, 0xB3, 0x22, 0x17, 0x0E, 0x21, 0xE0, 0x0E, 0x20,
|
||||
0xE5, 0x21, 0x0B, 0x11, 0x59, 0x21, 0x1B, 0xE6, 0x20, 0x09, 0x10, 0xCC, 0x20, 0x19, 0x21, 0x0B,
|
||||
0x11, 0x22, 0x21, 0x1D, 0x22, 0x07, 0x12, 0x22, 0x22, 0x17, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE4,
|
||||
0x21, 0x0D, 0x11, 0x59, 0x21, 0x1D, 0xE6, 0x21, 0x0D, 0x11, 0xB3, 0x21, 0x1D, 0x22, 0x07, 0x12,
|
||||
0xB3, 0x22, 0x17, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x0D, 0x11, 0x59, 0x21, 0x1D, 0xE6,
|
||||
0x21, 0x0D, 0x11, 0x22, 0x21, 0x1F, 0x22, 0x07, 0x12, 0x22, 0x22, 0x19, 0x0E, 0x28, 0xE0, 0x0E,
|
||||
0x20, 0xE5, 0x21, 0x0F, 0x11, 0x59, 0x21, 0x1F, 0xE6, 0x21, 0x0F, 0x11, 0xB3, 0x21, 0x1F, 0x22,
|
||||
0x09, 0x12, 0xB3, 0x22, 0x19, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE4, 0x21, 0x0F, 0x11, 0x59, 0x21,
|
||||
0x1F, 0xE6, 0x20, 0x09, 0x21, 0x0F, 0x11, 0x22, 0x21, 0x1F, 0x22, 0x09, 0x12, 0x83, 0x22, 0x17,
|
||||
0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x0F, 0x11, 0x59, 0x21, 0x1F, 0xE6, 0x10, 0x22, 0x20,
|
||||
0x1B, 0x21, 0x0F, 0x11, 0xB3, 0x21, 0x1F, 0x22, 0x07, 0x12, 0x22, 0x22, 0x19, 0x0E, 0x21, 0xE0,
|
||||
0x0E, 0x20, 0xE5, 0x21, 0x0F, 0x11, 0x59, 0x21, 0x1F, 0xE5, 0x20, 0x0B, 0x10, 0x59, 0x20, 0x1B,
|
||||
0x21, 0x0F, 0x11, 0xFF, 0x21, 0x1F, 0x22, 0x09, 0x12, 0x83, 0x22, 0x17, 0x0E, 0x28, 0xE0, 0x0E,
|
||||
0x20, 0xE5, 0x21, 0x0F, 0x21, 0x1F, 0xE6, 0x20, 0x0B, 0x10, 0x22, 0x20, 0x1B, 0x21, 0x0F, 0x21,
|
||||
0x1F, 0x22, 0x07, 0x12, 0x22, 0x22, 0x19, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x0F, 0x21,
|
||||
0x1F, 0xE6, 0x20, 0x0B, 0x10, 0x02, 0x20, 0x1B, 0x21, 0x0F, 0x21, 0x1F, 0x22, 0x09, 0x12, 0x83,
|
||||
0x22, 0x17, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x0F, 0x21, 0x1F, 0xE5, 0x21, 0x0F, 0x21,
|
||||
0x1F, 0x22, 0x07, 0x12, 0x22, 0x22, 0x19, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x0F, 0x21,
|
||||
0x1F, 0xE6, 0x21, 0x0F, 0x21, 0x1F, 0x22, 0x09, 0x12, 0x83, 0x22, 0x17, 0x0E, 0x28, 0xE0, 0x0E,
|
||||
0x20, 0xE5, 0x21, 0x0F, 0x21, 0x1F, 0xE6, 0x20, 0x0B, 0x10, 0xCC, 0x20, 0x19, 0x21, 0x0F, 0x21,
|
||||
0x1F, 0x22, 0x07, 0x12, 0x22, 0x22, 0x19, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE4, 0x21, 0x0F, 0x21,
|
||||
0x1F, 0xE6, 0x20, 0x09, 0x10, 0xB3, 0x20, 0x19, 0x21, 0x0F, 0x21, 0x1F, 0x22, 0x09, 0x12, 0x83,
|
||||
0x22, 0x17, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x0F, 0x21, 0x1F, 0xE6, 0x21, 0x0F, 0x21,
|
||||
0x1F, 0x22, 0x07, 0x12, 0x22, 0x22, 0x19, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x0F, 0x21,
|
||||
0x1F, 0xE6, 0x20, 0x09, 0x10, 0x83, 0x20, 0x19, 0x21, 0x0F, 0x21, 0x1F, 0x22, 0x09, 0x12, 0x83,
|
||||
0x22, 0x17, 0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE4, 0x21, 0x0F, 0x21, 0x1F, 0xE6, 0x20, 0x09, 0x10,
|
||||
0xB3, 0x20, 0x19, 0x21, 0x0F, 0x21, 0x1F, 0x22, 0x07, 0x12, 0x22, 0x22, 0x19, 0x0E, 0x21, 0xE0,
|
||||
0x0E, 0x20, 0xE5, 0x21, 0x0F, 0x21, 0x1F, 0xE6, 0x20, 0x09, 0x10, 0xCC, 0x20, 0x19, 0x21, 0x0F,
|
||||
0x21, 0x1F, 0x22, 0x09, 0x12, 0x83, 0x22, 0x17, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x0F,
|
||||
0x21, 0x1F, 0xE5, 0x21, 0x0F, 0x21, 0x1F, 0x22, 0x07, 0x12, 0x22, 0x22, 0x19, 0x0E, 0x21, 0xE0,
|
||||
0x0E, 0x20, 0xE5, 0x21, 0x0F, 0x21, 0x1F, 0xE6, 0x21, 0x0F, 0x21, 0x1F, 0x22, 0x09, 0x12, 0x83,
|
||||
0x22, 0x17, 0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x0F, 0x21, 0x1F, 0xE6, 0x21, 0x0F, 0x21,
|
||||
0x1F, 0x22, 0x07, 0x12, 0x22, 0x22, 0x19, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x0F, 0x21,
|
||||
0x1F, 0xE5, 0x20, 0x09, 0x21, 0x0F, 0x21, 0x1F, 0x22, 0x09, 0x12, 0x02, 0x22, 0x19, 0x0E, 0x30,
|
||||
0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x0F, 0x21, 0x1F, 0xE6, 0x21, 0x0F, 0x21, 0x1F, 0x22, 0x09, 0x12,
|
||||
0x83, 0x22, 0x19, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x0F, 0x21, 0x1F, 0xE6, 0x10, 0x22,
|
||||
0x20, 0x1B, 0x21, 0x0F, 0x21, 0x1F, 0x22, 0x09, 0x12, 0x02, 0x22, 0x1B, 0x0E, 0x28, 0xE0, 0x0E,
|
||||
0x20, 0xE4, 0x21, 0x0F, 0x21, 0x1F, 0xE6, 0x21, 0x0F, 0x21, 0x1F, 0x22, 0x0B, 0x12, 0x83, 0x22,
|
||||
0x1B, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x0F, 0x21, 0x1F, 0xE6, 0x21, 0x0F, 0x21, 0x1F,
|
||||
0x22, 0x0B, 0x12, 0x59, 0x22, 0x19, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x0F, 0x21, 0x1F,
|
||||
0xE6, 0x20, 0x0B, 0x20, 0x1B, 0x21, 0x0F, 0x21, 0x1F, 0x22, 0x09, 0x12, 0x02, 0x22, 0x1B, 0x0E,
|
||||
0x21, 0xE0, 0x0E, 0x20, 0xE4, 0x21, 0x0F, 0x21, 0x1F, 0xE6, 0x20, 0x0B, 0x10, 0x02, 0x20, 0x1B,
|
||||
0x21, 0x0F, 0x21, 0x1F, 0x22, 0x0B, 0x12, 0x59, 0x22, 0x19, 0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE5,
|
||||
0x21, 0x0F, 0x21, 0x1F, 0xE6, 0x20, 0x0B, 0x10, 0xCC, 0x20, 0x19, 0x21, 0x0F, 0x21, 0x1F, 0x22,
|
||||
0x09, 0x12, 0x02, 0x22, 0x1B, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x0F, 0x21, 0x1F, 0xE5,
|
||||
0x20, 0x09, 0x10, 0xB3, 0x20, 0x19, 0x21, 0x0F, 0x21, 0x1F, 0x22, 0x0B, 0x12, 0x59, 0x22, 0x19,
|
||||
0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x0F, 0x21, 0x1F, 0xE6, 0x20, 0x09, 0x10, 0x83, 0x20,
|
||||
0x19, 0x21, 0x0F, 0x21, 0x1F, 0x22, 0x09, 0x12, 0x02, 0x22, 0x1B, 0x0E, 0x21, 0xE0, 0x0E, 0x20,
|
||||
0xE5, 0x21, 0x0F, 0x21, 0x1F, 0xE6, 0x20, 0x09, 0x10, 0xB3, 0x20, 0x19, 0x21, 0x0F, 0x21, 0x1F,
|
||||
0x22, 0x0B, 0x12, 0x59, 0x22, 0x19, 0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x0F, 0x21, 0x1F,
|
||||
0xE5, 0x21, 0x0F, 0x21, 0x1F, 0x22, 0x09, 0x12, 0x02, 0x22, 0x1B, 0x0E, 0x21, 0xE0, 0x0E, 0x20,
|
||||
0xE5, 0x21, 0x0F, 0x21, 0x1F, 0xE6, 0x20, 0x09, 0x10, 0xCC, 0x20, 0x19, 0x21, 0x0F, 0x21, 0x1F,
|
||||
0x22, 0x0B, 0x12, 0x83, 0x22, 0x19, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x0F, 0x21, 0x1F,
|
||||
0xE6, 0x20, 0x09, 0x10, 0x02, 0x20, 0x1B, 0x21, 0x0F, 0x21, 0x1F, 0x22, 0x09, 0x12, 0x22, 0x22,
|
||||
0x1B, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE4, 0x21, 0x0F, 0x21, 0x1F, 0xE6, 0x21, 0x0F, 0x21, 0x1F,
|
||||
0x22, 0x0B, 0x12, 0x83, 0x22, 0x19, 0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x0F, 0x21, 0x1F,
|
||||
0xE6, 0x21, 0x0F, 0x21, 0x1F, 0x22, 0x09, 0x12, 0x22, 0x22, 0x1B, 0x0E, 0x21, 0xE0, 0x0E, 0x20,
|
||||
0xE5, 0x21, 0x0F, 0x21, 0x1F, 0xE6, 0x20, 0x0B, 0x10, 0xCC, 0x20, 0x19, 0x21, 0x0F, 0x21, 0x1F,
|
||||
0x22, 0x0B, 0x12, 0x83, 0x22, 0x19, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE4, 0x21, 0x0F, 0x21, 0x1F,
|
||||
0xE6, 0x20, 0x09, 0x10, 0xB3, 0x20, 0x19, 0x21, 0x0F, 0x21, 0x1F, 0x22, 0x09, 0x12, 0x22, 0x22,
|
||||
0x1B, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x0F, 0x21, 0x1F, 0xE6, 0x21, 0x0F, 0x21, 0x1F,
|
||||
0x22, 0x0B, 0x12, 0x83, 0x22, 0x19, 0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x0F, 0x21, 0x1F,
|
||||
0xE5, 0x20, 0x09, 0x10, 0x83, 0x20, 0x19, 0x21, 0x0F, 0x21, 0x1F, 0x22, 0x09, 0x12, 0x22, 0x22,
|
||||
0x1B, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x0F, 0x21, 0x1F, 0xE6, 0x20, 0x09, 0x10, 0x59,
|
||||
0x20, 0x19, 0x21, 0x0F, 0x21, 0x1F, 0x22, 0x0B, 0x12, 0x83, 0x22, 0x19, 0x0E, 0x30, 0xE0, 0x0E,
|
||||
0x20, 0xE5, 0x21, 0x0F, 0x21, 0x1F, 0xE6, 0x20, 0x09, 0x10, 0x83, 0x20, 0x19, 0x21, 0x0F, 0x21,
|
||||
0x1F, 0x22, 0x09, 0x12, 0x22, 0x22, 0x1B, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x0F, 0x21,
|
||||
0x1F, 0xE5, 0x21, 0x0F, 0x21, 0x1F, 0x22, 0x0B, 0x12, 0x83, 0x22, 0x19, 0x0E, 0x28, 0xE0, 0x0E,
|
||||
0x20, 0xE5, 0x21, 0x0F, 0x21, 0x1F, 0xE6, 0x21, 0x0F, 0x21, 0x1F, 0x22, 0x09, 0x12, 0x22, 0x22,
|
||||
0x1B, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x0F, 0x21, 0x1F, 0xE6, 0x21, 0x0F, 0x21, 0x1F,
|
||||
0x22, 0x0B, 0x12, 0x83, 0x22, 0x19, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE4, 0x21, 0x0F, 0x21, 0x1F,
|
||||
0xE6, 0x20, 0x09, 0x21, 0x0F, 0x21, 0x1F, 0x22, 0x09, 0x12, 0x22, 0x22, 0x1B, 0x0E, 0x21, 0xE0,
|
||||
0x0E, 0x20, 0xE5, 0x21, 0x0F, 0x21, 0x1F, 0xE6, 0x21, 0x0F, 0x21, 0x1F, 0x22, 0x0B, 0x12, 0x83,
|
||||
0x22, 0x19, 0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x0F, 0x21, 0x1F, 0xE6, 0x20, 0x19, 0x21,
|
||||
0x0F, 0x21, 0x1F, 0x22, 0x09, 0x12, 0x22, 0x22, 0x1B, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE4, 0x21,
|
||||
0x0F, 0x21, 0x1F, 0xE6, 0x20, 0x09, 0x10, 0xCC, 0x20, 0x19, 0x21, 0x0F, 0x21, 0x1F, 0x22, 0x0B,
|
||||
0x22, 0x1B, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x0F, 0x21, 0x1F, 0xE6, 0x20, 0x09, 0x10,
|
||||
0x22, 0x20, 0x1B, 0x21, 0x0F, 0x21, 0x1F, 0x22, 0x0B, 0x12, 0xB3, 0x22, 0x1B, 0x0E, 0x21, 0xE0,
|
||||
0x0E, 0x20, 0xE5, 0x21, 0x0F, 0x21, 0x1F, 0xE5, 0x20, 0x0B, 0x10, 0x59, 0x20, 0x1B, 0x21, 0x0F,
|
||||
0x21, 0x1F, 0x22, 0x0B, 0x12, 0x22, 0x22, 0x1D, 0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x0F,
|
||||
0x21, 0x1F, 0xE6, 0x20, 0x0B, 0x10, 0x83, 0x20, 0x1B, 0x21, 0x0F, 0x21, 0x1F, 0x22, 0x0D, 0x12,
|
||||
0xB3, 0x22, 0x1D, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x0F, 0x21, 0x1F, 0xE6, 0x21, 0x0F,
|
||||
0x21, 0x1F, 0x22, 0x0D, 0x12, 0x22, 0x22, 0x1D, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x0F,
|
||||
0x21, 0x1F, 0xE5, 0x21, 0x0F, 0x21, 0x1F, 0x22, 0x0D, 0x12, 0xB3, 0x22, 0x1D, 0x0E, 0x21, 0xE0,
|
||||
0x0E, 0x20, 0xE5, 0x21, 0x0F, 0x21, 0x1F, 0xE6, 0x20, 0x0B, 0x10, 0x22, 0x20, 0x1B, 0x21, 0x0F,
|
||||
0x21, 0x1F, 0x22, 0x0D, 0x12, 0x22, 0x22, 0x1F, 0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x0F,
|
||||
0x21, 0x1F, 0xE6, 0x20, 0x0B, 0x10, 0x02, 0x20, 0x1B, 0x21, 0x0F, 0x21, 0x1F, 0x22, 0x0F, 0x12,
|
||||
0xB3, 0x22, 0x1F, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE4, 0x21, 0x0F, 0x21, 0x1F, 0xE6, 0x21, 0x0F,
|
||||
0x21, 0x1F, 0x22, 0x0F, 0x12, 0x02, 0x22, 0x1F, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x0F,
|
||||
0x21, 0x1F, 0xE6, 0x20, 0x0B, 0x10, 0xCC, 0x20, 0x19, 0x21, 0x0F, 0x21, 0x1F, 0x22, 0x0F, 0x12,
|
||||
0x83, 0x22, 0x1F, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x0F, 0x21, 0x1F, 0xE6, 0x20, 0x09,
|
||||
0x10, 0xB3, 0x20, 0x19, 0x21, 0x0F, 0x21, 0x1F, 0x22, 0x0F, 0x12, 0xFF, 0x22, 0x1F, 0x0E, 0x28,
|
||||
0xE0, 0x0E, 0x20, 0xE4, 0x21, 0x0F, 0x21, 0x1F, 0xE6, 0x20, 0x09, 0x10, 0x83, 0x20, 0x19, 0x21,
|
||||
0x0F, 0x21, 0x1F, 0x22, 0x0F, 0x22, 0x1F, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x0F, 0x21,
|
||||
0x1F, 0xE6, 0x21, 0x0F, 0x21, 0x1F, 0x22, 0x0F, 0x12, 0x83, 0x22, 0x1F, 0x0E, 0x30, 0xE0, 0x0E,
|
||||
0x20, 0xE5, 0x21, 0x0F, 0x21, 0x1F, 0xE5, 0x21, 0x0F, 0x21, 0x1F, 0x22, 0x0F, 0x12, 0xFF, 0x22,
|
||||
0x1F, 0x0E, 0x21, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x0F, 0x21, 0x1F, 0xE6, 0x21, 0x0F, 0x21, 0x1F,
|
||||
0x22, 0x0F, 0x12, 0x83, 0x22, 0x1F, 0x0E, 0x28, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x0F, 0x21, 0x1F,
|
||||
0xE6, 0x20, 0x09, 0x21, 0x0F, 0x21, 0x1F, 0x22, 0x0F, 0x12, 0xFF, 0x22, 0x1F, 0x0E, 0x21, 0xE0,
|
||||
0x0E, 0x20, 0xE5, 0x21, 0x0F, 0x21, 0x1F, 0xE5, 0x21, 0x0F, 0x21, 0x1F, 0x22, 0x0F, 0x12, 0x83,
|
||||
0x22, 0x1F, 0x0E, 0x30, 0xE0, 0x0E, 0x20, 0xE5, 0x21, 0x0F, 0x21, 0x1F, 0xE6, 0xFF,
|
||||
};
|
||||
@@ -48,3 +48,26 @@
|
||||
#define INPUT_KB_UPDATE FALSE
|
||||
#define INPUT_KB_UPDATE_MIN 0
|
||||
#define INPUT_KB_UPDATE_MAX 8
|
||||
|
||||
// Music: screen tracks are lVGM (MSX-Music / YM2413 / OPLL); sound effects are
|
||||
// ayFX on the PSG, mixed over the FM music each frame. PSG is in buffered
|
||||
// (indirect) mode so ayFX writes g_PSG_Regs and PSG_Apply() flushes it once a
|
||||
// frame (the tracks carry no PSG data, so the PSG belongs entirely to the SFX).
|
||||
#define PSG_CHIP PSG_INTERNAL
|
||||
#define PSG_ACCESS PSG_INDIRECT
|
||||
#define PSG_USE_NOTES FALSE
|
||||
#define PSG_USE_EXTRA TRUE
|
||||
#define PSG_USE_RESUME FALSE
|
||||
// MSX-Music (the chip the music actually uses).
|
||||
#define MSXMUSIC_USE_RESUME FALSE
|
||||
// ayFX sound effects: use the PSG module's register buffer (no PT3 player here).
|
||||
#define AYFX_BUFFER AYFX_BUFFER_DEFAULT
|
||||
// lVGM replayer: enable only the chips these tracks target (PSG parser + MSX-Music).
|
||||
#define LVGM_USE_PSG TRUE // parser kept for clean linking; tracks carry no PSG data
|
||||
#define LVGM_USE_MSXMUSIC TRUE // MSX-Music (OPLL) — the music format used
|
||||
#define LVGM_USE_MSXAUDIO FALSE
|
||||
#define LVGM_USE_SCC FALSE
|
||||
#define LVGM_USE_SCCI FALSE
|
||||
#define LVGM_USE_PSG2 FALSE
|
||||
#define LVGM_USE_OPL4 FALSE
|
||||
#define LVGM_USE_NOTIFY FALSE
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
ProjName = "mazegame";
|
||||
ProjModules = [ ProjName ];
|
||||
LibModules = [ "system", "bios", "vdp", "input" ];
|
||||
LibModules = [ "system", "bios", "vdp", "input", "psg", "msx-music", "vgm/lvgm_player", "ayfx/ayfx_player" ];
|
||||
|
||||
Machine = "2P";
|
||||
Target = "ROM_KONAMI_SCC";
|
||||
@@ -15,4 +15,8 @@ AppSignature = true;
|
||||
AppCompany = "MZ";
|
||||
AppID = "01";
|
||||
|
||||
// The screen music is MSX-Music (YM2413/OPLL). Give openMSX the FM-PAC extension
|
||||
// so `./build.sh run` has an FM chip (real MSX2+ machines have MSX-Music built in).
|
||||
EmulMSXMusic = true;
|
||||
|
||||
Verbose = true;
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
; MSX ayFX sound-effect bank
|
||||
; sfx_bank.afb — 8 effects, 330 bytes total
|
||||
; Generated by the MSX Music Generator — https://github.com/jurjen74/msx-music-generator
|
||||
; Play on MSXgl with: ayFX_PlayBank(id, priority);
|
||||
|
||||
id name bytes frames ~time shape
|
||||
0 catpaws 26 20 0.33s noise + decay
|
||||
1 catpaws_2 26 20 0.33s noise + decay
|
||||
2 catpaws_3 26 20 0.33s noise + decay
|
||||
3 heartbeat_2 38 18 0.30s tone sweep + decay
|
||||
4 fanfare 39 27 0.45s tone + decay
|
||||
5 mapunfold 50 29 0.48s noise + decay
|
||||
6 manilaugh 70 25 0.42s tone sweep + noise + decay
|
||||
7 tadaaa_2 38 30 0.50s tone sweep + decay
|
||||
|
||||
; C names array for msxgl-example/s_mysfx.c (order matches the bank):
|
||||
const char* g_Names[] = { "catpaws", "catpaws_2", "catpaws_3", "heartbeat_2", "fanfare", "mapunfold", "manilaugh", "tadaaa_2" };
|
||||
#define SFX_COUNT 8
|
||||
|
||||
; Source descriptors (reproducible JSON, one per effect):
|
||||
[0] catpaws: {"name":"catpaws","segments":[{"frames":2,"tone":null,"toneCurve":"lin","noise":18,"noiseCurve":"lin","vol":[6,3],"volCurve":"exp"},{"frames":3,"tone":null,"toneCurve":"lin","noise":null,"noiseCurve":"lin","vol":0,"volCurve":"lin"},{"frames":2,"tone":null,"toneCurve":"lin","noise":20,"noiseCurve":"lin","vol":[5,2],"volCurve":"exp"},{"frames":3,"tone":null,"toneCurve":"lin","noise":null,"noiseCurve":"lin","vol":0,"volCurve":"lin"},{"frames":2,"tone":null,"toneCurve":"lin","noise":19,"noiseCurve":"lin","vol":[7,3],"volCurve":"exp"},{"frames":3,"tone":null,"toneCurve":"lin","noise":null,"noiseCurve":"lin","vol":0,"volCurve":"lin"},{"frames":2,"tone":null,"toneCurve":"lin","noise":21,"noiseCurve":"lin","vol":[5,1],"volCurve":"exp"},{"frames":3,"tone":null,"toneCurve":"lin","noise":null,"noiseCurve":"lin","vol":0,"volCurve":"lin"}]}
|
||||
[1] catpaws_2: {"name":"catpaws","segments":[{"frames":2,"tone":null,"toneCurve":"lin","noise":12,"noiseCurve":"lin","vol":[6,3],"volCurve":"exp"},{"frames":3,"tone":null,"toneCurve":"lin","noise":null,"noiseCurve":"lin","vol":0,"volCurve":"lin"},{"frames":2,"tone":null,"toneCurve":"lin","noise":14,"noiseCurve":"lin","vol":[5,2],"volCurve":"exp"},{"frames":3,"tone":null,"toneCurve":"lin","noise":null,"noiseCurve":"lin","vol":0,"volCurve":"lin"},{"frames":2,"tone":null,"toneCurve":"lin","noise":11,"noiseCurve":"lin","vol":[7,3],"volCurve":"exp"},{"frames":3,"tone":null,"toneCurve":"lin","noise":null,"noiseCurve":"lin","vol":0,"volCurve":"lin"},{"frames":2,"tone":null,"toneCurve":"lin","noise":13,"noiseCurve":"lin","vol":[5,1],"volCurve":"exp"},{"frames":3,"tone":null,"toneCurve":"lin","noise":null,"noiseCurve":"lin","vol":0,"volCurve":"lin"}]}
|
||||
[2] catpaws_3: {"name":"catpaws","segments":[{"frames":2,"tone":null,"toneCurve":"lin","noise":8,"noiseCurve":"lin","vol":[6,3],"volCurve":"exp"},{"frames":3,"tone":null,"toneCurve":"lin","noise":null,"noiseCurve":"lin","vol":0,"volCurve":"lin"},{"frames":2,"tone":null,"toneCurve":"lin","noise":10,"noiseCurve":"lin","vol":[5,2],"volCurve":"exp"},{"frames":3,"tone":null,"toneCurve":"lin","noise":null,"noiseCurve":"lin","vol":0,"volCurve":"lin"},{"frames":2,"tone":null,"toneCurve":"lin","noise":9,"noiseCurve":"lin","vol":[7,3],"volCurve":"exp"},{"frames":3,"tone":null,"toneCurve":"lin","noise":null,"noiseCurve":"lin","vol":0,"volCurve":"lin"},{"frames":2,"tone":null,"toneCurve":"lin","noise":11,"noiseCurve":"lin","vol":[5,1],"volCurve":"exp"},{"frames":3,"tone":null,"toneCurve":"lin","noise":null,"noiseCurve":"lin","vol":0,"volCurve":"lin"}]}
|
||||
[3] heartbeat_2: {"name":"heartbeat","segments":[{"frames":2,"tone":[80,55],"toneCurve":"exp","noise":null,"noiseCurve":"lin","vol":[13,15],"volCurve":"lin"},{"frames":3,"tone":[55,40],"toneCurve":"exp","noise":null,"noiseCurve":"lin","vol":[15,9],"volCurve":"exp"},{"frames":2,"tone":[110,75],"toneCurve":"exp","noise":null,"noiseCurve":"lin","vol":[12,14],"volCurve":"lin"},{"frames":4,"tone":[75,38],"toneCurve":"exp","noise":null,"noiseCurve":"lin","vol":[14,6],"volCurve":"exp"},{"frames":7,"tone":[38,38],"toneCurve":"lin","noise":null,"noiseCurve":"lin","vol":[6,0],"volCurve":"exp"}]}
|
||||
[4] fanfare: {"name":"fanfare","segments":[{"frames":3,"tone":523,"toneCurve":"lin","noise":null,"noiseCurve":"lin","vol":[12,14],"volCurve":"lin"},{"frames":3,"tone":659,"toneCurve":"lin","noise":null,"noiseCurve":"lin","vol":14,"volCurve":"lin"},{"frames":3,"tone":784,"toneCurve":"lin","noise":null,"noiseCurve":"lin","vol":14,"volCurve":"lin"},{"frames":2,"tone":1047,"toneCurve":"lin","noise":null,"noiseCurve":"lin","vol":15,"volCurve":"lin"},{"frames":5,"tone":1047,"toneCurve":"lin","noise":null,"noiseCurve":"lin","vol":[15,11],"volCurve":"lin"},{"frames":3,"tone":1319,"toneCurve":"lin","noise":null,"noiseCurve":"lin","vol":15,"volCurve":"lin"},{"frames":8,"tone":1319,"toneCurve":"lin","noise":null,"noiseCurve":"lin","vol":[15,0],"volCurve":"exp"}]}
|
||||
[5] mapunfold: {"name":"mapunfold","segments":[{"frames":2,"tone":null,"toneCurve":"lin","noise":3,"noiseCurve":"lin","vol":[8,11],"volCurve":"lin"},{"frames":3,"tone":null,"toneCurve":"lin","noise":[3,6],"noiseCurve":"lin","vol":[11,6],"volCurve":"lin"},{"frames":4,"tone":null,"toneCurve":"lin","noise":5,"noiseCurve":"lin","vol":[5,9],"volCurve":"lin"},{"frames":3,"tone":null,"toneCurve":"lin","noise":[4,7],"noiseCurve":"lin","vol":[9,5],"volCurve":"lin"},{"frames":5,"tone":null,"toneCurve":"lin","noise":[6,9],"noiseCurve":"lin","vol":[6,10],"volCurve":"lin"},{"frames":4,"tone":null,"toneCurve":"lin","noise":[8,12],"noiseCurve":"lin","vol":[10,4],"volCurve":"lin"},{"frames":5,"tone":null,"toneCurve":"lin","noise":[12,18],"noiseCurve":"lin","vol":[4,1],"volCurve":"lin"},{"frames":3,"tone":null,"toneCurve":"lin","noise":18,"noiseCurve":"lin","vol":[1,0],"volCurve":"lin"}]}
|
||||
[6] manilaugh: {"name":"manilaugh","segments":[{"frames":3,"tone":[280,420],"toneCurve":"exp","noise":null,"noiseCurve":"lin","vol":[10,14],"volCurve":"lin"},{"frames":2,"tone":[420,200],"toneCurve":"exp","noise":null,"noiseCurve":"lin","vol":[14,8],"volCurve":"lin"},{"frames":3,"tone":[300,460],"toneCurve":"exp","noise":null,"noiseCurve":"lin","vol":[11,15],"volCurve":"lin"},{"frames":2,"tone":[460,210],"toneCurve":"exp","noise":null,"noiseCurve":"lin","vol":[15,9],"volCurve":"lin"},{"frames":3,"tone":[320,500],"toneCurve":"exp","noise":null,"noiseCurve":"lin","vol":[12,15],"volCurve":"lin"},{"frames":2,"tone":[500,220],"toneCurve":"exp","noise":null,"noiseCurve":"lin","vol":[15,10],"volCurve":"lin"},{"frames":4,"tone":[350,600],"toneCurve":"exp","noise":null,"noiseCurve":"lin","vol":[13,15],"volCurve":"lin"},{"frames":6,"tone":[600,150],"toneCurve":"exp","noise":18,"noiseCurve":"lin","vol":[15,0],"volCurve":"exp"}]}
|
||||
[7] tadaaa_2: {"name":"tadaaa","segments":[{"frames":3,"tone":523,"toneCurve":"lin","noise":null,"noiseCurve":"lin","vol":[13,15],"volCurve":"lin"},{"frames":6,"tone":523,"toneCurve":"lin","noise":null,"noiseCurve":"lin","vol":15,"volCurve":"lin"},{"frames":2,"tone":null,"toneCurve":"lin","noise":null,"noiseCurve":"lin","vol":0,"volCurve":"lin"},{"frames":3,"tone":[523,784],"toneCurve":"exp","noise":null,"noiseCurve":"lin","vol":[13,15],"volCurve":"lin"},{"frames":10,"tone":784,"toneCurve":"lin","noise":null,"noiseCurve":"lin","vol":15,"volCurve":"lin"},{"frames":6,"tone":784,"toneCurve":"lin","noise":null,"noiseCurve":"lin","vol":[15,0],"volCurve":"exp"}]}
|
||||
@@ -0,0 +1,29 @@
|
||||
#include "msxgl.h"
|
||||
|
||||
// ayFX sound-effect bank (8 effects, PSG). Lives in fixed main ROM so the
|
||||
// H_TIMI music/SFX interrupt can read it without any bank switching.
|
||||
// ids: 0-2 catpaws (movement), 4 fanfare (finish), 5 mapunfold (M),
|
||||
// 6 manilaugh (C), 7 tadaaa (screen keypress). See sfx/sfx_bank.txt.
|
||||
const u8 g_SFXBank[330] = {
|
||||
0x08, 0x0F, 0x00, 0x27, 0x00, 0x3F, 0x00, 0x57, 0x00, 0x7B, 0x00, 0xA0, 0x00, 0xD0, 0x00, 0x14,
|
||||
0x01, 0x56, 0x12, 0x13, 0x90, 0x90, 0x90, 0x55, 0x14, 0x12, 0x90, 0x90, 0x90, 0x57, 0x13, 0x13,
|
||||
0x90, 0x90, 0x90, 0x55, 0x15, 0x11, 0x90, 0x90, 0x90, 0xD0, 0x20, 0x56, 0x0C, 0x13, 0x90, 0x90,
|
||||
0x90, 0x55, 0x0E, 0x12, 0x90, 0x90, 0x90, 0x57, 0x0B, 0x13, 0x90, 0x90, 0x90, 0x55, 0x0D, 0x11,
|
||||
0x90, 0x90, 0x90, 0xD0, 0x20, 0x56, 0x08, 0x13, 0x90, 0x90, 0x90, 0x55, 0x0A, 0x12, 0x90, 0x90,
|
||||
0x90, 0x57, 0x09, 0x13, 0x90, 0x90, 0x90, 0x55, 0x0B, 0x11, 0x90, 0x90, 0x90, 0xD0, 0x20, 0xAD,
|
||||
0x76, 0x05, 0xAF, 0xF2, 0x07, 0x8F, 0xAC, 0x51, 0x09, 0xA9, 0xED, 0x0A, 0xAC, 0xF9, 0x03, 0xAE,
|
||||
0xD3, 0x05, 0x8E, 0xAB, 0x4F, 0x07, 0xA8, 0x2B, 0x09, 0xA6, 0x80, 0x0B, 0x86, 0x85, 0x84, 0x83,
|
||||
0x82, 0x81, 0x80, 0xD0, 0x20, 0xAC, 0xD6, 0x00, 0x8D, 0x8E, 0xAE, 0xAA, 0x00, 0x8E, 0x8E, 0xAE,
|
||||
0x8F, 0x00, 0x8E, 0x8E, 0xAF, 0x6B, 0x00, 0x8F, 0x8F, 0x8E, 0x8D, 0x8C, 0x8B, 0xAF, 0x55, 0x00,
|
||||
0x8F, 0x8F, 0x8F, 0x8D, 0x8B, 0x89, 0x86, 0x84, 0x82, 0x80, 0xD0, 0x20, 0x58, 0x03, 0x1B, 0x1B,
|
||||
0x59, 0x05, 0x56, 0x06, 0x55, 0x05, 0x16, 0x18, 0x19, 0x59, 0x04, 0x57, 0x06, 0x55, 0x07, 0x56,
|
||||
0x06, 0x57, 0x07, 0x58, 0x08, 0x19, 0x5A, 0x09, 0x5A, 0x08, 0x58, 0x09, 0x56, 0x0B, 0x54, 0x0C,
|
||||
0x14, 0x53, 0x0E, 0x53, 0x0F, 0x52, 0x11, 0x51, 0x12, 0x11, 0x11, 0x10, 0xD0, 0x20, 0xAA, 0x90,
|
||||
0x01, 0xAC, 0x46, 0x01, 0xAE, 0x0A, 0x01, 0x8E, 0xA8, 0x2F, 0x02, 0xAB, 0x75, 0x01, 0xAD, 0x2D,
|
||||
0x01, 0xAF, 0xF3, 0x00, 0x8F, 0xA9, 0x15, 0x02, 0xAC, 0x5E, 0x01, 0xAE, 0x18, 0x01, 0xAF, 0xE0,
|
||||
0x00, 0x8F, 0xAA, 0xFC, 0x01, 0xAD, 0x40, 0x01, 0xAE, 0x0B, 0x01, 0xAE, 0xDF, 0x00, 0xAF, 0xBA,
|
||||
0x00, 0x4F, 0x12, 0x2C, 0xF6, 0x00, 0x29, 0x45, 0x01, 0x26, 0xAC, 0x01, 0x23, 0x35, 0x02, 0x20,
|
||||
0xEA, 0x02, 0xD0, 0x20, 0xAD, 0xD6, 0x00, 0x8E, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x90,
|
||||
0x90, 0x8D, 0xAE, 0xAF, 0x00, 0xAF, 0x8F, 0x00, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F,
|
||||
0x8F, 0x8F, 0x8F, 0x8C, 0x89, 0x86, 0x83, 0x80, 0xD0, 0x20,
|
||||
};
|
||||