Prince of Persia Disk Version ?

  • Das sind mir viel zu viele Halbwahrheiten und Spekulationen, also lasst mich da mal Licht in die Sache bringen.

    Erst mal ein Überblick:
    Prinzipiell scheitert's erst mal daran das die Originalversion auf 128KB ausgelegt wurde, weil das notwendig war um die ganzen Grafikdaten unterzubringen. D.h. hauptsächlich die Animations Frames für den Prince und einen Gegner. Dann dazu noch die Tiles für die Hintergrundgrafik dazugerechnet, das ist schonmal eine Menge. Alle diese Grafiken werden natürlich ständig gebraucht, man kann ja praktisch alle Aktionen jederzeit durchführen. Ladezeit for Sprung oder Kampf? Das wär glaub ich nix.
    Aufm Apple II brauchen diese Daten 30KB für den Spieler, 6KB für den Gegner und 13.5KB für die Hintergrundgrafik, also 49.5KB.

    Der Code fürs Spiel ist 48KB am Apple II. Vieles davon braucht man am C64 sicher nicht unbedingt so, aber das meiste schon. Gewisse Dinge (z.b. Joystickabfragen) muss man am Apple kompliziert ausprogrammieren, während man am C64 nur ein Register lesen muss. Einzelne Dinge könnte man u.U. auslagern und nachladen, aber das würde sicher nicht mehr als 10% davon ausmachen. Dazu muss man auch wissen das z.b. die Cutscenes im Spiel auch mit der Spiel Engine ablaufen, also eigentlich nicht separat sind.

    Das Spiel zeichnet die Räume mit Hilfe der Hintergrundgrafik Tiles in eine Bitmap (die Grafik geht nicht mit Zeichensatz, weil die 3 Stockwerke die man sieht nicht mit dem 8x8 Pixel Raster übereinstimmt). Damit man ordentlich animieren kann ohne das irgendwas ständig flackert wird ganz normales Double-Buffering verwendet. D.h. am Apple II 16KB für die zwei Bitmaps. Am C64 sind das auch gleich mal 16KB plus 2KB für die Screen Daten.
    Zusätzlich müssen die Spieler und Gegner Figuren auch hinter der Hintergrundgrafik stehen können, und an bestimmten Stellen (hinter einem Gitter) auch Pixel präzise ausmaskiert werden. Um das schnell zu lösen verwend' ich am C64 eine eigene Masken Bitmap (also nochmal 8KB, rechnet jemand mit?). Eine Lösung wie z.b. bei Caren wo die Spielfigur mit Sprites ausmaskiert wird ist nicht wirklich machbar, weil ich alle Sprites für Spieler und Gegner brauche (die Figuren sind ziemlich gross, z.b. wenn sie springen). Die Spielfiguren in die Bitmap zu zeichnen (wie am Apple II) würde durch die Farblimitierungen der C64 Multicolor Bitmap nicht gut aussehen, entweder wäre der Spieler auch blau wie der Hintergrund, oder man hätte unschönen "Color Clash", so wie bei vielen Spectrum Spielen.

    Die Level Beschreibung (also welche Räume, und wie die aussehen) braucht 2.25KB. Diverse Tabellen für die Animationen und für z.b. Multiplikation oder so brauchen auch noch mal 6KB. Von Musik und Soundeffekten reden wir noch gar nicht.

    Ist ja nicht so das ich nicht die anderen Optionen abgewägt hätte. Also erstmal REU:
    Dazu hab ich alle Grafikdaten in die REU geschaufelt, dabei die Figuren auch schon mal gespiegelt. Dann für jedes Frame die Sprite daten in einen Buffer im C64 RAM kopiert, dann maskiert. Aber es war noch immer viel zu viele Sachen im RAM und es ging sich noch immer nicht aus drei Bitmaps (2 Buffer und eine Maske) unterzubringen.
    Im Endeffekt gings mit der REU Version also einfach nicht vorwärts, ich stiess immer nur an Grenzen ohne Aussicht auf Lösungen. D.h das Projekt ist dadurch versandet und es hat fast ein Jahr gedauert bis ich mit dem neuen Modulansatz begonnen habe. Aber wer's ausprobieren will, die REU Version vom ersten Level gibt's hier, ist aber natürlich buggy und unfertig, das war der Stand von August 2009: pop_090809.prg
    Speicherbelegung von damals war circa so:

    Quellcode

    1. ; $0000-$03FF : Spiel Variablen + Buffer
    2. ; $0400-$3FFF : Code
    3. ; $4000-$5FFF : Bitmap
    4. ; $6000-$63FF : Screen + Spritezeiger
    5. ; $6400-$6FFF : Sprite Buffer
    6. ; $7000-$79FF : Liste aller Animationen
    7. ; $7A00-$7EAF : Liste aller Animations Frame Beschreibungen
    8. ; $7EB0-$7FFF : Tabellen
    9. ; $8000-$A80B : Hintergrund Grafik Tiles
    10. ; $A80C-$AFFF : FREI (für extra Hintergrund Grafik in Palast Levels)
    11. ; $B000-$B5FF : Tabellen
    12. ; $BC00-$BDFD : Tabelle um die Animationen in der REU zu finden
    13. ; $BDFE-$BFFF : Buffer wo die REU hineinkopiert
    14. ; $C000-$DFFF : Masken Bitmap
    15. ; $E000-$EBFF : FREI => Musik/Sound?
    16. ; $EC00-$F4FF : Level Daten
    17. ; $F500-$FFE8 : Tabellen
    Alles anzeigen

    Dann mit dem Modulansatz war alles einfacher:
    Man kann einfach vom ROM im Modul Teile einblenden, das geht nicht nur "erheblich schneller" wie oben beschrieben, sondern es braucht gar keine Zeit. Den Unterschied zwischen schnell und sofort muss man sich erstmal deutlich klar machen.
    Bei jedem C64 Modul, also egal ob EasyFlash, Ocean, Gmod2 oder sonst irgend einem ist es immer so das man direkt drauf zugreifen kann, d.h. man kann an die Adresse vom ROM springen und dort auch Code ausführen. Oder eben Daten direkt lesen, ohne Umweg über's RAM. Nur der VIC-II kann (im Normalfall) nicht auf das ROM zugreifen. Und beim Lesen der Grafikdaten kann ich sie auch gleich maskieren, ohne sie dann nochmal vom RAM lesen zu müssen.

    Aber prinzipiell ist das natürlich sehr geil. Wie ihr oben seht sind da erst <16KB (von $0400-$3fff) Code der Apple II version übernommen worden. Fast 32KB fehlen da noch. Also wohin damit? Natürlich ins ROM, und da das eh fast kein selbstmodifizierender Code ist, dann eben auch direkt von dort ausführen. Das geht natürlich mit einer REU gar nicht. Selbst umkopieren mit 1MB/s ist da nicht vergleichbar. Das ist ein ganz anderes Ding.

    Also darauf läuft's dann hinaus. Alles was man nicht ständig braucht kann ins ROM, dadurch wird Platz frei für die dritte Bitmap, dadurch werden die Hintergrund Animationen ohne Flackern erst möglich. Und dadurch ist dann schlussendlich Platz genug für alles, inklusive Musik und dergleichen.
    Und um das ganze dann in spielbare Bereiche zu beschleunigen braucht man Speed Code, d.h. die schnellstmögliche Variante um z.b. Speicherbereiche zu löschen, ohne Schleifen. Da gibts's dann im ROM Routinen um die Bitmaps zu löschen, die Sprite Buffer zu löschen, das Farbram zu löschen, etc. das braucht 8 mal 8KB Banken im ROM, also 64KB.

    Mit Modul sieht die Speicherbelegung im RAM dann so aus:


    Quellcode

    1. ; $0000-$03FF : Spiel Variablen
    2. ; $0400-$4FFF : Code
    3. ; $5000-$6F3F : Masken Bitmap
    4. ; $7000-$79FF : Liste aller Animationen
    5. ; $7A00-$7EAF : Liste aller Animations Frame Beschreibungen
    6. ; $7EB0-$7FFF : Tabellen
    7. ; $8000-$83FF : Screen 1 (+ Spritezeiger)
    8. ; $8400-$85FF : Sprite Buffer 1 ($100 pro Spielfigur)
    9. ; $8600-$8DFF : Hintergrund Blit Routinen
    10. ; $8E00-$8EFF : Buffer für Hintergrund Grafik Tile im RAM (weil beim Zeichnen des Hintergrunds muss das ROM aus sein)
    11. ; $8F00-$8FFF : Sprite Blit Tabelle
    12. ; Zusätzlich manchmal eingeblendet:
    13. ; $8000-$9FFF : LO ROM Banken -> Level Daten, Speed Code, Cutscene Hintergrund Bild, Titel Sequenz, Musik, Sound, etc.
    14. ; $9000-$96FF : Tabellen
    15. ; $9700-$9FFF : Level Daten (Kopie im RAM, weil Daten ständig gelesen werden und auch modifiziert werden, z.b. bei Schaltern)
    16. ; $A000-$BF3F : Bitmap 1 (d.h. ROM muss aus sein wenn Bitmap zum maskieren gelesen wird)
    17. ; Zusätzlich manchmal eingeblendet:
    18. ; $A000-$BFFF : HI ROM banks -> Animations und Hintergrund Grafikdaten, Tabellen, etc.
    19. ; $C000-$C3FF : Screen 2 (+ Spritezeiger)
    20. ; $C400-$C5FF : Sprite buffer 2 ($100 pro Spielfigur)
    21. ; $C600-$CEFF : Spielfigur Sprite Blit Routinen (mit maskieren)
    22. ; $CF00-$CFFF : Kopie der Zeropage während Musik oder Sound Player aktiv ist.
    23. ; $D000-$D1FF : Zeichensatz für Statuszeile am unteren Bildschirmrand
    24. ; $D200-$D7FF : Sprites für Titelsequenz
    25. ; $E000-$FF3F : Bitmap 2 (d.h. ROM muss aus sein wenn Bitmap zum maskieren gelesen wird)
    Alles anzeigen

    Schlussendlich, welche anderen Optionen hätte es gegeben:

    - Unter Umständen hätte man jedes zweite Animations Frame weglassen können, oder die Grafikdaten irgendwie komprimieren und auf Double Buffering verzichten können, den Code komplett neu und effizienter schreiben.
    Wer Lust hat das zu tun, der Quellcode ist ja heutzutage öffentlich verfügbar, damals war das natürlich nicht so. Gewisse Dinge hab ich nie reverse-engineered, sondern einfach 1:1 übernommen, z.B. die Gegner KI. Wenn man das neu schreibt geht es sicher effizienter, aber dann hat man auch neue Bugs. Viel Spass.

    - Am C128 hätte man u.U. mit einigen kleinen Abstrichen alles irgendwie unterbringen können.

    Hoffe das hilft beim Verständnis, bin für Fragen natürlich jederzeit verfügbar.
  • mrsid schrieb:

    - Am C128 hätte man u.U. mit einigen kleinen Abstrichen alles irgendwie unterbringen können.
    Danke für die ausführliche Erklärung. Das wäre dann tatsächlich meine Frage gewesen, ob das am C128 nicht irgendwie gepasst hätte. Ich habe es bis heute leider nicht hinbekommen, PoP am C128 zum Laufen zu bekommen. Das Spiel schaltet nach dem Titelbildschirm immer in den 2 Mhz-Modus (grauer Bildschirm). Ich dachte bislang, es lag an der EasyFlash-Emulation der 1541U2, aber anscheinend klappt es mit dem EasyFlash3 selber auch nicht, siehe blog.c128.net/archives/634
    Ist im Code irgendeine Stelle, die versehentlich in den 2Mhz-Modus schaltet? Andererseits meine ich mich, zu erinnern, dass Du irgendwann mal geschrieben hast, dass das Spiel den C128 ausnutzt und auch einige Fixes sind ja speziell für den C128 laut CSDB. Demnach muss es ja bei dir selber laufen. Ggf. mit EasyFlash1 statt 3?
  • Danke auch erstmal für deine sehr aufschlussreichen Erläuterungen.

    mrsid schrieb:

    Einzelne Dinge könnte man u.U. auslagern und nachladen, aber das würde sicher nicht mehr als 10% davon ausmachen. Dazu muss man auch wissen das z.b. die Cutscenes im Spiel auch mit der Spiel Engine ablaufen, also eigentlich nicht separat sind.

    Kannst du noch sagen, wie viel die Cutscenes in etwa verbrauchen oder sind die schon in den 10% mit drin?

    mrsid schrieb:

    Zusätzlich müssen die Spieler und Gegner Figuren auch hinter der Hintergrundgrafik stehen können, und an bestimmten Stellen (hinter einem Gitter) auch Pixel präzise ausmaskiert werden. Um das schnell zu lösen verwend' ich am C64 eine eigene Masken Bitmap (also nochmal 8KB, rechnet jemand mit?). Eine Lösung wie z.b. bei Caren wo die Spielfigur mit Sprites ausmaskiert wird ist nicht wirklich machbar, weil ich alle Sprites für Spieler und Gegner brauche (die Figuren sind ziemlich gross, z.b. wenn sie springen).

    Hast du für die Spites auch Multiplexing benutzt?

    mrsid schrieb:

    Am C128 hätte man u.U. mit einigen kleinen Abstrichen alles irgendwie unterbringen können.

    So eine C 128 Umsetzung würde dich vemutlich nicht reizen, oder? ;)
  • Sehr schöne Ausführung.

    So wie Du das beschrieben hast, ist es eigendlich sogut wie nicht möglich,
    das Spiel an die REU anzupassen. Ich hatte mir sowas auch schon gedacht.


    Schade.


    Eine C128 Umsetzung währe auch mal etwas.

    Gibt es grundsätzlich mit dem EasyFlash am 128er Probleme oder nur bei dem Spiel ?


    Eine SCPU Anpassung sollte normalerweise kein Problem sein. Es sei denn, Illegale OP-Codes wurden verwendet.



    Vielen Dank für die Ausführung



    Gruß: Stephan
  • tokra schrieb:

    Ist im Code irgendeine Stelle, die versehentlich in den 2Mhz-Modus schaltet?
    Das Bit wird schon gezielt genutzt, wie man am Chameleon erkennen kann. Ich habe aber leider keinen C128 (und kein kompatibles Modul), um das zu testen. In VICE wird ja leider nicht emuliert, was der VIC IIe im 2-Mhz-Modus sieht. Für Entwickler ist das von daher ungeeignet, weil man evtl. Programmierfehler nicht immer sieht.

    Klaus Scheuer schrieb:

    Eine SCPU Anpassung sollte normalerweise kein Problem sein. Es sei denn, Illegale OP-Codes wurden verwendet.
    Wenn es quelloffen ist, sollte es ja nicht weiter schwierig sein, Illegale Opcodes zu ersetzen. War das bei Apple überhaupt üblich, mit Illegalen Opcodes zu programmieren? Kompatibilitätsprobleme wären doch wahrscheinlich, da reinrassige 6502 von verschiedenen Herstellern kamen. Die Commodore-Rechner hatten da schon einen Sonderstatus, wo man sich auf den CPU-Hersteller verlassen konnte.
  • LogicDeLuxe schrieb:

    War das bei Apple überhaupt üblich, mit Illegalen Opcodes zu programmieren? Kompatibilitätsprobleme wären doch wahrscheinlich, da reinrassige 6502 von verschiedenen Herstellern kamen.
    Welche 6502, die von Fremdherstellern stammen, verhalten sich anders? Ausgenommen natütlich 65c02 und so, die in späteren Apple-II-Modellen ab Werk verwendet wurden.
  • Naja, Illegale OP-Codes habe ich öfter in Kopierprogramme und dort in den Schnelllade- und Saveroutinen gehabt. Diese musste ich dann doch tatsächlich mittels 256 Byte
    Tabelle ersetzen um es an die SCPU anzupassen. Filecopier von Prism Soft war das. Grand Prix Circuit von Accolade bedient sich auch diverser illegallen OP-Codes.

    Manchmal stosse ich auf soetwas

    ldx #$00
    stx $ffa0,x (01)
    inx
    bne (01)
    rts

    Das Bechreiben der Zeropage funktioniert mit dem c64.
    Mit der SCPU überschreibt man jedoch den C64-Kernal der ab $01e000 zu finden ist.

    Gruß: stephan
  • ogd schrieb:


    Kannst du noch sagen, wie viel die Cutscenes in etwa verbrauchen oder sind die schon in den 10% mit drin?
    Nicht viel. Vielleicht 2-3KB alles in allem.

    ogd schrieb:

    Hast du für die Spites auch Multiplexing benutzt?
    Nein, das hilft in dem Fall nicht allzu viel und macht das Timing und das Speicherlayout komplizierter.

    ogd schrieb:

    So eine C 128 Umsetzung würde dich vemutlich nicht reizen, oder? ;)
    Nein, das Interesse daran geht gegen null, so wie die Anzahl der C128 Benutzer... (ich hab selbst einen! ;) )

    Klaus Scheuer schrieb:



    Eine SCPU Anpassung sollte normalerweise kein Problem sein. Es sei denn, Illegale OP-Codes wurden verwendet.
    Nein, keinerlei illegale Opcodes wurden verwendet. Die wenigen 65C02 Opcodes musste ich durch äquivalenten Code ersetzen.

    LogicDeLuxe schrieb:

    Das Bit wird schon gezielt genutzt, wie man am Chameleon erkennen kann. Ich habe aber leider keinen C128 (und kein kompatibles Modul), um das zu testen. In VICE wird ja leider nicht emuliert, was der VIC IIe im 2-Mhz-Modus sieht. Für Entwickler ist das von daher ungeeignet, weil man evtl. Programmierfehler nicht immer sieht.
    Ja, es wird der 2MHz Modus verwendet. Ich hab' das natürlich auf einem echten C128 (D, Plastik) mit einem echten Easyflash getestet. Easyflash Support in der 1541 Ultimate oder dem Chameleon oder ein Easyflash 3 gab es damals noch gar nicht.
    Ein Bug beim Speichern auf einem C128 wurde in der Version 1.1 behoben.
  • @mrsid
    Danke für die Erklärung. :thumbup:

    Ne REU ist also auch nicht die Lösung für alle Probleme.

    Wie würde es mit dem RAM der SCPU aus sehen, würde es dort funktionieren?
    Platz sollte es ja genug haben und wenn die 64'er nicht nur Blödsinn verzapft hat, sollte es als Arbeitsspeicher benutzbar sein.


    Klaus Scheuer schrieb:

    Eine C128 Umsetzung währe auch mal etwas.
    Aber gleich im 80 Zeichenmodus - O.K. der VDC kann keine Sprites, schon Problem 1 - und mit 2 MHZ. ^^


    mrsid schrieb:

    Nein, das Interesse daran geht gegen null, so wie die Anzahl der C128 Benutzer... (ich hab selbst einen! )
    :cry:
    Das arme, vernachlässigte Stiefkind. :rolleyes:

    Gruss C=Mac.
  • Ich bin da schon am überlegen.

    Die SCPU hat ab $D300-$D3FF Arbeitsspeicher.

    Alle STA $de00 dahin umleiten

    Nichts tolles nur mal kurz nachgedacht.

    Quellcode

    1. ; ----easyflasch code ----
    2. lda #$05
    3. sta $0100
    4. jsr $d300 ; ursprünglich sta $de00
    5. ; ---- $d300 ----
    6. tax
    7. lda tabelle,x ; tabelle mit werten easyflash bank <--> scpu ram
    8. sta SCP01+1 ; scpu lo byte festlegen
    9. inx
    10. sta SCP01+2 ; scpu hi byte festlegen
    11. inx
    12. sta SCP02+2 ; scpu bankbyte festlegen
    13. sei
    14. clc
    15. xce
    16. rep #$30
    17. lda #$3fff ; anzahl der bytes , immer gleich
    18. SCP01 ldx #$XXXX ; von,wert aus tabelle
    19. ldy #$8000 ; nach
    20. phb
    21. SCP02 mvn $02,$00 ; von bank XX (wert aus tabelle) nach bank 00
    22. plb
    23. sep #$30
    24. sec
    25. xce
    26. rts
    Alles anzeigen

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Klaus Scheuer ()

  • Vernunftmensch schrieb:

    ? schrieb:

    Laut dem Entwickler der C64-Version hätte er das Projekt nicht ohne das EasyFlash fertigstellen können, da der normale RAM des C64 einfach nicht ausreichend gewesen wäre
    bei tt64 mit swap-file auf floppydisc gelöst
    Das habe ich mir auch schon so gedacht.

    Der C64 hat eben nicht nur 64kb Ram sondern auch noch einige KB (Modul)Rom

    Siehe Toki oder Navy Seals
  • PrinceOfPersia und TrapThem64 haben die selben Probleme. Nur ich habe die Mühe einer Diskettenversion gemacht.

    Ja, auch ich habe eine REU Version ausprobiert. Nur kann ich es nicht selber testen außer im Emu. Der Trick ist wie eine Diskette die REU nutzen, nachdem sie im REU endlich geladen ist.
    Wer den C64 nicht ehrt ist des x64ers nicht wert.
  • Das hätte ich sowiso vor.

    Der Code ab $d300 ist von mir gewählt worden, weil:

    z.b.
    1. lda #$05
    2. sta $0100
    3. jsr $d300 ; ursprünglich sta $de00
    Ich könnte da jetzt kein jsr $125000 einsetzen,weil der op-code 4 bytes hat.
    Deshalb ist die EasyFlash Emulations-Routine ab $d300.

    Diese Routine kopiert nun per mvn befehl (bedeutend schneller als die REU)
    die entsprechenden Bänke aus dem SCPU-Ram ab $020000 nach $8000-$bfff

    gruß: stephen