Beiträge von RPG Hacker

geschrieben am 08.09.2010 22:30:16 in Es geht voran, die Zweite
( Link )
Kann ich mit leben. Dieser Style gefällt mir eigentlich ziemlich gut. Aber ja, der Hammer-Mario nervt gewaltig.
-Das quadratische Rad neu erfinden-
Mit das quadratische Rad neu erfinden (englisch Reinventing the square wheel) bezeichnet man die Bereitstellung einer schlechten Lösung, wenn eine gute Lösung bereits existiert.

-Slowsort-
Slowsort (von engl. slow: langsam) ist ein langsamer, rekursiver Sortieralgorithmus, der nach dem Prinzip Vervielfache und kapituliere (engl. Multiply and surrender, eine Parodie auf Teile und herrsche) arbeitet.

geschrieben am 10.09.2010 22:09:12 in To-Do-Liste
( Link )
Übrigens: Wie wäre es mit Custom-Ranksets? Es geht jetzt mal nicht um die Ranksets an sich, da kann es von mir aus bei dem einen, YI-Rankset bleiben. Es geht alleine um die FUNKTION, dass man also, wenn man ein Rankset erstellt hat, dieses einfach nur noch "einfügen" muss und ein User dann in den Optionen sein Lieblings-Rankset auswählen kann.
-Das quadratische Rad neu erfinden-
Mit das quadratische Rad neu erfinden (englisch Reinventing the square wheel) bezeichnet man die Bereitstellung einer schlechten Lösung, wenn eine gute Lösung bereits existiert.

-Slowsort-
Slowsort (von engl. slow: langsam) ist ein langsamer, rekursiver Sortieralgorithmus, der nach dem Prinzip Vervielfache und kapituliere (engl. Multiply and surrender, eine Parodie auf Teile und herrsche) arbeitet.

geschrieben am 12.09.2010 10:31:27 in Stil!
( Link )
Und "Kostüm" bitte zu "Küstom"!
-Das quadratische Rad neu erfinden-
Mit das quadratische Rad neu erfinden (englisch Reinventing the square wheel) bezeichnet man die Bereitstellung einer schlechten Lösung, wenn eine gute Lösung bereits existiert.

-Slowsort-
Slowsort (von engl. slow: langsam) ist ein langsamer, rekursiver Sortieralgorithmus, der nach dem Prinzip Vervielfache und kapituliere (engl. Multiply and surrender, eine Parodie auf Teile und herrsche) arbeitet.

geschrieben am 12.09.2010 15:11:57 in Es geht voran, die Zweite
( Link )
Hat er doch gesagt, dass das hier nur ein Übergangsdesign ist.
-Das quadratische Rad neu erfinden-
Mit das quadratische Rad neu erfinden (englisch Reinventing the square wheel) bezeichnet man die Bereitstellung einer schlechten Lösung, wenn eine gute Lösung bereits existiert.

-Slowsort-
Slowsort (von engl. slow: langsam) ist ein langsamer, rekursiver Sortieralgorithmus, der nach dem Prinzip Vervielfache und kapituliere (engl. Multiply and surrender, eine Parodie auf Teile und herrsche) arbeitet.

geschrieben am 14.09.2010 17:50:06 in Deutsches ASM Tutorial (Abgebrochen)
zuletzt bearbeitet von RPG Hacker am 18.04.2011 14:58:59.
( Link )
Dieses Tutorial befindet sich noch im Aufbau. Es deckt einige Grundlagen der ASM-Programmierung ab. Grundlegende Dinge wie z.B. das Erstellen von Blocks für BTSD oder ähnliches sind aber noch nicht in diesem Tutorial enthalten. Zu diesem Zeitpunkt kann ich leider nicht sagen, ob bzw. wann ich fehlende Kapitel nachliefern werde.


SMW Hackings deutsches ASM Tutorial für Anfänger und Fortgeschrittene by Markus Wall also known as RPG Hacker TM
(oder kurz: SMWHdASMTfAuFbMWakaRPGH)



---------------------------------------------------------------------------


LEKTION 1: BINÄRES- UND HEXADEZIMALES ZAHLENSYSTEM

Wie ihr sicherlich alle wisst oder wissen solltet, arbeitet ein Computer mit Einsen und Nullen. Dies nennt man das Binärsystem. Eine Beispielzahl in binär könnte z.B. so aussehen:

00011001

Nun mal grundlegendes zum Binärsytem:
-Die einzelnen "Ziffern" einer binären Zahl nennt man Bits. 8 Bits sind 1 Byte.
-Bei der Benennung der Bits geht man von hinten nach vorne. Das Bit ganz rechts ist Bit 0, eine Stelle weiter links ist Bit 1, noch eine Stelle weiter links ist Bit 2 usw.
-Eine binäre Ziffer kann nur den Wert 1 (set) oder 0 (clear) haben.

Wie aber funktioniert das binäre Zahlensystem nun genau? Ich sag nur ein Wort: Zweierpotenzen!

Jedes Bit einer binären Zahl steht für eine Zweierpotenz, wieder ganz rechts angefangen mit . Nun, ich hoffe ihr habt Mathematik einigermaßen drauf, denn das ist hier echt das Minimum. Aber falls nicht hier noch mal eine Liste:

= 1
= 2
= 4
= 8
= 16
= 32
= 64
= 128

Falls ihr die Potenzrechnung nicht drauf habt, dann merkt euch einfach, dass jedes Bit doppelt so groß ist, wie das vorherige.

Nun müsst ihr einfach alle gesetzten Bits zusammenzählen. Noch mal das Beispiel von oben: 00011001 (denkt dran, wir gehen von hinten nach vorne):

+ 0 + 0 + + + 0 + 0 + 0
= 1 + 0 + 0 + 8 + 16 + 0 + 0 + 0 = 25

Diese Zahl ist dezimal geschrieben also 25.

Rechnen tut man im Binärsystem genau so wie im Dezimalsystem mit der schriftlichen Addition, bloß, dass man nur zwei Ziffern hat. Also Beispiel:

0110 +
0101

0 + 1 = 1
1 + 0 = 1
1 + 1 = 0; Übertrag: 1
0 + 1 = 1

Das Ergebnis lautet also 1011

Wie ihr seht, kann das ganze hier ziemlich kompliziert und unübersichtlich werden. Genau aus diesem Grund hat man das Hexadezimalsystem entwickelt. Das Hexadezimalsystem funktioniert genau wie das Dezimalsystem, bloß, dass man 16 statt 10 Ziffern hat. Um die fehlenden Ziffern darstellen zu können, nimmt man einfach die Buschstaben A bis F. So ist die höchste Ziffer im Hexadezimalsystem nicht die 9, sondern F (15 in dezimal). Die Addition funktioniert auch hier wieder wie die schriftliche Addition im Dezimalsystem. Also:

1F3B +
2242

B + 2 = D
3 + 4 = 7
F + 2 = 1; Übertrag: 1
1 + 3 = 4

Das Ergebnis dieser Addition ist also 417D.

Das Hexadezimalsystem wird hauptsächlich dazu verwendet, um binäre Zahlen ansehlicher zu machen. So schreibt man statt 11010011 z.B. D3. Noch was wichtiges, was ihr euch merken solltet:

1111 = F = 15
11111111 = FF = 255
1111111111111111 = FFFF = 65535

Ich hoffe mal, dass dies einigermaßen verstanden wurde. Wenn ihr ganz leicht Hexzahlen in Binärzahlen konvertieren wollt oder umgekehrt, müsst ihr einfach folgendes tun (nur für Windows Nutzer):

1. Geht auf Start > Ausführen
2. Gibt ins Feld "calc" ein und klickt dann auf "OK"
3. Geht auf "Ansicht" und danach je nach Betriebssystem auf "Wissenschaftlich" bzw. "Programmierer"

Ihr solltet nun diese Ansicht bekommen:

(Windows XP)


(Windows 7)


Zuerst wählt ihr oben rechts die Ausgangszahl aus, also z.B. "Hex".
Danach gibt ihr die Zahl ein, die ihr konvertieren wollt.
Danach klickt ihr oben links auf den gewünschten Zahlentyp, also z.B. "Bin".
Das war's schon! Eure Zahl wurde nun erfolgreich konvertiert.

Ich weiß, dass das ganze hier ziemlich kompliziert ist und die meisten von euch vermutlich schon längst abgeschaltet haben, aber das alles hier perfekt zu beherrschen ist einfach Grundvorraussetzung, wenn man es in ASM Programmierung zu etwas bringen will.


---------------------------------------------------------------------------


LEKTION 2: DER ASM GRUNDBEGRIFF

Oben das war alles nur eine Einführung. Nun geht es erst mit der eigentlichen ASM Programmierung los.

Was ist ASM überhaupt?

Nun, ich habe euch oben schon das Binär- und Hexadezimalsystem vorgestellt. Außerdem habe ich erwähnt, dass Computer nur durch Einsen und Nullen laufen. Das gilt auch für SMW. SMW besteht komplett aus Einsen und Nullen. Diese Einsen und Nullen wären aber ziemlich unübersichtlich, deshalb gibt es das Hexadezimalsystem. Assembly erfüllt nun genau die selbe Aufgabe, wie das Hexadezimalsystem: Es macht die Programmierung übersichtlicher. Denn ganz ehrlich: Obwohl das Hexadezimalsystem sehr viel übersichtlicher als das Binärsystem ist, kann man mit Code wie
8D BF 1D....
Noch nicht wirklich viel anfangen. Erstens müsste man sich unzählige Zahlen merken und zweitens ist es einfach sehr schwer, einen gesuchten Wert zu finden. Darum benutzt man ASM. SMW lässt sich also komplett als ASM Code darstellen.

So, das war jetzt die Theorie hinter dem ganzen. Wo ist aber der praktische Nutzen? Ganz einfach: Natürlich lässt sich dieser Code auch verändern, und genau da wird das ganze interessant. Tools wie Lunar Magic, Addmusic, Sprite Tool, Block Tool usw. tun nichts anderes, als diesen Code zu verändern. Meistens bekommt man davon allerdings nicht viel zu sehen. In Lunar Magic z.B. bekommt man nur ein fertiges SMW zu sehen. In Wirklichkeit aber übersetzt Lunar Magic sämtliche Befehle in ASM Code und überschreibt damit den originalen SMW Code. Allerdings ist man hier natürlich and die Funktionen von Lunar Magic gebunden. Es ist auch möglich, den Code komplett nach seinen Vorstellungen zu verändern. Da Lunar Magic das aber nicht kann, brauch man dafür andere Programme. Im Falle von SMW benutzt man dafür meistens xkas, block tool oder sprite tool.

Auch block tool und sprite tool sind in gewisser Weise ziemlich limitiert, da sie den Code nur an einer festen Stelle in einer SMW ROM einfügen können. Mit xkas allerdings kann man Code an jeder beliebigen Stelle der ROM einfügen, daher ist xkas für ASM Patches auch am besten geeignet. Wie genau das funktioniert, erkläre ich euch im Laufe des Tutorials.

In SMW wird ASM Code meisten dafür verwendet, Adressen aus der RAM Map zu verändern. Diese Enthalten sämtliche Informationen über den Spielverlauf. Indem man diese Adressen verändert, kann man also auf den Spielverlauf Einfluss nehmen.


---------------------------------------------------------------------------


LEKTION 3: DER ACCUMULATOR UND DAS LADEN UND SPEICHERN VON WERTEN

Fangen wir erst mal mit einer der wichtigsten Begriffe der ASM Programmierung an, dem Accumulator. Der Accumulator ist ein so genanntes Register. Register sind vereinfacht gesagt Variablen, die bestimmte Zahlen enthalten und durch ASM Befehle (Opcodes genannt) verändert werden können. Der Accumulator ist das wichtigste aller Register. Mit ihm werden die meisten Operationen und Rechnungen durchgeführt. Es gibt viele Befehle, mit denen man den Accumulator beeinflussen kann. Fangen wir mal mit den leichtesten an.

Code
LDA #10


Dieser Befehl lädt die Dezimalzahl 10 in den Accumulator.

Code
LDA #%01001100


Dieser Befehl lädt die binäre Zahl 01001100 in den Accumulator.

Da man aber in ASM meistens mit Hexadezimalzahlen rechnet, sieht man diese Befehle eher selten. Viel häufiger sieht man da folgendes:

Code
LDA #$1F


Lädt die Hexadezimalzahl 1F in den Accumulator.

Ihr solltet euch an diesesr Stelle also auf jeden Fall schon mal merken, dass man Hexdezimalzahlen immer durch ein $-Zeichen symbolisiert, also z.B. $10, $AB, $F3 usw.

