Scripting

8  Scripting

Das Scripting-Kapitel ist in Form eines Tutoriums gefasst, bei dem nicht bei Adam und Eva angefangen wird. Auch wird das Thema nicht in allen Feinheiten vorgestellt. Das würde den Sinn eines Tutoriums verfehlen. Ich bin leider nur Autodidakt und daher im Fachvokabular eines Informatikers nicht firm. Letztendlich sollte mein Wissen jedoch ausreichen, Laien das Admin Mod Scripting näher zu bringen.

Für das Schreiben von Plugins (oder Skripts) unter Admin Mod empfiehlt es sich, bereits Grundkenntnisse in einer Programmiersprache zu besitzen. Dabei genügen bereits Kenntnisse in Basic oder PHP, C++ Kenntnisse wären ideal. Das Wissen, wie ein HL-Server funktioniert, ist jedoch die wichtigste Voraussetzung!

Die verwendete Skriptsprache heißt Small (inzwischen Pawn genannt)1 und bietet gegenüber C++ nur eingeschränkte Möglichkeiten der Programmierung. Gerade deshalb wurde sie gewählt, da der Anwender maximal in der Lage ist, den HL-Server abstürzen zu lassen, nicht aber das gesamte Betriebssystem.

Zunächst sollen die Konventionen und der Syntax von Small vorgestellt werden. C++ Anhänger werden sich vermutlich wie zu Hause fühlen.

 8.1  Syntax
 8.2  Datentypen, Variablen und Konstanten
 8.3  Operatoren
 8.4  Verzweigungen
 8.5  Schleifen
 8.6  Direktiven
  8.6.1  include
  8.6.2  define
  8.6.3  if, elseif, else und endif
 8.7  Funktionen und Events
  8.7.1  Beispiele für Events von Admin Mod
 8.8  Tutorial
  8.8.1  Basis
  8.8.2  Befehle registrieren
  8.8.3  Auf say reagieren
  8.8.4  Spielerconnect abfangen
  8.8.5  Timer verwenden
  8.8.6  Vote ausführen
  8.8.7  Vault-File nutzen
  8.8.8  LogD verwenden
  8.8.9  Menüs nutzen
 8.9  Includes
  8.9.1  admin.inc
  8.9.2  adminlib.inc
  8.9.3  console.inc
  8.9.4  core.inc
  8.9.5  fixed.inc
  8.9.6  math.inc
  8.9.7  plugin.inc
  8.9.8  string.inc
 8.10  Funktionsreferenz
  8.10.1  access
  8.10.2  auth
  8.10.3  ban
  8.10.4  censor_words
  8.10.5  centersay
  8.10.6  centersayex
  8.10.7  changelevel
  8.10.8  ChangeMap
  8.10.9  check_auth
  8.10.10  check_immunity
  8.10.11  check_param
  8.10.12  check_user
  8.10.13  check_words
  8.10.14  clamp
  8.10.15  consgreet
  8.10.16  convert_string
  8.10.17  currentmap
  8.10.18  cvar_exists
  8.10.19  deletefile
  8.10.20  deleteproperty
  8.10.21  directmessage
  8.10.22  distance
  8.10.23  exec
  8.10.24  execclient
  8.10.25  execclient_all
  8.10.26  execute_command
  8.10.27  existproperty
  8.10.28  fileexists
  8.10.29  filesize
  8.10.30  fixed:f_abs
  8.10.31  fixed:f_arccos
  8.10.32  fixed:f_arccot
  8.10.33  fixed:f_arcosh
  8.10.34  fixed:f_arcoth
  8.10.35  fixed:f_arcsin
  8.10.36  fixed:f_arctan
  8.10.37  fixed:f_arctan_help
  8.10.38  fixed:f_arsinh
  8.10.39  fixed:f_artanh
  8.10.40  fixed:f_cos
  8.10.41  fixed:f_cosh
  8.10.42  fixed:f_cot
  8.10.43  fixed:f_coth
  8.10.44  fixed:f_degtorad
  8.10.45  fixed:f_euler
  8.10.46  fixed:f_faculty
  8.10.47  fixed:f_ln
  8.10.48  fixed:f_log10
  8.10.49  fixed:f_logab
  8.10.50  fixed:f_max
  8.10.51  fixed:f_min
  8.10.52  fixed:f_pi
  8.10.53  fixed:f_power
  8.10.54  fixed:f_powere
  8.10.55  fixed:f_radtodeg
  8.10.56  fixed:f_sin
  8.10.57  fixed:f_sinh
  8.10.58  fixed:f_sqrt
  8.10.59  fixed:f_tan
  8.10.60  fixed:f_tanh
  8.10.61  fixed:fdiv
  8.10.62  fixed:ffract
  8.10.63  fixed:fixed
  8.10.64  fixed:fixedstr
  8.10.65  fixed:fmul
  8.10.66  fixed:strtofix
  8.10.67  fixtostr
  8.10.68  format_command
  8.10.69  fround
  8.10.70  funcidx
  8.10.71  get_serverinfo
  8.10.72  get_timer
  8.10.73  get_userArmor
  8.10.74  get_userAuthID
  8.10.75  get_userFrags
  8.10.76  get_userHealth
  8.10.77  get_userindex
  8.10.78  get_userinfo
  8.10.79  get_userIP
  8.10.80  get_username
  8.10.81  get_userorigin
  8.10.82  get_userSessionID
  8.10.83  get_userTeam
  8.10.84  get_userWONID
  8.10.85  get_vaultdata
  8.10.86  get_vaultnumdata
  8.10.87  getarg
  8.10.88  getchar
  8.10.89  getproperty
  8.10.90  getstring
  8.10.91  getstrvar
  8.10.92  gettarget
  8.10.93  getteamcount
  8.10.94  getvalue
  8.10.95  getvar
  8.10.96  glow
  8.10.97  godmode
  8.10.98  heapspace
  8.10.99  help
  8.10.100  index
  8.10.101  kick
  8.10.102  kill_timer
  8.10.103  list_maps
  8.10.104  listspawn
  8.10.105  log
  8.10.106  log_command
  8.10.107  look_in_dir
  8.10.108  maptime
  8.10.109  matherror
  8.10.110  max
  8.10.111  maxplayercount
  8.10.112  menu
  8.10.113  message
  8.10.114  messageex
  8.10.115  min
  8.10.116  motd
  8.10.117  movespawn
  8.10.118  nextmap
  8.10.119  noclip
  8.10.120  numargs
  8.10.121  numtostr
  8.10.122  playercount
  8.10.123  playerinfo
  8.10.124  playsound
  8.10.125  plugin_checkcommand
  8.10.126  plugin_command
  8.10.127  plugin_connect
  8.10.128  plugin_disconnect
  8.10.129  plugin_exec
  8.10.130  plugin_info
  8.10.131  plugin_init
  8.10.132  plugin_message
  8.10.133  plugin_registercmd
  8.10.134  plugin_registerhelp
  8.10.135  plugin_registerinfo
  8.10.136  pointto
  8.10.137  print
  8.10.138  printf
  8.10.139  rainbow
  8.10.140  random
  8.10.141  readfile
  8.10.142  reject_message
  8.10.143  reload
  8.10.144  removespawn
  8.10.145  resetfile
  8.10.146  rindex
  8.10.147  say
  8.10.148  say_command
  8.10.149  selfmessage
  8.10.150  servertime
  8.10.151  set_serverinfo
  8.10.152  set_timer
  8.10.153  set_vaultdata
  8.10.154  set_vaultnumdata
  8.10.155  setarg
  8.10.156  setproperty
  8.10.157  setstrvar
  8.10.158  slap
  8.10.159  slay
  8.10.160  snprintf
  8.10.161  spawn
  8.10.162  speakto
  8.10.163  strbreak
  8.10.164  strcasecmp
  8.10.165  strcasestr
  8.10.166  strcasestrx
  8.10.167  strcat
  8.10.168  strchr
  8.10.169  strcmp
  8.10.170  strcount
  8.10.171  strcpy
  8.10.172  strcspn
  8.10.173  streq
  8.10.174  strgsep
  8.10.175  strgsplit
  8.10.176  strgtok
  8.10.177  strgtokrest
  8.10.178  strinit
  8.10.179  strlen
  8.10.180  strmatch
  8.10.181  strncasecmp
  8.10.182  strncat
  8.10.183  strncmp
  8.10.184  strncpy
  8.10.185  strpack
  8.10.186  strrchr
  8.10.187  strsep
  8.10.188  strsplit
  8.10.189  strspn
  8.10.190  strstr
  8.10.191  strstripquotes
  8.10.192  strstrx
  8.10.193  strsubst
  8.10.194  strtok
  8.10.195  strtokrest
  8.10.196  strtonum
  8.10.197  strtrim
  8.10.198  strunpack
  8.10.199  swapchars
  8.10.200  systemtime
  8.10.201  teleport
  8.10.202  timeleft
  8.10.203  tolower
  8.10.204  toupper
  8.10.205  typesay
  8.10.206  unban
  8.10.207  userlist
  8.10.208  valid_map
  8.10.209  valid_mapex
  8.10.210  version
  8.10.211  vote
  8.10.212  vote_allowed
  8.10.213  writefile
 8.11  Compiler Fehler und Warnungen
 8.12  Runtime Fehler
 8.13  LogD Events
 8.14  Properties in Small

