Portal-Zone Gothic-Zone Gothic II-Zone Gothic 3-Zone Gothic 4-Zone Modifikationen-Zone Download-Zone Foren-Zone RPG-Zone Almanach-Zone Spirit of Gothic
English Deutsch
World of Gothic



Inhalt:

  1. Einführung
  2. Beschreibung der Syntax
  3. Kommentare
  4. Anweisungen
  5. Ausdrücke
    • Operatoren
    • Ausdruck
  6. Typen, Variablen und Konstanten
    • Elementare Typen
    • C++ und DAEDALUS
    • Variablen und Konstanten
    • Bezugsrahmen: global, lokal
  7. Zuweisungen
  8. Funktionen
    • Definition
    • Parameterübergabe
    • Funktionsaufrufe
  9. Klassen, Schablonen und Instanzen
    • Klassen
    • Prototypen
    • Instanzen
  10. Kontrollstrukturen
  11. Dynamische Variablen
  12. Wichtige Unterschiede zu C++
  13. Schleifen

1. Einführung

Die von uns entworfene Skript-Sprache wird im folgenden Text mit DAEDALUS bezeichnet. Das eigentliche Spielprogramm, das den Skript-Code interpretiert wird in der Regel mit "C++"-Code bezeichnet.

Dieses Kapitel beschreibt die Skriptsprache DAEDALUS. Beim Design inspirierten uns vor allem die Programmiersprache "C", die Skript-Sprache "Quake-C" und zum Teil Pascal. DAEDALUS weicht jedoch in manchen Bereichen weit von diesen ab.

Einsatzgebiete von DAEDALUS

  • Dialoge / Informationen
  • NSC - AI
  • Aufträge
  • Text-Pool
  • NPCs (Prototypen und Instanzen)
  • Gegenstände (Prototypen und Instanzen)
  • Implementation von Konzept-Regeln
  • "Event-Programme" (Realisierung komplexer logischer Rätsel)
  • Deklaration von Sound-Resourcen
  • Deklaration von Grafik-Resourcen (auch mit Ani-Information)

2. Beschreibung der Syntax

Es gibt 5 Arten von sogenannten Token: Bezeichner (identifier), Schlüsselwörter (keywords), Literale (literals), Operatoren (operators) und andere Trennzeichen. Aus diesen Token ist ein Skript zusammengesetzt. Leerzeichen, Zeilenumbrüche, Kommentare etc. werden ignoriert. Die Länge von Bezeichnern ist nicht beschränkt.

Bezeichner sind Namen für Variablen, Konstanten, Instanzen, Prototypen, Klassen und Funktionen. Ein Bezeichner ist eine Folge von Buchstaben und Ziffern. Das erste Zeichen muß ein Buchstabe sein. Danach sind Buchstaben, die Ziffern 0 bis 9, sowie der Unterstrich erlaubt.

Schlüsselwörter sind:


class       const       else        float      func         if

instance    int         other       prototype  return       self

string      this        var         void       while

Literale sind Zeichenketten ("Hallo") und konstante Werte (453). Operatoren werden weiter unten eingeführt.

In dieser Referenz beschreibe ich die Skriptsprache formal in Anlehnung an das Buch "Die C++ Programmiersprache" von Bjarne Stroustrup. Syntaktische Bezeichner werden in Kursivschrift dargestellt.

Die Skriptsprache ist nicht case-sensitive (anders als in C).

Wir empfehlen aber folgende Konventionen für die Namensgebung von Bezeichnern: (Sei "dng" die Kurzkennung für ein Modul "dungeon.D")

  • Funktion: Dng_MoveLift();
  • Variable: dng_buttonsPressed;
  • Konstante: DNG_NUM_TRIES;

3. Kommentare

