# Kellogg's Tony and Friends — Remake-Projekt, Analyse-Notizen

## Ziel
Plattformunabhängiges Remake (Python) von "Kellogg's Tony and Friends" (DOS, 1994),
lauffähig auf x64 ohne DOS/QEMU. Ursprung: Spiel crasht in unserer FreeDOS-VM
(RTM.EXE-Engine vs. QEMU-VGA-Emulation, siehe Projekt "Classic Games" für den
Debug-Marathon dazu) — daher der Wunsch für ein eigenes Remake.

## Quelldateien (aus VM-Disk `dos_shareware` extrahiert, liegen in `raw/`)
- `RTM.EXE` — die eigentliche Spiel-Engine (Runtime), DOS-EXE (MZ-Header), 108 KB.
- `START.EXE` / `SETUP.EXE` — Launcher/Konfigurationsprogramme.
- `KELLOGG.INI` — Soundkarten-Konfig (IRQ/DMA), irrelevant fürs Remake.
- `PCKELL.DAT` — 2,69 MB, **unkomprimiert**. Beginnt mit einer monoton
  steigenden 16-Bit-LE-Offset-Tabelle (vermutlich Sprite-/Block-Offsets in
  die anhängenden Rohdaten). Enthält laut `SRB.LST` 32 "SRB"-Blöcke
  (vermutlich "Sprite Resource Block"). Tabellenstruktur noch nicht final
  verstanden — steigt über mehr Einträge als die reinen 32 Top-Level-Files,
  also vermutlich verschachtelt (pro Sprite/Frame-Offsets innerhalb jedes
  SRB-Blocks). TODO: Tabellenende finden und pro-SRB-Grenzen bestimmen.
- `PCKELL.SET` — **ist tatsächlich eine ZIP-Datei** (Signatur `PK\x03\x04`)!
  Enthält 3 Einträge:
  - `APPEND.LST` (Methode 6 "Imploded", 1945 Bytes entpackt) — Manifest mit
    178 Dateinamen für die in `PCKELL.PRE` zusammengefügten Assets.
  - `SRB.LST` (Methode 1 "Shrink", 314 Bytes entpackt) — Manifest mit den
    32 Dateinamen, die zu `PCKELL.DAT` gehören (1:1 gleiche Basisnamen wie
    ein Teil der BOB-Einträge in APPEND.LST, z.B. `TONY.SRB` ↔ `TONY.BOB`).
  - `PCKELL.PRE` (Methode 6 "Imploded", 2.328.934 Bytes entpackt) — die
    eigentliche Asset-Sammlung, konkateniert nach der Reihenfolge in
    `APPEND.LST`.

  **WICHTIG — Kompressions-Falle:** ZIP-Methode 6 "Imploding" ist NICHT
  dasselbe wie das "DCL Implode/Explode"-Format aus PKWAREs Data
  Compression Library (dafür gibt's `blast.c` in zlib/contrib — hab ich
  zuerst versucht, schlägt fehl mit "distance too far back", weil es ein
  anderer Algorithmus ist trotz gleichem Namen). Debian/Ubuntus
  `unzip` (Info-ZIP, kompiliert MIT Explode+Unshrink-Support) entpackt
  beide Methoden aber klaglos — auf `aria-wohnung` funktioniert
  `unzip PCKELL.SET` direkt. Das Alpine-`unzip` im Brain-Container
  (aria-proxy) kann das NICHT (kein Implode-Support einkompiliert).

## Datei-Typen in APPEND.LST (178 Einträge total)
| Ext  | Anzahl | Vermutung |
|------|--------|-----------|
| PCC  | 77     | "Compiled Picture" — vermutlich RLE/Palette-komprimiertes Vollbild (Titelscreens, Menüs, Hintergründe) |
| BOB  | 32     | "Blob" — Sprite-Grafik-Daten (Spielfiguren, Objekte), 1:1 mit den 32 SRB-Einträgen |
| MAP  | 22     | Level-/Karten-Daten |
| ARE  | 22     | "Area" — vermutlich Level-Metadaten/Kollisionszonen, im Paar mit MAP (22=22) |
| ICO  | 19     | Icons (z.B. für Menüs/HUD) |
| SAM  | 3      | Sound-Samples |
| TFX  | 3      | vermutlich Musik/Sound-Effekt-Format |

## Nächste Schritte (in dieser Reihenfolge sinnvoll)
1. **PCKELL.PRE aufteilen**: Die 178 Dateien sind laut APPEND.LST hintereinander
   konkateniert — es fehlt noch die Größentabelle pro Datei (vermutlich am
   Anfang von PCKELL.PRE selbst, ähnlich der Offset-Tabelle in PCKELL.DAT,
   oder implizit aus dem Dateiformat jedes Typs ableitbar). Header von
   PCKELL.PRE selbst noch nicht angeschaut.
2. **Ein PCC-Bild reverse-engineeren** — vermutlich klassisches Palette+RLE,
   das dürfte am leichtesten zu knacken sein (PCC ähnelt oft PCX-Varianten).
3. **BOB/SRB-Sprite-Format verstehen** — Kollisions-Header aus PCKELL.DAT
   (die Offset-Tabelle) mit den 32 SRB-Namen abgleichen.
4. **RTM.EXE nicht disassemblieren müssen** — Ziel ist ein sauberes
   Python-Reimplement der Spiellogik (Physik/Level/Gegner aus MAP/ARE lesen),
   nicht 1:1-Code-Nachbau der DOS-Engine.

## Aufbewahrungsort
Alle Rohdaten + Manifeste liegen unter `raw/` in diesem Projektordner
(`/shared/projects/kellogg_s_remake/raw/`). `raw/extracted/` enthält den
fehlgeschlagenen blast.c-Versuch (kann weg). Entpackte Dateien
(`APPEND.LST`, `SRB.LST`, `PCKELL.PRE` — alle bereits entpackt, nicht mehr
komprimiert) liegen direkt in `raw/`.

## DOSBox-Testumgebung (2026-07-22) — Original läuft jetzt!

**DOSBox 0.74-3 ist auf `aria-wohnung` installiert** (apt). Zweck: das
Original-Spiel als visuelle/funktionale Referenz neben dem Reverse-Engineering
laufen lassen, ohne die kaputte QEMU-VGA-Emulation aus dem "Classic Games"-Crash.

### Fehlende Dateien nachgeliefert
`raw/` hatte urspr. nur `RTM.EXE` + `PCKELL.*` — **`START.EXE`, `SETUP.EXE`,
`KELLOGG.INI`, `HDPMI16.EXE` (DPMI-Host) und `DPMI16BI.OVL`** fehlten (waren
nie aus der `dos_shareware`-VM-Disk kopiert worden, nur RTM+PCKELL). Auch ein
`READ.ME` (Original-Textdatei mit Installations-/Troubleshooting-Hinweisen)
lag dort. Alle liegen jetzt in `raw/` (Quelle: `dos_shareware`-Diskimage auf
`aria-wohnung`, Pfad `GAMES/KELLOGG/` — per `qemu-nbd --read-only` gemountet,
VM dafür kurz gestoppt, danach sauber wieder disconnected. **Die VM
`dos_shareware` ist seitdem gestoppt** — bei Bedarf über's Cockpit-Panel oder
`aria-vm boot dos_shareware` wieder hochfahren).

**RTM.EXE ist die eigentliche Engine**, aber sie verweigert den Direktstart
("This loader is invoked and required by Borland tools") — man MUSS über
`START.EXE` gehen, das dann RTM.EXE korrekt aufruft.

### Der Show-Stopper: IRQ-Konflikt (aus dem Original-READ.ME!)
Mit den Original-`KELLOGG.INI`-Werten (`Adr=544 DMA=1 IRQ=7`, Soundblaster)
hängt sich das Spiel nach dem 2. Studio-Logo (Factor 5) in einer Endlosschleife
auf — kompletter schwarzer Screen, DOSBox-Prozess lebt aber (kein Crash,
Freeze). Das READ.ME beschreibt dieses EXAKTE Symptom ("Bild bleibt schwarz")
und empfiehlt IRQ 5 statt 7. Fix:
- `raw/KELLOGG.INI`: `IRQ=5` (statt 7)
- `dosbox.conf` `[sblaster]`-Sektion MUSS matchen: `irq=5` (sonst redet DOSBox's
  emulierte SB16 am falschen IRQ vorbei und das Spiel hängt trotzdem)

Mit diesem Fix läuft das Spiel sauber durch: Rauser-Advertainment-Logo →
Factor-5-Logo → Kellogg's-Logo → "Tony & Friends in Kellogg's Land"-Titelbild
→ Weltkarte (Berge/Wald/Schloss mit Drache, alle Charaktere sichtbar:
Tiger/Tony, Toucan, Frosch, Affe/Coco, Bär). Screenshots liegen unter
`/shared/uploads/aria_kellogg_*.png`.