Was fängt man aber nun mit diesen Zahlen an? Nun, man kann sie in Adressen aus der RAM Map speichern. Das funktioniert z.B. so:

STA $7E0019

Dies speichert die Zahl im Accumulator in RAM Adresse $7E0019. Schauen wir mal in der RAM Map nach, wofür diese Adresse gut ist.

Zitat von RAM Map:
Powerup. #$00 = Small, #$01 = Big, #$02 = Cape, #$03 = Fire.


Aha. Das ist also Marios Powerup. Indem wir einen der angegebenen Werte in diese Adresse speichern, können wir Mario's Powerup beeinflussen.

Code
LDA #$02          ; Das hier ist übrigens ein Kommentar
STA $19


Kommentare stehen immer am Ende der Zeile, sind durch ein Semikolon abgetrennt und werden vom Programmcode ignoriert.

Dieser Code macht Mario also zu Cape Mario. War doch ganz schön einfach, oder? Aber halt mal, wieso habe ich einfach nur $19 geschrieben? Nun, es gibt bestimmte Register, die einem eine Menge Arbeit ersparen.

Code
STA $19
STA $0019
STA $7E0019


Diese drei Befehle sind alle möglich und speichern den Wert im Akkumulator in RAM Adresse $7E0019. Dafür sorgen die so gennanten Direct Page- und Data Bank Register. Diese ersetzen bei Befehlen wie LDA, STA und noch vielen anderen die fehlenden Ziffern. Das Data Bank Register (DB) ist eine 8-Bit Zahl, die das High Byte (das Byte ganz links) ersetzt, wenn man es wg lässt. In SMW ist es fast immer $7E. LDA $0019 ist deshalb also gleichzusetzen mit LDA $7E0019. Und was ist das Direct Page Register? Das Direct Page Register (DP) ist ein 16-Bit Register, dass bei einem LDA Befehl zur Adresse hinzuaddiert wird. Beispiel: Ist das Direct Page Register $0200 und ihr benutzt den Befehl "LDA $19", so wird in Wirklichkeit die Adresse $0219 geladen. Ist das Direct Page Register $05, so bekommt ihr die Adresse $001E wenn ihr "LDA $19" benutzt. In SMW ist das Direct Page Register meistens $0000. Hier sind noch ein paar weitere Beispiele:

; DB: $7E, DP: $0000

LDA $19

; Adresse im Accumulator: $7E0019


; DB: $7E, DP: $0201

LDA $19

; Adresse im Accumulator: $7E021A


; DB: $3E, DP: $0000

LDA $05

; Adresse im Accumulator: $3E0005


; DB: $2E, DP: $0300

LDA $0A

; Adresse im Accumulator: $2E030A


Wie genau man das Data Bank- und das Direct Page Register beeinflusst, erkläre ich euch an einer anderen Stelle. Diese Register haben übrigens nur auf Adressen Einfluss. Also wenn ihr z.B. schreibt "LDA #$AF", so wird die Zahl $AF in den Accumulator geladen, unabhängig vom Data Bank- und Direct Page Register.

Ach und noch etwas:

STA $19 ($19 = 8-Bit Adresse) nennt man Direct Adressing
STA $0019 ($0019 = 16-Bit Adresse) nennt man Absolute Adressing
STA $7E0019 ($7E0019 = 24-Bit Adresse) nennt man Long Adressing

Übrigens kann man auch Adressen in den Accumulator laden. Also

Code
LDA $19
LDA $0019
LDA $7E0019


sind alle drei möglich. Wäre Mario also gerade Cape Mario, so wäre nun der Wert $02 im Accumulator. Folgende Befehle sind nicht möglich (und währen auch ziemlich sinnlos):

Code
STA #$19
STA #$0019
STA #$7E0019


Übrigens ist es in xkas Patches auch möglich, bestimmte Begriffe mit Werten zu verknüpfen. Dafür müsst ihr einfach an den Anfang des Patches schreiben:

Code
!Powerup = $19
!ZufaelligeAdresse = $23
!NocheineAdresse = $50
[...]


Nun könnt ihr diese Begriffe ganz leicht in eurem Patch wiederverwenden:

Code
LDA !Powerup            ; = LDA $19
LDA #!Powerup ; = LDA #$19
LDA #!NocheineAdresse ; = LDA #$50


Beachtet, dass xkas zwischen Groß- und Kleinbuchstabe unterscheidet. Außerdem gibt es kein

Code
!Begriff1 = #$19


Stattdessen schreibt ihr

Code
!Begriff1 = $19


und dann nachher im Code

Code
LDA #!Begriff1


Es gibt auch noch den Befehl STZ (Set to Zero), mit dem ihr eine eine Adresse direkt auf $00 setzen könnt. Also

Code
STZ $19


entspricht

Code
LDA #$00
STA $19


Beachtet, dass STZ nur in Verbindung mit 8- und 16-bit Adressen geht. Es gibt kein STZ $7E0019 oder ähnliches.


---------------------------------------------------------------------------


LEKTION 4: EINFACHE RECHENOPERATIONEN

Die einfachsten zwei Rechenbefehle (wenn man sie denn so nennen kann) sind INC und DEC. INC inkrementiert (erhöht) einen Wert um $01, DEC dekrementiert (verringert) einen Wert um $01. Beispiele:

Code
LDA #$03
INC A ; Der Accumulator ist jetzt $04


Code
LDA #$06
DEC A ; Der Accumulator ist jetzt $05


Das ganze funktioniert aber nicht nur mit dem Accumulator, sondern auch mit Adressen.

Code
INC $19


inkrementiert RAM Adresse $19 um $01,

Code
DEC $19


dekrementiert RAM Adresse $19 umd $01.

Das geht aber nur mit 8- und 16-bit Adressen. INC $7E0019 z.B. geht nicht, genau so wenig wie DEC $7E1DBF.

Während das ganze zwar schon ziemlich toll ist, wäre es doch schön, wenn man auch beliebige Zahlen addieren bzw. subtrahieren könnte, oder? Nun, es geht! Dafür gibt es die Befehle ADC (Add with Carry) und SBC (Subtract with Carry). Diese addieren bzw. subtrahieren eine bestimmte Zahl vom Accumulator. Allerdings ist etwas wichtiges zu beachten:

Zitat
LDA #$01
CLC
ADC #$03 ; Der Accumulator enthält jetzt den Wert $04


Code
LDA #$09
SEC
SBC #$05 ; Der Accumulator enthält jetzt den Wert $04


Vor einer normalen Addition solltet ihr immer den Befehl CLC (Clear Carry Flag) und vor einer normalen Subtraktion den Befehl SEC (Set Carry Flag) schreiben. Wieso das so ist und mögliche Ausnahmen erkläre ich euch im nächsten Kapitel. Noch was wichtiges:

Code
LDA #$00
SEC
SBC #$01


Der Accumulator enthält nun den Wert $FF.

Code
LDA #$FF
CLC
ADC #$01


Der Accumulator enthält nun den Wert $00.

Ergibt eine Addition also einen Wert über $FF, so geht das ganze bei $00 weiter. Ergibt eine Subtraktion einen Wert unter $00, so geht das ganze bei $FF weiter.


---------------------------------------------------------------------------


LEKTION 5: DIE PROCESSOR FLAGS

Wenn es euch bis jetzt schwer gefallen ist diesem Tutorial zu folgen, solltet ihr noch mal die Zähne zusammenbeißen, denn hier wird es wieder ein bisschen abstrakt.

Also was sind Processor Flags? Processor Flags sind Bits der Hardware, die von bestimmten Befehlen unter bestimmten Umständen aktiviert werden. Die Processor Flags haben folgende Form:

envmxdizc

Jedes dieser Bits steht für eine Processor Flag. Abgesehen von der e Flag können alle Processor Flags mit dem Befehl REP gesetzt und mit SEP gecleart werden. Für einige Flags gibt es auch noch Sonderbefehle. Welche Befehle ihr genau für welche Flag braucht, erkläre ich euch an passender Stelle. Ein wichtiger Befehl für die Processor Flags ist CMP.

Code
LDA #$03
CMP #$02


Dieser Befehl vergleicht eine Zahl mit dem Accumulator, indem er sie von ihm subtrahiert. Dabei werden allerdings nur die Processor Flags beeinflusst, nicht der Accumulator selbst. Wenn ihr das CMP ganz weg lässt, so wird automatisch immer mit $00 verglichen. Nun erkläre ich euch, was die Processor Flags im eizelnen tun und wofür sie nützlich sein können.


e - Emulation Mode

Diese Flag ist für SMW nicht so wichtig und ich verstehe nicht so viel davon, deswegen gehe ich auch nicht weiter darauf ein. Alles was ich weiß ist, dass das SNES, wenn dieses Bit clear ist, im Emulation Mode ist und wie ein NES funktioniert. Ist das Bit gesetzt, ist das SNES im Native Mode. Wie bereits erwähnt, kann man dieses Bit nicht mit REP oder SEP beeifnlussen. Die einzige Möglichkeit dieses Bit zu setzten oder zu clearen ist es mit dem c Bit (wird nachher erklärt) zu tauschen. Dafür gibt es den Befehl XCE. Mit CLC cleart man das c Bit und mit SEC setzt man das c Bit. Mit diesem code aktiviert man also den Emulation Mode:

Code
CLC
XCE


Mit diesem Code aktiviert man den Native Mode

Code
SEC
XCE


Da ein SNES leistungsfähiger als ein NES ist, wird man bei einer ROM so früh wie möglich in den Native Mode wechseln wollen.


n - Negative Flag

Die Negative Flag wird immer dann aktiviert, wenn irgendeine vorhergehende Operation als Ergebnis einen Wert über $80 (8-bit Modus) oder über $8000 (16-bit Modus) hat. Wieso ist das so? Nun ganz einfach. Muss muss sich nur mal die Zahlen binär angucken.

$80 = %10000000

In vielen Situationen (zum Beispiel bei der Geschwindigkeit von Sprites) ist es so, dass es sehr nützlich wäre, wenn man auch negative Wert angeben könnte. Darum hat man sich gesagt, dass das höchste Bit (in diesem Fall Bit 7) das Vorzeichen darstellt. 0 = +, 1 = -. So einfach ist das! Alle Wert über $80 sind Minus-Werte! Darum wird die Negative Flag bei Werten über $80 bzw. über $8000 gesetzt. Manuell kann man die Negative Flag mit SEP #$80 setzen und mit REP #$80 clearen. Die Flag wird übrigens auch durch LDA beeinflusst. Also

Code
LDA #$91      ; Irgendeine Zahl über $80


setzt die Negative Flag, während

Code
LDA #$45      ; Irgendeine Zahl unter $80


sie cleart.


v - Overflow Flag

Wird gesetzt, wenn man eine Zahl zwischen $80 und $FF zum Accumulator hinzuaddiert und gecleart, wenn man eine Zahl zwischen $80 und $FF vom Accumulator subtrahiert.

Code
LDA #$03
CLC
ADC #$83


setzt die Overflow Flag,

Code
LDA #$03
SEC
SBC #$91


cleart die Overflow Flag.

Die Overflow Flag kann man manuell mit SEP #$40 setzen und mit REP #$40 clearen.


m - Accumulator Size Flag

Dieses Bit aktiviert man mit SEP #$20 und cleart es mit REP #$20. Es legt die Größe des Accumulators fest. Ist es gesetzt, hat der Accumulator eine Größe von 8-bit, andernfalls hat er eine Größe von 16-bit. Im 8-bit Modus kann der Accumulator Zahlen von $00 bis $FF enthalten. Im 16-bit Modus kann er Zahlen von $0000 bis $FFFF enthalten. Wenn der Accumulator 16-bit groß ist nennt man das linke Byte "High Byte" und das rechte Byte "Low Byte". Speichert man einen 16-bit Accumulator in eine Adresse, so wird auch die nachfolgende Adresse betroffen. Dabei wird in die angegebene Adresse das Low Byte und in die nachfolgende Adresse das High Byte gespeichert.

Beispiel:

Code
LDA #$13AF
STA $1DB9


Nach diesem Befehl enthält die Adresse $1DB9 den Wert $AF und die Adresse $1DBA den Wert $13. Mit dem Laden geht es genau so.

Achtung! Seid ihr im 16-bit und ladet eine 8-bit Zahl, wird das wahrscheinlich unvorhersehbare Folgen haben. Selbiges gilt, wenn ihr im 8-bit Modus seid und eine 16-bit Zahl ladet. Also Beispiel:

Code
REP #$20
LDA #$FF


oder

Code
SEP #$20
LDA #$FFFF


