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:

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:

Günther, April 2006
PeterW, April 2006