### Funktionierende dosbox.conf
```
[sdl]
fullscreen=false
output=surface

[sblaster]
sbtype=sb16
sbbase=220
irq=5
dma=1
hdma=5

[autoexec]
mount c <pfad-zu-raw>
c:
START.EXE
```

### Screenshot-Workflow (headless, ohne echten Desktop)
`aria-wohnung` hat keinen laufenden X-Server. Screenshots via
`xvfb-run -s '-screen 0 1024x768x24' dosbox ...` + `import -window root`
(ImageMagick) im selben xvfb-run-Prozess. Tasteneingaben simulierbar mit
`xdotool key <taste>` (kein `--window`-Targeting nötig, funktioniert auch
ohne Fenstermanager in Xvfb). Audio läuft im ALSA-nosound-Modus (keine echte
Soundkarte im Container/VM) — DOSBox emuliert die SB16 trotzdem korrekt genug
fürs IRQ-Timing, es kommt nur kein tatsächlicher Ton raus.

### Steuerung (aus READ.ME, für spätere Gameplay-Tests)
Pfeil links/rechts = laufen, Leertaste/Pfeil-hoch = springen, Pfeil-runter =
ducken, ALT = Sonderfunktion/Tür öffnen, P = Pause, ESC = zurück zur Karte
(ohne Leben zu verlieren).

## PCKELL.PRE Container-Format (2026-07-22) — Kernstruktur geknackt

Ziel: die 178 in `APPEND.LST` gelisteten Dateien (32 BOB, 77 PCC, 22 MAP,
22 ARE, 19 ICO, 3 SAM, 3 TFX) sauber aus `PCKELL.PRE` (2.328.934 Bytes,
bereits ZIP-entpackt) raustrennen. Tools liegen in `tools/split_pre.py`
(aktuellster Stand, laeuft auf `aria-wohnung` mit `python3`, braucht
`raw/PCKELL.PRE` + `raw/APPEND.LST` + `raw/SRB.LST`).

### Zwei Header-Varianten je nach Dateityp

**`.BOB`-Eintraege (32x, Sprite-Rohdaten):** kein Tag-Slot, Header direkt
lueckenlos hintereinander:
```
[4-Byte-LE-Laenge][NUL-terminierter Original-DOS-Pfad
  "H:\WIWA\ENGINE\GAMEDATA\<NAME>.BOB"][<Laenge> Bytes Rohdaten]
```
Danach folgt variables Zero-Padding (~219-226 Byte beobachtet) bis zum
naechsten Header. **Vollstaendig validiert: alle 32 BOB-Eintraege exakt
gefunden, 0 Namens-Mismatches gegen APPEND.LST.** Robusteste Methode zum
Finden: direkte Byte-Suche nach `H:\WIWA\ENGINE\GAMEDATA\<erwarteter Name>`
im File (nicht raten, den vollen erwarteten Namen pro Eintrag einzeln
suchen — das ist wasserdicht).

**Alle anderen Typen (PCC/MAP/ARE/ICO/SAM/TFX, 146x):** kein eingebetteter
Pfad, dafuer ein **256-Byte-Tag-Slot** VOR dem eigentlichen Header:
```
[Tag-Slot, exakt 256 Byte lang:
   1-Byte-Namenslaenge + Dateiname (z.B. 0x0B "CHOCOS7.PCC")
   + Rest mit Speicher-Muell des Kompilier-Tools aufgefuellt]
[bei Tag-Slot-Start + 256: 4-Byte-LE-Laenge][<Laenge> Bytes Rohdaten]
```
Bestaetigt an mehreren Stellen (ANTS.PCC, CHOCOS7.PCC, und der
"Master"-Tag "A.SRB" ganz am Dateianfang vor A.BOB). **Wichtige Falle:**
beim Uebergang von der letzten `.BOB`- zur ersten `.PCC`-Datei (DOORS.BOB
-> ANTS.PCC) ueberlappt der Tag-Slot von ANTS.PCC um ~34 Byte in das, was
man anhand der BOB-Laengenangabe als "Ende von DOORS.BOB" berechnen wuerde.
Grund noch nicht restlos geklaert (vermutlich rundet der Original-Compiler
beim Sektionswechsel BOB->PCC anders). Workaround im Skript: Tag-Suche
zuerst vorwaerts ab erwarteter Position, bei Fehlschlag Fallback mit
300 Byte Sicherheitsabstand rueckwaerts.

**Kuriosum:** Der Tag fuer `.BOB`-Eintraege (nur beim allerersten,
"A.SRB" vor A.BOB) nennt nicht den eigenen Namen, sondern den
`.SRB`-Begleitnamen aus `SRB.LST` (1:1 gleiche Reihenfolge wie die
BOB-Liste in APPEND.LST). Passt zur bekannten SRB<->BOB-Kopplung
(Kollisions-Metadaten in PCKELL.DAT <-> Sprite-Pixeldaten in PCKELL.PRE).

### PCC-Bildformat (erste Erkenntnisse, noch nicht fertig decodiert)
Nutzdaten beginnen mit einem PCX-aehnlichen 16-Byte-Header:
```
Byte 0:    0x0A  (Manufacturer-Marker, wie ZSoft PCX)
Byte 1:    0x05  (Version)
Byte 2:    0x01  (Encoding = RLE)
Byte 3:    0x08  (Bits pro Pixel = 8, also 256 Farben)
Byte 4-11: bisher immer 0 gesehen (Xmin/Ymin/Reserved?)
Byte 12-13: Breite (LE16), z.B. 0x0140 = 320
Byte 14-15: Hoehe (LE16), z.B. 0x00C8 = 200
Byte 16+:  vermutlich RLE-komprimierte Pixel-Indexdaten (klassisches
           PCX-RLE: Byte mit oberen 2 Bits gesetzt (0xC0-0xFF) = Lauflaenge
           (Byte&0x3F), gefolgt vom Wert-Byte; sonst literaler Pixel)
```
Farbpalette (256x3 Byte RGB) wahrscheinlich NICHT pro Datei (dafuer waeren
die kleinen Dateien wie ANTS.PCC mit nur 900 Byte total zu klein) — vermutlich
eine globale Palette, die noch gefunden werden muss (Kandidat: irgendwo in
RTM.EXE oder als eigene Ressource). TODO fuer naechste Session.

### PCKELL.PRE Splitter — GELOEST (2026-07-22, ~02:15 Ortszeit)
Der vermeintliche "14%-Drift-Bug" war GAR KEIN Bug im Tag-Matching. Diagnose
(`tools/diag_split.py`, inzwischen geloescht, siehe Git-History falls noetig)
zeigte: jeder der 178 Tags aus `APPEND.LST` wird exakt EINDEUTIG gefunden
(genau 1 Kandidat, Gap durchgehend 0, ausser dem bekannten BOB->PCC-
Uebergang mit -34 Byte). Der Splitter war also die ganze Zeit korrekt —
er endete nur zu frueh, weil **`APPEND.LST` gar nicht alle Eintraege in
`PCKELL.PRE` auflistet.**

Direkt im Anschluss an den letzten `APPEND.LST`-Eintrag (`TITEL2.SAM`,
endet bei `0x1e9aac`) folgen, im EXAKT GLEICHEN Tag-Slot-Format, noch
**3 weitere, nicht gelistete Eintraege**:
```
DPMI16BI.OVL  65312 Byte
RTM.EXE      108686 Byte
START.EXE    148480 Byte
```
Der letzte davon (`START.EXE`) endet bei `0x238966` — **exakt** die
Dateigroesse von `PCKELL.PRE`. Damit ist das Container-Format zu 100%
verifiziert, kein einziges Byte bleibt unerklaert. Macht inhaltlich auch
Sinn: `PCKELL.PRE` ist offenbar ein self-contained Redistributable-Paket,
das die komplette DOS-Extender-Runtime (DPMI-Server + Runtime-EXE +
Launcher) gleich mitbuendelt — nicht nur Spiel-Assets.

**Extra-Validierung:** die 3 extrahierten System-Dateien sind
byte-identisch (`cmp`) zu den Einzeldateien, die schon lose in `raw/`
liegen (aus der `dos_shareware`-VM kopiert) — zweite unabhaengige
Bestaetigung, dass die Extraktion korrekt ist.

**`tools/split_pre.py` (finale v7) extrahiert jetzt alle 181 Dateien
fehlerfrei nach `extracted_pre/`:**
```
32 BOB, 77 PCC, 22 MAP, 22 ARE, 19 ICO, 3 SAM, 3 TFX, 1 OVL, 2 EXE
```
Alte Splitter-Zwischenversionen (v1-v6, Diagnose-Scripts) sind auf
`aria-wohnung` (`/home/aria/kellogg_remake/tools/`) aufgeraeumt — nur
noch `split_pre.py` (v7, final) liegt dort, identisch zur Kopie hier im
Projekt unter `tools/split_pre.py`. `extracted_pre/` (2,6 MB, 181 Dateien)
liegt jetzt auch hier im Projekt, nicht nur auf `aria-wohnung`.