8.1  Syntax

Die Syntax Smalls lässt sich am Besten anhand eines „Hallo Welt“ Codes erklären:
1 #include <core>  
2 #include <string>  
3 #include <admin>  
4 #include <adminlib>  
5  
6 new VERSION[]= "1.0";  
7  
8 public plugin_init() {  
9    plugin_registerinfo("Hallo Welt Plugin","Hallo Welt!",VERSION);  
10    say("Hallo Welt!");  
11  
12    return PLUGIN_CONTINUE;  
13 }

Die Funktion plugin_init wird beim Starten des Plugins ausgeführt (entspricht der main() Funktion von C++). Die Funktion muss öffentlich bekannt sein (public) und sollte PLUGIN_CONTINUE zurückgeben. Der Beginn und das Ende von Verzweigungen, Schleifen, usw. wird durch geschweifte Klammern kenntlich gemacht. Funktionen müssen durch ein Semikolon abgeschlossen werden. Includes und Deklarationen werden mittels Hashes (#) kenntlich gemacht. Außerdem ist zu beachten, dass Small Groß- und Kleinschreibung unterscheidet.

8.2  Datentypen, Variablen und Konstanten

Small wird als „typenlose“ Programmiersprache bezeichnet. Der einzige, direkt unterstützte Datentyp ist 32-bit signed Integer (-2147483648 bis +2147483647).

Variablen werden in der Regel über die „new“-Anweisung deklariert. Man kann sie „global“ definieren, wenn sie im Skript außerhalb der Funktionen deklariert werden oder „lokal“ innerhalb ein Funktion.

new iZahl1;
new iZahl2 = 1;

Man kann die Variable ohne Zuweisung erstellen und diese im Code nachholen oder, wie im zweiten Beispiel gezeigt, direkt zuweisen.

Lokale Variablen gelten nur für die Funktion, in der sie erstellt wurden und werden nach Abschluss der Ausführung selbiger wieder gelöscht. Daher findet man hin und wieder auch statt „new“ „static“ bei der Deklarierung, da hier der Variableninhalt erhalten bleibt. Eine andere Möglichkeit den Variableninhalt zu behalten und ihn zudem allen Funktionen gleichzeitig zur Verfügung zu stellen, besteht in der Definition globaler Variablen. Dabei muss die Variable außerhalb der Funktionen definiert werden. Meist findet man diese am Kopf des Plugins wieder, damit sie den nachfolgenden Funktionen bekannt sind.

Zahlen können auch in bis zu zweidimensionalen Feldern verwendet werden.

new aFeld[2][2];
aFeld[1][0] = 5;
aFeld[1][1] = 3;

Eine einmal festgelegte Feldgröße kann während der Laufzeit nicht geändert werden. Man sollte vorausschauend programmieren und die Feldgröße ausreichend dimensionieren.

Die 1 und die 0 sieht Small neben den üblichen Rechnungen insbesondere in Vergleichen auch als Boolean-Wert „Wahr“ bzw. „Falsch“ an.

Konstanten werden stets am Kopf des Plugins definiert. Die Definition sieht etwa folgendermaßen aus:

#define MAX_TEST_LENGTH 100

Dies ist eine compilerspezifische Anweisung und muss damit nicht mit einem Semikolon abgeschlossen werden. Der Compiler ersetzt im Beispiel alle MAX_TEST_LENGTH beim Compilieren durch 100. Eine Feldvariable kann also auch so definiert werden:

new Variable[MAX_TEST_LENGTH];

Das mag auf den ersten Blick etwas umständlich erscheinen. Hat man jedoch mehrere dieser Felder, kann man die Größe aller bequem über die Konstantendefinition ändern. Darüber hinaus erhöht es die Lesbarkeit des Programmcodes.

Alternativ kann man Konstanten auch mit einem vorangestellten „const“ definieren:

const cVariable = 1

Strings werden in Feldern abgespeichert, wobei jeder Buchstabe eine Zahl in einer Zelle des Arrays ist. Das Feld zum zugehörigen Text muss immer um eine Zelle größer als die Länge des Texts angesetzt werden, da Small in die letzte Zelle ein „^0“ setzt, um das Ende des Strings festzulegen.

new Text[200]=“Hallo Welt!”;
new Text[]=“Hallo Welt!”;

Man kann wie gezeigt auch auf die Deklaration einer Feldgröße verzichten. Die Feldgröße beträgt in diesem Fall jedoch nur die Länge von „Hallo Welt!“ + 1 (12) und kann auch nicht während der Laufzeit vergrößert werden.

Neben dem Pseudo-Datentyp String gibt es den Typ der Festkommazahlen (Fixed). Die Festkommazahlen haben in Admin Mod einen Zahlenbereich von -2147482 bis +2147482 mit 3 Nachkommastellen. Festkommazahlen werden folgendermaßen deklariert:

new fixed:fPI = 3.142;

Die Information „fixed:“ weist den Compiler an, die Zahl als Festkommazahl zu betrachten.

Zu guter Letzt kann man auch Enums definieren. Dabei werden Begriffe einer aufsteigenden Zahlenreihe zugeordnet. Man kann sie zur besseren Lesbarkeit des Codes einsetzen.

enum tks{tk=0,victim};

Das „=0“ bedeutet, dass bei Null angefangen wird zu zählen. Jeder weitere Option bekommt einen um eins erhöhten Wert.

8.3  Operatoren

Es stehen folgende Rechenoperatoren zur Verfügung:

+ Addieren
- Subtrahieren
* Multiplizieren
/ Dividieren
& Bit-Shift-Aktionen

Auch existieren die üblichen Vereinfachungen aus anderen Sprachen.

i++; entspricht i=i+1;
i+=j; entspricht i=i+j;

Vorsicht! Nicht auf Zellen von Feldern anwenden. a[1]++; z.B. führt auf Grund eines Compilerbugs im schlimmsten Fall zum Absturz des HL-Servers!

Eine Besonderheit sind die Festkommazahlen. Während das Addieren und Subtrahieren noch identisch ausgeführt wird, gibt es für das Multiplizieren und Dividieren spezielle Funktionen (fmul und fdiv). Über die Grundrechenarten hinausgehende Rechenfunktionen bzw. -operatoren zu Festkommazahlen sind der math.inc zu entnehmen.

Es gibt darüber hinaus auch logische Operatoren, die insbesondere in Verzweigungen eingesetzt werden:

! Nicht
&& Und
|| Oder

8.4  Verzweigungen

Es gibt in Small zwei Verzweigungen, „if“ und „switch“. Die If-Verzweigung kann durch „else if“ und/oder „else“ erweitert werden.
1 vergleich(i){  
2    new j=0;  
3  
4    if (i = 1){  
5       j = 2;  
6    }  
7    else if (i = 2 || i = 3) {  
8       j = 5;  
9    }  
10    else {  
11       j = 1;  
12    }  
13  
14    return j;  
15 }

Die Vergleiche wurde zur besseren Lesbarkeit in runde Klammern gesetzt. Dies ist nicht notwendig, aber zu empfehlen. Für Konstrukte dieser Art sollte man aus Übersichtlichkeitsgründen aber eher auf die Switch-Verzweigung ausweichen. Das obige Beispiel sieht dann folgendermaßen aus:
1 vergleich(i){  
2    new j = 0;  
3  
4    switch(i){  
5       case 1:{  
6          j = 2;  
7       }  
8       case 2,3:{  
9          j = 5;  
10       }  
11       default:{  
12          j = 1;  
13       }  
14    }  
15  
16    return j;  
17 }

Switch-Verzweigungen können nur Zahlen jedoch keine Strings vergleichen.

8.5  Schleifen

Small hat 3 verschiedene Schleifen implementiert, „for“, „while“ und „do ... while“. In Admin Mod werden vorzugsweise For-Schleifen eingesetzt, da auf Grund der festgelegten Feldgröße auch die Schleifenlänge bereits vorab festgelegt werden kann.
1 schleife(){  
2    new j = 0;  
3  
4    for (i=0;i<=5;i++){  
5       j = j + i;  
6    }  
7  
8    return j  
9 }

In diesem Fall läuft die Schleife von 0 bis 5, wobei i um eins bei jedem Schritt erhöht wird. Will man die Schleife abbrechen, z.B. wenn j 10 überschreitet, muss man mit der break-Anweisung arbeiten.
1 schleife(){  
2    new j = 0;  
3  
4    for (i=0;i<=5;i++){  
5       if (j >= 10){  
6          break;  
7       }  
8       j = j + i;  
9    }  
10  
11    return j  
12 }

In diesem Fall bricht die For-Schleife komplett ab, und der Wert j wird zurückgegeben. Statt „break“ kann auch „continue“ verwendet werden.
6          continue;

Mit „continue“ wird direkt der nächste Durchlauf der Schleife initiiert, ohne dass die noch ausstehenden Rechnungen (hier: j = j + i;) durchgeführt werden.

Die gleiche Schleife kann auch mit „while“ und „do ... while“ durchgeführt werden, wobei beachtet werden muss, dass „do ... while“ mindestens einmal ausgeführt wird, da der Vergleich erst am Ende der Schleife durchgeführt wird.
1 schleife(){  
2    new j = 0;  
3  
4    do i++ while (j >= 10){  
5       j = j + i;  
6    }  
7  
8    return j  
9 }

Und hier auch ein Beispiel mit while:
1 schleife(){  
2    new j = 0;  
3  
4    while (j >= 10) i++{  
5       j = j + i;  
6    }  
7  
8    return j  
9 }

8.6  Direktiven

Direktiven sind Anweisungen an den Compiler, die nur zur Laufzeit des Compilers und nicht während der Laufzeit des Plugins berücksichtigt werden. Es sollen an dieser Stelle nur die gebräuchlisten Direktiven in Admin Mod beschrieben werden.

8.6.1  include

#include Include-Datei oder <Include-Datei>

Mit der Include-Direktive wird eine Include-Datei mit seinen Funktionen in den Quellcode eingebunden. Der Dateiname muss mit „.inc“ enden. Diese Endung darf jedoch nicht in der Direktive auftauchen. Ist der Dateiname in Klammern, wird die Include-Datei im Includes-Verzeichnis gesucht, während sie ohne die Klammern im gleichen Verzeichnis wie die Quelldatei erwartet wird.

8.6.2  define

#define KONSTANTENNAME Zahl

Mit dieser Direktive werden, wie bereits im Kapitel „Datentypen, Variablen und Konstanten“ beschrieben, Konstanten festgelegt.

8.6.3  if, elseif, else und endif

1 #define TEST 1  
2 #if Test == 1  
3    Small-Code 1  
4 #elseif Test&#