PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Eigenes Itemsystem [Tutorial]



Quetschi
03.11.2012, 17:02
Herzlich Willkommen zu meinem ersten Tutorial.

Oh, ich bin ja so aufgeregt. Also wo fang ich am besten an ? Ja...also das ist ein Tutorial für ein eigenes Itemsystem.

Ihr solltet bereits einige Erfahrung mit dem RPGmaker gesammelt haben, bevor ihr euch dazu entschließt, ein eigenes Itemsystem in euer Spiel einzubauen.

Zumindest sollte ihr die folgenden Punkte beherrschen:
- Der Umgang mit Variablen und die Verwendung von Zeigern/Pointers.
- Der Umgang mit Switches.
- Der Umgang mit Labels
- Die Fähigkeit seine Skripte genügend zu kommentieren, damit man sich zurecht findet. (Okay das ist nicht notwendig, aber hilft enorm. Ihr solltet es machen.)

So nun zu grundlegenden Informationen...

~Die Idee~

Wenn ihr ein Itemsystem so machen wollt, wie ich es in diesem Tutorial beschreibe, braucht ihr auch ein eigenes Shopsystem, da die Items in Variablen gespeichert werden und komplett unabhängig von der Database sind.
Das setzt zwar noch einmal MEHR Aufwand vorraus, aber man kann damit seinem Spiel auch etwas individuelles verpassen und ein sich bspw. ein eigenes System für Item's überlegen.

Da die Item IDs in Variablen gespeichert werden, können diese theoretisch von -999.999 bis +999.999 gehen. Somit könnte man 2*999.999 also 1.999.998 verschiedene Items erstellen, da die 0 für "kein Item vorhanden" belegt wird.
Das macht allerdings relativ wenig Sinn, da es (vermutlich) keine Spiele gibt/geben wird in denen es notwendig ist, soviele verschiedene Items zu haben. Außerdem kann man so Items mehr/weniger als 99 mal stappeln.

~Sich ein System überlegen~ (Beispiel)

Bringen wir also ein bisschen System in die Sache:
- Man benutzt immer Item IDs mit einem Mindestwert von 100.000 (das ist kein Problem da man Variablen ja bis auf 999.999 stellen kann.)
- Man kann sich verschiedene "Kategorien" machen indem man die Hunderttausenderziffer verändert. Beispiele:
-> Items mit einer Hunderttausenderziffer von 1 sind Heilitems (also alle Items mit einer ID von 100.000 bis 199.999)
-> Items mit einer Hunderttausenderziffer von 2 sind Schlüsselitems
-> Items mit einer Hunderttausenderziffer von 3 sind Ausrüstung
-> Items mit einer Hunderttausenderziffer von 4 sind Monsterdrops
- Die Zehntausenderziffer kann dann zur Unterscheidung verwendet werden. Beispiele:
-> Items mit einer Hunderttausenderziffer von 1 und Zehntausenderziffer von 1 sind Heilitems, die HP heilen
-> Items mit einer Hunderttausenderziffer von 1 und Zehntausenderziffer von 2 sind Heilitems, die MP heilen
-> Items mit einer Hunderttausenderziffer von 1 und Zehntausenderziffer von 3 sind Heilitems, die HP & MP heilen
-> Items mit einer Hunderttausenderziffer von 1 und Zehntausenderziffer von 4 sind Heilitems, die wiederbeleben
-> Items mit einer Hunderttausenderziffer von 1 und Zehntausenderziffer von 5 sind Heilitems, die Statusveränderungen heilen
-Die Tausenderziffer kann dann beispielsweise den Grad oder das Level des Items zu bestimmen. Auch hier wieder Beispiele:
-> Items mit einer Hunderttausenderziffer von 1 und Zehntausenderziffer von 1 und einer Tausenderziffer von 1 ist das Item "Heilkraut"
-> Items mit einer Hunderttausenderziffer von 1 und Zehntausenderziffer von 1 und einer Tausenderziffer von 2 ist das Item "schwacher Heiltrank"
-> Items mit einer Hunderttausenderziffer von 1 und Zehntausenderziffer von 1 und einer Tausenderziffer von 3 ist das Item "Heiltrank"
-> Items mit einer Hunderttausenderziffer von 1 und Zehntausenderziffer von 1 und einer Tausenderziffer von 4 ist das Item "starker Heiltrank"
-Die Hunderterziffer kann angeben ob das Item im Menü benutzt werden darf (1= ja, 2= nein)
-Die Zehnerziffer gibt dann an ob das Item im Kampf verwendet werden kann oder nicht (Auch hier 1= ja, 2= nein)
-Die Einerziffer kann auch noch eine Funktion haben.
-So ist z.B. das Item mit der ID 114.110 ein "starker Heiltrank" und ist im Menü und Kampf benutzbar.
-Ein weiteres Beispiel: ItemID = 123.110 Item = "Manatrank" und ist im Menü und Kampf benutzbar.

Hinweis: Der RPGmaker2k kann Variablen bis 999.999 haben und der RPGmaker2k3 bis 9.999.999

So kann man ein einfaches System in die Variablen seiner Item IDs verbauen. Wie ihr an die einzelnen Ziffern kommt, sollte eigentlich klar sein, da ich das Verwenden von Variablen vorraussetze. Der Vollständigkeit halber sag ich es aber trotzdem ;)
Ihr müsst die Modulusoperation benutzen. Modulus gibt euch den Rest einer ganzzahligen Division aus. D.h. wenn man die einer Ziffer abfragen möchte muss man die ItemID am Besten in eine neue Variable kopieren (ItemID 1er) und setzt diese gleich der ItemID.
Nun verwendet man die Modulusoperation auf die Variable "ItemID 1er".



<> Change Variable: [222:ItemID 1er] Mod= 10


Wenn man die 10er Stelle haben möchte benutzt man die Modulusoperation mit 100. Allerdings muss man dann abfragen ob die Variable über 90,80,70,60,50,40,30,20,10 ist. Dasselbe Verfahren gilt bei Hunderterziffer usw. Einfach eine 0 dranhängen.


So genug zur Theorie hinter dem System. Nun kommen wir zu eigentlichen Umsetzung. Ihr solltet auch beachten dass ich den Makercode auch für mich mit Kommentaren ausgeschmückt habe. Hauptsächlich um sich wieder reinzufinden, nachdem man längere Zeit nicht dran gearbeitet hat.