Die Zeichenfolge /* beginnt einen Kommentar, der mit der Zeichenfolge */ beendet wird. Die Zeichenfolge // beginnt einen Kommentar, der bis zum Ende der Zeile geht. Innerhalb eines Kommentars haben die Zeichenfolgen // und /*, sowie */ nach einem Zeilenkommentar keine weitere Bedeutung und werden wie andere Zeichen behandelt.

Das Kommentarkonzept wurde aus C++ übernommen

4. Anweisungen

Anweisungen (statements) sind Deklarationen, Befehle oder auch ein Block von Anweisungen:


statement

  vardecl

  constdecl

assignment	

  if-statement

  return-statement

statement-block


Beispiel: 

statement:        door_open();

statement-list:   door_open();  opened = TRUE;

statement-block:  { door_open(); opened = TRUE; }

5. Ausdrücke

Operatoren

Ein Operator "berechnet" aus einem oder zwei Werten den Ergebnis-Wert. Ein Vergleichsoperator sowie ein boolscher Operator liefert den Integer-Wert 1, falls der Ausdruck wahr ist, sonst 0. Bit-Operatoren manipulieren Variablen auf Bit-Ebene. Die Operatorenpriorität wurde von C++ übernommen.


operator:

  calc-op

  cmp-op

  bool-op

  bit-op



a) Operatoren



calc-op: 

  +   Addition

  -   Subtraktion

  *   Multiplikation

  /   Division

  %   Restdivision (Modulo)





c) Vergleichsoperatoren



cmp-op: 

  <   kleiner

  <=  kleiner gleich

  >   größer

  >=  größer gleich

  ==  Gleichheit

  !=  Ungleichheit



d) Boolesche Operatoren



bool-op:

  !   nicht

  &&  und

  ||  oder





e) Bitweise Operatoren



bit-op:

  &   and

  |   or



f) Vorzeichen



vorzeichen:

  +   positiv

  -   negativ

Ausdruck

Ausdrücke werden mit den oben dargestellten Operatoren wie in C üblich gebildet. Hier werden nur Beispiele von Ausdrücken gezeigt.


expression:

  literal

  calc-expressoin

  cmp-expression

  bool-expression

  bit-expression



a) Ausdruck



expression:

  -x1 + x2

  x1 * (x2 + x3)

  (x2 % 2) * x3



b) Vergleiche (compares)



cmp- expression: 

  x1 < x2

  x1 == x2



c) Boolesche Ausdrücke



bool- expression:

  x1 && x2

  x1 || x2

    (x0)



Ein numerischer Wert gilt als wahr, falls er nicht gleich Null ist.



d) Bitweise Manipulationen



bit- expression:

  x1 | 5;

  x1 & 4;

6. Typen, Variablen und Konstanten

Es existieren zwei Arten von Typen: elementare Typen und Klassen. Es können keine weiteren Typen definiert werden, wie in C/C++ üblich. Klassen haben eine direkte Entsprechung im C-Code der Engine. Variablen einer Klasse sind die sogenannten Instanzen.

Elementare Typen


float

int

string

Entsprechen den Typen in C/C++

Weiterhin können int- und string-arrays gebildet werden:


VAR INT attribute[MAX_ATTRIBUTES];

VAR STRING names[MAX_NAMES];

Es können nur eindimensionale Arrays erstellt werden. Die einzelnen Elemente der Felder werden wie in C++ gewohnt angesprochen, es können dafür aber nur Konstanten als Index benutzt werden:


attribute[1] = 0;

Das erste Element beginnt mit dem Index Null.

C++ und DAEDALUS

Funktionen, Variablen und Konstanten, auf die sowohl im C++-Code als auch in DAEDALUS zugegriffen werden muß, werden mindestens in DAEDALUS deklariert. Dazu dient das Schlüsselwort extern. Variablen und Konstanten werden zusätzlich auch definiert, d.h. ihnen werden Werte zugewiesen.

Variablen und Konstanten