### PCC-Header — ergaenzender Fund
Bei `MENU.PCC` sind Byte 4-11 NICHT alle Null (anders als bei `ANTS.PCC`
vermutet) — sie enthalten `Xmax`/`Ymax` (0x013f=319, 0x00c7=199), passend
zum klassischen PCX-Header-Layout `Xmin(2) Ymin(2) Xmax(2) Ymax(2)` bei
Offset 4. Fuer ein 320x200-Bild ab (0,0) macht Xmax=319/Ymax=199 Sinn.
Bei `ANTS.PCC` (kleines 900-Byte-Sprite-Preview-Bild) stehen dort
durchgehend Nullen — vermutlich weil die Original-Autoren dieses Feld
bei kleineren generierten Bildern nicht befuellt haben. Fuer den
PCC-Decoder erstmal ignorierbar, Breite/Hoehe kommt zuverlaessig aus
Offset 12-15.

### Naechste Schritte (Prioritaet) — ALT, siehe unten "PCC-Format GELOEST" fuer aktuellen Stand
~~1. Ein PCC-Bild vollstaendig decodieren~~ ERLEDIGT (siehe unten).
2. BOB/SRB-Sprite-Format verstehen (PCKELL.DAT-Offset-Tabelle mit den
   32 SRB-Namen abgleichen, dann Frame-Struktur pro Sprite ableiten).
3. MAP/ARE-Levelformat reversen (kleinste Dateien zuerst, z.B. ein
   simples frühes Level, z.B. `W1L0.MAP`/`W1L0.ARE`).
4. Erst danach: Python-Projektstruktur aufsetzen (pygame), Asset-Loader
   fuer BOB/PCC/MAP schreiben, Kernschleife (Physik/Kollision) gegen
   DOSBox-Referenzverhalten abgleichen.

## PCC-Bildformat — VOLLSTAENDIG GELOEST (2026-07-22, ~02:20 Ortszeit)

**Format zu 100% verstanden und visuell verifiziert.** PCC = klassisches
PCX v5, 256-Farben, mit **eingebetteter Palette PRO DATEI** (kein globales
Palette-Rätsel, wie in der vorherigen Notiz befürchtet):

```
Byte 0-15:  PCX-Header (Manufacturer=0x0A, Version=5, Encoding=1/RLE,
            BPP=8, Xmin/Ymin/Xmax/Ymax bei Offset 4-11,
            Width(LE16)/Height(LE16) bei Offset 12-15 — Width/Height sind
            DIREKTE Pixelmaße, nicht Xmax-Xmin+1, auch wenn beides meist
            gleich rauskommt bei 320x200-Vollbildern)
Byte 16 .. (len-769): SCANLINE-weise RLE-komprimierte Pixel-Indexdaten.
            RLE-Tupel: Byte mit oberen 2 Bits gesetzt (0xC0-0xFF) =
            Lauflaenge (Byte&0x3F), gefolgt von 1 Wert-Byte. Sonst
            literaler Pixel. WICHTIG: pro Scanline wird bis exakt
            `width` Pixel dekodiert, ueberschuessige Pixel eines Runs
            am Zeilenende werden verworfen (klassisches PCX-Verhalten,
            NICHT als ein durchgehender Bytestrom decodieren — das
            fuehrt zu Off-by-Overshoot-Fehlern und Fehlausrichtung
            gegenueber der eingebetteten Palette am Dateiende).
Letzte 769 Byte: `0x0C`-Marker + 768 Byte (256 x RGB) Palette — die
            klassische PCX-v5-256-Farben-Erweiterung. JEDE PCC-Datei
            traegt ihre EIGENE Palette mit sich (keine globale Palette
            aus RTM.EXE noetig, wie in der vorigen Session vermutet).
```

**Decoder fertig:** `tools/pcc_to_png.py` (auf `aria-wohnung` unter
`/home/aria/kellogg_remake/tools/pcc_to_png.py`, identische Kopie hier
im Projekt unter `tools/pcc_to_png.py`). Aufruf:
`python3 tools/pcc_to_png.py extracted_pre/<NAME>.PCC out.png`
(braucht ImageMagick `convert` auf dem Zielsystem — ist auf `aria-wohnung`
vorhanden).

**Visuelle Verifikation — 100% korrekt:**
- `KARTE.PCC` → exakte Weltkarte (Berge/Schloss/Drache, Tony/Tiger,
  Coco/Affe, Frosch, Fluss, Bäume) — Pixel-für-Pixel wiedererkennbar
  gegen den DOSBox-Screenshot `aria_kellogg_worldmap.png` von vorher.
- `KELLOGGS.PCC` → glasklares "Kellogg's präsentiert"-Logo mit
  korrektem geschwungenem Markenschriftzug, scharfe Kanten, kein
  Rauschen/Fehler in der Dekodierung.
- `MENU.PCC` → sauberer Menü-Rahmen (blauer Hintergrund, rot-goldene
  Box) — vermutlich Passwort-/Level-Auswahl-UI.
Alle Test-PNGs liegen unter `/shared/uploads/aria_pcc_*.png` zur
Ansicht, dauerhafte Kopien aller **77 von 77 PCC-Dateien fehlerfrei
batch-decodiert** liegen unter `png_out/` in diesem Projektordner
(416 KB total, 77 Dateien — vollstaendige Validierung, kein einziger
Absturz oder Format-Ausreisser).

Einzige kleine Restfrage (kein Blocker): bei manchen Dateien bleiben
1-30 Byte am Ende des Pixel-Datenblocks vor der Palette ungenutzt
(vermutlich Padding/Rundung des Original-Encoders) — beeinflusst das
Bildergebnis nicht sichtbar, wird ignoriert.

## BOB-Sprite-Format — erste Erkenntnisse (2026-07-22, ~02:30 Ortszeit, IN ARBEIT)

**Kein PCX-Verwandter.** BOB-Dateien starten NICHT mit `0x0A`-Manufacturer-
Byte, kein erkennbarer Klartext-Header wie bei PCC. Vermutlich beginnt die
(vermutlich RLE-komprimierte) Pixel-Nutzdaten direkt ab Byte 0.

**Wichtiger Fund:** Die 32 BOB-Namen sind NICHT alle "richtige" Objektnamen
— 14 davon sind Einzelbuchstaben (`A.BOB` .. `O.BOB`, ohne `M`) plus
`BLUME.BOB`/`WOLKE.BOB` (Blume/Wolke, Deko-Objekte), dann die Marken-Packs
(`VITAMIN`/`COCOPOPS`/`SMACKIES`/`FROSTIES`/`LOOPS`), dann Charaktere
(`TONY`/`SMACKS`/`TOUCAN`/`COCO`), dann Level-Objekte (`PLATFW1`=Plattform,
`KEYS`, `GAMEBAR`=HUD-Leiste, `KROKO`/`BOSSNAKE`/`DRAGON`=Gegner, `DOORS`).
Die Buchstaben-Sprites (A-O) sind vermutlich Sammel-Buchstaben-Items
(Bonus-Mechanik: Buchstaben im Level einsammeln) — passend zur Groessen-
Gruppierung (viele davon fast gleich gross: B/E/N/O=1295 Byte, D/H/I=4406,
J/K=2332 — deutet auf fixe Sprite-Dimensionen pro Buchstaben-"Familie",
vermutlich Schriftart-aehnliche Boxen).

**Byte-Identitaet als Format-Hinweis:** `FROSTIES.BOB`, `COCOPOPS.BOB`,
`SMACKIES.BOB` (alle 3323 Byte gross) haben BYTE-FUER-BYTE identische
ersten 16 Byte (`16 b4 2c 76 82 b4 3a 9f 06 88 82 cf 16 e8 03 2d`) und
divergieren erst ab ca. Offset 0x20. `LOOPS.BOB` (ebenfalls 3323 Byte)
zeigt eine um 4 Byte verschobene, aber erkennbar verwandte Bytefolge.
**Interpretation:** das ist vermutlich KEIN Klartext-Header, sondern
bereits RLE-komprimierte Pixeldaten — die vier Sprites sind alle
"Cerealien-Packung"-Objekte mit identischer Kastenform/Silhouette
(gleiche Pixel-Auesserform => gleiche RLE-Runs am Anfang), die sich nur
im aufgedruckten Marken-Logo unterscheiden (Divergenz kommt spaeter).
Das wuerde erklaeren warum 4 komplett verschiedene Marken exakt gleich
grosse Dateien mit ident. Praefix erzeugen: gleiche Box-Geometrie,
gleiches Kompressionsschema, nur Content-Unterschied in der Bildmitte.

