Datentypen
C4Script unterstützt die folgenden Datentypen für Variablen, Parameter und Rückgabewerte:
Typname |
Voller Name |
Variableninhalt |
Beispiel |
int |
Integer |
Eine ganze Zahl im Bereich von -2.147.483.648 bis +2.147.483.647. |
42 |
bool |
Boolean |
"wahr" (Wert true ) oder "falsch" (Wert false ). Wird von vielen Kontrollstrukturen wie if und while als Parameter erwartet. |
true |
id |
Definitions-ID |
ID einer Objektdefinition (siehe Objektdefinitionen) |
CLNK |
string |
Zeichenkette |
Ein beliebiger Text. Ein einzelnes Zeichen des Strings als int lässt sich mit GetChar extrahieren. Einzelne Zeichen eines Strings können als Ein-Zeichen-Strings mit "string"[index] extrahiert werden. Ändern von Strings ist damit nicht möglich. Ein negativer Index wird als Index vom String-Ende aus angesehen. |
"Dies ist ein Text!" |
object |
Objektzeiger |
Verweis auf ein im Spiel existierendes Objekt. Hat keine direkte Darstellung. Siehe z.B. FindObject().
Zugriff auf lokale Variablen ist mit obj["name"] oder obj.name , letzteres bei aktiviertem #strict 3 , möglich. |
- |
array |
Feld |
Ein Typ, der eine Reihe weiterer durchnummerierter Variablen enthält, deren Anzahl mit GetLength abgefragt werden kann, und die mit array[index] abgerufen werden können. Ab CR. |
[0,42,CLNK] |
map |
Map |
Ein Typ, der zu mehreren Schlüssel beliebigen Typs je eine Variable abspeichern kann. Mithilfe von GetKeys und GetValues können die gesetzten Schlüssel bzw. Werte als Array ermittelt werden. Zugriff auf den Wert mit bestimmten Schlüssel erfolgt mit map[key] . Zugriff auf Werte mit einem fest bestimmten String-Schlüssel der nur Identifier-Zeichen beinhaltet kann auch mit map.key erfolgen. Ab LC [334], nur mit #strict 3 oder höher. |
{ X: 10, Y: 50 } |
Außerdem gibt es noch zwei spezielle Typen:
-
any
: Der Typ ist nicht bekannt oder egal. "nil" hat immer diesen Typ.
-
&
: Der Wert ist eine Referenz - z.B. auf eine Variable. Er verhält sich genau wie der Zielwert, kann aber gesetzt werden (z.B. mit dem Operator "=
"). Siehe auch Referenzparameter.
Arrays
Arrays können entweder direkt durch
[Ausdruck 1, Ausdruck 2, ...]
oder
CreateArray() erstellt werden. Sie werden bei Zugriff auf ein Element gegebenenfalls automatisch verlängert, jedoch ist es schneller, das Array gleich mit der benötigten Länge zu erstellen. Wird ein Array einer Variablen zugewiesen oder einer Funktion übergeben, bekommt diese Variable eine eigene Kopie des Arrays. Das eigentliche Kopieren wird aber erst ausgeführt, wenn es nötig ist. Wenn das Array einer Funktion zum Ändern übergeben werden soll, muss ein Referenzparameter verwendet werden.
Zugriff auf ein Element i
eines Arrays a
erfolgt über a[i]
. Dabei entspricht i=0
dem ersten Element.
Elemente am Ende eines Arrays können mit a[] = wert;
am Ende angehängt werden.
Beispiel 1
func ArraySum(array a)
{
var l = GetLength(a);
var result = 0;
for (var i = 0; i < l; ++i)
{
result += a[i];
}
return (result);
}
Diese Funktion summiert alle Elemente eines Arrays.
Beispiel 2
func RandomID()
{
var a = [CLNK, WIPF, BIRD, HUT1];
return (a[Random(4)]);
}
Diese Funktion wählt zufällig aus einer der vier ids aus und gibt diese zurück.
Maps
Maps heißen in anderen Programmiersprachen auch Hashes oder assoziative Arrays.
Maps sind nur verfügbar, wenn das Script
#strict 3 oder höher ist.
Maps können direkt mit
{ Schlüssel 1 = Ausdruck 1, Schlüssel 2 = Ausdruck 2, "Schlüssel 3" = "Ausdruck 3, [Schlüsselausdruck] = Ausdruck 4, ... }
erstellt werden.
Zur einfacheren zukünftigen Weiterbearbeitung ist es erlaubt, auch nach dem letzten Schlüssel-Wert-Paar ein Komma stehen zu lassen.
Eine leere Map wird mit
{}
erstellt.
Falls der Schlüssel Leerzeichen oder andere in Identifiern nicht erlaubte Zeichen beinhalten soll, muss er wie ein richtiger String in "" (Anführungszeichen) stehen, ansonsten sind die Anführungszeichen optional. Um das Ergebnis eines Ausdrucks oder einen Wert der kein String ist als Schlüssel zu verwenden, kann ein Ausdruck in
[]
stehen (siehe Beispiel).
Zum Abfragen und Setzen von Werten wird die Syntax map[key]
verwendet.
Für String-Schlüssel die fest sind und nur Identifier-Zeichen beinhalten kann auch über map.key
(ohne Anführungszeichen), statt map["key"]
zugegriffen werden.
Um einen Schlüssel aus einer Map zu löschen muss der Wert auf nil
gesetzt werden.
Wird eine Map einer Variablen zugewiesen oder einer Funktion übergeben, bekommt diese Variable eine eigene Kopie der Map. Das eigentliche Kopieren wird aber erst ausgeführt, wenn es nötig ist. Wenn die Map einer Funktion zum Ändern übergeben werden soll, muss ein Referenzparameter verwendet werden.
Mithilfe einer speziellen Form von
for-Schleife können die Schlüssel-Wert-Paare einer Map durchiteriert werden.
Mit
GetKeys und
GetValues können die gesetzten Schlüssel bzw. Werte einer Map als Array ermittelt werden.
Maps sind intern mithilfe eines Hashes implementiert. Um aber die Synchronisation im Netzwerkmodus sicherzustellen, wird zusätzlich die Einfügereihenfolge der Schlüssel gespeichert.
Die Reihenfolge der Werte in den zurückgegebenen Arrays von GetValues und GetKeys und die Iterierreihenfolge entsprechen deshalb der Einfügereihenfolge.
Mit Einfügereihenfolge ist hier gemeint, mit welcher Reihenfolge ein Schlüssel, eventuell nach Löschen des Schlüssels, das erste mal in der Map gesetzt wird.
Achtung
Wird ein Objekt direkt als Schlüssel verwendet und das Objekt wird währenddessen gelöscht, so wird der zugehörige Wert aus der Map entfernt.
Wird hingegen ein Objekt beliebig verschachtelt in einer Map oder einem Array verwendet und wird währenddessen gelöscht, kann auf den darunter gespeicherten Wert nicht mehr zugegriffen werden. Löschen dieses Wertes ist ebenfalls nicht mehr möglich. Nur durch neu setzen der ganzen Map kann ein derartiger Zustand beseitigt werden.
Beispiel 1
func MapPlayground(int plr)
{
var clonk = GetCursor(plr);
var m = {
Position = { X = GetX(clonk), Y = GetY(clonk) },
Name = GetName(clonk),
Contents = {},
"Player's Name" = GetPlayerName(plr),
};
Log("Der Clonk von %s heißt %s und befindet sich bei Position %v.", m["Player's Name"], m.Name, m.Position);
var flint = clonk->CreateContents(FLNT);
var rock = clonk->CreateContents(ROCK);
m.Contents[0] = flint;
m.Contents[1] = rock;
m.Contents[FLNT] = flint;
m.Contents[ROCK] = rock;
Log("%v", m);
m.Contents[FLNT] = nil;
Log("Contents: %v", m.Contents);
}
Diese Funktion demonstriert den Umgang mit Maps.
Beispiel 2
#strict 3
local discounts;
func Initialize()
{
discounts = {
// [discount in %, pieces left], could also be maps, but would be more writing effort :p
[CLNK] = [10, 3],
[EFLN] = [25, 4],
[WOOD] = [50, 50],
[GetID(GetCursor(0))] = [5, 1],
// ...
};
}
func GetDiscount(id ID)
{
return discounts[ID]?[0] || 0;
}
func SoldItem(id ID)
{
if(discounts[ID])
{
if(--discounts[ID][1] == 0)
{
discounts[ID] = nil;
}
}
}
Teil eines Objektscripts, das mithilfe einer Map für eine begrenzte Anzahl diverser Artikel Rabatte verwaltet.
Konvertierung
Aus folgender Tabelle kann entnommen werden, welche Typen automatisch konvertiert werden und wo ein Fehler ausgelöst wird:
nach -> |
int |
bool |
id |
object |
string |
array |
map |
int |
OK |
OK |
if <= 9999 |
Error |
Error |
Error |
Error |
bool |
OK |
OK |
Error |
Error |
Error |
Error |
Error |
id |
#strict |
OK |
OK |
Error |
Error |
Error |
Error |
object |
#strict |
OK |
Error |
OK |
Error |
Error |
Error |
string |
#strict |
OK |
Error |
Error |
OK |
Error |
Error |
array |
Error |
OK |
Error |
Error |
Error |
OK |
Error |
map |
Error |
OK |
Error |
Error |
Error |
Error |
OK |
Erklärung der Tabelle:
- Wo #strict steht, wird nur ein Fehler ausgelöst wenn der Script #strict ist. Hierbei handelt es sich um "ungefährliche" aber sinnlose Konvertierungen, die nur in einigen "trickreichen" Scripts zur Anwendung kamen.
- Die Konvertierung int zu id ist nur erlaubt, wenn die Zahl größer gleich 0 und kleiner gleich 9999 ist. Auf diese Weise werden auch IDs, die nur aus Zahlen bestehen, unterstützt (z.B. 0001)
- Konvertierung nach bool ist generell erlaubt. Sie ergibt für jeden Wert außer 0
true
.
Günther, April 2006
PeterW, April 2006