Zum Inhalt springen
Michael Malura
273 Github Stars 10060 npm Downloads 29 Projekte

Secret of Evermore aufgemacht und das Spiel selbst rendern lassen

Ein Kumpel hat mit einem Remake von Secret of Evermore angefangen, dem SNES-Rollenspiel von 1995. Ich wollte ihm nur schnell die Grafiken und Sounds aus dem ROM ziehen. Aus dem Nachmittag wurde ein Wochenende, an dem ich das halbe Spiel auseinandergenommen habe.

Das Spiel rendert für dich

Die Maps sind fies komprimiert. Ein LZSS-Layer für die Anordnung, ein zweiter Codec für die Platzierung, ein dritter fürs Tileset, dazu Paletten aus einer eigenen Tabelle. Ich hab die Codecs eine Weile von Hand rückwärts gebaut, Byte für Byte gegen einen RAM-Dump. Ging, war aber zäh.

Dann kam mir die Idee, die Arbeit gar nicht selbst zu machen. Das Spiel kann seine Maps ja rendern, es tut nichts anderes. Also lade ich es headless im Emulator (Mesen2 über Lua) und häng mich an die spieleigene Map-Load-Routine. Ein Callback auf die Stelle, wo der Loader die aktuelle Map-ID aus dem RAM liest, und kurz davor überschreibe ich diese ID mit der, die ich sehen will.

emu.addMemoryCallback(function()
  emu.write(0x0ADB, target_map, emu.memType.snesWorkRam)
end, emu.memCallbackType.exec, 0x908F68)

Das Original baut dann jede Map über seinen kompletten eigenen Pfad, und ich lese am Ende einfach VRAM und CGRAM aus. Der Extractor bootet Mesen2, setzt die Map-ID und dumpt den dekodierten Zustand:

map  16: target=16 mapnum=16 24x15 -> OK, painted=104764 missing_quads=0 (2.9s)
map  54: target=54 mapnum=54 25x25 -> OK, painted=238854 missing_quads=0 (2.7s)
map 105: target=105 mapnum=105 54x79 -> OK, painted=1239641 missing_quads=0 (3.0s)

target==mapnum heißt, das Spiel hat genau die Map geladen, die ich wollte, und kein einziger Tile-Quadrant fehlt. So sieht eine fertige aus, die Kathedrale mit ihren Glasfenstern:

Kathedrale mit Glasfenstern, vom Spiel gerendert
Kathedrale mit Glasfenstern, vom Spiel gerendert

Das läuft über alle 127 Maps, kein einziger Fehler. Hier alle auf einen Blick, direkt aus dem Spiel gezogen:

Alle 127 Maps, direkt aus dem Spiel
Alle 127 Maps, direkt aus dem Spiel

Die erste Dschungel-Karte

Weil die Maps aus dem laufenden Spiel kommen, laufen sie auch weiter, wenn ich sie einfach stehen lasse. Damit fallen die Animationen quasi ab: das Laub schimmert, das Wasser kräuselt sich, die Fackeln flackern. Hier der Dschungel mit den geschlängelten Wegen, in dem der Junge am Anfang herumrennt, direkt aus dem Spiel als GIF:

Die erste Dschungel-Karte mit geschlaengelten Wegen, animiert aus dem Spiel
Die erste Dschungel-Karte mit geschlaengelten Wegen, animiert aus dem Spiel

Und die Vielfalt ist ordentlich. Vom Marktplatz über die Junk Towers bis zu den Lava-Pfaden, wo die Lava wirklich fließt:

Jungle Clearing mit Brunnen
Jungle Clearing mit Brunnen
Ancient City Square
Ancient City Square
Junk Towers ueber Wasser
Junk Towers ueber Wasser
Lava-Pfad, die Lava fliesst, animiert
Lava-Pfad, die Lava fliesst, animiert

Karten selbst würfeln

Wenn ich eh die echten Tiles und die Nachbarschaften jeder Map habe, kann ich damit auch neue Karten bauen. Ich hab die Adjazenz-Regeln aus den Original-Maps gelernt und per Wave Function Collapse frische Karten generiert, mit dem echten Tileset gerendert. Die Glashalle liefert eine schöne Fenster-Grammatik:

WFC-Karte, Glashallen-Grammatik
WFC-Karte, Glashallen-Grammatik

Bei anderen Vorlagen kommt eher Mauerwerk und Boden raus:

WFC-Karte aus Stein-Vorlage
WFC-Karte aus Stein-Vorlage