**Hypothese fuer naechste Session:** BOB = aehnliches RLE-Schema wie PCC
(Byte mit oberen 2 Bits gesetzt = Lauflaenge+Wert), aber OHNE PCX-Header
und OHNE eingebettete Palette — Breite/Hoehe muessen aus `PCKELL.DAT`
kommen (die SRB-Offset-Tabelle, noch nicht durchdrungen) oder aus einer
festen Tabelle in `RTM.EXE`. Naechste konkrete Schritte:
1. `PCKELL.DAT` Offset-Tabelle vs. `SRB.LST`-Namen abgleichen (32 Eintraege,
   1:1 mit den 32 BOB-Dateien) — dort vermutlich Breite/Hoehe/Frame-Anzahl
   pro Sprite zu finden.
2. Testweise RLE-Decode von `A.BOB` (kleinstes/einfachstes Beispiel aus der
   Buchstaben-Gruppe) mit angenommener kleiner Breite/Hoehe (z.B. 20x20 bis
   40x40 fuer ein UI-Buchstaben-Icon) durchprobieren, gegen erwartete
   Pixelzahl abgleichen (aehnlich wie beim PCC-Ansatz, der am Ende
   erfolgreich war: Header-Annahmen iterativ gegen Dateigroesse pruefen).
3. Falls das nicht schnell konvergiert: `TONY.BOB` (Hauptfigur, 47726 Byte,
   groesste Datei nach COCO) ist wahrscheinlich der wichtigste Fund fuer
   den Port und rechtfertigt tiefere Analyse zuerst.

## Naechste Schritte (Prioritaet, aktueller Stand)
1. **BOB/SRB-Sprite-Format weiter reversen** — siehe Hypothesen direkt
   oben. Naechster Schritt: `PCKELL.DAT`-Offset-Tabelle mit `SRB.LST`
   abgleichen, danach `A.BOB`-Testdecoding.
2. MAP/ARE-Levelformat reversen (kleinste Dateien zuerst, z.B. ein
   simples frühes Level, z.B. `W1L0.MAP`/`W1L0.ARE` falls vorhanden —
   sonst kleinste Datei nach Groesse waehlen).
3. Erst danach: Python-Projektstruktur aufsetzen (pygame), Asset-Loader
   fuer BOB/PCC/MAP schreiben (PCC-Loader ist im Grunde fertig, nur
   noch von PPM/ImageMagick-Zwischenschritt auf direktes PNG-Schreiben
   in Python umstellen, z.B. mit `Pillow` — aktuell haengt der Decoder
   noch am System-`convert`-Tool, das fuer den finalen Python-Port
   NICHT die Zielarchitektur sein soll).

### Hinweis fuer Fortsetzung nach Neustart/Session-Wechsel
Dieses Projekt laeuft bewusst autonom weiter (Stefan-Wunsch, 2026-07-22).
Fortschritt wird nach JEDEM Meilenstein hier in `NOTES.md` gesichert.
Zusaetzlich liegt ein gepinnter Kurz-Status im Memory (Suchbegriff
"Kellogg's Remake") als Fallback, falls diese Datei mal nicht griffbereit
sein sollte. Bei Session-Neustart: einfach hier weiterlesen ab
"Naechste Schritte" oben, keine Rueckfrage bei Stefan noetig.

Ein `trigger_timer` ("kellogg-remake-continue") ist als Selbst-Weck-Kette
aktiv: feuert stuendlich, arbeitet den naechsten offenen Punkt ab, speichert
hier, legt danach den naechsten Timer an — laeuft ohne Rueckfrage weiter.

## PCC-Decoder-Bugfix + Git-Repo (2026-07-22, ~09:20 Ortszeit)