Eine Variablendeklaration muß durch das Schlüsselwort var eingeleitet werden. Dies gilt für jede einzelne Deklaration, nicht, wie in PASCAL, für einen ganzen Block. Auflistungen von Variablen aber (wie in C) möglich:


vardecl:

  var  type  identifier [,identifier]opt  [...]opt;



Beispiel:



korrekt:

  var int wert1, wert2, wert3;

  var string frage, antwort;

  var int wert;



falsch:

  int value;

Eine Konstantendefinition muß durch das Schlüsselwort const eingeleitet werden:


constsdef:

  const type  identifier = expression;


Beispiel:

  const type identifier[x] = { expression, expression, expression };

Bezugsrahmen: global, lokal

Es existieren zwei verschiedene Bezugsrahmen für Variablen und Konstanten:

  • Eine außerhalb jedes Blockes deklarierte Variable oder Konstante ist global verfügbar: Sie ist nach ihrer Deklaration im gesamten folgenden Skriptteil gültig.
  • Eine innerhalb eines Blockes deklarierte Variable/Konstante ist lokal im Bezug auf den äußersten Block.

Beispiele:



var int count;



func void Test()

{ var int x; var int y; }

Die variable count ist im Skript global verfügbar. Die Variablen x und y haben wie in C/C++ - den gleichen lokalen Bezugsrahmen: die Funktion Test().

7. Zuweisungen


assignment:

  identifier = expression; // einfache Zuweisung



Beispiel:

  var int x1;

  x1 = 40;	

  x1 = x1 / 2;

  x1 = x1* 3;	

8. Funktionen

Definition

Funktionsdefinitionen werden mit dem Schlüsselwort func eingeleitet.


func-def:

  func type identifier ( vardecl1opt , ... , vardecl8opt ) statement-block



Beispiel:



  func int UsingSchild(var int x1, var string s1)

  {

    [...]

  };

Parameterübergabe

Die Länge der Parameterliste ist unbegrenzt, sollte allerdings aus Speicherplatzgründen möglichst gering gehalten werden. Parameter werden call-by-value übergeben, liefern also keinen Wert zurück. Arrays sind als Übergabeparameter nicht erlaubt.

Funktionsaufrufe

Funktionen werden wie in C++ üblich aufgerufen. Also mit ihrem Bezeichner sowie einer zwingend notwendigen Parameterklammer.

9. Klassen, Schablonen und Instanzen

Klassen

Die Klassendeklarationen beschreiben exakt die Datenstrukturen der Engine. Sie sind also nicht beliebig im Skript erweiterbar, sondern direkt mit der Engine verknüpft.


classdecl:

  class  classname  (base-classname)opt  declaration-block



Beispiel:



class Creature (Vob)

{

  // attributes

  var string  name;

  var int     hitpoints;

  var int     hp_max;

  // actions

  var funcref birth;

  var funcref death;

};

Die Attribute erhalten Standardwerte:

  • Variablen vom Typ int enthalten den Wert 0
  • Strings den leeren String ""
  • Pointertypen referenzieren NULL.

Prototypen

Mit dem Schlüsselwort prototype ist es möglich, sogenannte Prototypen zu erzeugen, die andere Standardwerte haben:


prototype-def:

	prototype class-identifier  identifier  statement-block

Ein Prototyp kann man als eine "abgeleitete" Klasse ansehen, bei der NUR die Standardwerte geändert wurden. Oder als eine Instanz der Klasse, die nur als Vorlage für weitere Instanzen dient. Die Definition der Standardwerte findet im statement-block satt.

Es findet eine Trennung zwischen Klassendeklaration (class), welche die exakte Struktur der Engine-internen Klasse widerspiegelt, und der Klassendefinition (prototype)statt.

Instanzen

Instanzen von Klassen oder Prototypen stellen deren konkrete Repräsentationen dar. Die Instanz einer Klasse Material ist ein bestimmtes Material mit all seinen Eigenschaften.