Ehrlich: für den Dschungel sind die WFC-Regeln zu schwach, das Biom flutet monoton und sieht lange nicht so gut aus wie die echte Karte mit ihren Wegen. Darum läuft mein Remake auf der echten Map, WFC bleibt der Knopf zum Durchwürfeln.

Wenn es nicht klappt, ehrlich bleiben

Nicht alles lief so glatt. Der Junge, also der Spieler-Sprite, liegt als rohes 4bpp im ROM, den konnte ich pixelgenau gegen ein Referenz-Sheet prüfen. Beim Versuch, auch die Angriffs- und Zauber-Posen so zu ziehen, bin ich abgeblitzt.

Derselbe Abgleich, der Stehen und Laufen exakt trifft, kommt bei den Action-Posen nur auf 0.44 bis 0.79. Zusammengesetzt sieht das aus wie Tile-Salat, lauter falsch zusammengesuchte Kacheln. Der Grund ist dass die dynamischen Posen nicht als fertige Bilder im ROM liegen. Sie werden zur Laufzeit aus einzelnen Hardware-Sprites mit eigenem Versatz zusammengebaut, gesteuert von einer Script-Engine. Ich hab das Negativ so stehen lassen, statt erfundene Offsets als fertig zu verkaufen.

Ein spielbares Stück

Am Ende hab ich ein pygame-Remake mit den echten ROM-Daten. Der Junge läuft und rennt in alle Richtungen mit den echten Frames, auf der echten Dschungel-Karte mit ihren Wegen, Items, einem NPC und echten Dialogen aus dem Spiel:

Das Remake, Boy laeuft auf der echten Jungle-Map
Das Remake, Boy laeuft auf der echten Jungle-Map

Für Angriff und Zauber mach ich es wie das Original: der Körper bleibt fast statisch, die Waffe und der Zauber sitzen als eigenes Sprite obendrauf. Genau diese Effekt-Sprites hab ich aus dem ROM geschnitten:

Angriff mit echtem Waffen-Schwung aus dem ROM
Angriff mit echtem Waffen-Schwung aus dem ROM
Zauber mit echtem Effekt aus dem ROM
Zauber mit echtem Effekt aus dem ROM

Dazu ein Menü mit den echten Item- und Alchemie-Tabellen:

Menue mit echten Item- und Alchemie-Tabellen
Menue mit echten Item- und Alchemie-Tabellen

Das ist alles noch Work in Progress, ich bau weiter dran. Man sieht ja auch unschwer, dass die Animationen noch nicht sauber exportiert werden, die GIFs flackern und ruckeln an den Raendern. Das kommt noch.

Ping-Pong mit der KI

Das Hin und Her war fast interessanter als der Code. Die eigentliche Fleißarbeit hat Claude gemacht, das Codec-Rückwärtsbauen, das Sprite-Matchen, verteilt über viele parallele Agenten. Die Ideen, wo es langgeht, kamen aber im Gespräch.

Der Caller-Trick zum Beispiel. Claude hat erst brav die Codecs von Hand geknackt, Byte für Byte. Ich hab dann gesagt, lass doch den Emulator die Funktion für dich aufrufen, das Spiel rendert seine Maps doch selbst. Das war der Moment, wo es klick gemacht hat, und ab da liefen alle 127 Maps.

Der andere Dauerbrenner war Ehrlichkeit. Claude hat mir mehr als einmal eine saubere Kathedrale verkauft, während das Bild noch dunkel und kaputt war. Also hab ich drauf bestanden, jedes gerenderte Bild selbst zu sehen, bevor irgendwas als fertig gilt. Genau so sind mehrere angebliche Durchbrüche als noch nicht fertig aufgeflogen. Beim Spieler-Sprite, wo die Action-Posen partout nicht aus dem ROM wollten, war die Ansage: lieber ein ehrliches Negativ als erfundene Offsets. Und bei den Effekten hab ich entschieden, es wie das Original zu machen, statt tief in die Animations-Engine zu graben.

Ich hatte die Ideen und den Blick fürs Ergebnis, Claude die Ausdauer und die tausend Details. Zusammen war das an einem Wochenende durch, allein hätte ich Wochen gebraucht. Nichts von Square landet übrigens im Repo, alle Assets kommen aus der eigenen ROM und sind gitignored.

30.08.2026 aktualisiert 30.08.2026
Teilen X Reddit Hacker News LinkedIn E-Mail
Neue Beiträge abonnieren RSS JSON