Vorwort:
Guten Tag, liebe Community.
In diesem Tutorial möchte ich intensiv die Tabellen bzw. "Arrays" der Sprache "Lua" behandeln.
Die meißten von euch sollten wissen, dass Metin2 eine abgewandelte Form Lua's für seine Quests verwendet und die Tabellen-/Arraystruktur ist demnach ziemlich identisch.
Trotzdem werde ich dieses Tutorial explizit auf Metin2 beziehen und versuchen bei jedem Kapitel ein sinnvolles Beispiel zu bringen. Ich kann schoneinmal vorwegnehmen, dass der Questname "testquest" und das Testitem "40002" immer gleich bleiben, also nicht wundern.
Warum ich dieses Tutorial schreibe, dafür gibt es mehrere Gründe. Zum einem das es noch kein derartiges Tutorial hier zu finden gibt. Natürlich sprechen Alessa und Nova(bzw. lolkid, oder?) Tabellen in ihren allgemeinen Tutorials an, es gibt aber noch viel mehr zu diesem Thema zu sagen und zu zeigen.
Zum anderen sprechen mich immer wieder Leute an, die das System nicht ganz verstanden haben und es noch einmal erklärt haben möchten, außerdem sieht man hier immer wieder mal Quests, die durch Tabellen deutlich kürzer und übersichtlicher geschrieben werden könnten.
Auch wenn ich mich selbst nicht als "Profi" oder ähnliches bezeichnen möchte, so kann ich den Anfängern bzw. Fortgeschrittenen Questern doch noch etwas beibringen in diesem Bereich der Tabellen und genau dies will ich auch tun.
Ich werde noch einmal von Grund auf anfangen im Thema Tabellen, setzte aber gewisse Grundkenntnisse im Bereich Questen vorraus.
Bevor ihr euch dieses Tutorial durchlest, solltet ihr zumindest folgende Tutorials über euch ergehen lassen
----------------------------------------------------------------------------------------------------------------------------------------------------
Tabellen: Was genau war das nochmal?Guten Tag, liebe Community.
In diesem Tutorial möchte ich intensiv die Tabellen bzw. "Arrays" der Sprache "Lua" behandeln.
Die meißten von euch sollten wissen, dass Metin2 eine abgewandelte Form Lua's für seine Quests verwendet und die Tabellen-/Arraystruktur ist demnach ziemlich identisch.
Trotzdem werde ich dieses Tutorial explizit auf Metin2 beziehen und versuchen bei jedem Kapitel ein sinnvolles Beispiel zu bringen. Ich kann schoneinmal vorwegnehmen, dass der Questname "testquest" und das Testitem "40002" immer gleich bleiben, also nicht wundern.
Warum ich dieses Tutorial schreibe, dafür gibt es mehrere Gründe. Zum einem das es noch kein derartiges Tutorial hier zu finden gibt. Natürlich sprechen Alessa und Nova(bzw. lolkid, oder?) Tabellen in ihren allgemeinen Tutorials an, es gibt aber noch viel mehr zu diesem Thema zu sagen und zu zeigen.
Zum anderen sprechen mich immer wieder Leute an, die das System nicht ganz verstanden haben und es noch einmal erklärt haben möchten, außerdem sieht man hier immer wieder mal Quests, die durch Tabellen deutlich kürzer und übersichtlicher geschrieben werden könnten.
Auch wenn ich mich selbst nicht als "Profi" oder ähnliches bezeichnen möchte, so kann ich den Anfängern bzw. Fortgeschrittenen Questern doch noch etwas beibringen in diesem Bereich der Tabellen und genau dies will ich auch tun.
Ich werde noch einmal von Grund auf anfangen im Thema Tabellen, setzte aber gewisse Grundkenntnisse im Bereich Questen vorraus.
Bevor ihr euch dieses Tutorial durchlest, solltet ihr zumindest folgende Tutorials über euch ergehen lassen
----------------------------------------------------------------------------------------------------------------------------------------------------
In Lua gibt es bekanntermaßen verschiedene Arten Variablen und ebenso wie ein String oder ein Boolean Variablen sind, sind auch Tabellen Variablen.
Da Tabellen Variablen sind, braucht jede Tabelle einen Namen (wobei es später noch "Ausnahmen" geben wird).
Tabellen sind zunächst dazu gedacht, viele, viele andere Variablen zu beherbergen und sortiert aufzulisten, dabei ist egal, welche Arten von Variablen dies sind.
Aber moment mal, haben wir nicht eben festgestellt, dass Tabellen ebenfalls Variablen sind, dann müsste man doch auch Tabellen innerhalb Tabellen beherbergen können?
Absolut richtig, theroetisch könnte man dies "unendlich" oft machen, ob dies einen praktischen Nutzen hätte ist eine andere Sache.
Einen einzelnen Wirkungsbereich von Tabellen zu definieren ist ziemlich schwer, wir werden im Verlauf dieses Tutorials viele sinnvolle Anwendungen sehen, die ohne Tabellen in zum Beispiel ewig langen if-Gefügen enden würden.
Aber fangen wir zunächst einmal mit dem Aufbau einer Tabelle an:
Da Tabellen Variablen sind, braucht jede Tabelle einen Namen (wobei es später noch "Ausnahmen" geben wird).
Tabellen sind zunächst dazu gedacht, viele, viele andere Variablen zu beherbergen und sortiert aufzulisten, dabei ist egal, welche Arten von Variablen dies sind.
Aber moment mal, haben wir nicht eben festgestellt, dass Tabellen ebenfalls Variablen sind, dann müsste man doch auch Tabellen innerhalb Tabellen beherbergen können?
Absolut richtig, theroetisch könnte man dies "unendlich" oft machen, ob dies einen praktischen Nutzen hätte ist eine andere Sache.
Einen einzelnen Wirkungsbereich von Tabellen zu definieren ist ziemlich schwer, wir werden im Verlauf dieses Tutorials viele sinnvolle Anwendungen sehen, die ohne Tabellen in zum Beispiel ewig langen if-Gefügen enden würden.
Aber fangen wir zunächst einmal mit dem Aufbau einer Tabelle an:
Der Aufbau einer Tabelle
Eine Tabelle, besser gesagt, alle Werte dieser Tabelle werden durch
eingegrenzt.
Wie wir bereits festgestellt haben, brauchen Tabellen in der Regel einen Namen, also weisen wir doch mal unser Variable tab eine Tabelle zu:
Nun ist die Tabelle aber ganz leer, so bringt sie uns wenig.
Setzen wir mal 3 Zahlenwerte ein:
Der aufmerksame Beobachter dürfte festgestellt haben, dass wir einzelne Werte bzw. Variablen mit Kommata abtrennen.
Aber naja, jetzt haben wir eine Tabelle mit 3 Werten in ihr, bringt uns so nicht weiter, wir wollen sie natürlich auch auslesen.
Das auslesen läuft immer gleich ab:
nimmt dabei den Wert der Position in der Tabelle tab an.
würde demnach ein "19" in den Chat schreiben.
Hierzu schonmal eine mini Beispielquest, wie wir das bis hierhin Gelernte sinnvoll anwenden können:
Da sel ja nach der Auswahl einen Wert zwischen 1 und 3 annimmt, geben wir anschließend das Item mit der Vnum aus der "sel'ten Position der Tabelle tab" aus.
Wir sparen uns dabei ein if-Gefüge mit 3 verschiedenen Verzweigungen. Stellt euch nun aber mal vor, ihr wollt aus 20 Items auswählen lassen, eine Tabelle mit 20 Werten ist deutlich schneller geschrieben und übersichtlicher als ein if-Gefüge mit 20 Verzweigungen, findet ihr nicht?
(Und nebenbei gesagt, sieht es auch schöner aus. )
Aber hatten wir nicht auch gesagt, dass "richtige" Variablen in einer Tabelle beherbergt werden können? Richtig:
würde genauso gehen, würde man jetzt
ansprechen, würde man "39" zurückerhalten, da "a" ja "39" entspricht.
PHP Code:
{}
Wie wir bereits festgestellt haben, brauchen Tabellen in der Regel einen Namen, also weisen wir doch mal unser Variable tab eine Tabelle zu:
PHP Code:
local tab = {}
Setzen wir mal 3 Zahlenwerte ein:
PHP Code:
local tab = {19, 29, 39}
Aber naja, jetzt haben wir eine Tabelle mit 3 Werten in ihr, bringt uns so nicht weiter, wir wollen sie natürlich auch auslesen.
Das auslesen läuft immer gleich ab:
PHP Code:
tab[Position]
PHP Code:
chat(tab[1])
Hierzu schonmal eine mini Beispielquest, wie wir das bis hierhin Gelernte sinnvoll anwenden können:
PHP Code:
quest testquest begin
state start begin
when 40002.use begin
local tab = {19,29,39}
say("Welches Item möchtest du?")
local sel = select("Schwert +9", "Langschwert +9", "Sichelschwert +9")
pc.give_item2(tab[sel], 1)
end
end
end
Wir sparen uns dabei ein if-Gefüge mit 3 verschiedenen Verzweigungen. Stellt euch nun aber mal vor, ihr wollt aus 20 Items auswählen lassen, eine Tabelle mit 20 Werten ist deutlich schneller geschrieben und übersichtlicher als ein if-Gefüge mit 20 Verzweigungen, findet ihr nicht?
(Und nebenbei gesagt, sieht es auch schöner aus. )
PHP Code:
local a = 39
local tab = {19, 29, a}
PHP Code:
tab[3]
Tabellen innerhalb Tabellen
So, wir haben ja schon gesagt, dass Tabellen auch Tabellen beherbergen können.
Das ganze wird jetzt zugegebenermaßen etwas abstrakt, aber in dem Beispiel am Ende dieses Kapitels sollte es einleuchtend sein.
Genaugenommen ändert sich das System von oben nicht.
Aber schauen wir uns zunächst eine Tabelle an, welche zwei Tabellen enthält, diese zwei Tabellen enthalten nun wiederum jeweils 3 Werte:
Aber hoppla, die zwei "Untertabellen" haben ja gar keinen Namen? In der Tat, dies war die Ausnahme, von der ich oben sprach. Manchmal kann dies aber auch Nachteile mit sich bringen. Wie wir den Untertabellen trotzdem "Namen" zuweißen, kommt im auf dieses Kapitel folgende Kapitel "Indizierung".
Aber zunächst hat der wiederum aufmerksame Beobachter bemerkt, dass nur nach der 1. "Untertabelle" ein Komma steht, warum wissen wir aber schon längst:
Die 1. Untertabelle ist die 1. Position der Tabelle tab und die 2. Untertabelle ist die 2. Position.
Da wir bekanntermaßen die einzelnen Positionen mit Kommata abtrennen müssen steht hinter der 1. Untertabelle ein Komma (nach der letzten Position einer Tabelle brauchen wir kein Komma)
Die 6 Werte kann man nun wie folgt ansprechen:
Will ich also 39 auslesen erreiche ich diesen Wert über
Will ich 3019 auslesen über:
Hierzu mal ein kleines Beispiel:
Bevor ihr zum nächsten Kapitel geht, solltet ihr dieses Beispiel komplett verstanden haben, andernfalls solltet ihr noch einmal das vorherige Kapitel durchlesen (oder ich kann's einfach nur nicht gut genug erklären ._.)
Dies gilt ab jetzt für jedes Beispiel, da ihr sonst vielleicht irgendwann nicht mehr mitkommt, alles weitere baut auf diese Grundsätze auf, dass muss einfach sitzen
Das ganze wird jetzt zugegebenermaßen etwas abstrakt, aber in dem Beispiel am Ende dieses Kapitels sollte es einleuchtend sein.
Genaugenommen ändert sich das System von oben nicht.
Aber schauen wir uns zunächst eine Tabelle an, welche zwei Tabellen enthält, diese zwei Tabellen enthalten nun wiederum jeweils 3 Werte:
PHP Code:
local tab = {
{19, 29, 39},
{3009, 3019, 3029}
}
Aber zunächst hat der wiederum aufmerksame Beobachter bemerkt, dass nur nach der 1. "Untertabelle" ein Komma steht, warum wissen wir aber schon längst:
Die 1. Untertabelle ist die 1. Position der Tabelle tab und die 2. Untertabelle ist die 2. Position.
Da wir bekanntermaßen die einzelnen Positionen mit Kommata abtrennen müssen steht hinter der 1. Untertabelle ein Komma (nach der letzten Position einer Tabelle brauchen wir kein Komma)
Die 6 Werte kann man nun wie folgt ansprechen:
PHP Code:
tab[Untertabelle][Position]
PHP Code:
tab[1][3]
PHP Code:
tab[2][2]
PHP Code:
quest testquest begin
state start begin
when 40002.use begin
local tab = {
{19,29,39},
{3009,3019,3029}
}
say("Schwerter oder Zweihänder?")
local sel_main = select("Schwerter", "Zweihänder")
say("Welches Item möchtest du?")
local sel_sub = select("Level 1'er Waffe", "Level 5'er Waffe", "Level 10'er Waffe")
pc.give_item2(tab[sel_main][sel_sub], 1)
end
end
end
Dies gilt ab jetzt für jedes Beispiel, da ihr sonst vielleicht irgendwann nicht mehr mitkommt, alles weitere baut auf diese Grundsätze auf, dass muss einfach sitzen
Indizierung
Zunächst einmal, "Indizierung" ist eine Bezeichung, die ich so verwende. Andere mögen das, was wir gleich machen, anderst nennen oder vielleicht gibt es sogar einen offiziellen Namen, wer weiß.
Wenn man es aus dem Englischem übersetzt, heißt es sowas wie "Schlüssel verteilen" (also nicht Indizierung bedeutet "Schlüssel verteilen", sondern in englsichen Tutorials spricht man von "keys").
Der Sinn ist das einfachere und zielgerichtetere Ansprechen eines bestimmten Wertes (oder Variable -> Tabelle) innerhalb einer Tabelle.
Ein gutes Beispiel wann dies sehr nützlich ist, ist zum Beispiel das, was wir im vorherigen kapitel kritisiert haben:
"Untertabellen" haben zunächst keinen "Namen", dies können wir aber ändern.
Es gibt zwei Varianten, wie wir ihnen einen "Namen", einen "Schlüssel" zuweißen können. Es gibt nur einen großen Unterschied, den wir nachher betrachten.
In der Ansprache später unterscheiden sie sich aber überhaupt nicht, sehen wir uns beide Varianten kurz an. Ich persönlich verwende aber nur eine davon.
Aber widmen wir uns zunächst der anderen:
Den Wert 39 können wir nun mittels
ausgeben, den Wert 3019 mittels
Man kann natürlich nicht nur Tabellen einen Schlüssel geben, nein, man kann jeder Variable und jedem Wert einen Schlüssel zuweißen:
Die einzelnen Werte können wir nun mit
ansprechen. Ja, es geht sowohl .hobbys, als auch ["hobbys"].
Nun aber zur anderen Möglichkeit der Schlüsselvergabe, welche ich persönlich übersichtlicher finde:
Anstatt
sähe das dann wie folgt aus:
hat sich ja nicht viel getan, die Werte können wir ebenfalls mit
ansprechen, also auch wieder mit beiden Methoden.
Einen großen Unterschied gibt es allerdings. Für "name" oder "hobby" dürften wir in der 1. Variante keine Zahlen, bzw. keine Variablen, die mit einer Zahl beginnen einsetzen, bei der 2. geht dies aber (ohne " ")!
Deswegen verwende ich die 2. Variante, sie funktioniert "immer" und ist wie gesagt meiner Meinung nach übersichtlicher.
Zeit für ein kleines Beispiel, nicht?
Wenn man es aus dem Englischem übersetzt, heißt es sowas wie "Schlüssel verteilen" (also nicht Indizierung bedeutet "Schlüssel verteilen", sondern in englsichen Tutorials spricht man von "keys").
Der Sinn ist das einfachere und zielgerichtetere Ansprechen eines bestimmten Wertes (oder Variable -> Tabelle) innerhalb einer Tabelle.
Ein gutes Beispiel wann dies sehr nützlich ist, ist zum Beispiel das, was wir im vorherigen kapitel kritisiert haben:
"Untertabellen" haben zunächst keinen "Namen", dies können wir aber ändern.
Es gibt zwei Varianten, wie wir ihnen einen "Namen", einen "Schlüssel" zuweißen können. Es gibt nur einen großen Unterschied, den wir nachher betrachten.
In der Ansprache später unterscheiden sie sich aber überhaupt nicht, sehen wir uns beide Varianten kurz an. Ich persönlich verwende aber nur eine davon.
Aber widmen wir uns zunächst der anderen:
PHP Code:
local tab = {
schwerter = {19, 29, 39},
zweihaender = {3009, 3019, 3029}
}
PHP Code:
tab.schwerter[3]
PHP Code:
tab.zweihaender[2]
PHP Code:
local tab = {
name = "554",
hobbys = {"Handball", "Party, Bruder"}
}
PHP Code:
tab.name
tab.hobbys[1]
tab["hobbys"][2]
Nun aber zur anderen Möglichkeit der Schlüsselvergabe, welche ich persönlich übersichtlicher finde:
Anstatt
PHP Code:
local tab = {
name = "554",
hobbys = {"Handball", "Party, Bruder"}
}
PHP Code:
local tab = {
["name"] = "554",
["hobbys"] = {"Handball", "Party, Bruder"}
}
PHP Code:
tab.name
tab.hobbys[1]
tab["hobbys"][2]
Einen großen Unterschied gibt es allerdings. Für "name" oder "hobby" dürften wir in der 1. Variante keine Zahlen, bzw. keine Variablen, die mit einer Zahl beginnen einsetzen, bei der 2. geht dies aber (ohne " ")!
Deswegen verwende ich die 2. Variante, sie funktioniert "immer" und ist wie gesagt meiner Meinung nach übersichtlicher.
Zeit für ein kleines Beispiel, nicht?
Der Befehl
liefet ja einen Wert zwischen 0 und 3 zurück. Wir wollen nun einem Spieler die richtige Starterwaffe geben.
Da aber unsere Tabellen immer bei Position 1 anfangen, müssten wir dann "extra" noch +1 addieren, das sieht doch aber total unschön aus, findet ihr nicht? Stattdessen können wir doch unsere Tabelle etwas anpassen:
Dies ist jetzt ein recht schlechtes Beispiel für die Wirkungsmacht einer Indizierung, schauen wir uns noch ein anderes an:
Dies geht nun deutlich schneller, als ein if-Gefüge mit 3 Verzweigungen zu machen oder die ganze Quest 3x zu schreiben.
PHP Code:
pc.get_job()
Da aber unsere Tabellen immer bei Position 1 anfangen, müssten wir dann "extra" noch +1 addieren, das sieht doch aber total unschön aus, findet ihr nicht? Stattdessen können wir doch unsere Tabelle etwas anpassen:
PHP Code:
quest testquest begin
state start begin
when 40002.use begin
local tab = {
[0] = 19,
[1] = 1019,
[2] = 19,
[3] = 7009
}
pc.give_item2(tab[pc.get_job()], 1)
end
end
end
----------------------------------------------------------------------------------------------------------------------------------------------------
Wir wollen eine Quest gestalten, die man mit 3 versch. Items startet (40002, 40003, 40004) und bei jeder soll ein anderes Item herausgegeben werden:PHP Code:
quest testquest begin
state start begin
when 40002.use or 40003.use or 40004.use begin
local tab = {
[40002] = 19,
[40003] = 29,
[40004] = 39
}
pc.give_item2(tab[item.get_vnum()], 1)
end
end
end
Tabellen-Befehle
Es gibt eine Ansammlung an Befehlen, die uns helfen, Tabellen zu erweitern, Positionen zu löschen, zu sortieren oder einfach "durchzuarbeiten".
Zunächst einmal muss ich noch klarstellen, dass oft Parameter optional sind, diese werden im Befehl mit [ ] eingeklammert, im eigentlichen Befehl sind diese aber dann natürlich nicht vorhanden (also die eckigen Klammern).
Listen wir ersteinmal alle Befehle auf:
Ui, ist ja'n ganz schöner Haufen, schauen wir uns sie Befehle im einzelnen einmal an.
table.getn:
Ein sehr wichtiger Befehl, der recht simpel ist.
Gibt die Anzahl der Positionen der Tabelle "TABELLE" zurück (als Zahl in Ziffern)
n wäre in diesem Fall 3
table.setn:
Die Tabelle bei "table.getn" hatte ja 3 Positionen.
Nach Ausführen des Befehls
hat sie nun 7 Positionen und
gibt nun auch "7" zurück, die weiteren 4 Positionen werden mit "nil" befüllt.
table.insert:
Selbsterklärend, nicht? Setzt den Wert "WERT/VARIABLE" in die Tabelle "TABELLE" und zwar an der Position "POS", sollte diese nicht angegeben werden, setzt er es an letzter Stelle.
Alle Werte die hinter der neu eingesetzten Variable stehen, werden eine Position nach hinten gesetzt (es wird also nichts "ersetzt").
var wäre in diesem Fall "29", da an 2. Position der Tabelle tab nun "29" steht.
table.remove:
Das Gegenstück zu table.insert.
Löscht die Position "POS" der Tabelle "TABELLE", und rückt alle folgenden Werte eine Position nach vorne. Ist "POS" nicht angegeben, so wird die letzte Position gelöscht.
var ist nun "39", da "29" gelöscht wurde und alles eins aufrückt.
table.sort:
Sortiert alle Werte innerhalb der Tabelle "TABELLE", ist die "SORTIERART" nicht gegeben so wird nach ">" sortiert, also von klein nach groß, "<" muss man eben manuall einsetzen.
Es können sowohl Zahlen untereinander als auch Wörter(Strings) untereinander sortiert werden. Sobald allerdings sowohl Zahlen als auch Strings in der Tabelle sind, kann er das logischerweiße nichtmehr sortieren. (Ist 3 > Baum? Haut ned hin )
var wäre also "78" und var2 wäre "Zaun".
table.foreach:
Diesen Befehl werden wir etwas länger bearbeiten, da er zugegebenermaßen nicht so einfach ist, wie die bisherigen.
Jeder, der bis hierhin gelesen hat, sollte wissen, was eine "for-Schleife" ist und wie sie arbeitet.
table.foreach läuft ähnlich wie eine for-schleife, und viele Quester verwenden lieber for-Schleifen als table.foreach, wir wollen aber natürlich trotzdem wissen, wie sie funktioniert.
Aber zunächst eine for-Schleife, die wir dann 1 zu 1 mit table.foreach ersetzen, also bei beiden Varianten wird exakt das selbe ausgegeben.
For-Schleife:
table.foreach:
Beide Funktionen geben
zurück.
Wie die for-Schleife arbeitet sollte klar sein, i wird von 1 bis zu 3 jeweils um 1 erhöht und wir geben einmal i und einmal tab[i] aus.
table.foreach arbeitet ähnlich, für jede Position nimmt i die Nummer der Position an, also auch wieder 1, 2, 3, und p nimmt DIREKT tab[i] an.
p kann auch eine Tabelle zugewiesen bekommen, sollte in "tab" eine vorhanden sein, dann muss man eben die Ausgabe anpassen.
Wichtig ist bei table.foreach, dass der Aufbau immer gleich ist, nähmlich immer
Die vorherigen Variablen i und p kann man also ersetzen, es sind aber immer 2 Variablen und die 2. Variable ist immer "TABELLE[VAR1]".
Bitte schreibt, wenn euch diese Erklärung nicht ausreicht, da table.foreach für viele nicht leicht verständlich ist.
table.foreachi:
Wir merken schon, der Aufbau von table.foreachi ist der selbe wie von table.foreach
Der einzige Unterschied ist zugleich auch etwas kompliziert.
table.foreachi geht ebenfalls eine Tabelle durch, allerdings sucht nur solange eine Reihenfolge gegeben ist.
Nun würde nur "19" und "29", da ab der "3." Position, also [4] = 39 die Reihenfolge unterbrochen wurde.
Gibt jetzt interessanterweiße allerdings
aus, solange alle Elemtene der Reihenfolge gegeben sind, läuft table.foreachi weiter, auch wenn es kreuz und quer durch die Tabelle springen muss.
Zu diesem Kapitel gibt es leider mal kein Beispiel, dafür ist das Beispiel im nächsten Kapitel um so wuchtiger.
Zunächst einmal muss ich noch klarstellen, dass oft Parameter optional sind, diese werden im Befehl mit [ ] eingeklammert, im eigentlichen Befehl sind diese aber dann natürlich nicht vorhanden (also die eckigen Klammern).
Listen wir ersteinmal alle Befehle auf:
PHP Code:
table.getn
table.setn
table.insert
table.remove
table.sort
table.foreach
table.foreachi
table.getn:
PHP Code:
table.getn(TABELLE)
Gibt die Anzahl der Positionen der Tabelle "TABELLE" zurück (als Zahl in Ziffern)
PHP Code:
local tab = {19, 39, 49}
local n = table.getn(tab)
table.setn:
PHP Code:
table.setn(TABELLE, n)
Nach Ausführen des Befehls
PHP Code:
table.setn(tab, 7)
PHP Code:
table.getn(tab)
table.insert:
PHP Code:
table.insert(TABELLE, [POS,] WERT/VARIABLE)
Alle Werte die hinter der neu eingesetzten Variable stehen, werden eine Position nach hinten gesetzt (es wird also nichts "ersetzt").
PHP Code:
local tab = {19,39}
table.insert(tab, 2, 29)
local var = tab[2]
table.remove:
PHP Code:
table.remove(TABELLE [, POS])
Löscht die Position "POS" der Tabelle "TABELLE", und rückt alle folgenden Werte eine Position nach vorne. Ist "POS" nicht angegeben, so wird die letzte Position gelöscht.
PHP Code:
local tab = {19,29,39}
table.remove(tab, 2)
local var = tab[2]
table.sort:
PHP Code:
table.sort(TABELLE [,SORTIERART])
Es können sowohl Zahlen untereinander als auch Wörter(Strings) untereinander sortiert werden. Sobald allerdings sowohl Zahlen als auch Strings in der Tabelle sind, kann er das logischerweiße nichtmehr sortieren. (Ist 3 > Baum? Haut ned hin )
PHP Code:
local tab = {78, 15, 35, 18}
local tab2 = {"Zaun", "Baum", "Apfel", "Pflaume"}
table.sort(tab)
table.sort(tab2)
local var = tab[4]
local var2 = tab[4]
table.foreach:
PHP Code:
table.foreach(TABELLE, FUNKTION)
Jeder, der bis hierhin gelesen hat, sollte wissen, was eine "for-Schleife" ist und wie sie arbeitet.
table.foreach läuft ähnlich wie eine for-schleife, und viele Quester verwenden lieber for-Schleifen als table.foreach, wir wollen aber natürlich trotzdem wissen, wie sie funktioniert.
Aber zunächst eine for-Schleife, die wir dann 1 zu 1 mit table.foreach ersetzen, also bei beiden Varianten wird exakt das selbe ausgegeben.
For-Schleife:
PHP Code:
local tab = {19,29,39}
for i = 1, table.getn(tab), 1 do
chat(i..", "..tab[i])
end
PHP Code:
local tab = {19, 29, 39}
table.foreach(tab,
function(i, p)
chat(i..", "..p)
end
)
PHP Code:
1, 19
2, 29
3, 39
Wie die for-Schleife arbeitet sollte klar sein, i wird von 1 bis zu 3 jeweils um 1 erhöht und wir geben einmal i und einmal tab[i] aus.
table.foreach arbeitet ähnlich, für jede Position nimmt i die Nummer der Position an, also auch wieder 1, 2, 3, und p nimmt DIREKT tab[i] an.
p kann auch eine Tabelle zugewiesen bekommen, sollte in "tab" eine vorhanden sein, dann muss man eben die Ausgabe anpassen.
Wichtig ist bei table.foreach, dass der Aufbau immer gleich ist, nähmlich immer
PHP Code:
table.foreach(TABELLE,
function(VAR1, VAR2)
bla bla bla
end
)
Bitte schreibt, wenn euch diese Erklärung nicht ausreicht, da table.foreach für viele nicht leicht verständlich ist.
table.foreachi:
PHP Code:
table.foreachi(TABELLE, FUNKTION)
Der einzige Unterschied ist zugleich auch etwas kompliziert.
table.foreachi geht ebenfalls eine Tabelle durch, allerdings sucht nur solange eine Reihenfolge gegeben ist.
PHP Code:
local tab = {
[1] = 19,
[2] = 29,
[4] = 39,
[5] = 49
}
table.foreachi(tab, function(i, p)
chat(p)
end)
PHP Code:
local tab = {
[1] = 19,
[2] = 29,
[4] = 39,
[5] = 49,
[3] = 59
}
table.foreachi(tab, function(i, p)
chat(p)
end)
PHP Code:
19
29
59
39
49
Mijago-Funktionen
So, nun muss ich mich natürlich wieder etwas bei Mijago einschleimen.
Naja, das lassen wir mal so im Raum stehen, Fakt ist jedoch, dass er in seiner Questlib einige Befehle publiziert hat, die uns bei der Arbeit mit Tabellen doch sehr gut unterstützen.
(Mijago, sag mir Bescheid wenn du hier den Link zu deinem Generator stehen haben möchtest )
Listen wir die für uns jetzt interessanten Befehle zunächst auf:
Fangen wir mit is_table an:
Prüft "ganz einfach" ob die Variable "var" eine Tabelle ist (wir errinern uns, Tabellen sind auch Variablen).
Wie das jetzt genau funktioniert interessiert uns jetzt zunächst einmal nicht
Nützlich wenn wir eine Variable als Tabelle behandeln und bearbeiten wollen, aber garnicht sicher wissen, ob es überhaupt eine Tabelle ist.
in_table:
Prüft, ob die Variable "var" in der Tabelle "TABELLE" enthalten ist und gibt je nachdem "true" oder "false" zurück.
Wenn wir zum Beispiel sicher gehen müssen, dass wir eine Tabelle nicht mit der selben Variable doppelt bestücken ist dieser Befehl sehr nützlich, auch wenn er ziemlich einfach ist:
Er geht einfach einmal die Tabelle durch und vergleicht jede Position mit "var", falls keine Übereinstimmung -> false.
select2:
Erstellt eine Auswahl, wobei die Texte der Buttons den einzelnen Strings der Tabelle tab entsprechen.
Das dies sehr nützlich ist, brauch ich ja wohl nicht zu erwähnen.
Außerdem wird ein "Weiter"- sowie ein "Abbruch"-Button an das Ende gesetzt.
select3:
mysql_query:
So, wie versprochen die "wuchtige" Beispielquest:
Naja, das lassen wir mal so im Raum stehen, Fakt ist jedoch, dass er in seiner Questlib einige Befehle publiziert hat, die uns bei der Arbeit mit Tabellen doch sehr gut unterstützen.
(Mijago, sag mir Bescheid wenn du hier den Link zu deinem Generator stehen haben möchtest )
Listen wir die für uns jetzt interessanten Befehle zunächst auf:
PHP Code:
is_table
in_table
select2
select3
mysql_query (Dazu aber im nächsten Kapitel mehr)
PHP Code:
is_table(var)
Wie das jetzt genau funktioniert interessiert uns jetzt zunächst einmal nicht
Nützlich wenn wir eine Variable als Tabelle behandeln und bearbeiten wollen, aber garnicht sicher wissen, ob es überhaupt eine Tabelle ist.
in_table:
PHP Code:
in_table(var, TABELLE)
Wenn wir zum Beispiel sicher gehen müssen, dass wir eine Tabelle nicht mit der selben Variable doppelt bestücken ist dieser Befehl sehr nützlich, auch wenn er ziemlich einfach ist:
Er geht einfach einmal die Tabelle durch und vergleicht jede Position mit "var", falls keine Übereinstimmung -> false.
select2:
PHP Code:
local tab = {"Eins", "Zwei", "Drei"}
local sel = select2(tab)
Das dies sehr nützlich ist, brauch ich ja wohl nicht zu erwähnen.
Außerdem wird ein "Weiter"- sowie ein "Abbruch"-Button an das Ende gesetzt.
select3:
Der gleiche Aufbau wie bei "select2", allerdings fügt er zusätzlich ab der 2. Auswahlseite noch einen Zurück-Button ein, wirkt dann schon ziemlich profesionell, auch wenn Mijago die Arbeit für uns erledigt hat.
Ist dem zu Folge etwas benutzerfreundlicher als select2, bei wenigen Buttons aber nicht notwendig.
Ist dem zu Folge etwas benutzerfreundlicher als select2, bei wenigen Buttons aber nicht notwendig.
mysql_query:
Den Befehl werde ich jetzt nicht komplett erläutern, mit der "SELECT"-query werden wir uns aber im nächsten Kapitel beschäftigen.
So, wie versprochen die "wuchtige" Beispielquest:
Es handelt sich um eine schon relativ profesionelle Warpringquest, bei der man für die einzelnen Warps jeweils ein bestimmtes Level erreicht haben muss, damit dieses in der Auswahl erscheint.
Außerdem kommt man für OT, Wüste, Eisland und Feuerland zum richtige Spawnpoint (jedes Reich hat ja einen anderen).
Wir kennen nun alle darin vorkommenden Befehle und wissen wie Tabellen ticken, also sollten wir diese Quest auch verstehen:
Versucht, die Quest zu überblicken, der Quelltext nach der großen Tabelle ist eigentlich ziemlich mickrig, oder?
Außerdem kommt man für OT, Wüste, Eisland und Feuerland zum richtige Spawnpoint (jedes Reich hat ja einen anderen).
Wir kennen nun alle darin vorkommenden Befehle und wissen wie Tabellen ticken, also sollten wir diese Quest auch verstehen:
PHP Code:
quest testquest begin
state start begin
when 40002.use begin
local warptab = {
{ -- 1
{{ 402100, 673900 }, { 270400, 739900 }, { 321300, 808000 }},
{ "Tal von Seungryong", 1},
},
{ -- 2
{{ 217800, 627200 }, { 221900, 502700 }, { 344000, 502500 }},
{ "Yongbi-Wüste", 1},
},
{ -- 3
{{ 434200, 290600 }, { 375200, 174900 }, { 491800, 173600 }},
{ "Berg Sohan", 1},
},
{ -- 4
{{ 599400, 757300 }, { 597300, 621800 }, { 730700, 689800 }},
{ "Feuerland", 1},
},
{ -- 5
{{ 590500, 110500 }},
{ "Dämonenturm", 30},
},
{ -- 6
{{ 60000, 496000 }},
{ "Spinnendungeon", 36},
},
{ -- 7
{{ 665600, 435200 }},
{ "Spinnendungeon 2", 45},
},
{ -- 8
{{ 290400, 5700 }},
{ "Geisterwald", 53},
},
{ -- 9
{{ 1119900, 70800 }},
{ "Roter Wald", 62},
},
{ -- 10
{{ 0, 1203200 }},
{ "Grotte der Verbannung", 73},
},
{ -- 11
{{ 241300, 1275400 }},
{ "Grotte der Verbannung 2", 78},
},
{ -- 12
{{ 171900, 1221300 }},
{ "Kammer des Wasserdrachen", 81},
},
}
local showtab = {}
table.foreach(warptab,
function(i, p) -- p = warbtab[i], nicht vergessen
if pc.get_level() >= p[2][2] then
table.insert(showtab, p[2][1])
end
end
)
local sel = select3(showtab)
local emp = pc.get_empire()
if table.getn(warptab[sel][1]) == 1 then
emp = 1
end
pc.warp(warptab[sel][1][emp][1], warptab[sel][1][emp][2])
end
end
end
Mysql_query und Tabellen?
Zunächst ein kleiner Ausschnitt aus der Silberminensystem-Quest von Alessa:
Wow, ich rede hier doch tatsächlich immer nur von den selben 3 Personen. Wie auch immer:
Der Zusammenhang interessiert uns jetzt erstmal nicht.
Aber was die meißten von euch schon einmal gesehen haben, sind die "[1][1]" hinter der Variable, auf die man die SELECT-query anwendet.
Da mich schon ein paar mal Leute angesprochen haben, wo diese "[1][1]" den herkommen, möchte ich das hier kurz erläutern, da es auch etwas mit Tabellen zu tun hat(wer hätte das gedacht?)
Mit der SELECT-query ziehen wir uns ja Teile einer Tabelle aus MySQL auf eine Variable. Die Variable nimmt dabei automatisch den Typ einer Tabelle an.
Ziehen wir uns nun einmal eine gesamte Tabelle aus MySQL:
Nun können wir mittels
auf JEDEN Wert dieser Tabelle zugreifen, probierts doch mal aus.
Wenn wir nun nur Teile aus der Tabelle auslesen, so bleibt die Struktur der Tabelle wie oben bestehen, wir streichen nur "unwichtige", bzw. nicht gefragte Zeilen und Spalten raus.
Wenn wir nun explizit nach einem Wert in der Tabelle fragen, so landet dieser in Zeile 1 und Spalte 1 und es gibt keine weiteren Zeilen/Spalten.
Trotzdem müssen wir ihn noch mit
bzw.
ansprechen, so kommen diese "[1][1]" also zu Stande, für alle, die sich dies je gefragt haben
Wow, ich rede hier doch tatsächlich immer nur von den selben 3 Personen. Wie auch immer:
PHP Code:
function get_working()
local result = mysql_query("SELECT working FROM player.player WHERE player.name='"..pc.get_name().."'")
return tonumber(result[1][1])
end
Aber was die meißten von euch schon einmal gesehen haben, sind die "[1][1]" hinter der Variable, auf die man die SELECT-query anwendet.
Da mich schon ein paar mal Leute angesprochen haben, wo diese "[1][1]" den herkommen, möchte ich das hier kurz erläutern, da es auch etwas mit Tabellen zu tun hat(wer hätte das gedacht?)
Mit der SELECT-query ziehen wir uns ja Teile einer Tabelle aus MySQL auf eine Variable. Die Variable nimmt dabei automatisch den Typ einer Tabelle an.
Ziehen wir uns nun einmal eine gesamte Tabelle aus MySQL:
PHP Code:
local tab = mysql_query("SELECT * FROM player.player")
PHP Code:
tab[ZEILE][SPALTE]
Wenn wir nun nur Teile aus der Tabelle auslesen, so bleibt die Struktur der Tabelle wie oben bestehen, wir streichen nur "unwichtige", bzw. nicht gefragte Zeilen und Spalten raus.
Wenn wir nun explizit nach einem Wert in der Tabelle fragen, so landet dieser in Zeile 1 und Spalte 1 und es gibt keine weiteren Zeilen/Spalten.
Trotzdem müssen wir ihn noch mit
PHP Code:
tab[ZEILE][SPALTE]
PHP Code:
tab[1][1]
Metatables/Metamethods
So, fast pünktlich zum 1-Monats-Jubiläum kommen wir nun auch hierzu.
Ich hab mir länger überlegt, wie ich dieses Thema einläuten lasse und bin zu einer interessanten These gekommen, was der "Sinn" von Metatabellen ist.
"Metatables bestimmten was passiert, wenn man eine Tabelle 'falsch' anspricht oder allgemein 'falsch behandelt'."
Das hört sich jetzt erstmal stupide an, allerdings ergeben sich damit ganz neue Möglichkeiten.
Was sich da zum Beispiel mit machen lässt sehen wir uns an, sobald wir den "Aufbau" einer Methatabelle angeschaut haben:
Das ist jetzt die ausführliche Variante, das kann man auch kürzer verpacken aber wir wollen das ja erstmal verstehen.
Wir haben also eine ganz normale Tabelle, deklarieren uns eine Metatabelle mit dem Event __index und weisen durch setmetatable unserer Tabelle tab diese Metatabelle zu.
Sobald wir nun unsere Tabelle so ansprechen, wie es das Event __index haben möchte startet die Funktion, die wir __index zugewießen haben, die Metamethod startet.
Und dieses "wie es das Event __index haben möchte" ist das "falsch ansprechen" das ich vorhin in den Raum warf.
__index startet nämlich dann, wenn wir eine Position ansprechen, die in der zugewießenen Tabelle tab nicht existiert.
Aber moment mal, die Funktion hat ja auch 2 Variablen.
Sehr richtig, jedes Event hat unterschiedlich viele Variablen, müsste man auswendig lernen, aber da man meißtens sowieso nur 3-5 oft sinnvoll anwenden kann ist das nicht besonders viel.
Aber schauen wir uns mal die Variablen die bei der Funktion von __index mitgeliefert werden an:
(t, i)
t ist dabei automatisch die Tabelle, die die Metatabelle starten ließ.
(kurzer Exkurs: Man kann eine Metatabelle mehreren Tabellen zuweißen, wir haben hier nur eine tabelle also wird t immer tab sein (ja, der Typ der Variable t ist damit auch Variable!))
i ist die Position, die wir ansprechen wollten, welche aber nicht existent ist.
Hier mal ein kleines Beispiel, was man damit "anstellen" könnte:
Spricht man nun die Positionen 1, 20 oder 30 (0 ginge auch, beachten wir aber mal nicht) an bekommt man in notice 1000, 2000 oder 3000 zurück.
Bei allen anderen Positionen bekommt man den Satz
"Die Position n existiert nicht, Keine Ausgabe möglich".
So, kommen wir mal zu __newindex, der Aufbau bleibt gleich:
Ist relativ ähnlich zu __index, nur "springt es an", sobald man einer nicht existierenden Position einen WERT zuweißt (Ist schon ein Unterschied, als nur die Position anzusprechen!)
In diesem Fall wird einfach sobald eine nicht existente Position belegt werden soll(hier 60) in die Tabelle(t) an der Position 60(i) der Wert 60*2(v) eingesetzt, somit wird der anschließende chat-Befehl immer ausgeführt werden können, egal, was wir für x einsetzen.
So, das sollte jetzt auch erstmal reichen, der Großteil der weiteren Events startet, sobald man die Tabelle mit einem mathematischen Operator verrechnet, was aber nur selten Sinn macht, Events wären zum Beispiel __add, __mod, __pow, __eq (equality) usw.
Vielleicht mach ich noch Beispiele zu interessanteren Events (__call, __tostring,[ __metatable (selten sinnvoll)]) aber meißtens sind __index und __newindex die meißt genutzten.
Ich hab mir länger überlegt, wie ich dieses Thema einläuten lasse und bin zu einer interessanten These gekommen, was der "Sinn" von Metatabellen ist.
"Metatables bestimmten was passiert, wenn man eine Tabelle 'falsch' anspricht oder allgemein 'falsch behandelt'."
Das hört sich jetzt erstmal stupide an, allerdings ergeben sich damit ganz neue Möglichkeiten.
Was sich da zum Beispiel mit machen lässt sehen wir uns an, sobald wir den "Aufbau" einer Methatabelle angeschaut haben:
PHP Code:
local tab = {
[10] = 1,
[20] = 2,
[30] = 3
}
meta = {
__index = function(t,i)
bla, bla, commands und so
end
}
setmetatable(tab, meta)
Wir haben also eine ganz normale Tabelle, deklarieren uns eine Metatabelle mit dem Event __index und weisen durch setmetatable unserer Tabelle tab diese Metatabelle zu.
Sobald wir nun unsere Tabelle so ansprechen, wie es das Event __index haben möchte startet die Funktion, die wir __index zugewießen haben, die Metamethod startet.
Und dieses "wie es das Event __index haben möchte" ist das "falsch ansprechen" das ich vorhin in den Raum warf.
__index startet nämlich dann, wenn wir eine Position ansprechen, die in der zugewießenen Tabelle tab nicht existiert.
Aber moment mal, die Funktion hat ja auch 2 Variablen.
Sehr richtig, jedes Event hat unterschiedlich viele Variablen, müsste man auswendig lernen, aber da man meißtens sowieso nur 3-5 oft sinnvoll anwenden kann ist das nicht besonders viel.
Aber schauen wir uns mal die Variablen die bei der Funktion von __index mitgeliefert werden an:
(t, i)
t ist dabei automatisch die Tabelle, die die Metatabelle starten ließ.
(kurzer Exkurs: Man kann eine Metatabelle mehreren Tabellen zuweißen, wir haben hier nur eine tabelle also wird t immer tab sein (ja, der Typ der Variable t ist damit auch Variable!))
i ist die Position, die wir ansprechen wollten, welche aber nicht existent ist.
Hier mal ein kleines Beispiel, was man damit "anstellen" könnte:
PHP Code:
tab = {
[0] = "Keine Ausgabe möglich",
1000,
[20] = 2000,
[30] = 3000
}
meta = {
__index = function(t,i)
return chat(string.format("Die Position %s existiert nicht , %s", i, t[0]))
end
}
setmetatable(tab,meta)
say("Welche Position ansprechen?")
pos = n_input()
notice(tab[pos])
Bei allen anderen Positionen bekommt man den Satz
"Die Position n existiert nicht, Keine Ausgabe möglich".
So, kommen wir mal zu __newindex, der Aufbau bleibt gleich:
PHP Code:
tab = {
[0] = "keine Ausgabe möglich",
1000,
[20] = 2000,
[30] = 3000
}
meta = {
__newindex = function(t,i,v)
return table.insert(t, i, v)
end
}
setmetatable(tab,meta)
local x = 60
tab[x] = x*2
chat(tab[x])
In diesem Fall wird einfach sobald eine nicht existente Position belegt werden soll(hier 60) in die Tabelle(t) an der Position 60(i) der Wert 60*2(v) eingesetzt, somit wird der anschließende chat-Befehl immer ausgeführt werden können, egal, was wir für x einsetzen.
So, das sollte jetzt auch erstmal reichen, der Großteil der weiteren Events startet, sobald man die Tabelle mit einem mathematischen Operator verrechnet, was aber nur selten Sinn macht, Events wären zum Beispiel __add, __mod, __pow, __eq (equality) usw.
Vielleicht mach ich noch Beispiele zu interessanteren Events (__call, __tostring,[ __metatable (selten sinnvoll)]) aber meißtens sind __index und __newindex die meißt genutzten.
----------------------------------------------------------------------------------------------------------------------------------------------------
Nachwort:
Ich hoffe, dass ich allen, die noch Probleme beim Arbeiten mit Tabellen hatten, weiterhelfen konnte. Da dies so ziemlich mein erstes Tutorial war könnten meine Erklärwege nicht gerade optimal gewesen sein.
Ich bitte daher um Feedback im Bereich "Erklärqualität" von den angehenden Questern und um Verbesserungen von den "Profis" was fehlende Aspekte angeht.
Naja, seht das mal als nen 800-Post Special an, obwohl ich das Tutorial so oder so machen wollte, war jetzt mehr oder weniger Zufall.
Nachwort:
Ich hoffe, dass ich allen, die noch Probleme beim Arbeiten mit Tabellen hatten, weiterhelfen konnte. Da dies so ziemlich mein erstes Tutorial war könnten meine Erklärwege nicht gerade optimal gewesen sein.
Ich bitte daher um Feedback im Bereich "Erklärqualität" von den angehenden Questern und um Verbesserungen von den "Profis" was fehlende Aspekte angeht.
Naja, seht das mal als nen 800-Post Special an, obwohl ich das Tutorial so oder so machen wollte, war jetzt mehr oder weniger Zufall.