From 46227e2003de28202cc4e82bca4f7f4745476c4e Mon Sep 17 00:00:00 2001 From: Alexander Kassouni Date: Sat, 5 Sep 2026 17:51:13 -0700 Subject: init --- docs/encoding.html | 136 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 docs/encoding.html (limited to 'docs/encoding.html') diff --git a/docs/encoding.html b/docs/encoding.html new file mode 100644 index 0000000..8b57261 --- /dev/null +++ b/docs/encoding.html @@ -0,0 +1,136 @@ + + + + + +2. Text → voice code — Animalese + + + + + + +

2. Text → voice code

+

A flat 256-entry table turns the game's own character encoding into a +34-value "voice code" alphabet. This is the only place text is looked at.

+ +

The game's character set

+ +

Messages are stored one byte per character in a custom encoding +(include/m_font.h). It is ASCII-compatible over exactly three ranges — +0-9 at 48–57, A-Z at 65–90, a-z at 97–122 — and +diverges everywhere else. Notable non-ASCII placements:

+ + + + + + + + + + + +
CodeCharacterNote
0–31uppercase accented Latin, ¡ ¿ Ç Ð Ñ ß Þwhere ASCII control codes would be
43♥where ASCII has +
47♪where ASCII has /
59droplet symbolwhere ASCII has ;
92annoyed symbolwhere ASCII has \
127CHAR_CONTROL_CODEescape byte; a control code follows
128CHAR_MESSAGE_TAGescape byte
210, 211short space, wide spacelayout-only spaces
+ +

The voice table

+ +

mMsg_sound_voice_get(code) (src/game/m_msg_sound.c_inc:1) is a +256-byte lookup with two hard-coded exceptions:

+ +
if (code == CHAR_CONTROL_CODE || code == CHAR_MESSAGE_TAG)
+    return -1;                      // no sound, and no state change
+return voice_array[code];
+ +

Those are the only two entries in the array holding 0xFF, so +0xFF is never actually returned from this function — it arrives at +Na_VoiceSe only as a padding value for the unused b/c +slots.

+ +

Voice code space

+ + + + + + + + + + + + + +
Voice codeMeaning
0x53–0x5Cdigits 0–9
0x5D–0x76letters a–z
0x80♪ — plays the speaker's melody, bypasses everything
0x81space
0x82? — raises pitch
0x83! — raises volume
0x84newline (injected, never in the table)
0x85mute — the catch-all for punctuation and symbols
0x86click — plays NA_SE_BEBE
0xFFempty slot in a window
+ +

The split at 0x77 matters: Sou_BoinShiinCheck and several rules in +Na_VoiceSe test > 0x77 to mean "this is punctuation, not a letter".

+ +

Case and accent folding

+ +

Upper and lower case map to the same code, and every accented Latin letter folds onto +its base letter. Some of the folds are worth knowing about:

+ + + + + + + + + + + + + + + +
Character(s)Folds to
À Á Â Ã Å à á â ã ä å, ª (feminine ordinal)a
ß (eszett)b — a glyph-shape fold, not a phonetic one
Ç çc
Ð ðd
È É Ê Ë è é ê ëe
Ì Í Î Ï ì í î ïi
Ñ ñn
Ò Ó Ô Õ Ö ò ó ô õ ö, º (masculine ordinal)o
Þ þ (thorn)p
Ù Ú Û Ü ù ú û üu
Ý ý ÿy
Œ œmute — the only accented Latin pair that is not folded
+ +

Everything else

+ + + +

Two wrappers

+ +

mMsg_sound_voice_get2

+ +
if (code == CHAR_NEW_LINE) return 0x84;
+return mMsg_sound_voice_get(code);
+ +

Newline has no entry in the table; the wrapper injects 0x84. This is the +function the scheduler actually calls, so 0x84 reaches the engine while the +raw table never produces it. m_msg_sound.c_inc:44

+ +

mMsg_sound_voice_get_for_editor

+ +
sound = mMsg_sound_voice_get(code);
+switch (sound) {
+    case 0x80: case 0x82: case 0x83: case 0x85: return 0x86;
+    default: return sound;
+}
+ +

In the text editor, ♪, ?, ! and every mute character all become +the click. See the editor path. +m_msg_sound.c_inc:26

+ +
+Only these 34 values leave the text layer. Word boundaries, capitalisation, +sentence structure and the actual letters beyond a-z0-9 are all gone by +the time audio sees anything. Whatever "understanding of English" the animalese has, +it lives entirely in the digraph table on the next page. +
+ +
+ ← 1. Gating + 3. Windowing & timing → +
+ + + -- cgit v1.3.1