Diese Codes führen beide ins Chaos! Außerdem sollten ihr nicht vergessen, das Bit wieder zu setzen, wenn ihr es in einem Patch gecleart hat (in SMW ist es die meiste Zeit lang gesetzt).


x - Index Size Flag

Ist genau wie die Accumulator Size Flag, bloß, dass sie die Größe der Register X und Y bestimmt. Mehr zu diesen Registern in einem anderen Kapitel. Dieses Bit wird mit SEP #$10 gesetzt und mit REP #$10 gecleart.


d - Decimal Flag

Ist dieses Bit gesetzt, werden Rechnungen dezimal durchgeführt. Beispiel:

Code
LDA #$06
CLC
ADC #$06 ; Der Accumulator enthält jetzt den Wert $12, nicht etwa $0C


Setzen kann man dieses Bit entweder mit SEP #$08 oder mit dem Befehl SED. Clearen kann man dieses Bit entweder mit REP #$08 oder mit CLD.


i - Interrupt Disable Flag

Diese Flag kann Interrupts wie IRQ deaktivieren (allerdinsg kein NMI). Mehr dazu in einem anderen Kapitel... Vielleicht...

Kann mit SEP #$04 oder SEI gesetzt und mit REP #$04 oder CLI gecleart werden.


z - Zero Flag

Wird gesetzt, wenn eine vorhergehende Operation $00 ergibt. Also:

Code
LDA #$03
SEC
SBC #$03


setzt die Zero Flag, aber auch

Code
LDA #$FF
CLC
ADC #$01


setzt die Zero Flag. Kommt bei einer Rechnung nicht $00 heraus, wird die Zero Flag gecleart.


c - Carry Flag

Diese Flag wird immer dann gesetzt, wenn bei einer Addition ein Wert über $FF (bzw. $FFFF im 16-bit Modus) herauskommt und dann gecleart, wenn bei einer Subtraktion ein Wert unter $00 herauskommt. Es gibt auch andere Situationen, in denen die Carry Flag beeinflusst wird. Aber was bringt sie überhaupt?
Ich habe ja irgendwo oben erwähnt, dass man ADC immer in Kombination mit CLC und SBC immer in Kombination mit SEC verwenden soll. SEC setzt die Carry Flag, während CLC sie cleart. Bei ADC ist es in Wirklichkeit so, dass nicht nur die Zahl hinter ADC zum Accumulator hinzuaddiert wird, sondern auch die Carry Flag. Bei SBC ist es so, dass zusätzlich #$01 subtrahiert wird, wenn die Carry Flag clear ist. Ziemlich schwachsinnig, oder? Nun, nicht unbedingt! Es gibt auch Situationen, wo das für uns ziemlich nützlich sein kann!

Stellt euch vor ihr wollt einen Münzcounter mit 6 Stellen machen. Der Accumulator kann aber maximal Zahlen bis $FFFF (also 65535) enthalten. Alleine mit dem Accumulator ist das ganze also nicht möglich. Mit der Carry Flag geht das aber! Nehmen wir einmal an, dass die Adressen $7F0D00, $7F0D01 und $7F0D02 die Daten für den Münz Counter enthalten. Maximal wäre also ein Wert von $FFFFFF, 16777215 in dezimal, möglich. Sagen wir $7F0D02 wäre das High Byte und $7F0D00 das Low Byte. Auf folgende Weise kann man den Münz Counter realisieren:

Code
REP #$20
LDA $7F0D00
CLC
ADC #$01
STA $7F0D00
SEP #$20
LDA $7F0D02
ADC #$00
STA $7F0D02


Was genau macht dieser Code? Nun, zu erst mal wechseln wir mit REP #$20 in den 16-Bit Modus und laden die Adressen $7F0D00 und $7F0D01 in den Accumulator. Danach clearen wir die Carrly Flag und addieren $01 zum Accumulator hinzu. Stellt euch vor im Accumulator wäre nun die Zahl $FFFE. Wir addieren $01 hinzu, die Zahl ist nun $FFFF. Wir speichern diesen Wert wieder in $7F0D00. Danach gehen wir zurück auf den 8-Bit Modus, laden $7F0D02 und addieren $00 hinzu. Nichts passiert. Wir speichern den Accumulator wieder in $7F0D02 ab.

Nun stellt eucht vor ihr führt genau den selben Code noch einmal aus. Was passiert? Da $7F0D00 vorher $FFFF enthielt und ihr nun $01 hinzuaddiert, enthält $7F0D00 anschließend $0000, außerdem wird die Carry Flag gesetzt. Da ihr anschließend nicht die Carry Flag cleart, wird zu $7F0D02 zusätzlich $01 hinzuaddiert. Hatte der Münzcounter also vorher noch den Wert $00FFFF, enthält er jetzt den Wert $010000. Ziemlich praktisch, oder?

Die Carry Flag kann man auch noch mit SEP #$01 setzen und mit REP #$01 clearen.


So! Das war erst mal meine Einführung zu den Processor Flags. Zu abstrakt? Das muss aber sein, wenn man ASM wirklich verstehen will! Warum seht ihr in der nächsten Lektion.


---------------------------------------------------------------------------


LEKTION 6: BRANCHES UND SUBROUTINEN

Wie ihr sicherlich gemerkt habt, sind "LDA" und "STA" schon ganz toll. Mit diesen Befehlen alleine kann man allerdings noch keinen komplizierten Code schreiben. Es muss also irgendwie möglich sein, einen Code dynamisch zu schreiben, damit es auf verschiedene Situationen auch verschieden reagieren kann. Dafür gibt es so genannte "Branches". Gleich werdet ihr auch verstehen, was die Processor Flags mit dem ganzen zu tun haben.

Erst mal: Was sind Branches überhaupt? Nun "Branch" heißt übersetzt "Zweig". Branches gibt es in wirklich jeder Programmiersprache, nur heißen sie meistens anders (z.B. "If Case" oder "Condition"). Vereinfacht ausgedrückt überprüfen Branch Befehle den Status bestimmter Processor Flags und führen daraufhin einen von zwei möglichen Codes aus. Der allgemeine Aufbau ist dabei wie folgt:

Code
[BRANCH BEFEHL] Label
[BEFEHL] ;\
[BEFEHL] ; | FALL 1 (BEDINGUNG NICHT ERFÜLLT)
[BEFEHL] ;/
[...]
Label:
[BEFEHL] ;\
[BEFEHL] ; | FALL 2 (BEDINGUNG ERFÜLLT)
[BEFEHL] ;/
[...]


Das ist der grundlegende Aufbau der meisten Branch Befehle. Ganz oben steht der Branch Befehl, der eine Bedinung überprüft. Ist diese Bedingung erfüllt, so wird der in diesem Beispiel als FALL 1 betitelte Code übersprungen und direkt der Code unter dem Label (hier FALL 2) ausgeführt. Ist die Bedingung nicht erfüllt, so wird der Code unter dem Branch Befehl (hier FALL 1) ausgeführt. Beachtet allerdings, das danach trotzdem noch der unter dem Label stehende Code (also FALL 2) ausgeführt wird. Der Label kann übrigens ein x-beliebiger Name sein. Ihr müsst nur sicherstellen, dass er keine Leerzeichen enthält und dass ihr zwei mal den gleichen Namen verwendet. Also ihr könntet euren Label auch "BedingungErfuellt" nennen. Dann müsstet ihr statt "Label:" aber auch "BedingungErfuellt:" benutzen. Und beachtet unbedingt, dass xkas zwischen Groß- und Kleinschreibung unterscheidet. "label" und "Label" sind also nicht das selbe.

Es gibt noch andere Verwendungen für Branch Befehle, nämlich so genannte "Loops" oder "Schleifen". Der Aufbau ist ähnlich wie bei normalen Labels, allerdings rückwärts. Beispiel:

Code
Label:
[BEFEHL] ;\
[BEFEHL] ; | FALL 1 (BEDINGUNG ERFÜLLT)
[BEFEHL] ;/
[...][BRANCH BEFEHL] Label
[BEFEHL] ;\
[BEFEHL] ; | FALL 2 (BEDINGUNG NICHT ERFÜLLT)
[BEFEHL] ;/
[...]


Was macht dieser Code? Nun, zuerst wird der "FALL 1" Code ausgeführt, danach wird die Bedingung überprüft. Was passiert dann? Nun, wenn die Bedingung erfüllt ist, wird rückwärts im Code gesprungen. Das heißt der "FALL 1" Code wird erneut ausgeführt. Danach wird die Bedingung erneut überpüft. Ist sie wieder erfüllt, wird wieder der "FALL 1" Code ausgeführt. Das wiederholt sich dann so lange, bis die Bedingung nicht mehr erfüllt ist. Erst dann wird der "FALL 2" Code ausgeführt. Dieser Aufbau ist also nützlich, wenn ihr einen bestimmten Code x mal ausführen wolt. Ihr solltet allerdings aufpassen, dass ihr keine Endlos-Schleife kreiert, da sich das Spiel sonst aufhängt.

Im Spziellen gibt es nun folgende Branch Befehle (rechts daneben immer die Bedingung):

BEQ (Branch if Equal): Springt, wenn die Zero Flag gesetzt ist
BNE (Branch if not Equal): Springt, wenn die Zero Flag clear ist
BCC (Branch if Carry clear): Springt, wenn die Carry Flag gesetzt ist
BCS (Branch if Carry set): Springt, wenn die Carry Flag clear ist
BMI (Branch if Minus): Springt, wenn die Negative Flag gesetzt ist
BPL (Branch if Plus): Springt, wenn die Negative Flag clear ist
BVS (Branch if Overflow set): Springt, wenn die Overflow Flag gesetzt ist
BVC (Branch if Overflow clear): Springt, wenn die Overflow Flag clear ist
BRA (Branch always (8-bit)): Springt immer
BRL (Branch always long (16-bit)): Springt immer

OK... Aber was nützt uns das ganze jetzt? Nun an dieser Stelle ist vielleicht noch nicht klar, was das ganze Zeug mit den Processor Flags soll. Aber ihr werdet es nachher verstehen, wenn ich es euch erklärt habe. Ich fange mal mit den leichtesten Branch Befehlen an: BEQ und BNE.

BEQ springt, wenn die Zero Flag gesetzt ist. BNE springt, wenn die Zero Flag clear ist. Aber wann wird die Zero Flag denn überhaupt nochmal gesetzt? Nun, wir sollten uns hier an einen ganz wichtigen Befehl erinnern, der bei fast allen Branch Befehlen eine Rolle spielt: CMP. Wie war das nochmal? CMP subtrahiert virtuell eine Zahl von Accumulator, beeinflusst dabei aber in Wirklichkeit nur die Processor Flags. Und wann ist die Zero Flag nochmal gesetzt? Wenn das Ergebnis einer Operation $00 ergibt. Und wann passiert das? Nun, jetzt sind wir genau da angekommen, worauf ich hinaus wollte!

Code
LDA #$02
CMP #$02


Zero Flag = Gesetzt, da $02 - $02 = $00

Code
LDA #$7A
CMP #$7A


Zero Flag = Gesetzt, da $7A - $7A = $00

Code
LDA #$00


Zero Flag = Gesetzt, da $00 - $00 = $00
Wie schon mal erwähnt, kann man das "CMP #$00" einfach weg lassen.

Code
LDA #$03
CMP #$04


Zero Flag = Clear, da $03 - $04 = $FF

Aaaaaaaah! Dafür sind BEQ und BNE also gut! BEQ springt also immer dann, wenn zwei Zahlen gleich sind, während BNE springt, wenn zwei zahlen ungleich sind. Und um herauszufinden, wann das der Fall ist, werden die Processor Flags benutzt. Auf einmal ergibt alles einen Sinn! Allerdings gibt es noch mehr Situationen, in denen diese Befehle springen. Beispiel:

Code
[...]
LDA #$FE
CLC
ADC #$02
BEQ Label1
[...]
Label1:
[...]


Auch in diesem Fall springt BEQ zu Label1, da $FE + $02 = $00 ist. Verständlich, oder? Mit diesem ganzen Vorwissen dürften auch die meisten anderen Branch Befehle nun viel leichter zu verstehen sein. Kommen wir also zu BCS und BCC.

BCS springt, wenn die Carry Flag gesetzt ist, BCC springt, wenn die Carry Flag clear ist. Wann passiert das noch mal? Auch hier müssen wir uns wieder an CMP erinnern. CMP subtrahiert eine Zahl vom Accumulator, wir müssen uns hier also nur auf die Subtraktion konzentrieren. Wir sagten, dass cie Carry Flag gecleart wird, wenn bei einer Subtraktion ein das Ergebnis kleiner als $00 ist und wieder bei $FF ankommt. Beispiel:

