2143 lines
121 KiB
Markdown
2143 lines
121 KiB
Markdown
# 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.
|
|
|
|
## Sound (TFMX) geloest + in Intro-Sequenz eingebaut (2026-07-22, spaeter Abend)
|
|
|
|
**`tools/tfmx_player/` (MIT-lizenziert, Copyright Peter Fors -- LICENSE liegt
|
|
bei) ist ein fertiger TFMX-Replayer in C.** Anders als beim C#-Referenzprojekt
|
|
fuer PCX/BOB/MAP/ICO (dort kein LICENSE, daher nur als Format-Wissen genutzt
|
|
und in eigenem Python neu geschrieben) erlaubt die MIT-Lizenz hier direkte
|
|
Nutzung/Einbindung -- deshalb kein Python-Reimplement des TFMX-Formats
|
|
(waere bei ~95KB Player-Logik in `tfmx.h` ein Mehrtage-Projekt ohne Mehrwert
|
|
gegenueber der fertigen, korrekt lizenzierten Loesung).
|
|
|
|
**Build:** `tools/tfmx_player/build.sh` kompiliert `render_tfmx`
|
|
(`gcc render_tfmx.c -lm`) -- ein CLI-Tool `render_tfmx <in.tfx> <in.sam>
|
|
<out.wav> [sekunden]`, das ein TFMX-Modul zu 16-bit/44100Hz-Stereo-WAV
|
|
rendert. **Alle 3 Musikstuecke (`TITEL`, `TITEL2`, `ONGAME2`) erfolgreich
|
|
gerendert und angehoert (nicht nur Byte-Statistik!)** -- echte, hoerbare
|
|
Chiptune-Musik, kein Rauschen/Stille. Vorschau-MP3s lagen kurz unter
|
|
`/shared/uploads/aria_tfmx_*.mp3` fuer Stefan zum Reinhoeren.
|
|
|
|
**Einbau in `tools/intro_sequence.py`:** neuer Wrapper `tools/tfmx_audio.py`
|
|
extrahiert TFX+SAM per `kellogg_formats.DATContainer` aus `PCKELL.DAT`,
|
|
rendert einmalig per Subprocess zu WAV (gecacht unter
|
|
`KELLOGG_AUDIO_CACHE`/`~/kellogg_remake/audio_cache/`, NICHT committed --
|
|
ist Original-Musikmaterial wie `raw/`). `intro_sequence.py` initialisiert
|
|
jetzt `pygame.mixer`, startet beim Erreichen des Kellogg's-Logos die
|
|
`TITEL`-Musik geloopt (Annahme: durchgehende Titelmusik ueber Logo+Titelbild
|
|
+Karte -- noch nicht per Timing-Vergleich gegen DOSBox-Ton verifiziert, da
|
|
DOSBox bisher nur im Nosound-Modus lief; plausibelste v1-Annahme). Mixer-
|
|
Init ist defensiv (try/except) -- auf `aria-wohnung` (keine Soundkarte im
|
|
Container/VM) laeuft die Sequenz jetzt nachweislich sauber STUMM weiter
|
|
(getestet), mit `SDL_AUDIODRIVER=dummy` laeuft der komplette Codepfad
|
|
inklusive Musik-Rendering fehlerfrei durch (ebenfalls getestet) -- auf
|
|
Stefans Rechner mit echter Soundkarte sollte die Musik beim Ausfuehren
|
|
tatsaechlich zu hoeren sein.
|
|
|
|
**Committed:** `tools/tfmx_player/` (Quellcode + LICENSE, NICHT das
|
|
kompilierte Binary -- Build-Artefakt, per `.gitignore` draussen wie
|
|
`audio_cache/`), `tools/tfmx_audio.py`, aktualisiertes
|
|
`tools/intro_sequence.py`.
|
|
|
|
**Noch offen (niedrige Prioritaet):**
|
|
- `TITEL2`/`ONGAME2` sind noch nicht eingebunden -- vermutlich `TITEL2` fuer
|
|
die Weltkarte und `ONGAME2` fuers eigentliche Level-Gameplay, aber welche
|
|
Musik wo genau einsetzt ist nur eine Annahme (Namen sprechen dafuer,
|
|
nicht per Referenz/Timing-Vergleich verifiziert).
|
|
- Timing/Verifikation der Titelmusik-Ein-/Aussatzpunkte gegen das Original
|
|
(DOSBox bisher stumm getestet) steht noch aus.
|
|
- Rauser-Layout und Fade/Wipe-Feinjustierung (siehe vorherige Notiz) weiter
|
|
offen, niedrige Prioritaet.
|
|
|
|
### Naechste Schritte (Prioritaet, Stand spaeter Abend 22.07.)
|
|
1. `TITEL2`/`ONGAME2` an Karte/Gameplay-Musik zuordnen und einbinden, sobald
|
|
diese Screens/Modi existieren.
|
|
2. Danach: Uebergang von Intro zu echtem Gameplay -- Tony-Bewegung auf
|
|
Level W1L0 als naechster grosser Meilenstein (MAP+ICO+BOB+jetzt auch
|
|
Sound-Infrastruktur sind fertig).
|
|
3. ARE/Kollisionsformat klaeren, wenn Spiellogik es braucht.
|
|
|
|
Laeuft selbstaendig weiter, keine Rueckfrage noetig.
|
|
|
|
## Pfade relativ gemacht + Rauser/Titelbild-Korrektur (22.07.2026, Nacht)
|
|
|
|
Stefan meldete zwei Dinge: (1) alle Tools haben `/home/aria/kellogg_remake/...`
|
|
hardcodiert -- muss relativ zum Projektordner sein; (2) 6 Screenshots als
|
|
Beleg fuer Bild-Bugs (Rauser zu gross, Titelbild "gestaucht", Original hat
|
|
Scanlines die verschwinden). **Wichtig: von den 6 Screenshots ist wegen eines
|
|
Upload-Bugs (alle 6 landeten unter demselben Dateinamen und ueberschrieben
|
|
sich gegenseitig) nur der LETZTE erhalten geblieben** -- ich hab Stefan das
|
|
gemeldet und ihn gebeten, die anderen 5 bei Bedarf nochmal zu schicken. Statt
|
|
zu raten hab ich stattdessen selbst frische DOSBox-Referenzaufnahmen gemacht
|
|
(Xvfb + `import -window root`, 0.12s-Intervall) und daraus die echten Werte
|
|
gemessen -- Details unten.
|
|
|
|
**1) Pfade:** `intro_sequence.py`, `tfmx_audio.py`, `render_assets.py`,
|
|
`dat_extract.py` hatten `/home/aria/kellogg_remake/...` fest im Code. Jetzt
|
|
ueberall `PROJECT_ROOT = dirname(dirname(abspath(__file__)))` + optionales
|
|
ENV-Override (`KELLOGG_DAT`, `KELLOGG_AUDIO_CACHE`, `KELLOGG_RENDER_OUT`,
|
|
`KELLOGG_EXTRACT_OUT`). Laeuft jetzt von jedem Pfad aus (VM, Container,
|
|
woanders geklont).
|
|
|
|
**2) Rauser -- per Pixelvermessung neu gebaut:**
|
|
- Echte Groesse per Bounding-Box-Analyse gegen eine frische DOSBox-Aufnahme
|
|
gemessen: das komplette Rauser-Logo (RAUSER1+2+3 zusammen) ist im Original
|
|
nur ca. 105x40px auf einer 320x240-Leinwand -- mein v1-Code hat die
|
|
PCC-Assets 1:1 nativ gezeichnet (182x46 fuer RAUSER1 allein!), viel zu
|
|
gross. **Alle drei Rauser-Assets werden jetzt bei 0.5x Nativgroesse
|
|
gezeichnet** (`ASSET_DISPLAY_SCALE`).
|
|
- Hintergrund war in v1 WEISS die ganze Zeit -- tatsaechlich: WEISS waehrend
|
|
Slide-in+Halten, dann kurzer Fade zu GRAU (73,73,73), dann Grau halten,
|
|
dann Schwarzblende (bestehende Pause).
|
|
- **Neu: Slide-in-Animation.** Per Screenshot-Serie entdeckt: RAUSER1
|
|
("RAUSER"-Box) faehrt von LINKS ins Bild, RAUSER3 (blaue Box mit "!")
|
|
faehrt von OBEN rein, RAUSER2 ("ADVERTAINMENT") steht von Anfang an fest.
|
|
Nachgebaut mit smoothstep-Ease ueber `RAUSER_SLIDE_SECONDS=0.9s`.
|
|
- **Neu: Sound-Sting.** `TITEL2.TFX/.SAM` (das kuerzeste der 3 Musikstuecke,
|
|
724 Byte TFX) ist kein Loop-Track, sondern ein kurzer ~1s-Jingle (RMS-
|
|
Analyse zeigt: Burst 0-0.9s, dann Stille, dann Wiederholung -- typisch fuer
|
|
ein kurzes Sample, das die Tracker-Engine in einer Schleife rendert). Wird
|
|
jetzt exakt beim Erreichen der Endposition (Slide-in fertig) EINMAL
|
|
abgespielt (`pygame.mixer.Sound`, nicht geloopt).
|
|
|
|
**3) Titelbild -- KORREKTUR einer fruehen Fehlannahme (das war der Bug hinter
|
|
Stefans "gestaucht"-Meldung):**
|
|
- v1 hat die 4 Quadranten KELL256A/B/C/D (je 160x240 PCC-nativ) 1:1 zu einem
|
|
320x**480**-Bild gestapelt (A|B oben, C|D unten) und das komplett 480 hoch
|
|
angezeigt. Das war falsch.
|
|
- Per Pixel-Rekonstruktion gegen eine echte DOSBox-Aufnahme verifiziert
|
|
(mehrere Hypothesen durchprobiert, mit numpy MSE + visuellem Abgleich):
|
|
**die 4 Quadranten werden je auf HALBE Hoehe (160x120) skaliert** (Breite
|
|
bleibt nativ, NUR die Hoehe wird halbiert -- anders als beim Rauser-Fix,
|
|
wo beide Achsen gleichmaessig skaliert werden!) und im 2x2-Raster
|
|
angeordnet: A oben-links, B oben-rechts, C unten-links, D unten-rechts ->
|
|
ergibt ein korrektes 320x240-Bild. Screenshot-Vergleich (Rekonstruktion
|
|
vs. echte DOSBox-Aufnahme) war praktisch deckungsgleich.
|
|
ACHTUNG fuer kuenftige Aenderungen: bei den Rauser-Assets ist die
|
|
0.5x-Skalierung GLEICHMAESSIG (Breite+Hoehe), bei den Titelbild-Quadranten
|
|
ist es NUR die Hoehe -- zwei verschiedene Funktionen im Code
|
|
(`pcc_surface_scaled` vs. `pcc_surface_half_height`), nicht verwechseln.
|
|
- **Neu entdeckter Scanline-Effekt** (das ist genau Stefans "Screenshot 4/5/6"
|
|
-Beobachtung): waehrend die untere Bildhaelfte einwaechst, ist sie zuerst
|
|
komplett entsaettigt (graustichig) UND mit sichtbaren horizontalen
|
|
Scanlines ueberzogen -- das loest sich in einer zweiten Animationsphase zu
|
|
vollen Farben auf, bis das Bild komplett scharf ist. Per 0.12s-Screenshot-
|
|
Serie ueber die komplette Wipe-Animation hinweg entdeckt und nachgebaut
|
|
(`_scanline_desaturate()`, per numpy: Graustufen-Mix + jede zweite Zeile
|
|
abgedunkelt, Intensitaet faedet ueber die zweite Haelfte der Wipe-Dauer von
|
|
1.0 auf 0.0).
|
|
- Reveal-Mechanik selbst (oben waechst 0->120 von oben, unten waechst 0->120
|
|
von unten, treffen sich in der Mitte) war in der urspruenglichen
|
|
Beobachtung schon richtig -- nur die falsche 480px-Endgroesse und der
|
|
fehlende Scanline-Effekt waren der Bug.
|
|
|
|
**Verifiziert:** eigene DOSBox-Referenzaufnahme (Xvfb, 0.12s-Serie) gegen den
|
|
neu gebauten `intro_sequence.py`-Output verglichen -- Rauser-Slide-in, Rauser-
|
|
Groesse/Farben und Titelbild (inkl. Scanline-Phase) sehen jetzt sehr nah am
|
|
Original aus. Screenshots liegen als Beleg bei:
|
|
|
|
[FILE: /shared/uploads/aria_rauser_fixed.png] (Rauser, neu: klein, weiss, Slide-in-Mitte)
|
|
[FILE: /shared/uploads/aria_title_wipe_scanline_fixed.png] (Titelbild-Wipe MIT Scanline-Effekt)
|
|
[FILE: /shared/uploads/aria_title_final_fixed.png] (Titelbild komplett, korrekt 320x240 statt 320x480)
|
|
|
|
**Noch offen / bewusste Vereinfachungen:**
|
|
- Die feine Choreografie von RAUSER3 (slidet vermutlich als "!" und blaue Box
|
|
getrennt, siehe Screenshot-Beobachtung) wurde vereinfacht zu EINEM Element,
|
|
das von oben reinfaehrt -- sieht in der Praxis schon sehr nah dran aus,
|
|
waere aber bei Bedarf noch weiter verfeinerbar.
|
|
- Kleiner kosmetischer Rest: RAUSER2/RAUSER3 haben weissen Hintergrund IN
|
|
ihrer eigenen PCC-Bounding-Box (kein Alpha-Kanal). Auf weiss (waehrend
|
|
Slide-in+Halten) faellt das nicht auf, nach dem Fade zu Grau sieht man
|
|
einen schwachen weissen Kasten drumrum. Versuch mit `set_colorkey()`
|
|
wieder verworfen (hat auch die weissen BUCHSTABEN in RAUSER1 durchsichtig
|
|
gemacht -- schlimmer als der Kasten). Braucht eine echte Alpha-Maske pro
|
|
Asset, low priority.
|
|
- Der Scanline-Clear-Effekt ist als gleichmaessige Intensitaet ueber die
|
|
ganze untere Haelfte umgesetzt, nicht als praezise von-der-Mitte-nach-
|
|
aussen wandernde Grenze (im Original loest sich ein duenner Reststreifen
|
|
am unteren Bildrand als letztes auf) -- optische Wirkung ist aber schon
|
|
sehr aehnlich.
|
|
- VM-Testverzeichnisse (`boot_frames2/`, `intro_check_frames/`,
|
|
`title_check_frames/`) nach der Analyse wieder aufgeraeumt, nicht im Repo.
|
|
|
|
Laeuft selbstaendig weiter, keine Rueckfrage noetig.
|
|
|
|
## 22.07.2026, spaeter Abend (2): drei Feedback-Bugs von Stefan gefixt
|
|
|
|
Stefan hatte nach dem letzten Pfade-relativ/Rauser/Titelbild-Fix drei neue
|
|
Beobachtungen gemeldet, alle drei bestaetigt und behoben:
|
|
|
|
**1. "Rauser-Text fadet nicht mit aus, bleibt hart umrandet stehen."**
|
|
Ursache endlich richtig verstanden (der oben als "kosmetischer Rest, low
|
|
priority" dokumentierte Kasten): RAUSER1/2/3.PCC haben keinen Alphakanal, ihr
|
|
papierweisser Hintergrund sitzt als hartes Rechteck um die Box-Grafik. Fix:
|
|
neue Funktion `make_border_bg_transparent()` in `intro_sequence.py` -- Flood-
|
|
Fill vom Bildrand aus ueber alle "papierweissen" Pixel (Schwelle 235/255 je
|
|
Kanal), NUR die vom Rand aus zusammenhaengende Flaeche wird transparent.
|
|
Isolierte weisse Pixel MITTEN im Motiv (z.B. die weissen Buchstaben in
|
|
RAUSER1) beruehren den Rand nicht und bleiben unangetastet -- genau das
|
|
Problem, an dem der fruehere `set_colorkey()`-Versuch gescheitert war.
|
|
Verifiziert per direktem Pixel-Test (nicht nur behauptet): Eckpixel neben der
|
|
Box liegt nach dem Fix exakt bei RAUSER_GREY (73,73,73) statt weiss, und im
|
|
Bild bleiben klar sichtbare, fast voll opake Buchstaben-Pixel (Alpha bis 254)
|
|
erhalten. Screenshot der Grau-Phase zum Beleg:
|
|
[FILE: /shared/uploads/aria_rauser_fade_grey_check.png]
|
|
|
|
**2. "Musik ist zu kurz, da fehlt der Rest" + Cache-Bug gefunden.**
|
|
Zwei uebereinanderliegende Ursachen:
|
|
a) `render_wav()` cached per Dateiname OHNE den `seconds`-Parameter zu
|
|
beruecksichtigen -- ein alter Test-Render (TITEL mit 8s, TITEL2 mit 15s
|
|
aus einer frueheren Debug-Session) blieb im `audio_cache/` liegen und
|
|
wurde bei jedem Aufruf stillschweigend weiterverwendet, egal welche
|
|
`seconds` der Aufrufer diesmal wollte.
|
|
b) selbst ein frischer Render haette bei den frueher verwendeten festen
|
|
Werten (TITEL: 60s) abgeschnitten -- **TITEL ist tatsaechlich ~109s
|
|
lang, ONGAME2 ~123s**, beides deutlich laenger als angenommen.
|
|
Echter Fix in `render_tfmx.c`: statt stur `seconds` lang zu rendern, wird
|
|
jetzt in kleinen 64-Frame-Haeppchen gerendert und tfmx.h's eigenes
|
|
`real_song_end`-Flag beobachtet (wird pro Tick gesetzt, sobald die
|
|
Track-Sequenz einmal komplett durchgelaufen ist und intern neu startet) --
|
|
sobald es feuert, ist GENAU eine vollstaendige natuerliche Song-Schleife im
|
|
Kasten, egal wie lang das Stueck wirklich ist. `seconds`/`max_seconds` ist
|
|
jetzt nur noch eine Sicherheits-Obergrenze (Default 180s, grosszuegig ueber
|
|
allen 3 bekannten Stuecken). Getestet und verifiziert:
|
|
- TITEL: 109.44s (natuerliches Ende erkannt)
|
|
- TITEL2 (Rauser-Sting): 2.04s (natuerliches Ende erkannt)
|
|
- ONGAME2: 122.88s (natuerliches Ende erkannt)
|
|
Alte falschen Cache-Dateien geloescht, mit dem gefixten Tool neu gerendert
|
|
und die Laengen direkt per `pygame.mixer.Sound(...).get_length()` verifiziert
|
|
(nicht nur die WAV-Header-Bytes ausgerechnet).
|
|
|
|
**3. "Bei Factor5 gibt's auch noch ne Melodie, solange das Lied ist Factor5
|
|
anzeigen und dann zum Kellogg's-praesentiert."**
|
|
`ONGAME2` war bis jetzt der einzige der 3 TFMX-Tracks ohne zugeordneten
|
|
Screen (TITEL2 = Rauser-Sting, TITEL = Kellogg's-Logo/Titelbild-Loop) --
|
|
genau das ist offenbar die Factor5-Melodie. `run_once()` in
|
|
`intro_sequence.py` spielt ONGAME2 jetzt beim Erscheinen des Factor5-Logos
|
|
einmal komplett ab und haelt den Screen exakt so lange (`sound.get_length()`,
|
|
~123s statt der alten festen 3.0s), bevor es zur schwarzen Pause + Kellogg's-
|
|
Logo weitergeht.
|
|
|
|
**Alle 3 Fixes verifiziert, nicht nur behauptet:**
|
|
- Rauser-Alpha-Fix: direkter Pixel-Test + Screenshot (oben verlinkt).
|
|
- Musik-Laengen: `render_tfmx`-Stderr-Ausgabe UND `pygame.mixer.Sound.get_length()`
|
|
geben identische Werte.
|
|
- Kompletter Smoke-Test (`xvfb-run python3 tools/intro_sequence.py --once`)
|
|
laeuft ohne Traceback durch (headless ohne Audio-Geraet, laeuft dann
|
|
erwartungsgemaess stumm mit Fallback-Dauern).
|
|
|
|
Committet + gepusht. Naechster Schritt weiterhin offen: echtes Gameplay
|
|
(Tony auf `W1L0` bewegen).
|
|
|
|
## 22.07.2026, Nacht (3): Rauser-Aufloesung wirklich gefixt + Factor5-Sound korrigiert (Multi-Song-Fund)
|
|
|
|
Stefan hatte zwei weitere Punkte gemeldet: "Rauser-Intro-Aufloesung ist immer
|
|
noch schlecht" (mit Referenz-Screenshot: `RAUSER!`-Logo klein, mittig, viel
|
|
weisser Rand drumrum) und "beim Factor5 hast du einen Level-Sound genommen,
|
|
der echte Factor5-Sound ist ein kurzes Brausen, nur wenig laenger als der
|
|
Rauser-Sound, Bild ca. 5s eingeblendet".
|
|
|
|
**Wichtiger Fund beim Reinschauen:** Zwischen den Chat-Nachrichten war im
|
|
Hintergrund (autonomer Weiterarbeits-Timer) schon ein erster Loesungsversuch
|
|
fuer beides auf der VM entstanden, aber weder ins Git-Repo synced noch
|
|
committet/gepusht -- der Chat-Verlauf hatte den Stand nicht wiedergegeben.
|
|
Ich hab den VM-Stand zuerst gegen den Repo-Stand geprueft (`diff`), den fuer
|
|
Factor5 bereits korrekten Teil uebernommen, und den Rauser-Aufloesungs-Fix
|
|
selbst nochmal nachgerechnet, weil er in der ersten Fassung (native 1.0x
|
|
Groesse) tatsaechlich einen NEUEN Bug enthielt.
|
|
|
|
**1) Rauser-Aufloesung -- diesmal wirklich pixelvermessen statt geraten:**
|
|
Stefans Referenz-Screenshot per Bounding-Box analysiert (PIL, Python auf der
|
|
VM): das Logo nimmt dort nur **34.5% der Bildbreite / 16.6% der Bildhoehe**
|
|
ein (223x83px auf einem 646x500px-Screenshot). Das widerlegt die vorige
|
|
Annahme "native Groesse (ASSET_DISPLAY_SCALE=1.0) ist richtig" klar -- bei
|
|
nativer Groesse waeren RAUSER1+RAUSER3 zusammen 198px breit auf einer
|
|
320px-Leinwand (62%), fast doppelt so viel wie die Referenz zeigt. Die
|
|
URSPRUENGLICHE 0.5x-Skalierung war groessenmaessig also die ganze Zeit
|
|
richtig -- der eigentliche Bug war die Skalierungs-METHODE:
|
|
`pygame.transform.smoothscale()` ist bilinear und verwaescht harte
|
|
Pixel-Kanten von Pixel-Art beim Verkleinern sichtbar. Fix: `smoothscale()`
|
|
durch `pygame.transform.scale()` ersetzt (Nearest-Neighbor, kein
|
|
Weichzeichnen) in `Assets.pcc_surface_scaled()` UND `pcc_surface_half_height()`
|
|
(Titelbild-Quadranten, gleiches Prinzip), `ASSET_DISPLAY_SCALE` bleibt 0.5.
|
|
Verifiziert per eigener Bounding-Box-Nachmessung des neuen Renders: **33.0%
|
|
Breite / 13.6% Hoehe** -- nah an Stefans Referenz (34.5%/16.6%), klar besser
|
|
als der 62%-Fehlgriff der vorigen (native) Version. Frisch gerenderter
|
|
Vergleichs-Screenshot:
|
|
[FILE: /shared/uploads/aria_rauser_scale05_check.png]
|
|
|
|
**2) Factor5-Sound -- Multi-Song-Fund geklaert die Zuordnung:**
|
|
Ein einzelnes TFX-Modul kann laut `tfmx.h` (`v_songs[]`/`v_songs_count`)
|
|
MEHRERE Songs buendeln, ausgewaehlt per `start_song`-Index -- das erklaert
|
|
Stefans Vermutung "das Spiel hat noch wesentlich mehr Lieder". Debug-Rendering
|
|
aller Songs in allen 3 Modulen ergab:
|
|
- `TITEL.TFX` -> 3 Songs (song0/1 lang >15s, song2 ~8.0s)
|
|
- `TITEL2.TFX` -> 2 Songs (song0 = 2.04s, song1 = 2.40s)
|
|
- `ONGAME2.TFX` -> 14(!) Songs (mehrere >15s-Tracks, vermutlich echte
|
|
Level-/Gameplay-Musik -- song3/11/12 sehr kurz 0.16-1.36s, song2/13
|
|
~10.3s; noch nicht im Detail zugeordnet, relevant fuer spaetere
|
|
Gameplay-Musik)
|
|
Die vorige Zuordnung (ONGAME2 komplett = "Factor5-Melodie") war schlicht
|
|
falsch -- vermutlich echte Level-Musik, nicht zum Studio-Logo passend (daher
|
|
Stefans "Level-Sound"-Eindruck). TITEL2-Song1 (2.40s) passt dagegen exakt zu
|
|
"nur ein bisschen laenger als der Rauser-Sound" (Rauser-Sting = TITEL2-Song0
|
|
= 2.04s, Differenz nur 0.36s). `tools/tfmx_audio.py` bekam dafuer einen
|
|
optionalen `song_index`-Parameter (durchgereicht an `render_tfmx` als
|
|
5. CLI-Arg), `run_once()` in `intro_sequence.py` spielt jetzt TITEL2-Song1
|
|
beim Factor5-Logo ab, Anzeigedauer ist fest auf `FACTOR5_HOLD_SECONDS = 5.0`
|
|
gesetzt (statt an eine -- falsche -- Songlaenge gekoppelt).
|
|
Verifiziert: `TITEL2.wav` (Song0) 2.04s, `TITEL2_song1.wav` (Song1) 2.40s,
|
|
beide mit gesunder Amplitude (kein Stille-Bug), unterschiedliche Dateigroesse
|
|
(89984 vs. 105856 Samples -- also wirklich unterschiedlicher Inhalt, keine
|
|
zufaellige Doublette).
|
|
|
|
**Ehrlicher Vorbehalt (wichtig):** Ich kann Audio nicht selbst abhoeren --
|
|
die Zuordnung TITEL2-Song1 = "Brausen" ist eine Indizien-Schlussfolgerung aus
|
|
der Songlaenge (passt sehr gut zu Stefans Beschreibung), NICHT durch
|
|
Reinhoeren verifiziert. Falls es beim echten Testen doch nicht wie ein
|
|
Brausen klingt: melden, dann probieren wir als naechste Kandidaten TITEL-Song2
|
|
(~8.0s) oder einen der kurzen ONGAME2-Songs (3/11/12).
|
|
|
|
Beide Fixes committet + gepusht. Naechster Schritt weiterhin offen: echtes
|
|
Gameplay (Tony auf `W1L0` bewegen).
|
|
|
|
## 23.07.2026 -- Hang-Bug gefixt + alle 19 TFMX-Songs fuer Stefan gerendert
|
|
|
|
**1) Hang-Bug (Stefans Meldung "nur noch ein schwarzes Bild, verschiebe ich
|
|
das Fenster wird der Desktop reingerendert, das Programm haengt"): real,
|
|
gefunden, gefixt, verifiziert.** Ursache: `tfmx_audio.render_wav()` rief den
|
|
TFMX-Renderer als blockierenden `subprocess.run()` auf -- bei einem frischen,
|
|
ungecachten Song (v.a. TITEL, ~109s Musik) dauert das reproduzierbar ~14s,
|
|
waehrend derer die pygame-Eventloop NICHT lief. Das OS stuft ein Fenster
|
|
ohne Event-Pumping als "nicht reagierend" ein -- exakt Stefans beschriebenes
|
|
Bild (schwarz eingefroren, Desktop blitzt beim Verschieben durch).
|
|
Fix: `preload_all_audio()` rendert jetzt alle 3 benoetigten Songs (Rauser-
|
|
Sting, Factor5-Sound, Titelmusik) EINMALIG vor der eigentlichen Sequenz, per
|
|
Hintergrund-Thread + responsivem "Lade..."-Bildschirm
|
|
(`render_audio_with_loading()`). Danach greifen alle `run_once()`-Durchlaeufe
|
|
nur noch auf fertige WAV-Pfade zu, nie mehr Live-Rendering im Hauptloop.
|
|
Verifiziert per Xvfb-Testlauf (`SDL_AUDIODRIVER=dummy`, `--once`): laeuft
|
|
jetzt exit-code-0 sauber durch, kein Haengen mehr.
|
|
Committet+gepusht (`73b887e`). Nebenbei `__pycache__/` ins `.gitignore`
|
|
aufgenommen (`8509cbc`).
|
|
|
|
**2) Alle 19 TFMX-Songs gerendert, als MP3-Zip an Stefan uebergeben (NICHT
|
|
ins Git-Repo, gleiche Begruendung wie bei raw/PCKELL.DAT -- ist Original-
|
|
Spielmaterial/Musik, nur als Download fuer den Privatgebrauch, siehe
|
|
`tfmx_audio.py`-Docstring und `.gitignore`):**
|
|
- `TITEL.TFX`: song0 (=`TITEL.mp3`, 109s, aktuell die Titelmusik),
|
|
song1 (109s, bisher ungenutzt), song2 (~8s, bisher ungenutzt)
|
|
- `TITEL2.TFX`: song0 (=Rauser-Sting, 2.04s), song1 (=aktuell als
|
|
Factor5-Sound eingebaut, 2.40s -- NICHT durch Reinhoeren verifiziert,
|
|
nur aus der Songlaenge geschlossen, siehe Vorbehalt vom 22.07.)
|
|
- `ONGAME2.TFX`: 14 Songs (song0-13), vermutlich echte Level-/Gameplay-
|
|
Musik, noch keinem Screen/Level zugeordnet
|
|
19 WAVs -> MP3 (ffmpeg, libmp3lame, konvertiert um die Downloadgroesse von
|
|
~300MB WAV auf ~59MB MP3 zu druecken) -> Zip, an Stefan uebergeben.
|
|
Dateinamen im Zip = `<TFX-Name>[_song<N>].mp3` (song0/Default ohne Suffix).
|
|
**Stefans Aufgabe:** reinhoeren und mir sagen, welche Datei WIRKLICH nach
|
|
Factor5-Brausen klingt -- falls es NICHT `TITEL2_song1.mp3` ist, dann in
|
|
`intro_sequence.py`/`run_once()` den `audio_paths.get(('TITEL2', 1))`-Call
|
|
auf die richtige Datei/song_index umstellen (Kandidaten laut Laenge:
|
|
`TITEL_song2.mp3` ~8s, oder ein kurzer ONGAME2-Song).
|
|
|
|
Naechster Schritt weiterhin offen: echtes Gameplay (Tony auf `W1L0` bewegen).
|
|
Sobald Stefan den richtigen Factor5-Song bestaetigt hat, kurzer Fix, dann
|
|
weiter zu Gameplay.
|
|
|
|
## Stand 23.07.2026, vormittags -- Factor5-Sound bestaetigt + Repo-Hygiene-Fund
|
|
|
|
**1) Factor5-Sound ist bestaetigt richtig.** Stefan hat sich durch die
|
|
Hoerproben gehoert und explizit `TITEL2_song1.wav` als den richtigen
|
|
Factor5-"Brausen"-Sound zurueckgemeldet -- das ist exakt die Datei, die seit
|
|
`af2ead1` schon eingebaut ist (`audio_paths.get(('TITEL2', 1))` in
|
|
`run_once()`). Kein Code-Aenderung noetig, nur der offene Vorbehalt von
|
|
22.07. ("nicht durch Reinhoeren verifiziert") ist jetzt erledigt.
|
|
|
|
**2) Repo-Hygiene-Bug gefunden + gefixt (kein Stefan-Report, selbst
|
|
entdeckt beim Nachschauen):** `tools/tfmx_player/render_tfmx.c` war in
|
|
`origin/master` NICHT auf dem aktuellen Stand -- das Song-Index-Feature
|
|
(noetig fuer genau obigen Factor5-Fix, TITEL2 Song 1 statt Song 0) existierte
|
|
nur lokal auf der VM (`/home/aria/kellogg_remake`, gebaut, aber nie
|
|
committet), nicht im Repo selbst. Ein frischer `git clone` + `build.sh`
|
|
haette also einen Binary OHNE Song-Auswahl erzeugt -- jeder
|
|
`render_wav(..., song_index=N)`-Call waere stillschweigend auf Song 0
|
|
zurueckgefallen (kein Crash, aber hörbar falscher Sound). Genau die Art
|
|
1:1-Port-Bruch, die Stefan nicht will.
|
|
|
|
Ursache: parallel zur Session ist ein zweiter Git-Checkout unter `/tmp`
|
|
(tmpfs!) entstanden und dort unabhaengig weitergearbeitet worden, ohne vorher
|
|
zu fetchen -- Historie ist auseinandergelaufen (zwei verschiedene Commits fuer
|
|
denselben Hang-Fix). Nach Abgleich: `/home/aria/kellogg_remake` (die
|
|
tatsaechliche Arbeitskopie) war fuer ALLE Dateien ausser dieser einen C-Datei
|
|
schon 1:1 identisch mit `origin/master`. Fix: `render_tfmx.c` nachgezogen und
|
|
committet (`a077dce`), der veraltete `/tmp`-Checkout mit den ueberholten
|
|
Doppel-Commits verworfen (kein Datenverlust, deren Inhalt war ohnehin ein
|
|
aelterer Zwischenstand als das, was schon auf `origin/master` lag).
|
|
|
|
**Lehre / Infra-Aenderung:** der Arbeits-Git-Checkout fuer Commits/Pushes
|
|
liegt jetzt dauerhaft unter `/home/aria/tony-remake-git` (statt `/tmp`,
|
|
das ist RAM-tmpfs und wird bei jedem VM-Neustart geleert -- genau DAS hat
|
|
den Doppel-Checkout ueberhaupt erst ermoeglicht). Kuenftige Sessions: dort
|
|
weiterarbeiten, IMMER zuerst `git fetch && git status` gegen `origin/master`
|
|
pruefen bevor neue Commits drauf, um erneutes Auseinanderlaufen zu vermeiden.
|
|
|
|
**Naechster Schritt:** Der Factor5-Sound-Vorbehalt ist jetzt erledigt, die
|
|
Intro-Sequenz ist damit inhaltlich fertig (Rauser -> Factor5 -> Kellogg's-Logo
|
|
mit Vorhang+Scanlines -> Titelbild, alles mit korrektem Sound, freeze-frei).
|
|
Zwei Baustellen bleiben offen, beide von Stefan noch nicht explizit
|
|
beauftragt:
|
|
1. Der von Stefan gemeldete schwarze-Screen/Fenster-Haenger nach dem
|
|
Rauser-Intro sollte jetzt behoben sein (Hang-Fix oben) -- noch nicht von
|
|
Stefan nochmal getestet/bestaetigt.
|
|
2. Der naechste grosse inhaltliche Meilenstein bleibt unveraendert: echtes
|
|
Gameplay, Tony auf Level `W1L0` steuerbar machen (Map/Sprites/Kollision
|
|
sind alle schon fertig extrahiert, es fehlt nur noch die Spiellogik/der
|
|
eigentliche Python-Spiel-Loop).
|
|
|
|
## 24.07.2026 -- Aufraeumen: Duplikate entfernt, Soundfiles ins Repo
|
|
|
|
Stefan wollte einen Ueberblick + die im Projektordner angesammelten Duplikate
|
|
bereinigen. Bestandsaufnahme ergab drei redundante Brocken (~327 MB, alle nur
|
|
lokal, nicht in git):
|
|
|
|
- **`aria_kelloggs_extrahierte_assets/` (+ `.zip`) -- geloescht.** War ein
|
|
VERALTETER Snapshot-Export von `tools/`/`png_out/`/`render_out/`/
|
|
`extracted_pre/`: png_out byte-identisch, aber die Tools alt (z.B.
|
|
`intro_sequence.py` 11 KB vs. aktueller Stand 34 KB). Aktueller Stand liegt
|
|
in git + Arbeitsbaum, der Snapshot war rein historisch.
|
|
- **`aria_kelloggs_soundfiles_voll.tar.gz` -- geloescht.** Redundante
|
|
Pack-Kopie des entpackten Sound-Ordners.
|
|
- **`aria_kelloggs_soundfiles_voll/` -> `audio/` umbenannt und COMMITTET.**
|
|
25 Dateien, 167 MB: alle gerenderten Musik-WAVs (TITEL/TITEL2/ONGAME2 inkl.
|
|
aller Songs) + die `.SAM`/`.TFX`-Quellen.
|
|
|
|
**Copyright-Entscheidung (Stefan):** die WAVs kommen bewusst mit ins Repo --
|
|
freies Werbespiel, innerhalb DE frei kopierbar, WAVs nur aus `PCKELL.DAT`
|
|
extrahiert/gerendert. Format bleibt WAV (nicht FLAC/MP3), so wie extrahiert.
|
|
|
|
**`audio_cache/` bleibt gitignored** -- reiner Laufzeit-Cache, den
|
|
`intro_sequence.py` bei jedem Start selbst regeneriert; committen wuerde die
|
|
gerade beseitigte Dopplung wieder einbauen.
|
|
|
|
Installer + Handbuch (`Tony-...Installer-Alt-1.zip`, `Tony-...Manual_DOS_DE.pdf`)
|
|
im Anschluss ebenfalls ins Repo committet (gleiche Copyright-Begruendung wie
|
|
audio/).
|
|
|
|
Naechster Schritt unveraendert: echtes Gameplay (Tony auf `W1L0`).
|
|
|
|
## 24.07.2026 (Nacht) -- Factor5-Tail, Menuesystem + Weltkarte (Referenz-getrieben)
|
|
|
|
**1) Factor5-Sound "nicht ganz abgespielt" -- Renderer-Fix.** real_song_end
|
|
markiert nur das Ende der TRACK-SEQUENZ (2.4s); die noch klingenden Samples
|
|
wurden hart abgeschnitten (RMS stieg bis zum letzten Frame). render_tfmx.c
|
|
kann jetzt einen Ausklang-Tail rendern (6. CLI-Arg): loop_mode=0 stoppt den
|
|
Sequencer bei song_end, die Paula-Voices klingen weiter (erster Versuch OHNE
|
|
loop_mode-Stopp nahm die naechste Loop-Iteration auf -- per RMS-Selbst-
|
|
aehnlichkeit von 3 Anschwell-Mustern nachgewiesen). Das Factor5-"Brausen"
|
|
loopt auf Paula-Ebene endlos (kein natuerliches Ende!) -> Tail 2.6s = exakt
|
|
5.0s Gesamt (DOSBox-Screendauer ~4.8s) mit 600ms-Fade-out. Rauser-Sting endet
|
|
natuerlich bei 2.34s (Stille-Erkennung). Cache-Suffix `_tail` invalidiert
|
|
alte abgeschnittene WAVs. Commit `949a7ee`.
|
|
|
|
**2) Kompletter Menuefluss per DOSBox-Referenz erfasst** (Xvfb + python3-Xlib
|
|
XTEST-Tasten -- xdotool ist auf Stefans Rechner nicht installiert; WICHTIG:
|
|
ohne Window-Manager ist der X-Fokus PointerRoot, also erst Pointer in die
|
|
Fenstermitte bewegen + set_input_focus, sonst kommen Keys nie an):
|
|
- Titelbild wartet ENDLOS (115s passiv, kein Attract-Loop). NUR ESC oeffnet
|
|
das Hauptmenue (Space/Return tun nichts -- per Einzeltasten-Sessions
|
|
verifiziert). Menue faedet ein.
|
|
- Hauptmenue: HIGHSCORES/ANLEITUNG/OPTIONEN/START/QUIT, Default-Auswahl
|
|
START, der selektierte Eintrag BLINKT (= der Cursor). PARTY1/PARTY2 links/
|
|
rechts, unten Credits-Ticker (gelb): "FREEGAMES #3", "REALISATION RAUSER
|
|
ADVERTAINMENT GMBH REUTLINGEN", "PRODUZIERT VON FACTOR 5", "ANIMATIONEN
|
|
UND ILLUSTRATIONEN HARTWIG NIEDERGASSEL".
|
|
- OPTIONEN: MUSIK EIN/AUS, EFFEKTE EIN/AUS, EXIT. ANLEITUNG: gelbe Texttafel
|
|
(Joystick-Text, Faehigkeiten TONY=RENNEN/SMACKS=WASSERBLASEN/COCO=HANGELN
|
|
+KLETTERN/TOUCAN=FLIEGEN). HIGHSCORES: NAME/SCORE/ITEMS/LEV-Tabelle
|
|
(MATTHIAS 100000 ... BORIS 2500). START -> Weltkarte (KARTE.PCC, mit
|
|
Charakter-Animationen im Original).
|
|
- Nebenfund: Copyright-Tafel ("DIESES SPIEL IST INNERHALB DEUTSCHLANDS FREI
|
|
KOPIERBAR...") erschien in einer Session vor dem Menue -- Ausloeser noch
|
|
unklar (nicht Return, nicht Space), evtl. zyklische Attract-Tafel im Menue.
|
|
Noch nicht nachgebaut.
|
|
|
|
**3) Implementiert in game/menu.py** (Commit `c8f7d4d`): BitmapFont-Parser
|
|
fuer FON_1/FON_1B (9x7-Zellen, ABER 8px-Vorschub -- sonst passen die
|
|
32-Zeichen-Anleitungszeilen nicht in die Box) und FON_2 (16x15, 3 Reihen:
|
|
A-T / U-Z.,:!?- / 1-0). Gelbe Schrift mit schwarzem Outline-Rendering.
|
|
PARTY-Sprites per make_border_bg_transparent freistellen (papierweisser BG;
|
|
ein Schwarz-Replace loescht die KONTUREN -- sichtbar kaputt, verworfen).
|
|
intro.py: Zustandsautomat Titelbild <-> Menue <-> Karte; QUIT beendet.
|
|
|
|
**Verifiziert:** End-to-End-Lauf des REMAKES unter Xvfb mit echten XTEST-
|
|
Tasten: Intro -> ESC -> Menue -> START -> Karte -> zurueck -> Optionen ->
|
|
Anleitung -> Highscores -> QUIT (rc=0). Alle Screens visuell gegen die
|
|
DOSBox-Referenz geprueft (Menue/Highscores/Anleitung/Karte praktisch
|
|
deckungsgleich).
|
|
|
|
**Offen/naechste Schritte:**
|
|
1. Weltkarte: KARTE0-9-Animationen + Levelauswahl (Cursor auf der Karte).
|
|
2. Gameplay: Tony auf W1L0 (Map/Tiles/Sprites laengst dekodiert).
|
|
3. Copyright-Tafel-Ausloeser im Original klaeren (niedrig).
|
|
4. Highscores persistent machen + Eintrag-Eingabe (erst mit Gameplay relevant).
|
|
|
|
## 25.07.2026 -- LEVEL 1 SPIELBAR (erster Gameplay-Slice)
|
|
|
|
Stefans Auftrag: Weltkarte Level 1 auswaehlbar + "schauen was du aus Level 1
|
|
machst". Ergebnis: das erste Level laeuft.
|
|
|
|
**Referenz-Erkenntnisse (DOSBox, Xvfb+XTEST mit gehaltenen Tasten):**
|
|
- Auf der Weltkarte startet SPACE das Level (Return tut nichts, Pfeiltasten
|
|
bewegen am Spielstart keinen sichtbaren Cursor -- 0 Pixel Diff nach 2x
|
|
Right). Kurze Schwarzblende, dann steht das Level sofort.
|
|
- **Level 1 = W1L1.MAP** -- per Template-Matching des Gameplay-Screenshots
|
|
gegen die gerenderten Maps (diff W1L1=35.4 vs W1L0=56.5/W1L2=58.8; Kamera-
|
|
Match bei Map-Pixel 128,496). W1L0 ist also NICHT Level 1 (vermutlich
|
|
Bonus-/Sonderlevel).
|
|
- HUD unten 320x24 (Viewport 320x176): Kellogg's-Schriftzug, Keks-Zaehler,
|
|
Item-Box, Score, 4 Herzen, Tony-Kopf + Leben (3), Uhr zaehlt von 10:00.
|
|
- Kollision: MAP-ctype **Bit 32 = solide** (40=Boden-Oberkante=32|8,
|
|
32=Fuellung; 0=Luft, 4=Item-Marker, 16=Special). Empirisch an der
|
|
Spawn-Plattform (Zeile 40) verifiziert.
|
|
- TONY.BOB-Frames: 8-Phasen-Gehzyklus, GERADE Indizes = links, UNGERADE =
|
|
rechts (0..15); 16/17 Sprung, 24/25 Ducken (Zuordnung v1, ggf. justieren).
|
|
- GAMEBAR.BOB: 0-9 Ziffern, 10-16 Herzen/Schluessel(rot/blau/gruen)/Kopf --
|
|
Ziffern rendern mit bob-Regel-Palette dunkelrot statt weiss wie im
|
|
Original-HUD (Laufzeit-Palette unklar) -> HUD v1 nutzt FON_1B-Ziffern.
|
|
|
|
**Implementiert (game/level.py, Commit siehe git):** Level-Klasse (MAP+ICO
|
|
einmal komplett vorgerendert, Kamera blittet Ausschnitt), Tony (AABB-Physik
|
|
gegen Tile-Grid: laufen 110px/s, Sprung -300px/s, g=900 -- v1 nach Gefuehl,
|
|
Feinschliff nach Stefans Test), HUD-Nachbildung, ONGAME2-Song0 als
|
|
Levelmusik-ANNAHME (wie Factor5: nach Gehoer korrigieren). ESC -> Karte
|
|
(Titelmusik startet wieder). Weltkarte: Space/Return -> Level.
|
|
ONGAME2 wird im Audio-Preload mitgerendert (Levelstart blockiert nie).
|
|
|
|
**Verifiziert:** E2E unter Xvfb mit gehaltenen Tasten -- Tony laeuft rechts
|
|
(Kamera scrollt), faellt Plattformkante runter, laeuft links unterm
|
|
Brueckenbogen durch, ESC->Karte->Menue->QUIT rc=0. Level-Standbild praktisch
|
|
deckungsgleich mit DOSBox-Referenz (Haus/Baum/?-Block/Bruecke/Saeulen).
|
|
--once-Regression exit 0.
|
|
|
|
**Offen:** Items (ctype 4) einsammeln, Gegner, Duck-Frame-Zuordnung pruefen,
|
|
Original-HUD-Grafik, Karten-Animationen (KARTE0-9), Levelmusik-Song nach
|
|
Gehoer, Zeitablauf/Leben-Logik, weitere Level freischalten.
|
|
|
|
## 25.07.2026 (2) -- Stefans Level-Feedback eingearbeitet
|
|
|
|
Stefans annotierter Screenshot (4 Punkte), alle behoben:
|
|
1. **Figur lief rueckwaerts** -- TONY.BOB: GERADE Frames = RECHTS, ungerade
|
|
= links (Zuordnung war exakt vertauscht).
|
|
2. **Schraegen: fiel durch** -- ctype 16 ist KEINE Tuer, sondern das
|
|
SCHRAEGEN-Tile (als blaue Diagonale in der ctype-Farbvisualisierung exakt
|
|
auf dem Grashang gefunden). 45-Grad-Slope-Kollision implementiert
|
|
(Richtung per Nachbar-Heuristik, Fussmittelpunkt-basiert, Snap-Toleranz
|
|
10px). Simulation: Tony laeuft den Hang bis Plateau-Hoehe (y=559) hoch,
|
|
faellt nirgends mehr durch.
|
|
3. **HUD**: weisse Kellogg's-Leiste ergaenzt (Schriftzug aus KELLOGGS.PCC
|
|
gecroppt + klein skaliert), Herzen jetzt echte GAMEBAR-Sprites (Frame 10
|
|
voll / 11 leer; 13-15 sind die rot/blau/gruenen Schluessel -- fuer
|
|
Stefans "Tueren mit farbigem Knauf brauchen Schluessel" spaeter), Uhr-
|
|
Layout gefixt + Start bei 9:59 (4-stellig passt immer; Original zeigte
|
|
~1.5s nach Start ohnehin 9:59).
|
|
4. **RENNEN** -- Tonys Faehigkeit lt. Original-Anleitung ("MIT ALT
|
|
AKTIVIERST DU DIE FAEHIGKEITEN... TONY: RENNEN"): ALT halten (LSHIFT als
|
|
moderne Alternative), 185 statt 110 px/s, schnellere Lauf-Animation.
|
|
|
|
Physik-Feel laut Stefan gut. Levelmusik-Song prueft er nach Gehoer.
|
|
Offen bleiben: Tueren oeffnen (ALT an Tuer, Schluessel-Logik), Items,
|
|
Gegner, Karten-Animationen.
|
|
|
|
## 25.07.2026 (3) -- Stefans grosses Feedback-Paket: Charaktere, Wasser, Animationen, HUD
|
|
|
|
Referenz: 7 annotierte Screenshots von Stefan + DOSBox (machine=vgaonly --
|
|
Stefans Fund: das WASSER wird nur bei vgaonly gerendert, VGA-Palette-Effekt!).
|
|
|
|
**Asset-Funde:**
|
|
- WECH_1-4.PCC = die 4 Charakter-Koepfe FARBIG, WECH_5-8 = GRAU (= im Level
|
|
nicht verfuegbar) -- exakt das Tuer-Auswahlmenue "MIT WEM MOECHTEST DU
|
|
SPIELEN?". ITE0-3.PCC = die 4 Cerealien-HUD-Icons (Flake/Puff/Loop/Choco).
|
|
FROS/SMAC/COCO/LOOP_W1-3.ICO = SAMMEL-Cerealien-Animationsphasen pro Welt
|
|
(fuer Items spaeter). TONY-Frames: 18/19=Sprung, 24/25=Ducken, 26-33=
|
|
RENN-"Rad" (Stefans Fuesse-wie-ein-Rad), 44-49=Idle-Packung. SMACKS: 51
|
|
Frames, 18/19=Ducken, 24/25=Sprung, 31-36=Idle-Packung, 37-44=SCHWIMMEN,
|
|
45-47=Wasserblasen.
|
|
- ARE-Format angeschaut (W1L1: 6690B, 3 Regionen; Header ab Byte 8 enthaelt
|
|
Big-Endian-Pixelkoordinaten-Paare, u.a. (256,592)~Spawn-Kopfposition) --
|
|
noch NICHT geknackt, v1 nutzt LEVEL_INFO-Konstanten. TODO.
|
|
|
|
**Implementiert (game/level.py):**
|
|
- Player-Klasse mit CHAR_DEFS (Tony/Smacks/Coco/Toucan): Tony rennt (ALT/
|
|
Shift, Rad-Animation), Smacks schwimmt (kein Wasserschaden, traege
|
|
Physik, Space=Schwimmstoss), Idle-Packungs-Animation nach 5s Stillstand,
|
|
Sprung-Frames korrigiert (18/19 gestreckt statt 16/17).
|
|
- Sprunghoehe kalibriert: -360 (~72px ~ Stefans "Kopf an den Ast").
|
|
- WASSER: water_y pro Level, dunkelblaues Overlay, Nicht-Schwimmer verlieren
|
|
alle 5s ein Herz; 0 Herzen -> Leben-1 + Respawn; 0 Leben -> Karte.
|
|
- TUER (Level-1-Haus, Tiles 12-13/37-39): Kopf-Symbol drueber; ALT im STEHEN
|
|
(nicht beim Rennen) oeffnet das Charakter-Menue (WECH-Koepfe, nicht
|
|
verfuegbare grau, Auswahl blinkt), Wechsel uebernimmt Position.
|
|
- HUD nach Referenz: Keks-Box MIT Cerealien-Icon des aktiven Charakters,
|
|
Herz-Box als 2x2-GRID, Charakter-Kopf-Box (zeigt IMMER die gewaehlte
|
|
Figur) + Leben, Uhr.
|
|
|
|
**Verifiziert:** E2E (Xvfb+XTEST): Tuer -> Menue -> Smacks gewaehlt -> HUD
|
|
zeigt Smacks-Kopf+Puff-Icon, Wasser-Overlay sichtbar, laufen/springen/
|
|
ducken als Smacks, ESC/QUIT rc=0. --once Regression exit 0.
|
|
|
|
**Offen:** ARE knacken (Charaktere/Wasser/Tueren/Spawns pro Level echt),
|
|
Items einsammeln (FROS_W1-Rotationssprites + ctype 4), Smacks-Blickrichtungs-
|
|
Paritaet pruefen, Coco/Toucan-Frames zuordnen (aktuell Tony-Layout
|
|
angenommen), Kamera-Hoehe feinjustieren, Gegner, Tuer-/Schluessel-Logik.
|
|
|
|
## 25.07.2026 (4) -- zweite Feedback-Runde: Wasser-Mechanik, Slopes, Spawn-Pose, HUD v3
|
|
|
|
Stefans Live-Test (5 Screenshots), alles umgesetzt:
|
|
1. **Slope-Schweben gefixt**: in der Luft snappt der Fuss nur noch bei
|
|
echter Durchdringung der Diagonale (tol=0); nur wer schon am Boden ist,
|
|
steigt mit 8px-Toleranz bergauf. (Nebenfund: der Grashang hat ZWEI
|
|
Slope-Tiles uebereinander -- gelaufen wird auf der oberen Diagonale.)
|
|
2. **Wasser-Mechanik wie im Original**: Nicht-Schwimmer tauchen NICHT unter
|
|
-- die Oberflaeche traegt (Fuss sinkt nur 14px ein, on_ground, man kann
|
|
von ihr abspringen), Herzverlust laeuft weiter. Schwimmer (Smacks): nahe
|
|
der Oberflaeche loest die Sprungtaste einen ECHTEN Sprung aus (vorher kam
|
|
man nicht mehr aus dem Wasser raus, nur schwacher Schwimmstoss).
|
|
Smacks-Blickrichtung: passt (Stefan bestaetigt).
|
|
3. **Start-Sprite-Sequenz** beim Levelstart/Charakterwechsel: Tony streckt
|
|
den Arm hoch (Frame 22), Smacks Daumen hoch (Frame 22); ~1.1s, jede
|
|
Eingabe bricht ab.
|
|
4. **Rennsprung weiter**: RUN_SPEED 185 -> 200 ("bis hinter die Blume").
|
|
5. **HUD v3** nach Original-Screenshot: helle Creme-Rahmen statt Gold,
|
|
groessere Boxen (18px), Icon in voller Groesse, leere Herz-Plaetze
|
|
bleiben dunkel.
|
|
|
|
Verifiziert per Physik-Simulationen (Wade-Ebene 686=water_y+14 + Sprung
|
|
vy=-345 von dort; Smacks-Ausstiegssprung vy=-360 an offener Wasserstelle;
|
|
Smacks unter der Bruecke stoesst korrekt an die Decke) + E2E rc=0 + --once ok.
|
|
|
|
## 25.07.2026 (5) -- dritte Feedback-Runde: echte GAMEBAR, Pixel-Slopes, Diverses
|
|
|
|
1. **GAMEBAR.PCC ist die echte HUD-Grafik** (320x25, aus PCKELL.DAT --
|
|
Stefans Fund via preview/png_out/GAMEBAR.png): Kellogg's-Leiste, alle 6
|
|
Boxrahmen, sogar der Uhr-":". Die weissen Box-Innenflaechen fuellt die
|
|
Engine zur Laufzeit dunkelrot -> wir ersetzen sie beim Laden (Pixel-Loop
|
|
rechts der Kellogg's-Leiste). HUD zeichnet nur noch Inhalte an die
|
|
gemessenen Box-Positionen (57/105/160/216/254/286). HUD_H jetzt 25,
|
|
VIEW_H 175. (Mit W1-Palette statt eigener wird die Grafik magenta --
|
|
getestet und verworfen.)
|
|
2. **Slopes jetzt PIXELGENAU**: pro Slope-Tile (ctype 16) und Spalte wird
|
|
der oberste Nicht-Himmel-Pixel der Tile-Grafik als Laufflaeche genommen
|
|
(slope_profiles; Sky-Index = haeufigster Pixel des haeufigsten Luft-Tiles
|
|
-- NICHT der ersten Luft-Zelle, das war Tile 0/Randfueller). Die Haenge
|
|
sind tatsaechlich ~1:2 geneigt, nicht 45 Grad -- daher das restliche
|
|
"Schweben" beim Drueberlaufen. Tiles mit reiner Himmel-Spalte tragen
|
|
nicht (die oberen der gestapelten Hang-Tiles inkl. Tile 1+ctype16).
|
|
Drop-Test: Landung exakt auf Grafikkante (626.0 = Kante 626).
|
|
3. **STEP_UP=6**: die untersten 6px der Hitbox blocken nicht an Waenden --
|
|
der 4px-Rest an der Plateau-Kante wird hochgestept (hohe Waende blocken
|
|
weiter ueber die oberen Hitbox-Zeilen, verifiziert).
|
|
4. **Wasser-Grund**: unterste Map-Zeile ist jetzt immer solide (der gruene
|
|
Bodenstreifen hat keine ctypes -- Smacks hing beim Tieftauchen in der
|
|
Grafik). Smacks-Grund jetzt 736 = Streifen-Oberkante.
|
|
5. **Smacks-Steh-Frames 12/13** (0/1 sind Schrittphasen -- "beim Anhalten
|
|
lief die Animation weiter").
|
|
|
|
Verifiziert: Slope-Drop pixelgenau, Plateau-Aufstieg + Weiterlauf, Wand-
|
|
Integritaet, Smacks idle=12, --once exit 0, E2E rc=0.
|
|
|
|
## 25.07.2026 (6) -- HUD final: GAMEBAR pur (weisse Boxen) + Original-Ziffern
|
|
|
|
Stefans Korrektur zur letzten Runde: die Box-Innenflaechen sind im Original
|
|
WEISS (genau wie in der GAMEBAR.PCC-Grafik -- die dunkelroten Boxen im
|
|
frueheren DOSBox-Screenshot waren wohl ein Farb-Artefakt), die Zahlen sind
|
|
ROT in der Original-HUD-Font, und es sind 6 HERZEN (3x2).
|
|
|
|
Loesung: GAMEBAR.PCC wird jetzt PUR geblittet (keine Fuellung mehr, der
|
|
Grafik-":" ist auf weiss natuerlich sichtbar). Die Zahlen sind die
|
|
GAMEBAR.BOB-Ziffern (7x13) gerendert mit der GAMEBAR.PCC-PALETTE -- damit
|
|
sind sie sattrot mit dunkler Umrandung, exakt wie der ":" (mit der
|
|
bob-Regel-Palette waren sie braeunlich; Stefan: "koennte sogar braun sein"
|
|
-- die PCC-Palette ist die konsistente Wahl, Umschalten waere 1 Zeile).
|
|
Herzen: 6 (3x2-Grid, Frame 10 mit PCC-Palette), leere Plaetze bleiben weiss.
|
|
hearts-Start/-Reset = 6.
|
|
|
|
HUD-Render deckungsgleich mit Stefans Original-Screenshot. --once/E2E ok.
|
|
|
|
## 25.07.2026 (7) -- Charakter-Icon + echte Tuergrafik
|
|
|
|
- HUD-Charakter-Kopf: WECH-Koepfe jetzt NEAREST-skaliert (pixelig statt
|
|
weichgezeichnet) + schwarzer 1px-Umriss -- Original-Look (Stefans Hinweis
|
|
"schwarzer Rand drum"). Eigene Mini-Kopf-Assets existieren offenbar nicht
|
|
(GAMEBAR.BOB[16] ist leer, W1ANI.ICO sind Tile-Animationen).
|
|
- DOORS.BOB entschluesselt: Frame 0 = Tuer MIT Kopf-Schild (32x48), Frames
|
|
1-4 = Tueren mit ROTEN/GRUENEN/BLAUEN Knaeufen (Schluessel-Tueren!),
|
|
Frame 5 = Kopf-Schild einzeln. Das Level blittet jetzt DOORS[0] auf die
|
|
Tuerposition (statt des improvisierten Mini-Symbols) -- deckungsgleich
|
|
mit Stefans Original-Screenshot (Kopf-Schild + Punkte).
|
|
- Nebenfund: W1ANI/W2ANI/W3ANI.ICO = Tile-ANIMATIONSPHASEN (broeckelnde
|
|
Bloecke etc.) -- fuer spaeter (animierte Tiles).
|
|
|
|
## 25.07.2026 (8) -- vierte Feedback-Runde: Tuer-Sequenz, Kamera, Feinschliff
|
|
|
|
1. **Fuesse schwebten**: Sprites sinken beim Zeichnen 4px ein (SPRITE_SINK)
|
|
-- im Original stehen die Figuren IN den Blaettern, nicht drauf.
|
|
2. **Steh-Frames**: Tony idle=16/17 (0/1 sind Schrittphasen -- "letzter
|
|
Lauf-Frame blieb stehen"); Smacks-Walk auf [0..11] gekuerzt (12-15 sind
|
|
Steh-/Uebergangsframes, Idle 12/13 jetzt nicht mehr im Zyklus).
|
|
3. **Tuer-Sequenz**: DOORS[0] ist die OFFENE Tuer (Stefans Korrektur).
|
|
Ruhezustand = geschlossene Tile-Tuer + Kopf-Schild (DOORS[5]); ALT ->
|
|
Tuer zeigt Frame 0 (offen), nach 1s folgt die Tuer-Aktion (Charakter-
|
|
Menue). Gilt kuenftig fuer alle Tueren (Schluessel-Tueren DOORS 1-4).
|
|
4. **Slope-Tunneling** beim Landen gefixt: SWEPT-Check ueber alle zwischen
|
|
alter und neuer Position ueberstrichenen Zeilen (bei 8px/Frame Fall
|
|
wurde die duenne Graskante sonst uebersprungen) + Herkunftsbedingung
|
|
(alte Position muss ueber der Kante gewesen sein). Stress-Test: 50
|
|
Drops ueber die ganze Hangbreite, 0 durchgefallen.
|
|
5. **Kamera**: Standard so, dass die Figur bei ~75% Hoehe steht (mehr Blick
|
|
nach unten); DUCKEN >=1.2s gehalten faehrt die Kamera sanft ~40px runter
|
|
(Wasser unter Abgruenden sichtbar), Loslassen faehrt zurueck.
|
|
|
|
Tony-auf-Wasser+Frosties-Idle von Stefan als "sehr geil" abgenommen (kein Fix).
|
|
|
|
## 25.07.2026 (9) -- fuenfte Feedback-Runde: Wasser-Bounce, Tod-Anim, Tuer-Peek, Kamera-Grace
|
|
|
|
1. **Wasser-Bounce**: Nicht-Schwimmer stehen nicht mehr statisch auf der
|
|
Oberflaeche, sie HUEPFEN endlos (~6px, WATER_BOUNCE_V=-110); Steuerung
|
|
bleibt, voller manueller Sprung zum Rauskommen geht weiter (on_ground
|
|
bleibt beim Aufsetzen kurz true). Kein Idle im Wasser mehr (Tonys
|
|
Frosties-Fressen auf dem Wasser ist damit Geschichte ;-).
|
|
2. **Tod-Animation bei 0 Herzen**: ASSET-FUND -- Tony-Frame 38 ist Tony
|
|
OHNE HALSTUCH (erschrocken), Frame 40 das Halstuch einzeln; Smacks 26 +
|
|
29 (Kappe). Sequenz: Figur fliegt (ohne Kollision) aus dem Bild, Tuch/
|
|
Kappe flattert herab, nach 2.4s Respawn mit Leben-1 (0 Leben -> Karte).
|
|
3. **Tuer-Peek**: waehrend der 1s-Offen-Phase zeigt die Figur einen
|
|
Reinschau-Frame (Tony 34, Smacks 20 -- frontal; echte Ruecken-Frames
|
|
gibt es nicht in den BOBs).
|
|
4. **Duck-Kamera-Flackern**: 0.2s-Grace-Period -- kurze Taste/on_ground-
|
|
Blips (X11-Autorepeat sendet Release/Press-Paare) setzen den
|
|
Halte-Timer nicht mehr zurueck.
|
|
|
|
## 25.07.2026 (10) -- sechste Feedback-Runde: Wasser-Regeln + Peek-Frames
|
|
|
|
- Ducken im Wasser fuer Nicht-Schwimmer verboten (Bounce + DOWN ergab
|
|
Duck-Pose auf der Oberflaeche).
|
|
- Wasser-Schaden: alle 1.5s statt 5s (Stefan: "5 Sekunden arg lang").
|
|
- Schadens-Blinken nach Herzverlust (0.9s Sichtbarkeits-Toggle ~6Hz --
|
|
ein eigenes Aua-Sprite gibt es in den BOBs nicht). Beim Todesstart wird
|
|
das Blinken deaktiviert (sonst waere die eingefrorene Blinkphase die
|
|
ganze Anim unsichtbar gewesen).
|
|
- TUER-REINSCHAU-Frames (Stefans Fund): TONY Frame 50 (Rueckenansicht!),
|
|
SMACKS Frame 48 -- jeweils der letzte Frame vor den Magenta-
|
|
Platzhaltern. Der als "gebueckt/kriechend" einsortierte Tony-50 war in
|
|
Wahrheit das Reinschauen.
|
|
|
|
## 25.07.2026 (11) -- Disassembly-Frage + Smacks-Sprung per Referenz geklaert
|
|
|
|
Stefans Frage: Animations-Zuordnungen aus dem Binary disassemblieren?
|
|
- Byte-Muster-Suche nach Frame-Tabellen (0,2,4..14 / 26,28,30,32 / 37,39,
|
|
41,43 als u8- und u16le-Folgen) in START.EXE und RTM.EXE: KEINE Treffer
|
|
-- die Sequenzen liegen nicht als nackte Tabellen im Binary (gepackt oder
|
|
als Code). Voll-Disassembly von 148KB 16-bit-Borland-Code waere ein
|
|
Wochenprojekt -- der empirische Weg (DOSBox-Frameserie) bleibt schneller
|
|
und sicherer.
|
|
- Stattdessen DOSBox-Session mit 0.12s-Intervall: per TUER zu Smacks
|
|
gewechselt (verifiziert dabei UNSER Tuer-/Menue-Design gegen das
|
|
Original: Menue-Layout deckungsgleich, Coco/Toucan grau ✓) und
|
|
Spruenge aufgenommen. ERKENNTNISSE:
|
|
1. Der Original-Sprung hat eine ABSPRUNG-HOCKE (Kauer-Frame im
|
|
Absprungmoment, dann Streckung im Flug) -- das fehlte bei uns
|
|
("Sprunganimation nicht richtig"-Gefuehl). Eingebaut:
|
|
JUMP_SQUAT_SECONDS=0.09 zeigt kurz den Duck-Frame.
|
|
2. Die TUER-SEQUENZ DIMMT DEN LEVEL AB (Szene dunkel waehrend der
|
|
Interaktion) -- eingebaut (Overlay waehrend door_open_t).
|
|
|
|
## 25.07.2026 (12) -- BINARY-DURCHBRUCH: NE-Overlay + Original-Animationstabellen
|
|
|
|
Stefans Frage "sollen wir Disassembly versuchen?" -- JA, und es hat sich
|
|
gelohnt (kein Voll-Disassembly noetig!):
|
|
|
|
**START.EXE-Struktur:** MZ-Stub (3.6KB) + NE-Executable als Overlay ab
|
|
Offset 3646 (Borland DPMI16, UNGEPACKT, 7 Segmente: 5 CODE ~100KB, 2 DATA).
|
|
Borland-Pascal-Shortstrings ("GAMEDATA\" + Name + ".BOB" wird zur Laufzeit
|
|
konkateniert -- deshalb fand die fruehe Dateinamen-Suche keine .ARE/.MAP).
|
|
String-Fund: "Willkommen im Kellogg's Cheat-Mode" -- Level-Waehler per
|
|
Pfeiltasten existiert im Original!
|
|
|
|
**ANIMATIONSTABELLEN im DATA-Segment (@143858 ff., Format
|
|
[delay_ticks][frame...] 0xffff, 70Hz-Ticks):**
|
|
FORMEL: Engine-Frame x2 = unser BOB-Frame (gerade=rechts, +1=links)!
|
|
- [0,4] 0..7 -> Gehzyklus 0,2..14, delay 4 = 17.5 fps
|
|
- [4] 8,8,8 -> Idle 16 (bestaetigt unsere Zuordnung)
|
|
- [4] 9 -> Sprung 18 (bestaetigt)
|
|
- [4] 10,10,10 -> Frontal 20
|
|
- [4] 13,14,15,16 -> RENN-RAD 26,28,30,32 (bestaetigt!)
|
|
- [25] 23,24,23,22,...,10x5 -> ECHTE Frosties-Sequenz
|
|
46,48,46,44,...,20x5 (delay 25 = 2.8 fps) -- uebernommen.
|
|
- Weitere Listen mit globalen Sprite-Indizes (100er/200er/400er/500er/
|
|
900er) = andere BOBs/Items/Karten-Sprites (Basis-Offsets noch offen).
|
|
|
|
**WELTKARTEN-DATEN (@145114-146760):** kompletter Karten-LAUFPFAD als
|
|
Records [x,y,flag,25] ((58,40)->...ueber die ganze Karte), dazwischen
|
|
[x,y]-Paare = LEVELPUNKT-Positionen ((53,56),(108,51),(126,81),(142,53)
|
|
...), am Ende die 22 Levelnamen W1L0..W3L7 als Pascal-Strings. => Die
|
|
Weltkarten-Levelauswahl liegt komplett im Binary -- perfekte Grundlage
|
|
fuer den naechsten Meilenstein! Voll-Dump gesichert (Session-Scratchpad
|
|
anim_tables.txt; bei Bedarf neu erzeugbar, Offsets dokumentiert).
|
|
|
|
**Angewendet:** Walk/Rad-FPS auf 17.5 (Original-Timing), Frosties-Sequenz
|
|
exakt uebernommen, Idle 2.8 fps.
|
|
|
|
**Offen:** globale Sprite-Basis-Offsets pro BOB entschluesseln (dann sind
|
|
ALLE Animationszuordnungen inkl. Smacks-Sprung exakt abzulesen); Karten-
|
|
pfad in die Weltkarte einbauen; Cheat-Mode-Aktivierung finden.
|
|
|
|
## 25.07.2026 (13) -- WELTKARTE MIT LEVELAUSWAHL (Daten aus dem Binary)
|
|
|
|
game/worldmap.py: parst zur Laufzeit Pfadsegmente, Levelpunkt-Positionen
|
|
und die 22 Levelnamen direkt aus START.EXE (NE-Datensegment; Anker-Suche
|
|
statt fester Offsets, Fallback auf nur-W1L1 wenn Parse scheitert).
|
|
Struktur pro Level: Wegpunkte (flag 1) -> Standpunkt (flag 0) ->
|
|
Label-Position; Sonder-Records mit ffff-Koordinaten (Weltwechsel) werden
|
|
uebersprungen. Ergebnis: 21 Segmente + 22 Namen (letztes W3L7-Label fehlt
|
|
noch -- Randfall im Parser, spaeter).
|
|
|
|
Karten-Sprites entschluesselt: KARTE0/2 = grosser oranger/blauer
|
|
Levelpunkt (Blink-Animation laut Binary-Tabelle [100] 900,902,900!),
|
|
KARTE1/3 = kleine Punkte, KARTE4-7 = MINI-KOEPFE (Tony/Smacks/Toucan/
|
|
Coco) als Kartenfigur, KARTE8/9 = Seeschlangen-/Baum-Deko-Frames.
|
|
|
|
Bedienung: Links/Rechts wandert zum vorigen/naechsten Levelpunkt (die
|
|
Figur laeuft die Original-Wegpunkte ab, ~0.18s/Punkt), Space/Return
|
|
startet das angewaehlte Level, ESC -> Menue. Der aktive Punkt blinkt
|
|
orange/blau (0.5s) wie im Original-Datensatz. Position bleibt ueber
|
|
Level-Besuche erhalten (map_state).
|
|
|
|
Level ohne handgepflegte LEVEL_INFO bekommen einen GENERISCHEN Spawn
|
|
(erste Spalte mit Boden + 2 Luftzellen darueber); Wasser/Tuer dort noch
|
|
None. Alle 22 Level sind anwaehlbar (bewusst -- Test-freundlich, quasi
|
|
eingebauter Cheat-Mode ;-).
|
|
|
|
E2E verifiziert: Karte -> 2x Right (Figur laeuft) -> W1L3 gestartet
|
|
(generischer Spawn) -> ESC -> Karte (Position gemerkt) -> Left -> W1L2
|
|
gestartet -> ESC/ESC/QUIT rc=0. --once exit 0.
|
|
|
|
## 25.07.2026 (14) -- Karten-Koordinaten korrigiert: y-Flip + Punkt/Kopf-Blinken
|
|
|
|
Stefans Einwand (Original-Screenshots inkl. zweier Netzfunde mit
|
|
fortgeschrittenem Spielstand): nur Level-1-Punkt sichtbar, Position unten
|
|
beim Haus -- nicht in den Bergen wie bei uns.
|
|
|
|
DOSBox-Nachmessung (Frame-Diff des blinkenden Markers): Level-1-Punkt real
|
|
bei (59,153); Binary-Label ist (53,56) => die Binary-y-Achse ist GEFLIPPT:
|
|
screen_y = 209 - y. Damit liegen W1 im Wald unten, W2/W3 in Bergen/
|
|
Schloss oben -- deckungsgleich mit den Netz-Referenzen (Kopf am Teich in
|
|
Bild 1 = W1L7-Position!).
|
|
|
|
Zweiter Fund aus der Diff-Region (13x15 = Kopfgroesse): an der aktuellen
|
|
Position wechseln PUNKT und MINI-KOPF im Blinkrhythmus (die Netzbilder
|
|
zeigen je eine Phase). Eingebaut.
|
|
|
|
Noch offen (bewusst): nur-freigeschaltete-Punkte anzeigen kommt mit dem
|
|
Level-Abschluss-Feature; aktuell sind alle Punkte sichtbar/anwaehlbar
|
|
(Testphase).
|
|
|
|
## 25.07.2026 (15) -- Karten-Punkte: Blit-Anker-Offset
|
|
|
|
Stefans Abgleich: alle Punkte ein Stueck nach rechts+unten. Ursache: die
|
|
Binary-KOORDINATEN stimmen, aber der BLIT-ANKER des Originals (topleft vs
|
|
zentriert) steht nicht im Binary -- wir hatten zentriert geraten. Fix:
|
|
empirische Offsets MAP_DX=5/MAP_DY=4 in worldmap._tf() (dort feinjustieren,
|
|
falls noch nicht exakt).
|
|
|
|
## 26.07.2026 (16) -- Karte PIXELEXAKT: Template-Matching statt Schaetzung
|
|
|
|
Stefans Nachmessung: immer noch daneben ("noch ein bisschen nach rechts
|
|
und weiter runter"). Diesmal richtig gemessen: KARTE-Sprites per
|
|
Template-Matching (mit Alpha-Maske) in den DOSBox-Referenzframes gesucht.
|
|
Ergebnis eindeutig (err ~10 = VGA-DAC-Rauschen, naechster Kandidat >200):
|
|
|
|
- KARTE0 (10x7) steht DAUERHAFT, Topleft (58,162) -- in BEIDEN Blinkphasen!
|
|
- KARTE4-Kopf (14x15) blinkt DARUEBER an/aus, Topleft (53,146) (steht auf
|
|
dem Punkt). Frueherer Befund "Punkt und Kopf wechseln sich ab" war
|
|
falsch (Diff-Region war die VEREINIGUNG beider Sprites).
|
|
- KARTE3 (kleine Punkte): am Spielstart NIRGENDS auf der Karte -- nicht
|
|
freigeschaltete Level sind unsichtbar (bestaetigt die Netz-Screenshots:
|
|
dort ist das Spiel durchgespielt).
|
|
|
|
Daraus die exakten Anker (Binary-Label (x,y)): Basis = (x, 218-y);
|
|
KARTE0-Topleft = Basis+(5,0); Kopf-Topleft = Basis+(0,-16); KARTE3
|
|
zentriert auf dem grossen Punkt = Basis+(7,2) (einzige verbleibende
|
|
Annahme -- kleine Punkte gibt es in keiner DOS-Referenzaufnahme).
|
|
|
|
WICHTIGER NEBENFUND -- Segment/Namens-Zuordnung war um 1 verschoben:
|
|
Das Start-Label (53,56) gehoert zu SEGMENT 0, und 21 Segmente = exakt
|
|
die 21 anwaehlbaren Level W1L1..W3L7 (3 Welten x 7). W1L0 (22. Name,
|
|
MAP existiert) hat KEINEN Kartenpunkt (Bonus-/Geheimlevel?). Also
|
|
segments[i] = names[i+1]; der "fehlende W3L7-Randfall" aus Eintrag (13)
|
|
war keiner. Cursorstart = Segment 0 = W1L1.
|
|
|
|
Disassembly-Check (Stefans Frage "bekommst du das nicht aus dem
|
|
Disassembler?"): einziges `mov ax,218` im Binary (Offset 0xf084) ist
|
|
eine HUD-ZIFFERN-Routine (X-Positionen 186/194/202, Spriteindex =
|
|
Ziffer+500 -- notiert fuer die Punkteanzeige!). Der Karten-Anker steht
|
|
nicht als Literal im Code -> Pixelmessung war der richtige Weg.
|
|
|
|
Verifikation: eigener Karten-Render vs. DOSBox-Frame, mittlerer
|
|
Pixelfehler 5.0 (identisch mit dem Ganzbild-Grundrauschen der
|
|
VGA-DAC-Quantisierung) in beiden Blinkphasen => pixelidentisch.
|
|
--once exit 0.
|
|
|
|
## 26.07.2026 (17) -- Weltkarten-Daten fest eingebettet, START.EXE-Abhaengigkeit weg
|
|
|
|
Stefans Wunsch: Daten dauerhaft ins Spiel, parse_worldmap() raus.
|
|
Umgesetzt: SEGMENTS + LEVEL_NAMES als feste Tabellen in game/worldmap.py
|
|
(Rohkoordinaten wie im Binary, Transform/Anker unveraendert zur Laufzeit).
|
|
Der Parser lebt als Dev-Werkzeug tools/worldmap_extract.py weiter (gibt
|
|
die Tabelle als Python-Literal aus, nur fuer etwaige Regeneration).
|
|
Verifiziert: Extraktor-Output == eingebettete Tabelle, Karten-Render
|
|
weiterhin Pixelfehler 5.14 (= VGA-DAC-Grundrauschen) gegen die
|
|
DOSBox-Referenz in beiden Blinkphasen. --once exit 0. Das Spiel braucht
|
|
zur Laufzeit jetzt wieder NUR PCKELL.DAT.
|
|
|
|
## 26.07.2026 (18) -- ANIMATIONSSYSTEM KOMPLETT GEKNACKT (Disassembly + BOB-Header)
|
|
|
|
Stefans Auftrag: alle Charaktere per Disassembly sauber bauen. Ergebnis:
|
|
das komplette Sprite-/Animationssystem des Originals ist jetzt verstanden.
|
|
|
|
### Die Schluessel-Erkenntnis: BOB-Frame-Header tragen SLOT-NUMMERN
|
|
Die 14-Byte-Frame-Header (Felder u0/u1/u2 vor width/height) bedeuten:
|
|
u0 = SLOT-Nummer (Engine-Sprite-Index!), u1 = Anker-X, u2 = Anker-Y
|
|
(Anker = Fusspunkt; u2=64 bei Cocos Hangel-Frames = Anker UNTER dem
|
|
Sprite, u2=40 bei Smacks-Schwimmframes = tiefer im Wasser. Das ersetzt
|
|
unseren SPRITE_SINK-Hack durch Originaldaten.)
|
|
|
|
### Richtungs-Regel (aus set_anim, Seg3:0x4cad, Datei 62637)
|
|
sprite = slot; wenn Blickrichtung LINKS: sprite += 50 (add ax,0x32)
|
|
-> Slots 0-49 rechts, 50-99 links. BOBs sind gepaart gespeichert
|
|
(gerade=rechts slot i/2, ungerade=links +50) -- deckt sich mit allen
|
|
bisherigen Funden. Einzel-Frames (45, 48, 49, Smacks 29-31) existieren
|
|
nur einseitig.
|
|
|
|
### Universelle Slot-Semantik (fuer ALLE Charaktere gleich!)
|
|
0-7 Laufzyklus ([delay 4] = 17.5 fps) 8 Stehen/Idle
|
|
9 Springen/Fallen 10,11 Absprung-Hocke
|
|
12 Ducken 13-16 RENNEN (nur Tony hat sie!)
|
|
17,18 (Schaden?) 19,20 Tod + Sturz 22,23,24 Idle-Warteanimation
|
|
22-28 Schwimmen (nur Smacks/Toucan haben die Slots!)
|
|
[10][25,26,27,28] = Schwimmstoss-Tabelle
|
|
29-31 Toucan: Fluegelschlag (Paare 32x56) / Smacks: Blasen-Aktion (Einzel)
|
|
33,34 Toucan: Gleiten ([4][34,34,34] mit Status-Flag 0x20)
|
|
35-44 Coco: HANGELN (Paare, Anker-Y 64!) -- Code setzt 43/44/91/92 direkt
|
|
45 In-die-Tuer-gucken (Einzelframe, alle Chars; Code: Flag ds:0xd7a0)
|
|
48,49 Accessoire-Dropitems beim Tod (16x16: Muetze/Schal/...)
|
|
-> FAEHIGKEITEN ergeben sich aus vorhandenen Slots: nur Tony hat 13-16
|
|
(rennen), nur Smacks/Toucan 25-28 (schwimmen), nur Coco 35-44
|
|
(hangeln), nur Toucan 29-34 als Paare (fliegen). Deckt sich 1:1 mit
|
|
dem Handbuch!
|
|
|
|
### Toucan-Flugmechanik (aus Zustandsmaschine Seg3 ~0xfb79)
|
|
Absprung/Schlag: v = -0x18000 (16.16 fixed); jeder weitere Schlag
|
|
addiert +0x2000 (wird schwaecher); unter -0x4000 kein Schlag mehr ->
|
|
genau die "fuenfmal mit den Fluegeln" aus dem Handbuch. Anim [12][29,30,31,30].
|
|
|
|
### Weitere Code-Funde
|
|
- Anim-Tabellenformat: [delay_ticks(70Hz)][slots...][ffff=Loop|fffe=Halten]
|
|
fffe-Variante: bleibt auf letztem Frame stehen (kein Loop).
|
|
- Tuer-Erkennung im Code: ctype-Nibble == 3 (Kopfhoehe y-0x2e) -> Tuer!
|
|
ctype == 0xc -> zweiter Spezialfall (y-0x36, vermutlich Levelausgang).
|
|
- Objektstruktur es:[di]: +0 x(16.16) +4 y(16.16) +0xc v(16.16)
|
|
+0x10 Sprite-Index +0x1c/0x1e Anim-Delay +0x20/0x22 Anim-Pos
|
|
+0x26 Richtung (1/-1) +0x28 ctype-Flags +0x3e Idle-Timer +0x6c Sprungkraft
|
|
- HUD-Ziffern-Routine (mov ax,218 @0xf084): X-Positionen 186/194/202,
|
|
Spriteindex = Ziffer + 500 (GAMEBAR-Slotbasis 500).
|
|
- Charakter-Lade-Trios @52417: fros_w/tony/frosties, smac_w/smacks/
|
|
smackies, loop_w/toucan/loops, coco_w/coco/cocopops (via ds:0xb568).
|
|
- KARTE0-9-Laderoutine @22834: Handles nach ds:0x9e40 (Karten-Slots 900+).
|
|
- 100er/200er-Tabellenwerte (@144006-144152) sind NICHT die Charaktere --
|
|
vermutlich Levelobjekt-/Gegner-Slots (Ladeliste 'ani',A-O,gamebar,keys,
|
|
vitamin,platfw1,doors,blume,wolke,KROKO,BOSSNAKE,w2snake,DRAGON @4984).
|
|
Noch offen.
|
|
|
|
## 26.07.2026 (19) -- Charaktersystem auf Original-Slots umgebaut (alle 4 Figuren)
|
|
|
|
Umsetzung von Eintrag (18) in game/level.py + game/formats.py:
|
|
|
|
- formats.BobFrame traegt jetzt slot/anchor_x/anchor_y aus dem Frame-Header.
|
|
- Player haelt Sprites als {slot: (Surface, Anker)}; Blickrichtung links =
|
|
Slot+50 (Original-Regel), Einzel-Frames fallen auf die Rechts-Variante
|
|
zurueck. Gezeichnet wird am Original-ANKER (Fusspunkt) + SPRITE_SINK.
|
|
- CHAR_DEFS auf bob/item_icon/head_index geschrumpft; FAEHIGKEITEN werden
|
|
aus den vorhandenen Slots abgeleitet (can_run=13, can_swim=25,
|
|
can_fly=29+79 als Paar, can_hang=35) -- deckt sich exakt mit Handbuch.
|
|
- Animationen = Original-Tabellen: Walk [4][0-7], Run [4][13-16],
|
|
Schwimmstoss [10][25-28], Fluegelschlag [12][29,30,31,30], Idle-Warten
|
|
[25][23,24,23,22,...,10x5] (= Schachtel-essen-Posen 22-24!).
|
|
- Dabei 3 Alt-Bugs gefixt: Smacks Sprung/Ducken waren VERTAUSCHT (Sprung
|
|
ist Slot 9 = BOB 18, Ducken Slot 12 = BOB 24 -- Stefans Verdacht war
|
|
richtig); Smacks' alte Schwimm-Frames waren die LINKS-Varianten;
|
|
Smacks-Idle war ein Laufframe (Slot 6) statt Slot 8.
|
|
- NEU Toucan: Flugkette wie im Original -- Absprung armiert
|
|
flap_strength=-300, jeder Schlag (Space-Edge in der Luft) wird um 48
|
|
schwaecher, unter -70 nur noch Gleiten (Slot 34, Sinken max 55 px/s,
|
|
Pfeil-runter bricht ab). Test: exakt 5 Schlaege bis zum Gleiten ✓.
|
|
- NEU Coco: Hangeln -- greift mit Hoch-Taste in der Luft einen "Ast",
|
|
hangelt seitlich (Slots 35-44, Anker-Y 64), Runter laesst los.
|
|
EXPERIMENTELL: Ast-Trigger = ctype-Bit 8; in W1L2 liegen solche Tiles
|
|
aber nur in Zeile 1 (unsichtbar oben) -> echter Ast-ctype noch per
|
|
DOSBox/W2-Level zu verifizieren.
|
|
- Wasser-Schaden: erster Kontakt kostet SOFORT ein Herz (+Blinken), danach
|
|
alle 1.5s (Stefans Erinnerung; DOSBox-Nachmessung steht noch aus).
|
|
- Tod: Slot 19 + fallendes Accessoire Slots 48/49 im Wechsel (16x16,
|
|
Muetze/Tuch); Tuer-Gucken = Slot 45 (alle Charaktere, wie vorher).
|
|
- Smacks-Slots 29-31 = WASSERBLASEN-Posen (Handbuch: ALT-Aktion) -- fuer
|
|
spaeter (Projektil fehlt noch); Slots 20/21 (32x16) = Spritzer?, offen.
|
|
|
|
Verifiziert headless: alle 4 Chars idle/walk/duck/squat/fall = Slots
|
|
8/0/12/10/9; Smacks schwimmt (25, Stoss 25-28); Toucan 5 Schlaege ->
|
|
gleiten; Coco haengt/hangelt/loest. --once exit 0.
|
|
|
|
## 26.07.2026 (20) -- Smacks: echtes Tauchen/Schwimmen
|
|
|
|
Stefans Feedback: Unterwasser Links/Rechts ohne Schwimmanimation; Hoch
|
|
fuehlte sich wie "kleines Springen unter Wasser" an. Umbau:
|
|
- Hoch/Runter im Wasser = sanftes Auf-/Abtauchen (Zielgeschwindigkeit
|
|
-85/+110 px/s, weiche Annaeherung statt Sprung-Impulse); an der
|
|
Oberflaeche haelt Hoch nur die Position.
|
|
- Leertaste = Schwimmstoss (Impuls -140 + Stossanimation 25-28); nahe der
|
|
Oberflaeche wie gehabt echter Sprung raus. HOCH loest keinen Sprung/
|
|
Stoss mehr aus (eigene Space-Flanke).
|
|
- Bei jeder aktiven Bewegung (links/rechts/hoch/runter) laeuft die
|
|
Schwimmanimation 25-28 durch; ohne Eingabe Treiben auf Slot 25.
|
|
Headless verifiziert (Tauchfahrt runter/hoch, Anim-Slots, Oberflaechen-
|
|
Exit nur per Space). --once exit 0. Vorher: Wasserschaden-Fix eb798a8
|
|
(can_swim statt swimming -- Smacks verlor beim Rausspringen Herzen).
|
|
|
|
## 26.07.2026 (21) -- Sterbe-Drop-Fix + Tuer-Menue-Leertasten-Leak
|
|
|
|
- Stefans Fund "Gegenstaende beim Sterben lila": SLOT_DROP war falsch auf
|
|
48/49 (16x16, lila Kloetzchen -- Zweck weiter unklar) gesetzt. Richtig
|
|
sind die flachen 32x16-Slots 20/21: Tonys rotes Halstuch (2 Flatter-
|
|
Frames) und Smacks' oranges Cappy. Visuell verifiziert.
|
|
- Leertasten-Leak: Bestaetigung im Charakterwechsel-Menue loeste beim
|
|
Rueckwechsel ins Level sofort einen Sprung aus (Taste noch gehalten).
|
|
Fix: player.jump_lock -- Sprung/Stoss gesperrt, bis die Taste einmal
|
|
losgelassen wurde; nach dem Tuer-Menue gesetzt + Eventqueue geleert.
|
|
|
|
## 26.07.2026 (22) -- Sprunghoehe nachjustiert (Ast/Blatt-Referenz)
|
|
|
|
Stefans Referenz am Haus (W1L1): Tony springt "bis zum Ast", Smacks "bis
|
|
zum Blatt" (das unterm Ast haengt). Aufloesung: im Original haben BEIDE
|
|
dieselbe Sprungkraft (-0x18000 aus dem Binary, ~72px Scheitel) -- der
|
|
Unterschied ist die Koerpergroesse (Tony 56px, Smacks 44px), dadurch
|
|
beruehren die Koepfe verschiedene Ziele. Bei uns fehlten ein paar Pixel
|
|
(SPRITE_SINK=4 + Frame-Diskretisierung): JUMP_VELOCITY -360 -> -380
|
|
(Scheitel gemessen 77px). Verifiziert: Tony-Kopf am Scheitel y=510
|
|
(Ast-Band 499-516), Smacks-Kopf y=522 (Blatt-Band 511-526).
|
|
Nebenfund: smacks_jump-DOSBox-Serie zeigt auch KURZE Huepfer (~30px)
|
|
-- das Original hat variable Sprunghoehe (Taste frueh loslassen), steht
|
|
noch auf der Offen-Liste.
|
|
|
|
## 26.07.2026 (23) -- Sprunghoehe 2. Feinjustage
|
|
|
|
Stefan: beide beruehrten fast nur das Blatt; Ziel: Smacks-Kopf ans Blatt,
|
|
Tony-Kopf an den Ast, jeweils aus dem Stand. JUMP_VELOCITY -380 -> -400
|
|
(Scheitel gemessen 85.6px). Kopf am Scheitel: Tony y=502 (Ast-Holz),
|
|
Smacks y=514 (Blatt) -- per Level-Render am Baum verifiziert
|
|
(apex_TONY/SMACKS.png). Sprungkraft bleibt fuer beide gleich; die
|
|
Zielhoehen ergeben sich rein aus den Koerpergroessen (56 vs 44 px).
|
|
|
|
## 26.07.2026 (24) -- ARE-FORMAT GEKNACKT + Smacks' Wasserblasen (v1)
|
|
|
|
Anlass: Stefan will Blasen (Gegner fangen) + Gegner mit Sterbeanimation
|
|
-> dafuer braucht es die echten Gegner-/Item-Positionen = ARE-Format.
|
|
|
|
### ARE-Struktur (Decoder: tools/are_dump.py)
|
|
@8..48 Header: 10 BE-u16-Paare (Bedeutung teils offen)
|
|
@352 SEKTOR-TABELLE: ceil(map_px/64) x ceil(map_px_h/64) BE-u16-
|
|
Offsets (W1L1: 55x12=660), ffff = leer, sonst Offset+352 ->
|
|
Objektliste des 64x64-Sektors
|
|
Liste: ffff-Marker, dann 3xBE-u16-Records [Typ][dx][dy] (Pixeloffset
|
|
im Sektor) bis zum naechsten ffff
|
|
W1L1: 193 Objekte. Verifizierte/plausible Typen:
|
|
151 = Cerealie (x100 -- der HUD-Zaehler!), 154 = Cerealie im Wasser
|
|
(x37, liegt in den Unterwasser-Clustern)
|
|
199 = TUER (exakt auf unserer Haus-Tuer Tile 12,37!)
|
|
71/72/73/76 = ?-Box-Inhalte (sitzen auf ctype-4-Tiles => ctype 4 =
|
|
?-BOX, nicht "Item" wie bisher angenommen!)
|
|
194..208 = Level-Moebel/Deko (Lampen etc.), 101/102 = Levelende?
|
|
1/2/3/11/12/17/18/20/31 = vermutlich GEGNER-Spawns (Typ->BOB-Zuordnung
|
|
per DOSBox-Abgleich offen; Kandidaten: A-O.BOB, 'ani'-Ladeliste)
|
|
|
|
### Wasserblasen v1 (game/level.py)
|
|
ALT beim Schwimmen/Tauchen (nur mit Slots 29-31 = Smacks): Blase waechst
|
|
29->30->31, treibt in Blickrichtung (vx 55, Daempfung), steigt nach 0.5s,
|
|
platzt an der Oberflaeche oder nach 4s. Gegner-Fang (Blase + rauswerfen)
|
|
kommt zusammen mit den Gegnern, sobald die Typ-Zuordnung steht. Gegner-
|
|
Sterbeanimationen (wie bei den Spielfiguren) ebenfalls dann.
|
|
|
|
## 26.07.2026 (25) -- Levelzeit-Timeout hat jetzt Konsequenzen
|
|
|
|
Stefans Fund: Timer lief runter, aber bei 0 passierte nichts. Fix in
|
|
run_level: time_left wird am Rundenanfang berechnet; bei <= 0 startet die
|
|
Sterbeanimation (wie Herzen leer), danach Leben -1, Respawn mit vollen
|
|
Herzen und FRISCHER Levelzeit (start-Reset auch beim Respawn nach
|
|
normalem Tod). E2E: Levelzeit auf 2s gestutzt -> 3 Versuche + Rueckkehr
|
|
zur Karte nach 13.4s. --once exit 0.
|
|
|
|
## 26.07.2026 (26) -- Steh-Pose korrigiert: Slot 17 (frontal), nicht Slot 8
|
|
|
|
Stefans Feedback: "Stand-Animation passt bei keinem Charakter". DOSBox-
|
|
Abgleich (stand_timeline.png, Tony steht nach Levelstart): das Original
|
|
steht FRONTAL (Bauch zur Kamera) = Slot 17 (Tony BOB 34); Slot 8 (BOB 16,
|
|
Seiten-/Rueckenpose) ist nur die kurze Uebergangspose beim Anhalten/
|
|
Landen (Original-Tabelle [4][8,8,8] = ~0.17s). Umgesetzt: SLOT_IDLE=17,
|
|
Slot 8 laeuft 0.17s beim Anhalten, Idle-Warteanimation (Schachtel) jetzt
|
|
nach 4s (Timeline: ~4s). Slot 18 = zweite Frontal-Pose (Variante), noch
|
|
ungenutzt. Damit ist auch klar: Slot-17-Frames sind KEINE Schadensposen.
|
|
Alle 4 Charaktere haben Slot 17 (Coco sogar als Richtungs-Paar).
|
|
|
|
## 26.07.2026 (27) -- Steh-Pose, die Zweite: frontal NUR am Spawn
|
|
|
|
Stefans Screenshots (unsere frontale Pose vs. Original seitlich):
|
|
Eintrag (26) war ueberkorrigiert. Original-Verhalten:
|
|
- Spawn/Charakterwechsel, noch nie bewegt -> FRONTAL (Slot 17)
|
|
(deshalb zeigten die sess_level-Frames vom Levelstart frontal)
|
|
- nach der ersten Bewegung -> SEITLICH in Blickrichtung (Slot 8)
|
|
Umgesetzt ueber player.moved-Flag (Reset bei set_character/Respawn).
|
|
Wichtig fuers Protokoll: die DOSBox-"Checks" liefen gegen GESPEICHERTE
|
|
Frameserien aus frueheren Capture-Sessions (Scratchpad), nicht live --
|
|
und die zeigten nur den Spawn-Fall. Idle-Warteanimation (Schachtel nach
|
|
4s) unveraendert.
|
|
|
|
## 26.07.2026 (28) -- Slot 8/9 = Sprungphasen, seitliches Stehen = Slot 0
|
|
|
|
Stefans Zuordnung: Tony 016.png (Slot 8) = Sprung AUFWAERTS, 018.png
|
|
(Slot 9) = FALLEN. Seitliche Steh-Pose (nach Bewegung) = Slot 0 (Beine
|
|
zusammen, zugleich erster Walkframe -- per Sprite-Vergleich mit Stefans
|
|
Original-Screenshots bestaetigt, auch bei Smacks). Damit:
|
|
Sprung = Hocke(10) -> aufwaerts(8) -> abwaerts(9); Stehen = frontal(17)
|
|
am Spawn, seitlich(0) nach Bewegung. Die Tabelle [4][8,8,8] ist also die
|
|
Aufwaerts-Sprungpose (Set beim Absprung), nicht "Idle" -- Eintrag (26)/
|
|
(27) entsprechend ueberholt.
|
|
|
|
## 26.07.2026 (29) -- TIME-OUT-Tafel + Sprungweite statt -hoehe
|
|
|
|
- Stefans Screenshot: Original zeigt bei abgelaufener Zeit eine
|
|
TIME-OUT-Tafel (Menue-Rahmen, weisse Box, gelbe Schrift). Umgesetzt:
|
|
2.5s Tafel (Taste bricht ab), dann Leben -1 + Respawn mit frischer
|
|
Zeit; Sterbeanimation entfaellt beim Timeout.
|
|
- Sprung-Korrektur "nicht hoeher sondern weiter": JUMP_VELOCITY zurueck
|
|
auf -400 (Scheitel 86px), stattdessen AIR_SPEED_FACTOR=1.27 (in der
|
|
Luft schnelleres Horizontaltempo) -> Sprungweite 92 -> 114px (~+1
|
|
Blattlaenge, Stefans Live-DOSBox-Vergleich).
|
|
- DOSBox-Durchspiel-Aufnahme W1L1 laeuft (capture3.py mit down/up-
|
|
Timeline: Rechts halten + periodische Spruenge, Idle-Fenster,
|
|
Links-Passage; ~1800 Frames a 0.2s nach scratchpad/w1l1_run/).
|
|
|
|
## 26.07.2026 (30) -- W1L1-Durchspiel-Aufnahme + Wasser-Timing GEMESSEN
|
|
|
|
DOSBox-Aufnahme (capture3.py, down/up-Timeline, 1265 Frames a 0.29s,
|
|
scratchpad/w1l1_run/): Boot -> Menue -> Level klappte; die Blind-
|
|
Steuerung kam allerdings nur bis zur Saeulen-Passage (~x1500) und
|
|
verbrachte viel Zeit am Haus. Trotzdem ergiebig:
|
|
|
|
- WASSER-SCHADEN NACHGEMESSEN: erstes Herz SOFORT beim Eintauchen
|
|
(innerhalb 0.3s Messraster), danach exakt alle 13 Frames = 3.77s
|
|
(Herz-Pixelzaehlung im HUD, konstant ueber 5 Verluste).
|
|
-> WATER_DAMAGE_EVERY = 3.8 (statt 1.5); Sofortschaden bestaetigt.
|
|
- Cornflakes-Einsammeln bestaetigt (Zaehler 003 nach Saeulen-Passage).
|
|
- GELBE BEWEGLICHE PLATTFORM gesichtet (PLATFW1!) ueber den Saeulen.
|
|
- Respawn fuellt Herzen wieder auf (Pixelzaehlung steigt).
|
|
- Keine Gegner im erreichten Abschnitt sichtbar (Spawns liegen weiter
|
|
rechts: ARE-Typen 17/18/31 ab x~1700).
|
|
TODO naechste Aufnahme: bessere Sprung-Timeline (Saeulen-Gaps schaffen),
|
|
um bis zu den Gegner-Spawns und zum Levelende zu kommen.
|
|
|
|
## 26.07.2026 (31) -- Karten-Fortschrittsanzeige + Level-Zusammenfassung (Stefans Durchspiel-Referenzen)
|
|
|
|
Stefan hat Level 1 im Original durchgespielt. Zwei Referenz-Screenshots:
|
|
|
|
1. LEVEL-ZUSAMMENFASSUNG (nach Levelende): Tafel mit SCORE, "MAXIMUM n /
|
|
GESAMMELT n" (Cerealien), "VITAMINE n", gruene Buchstaben-Kaestchen
|
|
(=> die A-O.BOBs sind VITAMIN-BUCHSTABEN! A, B1, C ... -- passt zu
|
|
VITAMIN.SRB und ARE-Typ 12?), "n x [Kopf]" (Bonusleben?), links/rechts
|
|
Gruppenbilder der 4 Charaktere. TODO: Screen nachbauen, sobald es
|
|
Levelende + Sammel-Zaehler gibt.
|
|
2. KARTE nach Durchspielen: erledigte Punkte werden BLAU (KARTE2), der
|
|
gelaufene Weg zwischen zwei Leveln = Spur kleiner ORANGER Punkte
|
|
(KARTE1) entlang der Original-Wegpunkte, noch nicht erreichte Level
|
|
bleiben UNSICHTBAR. UMGESETZT in worldmap.draw(): i < current = blau,
|
|
Pfade 1..current = Punktspur (Wegpunkte um Label-Offset -5,-16
|
|
versetzt), Rest unsichtbar. Interim: "erledigt" = links vom Cursor
|
|
(echtes Abschluss-Tracking kommt mit dem Levelende-Feature).
|
|
|
|
## 26.07.2026 (32) -- Seitliche Steh-Pose = Slot 10 (Stefans Frame-Fund)
|
|
|
|
Stefan: Steh-Pose nach dem Laufen = 020.png bei Tony UND Smacks = Slot 10
|
|
(nicht Slot 0). Macht ruecklickend alles konsistent: Spawn-Tabelle
|
|
[70][10,11,10] = stehen/Arm-hoch/stehen, Schachtel-Idle endet [...,10x5]
|
|
= zurueck zum Stehen. Slot 10 war faelschlich als "Absprung-Hocke"
|
|
belegt -- die Hocke zeigt jetzt wieder den Duck-Frame (Slot 12, wie die
|
|
urspruengliche, abgenommene Version). SLOT_SQUAT entfernt.
|
|
|
|
## 26.07.2026 (33) -- Kartenspur: blau zwischen fertigen Leveln
|
|
|
|
Stefan hat Level 2 durchgespielt: der Weg zwischen zwei FERTIGEN Leveln
|
|
wird BLAU (KARTE3 -- damit ist auch dieser Sprite zugeordnet), nur der
|
|
Weg zum aktuellen, noch nicht geschafften Punkt bleibt orange (KARTE1).
|
|
Umgesetzt; Render mit current=2 deckungsgleich mit Stefans Screenshot.
|
|
Alle 4 KARTE-Punktsprites sind damit erklaert: 0=gross orange (aktuell),
|
|
2=gross blau (fertig), 1=kleine orange Spur, 3=kleine blaue Spur.
|
|
|
|
## 26.07.2026 (34) -- Kein Duck-Blitzer beim Sprung, Stand nach Spawn = Slot 10
|
|
|
|
Stefan: (1) beim Springen/Aufkommen blitzte kurz der Duck-Frame auf --
|
|
die "Absprung-Hocke" komplett entfernt (Sprung ist jetzt nur 8 hoch /
|
|
9 runter). (2) Nach der Arm-hoch-Spawn-Pose kam die frontale 034.png
|
|
(Slot 17, "Beine verdreht") -- jetzt kommt immer die seitliche 020.png
|
|
(Slot 10). Slot 17 (frontal) ist damit nirgends mehr in Gebrauch;
|
|
die sess_level-"Frontal am Levelstart"-Deutung aus Eintrag (26) war
|
|
wohl eine Fehlinterpretation der kleinen Crops.
|
|
|
|
## 26.07.2026 (35) -- Levelende v1 + Tafeln bleiben stehen
|
|
|
|
Stefans Regeln: TIME-OUT-Tafel (und Levelende-Tafel) bleiben STEHEN bis
|
|
Enter/Leertaste (_wait_panel). NEU Levelende v1:
|
|
- Exit-Zone erreicht -> Zusammenfassungstafel (SCORE/MAXIMUM/GESAMMELT/
|
|
VITAMINE/"0 X" -- nach Stefans Original-Screenshot; Werte noch 0, bis
|
|
Items gebaut sind; MAXIMUM = echte ARE-Zaehlung 151+154) -> 'completed'
|
|
-> intro.py laesst die Kartenfigur zum naechsten Punkt weiterwandern
|
|
(Punkt + Spur werden blau, Original-Regeln aus (31)/(33)).
|
|
- Exit-Zone W1L1 = SCHAETZUNG (rechtes Ende, um ARE-Objekt 194 bei
|
|
(3168,432)): exit_px=(3140,300,348,452). Echte Stelle + Aussehen des
|
|
Ausgangs von Stefan/DOSBox zu verifizieren!
|
|
- MAXIMUM-Diskrepanz: wir zaehlen 137 (151er+154er), Stefans Original-
|
|
Screen zeigte 158 -- vermutlich zaehlen ?-Box-Inhalte (71-76) und/oder
|
|
15x-Typen mit. Offen.
|
|
- ctype-Nibble-12 (44) liegt NICHT am Levelende (2 Tiles bei (91/99,17))
|
|
-- also kein Exit-Marker; Bedeutung offen. Bit 8 steckt zudem in
|
|
Standard-Boden (40=32+8) => Coco-Ast-Trigger (Bit 8) ist FALSCH und
|
|
muss neu bestimmt werden (aktuell greift Coco evtl. am Boden?? pruefen).
|
|
|
|
## 26.07.2026 (36) -- Stefans Level-1-Video (dosbox/capture/start_000.avi, 70fps ZMBV)
|
|
|
|
4.5 Min, 19098 Frames, verlustfrei + Ton. Erste Auswertung (Kontaktboegen
|
|
lsheet_0..6, Feinanalyse folgt -- Stefan ist bewusst nicht jede Ecke
|
|
abgelaufen):
|
|
|
|
- LEVELAUSGANG W1L1: dunkelrote TOR-/HOEHLENOEFFNUNG in Steinbogen in
|
|
der Blaetterwand oben rechts (Video ~246-249s, Restzeit 6:26). Figur
|
|
geht HINEIN -> Summary. Exakte Tile-Position noch gegen Map-Render
|
|
matchen; exit_px-Schaetzung ersetzen. Ausgang ist eine begehbare
|
|
Oeffnung, kein unsichtbarer Rand!
|
|
- SUMMARY-SCREEN IST ANIMIERT: GESAMMELT zaehlt hoch (10->62->115->141)
|
|
waehrend SCORE mitzaehlt (1100->2410) = Kekse werden live in Punkte
|
|
umgerechnet; danach erscheinen die VITAMIN-BUCHSTABEN nacheinander
|
|
(A,B1 -> C -> E als gruene Kaestchen). MAXIMUM diesmal 150 (Durchlauf
|
|
zuvor 158!) -> MAXIMUM ist offenbar lauf-/inhaltsabhaengig (?-Boxen?).
|
|
- CHARAKTERWAHL im Original (Video 21-22s): Tafel-Stil (weisse Box,
|
|
Menue-Rahmen) mit GANZKOERPER-Sprites der 4 Figuren + Namen darunter;
|
|
nicht verfuegbare (Coco/Toucan) sind GRAU. Unser WECH-Kopf-Menue
|
|
entsprechend umbauen (die grauen Ganzkoerper = vermutlich eigene
|
|
Sprites oder Palette-Swap; pruefen).
|
|
- Stefan spielte ab der Tuer SMACKS; braunes fliegendes Objekt bei ~38s
|
|
am Baum = erster GEGNER-Kandidat (Feinanalyse ausstehend); Baum-
|
|
Innenraum voller Cerealien (~33-36s) mit Gesicht in den Blaettern.
|
|
- Video + Frames (lvid/, 2fps) liegen im Scratchpad; Vollaufloesung bei
|
|
Bedarf erneut aus AVI ziehen (ffmpeg, Frame-genau).
|
|
NAECHSTE SCHRITTE aus dem Video: Exit-Position exakt bestimmen, Gegner-
|
|
Frames einsammeln (Typ->BOB), Summary-Animation nachbauen, Charakter-
|
|
wahl-Tafel nachbauen. Intro-Feinvergleich (Rauser/Vorhang) macht Stefan
|
|
als separate Aufnahme spaeter.
|