~Einbauen des Systems~

~Die Truhe~

Als erstes brauchen wir eine Truhe die uns ein Item ausgibt. Dazu benötigen wir zwei Events. Ein Mapevent für die Truhe und ein Common Event für das eigentliche Ausgeben des Items, da das Event bzw. der Eventcode der Truhe nicht immer riesengroß sein soll.

Für die Truhe erstellen wir ganz normal ein Event auf der Map. In diesem Event setzen wir (beispielweise) die Variable 208:ItemID# auf die ID, welche das Item das wir erhalten sollen hat. In unserem Beispiel 114100 also einen "starken Heiltrank".
Dann rufen wir das Common Event "Itemausgabe eig Inv" auf.




- SCRIPT -
<> Fork Condition: If Hero is facing up then ...
. <> Change Variable: [208:ItemID#] = 114100
. <> Call Event: Common Event #2 Itemausgabe eig Inv
. <> Fork Condition: If Switch [1:Item.Got] == ON then ...
. . <> Change Switch: [2:Truhe#1] = ON
. . <> Change Switch: [1:Item.Got] = OFF
. . <>
. : Else ...
. . <> Change Variable: [221:RandPhrase] = Random [1-4]
. . <> Fork Condition: If Variable [221:RandPhrase] == 1 then ...
. . . <> Show Message: Ich kann nicht mehr tragen...
. . . <>
. . : End of fork
. . <> Fork Condition: If Variable [221:RandPhrase] == 2 then ...
. . . <> Show Message: Mein Inventar ist Voll...
. . . <>
. . : End of fork
. . <> Fork Condition: If Variable [221:RandPhrase] == 3 then ...
. . . <> Show Message: Ich kann nicht soviel schleppen wie ein Lastenesel.
. . . <>
. . : End of fork
. . <> Fork Condition: If Variable [221:RandPhrase] == 4 then ...
. . . <> Show Message: Das passt nicht mehr.
. . . <>
. . : End of fork
. . <>
. : End of fork
. <>
: Else ...
. <> Show Message: Von hier aus kann ich die Truhe nicht öffnen...
. <>
: End of fork



Wie man hier sieht wird zuerst die "ItemID#" gesetzt und dann das CE zur Ausgabe aufgerufen. Danach wird abgefragt ob der "Switch 1:Item.Got" ON ist. Wenn dies der Fall ist wird der Switch der Truhe auf ON gesetzt und "Item.Got" auf OFF.
Die Truhe wird also nur umswitchen wenn man das Item wirklich bekommen hat. Wann der Switch "Item.Got" umgelegt wird, sieht man im CE. Der Rest in diesem Event ist nicht unbedingt notwendig und eher reine "Kosmetik".

~Die Ausgabe der Items~

Zum CE:




- SCRIPT -
<> Comment: Werte und Zeiger zur Ausgabe im Inventar vorbereiten
<> Change Variable: [201:ItemPointer] = 1
<> Change Variable: [202:PointedItem] = V[V[201]]
<> Change Variable: [203:StackPointer] = 51
<> Change Variable: [204:PointedStack] = V[V[203]]
<> Change Variable: [205:ItemSlot] = 1
<> Change Variable: [206:ItemSlotCheck] = V[V[205]]
<> Change Variable: [220:StackSlot] = 51
<> Label: 1
<> Comment: Abfragen ob das Item bereits im Inventar ist.
: ItemID# wird mit der ItemID von ItemSlot die in ItemSlotCheck
: gespeichert ist verglichen.
<> Fork Condition: If Variable [208:ItemID#] == V[206:ItemSlotCheck] then ...
. <> Comment: Wenn sie gleich sind, ist das Item bereits vorhanden
. <> Change Variable: [V[220]] += 1
. <> Comment: Die Menge wird um 1 erhöht.
. <> Change Switch: [1:Item.Got] = ON
. <> Comment: Der Switch Item.Got wird auf ON gesetzt, damit nachher
. : vermerkt wird, dass ein Item erhalten wurde und der Switch
. : der Truhe bestätigt wird.
. <> Jump To Label: 2
. <>
: Else ...
. <> Comment: Wenn ItemID# nicht gleich der ItemID im ItemSlot ist
. : wird der ItemSlot um 1 erhöht und die Item ID vom ItemSlot
. : wird aktualisiert
. <> Change Variable: [205:ItemSlot] += 1
. <> Change Variable: [206:ItemSlotCheck] = V[V[205]]
. <> Comment: Der StackSlot wird ebenfalls um 1 erhöht, damit beim richtigen Item
. : die Menge um 1 erhöht wird
. <> Change Variable: [220:StackSlot] += 1
. <> Fork Condition: If Variable [205:ItemSlot] == 51 then ...
. . <> Comment: Wenn ItemSlot den Wert 51 hat springt der Maker aus der Labelschleife
. . : , da die Itemslots nur von 1-50 gehen.
. . <> Jump To Label: 4
. . <>
. : End of fork
. <>
: End of fork
<> Label: 4
<> Comment: Jetzt folgt der Teil zum hinzufügen eines Items
: dafür werden nacheinander alle Itemslots von 1-50 durchgegangen
: und wenn ein leerer Itemslot gefunden wird, wird das Item dort hinein-
: gelegt
<> Fork Condition: If Variable [202:PointedItem] == 0 then ...
. <> Comment: Wenn die ItemID des aktuellen Slots 0 ist - d.h. kein Item vorhanden -
. : dann wird das neue Item eingefügt.
. : Wenn das Inventar nicht sortiert ist, dann kann dies auch mittendrin
. : geschehen
. <> Change Variable: [V[201]] = V[208:ItemID#]
. <> Change Variable: [V[203]] += 1
. <> Change Switch: [1:Item.Got] = ON
. <> Comment: Der Switch Item.Got wird auf ON gesetzt, damit nachher
. : vermerkt wird, dass ein Item erhalten wurde und der Switch
. : der Truhe bestätigt wird.
. : Anschließend wird die Labelschleife verlassen.
. <> Jump To Label: 2
. <>
: Else ...
. <> Comment: Wenn es ungleich 0 ist, dann wird die Variable ItemPointer um 1 erhöht
. : und PointedItem auf den Wert der in dem Index von ItemPointer ist
. : gesetzt.
. : Das gleiche geschieht mit StackPointer und PointedStack
. <> Change Variable: [201:ItemPointer] += 1
. <> Change Variable: [203:StackPointer] += 1
. <> Change Variable: [202:PointedItem] = V[V[201]]
. <> Change Variable: [204:PointedStack] = V[V[203]]
. <>
: End of fork
<> Fork Condition: If Variable [201:ItemPointer] > 50 then ...
. <> Comment: Wenn das Item nicht einsortiert werden konnte, da das Inventar voll ist
. : wird der Switch Item.Got NICHT auf ON gestellt und die Schleife wird
. : abgebrochen. Somit kann man sich das Item später noch holen
. <> Jump To Label: 2
. <>
: End of fork
<> Wait: 0,0 sec.
<> Jump To Label: 1
<> Label: 2



Okay nun haben wir ein schönes CE. Aber was macht das ganze ?
So als erstes setzten wir uns unsere Variablen zurecht.
Zuerst wird unsere Variable "ItemPointer" auf 1 gesetzt, da unsere Variablen bei 1 anfangen und 50 aufhören (das ist ein Beispiel, die Werte könnt ihr beliebig verändern) und wir zuerst das Item in diesem "Slot" abfragen wollen.
Dafür wird die Variable "PointedItem" benutzt. Wir setzen sie auf auf den Wert auf der in Variable 1 (unserem ersten ItemSlot) ist. Dafür benutzen wir Value Stored in Index.
Als nächstes machen wir dies mit den Variablen "StackPointer" und "PointedStack" (StackPointer nimmt den Wert 51 an, da unsere erste Variable für die Menge die 51. Variable ist).
Danach nochmal "ItemSlot" und "ItemSlotCheck". Dem ein oder anderem wird sicherlich aufgefallen sein, dass das dasselbe ist wie bei "ItemPointer" und "PointedItem", ich mache das so, damit ich die Gewissheit habe, dass sich diese Variablen nicht überschneiden werden, da ich sie für separate Zwecke benutze. Natürlich kann man das auch nur mit 2 von den 4 Variablen machen.
Als letztes setzen wir noch "StackSlot" auf 51.

Nachdem die Variablen gesetzt sind, fangen mir nun mit dem eigentlichem Event richtig an.

Als erstes soll überprüft werden, ob sich das Item bereits in unserem Inventar befindet damit wir nicht 2 separte Stacks von diesem Item haben.
Dafür wird mitels einer Conditional Branch (oder auch Fork) abgefragt ob "ItemID#" gleich "ItemSlotCheck" ist.
Wenn sie gleich sind, wird die Variable, welche die Menge bestimmt um 1 erhöht. Damit dies bei der richtigen geschieht, benutzen wir hier einen Zeiger/Pointer. Wenn man möchte das ein Item nur 99 mal stappelbar ist, nimmt man beispielsweise noch eine Variable "StackSlotCheck" und verfährt mit dieser genauso wie mit "ItemSlotCheck" und vor erhöhen der Menge wird abgefragt ob "StackSlotCheck" < 99 ist. Und "Item.Got" wird auf ON gestellt. Anschließend wird zum Ende des Events gesprungen.
Wenn sie ungleich sind wird "ItemSlot" um 1 erhöht und "ItemSlotCheck" mittels Value Stored in Index erneut ausgerichtet.
Diese Abfrage wird nun solange durchlaufen bis entweder ein Item gefunden wurde, oder "ItemSlot" den Wert 51 erreicht, da es nun bei den Variablen für den Mengen angekommen ist.
Ist das der Fall, so ist das Item noch nicht in unserem Inventar enthalten.
Also wird geprüft ob es noch einen freien Slot, in den ein Item kann, gibt.

Dafür brauchen wir wieder eine Conditional Branch.
Wenn "PointedItem" 0 ist, dann soll unser Item als neuer Slot im Inventar registriert werden. Also setzen wir Variable Reference "ItemPointer" auf den wert von "ItemID#" (wurde in der Truhe festgelegt). und erhöhen die zugehörige Mengenvariable um 1. Danach wird "Item.Got" auf ON gestellt und zum Ende des Common Events gesprungen.
Wenn das nicht der Fall ist, werden "ItemPointer" und "StackPointer" um 1 erhöht und "PointedItem" und "PointedStack" werden erneut ausgerichtet.
Auch diese Abfrage wiederholt sich so oft bis etwas gefunden wurde oder "ItemPointer" den Wert 51 erreicht und springt dann zum Ende des CE.
Wenn das Item also nicht schon im Inventar war und es auch keinen freien Platz gab, wird "Item.Got" nicht auf ON gestellt und die Truhe somit auch nicht deaktiviert.
So...das war der Teil zum Erhalten der Items.

~Das Sortieren der Items~

Jetzt kommen wir zum Sortieren der Items. Für das Sortieren verwende ich den Sortieralgorithmus Gnomesort, da dieser einfach im RPGmaker umzusetzen ist. (Gnomesort: http://de.wikipedia.org/wiki/Gnomesort).

Zuerst kopiere ich allerdings die Werte der Variablen 1-100 in die Variablen 101-200. (Das ist nicht unbedingt notwendig, aber wenn man nachher evtl noch andere Variablen sortieren will ist es einfacher, da man diese auch kopieren kann)
Den Code für's Kopieren werde ich allerdings nicht ausfürhlich kommentieren.




- SCRIPT -
<> Change Variable: [101-200] = 0
<> Comment: Das Arbeitsarray (Variable 101-200) wird gesäubert.

<> Change Variable: [201:ItemPointer] = 1
<> Change Variable: [202:PointedItem] = V[V[201]]
<> Change Variable: [203:StackPointer] = 51
<> Change Variable: [204:PointedStack] = V[V[203]]
<> Change Variable: [207:ItemPointerSort] = 101
<> Change Variable: [209:StackPointerSort] = 151
<> Comment: Die Variablen, die für's Sortieren notwendig sind werden gesetzt.
<> Label: 1
<> Change Variable: [V[207]] = V[202:PointedItem]
<> Change Variable: [V[209]] = V[204:PointedStack]
<> Change Variable: [201:ItemPointer] += 1
<> Change Variable: [202:PointedItem] = V[V[201]]
<> Change Variable: [203:StackPointer] += 1
<> Change Variable: [204:PointedStack] = V[V[203]]
<> Comment: Die Variablen werden kopiert.
<> Change Variable: [207:ItemPointerSort] += 1
<> Change Variable: [209:StackPointerSort] += 1
<> Comment: Der nächste Kopierschrit geschieht eine Variable "höher"
<> Fork Condition: If Variable [201:ItemPointer] == 51 then ...
. <> Comment: Wenn ItemPointer 51 erreicht, wird die Schleife abgebrochen und alle
. : Items sowie die dazugehörigen Mengen sind kopiert
. <> Jump To Label: 2
. <>
: End of fork
<> Jump To Label: 1
<> Label: 2



So nachdem die Items kopiert sind, beginnt das eigentliche Sortieren. Ich zeige euch hier wie man die Items nach der (selbst zugewiesenen) ID sortiert. Wenn ihr das System benutzt, dass ich oben beschrieben habe, dann sind eure Items gleich auch noch Kategorisch geordnet.

Erst einmal der Code:




- SCRIPT -
<> Comment: ItemPointerSort wird auf 101 (erstes Item im Arbeitsarry) gesetzt
: ItemPointerSort2 wird auf 102 (zweites Item im Arbeitsarry) gesetzt
: damit man 2 Werte vergleichen kann.
: StackPointerSort und StackPointerSort2 werden auf 151 und 152 gesetzt
: damit man die Mengen der Items von IPS und IPS2 hat.
<> Change Variable: [207:ItemPointerSort] = 101
<> Change Variable: [211:ItemPointerSort] = 102
<> Change Variable: [209:StackPointerSort] = 151
<> Change Variable: [213:StackPointerSort2] = 152
<> Label: 1
<> Change Variable: [208:ItemID#] = V[V[207]]
<> Change Variable: [210:StackID#] = V[V[209]]
<> Change Variable: [212:ItemID#2] = V[V[211]]
<> Change Variable: [214:StackID#2] = V[V[213]]
<> Comment: Jedes mal wenn die Schleife von neuem beginnt werden die
: ItemID's und StackID's erneut berechnet.
<> Fork Condition: If Variable [208:ItemID#] <= V[212:ItemID#2] then ...
. <> Comment: Wenn die ItemID# kleiner ist als die ItemId#2 dann werden die
. : IPS und SPS hochgesetzt
. :
. : IPS = ItemPointerSort
. : SPS = StackPointerSort
. <> Change Variable: [207:ItemPointerSort] += 1
. <> Change Variable: [209:StackPointerSort] += 1
. <> Change Variable: [211:ItemPointerSort2] += 1
. <> Change Variable: [213:StackPointerSort2] += 1
. <>
: Else ...
. <> Comment: Wenn das nicht der Fall ist, werden die beiden getauscht
. : dabei werden swapItemID und swapStackID zum Tauschen benutzt
. : da es keine Funktion zum direkten Tauschen gibt.
. <> Change Variable: [215:swapItemID] = V[208:ItemID#]
. <> Change Variable: [216:swapStackID] = V[210:StackID#]
. <> Change Variable: [208:ItemID#] = V[212:ItemID#2]
. <> Change Variable: [210:StackID#] = V[214:StackID#2]
. <> Change Variable: [212:ItemID#2] = V[215:swapItemID]
. <> Change Variable: [214:StackID#2] = V[216:swapStackID]
. <> Change Variable: [V[207]] = V[208:ItemID#]
. <> Change Variable: [V[209]] = V[210:StackID#]
. <> Change Variable: [V[211]] = V[212:ItemID#2]
. <> Change Variable: [V[213]] = V[214:StackID#2]
. <> Comment: Anschließend werden die IPS und SPS um 1 niedriger gemacht.
. <> Change Variable: [207:ItemPointerSort] -= 1
. <> Change Variable: [209:StackPointerSort] -= 1
. <> Change Variable: [211:ItemPointerSort2] -= 1
. <> Change Variable: [213:StackPointerSort2] -= 1
. <>
: End of fork
<> Fork Condition: If Variable [207:ItemPointerSort] == 100 then ...
. <> Comment: Wenn IPS auf 100 gesetzt wird wird es auf 102 gesetzt und IPS2 auf
. : 103 und SPS auf 152 und SPS2 auf 153, da diese Zeiger nicht weiter
. : nach links können, da 100 nicht mehr im Arbeitsarry ist und damit das
. : Sortieren weitergeht werden sie 1 nach rechts geschoben,
. <> Change Variable: [207:ItemPointerSort] = 102
. <> Change Variable: [211:StackPointerSort] = 103
. <> Change Variable: [209:ItemPointerSort2] = 152
. <> Change Variable: [213:StackPointerSort2] = 153
. <>
: End of fork
<> Fork Condition: If Variable [207:ItemPointerSort] == 150 then ...
. <> Comment: Wenn IPS auf 150 ist, ist der "Zeiger" ganz rechts angekommen und
. : muss keinen Vergleich mehr machen, da das Arbeitsarray bereits
. : sortiert ist.
. : Die Schleife wird abgebrochen
. <> Jump To Label: 2
. <>
: End of fork
<> Jump To Label: 1
<> Label: 2
<> Comment: Der verwendete Sortieralgorithmus ist Gnomesort, da dieser sehr einfach
: mit dem RPGmaker umzusetzen ist
<> Call Event: Common Event #6 Items korrigieren



Ich denke die Kommentare mit dem ich meinen Code versehen habe und die Wikipediaseite zu Gnomesort erklären dieses Event eigentlich ganz gut.
Also als erstes setzen wir "ItemPointerSort" und "ItemPointerSort2" auf 101 und 102, da wir an die beiden erstens Inventarslots wollen (wurden ja kopiert) und dann "StackPointerSort" und "StackPointerSort2" auf 151 und 152.
Nachdem wir das erledigt haben, setzen wir Label1 (Alternativ kann man hier auch eine Schleife (Loop/Cycle) starten lassen, aber ich arbeite lieber mit Labels).
Nach dem Label werden die Item IDs und die Stack IDs verteilt und in den Variablen "ItemID#","ItemID#2","StackID#" und "StackID#2" gespeichert.
Jetzt kommt die Abfrage.
Wenn "ItemID#" kleiner ist als "ItemID#2" dann sind die beiden Zahlen in der richtigen Reihenfolge und "ItemPointerSort", "ItemPointerSort2", "StackPointerSort" und "StackPointerSort2" werden um 1 erhöht.

Wenn dies allerdings nicht der Fall ist und "ItemID#" größer ist als "ItemID#2", dann sollen die beiden getauscht werden. Da es allerdings keine direkte Funktion zum Tauschen gibt, müssen wir uns anders helfen. Wir speichern "ItemID#" in "swapItemID" und "StackID#" in "swapStackID". Anschließend setzen wir "ItemID#" auf "ItemID#2" und "StackID#" auf "StackID#2" bevor wir "ItemID#2" auf "swapItemID" und "StackID#2" auf "swapStackID" setzen. Nun haben wir die beiden Werte vertauscht.
Nach dem Vertauschen müssen "ItemPointerSort", "ItemPointerSort2", "StackPointerSort" und "StackPointerSort2" um 1 reduziert werden.

Anschließend kommt noch eine Abfrage die abfragt, ob "ItemPointerSort" gleich 100 ist. Wenn es nämlich 100 ist ragt es aus dem Arbeitsarray raus wäre gleich dem Wert der 50. Mengenvariable der Items. Das wäre also der Fall, dass der Sortieralgorithmus 1 Schritt nach "links" will, aber dort begrenzt ist. Also müssen wir "ItemPointerSort", "ItemPointerSort2", "StackPointerSort" und "StackPointerSort2" auf 102,103 und 151,152 setzen (oder einfach 2 addieren).
Als vorletztes vom eigentlichen Sortieren kommt noch die Abfrage ob "ItemPointerSort" gleich 150 ist. (Alternativ könnte man abfragen ob "ItemPointerSort2" gleich 151 ist (und somit außerhalb des Arbeitsarrays ist)). Wenn das der Fall ist kommt ein JumpToLabel:2(oder wenn mein mit einer Loop arbeitet ein Break out of Lopp),da der Sortiervorgang abgeschlossen ist.
Nach der Abfrage kommt JumpToLabel:1 (bzw. das Ende der Loop).
So nun wird ganz am Ende dieses CE das CE "Items korrigieren" aufgerufen.

~Die Itempositionen korrigieren~

Mit dem eigentlichem Sortieren sind wir zwar fertig, aber die 0 wurde mitsortiert. Das heißt ihr werdet vielleicht erstmal eine gewisse Anzahl an Items mit der ID 0 haben bevor irgendwann ganz hinten (z.B. bei Itemslot 48,49 und 50 wenn man nur 3 Items hatte) eure sortierten Items kommen.
Um diesen "Missstand" zu beheben benutzen wir jetzt das CE "Items korrigieren". Natürlich könnte man das auch im Sortierevent dranhängen, aber ich habe lieber alles sortiert und weiß welcher Teil was bewirkt.

Der Code:




- SCRIPT -
<> Change Variable: [201:ItemPointer] = 0
<> Comment: ItemPointer wird auf 0 gesetzt, da sonst ein Bug ensteht und die Zahl aus dem ItemPointer mit nachgerückt wird, wahrscheinlich die 51...allerdings weiß
: ich nicht warum da die Variable 201 hier nicht verwendet wird. (Oder ich bin blind. :D)
<> Change Variable: [207:ItemPointerSort] = 101
<> Change Variable: [211:ItemPointerSort2] = 102
<> Change Variable: [209:StackPointerSort] = 151
<> Change Variable: [213:StackPointerSort2] = 152
<> Change Variable: [208:ItemID#] = V[V[207]]
<> Change Variable: [212:ItemID#2] = V[V[211]]
<> Change Variable: [217:Sortierzähler] = 1
<> Change Variable: [219:StackCorrectSlot] = 151
<> Change Variable: [218:ItemCorrectSlot] = 101
<> Change Variable: [210:StackID#] = V[V[209]]
<> Change Variable: [214:StackID#2] = V[V[213]]
<> Comment: Die notwendigen Variablen werden initialisiert...yay ein fachwort :D
<> Label: 1
<> Fork Condition: If Variable [208:ItemID#] == 0 then ...
. <> Comment: Wenn die ItemID# an der Stelle von ItemCorrectPointer 0 ist,
. : dann sollen alle nachfolgenden Items 1 Feld nachrücken
. : und der Switch ItemCorrector wird auf ON gesetzt um nachher die
. : letzte Variable auf 0 zu setzen (sonst stimmt es nicht)
. <> Change Switch: [3:ItemCorrector] = ON
. <> Fork Condition: If Variable [217:Sortierzähler] <= 50 then ...
. . <> Comment: Das Nachrücken wird für alle 50 Items und Mengen durchgeführt
. . <> Change Variable: [V[218]] = V[212:ItemID#2]
. . <> Change Variable: [V[219]] = V[214:StackID#2]
. . <> Change Variable: [218:ItemCorrectSlot] += 1
. . <> Change Variable: [219:StackCorrectSlot] += 1
. . <> Change Variable: [211:ItemPointerSort2] += 1
. . <> Change Variable: [213:StackPointerSort2] += 1
. . <> Change Variable: [212:ItemID#2] = V[V[211]]
. . <> Change Variable: [214:StackID#2] = V[V[213]]
. . <> Change Variable: [217:Sortierzähler] += 1
. . <>
. : Else ...
. . <> Change Variable: [217:Sortierzähler] = 1
. . <> Change Variable: [207:ItemPointerSort] = 101
. . <> Change Variable: [211:ItemPointerSort2] = 102
. . <> Change Variable: [209:StackPointerSort] = 151
. . <> Change Variable: [213:StackPointerSort2] = 152
. . <> Change Variable: [208:ItemID#] = V[V[207]]
. . <> Change Variable: [212:ItemID#2] = V[V[211]]
. . <> Change Variable: [210:StackID#] = V[V[209]]
. . <> Change Variable: [214:StackID#2] = V[V[213]]
. . <> Change Variable: [218:ItemCorrectSlot] = 101
. . <> Change Variable: [219:StackCorrectSlot] = 151
. . <> Comment: Die Variablen werden zurückgesetzt, damit wieder in Itemslot 1
. . : die ItemID abgefragt wird...das wird wiederholt bis die ItemID
. . : ungleich 0 ist
. . <>
. : End of fork
. <>
: Else ...
. <> Comment: Wenn die ItemID ungleich 0 ist, wird die Schleife verlassen
. <> Jump To Label: 2
. <>
: End of fork
<> Jump To Label: 1
<> Label: 2
<> Fork Condition: If Switch [3:ItemCorrector] == ON then ...
. <> Comment: Wenn mindestens 1x nachgerückt wurde, ist ItemCorrector ON
. : und dann werden ItemSlot 50 und MengenSlot 50 auf 0 gesetzt
. <> Change Variable: [218:ItemCorrectSlot] = 150
. <> Change Variable: [V[218]] = 0
. <> Change Variable: [219:StackCorrectSlot] = 200
. <> Change Variable: [V[219]] = 0
. <> Comment: Am Ende wird ItemCorrector wieder ausgeschaltet
. <> Change Switch: [3:ItemCorrector] = OFF
. <>
: End of fork



Auch hier werden zuerst alle nötigen Variablen gesetzt. Ich denke dazu muss ich nicht mehr viel sagen.

Nun fängt das System mit dem Nachrücken an.
Zuerst wird ein Label gesetzt, das nachher wieder mit einem JumpToLabel eine Schleife darstellt. Dann wird abgefragt ob die "ItemID#" an der Stelle gleich 0 ist.
Wenn das der Fall ist, dann müssen die hinteren Items nachrücken.
Als erstes stellen wir den Switch "ItemCorrector" auf ON. Warum erkläre ich später. Dann wird abgefragt ob die Variable "Sortierzähler" kleiner oder gleich 50 ist.
Wenn "Sortierzähler" kleiner oder gleich 50 ist, werden die Schritte für das Korrigieren ausgeführt. Das heißt in die Slotnummer die bei "ItemCorrectSlot" steht (Variable Reference) wird die "ItemID#2" (Value of Variable) reingeschrieben. Somit ist das 2. Item auf Platz 1 gerückt. Damit das auch mit der Menge geschieht, muss man das auch mit "StackCorrectSlot" und "StackID#2" machen. Danach werden die Variablen bearbeitet, damit das beim nächsten durchgang einen Slot höher passiert (Item 3 rutscht auf Plat 2 usw.) Anschließend wird "Sortierzähler" noch um 1 erhöht, da der Durchgang 50 mal (Anzahl der Itemslots) wiederholt werden soll.
Wenn "Sortierzähler" größer als 50 ist, werden die Variablen wieder auf die Anfangswerte (am Anfang des CE) gesetzt, damit erneut die erste Item ID geprüft wird.
Wenn diese gleich 0 ist fängt das ganze von vorne an. Andernfalls Wird das CE aus der Label-Schleife springen.

Nun wird überprüft ob der Switch "ItemCorrector" ON ist.
Wenn ja ist das Nachrücken mindestens einmal durchgelaufen und d.h. alle Variablen wurden verschoben und der letzte Slot muss eine 0 sein. Da er das aber nicht ist, wird jetzt sowohl bei dem letzten Itemslot als auch bei dem letzten Stackslot die Variable auf 0 gesetzt und der Switch "ItemCorrector" wieder auf OFF gestellt.

Jetzt sind alle unsere Items fertig sortiert und in einer schönen Reihenfolge. Alle Items die wir nicht haben (Item ID = 0) sind hinter allen anderen Variablen.
Somit sind wir nahezu komplett fertig. Allerdings müssen wir noch die Variablen aus dem Arbeitsarray zurück in das richtige Array kopieren. Hier gebe ich ebenfalls nur unkommentierten Code.




- SCRIPT -
<> Change Variable: [201:ItemPointer] = 101
<> Change Variable: [202:PointedItem] = V[V[201]]
<> Change Variable: [203:StackPointer] = 151
<> Change Variable: [204:PointedStack] = V[V[203]]
<> Change Variable: [207:ItemPointerSort] = 1
<> Change Variable: [209:StackPointerSort] = 51
<> Comment: Die Variablen, die für's Kopieren notwendig sind werden gesetzt.
<> Label: 1
<> Change Variable: [V[207]] = V[202:PointedItem]
<> Change Variable: [V[209]] = V[204:PointedStack]
<> Change Variable: [201:ItemPointer] += 1
<> Change Variable: [202:PointedItem] = V[V[201]]
<> Change Variable: [203:StackPointer] += 1
<> Change Variable: [204:PointedStack] = V[V[203]]
<> Comment: Die Variablen werden kopiert.
<> Change Variable: [207:ItemPointerSort] += 1
<> Change Variable: [209:StackPointerSort] += 1
<> Comment: Der nächste Kopierschrit geschieht eine Variable "höher"
<> Fork Condition: If Variable [201:ItemPointer] == 151 then ...
. <> Comment: Wenn ItemPointer 51 erreicht, wird die Schleife abgebrochen und alle
. : Items sowie die dazugehörigen Mengen sind kopiert
. <> Jump To Label: 2
. <>
: End of fork
<> Jump To Label: 1
<> Label: 2
<> Comment: Die Variablen zur Ausgabe/zum Kopieren/zum Sortieren/zum Korrigieren
: werden auf 0 gesetzt.
<> Change Variable: [201-220] = 0



So das wäre es dann erstmal mit dem eigenem Itemsystem. Ihr müsstet aber noch ein eigenes Shopsystem machen um die Items zu kaufen bzw. mit ihnen zu handeln und ein eigenes Menü um sie zu benutzen. Das sollte aber keine allzu große Herausforderung mehr darstellen, da das hauptsächlich Abfragen sind und ein paar Bilder anzeigen lassen oder sich ein Menü auf eine Map basteln.



Also das war jetzt mein Tutorial zum Erstellen von einem eigenem Itemsystem. Da es mein allererstes Tutorial ist hoffe ich euch hat's gefallen, ihr konntet das ein oder andere lernen (dafür sind Tutorials ja da) und das man mich und meine Schreibweise verstehen konnte. (: Ich würde mich über konstruktive Kritik freuen. (:


LG Quetschi

PS: Ich hoffe es haben sich keine Rechtschreib- oder Grammatikfehler eingeschlichen.

goldenroy
03.11.2012, 17:24
Nette Idee, wie wärs mit ein bisschen Formatierung? Fette Texte etc. ein bisschen Struktur, Unterteilung in Kapitel etc. Denn so auf den ersten Blick wirkt das ein bisschen durcheinander. Ich les es auf jeden Fall und gib dann noch Kritik zum Inhalt ab. :3~

Kelven
03.11.2012, 17:24
Ist das System nicht etwas kompliziert? Ich mache das bei meinen Spielen immer so, dass ich einfach sage: Variable 101-120 sind Heilgegenstände. Der Gegenstand bei 101 ist immer "Heiltrank x". Dort steht also nur die Menge. Nun startet der Spieler das Menü und wählt den Punkt "Heilgegenstände" aus. Dann geht der Maker die Variablen 101-200 durch, schaut nach ob die Menge > 0 ist. Falls ja, wird die ID in eine temporäre Liste kopiert.

Quetschi
03.11.2012, 17:36
wie wärs mit ein bisschen Formatierung?

Ja, das mach ich noch. Ich hab das ganze mit dem Texteditor geschrieben, weil mein Internet grade nicht so läuft wie es laufen soll und immer wenn ich vom Internet getrennt werde, crahst auch iwie mein Browser und ich wollte nicht dass ich immer von vorne anfangen muss^^


Ist das System nicht etwas kompliziert?

Ja, aber dafür kann man eben auch viel da raus holen. Du wärst jetzt beispielsweise auf 20 Heilitems eingeschränkt (nicht dass das nicht reicht^^) und mit meinem System kann man ein vielfaches an verschiedenen Items "erstellen" ohne gleich pro Item eine Variable mehr zu benutzen.
Nehmen wir also mal an du machst ein richtig großes Spiel und hast um die 500 Items. Mit deinem System bräuchtest du dann 500 Variablen mir reichen die hier. Es ist ja auch nur eine von ganz vielen Arten, wie man es machen kann und ich hab mir halt überlegt wie hab ich möglichst großen Freiraum und dabei bin ich eben auf dieses System gekommen.

Bex
03.11.2012, 21:38
Kommt ihr da nicht ein bischen durcheinander?
Es ist doch nur eineVariable die man braucht. Variable1 = 9 999 999 Items.
Für jeden Slot im Inventar braucht man eine weitere Variable.
Und wenn man nicht nur 1Item pro Slot haben will, braucht man eine 2te Variable die die Anzahl im Slot bestimmt.

Hab das Tutorial nur überflogen, beim ersten lesen hab ich paar richtige Sachen rausgelesen , aber auch einiges wo ich nur dachte was macht ihr denn da?Und geht das nicht deutlich einfacher?.Das mit den Items und den Zahlen würd ich auch in etwa so angehen wie Kelven.Ist genauso viel Arbeit nur in Grün,
da du bei beiden Varianten trotzdem irgendwo festlegen musst was bei den Werten passiert.

Gruß Bex

Kelven
04.11.2012, 10:12
@Quetschi
Also ist der Vorteil deines Systems vor allem das Einsparen von Variablen?

Quetschi
04.11.2012, 10:50
Es ist doch nur eineVariable die man braucht. Variable1 = 9 999 999 Items.


Irgendwie verstehe ich grade nicht was du damit meinst. Kannst du das bitte kurz erklären ?



Für jeden Slot im Inventar braucht man eine weitere Variable.
Und wenn man nicht nur 1Item pro Slot haben will, braucht man eine 2te Variable die die Anzahl im Slot bestimmt.


Das hab ich ja auch so beschrieben^^



aber auch einiges wo ich nur dachte was macht ihr denn da?Und geht das nicht deutlich einfacher?


Könntest du dazu eventuell etwas genaueres schreiben ? Ich hab das Tutorial, ja erstellt und kann es nur aus meiner Sicht beurteilen und da erscheint mir alles logisch^^ Und ja es wird vielleicht ein paar Stellen geben an denen man es sicher einfacher machen könnte, aber das Skript funktioniert so im Maker. Ich hab's ausgiebig getestet und deshalb nicht geguckt wo man es noch einfacher gestalten könnte.

@Kelvin
Jein. Das Einsparen von Variablen passiert ja erst ab einer bestimmten Anzahl von Items. Du wirst mit deinem System deutlich weniger Variablen brauchen, wenn wir beide nur 20 Items haben würden. Aber ab einer gewissen Menge ist mein System vorteilhafter (sehe ich zumindest so).
Ein weiter Vorteil von meinem System ist, das man wie ich bereits im Tutorial selber geschrieben habe an die 2 Millionen Items (mit dem 2k3 sogar an die 20 Millionen Items) haben könnte. Das wird zwar (wahrscheinlich) keiner machen, dennoch ist es ein Vorteil.
Ein Nachteil zu deinem System ist allerdings, dass man bei dir einfacher Items hinzufügen kann. Wenn man bei meinem System nachträglich noch die Anzahl der Itemslots erhöhen will geht das nicht ohne alle anderen Variablen auch umzuräumen.

Bex
04.11.2012, 15:44
Ich hab mir dein Tutorial noch mal ausführlich durchgelesen.
Dabei hab ich verstanden das du viel mit Pointern arbeitest. Diese Funktion gab es bei den Makern die ich benutze bisher nicht.
Dein System scheint eine gute Schaltung zu sein. Kann es leider nicht nachbauen, da mir der Maker fehlt.
Einzig wie du die Funktion des Items aufrufst ist mir im tutorial nicht ganz klar geworden.

Zu der Frage:
(Zitat:Es ist doch nur eineVariable die man braucht. Variable1 = 9 999 999 Items).
Ich hatte mal angefangen ein Inventar zu bauen wo man nur ein Item pro Itemslot haben konnte.Wenn man also 3 Kleine Heiltränke hatte, haben die auch 3von den 10 Plätzen meines Inventars belegt.
z.B.: VariableItemslot10 =500
dann wird Variable1Itemwähler = VariableItemslot10 gesetzt.
Nun steuert der Itemwähler das Item mit der Nummer 500 im Common Event an.
Deshalb Variable1 kann soviele Item IDS im Common Event ansteuern bis der Maker zuviel hat^^ dann schachteln wir das nochmal und so sind bestimmt min 999 verschiedene Items möglich.

Gruß Bex

Quetschi
04.11.2012, 16:28
Ihr müsstet aber noch ein eigenes Shopsystem machen um die Items zu kaufen bzw. mit ihnen zu handeln und ein eigenes Menü um sie zu benutzen. Das sollte aber keine allzu große Herausforderung mehr darstellen, da das hauptsächlich Abfragen sind


Ich habe auch nicht geschrieben, wie ich die Funktionen der Items aufrufe. Ich habe lediglich hinzugefügt, dass man dafür ein eigenes Menü braucht (ganz egal ob es aus Messages oder Grafiken besteht). Anders geht es nicht.
Und nach dem Abfragen ist der Rest eigentlich auch nur Variablenspielerei, da sich der Makerer ja selber überlegt welche Effekte seine Items haben. Man kann z.B. mit diesem System auch Items einbauen, welche die HP um einen zufälligen (Prozent-)wert zwischen x und y heilen (bietet einem das Standarditemsystem ja nicht) oder andere "tolle" Effekte.
Worauf ich hinaus will ist, das wenn man sich dieses Tutorial anguckt und versteht und das System (vielleicht) in sein Spiel integrieren möchte, das Aufrufen der Funktionen eigentlich alleine Hinbekommen sollte.

DNKpp
05.11.2012, 09:55
ok, ich lese grade noch, aber mir fällt direkt etwas ins auge.
du versuchst flags (flags werden in der programmierung bitwerte, also 0 und 1, genannt) nachzubasteln, nutzt aber die zehner stellen. das mag an für sich einfacher sein, ist aber meiner ansicht nacht wenig zweckmäßig.
wenn du sowieso nur an oder aus hast, kannst du auch entsprechend auch folgendes machen:

im menü nutzbar = 1
im kampf nutzbar = 2
verbrauchbar = 4
etc = 8

jetzt hast du mit zwei zehnerstellen schon 4 mögliche flags, die beliebig miteinander kombiniert werden können.
lass mich eben zeigen, wie man das macht:

sagen wir, du hast ein item mit der ID 100013. jetzt wenden wir den modulo darauf an. aber welchen wert wenden wir an? wir nehmen einfach die nächst höhere zehnerpotenz. wir haben 4 flags. diese potenzieren wir mit 2 und subtrahieren 1, was 15 entspricht (15 ist der höchste wert, den die item flags haben können, wenn alle flags gesetzt sind). die nächst höhere zehner potenz nach 15 ist 100, also machen wir 100013 % 100. raus bekommen wir 13.
jetzt beginnt das richtige aufschlüsseln:
wir beginnen mit dem höchsten flag wert, und schauen ob der in unseren wert hinein passt.
unser flag etc hat einen wert von 8. 8 ist kleiner als 13, also setzen wir einen zwischenspeicher switch auf an und subtrahieren 8 von 13. am ende bleibt die 5. der nächste flag hat den wert 4. gleiches spiel wieder. 4 passt in 5, also wieder einen anderen switch auf an, und am ende bleibt die 1. der nächste flag hat den wert 2. 2 ist größer als 1 also ist der flag nicht gesetzt, gehen wir also weiter.
zum schluss steht dann noch die 1, 1 passt in 1 also ist der flag mit dem wert 1 gesetzt, und wir setzen wieder einen hilfsswitch auf 1.
am ende wäre dann unser ergebnis:
im menü nutzbar = ja
im kampf nutzbar = nein
verbrauchbar = ja
etc = ja

das ganze ist beliebig erweiterbar.
hoffe es ist verständlich geworden, was ich meine ;)

Kelven
05.11.2012, 10:55
@Quetschi
Ich denke, es ist auf dem 2K(3) aber auch besser, relativ wenige Gegenstände zu haben. Die kommerziellen Spiele sind in der Hinsicht nicht gut designed, zumindest die JRPGs, über westliche RPGs kann ich nichts sagen. Es gibt tonnenweise Gegenstände, von denen man den Großteil nicht braucht, entweder weil sie nichts nützen oder weil sie redundant sind. Aber zurück zum 2K. Dort müsste man die Gegenstände ja alle anzeigen. Egal ob man Pictures oder Events nimmt, den Namen und die Beschreibung müsste man trotzdem auf ein Bild zeichnen. Bei >1000 Gegenständen wäre das eine riesige Arbeit. Es sei denn man nimmt einen Patch (keine Ahnung wie performant ein Menü mit dieser Draw-Text-Funktion laufen würde).

Quetschi
10.11.2012, 10:28
Naja das mit den Items ist immer so eine Sache. Ich persönlich hab eig nur Final Fantasy 4-9 gespielt und da fand ich als überflüssig nur die Items, die dem Gegner Schaden zufügen (weil das nur ein Bruchteil ist von dem Schaden den man selber mit Zaubern macht) und die meisten die dem Gegner negative oder mir positive Statuseffekte geben, weil das auch mit Zaubern geht.

Und das Items überflüssig sind, naja dann muss man die Items nicht unbedingt ins Spiel einbauen. Ich habe beispielsweise vor alle Items, die man in meinem Spiel erhält verwerten zu können. Man muss nur gucken wie man das macht. Selbst wenn es nur verkaufen ist. Wird es bei mir geben, weil die meisten nicht-menschlichen Gegner nicht sehr viel Gold abgeben (Jetzt mal ehrlich, als ob jedes Monster zich Helden,Wanderer und Händler am Tag frisst, damit es mir nachher 5.000 Goldstücke droppen kann.) Und dann verkauft man diese eben oder lässt sich Sachen daraus schmieden (die dann zum Großteil besser sind als die,die man findet), braucht die für Side-Quests und weiß ich nicht was man noch alles damit machen kann.

Und das mit dem großen Aufwand bei einer erhöhten Anzahl von Items stimmt schon, das hat man aber bei jedem eigenem Inventar oder Menü. Sind aber auch nur 2 Bilder pro Item (Name und Beschreibung) also wenn man nicht gerade übertreibt und wie du sagtest über 1000 Items macht, dann sollte das vom Aufwand her eigentlich auch gehen.