Code
LDA #$02
CMP #$03


Carry Flag = Clear, da $02 - $03 = $FF

Code
LDA #$05
CMP #$07


Carry Flag = Clear, da $05 - $07 = $FE

Code
LDA #$04
SEC
SBC #$05


Carry Flag = Clear, da $04 - $05 = $FF

Code
LDA #$04
CMP #$03


Carry Flag = Set, da $04 - $03 = $01

Code
LDA #$04
CMP #$04


Carry Flag = Set, da $04 - $04 = $00

Mit BCC kann man also prüfen, ob eine Zahl kleiner ist als eine andere, während man mit BCS prüfen kann, ob eine Zahl größer oder gleich eine andere Zahl ist. Diese Befehle werdet ihr wahrscheinlich sehr häufig verwenden. Nehmen wir wieder Marios Powerup als Beispiel. Ihr wollt einen Block machen, der euch nur dann zu Feuer Mario macht, wenn ihr Small Mario oder Super Mario seid. Die RAM Adresse für Marios Powerup ist nach wie vor $19 und kann folgende Werte enthalten:

$00 - Small Mario
$01 - Super Mario
$02 - Cape Mario
$03 - Feuer Mario

Der Block soll euch also zu Feuer Mario machen, wenn Adresse $19 < $02 ist. Das lässt sich mit diesen Befehlen umsetzen. Eines sollte ich euch aber noch sagen: Wenn ihr mit Branches arbeitet, werdet ihr meistens den gegenteiligen Befehl von dem nehmen, den ihr eigentlich benutzen wollt. Hier nun ein Beispiel:

Code
LDA $19        ; Lade das Powerup
CMP #$01 ; Vergleiche mit $01
BCS NichtFeuerMario ; Größer/gleich $01? Dann nicht zu Feuer Mario machen!
LDA #$03 ;\ Andernfalls mache Mario zu Feuer Mario
STA $19 ;/
NichtFeuerMario:
[...]


So z.B. könnte das ganze aussehen. Aber wieso wäre hier BCC nicht ganz so schön? Nun, das zeige ich euch gerne:

Code
LDA $19        ; Lade das Powerup
CMP #$02 ; Vergleiche mit $02
BCC FeuerMario ; Kleiner $02? Dann mache Mario zu Feuer Mario
[...]
FeuerMario:
LDA #$03 ;\ Dieser Code wird immer ausgeführt
STA $19 ;/


Nun ist ganz leicht zu sehen, warum BCS hier eindeutig besser geeignet ist. Benutzt ihr BCC, so wird, wenn die Bedingung erfüllt ist, der Code unter "BCC" gar nicht ausgeführt. Anders wird aber der Code unter "FeuerMario:" selbst dann ausgefüllt, wenn die Bedingung nicht erfüllt ist. Zugegeben, dieses Problem ließe sich leicht beheben:

Code
LDA $19        ; Lade das Powerup
CMP #$02 ; Vergleiche mit $02
BCC FeuerMario ; Kleiner $02? Dann mache Mario zu Feuer Mario
AndererCode:
[...]
BRA Ueberspringen
FeuerMario:
LDA #$03 ;\ Mache Mario zu Feuer Mario
STA $19 ;/
BRA AndererCode
Ueberspringen:


Dieser Code funktioniert genau wie der Code mit BCS, da "BRA" immer springt. Allerdings enthält er einige Befehle mehr (ist also minimal langsamer) und sieht auch einfach hässlicher aus. Ihr solltet euch also schon mal daran gewöhnen, bei Branch Befehlen etwas umzudenken. Am Anfang ist es aber noch normal, wenn man es auf die eben gezeigte Art und Weise macht.

Kommen wir zu den nächsten zwei Branch Befehlen: BMI und BPL.

Hier gibt es eigentlich nicht viel zu erzählen. BMI springt, wenn die Negative Flag gesetzt ist, also bei einer negativen Zahl. BPL hingegen springt, wenn die Negative Flag clear ist, also bei einer positivien Zahl. Darauf will ich nicht lange eingehen. Nur ein paar Beispiele:

Code
LDA #$81
BMI


Negative Flag = Gesetzt, BMI springt

Code
LDA #$10
BMI


Negative Flag = Clear, BMI springt nicht

Code
LDA #$40
BPL


Negative Flag = Clear, BPL springt

Code
LDA #$FF
BPL


Negative Flag = Gesetzt, BPL springt nicht.

Keine Ahnung, wo das nützlich sein könnte. Vielleicht bei der Programmierung von Sprites.

BVS springt dann, wenn die Overflow Flag gesetzt ist. BVC springt dann, wenn die Overflow Flag clear ist.

Ich kann mir echt nicht vorstellen, wo das nützlich sein könnte. Hier aber mal einige Beispiele:

Code
LDA $03
CLC
ADC #$9A
BVS IrgendEinLabel


Overflow Flag = Gesetzt, BVS springt

Code
LDA
SEC
SBC #$BC
BVC IrgendEinLabel


Overflow Flag = Clear, BVC springt

Ich denke darauf brauche ich nicht weiter einugehen.

Nun noch die letzten zwei Branch Befehle: BRA und BRL.

BRA und BRL springen immer. Dabei ist BRA 8-bit und BRL 16-bit. Wie jetzt, 8-bit und 16-bit? Ach stimmt ja, das habe ich ja noch gar nicht erwähnt!

Oben habe ich ja die ganze Zeit Labels verwendet. Das liegt daran, dass ich die ganze Zeit davon ausging, dass wir xkas benutzen. In Wirklichkeit gibt es im Programmcode von SMW aber keine Label. Branch Befehle geben nämlich nicht an, wohin sie springen sollen, sondern wie viele Bytes sie überspringen sollen. Wenn wir Labels verwenden, übersetzt xkas das ganze aber entsprechend. Außerdem sollte man wissen, dass der Wert hinter einem Branch Befehl immer ein signierter Wert ist. Das bedeutet, dass Zahlen von $80 bis $FF (bzw. von $8000 bis $FFFF) als negative Zahlen gedeutet werden. Muss ja so sein, denn sonst wären Loops überhaupt nicht möglich. Nun noch einige Beispiele dazu:

Code
BEQ Label1
LDA #$03
STA $19
LDA #$04
STA $0DBE
Label1:


sieht in Wirklichkeit so aus:

Code
BEQ $09
LDA #$03
STA $19
LDA #$04
STA $0DBE


Warum hier $09 hinkommt und nicht etwa $04, wie ihr vielleicht geglaubt habt, erkläre ich euch an einer anderen Stelle.

Code
Label1:
LDA #$03
STA $19
LDA #$04
STA $0DBE
LDA $0DBF
BEQ Label1


sieht in Wirklichkeit aus so aus:

Code
LDA #$03
STA $19
LDA #$04
STA $0DBE
LDA $0DBF
BEQ $8B


Ich hoffe mal, das wurde so einigermaßen verstanden. Ach ja, noch was:

Code
BRA $00


tut überhaupt gar nichts.

Das war's dann soweit zu Branches. Allerdings möchte ich in dieser Lektion auch noch ein paar andere wichtige Funktionen erläutern, nämlich Jumps und Subroutinen.

Als aller erstes mal Jumps. Für Jumps gibt es die Befehle JMP (16-bit) und JML (24-bit). Sie funktionieren ähnlich wie BRA und BRL, haben aber einen entscheidenden Vorteil: Sie können nicht nur $80 bzw. $8000 Bytes überspringen, sondern an eine beliebige Stelle in der ROM springen. Darum kommt hinter diese Befehle auch nicht die Anzahl der Bytes, die ihr überspringen wollt, sondern die Adresse, zu der ihr springen wollt. Beispiel:

Code
JML $248200


springt zu Adresse $2482000 in eurer ROM.

Code
JMP $8200


springt zu Adresse $XX8200 in eurer ROM.

Das ganze kann ziemlich nützlich sein, wenn ihr xkas Patches schreibt. Aber das erkläre ich euch an einer anderen Stelle.

Nun gibt es aber sogar noch etwas viel nützlicheres: Nämlich Subroutinen.

Was sind Subroutinen? Was eine Routine ist, wisst ihr sicherlich, nämlich eine Ansammlung von Code mit einem bestimmten Spiel. Beispiel:

Code
LDA #$03
STA $19


Das ist eine Routine, die Mario zu Feuer Mario macht.

Nun stellt ich vor, ihr habt eine Routine, die sehr häufig im Spiel aufgeführt wird. Beispiel: Die "Level End" Routine. Diese wird nach jedem Level ausgeführt. Nun gäbe es zwei Optionen. Entweder wir machen für jedes Level eine neue Level End Routine. Das würde aber sehr viel Speicherplatz verbrauchen. Deswegen entscheiden wir uns für die bessere Lösung: Subroutinen!

Um es mal einfach auszudrücken: Subroutinen sind Routinen, die von einer beliebigen Position in eurer ROM aus aufgerufen werden können und nachdem sie beendet wurden wieder an die Position zurück springen, von der aus sie aufgerufen wurden. Subroutinen werden mit JSR (16-bit) oder JSL (24-bit) aufgerufen. Mit RTS (16-bit) oder RTL (24-bit) kehrt man von einer Subroutine zurück. Nun versuche ich mal euch das ganze zu veranschaulichen.

Code
LDA #$03
STA $19
JSL $248200
LDA #$04
STA $0DBE

org $248200
LDA #$00
STA $0DBF
RTL


Fangen wir mal oben an. Wir laden den Wert $03 und speichern ihn in Adresse $19. Was genau das bringt spielt bei diesem Beispiel keine Rolle. Nun kommen wir bei JSL an. Was passiert jetzt? Das Programm springt jetzt an Adresse $248200 in der ROM. org benutzen wir in xkas Patches um dem Programm zu sagen, dass wir an einer bestimmten Adresse Code einfügen wollen. org $248200 fügt also Adresse $248200 den Code
LDA #$00
STA $0DBF
RTL
Das habe ich aber nur gemacht, damit man leichter nachvollziehen kann, was passiert, denn jetzt wissen wir genau, was unter $248200 passiert, zu der wir soeben gesprungen sind. Als nächstes wird also der Wert $00 geladen und in Adresse $0DBF gespeichert. Dann treffen wir auf das RTL. Was passiert jetzt? Jetzt springen wir zurück an die Stelle, an der das JSL stand und führen den Code dahinter auf, laden also in diesem Fall $04 und speichern den Wert in Adresse $0DBE.

Habt ihr nun so einigermaßen verstanden, wie Subroutinen funktionieren? Klar, dieses Beispiel wäre ohne Subroutine tausend mal besser. Aber stellt euch vor ihr hättet eine Routine von über 1000 Bytes, die nach jedem Level ausgeführt wird. In dem Fall würde man wirklich eine Menge Speicherplatz (und Zeit) verschwenden, wenn man die Routine für jedes Level neu schreiben würde. In solchen Fällen sind Subroutinen also wirklich Pflicht. Schlauer Einsatz von Subroutinen erleichtert euch die Programmierung in ASM um einiges!

Ach ja, noch etwas: Custom Blocks sind IMMER Subroutinen. Daher muss am Ende von Custom Blocks immer RTS (block tool) oder RTL (BTSD) stehen. Glückwunsch! Nun seid ihr bereits in der Lage eure eigenen Custom Blocks zu programmieren!


---------------------------------------------------------------------------


SPEZIAL 1: PRAXISTEST 1

Nun kommen wir zur aller, aller wichtigsten Lektion in Sachen ASM. Wer diese Lektion nicht beachtet, wird niemals erfolgreich in ASM programmieren können. Dabei ist sie so leicht! Sie lautet:

NICHT DURCH TUTORIALS LERNT MAN ASM, SONDERN DURCH AUSPROBIEREN!

Und da man sich zu so etwas aber ziemlich schwer durchringen kann, stelle ich euch hier ein paar Aufgaben, die ihr bewältigen solltet, bevor ihr euch an die nächste Lektion begebt.

