commit 3c650e6aef93f13b57b9821420986727a963a797 Author: ARIA Date: Wed Jul 22 07:20:13 2026 +0000 Initial commit: PCC-Decoder (mit Xmax/Ymax-Bugfix), Notes, DOSBox-Config - tools/pcc_to_png.py: PCX-artiger Decoder fuer die 77 PCC-Vollbild-/Logo- Dateien, mit Fix fuer falsch gelesene Width/Height (muss aus Xmax-Xmin+1/ Ymax-Ymin+1 statt Offset 12-15 berechnet werden) - tools/split_pre.py: Extrahiert alle 181 Dateien aus PCKELL.PRE - png_out/: alle 77 konvertierten PNGs (Arbeitsergebnis, kein Original-Asset) - NOTES.md: vollstaendiger Analyse-Stand inkl. offener Punkte - dosbox/dosbox.conf: funktionierende Testkonfiguration (IRQ-Fix) Bewusst ausgeschlossen (.gitignore): raw/ und extracted_pre/, da Original- Spieldaten von Kellogg's Tony and Friends (1994), keine Weiterverbreitung. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..11f2ab9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +# Original-Spieldateien (copyrighted, gehoeren nicht ins Repo) +raw/ +extracted_pre/ +*.ppm diff --git a/NOTES.md b/NOTES.md new file mode 100644 index 0000000..1f3802b --- /dev/null +++ b/NOTES.md @@ -0,0 +1,467 @@ +# 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 +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 ` (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\.BOB"][ 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\` +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][ 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/.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). diff --git a/dosbox/dosbox.conf b/dosbox/dosbox.conf new file mode 100644 index 0000000..5a76bed --- /dev/null +++ b/dosbox/dosbox.conf @@ -0,0 +1,15 @@ +[sdl] +fullscreen=false +output=surface + +[sblaster] +sbtype=sb16 +sbbase=220 +irq=5 +dma=1 +hdma=5 + +[autoexec] +mount c ~/kellogg_remake/raw +c: +START.EXE diff --git a/png_out/ANTS.png b/png_out/ANTS.png new file mode 100644 index 0000000..3901246 Binary files /dev/null and b/png_out/ANTS.png differ diff --git a/png_out/CHOCOS.png b/png_out/CHOCOS.png new file mode 100644 index 0000000..6d2b403 Binary files /dev/null and b/png_out/CHOCOS.png differ diff --git a/png_out/CHOCOS10.png b/png_out/CHOCOS10.png new file mode 100644 index 0000000..eacabfa Binary files /dev/null and b/png_out/CHOCOS10.png differ diff --git a/png_out/CHOCOS2.png b/png_out/CHOCOS2.png new file mode 100644 index 0000000..f8a3730 Binary files /dev/null and b/png_out/CHOCOS2.png differ diff --git a/png_out/CHOCOS3.png b/png_out/CHOCOS3.png new file mode 100644 index 0000000..f8a3730 Binary files /dev/null and b/png_out/CHOCOS3.png differ diff --git a/png_out/CHOCOS4.png b/png_out/CHOCOS4.png new file mode 100644 index 0000000..874bd41 Binary files /dev/null and b/png_out/CHOCOS4.png differ diff --git a/png_out/CHOCOS5.png b/png_out/CHOCOS5.png new file mode 100644 index 0000000..3ff1872 Binary files /dev/null and b/png_out/CHOCOS5.png differ diff --git a/png_out/CHOCOS6.png b/png_out/CHOCOS6.png new file mode 100644 index 0000000..8752848 Binary files /dev/null and b/png_out/CHOCOS6.png differ diff --git a/png_out/CHOCOS7.png b/png_out/CHOCOS7.png new file mode 100644 index 0000000..194533a Binary files /dev/null and b/png_out/CHOCOS7.png differ diff --git a/png_out/CHOCOS8.png b/png_out/CHOCOS8.png new file mode 100644 index 0000000..eacabfa Binary files /dev/null and b/png_out/CHOCOS8.png differ diff --git a/png_out/CHOCOS9.png b/png_out/CHOCOS9.png new file mode 100644 index 0000000..eacabfa Binary files /dev/null and b/png_out/CHOCOS9.png differ diff --git a/png_out/COCO.png b/png_out/COCO.png new file mode 100644 index 0000000..3901246 Binary files /dev/null and b/png_out/COCO.png differ diff --git a/png_out/FAC0.png b/png_out/FAC0.png new file mode 100644 index 0000000..7a374ee Binary files /dev/null and b/png_out/FAC0.png differ diff --git a/png_out/FAC1.png b/png_out/FAC1.png new file mode 100644 index 0000000..af0f07d Binary files /dev/null and b/png_out/FAC1.png differ diff --git a/png_out/FAC2.png b/png_out/FAC2.png new file mode 100644 index 0000000..7a374ee Binary files /dev/null and b/png_out/FAC2.png differ diff --git a/png_out/FAC3.png b/png_out/FAC3.png new file mode 100644 index 0000000..7a374ee Binary files /dev/null and b/png_out/FAC3.png differ diff --git a/png_out/FACTOR5.png b/png_out/FACTOR5.png new file mode 100644 index 0000000..0b58052 Binary files /dev/null and b/png_out/FACTOR5.png differ diff --git a/png_out/FON_1.png b/png_out/FON_1.png new file mode 100644 index 0000000..cce01a6 Binary files /dev/null and b/png_out/FON_1.png differ diff --git a/png_out/FON_1B.png b/png_out/FON_1B.png new file mode 100644 index 0000000..11b9ad0 Binary files /dev/null and b/png_out/FON_1B.png differ diff --git a/png_out/FON_2.png b/png_out/FON_2.png new file mode 100644 index 0000000..8db6da4 Binary files /dev/null and b/png_out/FON_2.png differ diff --git a/png_out/FRA_L.png b/png_out/FRA_L.png new file mode 100644 index 0000000..c194e14 Binary files /dev/null and b/png_out/FRA_L.png differ diff --git a/png_out/FRA_LO.png b/png_out/FRA_LO.png new file mode 100644 index 0000000..c194e14 Binary files /dev/null and b/png_out/FRA_LO.png differ diff --git a/png_out/FRA_LU.png b/png_out/FRA_LU.png new file mode 100644 index 0000000..c194e14 Binary files /dev/null and b/png_out/FRA_LU.png differ diff --git a/png_out/FRA_M.png b/png_out/FRA_M.png new file mode 100644 index 0000000..c194e14 Binary files /dev/null and b/png_out/FRA_M.png differ diff --git a/png_out/FRA_O.png b/png_out/FRA_O.png new file mode 100644 index 0000000..c194e14 Binary files /dev/null and b/png_out/FRA_O.png differ diff --git a/png_out/FRA_R.png b/png_out/FRA_R.png new file mode 100644 index 0000000..c194e14 Binary files /dev/null and b/png_out/FRA_R.png differ diff --git a/png_out/FRA_RO.png b/png_out/FRA_RO.png new file mode 100644 index 0000000..c194e14 Binary files /dev/null and b/png_out/FRA_RO.png differ diff --git a/png_out/FRA_RU.png b/png_out/FRA_RU.png new file mode 100644 index 0000000..c194e14 Binary files /dev/null and b/png_out/FRA_RU.png differ diff --git a/png_out/FRA_U.png b/png_out/FRA_U.png new file mode 100644 index 0000000..c194e14 Binary files /dev/null and b/png_out/FRA_U.png differ diff --git a/png_out/GAMEBAR.png b/png_out/GAMEBAR.png new file mode 100644 index 0000000..be0249d Binary files /dev/null and b/png_out/GAMEBAR.png differ diff --git a/png_out/ITE0.png b/png_out/ITE0.png new file mode 100644 index 0000000..e1d722e Binary files /dev/null and b/png_out/ITE0.png differ diff --git a/png_out/ITE1.png b/png_out/ITE1.png new file mode 100644 index 0000000..e1d722e Binary files /dev/null and b/png_out/ITE1.png differ diff --git a/png_out/ITE2.png b/png_out/ITE2.png new file mode 100644 index 0000000..6514edc Binary files /dev/null and b/png_out/ITE2.png differ diff --git a/png_out/ITE3.png b/png_out/ITE3.png new file mode 100644 index 0000000..5c98941 Binary files /dev/null and b/png_out/ITE3.png differ diff --git a/png_out/KARTE.png b/png_out/KARTE.png new file mode 100644 index 0000000..b2b8bea Binary files /dev/null and b/png_out/KARTE.png differ diff --git a/png_out/KARTE0.png b/png_out/KARTE0.png new file mode 100644 index 0000000..22a4b88 Binary files /dev/null and b/png_out/KARTE0.png differ diff --git a/png_out/KARTE1.png b/png_out/KARTE1.png new file mode 100644 index 0000000..bfecb3f Binary files /dev/null and b/png_out/KARTE1.png differ diff --git a/png_out/KARTE2.png b/png_out/KARTE2.png new file mode 100644 index 0000000..22a4b88 Binary files /dev/null and b/png_out/KARTE2.png differ diff --git a/png_out/KARTE3.png b/png_out/KARTE3.png new file mode 100644 index 0000000..bfecb3f Binary files /dev/null and b/png_out/KARTE3.png differ diff --git a/png_out/KARTE4.png b/png_out/KARTE4.png new file mode 100644 index 0000000..68036e3 Binary files /dev/null and b/png_out/KARTE4.png differ diff --git a/png_out/KARTE5.png b/png_out/KARTE5.png new file mode 100644 index 0000000..fcbb095 Binary files /dev/null and b/png_out/KARTE5.png differ diff --git a/png_out/KARTE6.png b/png_out/KARTE6.png new file mode 100644 index 0000000..2b6a668 Binary files /dev/null and b/png_out/KARTE6.png differ diff --git a/png_out/KARTE7.png b/png_out/KARTE7.png new file mode 100644 index 0000000..17358be Binary files /dev/null and b/png_out/KARTE7.png differ diff --git a/png_out/KARTE8.png b/png_out/KARTE8.png new file mode 100644 index 0000000..d1b62b0 Binary files /dev/null and b/png_out/KARTE8.png differ diff --git a/png_out/KARTE9.png b/png_out/KARTE9.png new file mode 100644 index 0000000..291f3ce Binary files /dev/null and b/png_out/KARTE9.png differ diff --git a/png_out/KELL256A.png b/png_out/KELL256A.png new file mode 100644 index 0000000..18aea5a Binary files /dev/null and b/png_out/KELL256A.png differ diff --git a/png_out/KELL256B.png b/png_out/KELL256B.png new file mode 100644 index 0000000..d4481b3 Binary files /dev/null and b/png_out/KELL256B.png differ diff --git a/png_out/KELL256C.png b/png_out/KELL256C.png new file mode 100644 index 0000000..836d366 Binary files /dev/null and b/png_out/KELL256C.png differ diff --git a/png_out/KELL256D.png b/png_out/KELL256D.png new file mode 100644 index 0000000..db327fd Binary files /dev/null and b/png_out/KELL256D.png differ diff --git a/png_out/KELLOGGS.png b/png_out/KELLOGGS.png new file mode 100644 index 0000000..fc581cb Binary files /dev/null and b/png_out/KELLOGGS.png differ diff --git a/png_out/MENU.png b/png_out/MENU.png new file mode 100644 index 0000000..d5ad31c Binary files /dev/null and b/png_out/MENU.png differ diff --git a/png_out/PARTY1.png b/png_out/PARTY1.png new file mode 100644 index 0000000..a5e313d Binary files /dev/null and b/png_out/PARTY1.png differ diff --git a/png_out/PARTY2.png b/png_out/PARTY2.png new file mode 100644 index 0000000..7b5deeb Binary files /dev/null and b/png_out/PARTY2.png differ diff --git a/png_out/RAUSER1.png b/png_out/RAUSER1.png new file mode 100644 index 0000000..f7682d4 Binary files /dev/null and b/png_out/RAUSER1.png differ diff --git a/png_out/RAUSER2.png b/png_out/RAUSER2.png new file mode 100644 index 0000000..24ef693 Binary files /dev/null and b/png_out/RAUSER2.png differ diff --git a/png_out/RAUSER3.png b/png_out/RAUSER3.png new file mode 100644 index 0000000..c27dead Binary files /dev/null and b/png_out/RAUSER3.png differ diff --git a/png_out/SMACKS.png b/png_out/SMACKS.png new file mode 100644 index 0000000..f425f71 Binary files /dev/null and b/png_out/SMACKS.png differ diff --git a/png_out/TONY.png b/png_out/TONY.png new file mode 100644 index 0000000..f425f71 Binary files /dev/null and b/png_out/TONY.png differ diff --git a/png_out/TOUCAN.png b/png_out/TOUCAN.png new file mode 100644 index 0000000..dd55b2f Binary files /dev/null and b/png_out/TOUCAN.png differ diff --git a/png_out/VIT1.png b/png_out/VIT1.png new file mode 100644 index 0000000..1d2a2ac Binary files /dev/null and b/png_out/VIT1.png differ diff --git a/png_out/VIT2.png b/png_out/VIT2.png new file mode 100644 index 0000000..1d2a2ac Binary files /dev/null and b/png_out/VIT2.png differ diff --git a/png_out/VIT3.png b/png_out/VIT3.png new file mode 100644 index 0000000..1d2a2ac Binary files /dev/null and b/png_out/VIT3.png differ diff --git a/png_out/VIT4.png b/png_out/VIT4.png new file mode 100644 index 0000000..1d2a2ac Binary files /dev/null and b/png_out/VIT4.png differ diff --git a/png_out/VIT5.png b/png_out/VIT5.png new file mode 100644 index 0000000..1d2a2ac Binary files /dev/null and b/png_out/VIT5.png differ diff --git a/png_out/VIT6.png b/png_out/VIT6.png new file mode 100644 index 0000000..1d2a2ac Binary files /dev/null and b/png_out/VIT6.png differ diff --git a/png_out/W1.png b/png_out/W1.png new file mode 100644 index 0000000..dd55b2f Binary files /dev/null and b/png_out/W1.png differ diff --git a/png_out/W2.png b/png_out/W2.png new file mode 100644 index 0000000..44a88cd Binary files /dev/null and b/png_out/W2.png differ diff --git a/png_out/W3.png b/png_out/W3.png new file mode 100644 index 0000000..73413be Binary files /dev/null and b/png_out/W3.png differ diff --git a/png_out/WECH_1.png b/png_out/WECH_1.png new file mode 100644 index 0000000..f043381 Binary files /dev/null and b/png_out/WECH_1.png differ diff --git a/png_out/WECH_2.png b/png_out/WECH_2.png new file mode 100644 index 0000000..4554a7f Binary files /dev/null and b/png_out/WECH_2.png differ diff --git a/png_out/WECH_3.png b/png_out/WECH_3.png new file mode 100644 index 0000000..3c5ac0b Binary files /dev/null and b/png_out/WECH_3.png differ diff --git a/png_out/WECH_4.png b/png_out/WECH_4.png new file mode 100644 index 0000000..ff69d5c Binary files /dev/null and b/png_out/WECH_4.png differ diff --git a/png_out/WECH_5.png b/png_out/WECH_5.png new file mode 100644 index 0000000..c10111a Binary files /dev/null and b/png_out/WECH_5.png differ diff --git a/png_out/WECH_6.png b/png_out/WECH_6.png new file mode 100644 index 0000000..253fc5b Binary files /dev/null and b/png_out/WECH_6.png differ diff --git a/png_out/WECH_7.png b/png_out/WECH_7.png new file mode 100644 index 0000000..a224852 Binary files /dev/null and b/png_out/WECH_7.png differ diff --git a/png_out/WECH_8.png b/png_out/WECH_8.png new file mode 100644 index 0000000..be1b2e8 Binary files /dev/null and b/png_out/WECH_8.png differ diff --git a/png_out/WECH_9.png b/png_out/WECH_9.png new file mode 100644 index 0000000..f9d2894 Binary files /dev/null and b/png_out/WECH_9.png differ diff --git a/tools/pcc_to_png.py b/tools/pcc_to_png.py new file mode 100644 index 0000000..29f66e1 --- /dev/null +++ b/tools/pcc_to_png.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python3 +"""Finaler PCC-Decoder fuer Kellogg's Tony and Friends (2026-07-22, ARIA). + +Format (verifiziert gegen MENU.PCC/RAUSER1-3/FACTOR5, visuell + byte-exakt): +- Byte 0-15: echter PCX-Header-Anfang (Manufacturer=0x0A, Version=5, + Encoding=1/RLE, BPP=8, dann Xmin/Ymin/Xmax/Ymax als LE16 bei Offset 4-11). + WICHTIG (Bugfix 2026-07-22): Width/Height MUESSEN aus Xmax-Xmin+1 / + Ymax-Ymin+1 berechnet werden. Die 2 LE16-Werte bei Offset 12-15 sehen fuer + Vollbild-Screens (320x200) zufaellig identisch aus und wurden erst dafuer + gehalten -- sind aber tatsaechlich NICHT die Bilddimensionen (vermutlich + ein DPI/Reserved-Feld wie im echten 128-Byte-PCX-Header), sondern ein + Konstantwert der bei kleinen Sprites/Logos (z.B. RAUSER1.PCC: 182x46, + FAC0.PCC: 16x16) komplett falsch war und zu kaputten/leeren Bildern fuehrte. + Mit dem Xmax/Ymax-Fix konsumiert z.B. FACTOR5.PCC exakt 100% der + komprimierten Bytes (51609/51609) statt vorher mit falscher Hoehe (200 + statt echten 199) zu ueberlaufen. +- Byte 16 .. (len-769): RLE-komprimierte Pixel-Indexdaten, SCANLINE-weise + decodiert (pro Zeile wird bis width Pixel gefuellt, ueberschuessige Pixel + eines Runs am Zeilenende werden verworfen -- klassisches PCX-Verhalten). + RLE-Tupel: Byte mit oberen 2 Bits gesetzt (0xC0-0xFF) = Lauflaenge (&0x3F), + gefolgt von einem Wert-Byte. Sonst literaler Pixel. +- Letzte 769 Bytes: 0x0C-Marker + 768 Byte (256 x RGB) eingebettete Palette + (klassische PCX-v5-256-Farben-Erweiterung). PRO DATEI eigene Palette, + keine globale Palette noetig. + +BEKANNTER OFFENER BUG (Stand 2026-07-22, noch nicht geloest): + KELLOGGS.PCC und KARTE.PCC (volle 320x200-Screens) zeigen weiterhin einen + lokalen Deko-Fehler (ein "Kerbe"/Notch-Artefakt rechts neben dem Kellogg's- + Schriftzug, roter/gelber Fleck der nicht ins Referenz-Screenshot passt). + Ausgeschlossen als Ursache: (a) horizontales Rollen/Verschieben des ganzen + Bilds -- getestet mit 18 Shift-Kandidaten, Artefakt bleibt IMMER an + derselben Position relativ zum Bildinhalt, nicht zur Leinwand -> kein + Rotations-/Scroll-Bug. (b) Zeilenweises Verwerfen von RLE-Overshoot -- + zeilenbasierte und "kontinuierliche" (ohne Row-Reset) Decodierung liefern + BYTE-IDENTISCHE Ergebnisse fuer diese Dateien. Vermutung: entweder eine + Palette-Fehlzuordnung fuer einzelne Indizes, oder eine RLE-Ambiguitaet bei + literalen Pixelwerten >= 0xC0 (die durch (b&0xC0)==0xC0 faelschlich als + Lauflaengen-Token statt als literaler Indexwert interpretiert werden + koennten) -- noch nicht verifiziert. FACTOR5.PCC's "Geister"-Doppellogo + ist dagegen vermutlich KEIN Bug, sondern ein Reflexions-/Schatten- + Designelement (Byte-Konsum ist bei diesem File exakt 100%). + +Nutzung: python3 pcc_to_png.py +Schreibt ein PPM und konvertiert via ImageMagick `convert` zu PNG. +""" +import sys, struct, subprocess, os + +def decode_pcc(data): + manuf, version, encoding, bpp = data[0], data[1], data[2], data[3] + xmin, ymin, xmax, ymax = struct.unpack('= n: + break + val = pixel_region[i]; i += 1 + row_out.extend([val] * count) + else: + row_out.append(b) + row_out = row_out[:width] + if len(row_out) < width: + row_out.extend([0] * (width - len(row_out))) + out.extend(row_out) + + return dict(width=width, height=height, marker_ok=(marker == 0x0C), + pixels=bytes(out), palette=palette, + consumed=i, pixel_region_len=n) + +def write_png(pixels, palette, width, height, out_png): + ppm = out_png + '.ppm' + with open(ppm, 'wb') as f: + f.write(f'P6\n{width} {height}\n255\n'.encode()) + buf = bytearray() + for px in pixels[:width*height]: + r, g, b = palette[px] + buf.extend([r, g, b]) + f.write(bytes(buf)) + subprocess.run(['convert', ppm, out_png], check=True) + os.remove(ppm) + +def main(): + inp, outp = sys.argv[1], sys.argv[2] + with open(inp, 'rb') as f: + data = f.read() + res = decode_pcc(data) + print(f"{inp}: {res['width']}x{res['height']} marker_ok={res['marker_ok']} " + f"consumed={res['consumed']}/{res['pixel_region_len']}") + write_png(res['pixels'], res['palette'], res['width'], res['height'], outp) + print(f"-> {outp}") + +if __name__ == '__main__': + main() diff --git a/tools/split_pre.py b/tools/split_pre.py new file mode 100644 index 0000000..9887468 --- /dev/null +++ b/tools/split_pre.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python3 +"""PCKELL.PRE Splitter v7 -- FINAL (2026-07-22) + +Format komplett verstanden: +- .BOB-Eintraege (32x): kein Tag-Slot, Header direkt per Pfad-Praefix-Suche + gefunden ("H:\\WIWA\\ENGINE\\GAMEDATA\\"), Header = Fundstelle-4. +- Alle Nicht-BOB-Eintraege (PCC/MAP/ARE/ICO/SAM/TFX, 146x aus APPEND.LST, + PLUS 3 weitere System-Dateien ohne APPEND.LST-Eintrag): Tag-Slot + [1-Byte-Namenslaenge][Dateiname][Fuellmuell bis 256 Byte], danach + [4-Byte-LE-Laenge][Rohdaten]. + +WICHTIGER FUND: APPEND.LST listet nur die 178 Spiel-Assets. PCKELL.PRE +enthaelt zusaetzlich, im GLEICHEN Tag-Format, direkt im Anschluss an den +letzten APPEND.LST-Eintrag (TITEL2.SAM), noch 3 System-/Runtime-Dateien: +DPMI16BI.OVL, RTM.EXE, START.EXE (die DOS-Extender-Runtime -- macht Sinn, +das ist ein self-contained Redistributable). Der letzte dieser 3 Eintraege +endet EXAKT auf EOF (0x238966) -- damit ist das Format zu 100% verifiziert, +keine Bytes bleiben unerklaert. + +Ergebnis: 178 (APPEND.LST) + 3 (System) = 181 Dateien total. +""" +import struct +import os + +RAW = "/home/aria/kellogg_remake/raw/PCKELL.PRE" +APPEND_LST = "/home/aria/kellogg_remake/raw/APPEND.LST" +OUT_DIR = "/home/aria/kellogg_remake/extracted_pre" + +with open(RAW, "rb") as f: + data = f.read() +with open(APPEND_LST) as f: + names = [l.strip() for l in f if l.strip()] + +# die 3 unlisted System-Dateien, empirisch gefunden direkt im Anschluss +EXTRA_NAMES = ["DPMI16BI.OVL", "RTM.EXE", "START.EXE"] + +PATH_PREFIX = b"H:\\WIWA\\ENGINE\\GAMEDATA\\" +N = len(data) + +pos = 0x100 +entries = [] +all_names = names + EXTRA_NAMES + +for i, name in enumerate(all_names): + is_bob = name.upper().endswith(".BOB") + if is_bob: + marker = PATH_PREFIX + name.encode("ascii") + p = data.find(marker, pos) + if p == -1: + print(f"FEHLER: Pfad fuer #{i} ({name}) nicht gefunden ab {pos:#x}") + break + header_start = p - 4 + length = struct.unpack_from(" N: + print(f"FEHLER: Datenende {data_end:#x} > Dateigroesse bei #{i} ({name}) length={length}") + break + entries.append((name, header_start, length, data_start, data_end, path)) + pos = data_end + +print(f"{len(entries)} von {len(all_names)} Eintraegen gefunden.") +if entries: + print(f"Letztes Datenende: {entries[-1][4]:#x} von {N:#x} (Match: {entries[-1][4] == N})") + +mism = sum(1 for name, hs, length, ds, de, path in entries + if path is not None and path.split("\\")[-1].upper() != name.upper()) +print(f"BOB Pfad-Mismatches: {mism}") + +if len(entries) == len(all_names) and entries[-1][4] == N and mism == 0: + os.makedirs(OUT_DIR, exist_ok=True) + for name, hs, length, ds, de, path in entries: + with open(os.path.join(OUT_DIR, name), "wb") as out: + out.write(data[ds:de]) + print(f">>> ERFOLG: {len(entries)} Dateien geschrieben nach {OUT_DIR}") + import collections + ext_count = collections.Counter(n.split(".")[-1].upper() for n, *_ in entries) + print("Typen:", dict(ext_count)) +else: + print(">>> Unvollstaendig.") + for e in entries[-5:]: + print(" ", e[0], hex(e[1]), e[2])