instance-def:

	instance class-identifier  identifier  statement-block

	instance instance-identifier prototype-identifier statement-block

Der statement-block einer Instanz-Definition dient zur Definition der Variablen, die zu der Klasse gehören. Dabei behalten nicht definierte Attribute oder Aktionen ihren Standardwert. Es sind aber auch alle weiteren Anweisungen erlaubt, soweit sie in irgendeiner Weise Sinn machen.


Kleines (fiktives) Beispiel für Item/Schild/Holzschild



class Item(Vob)

{

  // attributes

  var int damage;

  var int attack;

  var string description;

  // actions

  var funcref use;

};

  



prototype SchildProtoType (Item)

{

  damage = 0;

  attack = 0;

  descriptions = "";

  // actions

  use = UsingSchild();

};



instance HolzSchild1 (SchildProtoType)

{

  // attributes

  description = "Ein recht erbärmliches Holzschild";

};

10. Kontrollstrukturen

Verzweigung: if-then-else

Die if-Abfrage wurde aus C++ übernommen. Zu beachten sind nur die eingeschränkten Möglichkeiten von Ausdrücken. Außerdem wird immer ein statement-block erwartet.


if-statement:

  if ( expression ) statement-block

  if ( expression ) statement-block else statement-block



falsch:   if (x<4) SoundPlay(ID_sound_roar);

richtig:  if (x<4) { SoundPlay(ID_sound_roar); };

Funktionswert-Rückgabe: return

In Funktionen, die einen Wert zurückliefern, wird wie in C++ die return-Anweisung verwendet:


return-statement:

    return ( expression );

11. Dynamische Variablen

Einige Variablen werden beim Aufruf einer Funktion dynamisch gesetzt und verweisen dann z.B. in einem Dialog auf die Instanz des NPCs (self) und seinen Gesprächspartner(other). Weiterhin wird es Build-In-Funktionen geben, die einen Zugriff auf andere VOBs ermöglicht.

Zur Unterstützung dieses Konzeptes werden einige globale Variablen deklariert und im Spielverlauf dynamisch gesetzt, so daß diese in Funktionen abgefragt werden können. Die Variablen sind momentan folgende:




VAR C_NPC self;

VAR C_NPC other;

VAR C_NPC victim;

VAR C_NPC hero;

VAR C_NPC item;

12. Wichtige Unterschiede zu C++

Hier sollen nur in Stichworten einige Fallstricke aufgezeigt werden, die aus den Unterschieden zu C++ entstehen. Wo C++ auch einzelne Anweisungen erlaubt, muß in DAEDALUS ein Anweisungsblock stehen. Dies betrifft if-Statement.


Beispiel:



if (x<4) { SoundPlay(); };



13. Schleifen

Daedalus kennt keine Schleifen-Konstrukte, aber man kann mittels Rekursion dennoch eine Iteration durchführen.

FOR-Schleife


Beispiel:



var int Zaehler;



func void TestFunc()

{

	// ... Beliebiger Code



	// Aufruf der Schleife

	Zaehler = 0;

	ForLoop();



	// ... Beliebiger Code

};



func void ForLoop()

{

	// ... Code der Schleife



	// Um eins erhöhen

	Zaehler = Zaehler + 1;



	// Schleife läuft von 0 bis 19

	if (Zaehler >= 20)

	{

		ForLoop();

	};

};

WHILE-Schleife


Beispiel:



func void TestFunc2()

{

	// ... Beliebiger Code



	// Aufruf der Schleife 

	WhileLoop();



	// ... Beliebiger Code

};



func void WhileLoop()

{

	// Kontrolle, ob While-Bedingung noch erfüllt

	if (...)

	{

		// ... Beliebiger Code



		// Und noch einmal

		WhileLoop();	

	};

};

 

Basiert auf der G1MDK-Dokumentation. Copyright © Piranha Bytes




Username:
Passwort:
angemeldet bleiben:

Fanart