-Erstellt einen Custom Block, der eure Münzen um 1 erhöht.
-Erstellt einen Custom Block, der eure Münzen nur dann um 1 erhöht, wenn ihr weniger als 99 (dezimal) Münzen habt und eure Münzen ansonsten auf 0 setzt.
-Erstellt einen Custom Block, der eure Leben um 1 erhöht, wenn ihr Feuer Mario seid.
-Erstellt einen Custom Block, der euch zu Cape Mario macht, wenn ihr 30 (dezimal) oder mehr Münzen habt und eure Münzen danach auf 0 setzt.
-Erstellt einen Custom Block, der euch zu Cape Mario macht, wenn ihr genau 0 Münzen habt.
-Erstellt einen Custom Block, der euch zu Cape Mario macht, wenn ihr nicht genau 0 Münzen habt.
-Erstellt einen Custom Block, der eure Münzen so lange um 1 erhöht, bis ihr genau 50 (dezimal) habt. Beachtet dabei, dass die Münzen nicht über 99 (dezimal) gehen dürfen).
-Erstellt einen Custom Block, der mit JSR zu einer Subroutine springt, die überprüft, ob ihr 50 (dezimal) oder mehr Münzen habt und in diesem Falle eure Münzen auf 0 setzt. Danach soll sie zur Hauptroutine zurück kehren.

Hiermit sei euch noch mal die RAM Map von SMW Central an's Herz gelegt. Da findet ihr eigentlich alles, was ihr für die Bewältigung dieser Aufgaben benötigt.

Könnt ihr diese Aufgaben alle blind bewältigen? Dann seid ihr bereit für die nächste Lektion!


---------------------------------------------------------------------------


LEKTION 7: INDEXING

Kommen wir nun zu einer der, wie ich finde, nützlichsten Funktionen in ASM, wenn man denn in er Lage ist sie zu meistern. Ich rede vom Indexing.

Ziemlich am Anfang habt ihr den Akkumulator (oder "A") als ein Register kennengelernt, mit dem man verschiedene Rechnungen durchführen und noch viel mehr anstellen kann. Nun möchte ich euch zwei Register vorstellen, die dem Akkumulator sehr ähnlich sind, jedoch noch ein paar Zusatzfunktionen haben und dafür ein paar Dinge nicht können, die der Akkumulator kann. Ich rede von den X- und Y Registern, auch "Index Register" genannt.

Viele der Befehle, die es für den Akkumulator gibt, gibt es auch für die X- und Y Register. Z.B. gibt es LDX und LDY zum laden von Werten und Adressen, STX und STY zum Speichern der Werte in Adressen, INX und INY bzw. DEX und DEY zum erhöhen bzw. verringern der Register, CPX und CPY zum Vergleichen der Register mit einer Zahl und sogar noch viele mehr. Das alles ist aber nur nebensächlich. Was diese Register viel interessanter macht ist das so genannte Indexing.

Stellt euch vor ihr wolltet einen Block machen, der abhängig von eurem Powerup verschiedene Routinen ausführt. Sagen wir einfach mal er soll eure Münzen um eine je nach Powerup variierende Anzahl erhöhen:

Small Mario - 10 Münzen
Super Mario - 25 Münzen
Cape Mario - 35 Münzen
Feuer Mario - 50 Münzen

Nach unserem bisherigen Wissen sollte das in etwa so aussehen:

Code

LDA $19
CMP #$00 ; Powerup nicht 0? Mario nicht klein!
BNE Nichtklein
LDA #$10
BRA Addieren

Nichtklein:
CMP #$01 ; Powerup nicht 1? Mario nicht Super Mario!
BNE NichtSuperMario
LDA #$25
BRA Addieren

NichtSuperMario:
CMP #$02 ; Powerup nicht 2? Mario nicht Cape Mario!
BNE NichtCapeMario
LDA #$35
BRA Addieren

NichtCapeMario: ; Dann kann Mario höchstens noch Feuer Mario sein
LDA #$50

Addieren:
CLC
ADC $0DBF
STA $0DBF


Wie ihr seht, ist das schon ganz schön viel Schreibarbeit. Nun stellt euch mal vor ihr hättet nicht 4 verschiedene Werte, sondern 100. Da sähe die Sache nochmal ganz anders aus. Weil das wohl auch den Programmierern von damals zu blöd war, erfand irgendeiner schlauer Kopf das Indexing, das einem eine Menge Arbeit erspart. Hier nun der obige Code nochmal, bloß mit Indexing:

Code

LDX $19
LDA MuenzTabelle,x
CLC
ADC $0DBF
STA $0DBF

MuenzTabelle:
db $10,$25,$35,$50


Woah! Das sieht doch schon mal wesentlich besser aus, nicht wahr? Nun mal zu Erläuterung. Als erstes mal sollte man alle in Frage kommenden Werte in einer Tabelle festhalten. In ASM gibt es verschiedene Formen von Tabellen, in diesem Beispiel wird die Tabelle durch "db" eingeleitet. Dahinter stehen die einzelnen Werte der Tabelle, die jeweils mit Kommata abgetrennt sind. Bitte merkt euch diesen Aufbau genau. Zuerst der Tabellentyp (hier "db"), dann ein Leerzeichen, dann die einzelnen Werte, jeweils durch Kommata abgetrennt. Hinter den Kommatas dürfen keine Leerzeichen stehen und hinter dem letzten Wert darf kein Komma stehen. Andere Tabellentypen sind zum Beispiel:

Code

16BitTabelle:
dw $0000,$0002,$3456,$7895,$AAFF

24BitTabelle:
dl $700360,$700366,$70036A


In diesen Beispielen haben die Werte einfach nur verschiedene Längen. Ihr braucht euch aber nur "db" zu merken. Im Grunde genommen sind db, dw und dl sowieso alle genau gleich und sollen den Programmcode nur übersichtlicher machen. Werden solche Tabellen in eine ROM eingefügt, werden einfach nur die einzelnen Bytes in der selben Reihenfolge in die ROM eingefügt. Also nehmen wir einfach mal diese Tabelle:

Code

TestTabelle1:
db $00,$01,$02,$03,$04,$05


Fügen wir diesen Code in einer ROM an einer bestimmten Stelle ein (zum Beispiel mit xkas), so würde an dieser Stelle dann in Hex stehen:

Code
...00 01 02 03 04 05...


Dasselbe Ergenbis würde man mit folgenden Tabellen erreichen (auch bei Tabellen stehen die niederwertigeren Bytes immer vorne):

Code

TestTabelle2:
dw $0100,$0302,$0504

TestTabelle3:
dl $020100,$050403


Bei manchen Assemblern, wie zum Beispiel Trasm, welcher von sprite tool benutzt wird, weichen die Tabellenbezeichnungen geringfügig ab. So verwendet man z.B. statt "db" in Trasm "dcb" oder statt "dw" dann "dcw".

Also ich hoffe mal ihr versteht so einigermaßen das Prinzip hinter Tabellen. Aber nun zurück zum eigentlichen Code. Mit der Tabelle alleine können wir ja noch nicht viel anfangen, erstmal müssen wir indexen. Hier kommen jetzt die Index Register ins Spiel.

Code

LDX $19
LDA MuenzTabelle,x
[...]


Was LDX $19 tut wissen wir bereits: Es lädt den Wert der Adresse $19 in das X Register. Wirklich neu ist nur das LDA MuenzTabelle,x. Dieser Befehl lädt den x-ten Wert der Tabelle "MuenzTabelle" in den Akkumulator. Was genau heißt das jetzt? Nun, wir haben die Adresse $19 in unser X Register geladen. Dies ist, wie ihr wisst, Marios Powerup. Hier noch mal die genauen Werte:

$00 = Klein
$01 = Super Mario
$02 = Cape Mario
$03 = Feuer Mario

Stellen wir uns nun vor Mario ist klein. In dem Fall wird also der 0. Wert der MuenzTabelle in den Akkumulator geladen. Da wir bei Computern immer bei 0 anfangen zu zählen, laden wir also eine $10 in den Akkumulator. Ist Mario hingegen Super Mario, laden wir den 1. Wert, also $25 in den Akkumulator. Bei Cape Mario entsprechend $35 und bei Feuer Mario $50. So einfach geht das und es verkürzt euren Code in bestimmten Fällen ungemein. Das ganze geht aber auch mit RAM Adressen und wird sogar im Spiel so genutzt. Stellt euch nun vor ihr macht einen Patch für zwei Spieler. Natürlich soll jeder Spieler seine eigenen Adressen haben, aber ihr wollt auch nicht jede Funktion für jeden Spieler extra programmieren. Hier ist das Indexing sehr nützlich. Hier mal ein Beispiel direkt aus SMW:

$0DB3 = Der momentane Spieler; $00 = Mario, $01 = Luigi
$0DB4 = Marios Leben
$0DB5 = Luigis Leben
$0DBE = Leben des momentanen Spielers

Stellt euch vor ihr seid gerade am Ende eines Levels und wollt, dass eure Anzahl an Leben aus Adresse $0DBE in die dafür vorgesehene Adresse für den jeweiligen geschrieben wird. Das geht durch Indexing ganz leicht, denn auch für das Speicher von Werten gibt es einen Indexing Befehl:

Code

LDX $0DB3 ; Anzahl an Spieler in X laden
LDA $0DBE ; Anzahl Leben in A laden
STA $0DB4,x ; Und in $0DB4 + x speichern


Dies funktioniert im Prinzip genau wie mit dem Laden, bloß andersherum. Ihr lädt den aktuellen Spieler in X und die Anzahl an Leben in $0DBE. Nun müsst ihr euch einfach vorstellen, dass unter $0DB4 eine Tabelle sein, in der ihr den Wert speicher wollt. Seid ihr Mario und ist das X Register somit $00, wird eure Anzahl an Leben an 0. Stelle, also in Adresse $0DB4 gespeichert. Seid ihr Luigi und ist das X Register somit $01, so wird die Anzahl an Leben an 1. Stelle gespeichert, also in $0DB5.

Vielleicht blickt ihr bei dem ganzen noch nicht so wirklich durch und findet es ziemlich kompliziert, aber macht euch da mal keine Gedanken. Das ist am Anfang völlig normal und reine Probiersache. Irgendwann habt ihr den Dreh dann raus und seid froh, dass es diese Tabellen und Indexing gibt.

Ach ja noch eine Kleinigkeit: Oben habe ich die ganze Zeit das X Register verwendet, aber mit dem Y Register geht das natürlich genauso. Lediglich eine kleine Einschränkung ist zu beachten. Während

Code

STA $19,x
STA $0019,x
STA $7E0019,x


allesamt möglich sind, gibt es beim Y Register nur

Code

STA $19,y
STA $0019,y


und kein "STA $7E0019,y". In der Regel solltet ihr also das X Register benutzen. Manchmal werdet ihr allerdings mit beiden arbeiten müssen. Außerdem solltet ihr wissen, dass ihr die Größe der Index Register ähnlich wie beim Akkumulator verändern könnt (was ja schon in der Lektion mit den Processor Flags angekratzt wurde). Mit REP #$10 stellt ihr die Größe der Index Register auf 16-bit, während ihr sie mit SEP #$10 wieder auf 8-bit stellt. Benutzt ihr REP #$30 und SEP #$30, so könnt ihr die Akkumulatorgröße und die Größe der Index Register gleichzeitig verändern.
-Das quadratische Rad neu erfinden-
Mit das quadratische Rad neu erfinden (englisch Reinventing the square wheel) bezeichnet man die Bereitstellung einer schlechten Lösung, wenn eine gute Lösung bereits existiert.

-Slowsort-
Slowsort (von engl. slow: langsam) ist ein langsamer, rekursiver Sortieralgorithmus, der nach dem Prinzip Vervielfache und kapituliere (engl. Multiply and surrender, eine Parodie auf Teile und herrsche) arbeitet.

geschrieben am 14.09.2010 17:57:14 in Deutsches Sample Tool (SMWS) Tutorial
( Link )
Hier kommt nun mein deutsches Sample Tool Tutorial. Ich weiß ja, dass hier außer Cellcen so ziemlich niemand Custom Music macht und davon abgesehen ist sample tool auch nicht wirklich schwer zu benutzen, aber so ein Tutorial kann trotzdem ziemlich nützlich sein. Daher



Deutsches Sample Tool Tutorial by RPG Hacker



Was ist sample tool überhaupt?

Leute, die SMW Custom Music machen, dürften gemerkt haben, dass es manchmal ziemlich schwierig bist unmöglich ist, geportete Musik wie das Original klingen zu lassen. Das liegt ganz einfach daran, dass die SMW Instrumente so limitiert sind und es oftmals kein Instrument in SMW gibt, dass so richtig zu geporteten Lied passt. Aus diesem Grund hat smkdan sample tool entwickelt. Mit diesem Tool ist es nun endlich möglich die Instrumente in SMW durch andere zu ersetzen.


Ich verliere also die originalen SMW Instrumente? Und gibt es sonst irgendwelche Haken an der ganzen Sache?

