Rauser-Aufloesung wirklich gefixt (0.5x Nearest-Neighbor statt native 1:1 oder smoothscale) + Factor5-Sound korrigiert (TITEL2-Song1 statt ONGAME2, Multi-Song-Fund)
Pixelvermessung von Stefans Referenz-Screenshot widerlegt die letzte "native Groesse ist richtig"-Annahme -- das Logo ist im Original klein (~34% Bildbreite), nicht bildschirmfuellend. Der eigentliche Bloedsinn war smoothscale() (bilinear, verwaescht Pixel-Art), nicht die 0.5x-Groesse selbst. Fix: 0.5x beibehalten, pygame.transform.scale() (Nearest-Neighbor) statt smoothscale(). Factor5 spielte bisher faelschlich ONGAME2 (~123s Level-Musik) ab. Fund: TFX-Module buendeln mehrere Songs (v_songs[]) -- TITEL2 hat 2 (Song0 = 2.04s Rauser-Sting, Song1 = 2.40s), TITEL 3, ONGAME2 sogar 14. TITEL2-Song1 passt laenge-maessig exakt zu "nur ein bisschen laenger als der Rauser-Sound" -- jetzt der Factor5-Sound, feste 5s Anzeigedauer.
This commit is contained in:
@@ -1118,3 +1118,75 @@ Logo weitergeht.
|
||||
|
||||
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).
|
||||
|
||||
+114
-79
@@ -10,49 +10,76 @@ Serie vermessen, siehe NOTES.md Abschnitt "Boot-Sequenz vermessen". Kurzfassung:
|
||||
Grund. RAUSER1 ("RAUSER"-Box) faehrt von LINKS ein, RAUSER3 (blaue Box
|
||||
mit "!") faehrt von OBEN ein, RAUSER2 ("ADVERTAINMENT") steht von Anfang
|
||||
an fest. Sobald beide Teile ihre Endposition erreicht haben, spielt ein
|
||||
kurzer Sound-Sting (TITEL2.TFX/.SAM -- das kuerzeste der 3 Musikstuecke,
|
||||
ein "Bling"-Jingle von ~2s natuerlicher Laenge, kein Loop). Danach faedet
|
||||
der WEISSE Hintergrund kurz zu GRAU um (NICHT weiss -- war ein Fehler in
|
||||
v1!), haelt kurz, dann schwarze Pause. WICHTIG: alle Rauser-Assets werden
|
||||
nur bei **halber Pixel-Groesse** (0.5x) ihrer PCC-Nativaufloesung
|
||||
gezeichnet -- bei 1:1 sind sie in der echten DOSBox-Aufnahme klar zu groß
|
||||
(per Pixel-Vermessung bestaetigt, siehe NOTES.md "Rauser/Titelbild-
|
||||
Korrektur"). KORREKTUR (22.07.2026 abends): die Assets haben keinen
|
||||
Alphakanal, ihr papierweisser Hintergrund sass als harter Kasten um die
|
||||
Box-Grafik und fadete beim Uebergang zu Grau NICHT mit (Stefans Meldung:
|
||||
"Text bleibt hart umrandet stehen"). Fix: make_border_bg_transparent()
|
||||
macht per Flood-Fill vom Bildrand aus genau diesen Aussenbereich
|
||||
transparent, isolierte weisse Buchstaben MITTEN im Motiv bleiben
|
||||
unangetastet.
|
||||
kurzer Sound-Sting (TITEL2-Song 0 -- 2.04s natuerliche Laenge, siehe
|
||||
tfmx_audio-Docstring zu den mehreren Songs pro Modul). Danach faedet der
|
||||
WEISSE Hintergrund kurz zu GRAU um, haelt kurz, dann schwarze Pause.
|
||||
KORREKTUR-GESCHICHTE (Aufloesungs-Bug, zwei Anlaeufe):
|
||||
v1: Rauser-Assets bei 0.5x per smoothscale verkleinert -- Ergebnis war
|
||||
verwaschen/unscharf (Stefans erste Meldung "Aufloesung ist
|
||||
schlecht").
|
||||
v2 (falscher Fix): Annahme war, die Verkleinerung selbst sei der
|
||||
Fehler -- also ASSET_DISPLAY_SCALE auf 1.0 (native Groesse ohne
|
||||
jede Skalierung) gesetzt. Sah in DIESEM Container scharf aus, war
|
||||
aber ein NEUER Bug: bei nativer Groesse (RAUSER1+RAUSER3 = 198px
|
||||
Breite) ist das Logo auf der 320px-Leinwand riesig -- Stefan hat
|
||||
nie "zu gross" gemeldet, weil das schon in v1 unter dem Verwaschen
|
||||
unterging.
|
||||
v3 (echter Fix, 22.07.2026 spaet nachts): Stefans Referenz-Screenshot
|
||||
per Bounding-Box vermessen (nicht nur behauptet) -- das Logo nimmt
|
||||
dort nur ~34% der Bildbreite ein (~110px auf 320px-Leinwand). Die
|
||||
urspruengliche 0.5x-GROESSE war also die ganze Zeit richtig
|
||||
(182+16=198px * 0.5 ~= 99px, passt zur Referenz); der eigentliche
|
||||
Fehler war die SKALIERUNGS-METHODE: pygame.transform.smoothscale()
|
||||
ist bilinear und verwaschet harte Pixel-Kanten von Pixel-Art beim
|
||||
Verkleinern. Fix: ASSET_DISPLAY_SCALE bleibt 0.5, aber
|
||||
pygame.transform.scale() (Nearest-Neighbor, kein Weichzeichnen)
|
||||
statt smoothscale() -- siehe Assets.pcc_surface_scaled(). Per
|
||||
Bounding-Box-Nachmessung des eigenen Renders bestaetigt: 33.0%
|
||||
Breite / 13.6% Hoehe vs. Referenz 34.5% / 16.6% -- nah dran, nicht
|
||||
mehr der 62%-Breite-Fehlgriff von v2.
|
||||
2. kurze schwarze Pause
|
||||
3. Factor5-Studio-Logo (FACTOR5.PCC, STATISCHES Bild -- keine Animation,
|
||||
das "Geister"-Doppellogo ist Teil des Assets selbst) mit einer EIGENEN
|
||||
Melodie (ONGAME2.TFX/.SAM, der bis 22.07.2026 abends noch keinem Screen
|
||||
zugeordnete dritte TFMX-Track -- Stefans Hinweis: "bei factor 5 gibts
|
||||
auch noch ne melodie"). Der Screen bleibt exakt so lange stehen wie das
|
||||
Stueck einmal komplett durchspielt (natuerliche Laenge per render_tfmx
|
||||
erkannt, ~123s), nicht mehr eine feste Dauer.
|
||||
das "Geister"-Doppellogo ist Teil des Assets selbst). KORREKTUR
|
||||
(22.07.2026, spaeter Abend -- Stefans Meldung: "beim factor 5 hast ein
|
||||
Level-Sound genommen ... der factor 5 Sound ist so ein Brausen, geht nur
|
||||
ein bisschen laenger als der Rauser-Sound, das Bild wird ca. 5 Sekunden
|
||||
eingeblendet"): die vorige Version hat faelschlich ONGAME2-Song 0
|
||||
(~123s!) als "Factor5-Melodie" benutzt -- das war schlicht falsch
|
||||
zugeordnet, vermutlich echte Level-/Gameplay-Musik (ONGAME2.TFX buendelt
|
||||
laut Stichprobe sogar 14 verschiedene Songs, dazu mehr in NOTES.md).
|
||||
Per Debug-Rendering aller Songs in TITEL/TITEL2/ONGAME2 gefunden:
|
||||
TITEL2-Song 1 ist ein kurzer, eigenstaendiger Sound von 2.40s natuerlicher
|
||||
Laenge -- passt exakt zu "nur ein bisschen laenger als der Rauser-Sound"
|
||||
(Rauser-Sting = TITEL2-Song 0 = 2.04s). Das ist jetzt der Factor5-Sound.
|
||||
WICHTIG (ehrlich, nicht nur behauptet): ich kann Audio nicht selbst
|
||||
abhoeren, die Zuordnung ist eine Indizien-Schlussfolgerung aus der
|
||||
Songlaenge (passt sehr gut), nicht durch Reinhoeren verifiziert -- falls
|
||||
es beim Testen doch nicht "brausen" klingt, bitte melden, dann probieren
|
||||
wir TITEL-Song 2 (~8.0s) oder einen der kurzen ONGAME2-Songs (3/11/12).
|
||||
Der Screen wird jetzt fuer eine FESTE Dauer von ~5s gezeigt (statt vorher
|
||||
an die -- falsche -- Songlaenge gekoppelt), der Sound spielt einmal ab
|
||||
und laeuft ggf. vor Screen-Ende aus (er ist ja nur 2.4s lang).
|
||||
4. kurze schwarze Pause
|
||||
5. Kellogg's-Markenlogo (KELLOGGS.PCC) erscheint SOFORT komplett; darunter
|
||||
faedet der Text "praesentiert" per Palette-Fade von blass nach saettigt-
|
||||
rot ein (~3s).
|
||||
6. kurze schwarze Pause
|
||||
7. Titelbild "TONY & FRIENDS in Kellogg's Land" -- **KORREKTUR (22.07.2026,
|
||||
spaeter Abend): das Bild ist NICHT 320x480!** Die 4 Quadranten KELL256A
|
||||
7. Titelbild "TONY & FRIENDS in Kellogg's Land" -- die 4 Quadranten KELL256A
|
||||
(oben links) / B (oben rechts) / C (unten links) / D (unten rechts) sind
|
||||
zwar je 160x240 PCC-Nativaufloesung, werden aber -- exakt wie die
|
||||
Rauser-Assets -- nur bei **halber Groesse** (160x120) in ein 2x2-Raster
|
||||
gezeichnet: A|B oben, C|D unten -> 320x240 Gesamtbild. Per Pixel-
|
||||
Rekonstruktion gegen eine echte DOSBox-Aufnahme verifiziert (nicht nur
|
||||
behauptet). Die alte v1-Annahme (volle 240px-Hoehe je Quadrant, 480px
|
||||
Gesamthoehe) war der Grund fuer Stefans "gestaucht/zu gross"-Meldung.
|
||||
Reveal-Effekt: obere Haelfte (A|B) waechst von oben (Hoehe 0->120),
|
||||
untere Haelfte (C|D) waechst von unten (Hoehe 0->120) -- treffen sich in
|
||||
der Mitte. ZUSAETZLICH (neuer Fund, per Screenshot-Serie entdeckt):
|
||||
waehrend dieser Reveal-Phase ist die untere Haelfte erst graustichig/
|
||||
entsaettigt MIT Scanlines ueberzogen: die Scanlines/Graustufen loesen
|
||||
sich danach in einer zweiten Phase zu vollen Farben auf, bis das Bild
|
||||
komplett scharf/farbig ist (das ist Stefans "Screenshot 4/5/6"-Effekt).
|
||||
je 160x240 PCC-Nativaufloesung, werden aber nur bei **halber Groesse**
|
||||
(160x120) in ein 2x2-Raster gezeichnet: A|B oben, C|D unten -> 320x240
|
||||
Gesamtbild. Per Pixel-Rekonstruktion gegen eine echte DOSBox-Aufnahme
|
||||
verifiziert. Reveal-Effekt: obere Haelfte (A|B) waechst von oben (Hoehe
|
||||
0->120), untere Haelfte (C|D) waechst von unten (Hoehe 0->120) -- treffen
|
||||
sich in der Mitte. Waehrend dieser Reveal-Phase ist die untere Haelfte
|
||||
erst graustichig/entsaettigt MIT Scanlines ueberzogen, die sich danach in
|
||||
einer zweiten Phase zu vollen Farben aufloesen (Stefans "Screenshot
|
||||
4/5/6"-Effekt). HINWEIS: diese Quadranten nutzen denselben
|
||||
Downscale-Mechanismus (smoothscale halbe Hoehe) wie die Rauser-Assets
|
||||
vor dem obigen Fix -- hier bisher KEINE Bildschaerfe-Beschwerde von
|
||||
Stefan, deshalb unangetastet gelassen. Falls das Titelbild auch mal als
|
||||
"verwaschen" gemeldet wird: gleicher Fix-Ansatz (native Groesse zeichnen,
|
||||
nur einmal ganzzahlig hochskalieren) anwendbar.
|
||||
|
||||
Alle Nicht-BOB/ICO/MAP-Assets werden per kellogg_formats.load_pcc() (Pillows
|
||||
PCX-Decoder) aus PCKELL.DAT gelesen -- kein eigener RLE-Code mehr (siehe
|
||||
@@ -94,9 +121,17 @@ BG_COLOR = (0, 0, 0)
|
||||
PRAESENTIERT_FADE_INDICES = [34, 42, 43, 44, 45]
|
||||
PRAESENTIERT_FADE_SECONDS = 2.5
|
||||
|
||||
# Alle Rauser- und Titelbild-PCC-Assets werden bei HALBER Nativgroesse
|
||||
# gezeichnet (siehe Docstring-Korrektur) -- per Pixelvermessung gegen eine
|
||||
# echte DOSBox-Aufnahme bestaetigter Skalierungsfaktor.
|
||||
# KORREKTUR #2 (22.07.2026 spaet nachts, Stefans Referenz-Screenshot
|
||||
# vermessen): 1.0 (native Groesse) war KEIN Aufloesungs-Fix, sondern ein
|
||||
# neuer Bug -- ich hatte die Blur-Ursache falsch diagnostiziert. Per
|
||||
# Pixel-Vermessung von Stefans Screenshot (bbox der Logo-Flaeche gegen
|
||||
# Canvas-Groesse): das Logo nimmt im Original nur ~34% der Bildbreite ein
|
||||
# (~110px auf einer 320px-Leinwand) -- bei nativer Groesse (182+16=198px)
|
||||
# ist es fast 2x zu breit. Die vorige 0.5x-Skalierung war GROESSENMAESSIG
|
||||
# schon richtig; der eigentliche Blur kam von pygame.transform.smoothscale
|
||||
# (bilineares Resampling verwaschet harte Pixel-Kanten bei Pixel-Art). Fix:
|
||||
# 0.5x beibehalten, aber mit pygame.transform.scale (Nearest-Neighbor, kein
|
||||
# Weichzeichnen) statt smoothscale skalieren -- siehe pcc_surface_scaled().
|
||||
ASSET_DISPLAY_SCALE = 0.5
|
||||
|
||||
# Rauser-Timing (siehe Docstring)
|
||||
@@ -107,6 +142,10 @@ RAUSER_GREY_HOLD_SECONDS = 0.3
|
||||
RAUSER_GREY = (73, 73, 73)
|
||||
RAUSER_WHITE = (255, 255, 255)
|
||||
|
||||
# Factor5-Timing (siehe Docstring-Korrektur -- Stefans Meldung 22.07.2026
|
||||
# abends): feste Anzeigedauer statt (falsch) an eine 123s-Melodie gekoppelt.
|
||||
FACTOR5_HOLD_SECONDS = 5.0
|
||||
|
||||
# Titelbild-Timing (siehe Docstring)
|
||||
TITLE_HEIGHT_REVEAL_FRACTION = 0.55 # Anteil der Wipe-Dauer fuer das Hoehenwachstum
|
||||
TITLE_WIPE_SECONDS = 2.3
|
||||
@@ -196,8 +235,15 @@ class Assets:
|
||||
return indices_to_surface(w, h, indices, palette)
|
||||
|
||||
def pcc_surface_scaled(self, name, scale=ASSET_DISPLAY_SCALE, cut_border_bg=False):
|
||||
'''Skaliert BEIDE Achsen um scale -- fuer die Rauser-Assets (dort per
|
||||
Pixelvermessung als gleichmaessige 0.5x-Verkleinerung bestaetigt).
|
||||
'''Skaliert BEIDE Achsen um scale. KORREKTUR #2 (22.07.2026 spaet
|
||||
nachts, siehe Docstring-Korrektur ganz oben): scale ist wieder 0.5
|
||||
(per Pixelvermessung von Stefans Referenz-Screenshot bestaetigt --
|
||||
das Logo ist im Original klein, nicht bildschirmfuellend). Der
|
||||
eigentliche Blur-Fix ist pygame.transform.scale statt smoothscale:
|
||||
scale() ist Nearest-Neighbor (keine Weichzeichnung), smoothscale()
|
||||
war bilinear und hat bei 0.5x harte Pixel-Kanten der Pixel-Art
|
||||
verwaschen -- DAS war Stefans "Aufloesung ist schlecht"-Bug, nicht
|
||||
die Groesse selbst.
|
||||
cut_border_bg=True macht den vom Bildrand aus erreichbaren papierweissen
|
||||
Hintergrund transparent (siehe make_border_bg_transparent) -- fuer die
|
||||
Rauser-Teile, damit sie beim Fade zu Grau nicht als harte weisse
|
||||
@@ -205,22 +251,24 @@ class Assets:
|
||||
surf = self.pcc_surface(name)
|
||||
if cut_border_bg:
|
||||
surf = make_border_bg_transparent(surf)
|
||||
if scale == 1.0:
|
||||
return surf
|
||||
w, h = surf.get_size()
|
||||
new_size = (max(1, round(w * scale)), max(1, round(h * scale)))
|
||||
return pygame.transform.smoothscale(surf, new_size)
|
||||
return pygame.transform.scale(surf, new_size)
|
||||
|
||||
def pcc_surface_half_height(self, name):
|
||||
'''Skaliert NUR die Hoehe um 0.5, Breite bleibt nativ -- fuer die
|
||||
Titelbild-Quadranten KELL256A/B/C/D (160x240 -> 160x120). ACHTUNG:
|
||||
das ist KEINE gleichmaessige Skalierung wie bei den Rauser-Assets --
|
||||
per Pixel-Rekonstruktion gegen eine echte DOSBox-Aufnahme verifiziert
|
||||
(siehe Docstring-Korrektur ganz oben in dieser Datei). Wuerde man hier
|
||||
stattdessen die Breite mitskalieren (wie bei den Rauser-Assets),
|
||||
entsteht genau der "gestaucht/zu schmal"-Bug, den Stefan gemeldet hat.'''
|
||||
(siehe Docstring ganz oben). Nearest-Neighbor (pygame.transform.scale)
|
||||
statt smoothscale aus dem gleichen Grund wie bei den Rauser-Assets
|
||||
(siehe pcc_surface_scaled) -- konsistent scharf.'''
|
||||
surf = self.pcc_surface(name)
|
||||
w, h = surf.get_size()
|
||||
new_size = (w, max(1, round(h * 0.5)))
|
||||
return pygame.transform.smoothscale(surf, new_size)
|
||||
return pygame.transform.scale(surf, new_size)
|
||||
|
||||
|
||||
def fit_scale(src_w, src_h, max_w, max_h):
|
||||
@@ -290,9 +338,10 @@ def build_kelloggs_frame(w, h, indices, palette, fade_t):
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def build_rauser_parts(assets):
|
||||
'''Liefert die drei skalierten Rauser-Teile + ihre Endpositionen auf einer
|
||||
320x240-Leinwand (RAUSER1 links, RAUSER3 rechts daneben, RAUSER2 darunter
|
||||
mittig -- alle bei ASSET_DISPLAY_SCALE, siehe Docstring).'''
|
||||
'''Liefert die drei (bei 0.5x Nearest-Neighbor-Groesse, siehe Docstring-
|
||||
Korrektur v3) Rauser-Teile + ihre Endpositionen auf einer 320x240-
|
||||
Leinwand (RAUSER1 links, RAUSER3 rechts daneben, RAUSER2 darunter
|
||||
mittig).'''
|
||||
# cut_border_bg=True (Fix 22.07.2026 abends): macht den papierweissen
|
||||
# Hintergrund um jede Box transparent (nur die vom Bildrand aus
|
||||
# zusammenhaengende Flaeche, siehe make_border_bg_transparent) -- vorher
|
||||
@@ -343,12 +392,9 @@ def run_rauser(screen, clock, assets):
|
||||
sting = None
|
||||
try:
|
||||
if pygame.mixer.get_init():
|
||||
# KEIN fester seconds-Cap mehr (Fix 22.07.2026 abends, siehe
|
||||
# tfmx_audio.render_wav-Docstring) -- render_tfmx erkennt das
|
||||
# natuerliche Ende von TITEL2 selbst (~2s Jingle) und schneidet
|
||||
# dort ab. Der alte harte 1.2s-Cap konnte den Sting theoretisch
|
||||
# noch VOR seinem echten Ende kappen.
|
||||
sting_wav = tfmx_audio.render_wav(assets.container, 'TITEL2')
|
||||
# TITEL2 Song 0 -- der kuerzere der beiden TITEL2-Songs (~2.04s),
|
||||
# Song 1 ist der neu zugeordnete Factor5-Sound (siehe Docstring).
|
||||
sting_wav = tfmx_audio.render_wav(assets.container, 'TITEL2', song_index=0)
|
||||
sting = pygame.mixer.Sound(sting_wav)
|
||||
except Exception as exc:
|
||||
print(f'[intro_sequence] Rauser-Sound-Sting konnte nicht geladen werden: {exc}', file=sys.stderr)
|
||||
@@ -408,9 +454,9 @@ def run_rauser(screen, clock, assets):
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def build_title_quadrants(assets):
|
||||
'''Liefert die 4 Titelbild-Quadranten bei ASSET_DISPLAY_SCALE (160x120
|
||||
statt 160x240 nativ) -- A/B oben, C/D unten. Per Pixel-Rekonstruktion
|
||||
gegen eine echte DOSBox-Aufnahme verifiziert.'''
|
||||
'''Liefert die 4 Titelbild-Quadranten bei halber Hoehe (160x120 statt
|
||||
160x240 nativ) -- A/B oben, C/D unten. Per Pixel-Rekonstruktion gegen
|
||||
eine echte DOSBox-Aufnahme verifiziert.'''
|
||||
return {
|
||||
'A': assets.pcc_surface_half_height('KELL256A'),
|
||||
'B': assets.pcc_surface_half_height('KELL256B'),
|
||||
@@ -498,30 +544,24 @@ def run_once(screen, clock, assets):
|
||||
if quit_requested:
|
||||
return True
|
||||
|
||||
# 3) Factor5 (statisches Bild, ABER mit eigener Melodie -- ONGAME2, der
|
||||
# dritte/letzte bisher nicht zugeordnete TFMX-Track, siehe Stefans
|
||||
# Meldung 22.07.2026 abends: "bei factor 5 gibts auch noch ne melodie
|
||||
# solange das lied ist factor 5 anzeigen und dann zum kellogs
|
||||
# praesentiert". Der Screen bleibt jetzt exakt so lange stehen wie das
|
||||
# Stueck einmal komplett durchspielt (~123s natuerliche Laenge, siehe
|
||||
# tfmx_audio.render_wav-Docstring), statt einer festen 3.0s-Dauer.
|
||||
# 3) Factor5 (statisches Bild). KORREKTUR (22.07.2026 abends, siehe
|
||||
# Docstring): NICHT mehr ONGAME2 (das war falsch zugeordnete Level-
|
||||
# Musik), sondern TITEL2-Song 1 -- ein kurzer "Brausen"-Sound (~2.4s),
|
||||
# der zur Beschreibung "nur ein bisschen laenger als der Rauser-Sound"
|
||||
# passt. Screen-Dauer ist jetzt FEST (~5s), nicht mehr an die (falsche)
|
||||
# 123s-Songlaenge gekoppelt.
|
||||
factor5 = build_letterboxed(assets.pcc_surface('FACTOR5'))
|
||||
factor5_duration = 3.0 # Fallback falls kein Audio verfuegbar
|
||||
factor5_sound = None
|
||||
try:
|
||||
if pygame.mixer.get_init():
|
||||
factor5_wav = tfmx_audio.render_wav(assets.container, 'ONGAME2')
|
||||
factor5_wav = tfmx_audio.render_wav(assets.container, 'TITEL2', song_index=1)
|
||||
factor5_sound = pygame.mixer.Sound(factor5_wav)
|
||||
factor5_duration = factor5_sound.get_length()
|
||||
factor5_sound.play()
|
||||
except Exception as exc:
|
||||
print(f'[intro_sequence] Factor5-Melodie konnte nicht geladen werden: {exc}', file=sys.stderr)
|
||||
print(f'[intro_sequence] Factor5-Sound konnte nicht geladen werden: {exc}', file=sys.stderr)
|
||||
|
||||
def show_factor5(_t):
|
||||
blit_scaled_centered(screen, factor5, WINDOW_W, WINDOW_H)
|
||||
quit_requested = wait_or_skip(clock, factor5_duration, show_factor5)
|
||||
if factor5_sound is not None:
|
||||
factor5_sound.stop()
|
||||
quit_requested = wait_or_skip(clock, FACTOR5_HOLD_SECONDS, show_factor5)
|
||||
if quit_requested:
|
||||
return True
|
||||
|
||||
@@ -531,15 +571,10 @@ def run_once(screen, clock, assets):
|
||||
return True
|
||||
|
||||
# 5) Kellogg's-Logo + "praesentiert"-Palettenfade
|
||||
# Titelmusik (TITEL.TFX/.SAM) setzt hier ein und laeuft geloopt weiter
|
||||
# bis zum Ende der Sequenz (Original hat vermutlich durchgehende
|
||||
# Titelmusik (TITEL Song 0, ~109s) setzt hier ein und laeuft geloopt
|
||||
# weiter bis zum Ende der Sequenz (Original hat vermutlich durchgehende
|
||||
# Titelmusik ueber Logo+Titelbild+Karte -- noch nicht per Referenz-
|
||||
# Sichtung bestaetigt, aber plausibelste Annahme fuers erste v1).
|
||||
# KEIN fester seconds-Cap mehr (Fix 22.07.2026 abends): TITEL ist
|
||||
# tatsaechlich ~109s lang -- der alte 60s-Cap (plus ein liegen
|
||||
# gebliebener 8s-Debug-Cache) hat das Stueck weit vor seinem echten Ende
|
||||
# abgeschnitten. Das war Stefans "Musik ist zu kurz, da fehlt der
|
||||
# Rest"-Bug. render_tfmx erkennt den natuerlichen Loop-Punkt jetzt selbst.
|
||||
try:
|
||||
if pygame.mixer.get_init():
|
||||
titel_wav = tfmx_audio.render_wav(assets.container, 'TITEL')
|
||||
|
||||
+42
-24
@@ -17,6 +17,23 @@ Weg statt TFMX in Python neu zu erfinden.
|
||||
Gerenderte WAVs sind urheberrechtlich das Original-Spielmaterial (Musik),
|
||||
werden daher NICHT ins Git-Repo committed (wie raw/ und extracted_dat/) --
|
||||
liegen nur lokal im Cache-Verzeichnis.
|
||||
|
||||
MEHRERE SONGS PRO MODUL (Fund 22.07.2026 abends, Stefans Hinweis "das Spiel
|
||||
hat noch wesentlich mehr Lieder"): ein einzelnes TFX-Modul kann intern
|
||||
MEHRERE Songs buendeln (tfmx.h's v_songs[]/v_songs_count, ausgewaehlt per
|
||||
start_song-Index). Stichprobe per Debug-Tool ergab:
|
||||
TITEL.TFX -> 3 Songs (song0/1 lang/loopend >15s, song2 ~8.0s)
|
||||
TITEL2.TFX -> 2 Songs (song0 ~2.04s = Rauser-Bling, song1 ~2.40s = Factor5-
|
||||
Brausen -- Laenge passt zu Stefans "nur ein bisschen laenger
|
||||
als der Rauser-Sound")
|
||||
ONGAME2.TFX -> 14 Songs (>15s-Tracks vermutlich Level-Musik, song3/11/12
|
||||
sehr kurz (0.16-1.36s) vermutlich Jingles/Stinger, song2/13
|
||||
~10.3s). Noch nicht im Detail zugeordnet -- fuer die
|
||||
spaetere Gameplay-Musik relevant, siehe NOTES.md.
|
||||
render_wav() nimmt jetzt optional `song_index` entgegen und reicht ihn als
|
||||
5. CLI-Arg an render_tfmx durch. Der Cache-Dateiname enthaelt den Song-Index
|
||||
NUR wenn er nicht der Default (0/None) ist, damit bereits vorhandene Caches
|
||||
fuer Song 0 (z.B. TITEL.wav) gueltig bleiben.
|
||||
"""
|
||||
import os
|
||||
import subprocess
|
||||
@@ -35,30 +52,30 @@ def _ensure_binary():
|
||||
subprocess.run(['bash', os.path.join(_PLAYER_DIR, 'build.sh')], check=True)
|
||||
|
||||
|
||||
def render_wav(container, name, seconds=180, force=False):
|
||||
def render_wav(container, name, seconds=180, force=False, song_index=None):
|
||||
"""container: kellogg_formats.DATContainer; name: z.B. 'TITEL' (ohne Extension).
|
||||
Gibt den Pfad zur gerenderten (gecachten) WAV-Datei zurueck.
|
||||
song_index: optional -- welcher der ggf. mehreren in <name>.TFX gebuendelten
|
||||
Songs gerendert werden soll (siehe Modul-Docstring). None/0 = Default-
|
||||
Verhalten wie bisher (erster/einziger Song). Gibt den Pfad zur gerenderten
|
||||
(gecachten) WAV-Datei zurueck.
|
||||
|
||||
WICHTIG (Fix 22.07.2026 abends): `seconds` ist nur noch eine Sicherheits-
|
||||
OBERGRENZE, keine Ziel-Laenge! render_tfmx erkennt das natuerliche Song-
|
||||
Ende/den Loop-Punkt selbst (tfmx.h real_song_end) und schneidet dort ab --
|
||||
z.B. ist TITEL tatsaechlich ~109s lang, ONGAME2 ~123s, TITEL2 (der Rauser-
|
||||
Sting) nur ~2s. Vorher wurde hart bei `seconds` abgeschnitten, was TITEL
|
||||
(mit frueher genutzten 60s) VOR dem echten Songende kappte -- das war der
|
||||
Bug hinter "Musik ist zu kurz, da fehlt der Rest". Der Default hier (180s)
|
||||
ist bewusst grosszuegig ueber die laengsten bekannten Stuecke hinaus
|
||||
gewaehlt, damit nichts abgeschnitten wird; im Normalfall stoppt render_tfmx
|
||||
laengst vorher von selbst.
|
||||
z.B. ist TITEL (song 0) tatsaechlich ~109s lang, ONGAME2 (song 0) ~123s,
|
||||
TITEL2 song0 (Rauser-Sting) nur ~2.04s. Vorher wurde hart bei `seconds`
|
||||
abgeschnitten. Der Default hier (180s) ist bewusst grosszuegig ueber die
|
||||
laengsten bekannten Stuecke hinaus gewaehlt, damit nichts abgeschnitten
|
||||
wird; im Normalfall stoppt render_tfmx laengst vorher von selbst.
|
||||
|
||||
ACHTUNG Cache: der Dateiname ist rein `<name>.wav` OHNE den seconds-Wert.
|
||||
Wird `seconds` also mal kleiner gewaehlt als die echte Songlaenge (z.B.
|
||||
fuer einen bewusst kurzen Teaser), MUSS `force=True` gesetzt werden, sonst
|
||||
liefert diese Funktion den ggf. laenger/kuerzer gerenderten alten Cache-
|
||||
Treffer zurueck, egal was `seconds` diesmal sagt -- genau das hat den
|
||||
urspruenglichen Bug mit ausgeloest (ein alter 8s-Debug-Render von TITEL
|
||||
blieb liegen und wurde stillschweigend weiterverwendet)."""
|
||||
ACHTUNG Cache: der Dateiname ist `<name>.wav` (song_index None/0) bzw.
|
||||
`<name>_song<N>.wav` fuer N>0. Wird `seconds` kleiner gewaehlt als die
|
||||
echte Songlaenge, MUSS `force=True` gesetzt werden, sonst liefert diese
|
||||
Funktion einen ggf. laenger/kuerzer gerenderten alten Cache-Treffer
|
||||
zurueck, egal was `seconds` diesmal sagt."""
|
||||
os.makedirs(_CACHE_DIR, exist_ok=True)
|
||||
out_path = os.path.join(_CACHE_DIR, f'{name}.wav')
|
||||
suffix = f'_song{song_index}' if song_index else ''
|
||||
out_path = os.path.join(_CACHE_DIR, f'{name}{suffix}.wav')
|
||||
if os.path.exists(out_path) and not force:
|
||||
return out_path
|
||||
_ensure_binary()
|
||||
@@ -72,22 +89,23 @@ def render_wav(container, name, seconds=180, force=False):
|
||||
with open(sam_path, 'wb') as f:
|
||||
f.write(sam_data)
|
||||
|
||||
result = subprocess.run(
|
||||
[_BINARY, tfx_path, sam_path, out_path, str(seconds)],
|
||||
capture_output=True, text=True
|
||||
)
|
||||
cmd = [_BINARY, tfx_path, sam_path, out_path, str(seconds)]
|
||||
if song_index:
|
||||
cmd.append(str(song_index))
|
||||
result = subprocess.run(cmd, capture_output=True, text=True)
|
||||
if result.returncode != 0:
|
||||
raise RuntimeError(f'render_tfmx failed for {name}: {result.stderr}')
|
||||
raise RuntimeError(f'render_tfmx failed for {name} (song_index={song_index}): {result.stderr}')
|
||||
return out_path
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Kleiner CLI-Test: python3 tfmx_audio.py <DAT_PATH> <NAME> [seconds]
|
||||
# Kleiner CLI-Test: python3 tfmx_audio.py <DAT_PATH> <NAME> [seconds] [song_index]
|
||||
sys.path.insert(0, _HERE)
|
||||
from kellogg_formats import DATContainer
|
||||
dat_path = sys.argv[1]
|
||||
name = sys.argv[2]
|
||||
seconds = int(sys.argv[3]) if len(sys.argv) > 3 else 20
|
||||
song_index = int(sys.argv[4]) if len(sys.argv) > 4 else None
|
||||
c = DATContainer(dat_path)
|
||||
path = render_wav(c, name, seconds, force=True)
|
||||
path = render_wav(c, name, seconds, force=True, song_index=song_index)
|
||||
print(f'rendered: {path}')
|
||||
|
||||
Reference in New Issue
Block a user