Stefan hat zurecht bemaengelt, dass die PCC-Bilder verzerrt/verrutscht
aussehen (z.B. Smacks-Frosch spiegelverkehrt, Kellogg's-Logo mit Fehlstelle).
Ergebnis der Untersuchung:

**GEFUNDEN UND GEFIXT — Width/Height-Bug:** Der Decoder las Breite/Hoehe
bisher aus Offset 12-15 (siehe alte Notiz oben). Das ist FALSCH — dieses
Feld ist bei allen Dateien ein Konstant-/Platzhalterwert (vermutlich
DPI-Reserved-Feld wie im echten 128-Byte-PCX-Header), der bei
Vollbild-Screens (320x200) zufaellig mit der echten Groesse
uebereinstimmt, bei kleineren Sprites/Logos aber komplett falsch ist.
**Richtig:** Breite/Hoehe muessen aus `Xmax-Xmin+1` / `Ymax-Ymin+1`
(Offset 4-11) berechnet werden. Beweis: `FACTOR5.PCC` konsumiert mit der
alten (falschen) Hoehe 200 nicht alle Bytes sauber, mit der echten Hoehe
199 (aus Ymax=198) landet der Byte-Konsum exakt bei 100% (51609/51609).
Betroffen/jetzt gefixt: `RAUSER1.PCC` (182x46 statt fälschlich 320x200),
`RAUSER2.PCC` (228x21), `RAUSER3.PCC` (16x55), `FAC0-3.PCC` (16x16),
`FACTOR5.PCC` (320x199). Fix ist in `tools/pcc_to_png.py` eingebaut,
alle 77 PNGs unter `png_out/` mit dem Fix neu generiert.

**Rauser-Intro: JA, schon extrahiert.** `RAUSER1/2/3.PCC` sind Frames
eines scrollenden Text-Logos (vermutlich "RAUSER ADVERTAINMENT PRESENTS"),
mit dem Fix jetzt lesbar (zeigt z.B. "...USER TRAI..." als Ausschnitt).
Volles Logo muesste sich aus allen 3 Frames zusammensetzen lassen (noch
nicht gemacht).

**FACTOR5.PCC "Geister"-Doppellogo: vermutlich KEIN Bug**, sondern ein
Reflexions-/Schatten-Designelement — Byte-Konsum ist exakt 100%, also
decodiert der Inhalt komplett korrekt, das Doppelbild ist einfach das,
was in der Datei steht.

**OFFEN — KELLOGGS.PCC/KARTE.PCC-Notch-Artefakt:** Der Width/Height-Fix
hat den harmlosen 320x200-Fall nicht veraendert (Xmax/Ymax ergeben dort
zufaellig dieselbe Groesse wie vorher). Das Notch-Artefakt (rot/gelber
Fleck rechts neben "Kellogg's"-Schriftzug, passt nicht zum
DOSBox-Referenz-Screenshot) bleibt bestehen. Ausgeschlossen als Ursache
(empirisch getestet, nicht nur vermutet):
- Horizontales Rollen/Scrollen des ganzen Bilds (18 Shift-Kandidaten
  durchprobiert) — Artefakt bleibt IMMER an derselben Stelle relativ zum
  Bildinhalt (Box/Text), nicht zur Leinwand. Kein Verschiebe-/Wrap-Bug.
- Zeilenweises Verwerfen von RLE-Overshoot am Zeilenende — zeilenbasierte
  und durchgehende (row-boundary-freie) Decodierung liefern fuer
  KELLOGGS.PCC byte-identische Ergebnisse (kein Overshoot tritt je auf).
Interessant: `MENU.PCC` nutzt vermutlich denselben Box-Rahmen (leere
Variante) und rendert jetzt SAUBER ohne Notch — der Fehler ist also
dateispezifisch, nicht im Rahmen-Design selbst. Naechste Hypothese:
Palette-Fehlzuordnung fuer einzelne Indizes ODER RLE-Ambiguitaet bei
literalen Pixelwerten >= 0xC0 (werden durch `(b&0xC0)==0xC0` evtl.
faelschlich als Lauflaengen-Token statt literaler Indexwert gelesen) —
noch zu verifizieren durch gezielten Test mit einem Decoder, der beide
Interpretationen an der vermuteten Fehlstelle durchspielt.

Ebenfalls noch offen (niedrige Prioritaet): `TONY.PCC`/`SMACKS.PCC`
liefern mit dem Xmax/Ymax-Fix nur 1x1 Pixel (degenerated, Xmax=Ymax=0
im Header) — vermutlich sind das keine "echten" Vollbilder, sondern
Platzhalter/ungenutzte Preview-Slots; die eigentlichen Charakter-Sprites
stecken hoechstwahrscheinlich in den `.BOB`-Dateien (`TONY.BOB`,
`SMACKS.BOB` etc.), nicht in den gleichnamigen `.PCC`-Dateien.

**Git-Repo eingerichtet:** Auf Stefans Wunsch liegt der Projektstand jetzt
unter `https://git.hacker-net.de/Aria-Software/tony-remake`. Bewusst NICHT
mit eingecheckt: `raw/` (Original-Spieldateien: PCKELL.DAT/.PRE/.SET,
RTM.EXE, START.EXE etc. — das ist buchstaeblich das Original-Spiel) und
`extracted_pre/` (die daraus entpackten 181 Rohdateien — noch
Original-Asset-Material, nur unverpackt). Mit eingecheckt: `NOTES.md`,
`tools/` (unser Code: `split_pre.py`, `pcc_to_png.py`), `dosbox/`
(Test-Konfiguration), `png_out/` (unsere konvertierten PNG-Ergebnisse,
408 KB, reine Arbeitsergebnisse kein Originalmaterial).

## KELLOGGS.PCC/KARTE.PCC-Notch-Artefakt — GELOEST (2026-07-22, ~09:30 Ortszeit)

**Die Notiz oben ("Ausgeschlossen als Ursache ... Zeilenweises Verwerfen von
RLE-Overshoot ... liefern byte-identische Ergebnisse") war FALSCH.** Das war
ein Messfehler einer frueheren Session: der "kontinuierliche" Testdecoder
hat versehentlich weiterhin die width/height aus Offset 12-15 gelesen (dem
VERWORFENEN Bugfix-1-Feld) statt aus Xmax/Ymax — dadurch kam bei den beiden
320x200-Vollbildern zufaellig das gleiche (korrekte) Ergebnis raus wie beim
zeilenbasierten Decoder, und der Test schien zu bestaetigen, dass beide
Methoden aequivalent sind. Sind sie nicht.

**Neu verifiziert mit einem sauberen Vergleichstest** (`Buffer.compare` in
Node.js, unabhaengige Re-Implementierung): zeilenbasiertes Decoding
(Row-Reset, discard Overflow am Zeilenende) und durchgehendes Decoding
(RLE-Runs duerfen ueber Zeilengrenzen hinweglaufen) liefern **NICHT**
identische Ergebnisse — 216 von 64000 Pixeln unterscheiden sich bei
KARTE.PCC, 293 von 64000 bei KELLOGGS.PCC. Klingt nach wenig (<0.5%), reicht
aber, um ganze Bildbereiche sichtbar zu verschieben, weil ab dem ersten
"verlorenen" Ueberlauf-Pixel alle nachfolgenden Zeilen einen Pixel weiter
"nachruecken".

**Beweis per Ground-Truth-Vergleich:** DOSBox-Screenshot
`aria_kellogg_worldmap.png` (1024x768 mit schwarzen Balken) exakt auf den
reinen Spielbereich zugeschnitten (`convert -fuzz 5% -trim` → 640x400,
= 2x 320x200) und auf 320x200 runterskaliert
(`/shared/uploads/aria_karte_reference_320.png`). Nebeneinander-Vergleich
mit dem durchgehend (ohne Row-Reset) decodierten `KARTE.PCC`
(`/shared/uploads/aria_karte_compare2.png`): **pixel-identisch** — Berge,
Schloss, Drache, Tiger, Affe/Coco, Frosch, Teich, Haus, Voegel-Ecke, alles
exakt an der richtigen Stelle. Das Row-Reset-Verhalten war der einzige
Bug; es gibt kein horizontales Rollen, keine Palette-Fehlzuordnung, keine
RLE-Ambiguitaet bei Werten >=0xC0.

**Fix:** `tools/pcc_to_png.py` decodiert jetzt global `width*height` Pixel
aus dem RLE-Strom OHNE pro Zeile abzuschneiden (kein Row-Reset mehr). Alle
77 PNGs in `png_out/` wurden mit diesem finalen Decoder neu erzeugt
(diesmal wirklich verifiziert, nicht nur "sieht plausibel aus"). Kleine
Sprites/Logos waren von diesem Bug kaum betroffen (selten ein Run, der eine
Zeilengrenze ueberschreitet) — deshalb fiel es dort nie auf, nur bei den
zwei grossen 320x200-Vollbildern.

**Rauser-Intro bestaetigt (Frage von Stefan):** `RAUSER1/2/3.PCC` sind schon
laenger extrahiert und liegen jetzt mit dem finalen Decoder sauber decodiert
in `png_out/`. Es ist ein Text-Logo "RAUSER" + "ADVERTAINMENT" (Studio-Card),
als 3 Bild-Frames — vermutlich fuer einen Scroll-/Fade-Effekt, den die
Original-Engine (RTM.EXE) zur Laufzeit zusammensetzt, KEIN Video/keine
Animation-Datei. Fuers Remake heisst das: die 3 Frames sind da, die
Overlay-/Scroll-Logik muss im Python-Port nachgebaut werden (vermutlich
simpel: Frame croppen + ueber Zeit einblenden, sobald wir wissen wie die
Original-Sequenz zeitlich ablaeuft — dafuer ggf. DOSBox-Referenzvideo/
Screenshots in der Sequenz aufnehmen, spaeterer Schritt).

## BOB-Sprite-Format — Exploration laeuft, noch nicht geloest (Stand 09:30)

Auf `aria-wohnung` (`/home/aria/kellogg_remake/tools/`) lief parallel schon
einiges an Exploration fuer das naechste Format (BOB-Sprites): Brute-Force-
Breitensuche (`bob_width_search.py`), Header-Diff zwischen aehnlich grossen
Dateien (`bob_header_diff.py`, `bob_header_search.py`), Histogramm-Analyse
(`bob_histogram.py`), Sichtgitter-Rendering mit mehreren Breiten-Kandidaten
(`bob_render_grid.py`/`bob_render_grid2.py`), sowie erste Versuche die
`PCKELL.DAT`-Offset-Tabelle zu parsen (`dat_analyze.py`/`dat_analyze2.py`,
`dat_table2.py`, `dat_u16.py`). **Kein Ergebnis/Durchbruch bisher** — alles
noch offene Exploration, keiner der Scripts hat schon eine verifizierte
Loesung. Zur Sicherheit (Stefans Wunsch: nichts soll bei einem VM-Neustart
verloren gehen) sind alle diese Scripts jetzt zusaetzlich hier im
Projekt gesichert unter `tools/wip_bob_sprite_research/` (noch nicht
aufgeraeumt/nicht final, bewusst als "work in progress" separiert von den
fertigen Tools `split_pre.py`/`pcc_to_png.py`).

## KORREKTUR 2026-07-22 (nachmittags) — der "kontinuierliche" Fix oben war FALSCH

Stefan hat sich das gepushte Repo angeschaut und den Bug SOFORT wieder
gesehen (Frosch links statt rechts, Kellogg's-Logo verschoben) — die
"pixel-perfect verifiziert"-Behauptung im Abschnitt direkt darueber war
**selbst ein Messfehler**, genau wie der davor schon korrigierte. Beide
eigenen Hand-RLE-Decoder (Row-Reset UND kontinuierlich) haben KARTE.PCC/
KELLOGGS.PCC nachweislich sichtbar falsch decodiert (Bildinhalt dupliziert/
verschoben) — mein visueller Vorher-Vergleich war schlicht nicht sorgfaeltig
genug, ich habe der eigenen Automatik zu frueh vertraut.

**Stefans entscheidender Hinweis:** https://github.com/movAX13h/tony-and-friends-in-kelloggs-land
— ein bereits existierendes Reverse-Engineering-Projekt fuer GENAU dieses
Spiel (dort "Tony and Friends in Kellogg's Land" genannt, gleiche
PCKELL.DAT/PCKELL.SET-Assets). Enthaelt fertigen, funktionierenden C#-Code
fuer PCX/BOB/MAP/ARE/ICO/DAT — Quelle: `/tmp/tony-ref` (geklont, kein
LICENSE-File im Repo, daher NICHT 1:1-Code uebernommen, sondern nur als
Format-Referenz genutzt und in eigenem Python-Code neu umgesetzt).

Deren `Formats/PCXFile.cs` bestaetigt: `.PCC` ist stinknormales PCX v5,
8bpp, RLE, **mit Row-Reset** (pro Zeile wird ein frischer RLE-Reader
erzeugt, ueberschuessige Pixel eines Runs am Zeilenende werden verworfen —
Standard-PCX-Verhalten, keine Sonderregel). Das war also urspruenglich
(Bugfix 1, vormittags) schon RICHTIG vermutet — der eigentliche Bug lag
tiefer in der eigenen Implementierung und wurde nie gefunden.

**Der eigentliche Fix:** Decoder komplett ausgetauscht — `tools/pcc_to_png.py`
nutzt jetzt NICHT mehr eigenes RLE-Decoding, sondern `convert pcx:datei.PCC
out.png` (ImageMagick's ausgereifter PCX-Decoder, der die Datei einfach
per Standard-Format-Erkennung liest). Kein Workaround, sondern die richtige
Loesung: unser Format-Verstaendnis war im Kern korrekt, nur die
Handimplementierung hatte einen Bug den wir trotz zweier Anlaeufe nicht
gefunden haben — ein reifer, jahrzehntealter PCX-Decoder macht das
zuverlaessig richtig.

**Neu verifiziert (diesmal wirklich sorgfaeltig, Bild angeschaut statt nur
Byte-Statistik):** `png_out/KELLOGGS.png` und `png_out/KARTE.png` sehen jetzt
visuell identisch zu den echten DOSBox-Screenshots aus
(`aria_kellogg_titlescreen.png`/`aria_kellogg_worldmap.png`) — Vogelkopf
oben links, Drache+Schloss oben rechts, Frosch im Teich, Tiger unten
rechts, Coco unten links, alles an der richtigen Stelle, kein Doppel-Bild,
keine Kerbe. `FACTOR5.PCC`s "Geister-Doppellogo" ist ueber ImageMagick
ebenfalls sauber decodiert und bestaetigt sich damit endgueltig als
Absicht (Reflexions-Design), nicht als Bug. Alle 77 PCC-Dateien mit dem
neuen Decoder neu erzeugt und liegen in `png_out/`.

**Nebenfund:** `TONY.PCC`, `SMACKS.PCC`, `TOUCAN.PCC`, `COCO.PCC` (und
vermutlich weitere Charakter-Namen) decodieren zu winzigen 1x1-Pixel-Bildern
— das ist KEIN Extraktions-Bug. Laut `Form1.cs` der Referenz dienen manche
`.PCC`-Dateien nur als **Palette-Lieferant** fuer die zugehoerige `.ICO`/
`.BOB`-Sprite-Datei (ICO/BOB haben selbst keine eingebettete Palette,
im Gegensatz zu vollen PCC-Bildschirmen). Wichtig fuers spaetere BOB/ICO-
Decoding: Palette kommt dann von der PCC-Datei mit gleichem Basisnamen
(z.B. `TONY.BOB` -> Palette aus `TONY.PCC`), nicht aus der Sprite-Datei
selbst.

## Naechste Schritte (Prioritaet, Stand nachmittags 22.07.)
1. **BOB/SRB-Sprite-Format mit Hilfe der Referenz reversen.** Die Referenz
   (`/tmp/tony-ref/Unpacker/Formats/BOBFile.cs`, `BOBPainter.cs`) hat das
   schon geloest — README beschreibt BOB als "data and x86 code to display;
   somewhat similar to BOB format of Turrican II". Naechster Schritt: deren
   `BOBFile.cs` genau lesen und die Logik in eigenes Python uebersetzen
   (nicht 1:1 kopieren, kein LICENSE im Repo), dann gegen `A.BOB`
   (kleinstes Beispiel) verifizieren. Das sollte den bisherigen
   `wip_bob_sprite_research/`-Blindflug ueberfluessig machen.
2. Genauso `MAPFile.cs`/`AREFile.cs`/`ICOFile.cs` fuer Level-Maps/Areas/
   Tilesets nutzen statt weiter blind zu raten — auch hier: Format-Wissen
   uebernehmen, Code selbst neu schreiben.
3. Rauser-Intro-Sequenz (3 Frames) zu einer zusammengesetzten Vorschau
   rendern/dokumentieren, sobald Zeit ist — niedrige Prioritaet, Assets sind
   schon da.
4. Python/pygame-Projektstruktur aufsetzen (PCC-Loader ist jetzt wirklich
   fertig und verifiziert: `convert pcx:datei.PCC out.png` bzw. fuer den
   finalen Port direkt Pillow's PCX-Reader nutzen — Pillow unterstuetzt
   PCX nativ, damit brauchen wir zur Laufzeit kein externes ImageMagick
   mehr).

**Lektion fuer mich selbst (ARIA):** zweimal hintereinander eine "pixel-
perfect verifiziert"-Behauptung aufgestellt, die beim tatsaechlichen
Hinschauen (Bild anzeigen, nicht nur Bytes vergleichen) klar falsch war.
Naechstes Mal: bei jeder Verifikations-Behauptung IMMER das decodierte Bild
selbst anschauen (Read-Tool, multimodal), nicht nur Byte-/Pixel-Statistiken
vertrauen, bevor ich "geloest"/"verifiziert" sage.

## DURCHBRUCH 2026-07-22 (Nachmittag/Abend) — BOB/ICO/MAP komplett geloest

Stefan wollte aufraeumen + alle restlichen Assets (BOB/ICO/MAP/ARE/SAM/TFX).
Grosser Fund dabei: **`PCKELL.DAT` ist der eigentliche, einzige Asset-
Container** — nicht `PCKELL.PRE` (das war nur ein Nebenprodukt/Cache aus
`PCKELL.SET`). Referenz-Repo (`Formats/DATFile.cs`) beschreibt ihn explizit
als "the only container format": Index steht am DATEIENDE (Anzahl Entries
als u16 bei `len-4`, Index-Offset als i32 bei `len-8`), pro Entry
`[u16 NameLen][Name][i32 Offset]`, Laenge = Differenz zum naechsten Offset.
Score: **alle 178 Dateien fehlerfrei extrahiert**, exakt matchend zu
APPEND.LST — und `KELLOGGS.PCC` daraus ist **byte-identisch** zur alten
PRE-Extraktion, also war unser PCC-Weg schon konsistent. `PCKELL.PRE`/
`extracted_pre/`/`split_pre.py` sind damit ueberfluessig geworden, aus dem
Tool-Set entfernt (Repo-Hygiene, kein Skill-Friedhof-Aequivalent fuer
Tools). Neue kanonische Quelle: `tools/dat_extract.py` +
`tools/kellogg_formats.DATContainer`.

**PCC-Bug-Nachtrag:** beim heutigen Re-Check mit frischem Blick (Kellogg's-
Logo UND Weltkarte hochskaliert wirklich angeschaut, nicht nur behauptet)
ist `png_out/` tatsaechlich korrekt — Frosch im Teich unten links, Drache+
Schloss oben, Tiger/Coco richtig platziert, "Kellogg's präsentiert"-Box sauber.
Der PCC-Teil war also wirklich fertig, keine weitere Aktion noetig.

**BOB (Sprites) — komplett geloest.** Format aus `BOBFile.cs`/`Form1.cs`
in eigenes Python uebersetzt (`tools/kellogg_formats.py`, Funktionen
`parse_bob`/`_parse_bob_executable`): jede BOB-Datei ist eine Sequenz von
Frames, jeder Frame hat einen 14-Byte-Header (Breite/Hoehe/Laenge des
"Pointer"-Segments), gefolgt von echtem, sich selbst beschreibendem x86-
Maschinencode (`mov byte/word ptr [si+X], Y`-Ketten + `out dx,al` fuer
EGA-Page-Wechsel), der beim "Ausfuehren" direkt die Pixel-Kopieranweisungen
liefert (Offset+EGA-Page -> x/y, Pixelwert = Byte-Konstante minus 0x80 als
Palette-Index). Kein echter x86-Interpreter noetig, nur ein kleiner
Pattern-Matcher fuer die 10 vorkommenden Opcodes. Palette kommt (Form1.cs-
Regel) von der PCC-Datei mit gleichem Basisnamen (z.B. `TONY.BOB` ->
Palette aus `TONY.PCC`), bei 1-Buchstaben-Dateien (`A.BOB`..`O.BOB`, die
Ameisen) von `ANTS.PCC`, sonst von `W2.PCC` mit Index 0 auf Schwarz
gesetzt. **Alle 32 BOB-Dateien fehlerfrei decodiert, 462 Frames total.**
Visuell verifiziert (nicht nur Byte-Statistik!): `A.BOB` ist eine 8-Frame-
Laufanimation eines kleinen Kaefers/Ameise, `TONY.BOB` zeigt Tony den
Tiger unmissverstaendlich in Lauf-, Wink-, Sitz- und Sprung-Posen (53
Frames). Ergebnisse in `render_out/bob/<NAME>/NNN.png` (Einzelframes) +
`render_out/bob/<NAME>_sheet.png` (Grid-Uebersicht).

**ICO (Tilesets) — komplett geloest.** 16x16-Kacheln in "gescrambelter"
EGA-Spaltenreihenfolge (`parse_ico`): pro Zeile 4 EGA-Pages a 4 Pixel,
Palette-Index = Byte minus 128. Palette-Regel: `W1`/`W2`/`W3` aus dem
Dateinamen erkannt, Basis-Palette von `<WORLD>.PCC`, aber die 16 Farben
Index 16-31 IMMER von `W2.PCC` ueberschrieben (die sind laut Referenz die
geteilten Animations-/Item-Farben aller drei Welten) — ausser bei `W2`
selbst. **Alle 19 ICO-Dateien fehlerfrei decodiert.** Ergebnis in
`render_out/ico/<NAME>.png`.

**MAP (Level-Karten) — komplett geloest.** Klares Format, aber
GROSS-ENDIAN (!), Signatur `"TLE1"`, dann Breite/Hoehe/Konstante(=9) je
als big-endian int16, danach `Breite*Hoehe` big-endian u16-Zellen: unteres
9-Bit-Feld = Tile-Index (ins passende `<WORLD>.ICO`), oberes 7-Bit-Feld =
Kollisions-/Typ-Info (noch nicht weiter interpretiert). **Alle 22 MAP-
Dateien fehlerfrei decodiert UND gerendert** (Tile-Lookup im passenden ICO
+ Palette) — `W1L0.png` zeigt ein komplettes, stimmiges Level: Haeuser mit
rotem Dach, Buesche/Baeume, Wolken, blauer Himmel, Bergketten, alles exakt
an der Stelle, die man von einem Kellogg's-Tony-Jump'n'Run erwartet.
Ergebnis in `render_out/map/<NAME>.png`.

**ARE (Kollisionszonen) — NICHT geloest, bewusst zurueckgestellt.** Auch
die C#-Referenz hat das nie fertig gemacht (`AREFile.cs` liest nur naiv
176 little-endian u16-Werte ohne jede semantische Deutung, README nennt
nur den Namen "Area" ohne Details). Da MAP-Zellen bereits ein 7-Bit-
Kollisions-Typ-Feld mitbringen, ist unklar ob ARE ueberhaupt noch fuer den
Python-Port gebraucht wird (vielleicht redundant/Level-Editor-Metadaten) —
das klaeren wir erst, wenn die Spiellogik so weit ist dass Kollision
gebraucht wird. Rohdaten bleiben in `extracted_dat/` (nicht committed)
falls wir spaeter draufschauen wollen.

**SAM/TFX (Sound, TFMX-Format) — noch nicht angefasst.** 3+3 = 6 Dateien,
niedrige Prioritaet (Musik/SFX kommt spaeter, sobald Grafik+Logik stehen).
TFMX ist ein bekanntes Amiga/DOS-Tracker-Format, sollte mit vorhandenen
Libraries (z.B. `libxmp`/`ym2149`-Tools) machbar sein, nicht neu erfunden
werden muessen.

**Aufraeumen erledigt:**
- VM-Arbeitsverzeichnis (`/home/aria/kellogg_remake` auf `aria-wohnung`,
  NICHT im Repo): alle Debug-Logs/Test-Screenshots aus der DOSBox-IRQ-
  Session sowie `png_out_v2/` (veraltet) geloescht.
- `tools/`: alle Blindflug-Skripte aus der ersten BOB-Exploration
  (`bob_header_diff.py`, `bob_width_search.py`, `dat_analyze*.py`, etc.)
  UND `tools/wip_bob_sprite_research/` komplett entfernt — durch die
  echte Loesung in `kellogg_formats.py` ueberfluessig. `split_pre.py`
  ebenfalls entfernt (PRE-Weg durch DAT-Weg ersetzt).
- `.gitignore`: `extracted_dat/` ergaenzt (Rohdaten, copyrighted, wie
  `raw/`/`extracted_pre/` vorher schon).

**Naechste Schritte (Prioritaet, Stand Abend 22.07.):**
1. Rauser-Intro-Sequenz zusammensetzen (niedrig, Assets schon da).
2. Sound (SAM/TFX, TFMX-Format) angehen, wenn Zeit ist.
3. ARE/Kollisionsformat klaeren — erst wenn's fuer Spiellogik gebraucht wird.
4. **Jetzt wo alle visuellen Assets (PCC/BOB/ICO/MAP) fertig sind:**
   Python/pygame-Projektstruktur aufsetzen — Asset-Loader (Palette-Regeln
   aus `kellogg_formats.py` direkt uebernehmen), dann Tony-Bewegung/
   Kollision/Level-Scrolling als erste spielbare Vertical Slice.

## ENTSCHEIDUNG 2026-07-22 abends — erster Meilenstein: Boot-/Intro-Sequenz statt Gameplay

Stefan-Wunsch: als leichten, sichtbaren Einstieg zuerst die komplette
Boot-Sequenz nachbauen (Rauser-Card → Factor5-Logo → Kellogg's-Logo mit
"Vorhang"-Aufdeck-Effekt → Titelbild → Hauptmenue mit Menuepunkten →
Weltkarte), BEVOR Tony ueberhaupt beweglich ist. Sinnvolle Wahl: das
zwingt genau die Kern-Engine-Bausteine, die spaeter das ganze Spiel
braucht (Asset-Loader, Bild-Blitting mit Palette, Timing/Sequenzer,
Sound-Playback, Input-Handling fuers Menue) — nur eben am kleinstmoeglichen
Slice, bevor Physik/Kollision/Level-Logik dazukommen.

**Stand der benoetigten Assets (alle schon extrahiert, nur noch nicht
zu einer Sequenz zusammengesetzt):**
- Rauser-Card: `RAUSER1/2/3.PCC` (3 Scroll-/Fade-Frames, siehe oben)
- Factor5-Logo: `FACTOR5.PCC` + `FAC0-3.PCC` (kleine Begleit-Frames,
  vermutlich Blink-/Reflex-Animation)
- Kellogg's-Logo: `KELLOGGS.PCC` — **"Vorhang"-Effekt (Stefans Beobachtung:
  oberer Teil muesste sich von rechts nach links aufdecken) ist NICHT als
  Asset gespeichert**, sondern eine Laufzeit-Animation von RTM.EXE (reines
  Wipe/Reveal auf einem statischen Vollbild). Muss durch Beobachtung
  nachgebaut werden (Screenshot-Serie waehrend des Boot-Vorgangs in
  DOSBox, kurze Intervalle, um Richtung/Geschwindigkeit/Dauer zu
  bestimmen) — noch nicht gemacht, naechster Schritt.
- Titelbild ("Tony & Friends in Kellogg's Land"): noch keine eigene PCC-
  Datei dafuer identifiziert unter den 77 — moeglich, dass das Kellogg's-
  Logo direkt das Titelbild IST (ein Screen), oder der Text wird von der
  Engine ueber ein weiteres, noch nicht namentlich zugeordnetes PCC
  gelegt. Zu klaeren beim naechsten DOSBox-Screenshot-Durchlauf.
- Hauptmenue: `MENU.PCC` (Rahmen/Box vorhanden) — Menuepunkte selbst
  vermutlich als Text von der Engine gerendert (kein Font-Asset bisher
  identifiziert) oder als eigene ICO/BOB-Sprites. Noch offen.
- Karte: `KARTE.PCC` + `KARTE0-9.PCC` (10 Zusatz-Frames, vermutlich
  kleine Animationen auf der Karte — Wasser/Flagge/Feuer o.ae., noch
  nicht einzeln zugeordnet).
- Sound: 3x SAM + 3x TFX (TFMX-Format, Amiga/DOS-Tracker) — bisher NICHT
  decodiert. Ob Rauser/Factor5/Kellogg's-Screens ueberhaupt Sound haben,
  ist unklar (DOSBox lief bisher im ALSA-nosound-Modus, kein Ton
  gehoert) — zu klaeren durch Sichtung von `tools/tfmx_player` (C-Referenz-
  Tool, liegt schon lokal unter `tools/tfmx_player/`, noch uncommitted)
  und/oder DOSBox mit echtem Audio-Sink testen.

**Plan (in dieser Reihenfolge):**
1. pygame auf `aria-wohnung` installiert (User-pip, erledigt).
2. DOSBox-Screenshot-Serie waehrend des Bootvorgangs aufnehmen (kurze
   Intervalle ueber Rauser→Factor5→Kellogg's→Titel→Menue), um Timing +
   Wipe-Richtung/-Geschwindigkeit des Kellogg's-Vorhang-Effekts zu
   bestimmen, und um das noch unklare Titelbild/Menue-Text-Rendering zu
   identifizieren.
3. `tools/intro_sequence.py` (neu): pygame-basierter Player, der die
   Screens in der beobachteten Reihenfolge + Timing zeigt (erst ohne
   Ton), Wipe-Effekt fuer Kellogg's-Logo nachbauen.
4. TFMX-Sound anhaengen, sobald `tfmx_player` als Referenz ausgewertet
   ist (Python-Wrapper oder Re-Implementierung der Decodierung).
5. Committen/pushen nach jedem funktionierenden Teilschritt (nicht erst
   am Ende), NOTES.md nach jedem Meilenstein aktualisieren — wie von
   Stefan gewuenscht, damit bei einem VM-/Brain-Neustart nichts verloren
   geht und einfach hier weitergelesen werden kann.

Laeuft jetzt selbstaendig weiter, keine Rueckfrage noetig.

## Boot-Sequenz vermessen + Intro-Player gebaut (2026-07-22 abends, Fortsetzung)

### 1) Echter Regressions-Bug gefunden + gefixt (tools/pcc_to_png.py)

Beim Draufschauen fuer die Intro-Arbeit aufgefallen: Commit `62af15e` hatte
den PCC-Decoder korrekt auf ImageMagick umgestellt (nachdem zwei eigene
Hand-RLE-Parser nachweislich falsche Pixel lieferten). Der naechste Commit
`3410a53` (eigentlich nur fuer BOB/ICO/MAP gedacht) hat `pcc_to_png.py`
aber **versehentlich durch eine AELTERE Version mit dem kaputten
Hand-RLE-Decoder ueberschrieben** -- vermutlich ein Merge-/Copy-Fehler beim
Zusammenfuehren von Aenderungen. Die bereits committeten 77 PNGs in
`png_out/` waren zum Glueck NICHT betroffen (die stammen noch von der guten
ImageMagick-Version), aber ein Rerun des Skripts haette wieder kaputte
Bilder erzeugt, ohne dass es aufgefallen waere.

**Fix:** Statt ImageMagick-Subprocess jetzt `kellogg_formats.load_pcc()` --
nutzt Pillows eingebauten, robusten PCX-Decoder direkt (`PIL.Image.open`
erkennt PCX an den Magic-Bytes, nicht am Dateinamen). Kein eigener
RLE-Parser mehr im Projekt, an keiner Stelle. Alle 77 PCC neu aus
`PCKELL.DAT` gerendert und via `compare -metric AE` **byte-fuer-byte
pixelidentisch (AE=0)** zu den alten (guten) PNGs verifiziert -- keine
Regression, sauberer Fix. Neue Funktionen `load_pcc()` / `pcc_to_rgba()`
in `kellogg_formats.py`, wiederverwendbar fuer den Intro-Player.

### 2) Boot-Sequenz per echter Screenshot-Serie vermessen (0.3s-Intervall)

`xvfb-run`-Setup (Xvfb + `import -window root` alle 0.3s) waehrend
`START.EXE` bootet, ~90 Frames ueber ~27s. Ergebnis (Hash-Dedup + visuelle
Pruefung der Uebergaenge):

1. **Rauser-Advertainment-Karte** -- Komposit aus `RAUSER1.PCC` (dunkle Box
   "RAUSER"), `RAUSER3.PCC` (blaue Box, Ausrufezeichen), `RAUSER2.PCC`
   ("ADVERTAINMENT"-Schriftzug) auf weissem Grund. Statisch gehalten (kein
   Aufbau-Effekt beobachtet), ~3s.
2. Kurze schwarze Pause (~0.3-0.5s).
3. **Factor5-Studio-Logo** (`FACTOR5.PCC`, 320x199) -- **komplett statisches
   Bild**, keine Laufzeit-Animation. Das "Geister"-Doppellogo (zwei leicht
   versetzte FACTOR-Schriftzuege + Spiegelung am Boden) ist Teil des Assets
   selbst (Byte-Konsum exakt 100%, kein Bug). Lange gehalten, ~6s.
4. Kurze schwarze Pause.
5. **Kellogg's-Markenlogo** (`KELLOGGS.PCC`, 320x200) -- erscheint SOFORT
   komplett und bleibt die ganze Zeit scharf. **KORREKTUR einer fruehen
   Fehlannahme:** es gibt HIER keinen Vorhang-/Wipe-Effekt auf dem Logo
   selbst. Was tatsaechlich passiert: der Text **"praesentiert"** darunter
   faedet per **Palette-Animation** von blass (fast weiss) zu kraeftigem
   Rot ein (~3-4s beobachtet). Per Index-Analyse verifiziert: die Pixel des
   Textes nutzen exklusiv die Palette-Indizes **34, 42, 43, 44, 45** (Bbox
   x=71-241, y=108-141 im 320x200-Bild) -- alles andere im Bild bleibt
   waehrend des Fades unveraendert.
6. Kurze schwarze Pause.
7. **Titelbild "TONY & FRIENDS in Kellogg's Land"** -- **DAS ist der
   eigentliche Vorhang-Effekt**, den Stefan urspruenglich meinte. Wichtiger
   Fund: dieses Bild ist intern **320x480** (doppelt so hoch wie die
   anderen Screens!), zusammengesetzt aus den 4 PCC-Quadranten `KELL256A`
   (oben links) / `KELL256B` (oben rechts) / `KELL256C` (unten links) /
   `KELL256D` (unten rechts), je 160x240 -- durch Stitchen zu einem
   320x480-Gesamtbild verifiziert (siehe `/tmp/kell_full_stitch.png`
   waehrend der Session, zeigt exakt das erwartete Titelbild). Der
   Reveal-Effekt: **obere Bildhaelfte (A|B) faehrt von oben nach unten
   ein, untere Haelfte (C|D) von unten nach oben** -- wie ein Theater-
   vorhang, nur vertikal, beide Haelften treffen sich exakt in der Mitte
   (y=240 im 480px-Bild). Dauer ~3s (Frames 73->83 in der Aufnahme).
   DOSBox-Fenster ist fuer diesen Screen sichtbar groesser/anders
   proportioniert als bei den 320x240-Screens davor -- passt zur These
   eines eigenen 320x480-Modus nur fuer dieses Bild.

Alle anderen Screens (Rauser/Factor5/Kellogg's-Logo) laufen im
Fenster-Seitenverhaeltnis 320x240 (aus Trim-Analyse des DOSBox-Fensters:
640x480 Xvfb-Ausschnitt = exakt 2x 320x240) -- die PCC-Bilder selbst sind
oft nur 320x199/200 und werden darin mit schwarzen Balken oben/unten
letterboxed (gut sichtbar am schwarzen Rand um die Kellogg's-Box in den
Screenshots).

### 3) Erster spielbarer Meilenstein: `tools/intro_sequence.py`

pygame-Player, der die komplette oben beschriebene Sequenz nachbaut:
Asset-Loading aus `PCKELL.DAT` (ueber `kellogg_formats`), Bild-Rendering
mit Palette, Timing/Sequenzer, Palette-Fade-Effekt (echte Index-Animation,
kein Alpha-Crossfade-Hack), Vorhang-Wipe-Effekt fuer das Titelbild.
Headless getestet (Xvfb + Screenshot-Serie) -- **visuell verifiziert,
sieht in allen Phasen sehr nah am echten DOSBox-Boot aus**:

[FILE: /shared/uploads/aria_intro_rauser.png] (Rauser-Karte, Komposit)
[FILE: /shared/uploads/aria_intro_factor5.png] (Factor5-Logo, statisch)
[FILE: /shared/uploads/aria_intro_kelloggs_fade.png] ("praesentiert" mitten im Fade)
[FILE: /shared/uploads/aria_intro_titel_wipe.png] (Titelbild-Vorhang mitten im Reveal)
[FILE: /shared/uploads/aria_intro_titel_final.png] (Titelbild komplett offen)

**Bekannte Ungenauigkeiten (v1, nicht pixelperfekt, aber nah dran):**
- Rauser-Komposit-Layout (Position von RAUSER1/2/3 zueinander) ist per
  Augenmass an die Screenshots angenaehert, nicht pixelgenau vermessen --
  bei Bedarf spaeter per genauerem Screenshot-Vergleich nachjustieren.
- Fade-/Wipe-Dauern sind aus der 0.3s-Sample-Screenshot-Serie abgeleitet
  (+/- ein paar hundert ms Unschaerfe), nicht aus dem Originalcode gelesen
  (RTM.EXE ist compiliert, kein Quellcode verfuegbar).
- Sound fehlt komplett (TFMX/SAM noch nicht decodiert, siehe unten).

**Ausfuehren:** `python3 tools/intro_sequence.py` auf `aria-wohnung`
(pygame jetzt per `apt install python3-pygame` installiert, NICHT pip --
System-Python ist "externally managed", pip-User-Install schlug fehl).
`--once` fuer einen Durchlauf statt Endlosschleife wie im Original.

### Naechste Schritte (Prioritaet)
1. Sound (SAM/TFX TFMX-Format) decodieren + an die Intro-Sequenz haengen --
   `tools/tfmx_player/` (C-Referenztool) liegt bereit.
2. Rauser-Layout und Fade/Wipe-Timings feinjustieren falls gewuenscht.
3. Danach: Uebergang von Intro zu echtem Gameplay -- Tony-Bewegung auf
   Level W1L0 als naechster grosser Meilenstein (MAP+ICO+BOB sind fertig).

Laeuft selbstaendig weiter, keine Rueckfrage noetig.