Langsam! Erstens: NEIN! Ihr verlieret die SMW Instrumente NICHT! Sample Tool ersetzt die Instrumente nämlich auf einer "pro Level"-Basis. Das heißt ihr könnt selbst bestimmen, welches Level welche Instrumente benutzt. Zweitens: Die einzigen Haken:

-Einige samples (=Instrumente) werden auch von Soundeffekten benutzt (Ersetzen=Unheil)
-Der Speicherplatz für die samples ist ziemlich begrenzt
-Bis jetzt können nur samples 1 bis 13 verwendet werden (außer man ist Japaner)
-Es können die Instrumente nur in Levels verändert werden (nicht auf der Overworld)

Ansonsten sind euch im Grunde genommen keine Grenzen gesetzt. Ihr könnt sogar WAV-Dateien mit sample tool in eure ROM einfügen. So könnt ihr z.B. sogar Stimmen in euerem Spiel verwenden! Ihr solltet die WAV-Dateien vorher aber auf 8000 Hz und 8-bit Mono konvertieren, da sie ansonsten a) zu groß sind und b) ganz einfach nicht richtig mit dem SNES kompatibel sind.


Legen wir los!

Also als erstes mal solltet ihr euch natürlich das Tool SMWS von SMW Central runterladen. Als nächstes braucht ihr eine SPC-Datei, die das gewünschte Instrument enthält. Beispiel: Wir wollen das Instrument, dass die SMW Castle Main Melody spielt, durch die Orgel aus Mario Paint ersetzen. Also holen wir uns irgendeine SPC-Datei aus Mario Paint, die das gesuchte Instrument abspielt. Alternativ geht auch eine eine WAV-Datei im richtigen Format (siehe oben).

Öffnet eure ROM in sample tool. Ihr solltet nun dieses Fenster sehen:

Hier müsst ihr eine beliebige Free Space Adresse mit genügend freiem Speicherplatz (ca. 1024 Bytes) angeben. Danach installiert sample tool einen ASM Hack in eurer ROM. Das braucht ihr nur ein einziges mal zu tun. Solltet ihr den Hack aus irgendeinem Grund später wieder entfernen wollen, könnt ihr das im Menü tun.

Nachdem ihr die Adresse angegeben habt, solltet ihr dieses Fenster sehen:

Erstmal zur Erklärung: Eine Bank in sample tool ist ein Set von Instrumenten. Bank F ist die Standard Bank in SMW. Diese Bank könnt ihr nicht löschen oder bearbeiten. Erstellt ihr eine neue Bank in sample tool, so ist diese eine exakte Kopie von Bank F. Allerdings könnt ihr hier die Instrumente ersetzen. Dazu solltet ihr erst mal unter "Level Banks" das Level aussuchen, für das ihr die Instrumente verändern wollt. In diesem Beispiel Level 105. Dann müsst ihr bei "Add new bank" die Nummer der neuen Bank angeben, die ihr erstellen wollt und auf "Add bank" klicken. Außer den Banks 0 - 10 könnt ihr jede Bank vewenden, die noch nicht belegt ist. Manchmal kann es allerdings passieren, dass sample tool ein RATS Tag in eurer ROM entdeckt und deswegen die Bank nicht erstellen kann. In dem Fall probiert ihr einfach eine andere Nummer aus. Das tut ihr so lange, bis ihr eine freie Bank gefunden habt (bei mir hat's z.B. bei 12 funktioniert). Danach sollte euer Fenster etwa so aussehen:


Wie ihr seht, könnt ihr nun rechts eure Banks bearbeiten. Bei "Bank to edit" solltet ihr die Bank aussuchen, die ihr bearbeiten wollt (in diesem Fall also die neu erstellte Bank 12). Darunter, bei "samples", könnt ihr die einzelnen samples in dieser Bank auswählen. Danach könnte ihr sie euch unten links mit einem Klick auf "Play" anhören (bei "Playback Pitch" könnt ihr die Wiedergabe-Geschwindigkeit einstellen). Bedenkt allerdings, dass eingie Samples so kurz sind, dass sie für das menschliche Ohr regelrecht unhörbar sind.

So, sagen wir nun wir wollen Sample 1 (das Instrument für die SMW Castle Main Melody) durch die Orgel aus Mario Paint ersetzen. Zu erst mal solltet ihr einen Blick auf "Free space" werfen. FDA Bytes. Das sind nicht gerade viel. Mir müssen also Speicherplatz schaffen! Wie machen wir das? Indem wir bereits vorhanden samples löschen. Als erstes sollten wir uns ein sample suchen, dass im jeweiligen Level nicht verwendet wird. Die Distortion Guitar z.B., Sample 11, wird im Castle Theme nicht verwendet. Wählen wir sie also bei "Sample" aus. Bei Size sehen wir nun die Größe dieses Samples. Oh! Prima! Die Distortion Guitar ist auch noch ziemlich groß. Das heißt wenn wir sie löschen, sollten wir genügend Speicherplatz frei haben. Also klickt auf "Delete Sample". Da wir Sample 1 ersetzen wollen, müssen wir das auch jetzt auswählen und löschen. Nun sollte euer Fenster etwa so aussehen:


Merkt ihr, wie ihr nun viel mehr Free Space als vorher habt?

Nun wollen wir das Sample ins Spiel einfügen. Für Wave Dateien müsst ihr "Insert" oder "Insert Looped" auswählen. Wir wollen aber ein Instrument aus einer SPC-Datei rippen, also wählen wir "Insert SPC" und öffnen dann die jeweilige SPC-Datei, in diesem Fall also eine SPC-Datei, die die Mario Paint Orgel abspielt. Ihr solltet nun dieses Fensterchen sehen:


Bei "Sample" könnt ihr nun alle Samples aus der SPC-Datei auswählen und dann unten bei "Play" wie schon zuvor beim Hauptfenster abspielen. Das macht ihr so lange, bis ihr das gewünschte Sample gefunden hat. Die Orgel aus Mario Paint z.B. ist Sample 9. Nun müsst ihr entweder "Insert" oder "Insert Looped" auswählen. "Insert" wird meistens für Soundeffekte verwendet, während "Insert Looped" für Instrumente verwendet wird (Insert Looped beduetet, dass das Sample nach dem abspielen wiederholt wird). Wir wollen ein Instrument ersetzen, deswgen klicken wir auf "Insert Looped". Nun kommen wir zum Hauptfenster zurück. Hier klicken wir auf "Save bank" um die Bank zu speichern. Dnach klicken wir auf "File > Save" um die Veränderungen auf die ROM zu übertragen. Fertig! Das war's! Ihr habt nun erfolgreich ein Sample aus Super Mario World ersetzt. Glückwunsch! Zum Testen solltet ihr erst einmal eure ROM in Lunar Magic öffnen und dann für Level 105 die Musik auf das Castle Theme setzen. Danach öffnet ihr eure ROM in einem Emulator und geht in Level 105. Hört ihr den Unterschied? Wenn ja, dann ist alles gut gelaufen. Wenn nicht, dann versucht es noch einmal.

Wenn ihr nun die selbe Bank auch noch in einem anderen Level verwenden wollt, geht das ganz einfach: Ihr wählt bei "Level banks" das jeweilige Level aus und dann da drunter einfach die Bank (also in diesem Fall einfach Bank 12). Danach wieder über "File > Save" speichern und fertig!

Über "Export bank" könnt ihr übrigens eure Bank in einer Datei speichern. Das ist sehr nützlich, wenn ihr Custom Music veröffentlicht und dafür eigene Instrumente verwendet. Dann könnt ihr ganz einfach die Bank exportieren und mit der Custom Music hochladen. Über "Import bank" könnt ihr diese Datei dann ganz leicht in eure ROM laden. Fertig!

War doch ein Kinderspiel, oder? Hausaufgaben: Atemberaubende Custom Music erstellen!
-Das quadratische Rad neu erfinden-
Mit das quadratische Rad neu erfinden (englisch Reinventing the square wheel) bezeichnet man die Bereitstellung einer schlechten Lösung, wenn eine gute Lösung bereits existiert.

-Slowsort-
Slowsort (von engl. slow: langsam) ist ein langsamer, rekursiver Sortieralgorithmus, der nach dem Prinzip Vervielfache und kapituliere (engl. Multiply and surrender, eine Parodie auf Teile und herrsche) arbeitet.

geschrieben am 14.09.2010 17:59:24 in Lunar Magic 1.64+ - Custom Sprites Collection
( Link )
Da das ganze gar nicht so offensichtlich ist, erkläre ich euch in diesem Tutorial mal, wie das ganze mit der Custom Sprite Collection in Lunar Magic 1.64 geht. Dazu gehören:

-Hinzufügen der Sprites zur Custom Sprites Collection Liste
-Sprites aus der Liste ins Spiel einfügen
-Anzeige der richtigen Grafiken in Lunar Magic

Einzige Vorraussetzung ist, dass ihr die jeweiligen Sprites schon mit sprite tool ins Spiel eingefügt habt und natürlich, dass ihr Lunar Magic 1.64 startbereit habt.

Also fangen wir an!

Ich habe so eben den Poison Goomba aus meinem HP Counter Patch mit sprite tool in mein Spiel eingefügt. Nun möchte ich, dass er in Lunar Magic richtig angezeigt wird.

Als erstes öffnen wir in Lunar Magic unser Projekt, gehen dann in den Sprite Editing Mode, öffnen das "Add Sprites" Fenster und wählen dann aus dem Dropdown Menü die neue Option "Custom Collection of Sprites" aus. Nun solltet ihr ein Fenster bekommen, dass in etwa so aussieht:



Wie ihr seht habe ich schon einige Sprites in meiner Liste. Bei euch wird sie wahrscheinlich noch ganz leer sein. Auch der Poison Goomba ist bei mir schon als Sprite Nummer 02 drin. Zur Demonstration füge ich ihn nun aber noch ein zweites mal als Sprite Nummer 04 ein.

Nun gut. Zunächst solltet ihr mal in Lunar Magic auf "Options gehen" und sicherstellen, dass neben der Option "Display Custom Sprites" ein Häkchen ist. Danach solltet ihr die Custom Sprite erstmal ganz normal manuell einfügen, so, wie ihr es bis jetzt immer getan habt. Da wir uns schon im Sprite Editing Mode befinden, müssen wir einfach nur auf "Einfügen" drücken. Nun bei "Command" die Nummer der Sprite, also 04 und bei Extra Info dann 2 oder 3, je nachdem ob ihr das Extra Bit eurer Sprite aktiviert haben wollt oder nicht. In meinem Fall nein, also 2. Ihr solltet euch aber merken, welche Nummer ihr hier eingibt. Das wird nachher noch eine Rolle spielen. Nun sollte das ganze in etwa so aussehen:





Wie ihr seht, wird jetzt oben links ein X dargestellt. Das ist unsere Custom Sprite. Da die "Display Custom Sprites" Option aktiviert ist, wir aber noch keine Grafik für unsere Sprite festgelegt haben, wir diese einfach als X dargestellt. Das werden wir aber zu gegebener Zeit noch ändern. Nun kommt einer der wichtigsten Schritte, bei dem ihr keine Fehler machen solltet: Stellt sicher, dass die Custom Sprite genau auf dieser Position, nämlich X0 Y0 auf Screen 00 ist und dass sich auf dieserm Screen sonst KEINE andere Sprite befindet. Ich wiederhole: KEINE! Stellt außerdem sicher, dass ihr eure Sprite markiert habt. Wenn ihr das sicher gestellt habt, drückt gleichzeitig STRG + SHIFT + F12. Nun solltet ihr folgendes Fenster erhalten:



Hier solltet ihr nun die Nummer der Sprite als auch ihren Namen eintragen. Bei mir - wie schon erwähnt - Sprite Nummer 04. Und da ich bereits einen Poison Goomba in der Liste habe, nenne ich diesen einfach mal "Poison Goomba 2". Stellt allerdings sicher, dass die Nummer und der Name durch ein Leerzeichen getrennt sind. Bei mir sieht das ganze dann folgendermaßen aus:



Nun klickt ihr auf "OK". Speichert euer Level in Lunar Magic ab, schließt Lunar Magic, öffnet es dann erneut und lädt euer Spiel darin. Wenn ihr nun die Custom Collection of Sprites öffnet:



TAA-DAA! Eure Sprite wird nun in der Liste angezeigt. Wenn nicht, habt ihr im vorherigen Schritt etwas falsch gemacht. Habt ihr sicher gestellt, dass
-Eure Sprite ganz oben links auf Screen 00 war?
-Auf dem Screen sonst keine andere Sprite war?
-Ihr die Sprite ausgewählt hattet, als ihr STRG + SHIFT + F12 gedrückt habt?
-Ihr Lunar Magic anschließend neu gestartet habt?
Wenn alles geklappt hat, können wir zum nächsten Schritt übergehen. Zunächst sollten wir gucken, ob auch alles richtig funktioniert hat. Fügen wir die Sprite also einmal über die Custom Collection of Sprites ins Spiel ein (stellt sicher, dass ihr euch im Sprite Editing Mode befindet). Danach gehen wir in Lunar Magic auf "View > Sprite Data (Hex Code)" um sicher zu gehen, dass unserer Sprite auch die richtige Nummer zugeordnet ist.



Na bitte! Sprite ist im Spiel und hat Sprite Nummer 04! Dann können wir "View > Sprite Data (Hex Code)" wieder ausschalten.

Bis hierher hat also schon mal alles super geklappt. Euch dürfte aufgefallen sein, dass sich im Ordner eurer ROM nun zwei neue Dateien befinden: [ROMName].mwt und [ROMName].mw2. Diese Dateien sind beide für die Custom Collection of Sprites notwendig. Ihr solltet nicht an ihnen rumspielen, wenn ihr nicht wisst, wie Lunar Magic mit ihnen umgeht. Ein kleiner Fehler und ihr könntet eure ganze Liste durcheinander bringen.

Gut, nun kommen wir aber zum interessanten Teil dieses Tutorials: Das Darstellen der Grafiken in Lunar Magic (Hinweis: Die Darstellung bezieht sich wirklich nur auf Lunar Magic und nimmt keinen Einfluss auf das Spiel).

Als erstes solltet ihr in Lunar Magic den 16x16 Tile Map Editor öffnen. Nun macht ihr folgendes: Drückt gleichzeitg STRG + SHIFT + Bild Runter. Nun sollte unten links im Tile Map Editor die Nachricht "Sprite Map16 data viewing unlocked" erscheinen. Nun könnt ihr euch die Sprite Grafiken eures Spiels im Map16 Editor angucken. Dazu müsst ihr so oft die Pfeil Runter Taste drücken, bis ihr die Sprite Daten gefunden habt (das müsste bei Seite 20 in Hex sein). Das ganze dürfte in etwa so aussehen:



Hier befinden sich nun die ganzen Grafiken, die Lunar Magic für die Darstellung von Sprites verwendet (wie bereits erwähnt nur im Editor, nicht etwa im Spiel). Die ersten 4 Seiten sind nur für normale Sprites. Springen wir also zu Seite 23 (drückt vier mal runter). Die nächsten 8 Seiten sind einzig und alleine für die Darstellung von Custom Sprites. Hier könnt ihr euch also austoben. Das ganze funktioniert genau so wie auch mit Blöcken, bloß, dass ihr mit STRG + SHIFT + F9 speichert statt nur mit F9. Bei mir sieht das ganze anschließend dann so aus:



Wo genau auf diesen 8 Seiten ihr eure Grafik speichert, ist im Prinzip egal. Ihr müsst euch nur die Nummer merken, die ich unten rot eingekreist habe, in meinem Fall also 402.

Jetzt müsst ihr folgendes tun: Erstellt in dem Ordner, wo eure ROM drin ist, eine Text-Datei und nennt diese anschließend "[ROMName].ssc". Als beispiel: Wenn weure ROM "SMW.smc" heißt, erstellt ihr eine Datei namens "SMW.ssc". Diese neu erstellte Datei öffnet ihr dann anschließend in einem beliebigen Text-Editor. Nun erkläre ich euch, wie genau der Inhalt auszusehen hat:

SS[TAB]EC[TAB](X1,Y1,G1[Leerzeichen]X2,Y2,G2[Leerzeichen][...]Xn,Yn,Gn[TAB])Beschreibung[Enter]

Der Teil in den roten Klammern ist dabei optional und die blauen Begriffe in eckigen Klammern symbolisieren jeweils Tasten, die ihr drücken müsst. Wofür genau stehen jezt die einzelnen Buchstaben?

SS ist die Nummer eurer Sprite. In meinem Fall also 04
E ist die Art von Sprite, deren Aussehen ihr modifizieren wollt. 0 und 1 ist für normale Sprites (ja, ihr könnte auch das Aussehen normaler Sprites in Lunar Magic modifizieren!). 2 und 3 sind für Custom Sprites. Hier kommt es darauf, welche Extra Info ihr beim Einfügen eurer Sprite benutzt (deswegen sagte ich auch ihr sollt euch das merken). Bei mir ist das eine 2, deswegen kommt auch hier eine 2 hin. Wenn ihr für die 3 keinen gesonderten Wert definiert, so wird Lunar Magic für 2 und 3 die selben Grafiken verwenden. Nur so zur Info.
C bedeutet ob ihr für die Sprite in Lunar Magic eine Custom Grafik verweden wollt (2) oder nicht (0). In meinem Fall also 2, denn genau dafür machen wir das ganze ja.

Der nächste Teil ist jetzt der wichtige. Habt ihr beim vorherigen Schritt 0 angegeben, so könnt ihr diesen Teil überspringen und direkt die Beschreibung eurer Sprite eingeben. Dann wird aber natürlich auch die Grafik in Lunar Magic nicht verändert. Also wenn ihr vorher eine 2 gewählt habt, dann kommt jetzt das, was ihr tun müsst:

Also wie ihr sicherlich wisst, bestehen Sprites aus 16x16 Pixel Blocks. Genau die selbe Art von Blocks, die ihr im Map16 Editor vorfindet. Wenn ein SNES Spiel Sprites darstellt, die Größer als 16x16 Pixel sind, dann tut es das indem es mehrere solcher 16x16 Blöcke nebeneinander darstellt. Genau das müssen wir auch tun. In diesem Fall ist das noch nicht wichtig, da der Poison Goomba nur einen Block groß ist. Bei anderen Gegnern aber - einem Koopa z.B. - sieht das ganze schon anders aus. Wir fangen aber erst mal klein an.

Also ein Sprite Block (so nenne ich es mal) besteht in unserer SSC Datei aus drei Werten: X, Y und G. X und Y sind die Koordinaten der Sprite. Diese sind relativ zur Position der Sprite in Lunar Magic. Platzieren wir unsere Sprite in Lunar Magic also auf X Position 10 und Y Position 15 und schreiben dann in der SSC-Datei 0,0 als Koordinaten, so wird die Grafik in Lunar Magic auf Position 10,15 dargestellt. Ist doch einfach, oder? Indem ihr nun diese Werte modifiziert, könnt ihr mehrere Blöcke nebeneinander darstellen. Dabei müsst ihr folgendes beachten:

-Bei der X Koordinate verschieben positive Werte den Block nach rechts und negative Werte ihn nach links
-Bei der Y Koordinate verschieben positive Werte den Block nach unten und negative Werte ihn nach oben

Dazu gleich ein anderes Biespiel. Aber erst mal zurück zu unserem Goomba. Der dritte Wert, der uns fehlt, ist die Grafik selbst. Das ist die Nummer, die ich auf dem letzten Bild rot eingerkeist habe, also 402. Alle drei Werte sind durch ein Komma voneinander getrennt. Nun kommt die Beschreibung. Ich denke hier muss ich ja nicht viele Worte zu verlieren. Für meinen Goomba sähe das ganze dann in etwa so aus:
Code
04          22          0,0,402          Dies ist ein vergifteter Goomba

Beachtet auch die Tabs. Zwischen 04 und 22, zwischen 22 und 0 und zwischen 402 und "Dies" müssen jewils Tabs stehen, keine Leerzeichen!

So, nun versuchen wir das ganze mal mit einer Koopa-Grafik statt mit einer Goomba-Grafik. Diese hat, wie schon erwähnt, zwei Blöcke statt nur einen. Unseren Code müssen wir allerdings nur minimal ändern. Die Nummern meines Koopas im Map16 Editor sind 403 (Kopf) und 413 (Körper). Das ganze sähe dann so aus:

Code
04          22          0,0,413 0,-16,403          Dies ist ein vergifteter Goomba


Seht ihr den Unterschied? Im ersten Block habe ich nur die 402 durch 413 ersetzt um statt des Goombas den Koopa darzustellen. Dann habe ich noch einen zweiten Block hinzugefügt. Hier habe ich als Y Koordinate -16 genommen. Das bedeutet, dass der Kopf um 16 Pixel nach oben verschoben sein wird (denn genau so hoch ist ja der Körper des Koopas). Die X Koordinate ist für beide Grafiken gleich. So lässt sich das ganze dann für beliebig viele Blöcke wiederholen. Ihr müsst nur eines beachten: Während sonst überall Tabs stehen, müssen zwischen den einzelnen Blöcken Leerzeichen stehen. Das ist sehr wichtig! Dann testen wir das ganze mal. Zu erst die Goomba Grafik. Damit die Änderungen in Lunar Magic angezeigt werden, müssen wir die SSC-Datei speichern und dann Lunar Magic neu starten.



Na bitte! Geht doch! Nun das ganze noch mit der Koopa Grafik:



Funktioniert auch wunderbar! Und das ist im Grunde genommen auch schon alles. Wenn ihr jetzt noch mehr Grafiken hinzufügen wollt, müsst ihr einfach am Ende eurer SSC-Datei einen Zeilenumbruch einfügen und in der nächste Zeile dann die selbe Prozedur wiederholen.

Damit endet mein kleines Tutorial über Lunar Magics Custom Collection of Sprites.
-Das quadratische Rad neu erfinden-
Mit das quadratische Rad neu erfinden (englisch Reinventing the square wheel) bezeichnet man die Bereitstellung einer schlechten Lösung, wenn eine gute Lösung bereits existiert.

-Slowsort-
Slowsort (von engl. slow: langsam) ist ein langsamer, rekursiver Sortieralgorithmus, der nach dem Prinzip Vervielfache und kapituliere (engl. Multiply and surrender, eine Parodie auf Teile und herrsche) arbeitet.

geschrieben am 14.09.2010 18:08:43 in ASM-Projekte-Thread
( Link )
Ich dachte mir wir könnten hier, ähnlich wie SMW Central, einen Thread gebrauchen, auf dem man alle seine ASM-Projekte, an denen man gerade arbeitet oder die man fertiggestellt hat und für die man keinen gesonderten Thread anlegen will, vorzeigen kann. Ich fange gleich mal mit einem meiner wohl beliebtesten (wenn auch noch nicht veröffentlichten) Patches an.



Habe die letzten Tage nicht so viel dran gemacht, weil ich noch ein RPG-Maker-Projekt schnellstmöglich fertigstellen muss. Ich werde aber versuche es zur nächsten C3 fertigzustellen.
-Das quadratische Rad neu erfinden-
Mit das quadratische Rad neu erfinden (englisch Reinventing the square wheel) bezeichnet man die Bereitstellung einer schlechten Lösung, wenn eine gute Lösung bereits existiert.

-Slowsort-
Slowsort (von engl. slow: langsam) ist ein langsamer, rekursiver Sortieralgorithmus, der nach dem Prinzip Vervielfache und kapituliere (engl. Multiply and surrender, eine Parodie auf Teile und herrsche) arbeitet.

geschrieben am 14.09.2010 19:07:51 in Gute Videos
( Link )
Joa, der gute, alte "Gute Videos"-Thread. Diesmal in Off-Topic erstellt, weil er meiner Meinung nach noch nie ins Irrenhaus gehört hat.

Ich mache mal den Start mit einen unglaublichen Hit, den ich heute entdeckt habe.
-Das quadratische Rad neu erfinden-
Mit das quadratische Rad neu erfinden (englisch Reinventing the square wheel) bezeichnet man die Bereitstellung einer schlechten Lösung, wenn eine gute Lösung bereits existiert.

-Slowsort-
Slowsort (von engl. slow: langsam) ist ein langsamer, rekursiver Sortieralgorithmus, der nach dem Prinzip Vervielfache und kapituliere (engl. Multiply and surrender, eine Parodie auf Teile und herrsche) arbeitet.

geschrieben am 14.09.2010 21:13:02 in The Legend of Zelda: Skyward Sword [Release steht fest]
( Link )
Zitat von HoZweMu:
-Kein Voice Acting


Auf welche Quelle beziehst du dich da?
-Das quadratische Rad neu erfinden-
Mit das quadratische Rad neu erfinden (englisch Reinventing the square wheel) bezeichnet man die Bereitstellung einer schlechten Lösung, wenn eine gute Lösung bereits existiert.

-Slowsort-
Slowsort (von engl. slow: langsam) ist ein langsamer, rekursiver Sortieralgorithmus, der nach dem Prinzip Vervielfache und kapituliere (engl. Multiply and surrender, eine Parodie auf Teile und herrsche) arbeitet.

geschrieben am 14.09.2010 21:15:25 in Gute Videos
( Link )
Andy Samberg ist der beste.
-Das quadratische Rad neu erfinden-
Mit das quadratische Rad neu erfinden (englisch Reinventing the square wheel) bezeichnet man die Bereitstellung einer schlechten Lösung, wenn eine gute Lösung bereits existiert.

-Slowsort-
Slowsort (von engl. slow: langsam) ist ein langsamer, rekursiver Sortieralgorithmus, der nach dem Prinzip Vervielfache und kapituliere (engl. Multiply and surrender, eine Parodie auf Teile und herrsche) arbeitet.

geschrieben am 15.09.2010 18:21:25 in Umzug fertig!
( Link )
Zitat von Wysey:
Hm ich frage mich warum eigentlich manche schon über 20 Beiträge haben obwohl die Seite ja erst richtig seit ein Paar Tagen Aktiv ist...


Korrektur: Dieses Forum gibt es schon seit einigen Monaten. Es wurde allerdings nicht genutzt, weil es eben noch nicht fertig war.

Was übrigens im alten Forum bisschen doof ist, ist dass man, wenn man auf das verlinkte Wort "Forum" klickt, statt in dieses Forum zu gelangen in ein nicht existentes Forum im alten Forum (oh Gott, wie oft noch dasselbe Wort?) kommt. Man sollte es vielleicht so verändern, dass man den tatsächlichen Link in Klammern setzt. Sonst kann das ganz schön verwirren, dass da dann steht "Dieses Forum ist gesperrt", wenn man auf das Wort "Forum" klickt.
-Das quadratische Rad neu erfinden-
Mit das quadratische Rad neu erfinden (englisch Reinventing the square wheel) bezeichnet man die Bereitstellung einer schlechten Lösung, wenn eine gute Lösung bereits existiert.

-Slowsort-
Slowsort (von engl. slow: langsam) ist ein langsamer, rekursiver Sortieralgorithmus, der nach dem Prinzip Vervielfache und kapituliere (engl. Multiply and surrender, eine Parodie auf Teile und herrsche) arbeitet.

geschrieben am 15.09.2010 18:32:15 in The Legend of Zelda: Skyward Sword [Release steht fest]
( Link )
Zitat von HoZweMu:
Zitat von RPG Hacker:
Zitat von HoZweMu:
-Kein Voice Acting


Auf welche Quelle beziehst du dich da?


Auf ein Interview mit Eiji Aonuma. Er meinte, es passe einfach nicht zur Zelda Serie.


Verdammt! Aonuma, ich hasse dich! Es wird zeit, dass die Retro Studios mal die Zelda-Serie kriegen. Alle Serien, die die bisher angepackt wruden, wurden episch und außerdem haben sie es auch geschafft in Metroid Prime 3 Voice Acting einzuführen, ohne dass es besonders seltsam erschien, dass Samus nicht gesprochen hatte. Oder von mir aus kann Nintendo das nächste Zelda auch zusammen mit Team Ninja entwickeln und ein Zelda Other M machen. Manchmal macht es mich echt wahnsinnig, wie Nintendo vorgeht. Besonders wenn sie riesengroße Veränderungen ankündigen (Zitat Miyamoto: "Twilight Princess wird das letzte Zelda seiner Art sein!") und dann trotzdem so konservativ vorgehen. Wenn das so weitergeht wird Zelda uns irgendwann in ein paar Jahren nur noch total am Arsch vorbeigehen, weil es immer wieder dasselbe ist.
-Das quadratische Rad neu erfinden-
Mit das quadratische Rad neu erfinden (englisch Reinventing the square wheel) bezeichnet man die Bereitstellung einer schlechten Lösung, wenn eine gute Lösung bereits existiert.

-Slowsort-
Slowsort (von engl. slow: langsam) ist ein langsamer, rekursiver Sortieralgorithmus, der nach dem Prinzip Vervielfache und kapituliere (engl. Multiply and surrender, eine Parodie auf Teile und herrsche) arbeitet.

geschrieben am 15.09.2010 18:35:22 in Allgemeine Diskussionen
( Link )
Jab, so ist es. Würde mich allerdings freuen, wenn sie im nächsten Metroid NOCH einen Schritt zurückgingen und etwas über Samus' Vergangenheit bei den Chozos enthüllen würden.
-Das quadratische Rad neu erfinden-
Mit das quadratische Rad neu erfinden (englisch Reinventing the square wheel) bezeichnet man die Bereitstellung einer schlechten Lösung, wenn eine gute Lösung bereits existiert.

-Slowsort-
Slowsort (von engl. slow: langsam) ist ein langsamer, rekursiver Sortieralgorithmus, der nach dem Prinzip Vervielfache und kapituliere (engl. Multiply and surrender, eine Parodie auf Teile und herrsche) arbeitet.

geschrieben am 15.09.2010 18:39:55 in Vorstellungs-/Verlassens-/Rückkehr-Thread
( Link )
Markus Wall, zur Zeit 18 Jahre alt (am 28.10.1991 geboren). In den meisten Foren heiße ich RPG Hacker und die meisten hier kennen mich ja. Hauptsächlih zieht mich die ASM-Programmierung zum SMW-Hacking. Levels machen, Grafiken, Musik etc. liegt mir alles nicht so besonders. Aber im Programmieren bin ich dafür umso besser. Es ist auch mein Lebenstraum, eines Tages ein Spieleprogrammierer zu werden und bei irgendeinem größeren Entwickler zu arbeiten. Nach der Schule werde ich mich wohl an der Games Academy in Frankfurt bewerben, aber mal sehen, ob ich da überhaupt aufgenommen werde.

Ansonsten mache ich auch sehr gerne Spiele mit dem RPG Maker, wo ich mich auch mal wieder eher um technische Aspekte als um Design oder ähnliches kümmere.

Wie viele Leute stehe ich auf Videospiele und Animes. Mein Lieblingsspiel ist Terranigma auf dem SNES, mein Lieblingsanime Eureka Seven.

Das war so ziemlich alles über mich.
-Das quadratische Rad neu erfinden-
Mit das quadratische Rad neu erfinden (englisch Reinventing the square wheel) bezeichnet man die Bereitstellung einer schlechten Lösung, wenn eine gute Lösung bereits existiert.

-Slowsort-
Slowsort (von engl. slow: langsam) ist ein langsamer, rekursiver Sortieralgorithmus, der nach dem Prinzip Vervielfache und kapituliere (engl. Multiply and surrender, eine Parodie auf Teile und herrsche) arbeitet.

geschrieben am 15.09.2010 18:42:44 in Tutorial-Bereich!
( Link )
Oder einfach das kostenlose Open Office verwenden. Oder ganz einfach als RTF speichern (wird von jedem Windows-Rechner unterstützt). HTML oder PDF wären aber wohl optimal, wobei ich HTML sogar PDF noch vorziehe, ganz einfach weil der Adobe Reader das behinderste Programm ist, das es gibt und immer erstmal fünf Stunden braucht, um aufzugehen, nur um den Computer dann die ganze Zeit zu verlangsamen.
-Das quadratische Rad neu erfinden-
Mit das quadratische Rad neu erfinden (englisch Reinventing the square wheel) bezeichnet man die Bereitstellung einer schlechten Lösung, wenn eine gute Lösung bereits existiert.

-Slowsort-
Slowsort (von engl. slow: langsam) ist ein langsamer, rekursiver Sortieralgorithmus, der nach dem Prinzip Vervielfache und kapituliere (engl. Multiply and surrender, eine Parodie auf Teile und herrsche) arbeitet.

geschrieben am 15.09.2010 18:46:31 in Vorstellungs- / Verlassens- / Rückkehr-Thread
( Link )
Häh?

Na gut, dann eben noch einmal.

Markus Wall, zur Zeit 18 Jahre alt (am 28.10.1991 geboren). In den meisten Foren heiße ich RPG Hacker und die meisten hier kennen mich ja. Hauptsächlih zieht mich die ASM-Programmierung zum SMW-Hacking. Levels machen, Grafiken, Musik etc. liegt mir alles nicht so besonders. Aber im Programmieren bin ich dafür umso besser. Es ist auch mein Lebenstraum, eines Tages ein Spieleprogrammierer zu werden und bei irgendeinem größeren Entwickler zu arbeiten. Nach der Schule werde ich mich wohl an der Games Academy in Frankfurt bewerben, aber mal sehen, ob ich da überhaupt aufgenommen werde.

Ansonsten mache ich auch sehr gerne Spiele mit dem RPG Maker, wo ich mich auch mal wieder eher um technische Aspekte als um Design oder ähnliches kümmere.

Wie viele Leute stehe ich auf Videospiele und Animes. Mein Lieblingsspiel ist Terranigma auf dem SNES, mein Lieblingsanime Eureka Seven.

Das war so ziemlich alles über mich.
-Das quadratische Rad neu erfinden-
Mit das quadratische Rad neu erfinden (englisch Reinventing the square wheel) bezeichnet man die Bereitstellung einer schlechten Lösung, wenn eine gute Lösung bereits existiert.

-Slowsort-
Slowsort (von engl. slow: langsam) ist ein langsamer, rekursiver Sortieralgorithmus, der nach dem Prinzip Vervielfache und kapituliere (engl. Multiply and surrender, eine Parodie auf Teile und herrsche) arbeitet.

geschrieben am 15.09.2010 19:42:51 in The Legend of Zelda: Skyward Sword [Release steht fest]
( Link )
Es muss ja nicht unbedingt sofort jeder unwichtige NPC sprechen. Es würde ja schon reichen, wenn es zumindest mal in wichtigen Cutscenes Voice Acting gäbe. Stell dir nur mal den finalen Kampf mit Ganondorf in Twilight Princess vor. Stell dir vor, wie er, nachdem er besiegt wurde, flucht. Das ganze mit Voice Acting. Ich könnte mir das super vorstellen und bin mir sicher, dass das die Szene nochmal um ein ganzes Stück aufgewertet hätte. Und wie gesagt: In Metroid Prime 3 hat es auch super funktioniert, obwohl Samus nicht gesprochen hat (alle anderen aber schon, sogar unwichtige NPCs). Sind immerhin beides Spiel von Nintendo. Wieso also nicht auch Zelda?
-Das quadratische Rad neu erfinden-
Mit das quadratische Rad neu erfinden (englisch Reinventing the square wheel) bezeichnet man die Bereitstellung einer schlechten Lösung, wenn eine gute Lösung bereits existiert.

-Slowsort-
Slowsort (von engl. slow: langsam) ist ein langsamer, rekursiver Sortieralgorithmus, der nach dem Prinzip Vervielfache und kapituliere (engl. Multiply and surrender, eine Parodie auf Teile und herrsche) arbeitet.

geschrieben am 15.09.2010 19:49:54 in To-Do-Liste
( Link )
Was ich noch ein bisschen vermisse ist ein Logo für das Forum oben in Firefox. Könnte man da nicht den Mond von der Hauptseite holen?
-Das quadratische Rad neu erfinden-
Mit das quadratische Rad neu erfinden (englisch Reinventing the square wheel) bezeichnet man die Bereitstellung einer schlechten Lösung, wenn eine gute Lösung bereits existiert.

-Slowsort-
Slowsort (von engl. slow: langsam) ist ein langsamer, rekursiver Sortieralgorithmus, der nach dem Prinzip Vervielfache und kapituliere (engl. Multiply and surrender, eine Parodie auf Teile und herrsche) arbeitet.

geschrieben am 15.09.2010 20:20:56 in The Legend of Zelda: Skyward Sword [Release steht fest]
( Link )
Joa. Aber solange Eijia Aonuma + Shigeru Miyamoto an der Serie mitwirken, wird das wohl sobald nicht passieren.

@Grafikstil:
Es ist vielleicht nicht der schönste Grafikstil, aber er macht in diesem Spiel mit WiiMotionPlus-Steuerung durchaus Sinn, weil durch die krassen Farben die Schwachstellen der Gegner und Links Schwert sehr viel mehr herausstechen. Genau das wollte Nintendo auch damit bezwecken.
-Das quadratische Rad neu erfinden-
Mit das quadratische Rad neu erfinden (englisch Reinventing the square wheel) bezeichnet man die Bereitstellung einer schlechten Lösung, wenn eine gute Lösung bereits existiert.

-Slowsort-
Slowsort (von engl. slow: langsam) ist ein langsamer, rekursiver Sortieralgorithmus, der nach dem Prinzip Vervielfache und kapituliere (engl. Multiply and surrender, eine Parodie auf Teile und herrsche) arbeitet.