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)
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.
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.
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.
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
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.
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 }
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.
#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.
#define KONSTANTENNAME Zahl
Mit dieser Direktive werden, wie bereits im Kapitel „Datentypen, Variablen und Konstanten“
beschrieben, Konstanten festgelegt.
1 #define TEST 1
2 #if Test == 1
3 Small-Code 1
4 #elseif Test == 2
5 Small-Code 2
6 #else
7 Small-Code 3
8 #endif
Man kann damit über eine Konstante definieren, welchen Code der Compiler für das Plugin
nutzen soll. Ich würde das als Poor-Man’s-Option bezeichnen. Für den Enduser sollte man die
Option üblicherweise zur Laufzeit änderbar machen (z.B. mit einem Admin Mod
Befehl).
Funktionen sind ein wesentlicher Bestandteil Admin Mods. Funktionen können aus anderen
(einfacheren) Funktionen erstellt werden. Viele Funktionen werden jedoch auch von Admin
Mod zur Verfügung gestellt. Sie werden in den sogenannten Includes vermerkt und stehen
nach Einbindung selbiger für die Programmierung zur Verfügung.
Es gibt aber auch Funktionen, die bei bestimmten Events (z.B. Serverbefehl oder
Spielerconnect) automatisch ausgeführt werden. Dabei kann die zugehörige Reaktion
programmiert werden. Dies sind:
Auf die Anwendung von Events wird im Tutorial näher eingegangen.
Vorgegebenen Funktionen ist ein „stock“ (in Small erstellte Funktion) bzw. „native“ (von
Admin Mod zur Verfügung gestellte Funktion) vorangestellt. Sie werden nur vom Compiler
eingebunden, wenn sie auch benötigt werden. Beide Schlüsselwörter sind nur von
Interesse, wenn man eigene Includes erstellen möchte. Funktionen, die auf Events
reagieren, muss ein „public“ vorangestellt werden, da anderenfalls die Funktion zur
Laufzeit nicht gefunden wird. Alle weiteren Funktionen benötigen keine besondere
Kennzeichnung.
Zunächst startet Metamod Admin Mod. Admin Mod lädt seine Plugins in der Reihenfolge, wie
sie in der plugin.ini stehen und führt jeweils die plugin_init Funktion aus. Die plugin_init
sollte so programmiert sein, dass Pluginname, Beschreibung, Version und ggf. zu
registrierende Befehle an Admin Mod zurückgegeben werden. Admin Mod weiß nun, welche
Befehle es an das Plugin weiterleiten soll.
Kommt ein Spieler auf den Server, ruft Admin Mod die Funktion plugin_connect auf (sofern
im Plugin definiert) und führt die angegebenen Aktionen durch.
Wird ein im Plugin definierter Befehl aufgerufen, wird die zugehörige Funktion
aufgerufen, die (sofern der Accesslevel des Spielers ausreicht) ausgeführt wird. Das
Plugin meldet zurück, ob Admin Mod noch andere Plugins abfragen soll (return
PLUGIN_CONTINUE), oder ob Admin Mod die weiteren Plugins übergehen soll (return
PLUGIN_HANDLED).
In diesem Tutorial wird auf das Grundgerüst aufgebaut und die wichtigsten Funktionen und
Events sowie deren Anwendung vorgestellt.
Small bzw. Admin Mod erwarten ein gewisses Grundgerüst, damit sie das compilierte Plugin
akzeptieren.
1 #include <core>
2 #include <string>
3 #include <admin>
4 #include <adminlib>
5
6 public plugin_init() {
7 plugin_registerinfo("Testplugin","Ein Testplugin!","1.0");
8 return PLUGIN_CONTINUE;
9 }
Zunächst werden die Includes eingebunden.
1 #include <core>
2 #include <string>
3 #include <admin>
4 #include <adminlib>
Man sollte nie zu sparsam bei den Includes sein. Theoretisch kann man alle vorhandenen
Includes einbinden, da nur das vom Compiler berücksichtigt wird, was er auch benötigt. Das
Plugin wird durch mehr Includes nicht größer.
Damit das Plugin überhaupt etwas tut, wird das Event plugin_init eingebunden.
Überlicherweise geschieht dies am Ende des Quellcodes.
6 public plugin_init() {
7 plugin_registerinfo("Testplugin","Das Plugin macht noch nichts!","1.0");
8 return PLUGIN_CONTINUE;
9 }
Das Event plugin_init wird nach dem HL-Serverstart bzw. nach jedem Mapwechsel von
Admin Mod aufgerufen. Damit Admin Mod erkennt, dass das Plugin plugin_init
implementiert hat, muss das Event mit „public“ bekanntgegeben werden. In Zeile 8 wird
Admin Mod zurückgemeldet, dass die Abarbeitung des Events erfolgreich beendet
ist.
In Zeile 7 wird Admin Mod mitgeteilt (plugin_registerinfo), wie das Plugin heißt, was das
Plugin macht, und um welche Version des Plugins es sich handelt.
7 plugin_registerinfo("Testplugin","Das Plugin macht noch nichts!","1.0");
Die angebenen Informationen haben keine Funktion in Admin Mod, sondern dienen nur zur
späteren Darstellung in der Console, wenn man sich alle geladenen Plugins auflisten
lässt.
Dieses Plugin registriert sich also lediglich bei Admin Mod. Weitergehende Aktionen werden
nicht ausgeführt.
Meist möchte man, dass Admin Mod auf einen bestimmten Befehl eine Aktion ausführt. Dafür
muss zunächst bei Admin Mod ein Befehl registriert werden. Üblicherweise macht
man dies im Event plugin_init. Zum einfacheren Verständnis erweitern wir das
Grundplugin.
1 #include <core>
2 #include <string>
3 #include <admin>
4 #include <adminlib>
5
6 public test(HLCommand,HLData,HLUserName,UserIndex) {
7 new sData[MAX_DATA_LENGTH];
8
9 convert_string(HLData,sData,MAX_DATA_LENGTH);
10 userlist(sData);
11
12 return PLUGIN_HANDLED;
13 }
14
15 public plugin_init() {
16 plugin_registerinfo("Testplugin","Ein Testplugin!","1.0");
17 plugin_registercmd("admin_test","test",ACCESS_ALL,"Userlist anzeigen");
18
19 return PLUGIN_CONTINUE;
20 }
Das Plugin wurde um einen Befehl „plugin_registercmd„ erweitert, der einen Befehl bei
Admin Mod registriert.
17 plugin_registercmd("admin_test","test",ACCESS_ALL,"Userlist anzeigen");
Dabei ist admin_test der Befehl, auf den Admin Mod später reagiert und die Funktion „test“
ausführt, die ebenfalls hinzugefügt wurde. Zugriff auf den Befehl haben alle Spieler
(ACCESS_ALL). Die vordefinierten Accesslevel sind der admin.inc zu entnehmen oder selbst
zu definieren. Zu letzt gibt man einen Hilfetext an, der bei der Ausführung von „admin_help“
ausgegeben wird.
Damit Admin Mod auch eine Aktion ausführen kann, wenn das Event „admin_test“
ausgeführt wird, muss auch die Funktion „test“ definiert werden.
6 public test(HLCommand,HLData,HLUserName,UserIndex) {
7 new sData[MAX_DATA_LENGTH];
8
9 convert_string(HLData,sData,MAX_DATA_LENGTH);
10 userlist(sData);
11
12 return PLUGIN_HANDLED;
13 }
Damit Admin Mod die Funktion auch aufrufen kann, muss ein „public“ vorangestellt werden.
Die übergebenen Variablen bei einem Befehlsevent sind vorgegeben. „HLCommand“ bringt
den die Funktion aufrufenden Befehl (hier: „admin_test“). Es können aber auch verschiedene
Befehle die gleiche Funktion aufrufen. Dann kann man mit Verzweigungen unterschiedlichen
Code ausführen lassen. In „HLData“ stehen die Befehlsoptionen und in „HLUserName“ der
Spielername, der den Befehl aufgerufen hat. „UserIndex“ wiederum gibt an, in welchem Slot
der aufrufenden Spieler auf dem Server ist.
Die HL-Variablen müssen, sofern sie genutzt werden sollen, erst in Small-Strings konvertiert
werden. Nur der UserIndex liegt bereits als Zahl vor.
9 convert_string(HLData,sData,MAX_DATA_LENGTH);
Nach Ausführung der convert_string Funktion liegt alles, was nach „admin_test“ eingegeben
wurde, in der Variable sData vor. Nun wird die Funktion „userlist“ ausgeführt.
10 userlist(sData);
Ist sData leer, werden alle Spieler auf dem Server mit einigen Zusatzinformationen in der
Console ausgegeben. Ist z.B. „admin_test a“ eingegeben worden, ist sData = „a“. Es werden
dann alle Spieler ausgegeben, deren Name ein „a“ enthält.
Die Funktion wird nicht wie bei der plugin_init durch PLUGIN_CONTINUE beendet.
13 return PLUGIN_HANDLED;
Admin Mod geht der Reihe nach durch die Plugins und überprüft, ob der gesuchte Befehl
einem Plugin gehört. Erst wenn es kein passendes Plugin findet, gibt es den Befehl an den
Server weiter. Würde man hier PLUGIN_CONTINUE angeben, so würde Admin Mod in den
nachfolgenden Plugins weitersuchen und den Befehl anschließend an den Server weitergeben.
Der Server kennt den Befehl aber nicht und würde mit „Unknown command“ antworten,
obwohl die Admin Mod Aktion durchgeführt wurde.
Mit PLUGIN_HANDLED verhindert man, dass Admin Mod weitersucht bzw. den Befehl an
den Server weitergibt.
Die gleiche Funktionalität kann man auch über den Chat erreichen, wenngleich die Ausgabe
weiterhin in der Console stattfindet. Es soll also bei der Eingabe von „userlist“ im Chat, die
Spielerliste in der Console ausgegeben werden.
1 #include <core>
2 #include <string>
3 #include <admin>
4 #include <adminlib>
5
6 public test(HLCommand,HLData,HLUserName,UserIndex) {
7 new sData[MAX_DATA_LENGTH];
8 new sCommand[MAX_COMMAND_LENGTH];
9
10 convert_string(HLData,sData,MAX_DATA_LENGTH);
11 strsep(sData," ",sCommand,MAX_COMMAND_LENGTH,sData,MAX_DATA_LENGTH);
12
13 if (streq(sCommand, "userlist") == 1) {
14 userlist(sData);
15 return PLUGIN_HANDLED;
16 }
17
18 return PLUGIN_CONTINUE;
19 }
20
21 public plugin_init() {
22 plugin_registerinfo("Testplugin","Ein Testplugin!","1.0");
23 plugin_registercmd("say","test",ACCESS_ALL);
24 plugin_registercmd("say_team","test",ACCESS_ALL);
25 plugin_registerhelp("say",ACCESS_ALL,"userlist <Muster>: Userlist anzeigen");
26
27 return PLUGIN_CONTINUE;
28 }
Es wurde „admin_test“ durch „say“ (freier Chat) und „say_team“ (Teamchat)
ersetzt.
23 plugin_registercmd("say","test",ACCESS_ALL);
24 plugin_registercmd("say_team","test",ACCESS_ALL);
25 plugin_registerhelp("say",ACCESS_ALL,"userlist <Muster>: Userlist anzeigen");
Da auch andere Plugins „say“ und „say_team“ reagieren können, verzichtet man beim
Registrieren auf einen Hilfetext. Stattdessen legt man mit plugin_registerhelp einen
Hilfetext fest. Auf diese Weise können auch Unteroptionen genauer beschrieben
werden. Eine Funktion muss nicht angegeben werden, da der Befehl nur den Hilfetext
festlegt.
Auch die Funktion „test“ hat sich verändert.
6 public test(HLCommand,HLData,HLUserName,UserIndex) {
7 new sData[MAX_DATA_LENGTH];
8 new sCommand[MAX_COMMAND_LENGTH];
9
10 convert_string(HLData,sData,MAX_DATA_LENGTH);
11 strsep(sData," ",sCommand,MAX_COMMAND_LENGTH,sData,MAX_DATA_LENGTH);
12
13 if (streq(sCommand, "userlist") == 1) {
14 userlist(sData);
15 return PLUGIN_HANDLED;
16 }
17
18 return PLUGIN_CONTINUE;
19 }
Da der Befehl immer „say“ oder „say_team“ lautet, muss man erst sData trennen, um an den
eigentlichen Befehl heranzukommen.
11 strsep(sData," ",sCommand,MAX_COMMAND_LENGTH,sData,MAX_DATA_LENGTH);
Mit „strsep“ wird der String sData am ersten Leerzeichen in sCommand und sData getrennt
(sData wird dabei überschrieben). Man muss jeweils auch die maximale Länge des Strings
angeben.
Anschließend wird der Befehl in sCommand überprüft, ob er mit „userlist“ identisch ist
(streq). Wenn dies der Fall ist, wird die Spielerliste ausgegeben und nicht weitergesucht
(PLUGIN_HANDLED). Das bedeutet auch, dass die Nachricht nicht im Chat ankommt.
Admin Mod gibt die Nachricht nicht an den Server weiter. Ist sCommand nicht mit „userlist“
identisch, gibt Admin Mod die Nachricht an das nächste Plugin oder an den Server
weiter. Sofern also kein anderes Plugin die Weiterleitung blockiert, landet sie beim
Serverchat.
Es könnte von Interesse sein, eine Aktion durchzuführen, wenn ein Spieler den Server betritt.
Im folgenden Plugin soll in den Logfiles gespeichert werden, welcher Slot beim Connect besetzt
wird.
1 #include <core>
2 #include <string>
3 #include <admin>
4 #include <adminlib>
5
6 public plugin_connect(HLUserName, HLIP, UserIndex) {
7 new sText[MAX_TEXT_LENGTH];
8
9 snprintf(sText,MAX_TEXT_LENGTH,"Slot %d ist besetzt",UserIndex);
10 log(sText);
11
12 return PLUGIN_CONTINUE;
13 }
14
15 public plugin_init() {
16 plugin_registerinfo("Testplugin","Ein Testplugin!","1.0");
17 return PLUGIN_CONTINUE;
18 }
Der Event „plugin_connect“ muss wie alle Events mit „public“ öffentlich gemacht
werden.
6 public plugin_connect(HLUserName, HLIP, UserIndex) {
Wie beim Serverbefehl-Event gibt es auch für den Spielerbeitritt festgelegte Variablen, die
ausgewertet werden können. Leider ist der Event in der Regel zu früh, so dass weder
Spielername noch seine IP zurückgegeben werden. Nur der Slot (UserIndex) lässt sich
zuverlässig nutzen.
Aus dem „UserIndex“ soll ein ausagekräfter Text für die Logdateien gemacht werden.
9 snprintf(sText,MAX_TEXT_LENGTH,"Slot %d ist besetzt",UserIndex);
10 log(sText);
Mit der Funktion „snprintf“ lassen sich einfach Strings und Zahlen in einen bestehenden String
implementieren. Neben dem String, in den der Text gespeichert werden soll, muss auch die
maximale Länge des Strings angegeben werden. Der folgende String beinhaltet neben dem
eigentlichen Text auch einen Platzhalter für den Slot (%d steht für eine Zahl, %s steht für
einen String). Abschließend müssen in der Reihenfolge des Auftauchens im Text
die Variablen angegeben werden. Das Ergebnis sieht dann z.B. folgendermaßen
aus:
Slot 9 ist besetzt
Als letztes wird der Text mittels der Funktion „log“ in die Logdatei eingetragen. Dies passiert
bei jedem Spieler, der auf den Server kommt.
Oftmals möchte man bestimmte Aktionen in regelmäßigen Abständen wiederholen lassen.
Admin Mod bietet dafür Timer an, die eine Aktion ein- oder mehrmals durchführen können.
Es wird damit bei jedem Auslösen des Timers ein Event erzeugt, das mit einer vordefinierten
Funktion (wie bei einem Serverbefehl) verarbeitet werden kann.
Das folgende Plugin zeigt in roter, zentrierter Schrift alle 60 Sekunden den Begriff „Admin
Mod“ an.
1 #include <core>
2 #include <string>
3 #include <admin>
4 #include <adminlib>
5
6 public say_stuff(Timer,Repeat,HLName,HLParam) {
7 centersay("Admin Mod",10,255,0,0);
8 }
9
10 public plugin_init() {
11 plugin_registerinfo("Testplugin","Ein Testplugin!","1.0");
12 set_timer("say_stuff", 60, 99999,"");
13 return PLUGIN_CONTINUE;
14 }
In plugin_init wird zunächst mittels set_timer ein Timer gestartet.
12 set_timer("say_stuff", 60, 99999,"");
Es muss angegeben werden, welche Funktion („say_stuff“) beim Ablauf des Timers
aufgerufen werden soll, wie lang der Timer jeweils laufen soll (60 Sekunden), wie lang er
wiederholt werden soll. Die 99999 hat eine Sonderstellung und steht für unendlich viele
Wiederholungen. Admin Mod wird nun versuchen alle 60 Sekunden die Funktion „say_stuff“
auszuführen.
Diese Funktion muss wiederum öffentlich (public) gemacht werden.
6 public say_stuff(Timer,Repeat,HLName,HLParam) {
7 centersay("Admin Mod",10,255,0,0);
8 }
Da es sich um eine Funktion handelt, die von einem Timer aufgerufen wurde, gibt es wieder
festgelegte Variable. Zunächst wird die Nummer des Timers zurückgegeben. Diese erhält
man auch als Rückgabe von set_timer. Weiterhin wird übergeben, um die wievielte
Wiederholung es sich handelt. „HLName“ gibt den Spieler zurück, der den Timer
ausgelöst hat. Hier ist der Timer automatisch ausgelöst worden, es wird kein Name
zurückgegeben. Wird der Timer aus einem Serverbefehlevent ausgeführt, wird der Spieler
zurückgegeben, der den Befehl aufgerufen hat. Zuletzt wird ein beliebiger String
„HLParam“ übergeben, der in set_timer festgelegt wurde. Im Beispiel wurde nichts
angegeben. „HLName“ und „HLParam“ müssen mit convert_string konvertiert
werden.
Die centersay Funktion sorgt für die eigentlich Darstellung des Texts „Admin Mod“.
Dieser muss natürlich angegeben werden. Weiterhin benötigt die Funktion die Dauer
der Darstellung (10 Sekunden) und die Farbe in RGB-Farben (jede Farbe 0 bis
255).
Das nächste Beispiel soll zeigen, wie man einen Vote mit Admin Mod durchführt. In diesem
Plugin soll die Mehrheit der Spieler entscheiden, ob in einem Counter-Strike Spiel die Map neu
gestartet werden soll.
1 #include <core>
2 #include <string>
3 #include <admin>
4 #include <adminlib>
5
6 public test(HLCommand,HLData,HLUserName,UserIndex) {
7 if (vote_allowed()!=1) {
8 selfmessage( "Vote noch nicht erlaubt.");
9 return PLUGIN_HANDLED;
10 }
11
12 vote("Restart?","Ja","Nein","HandleVsay","");
13 return PLUGIN_HANDLED;
14 }
15
16 public HandleVsay(WinningOption,HLData,VoteCount,UserCount) {
17 if (WinningOption == 1) {
18 say("Mehrheit wollte Restart");
19 setstrvar("sv_restart","1");
20 }
21 else {
22 say("Mehrheit wollte keinen Restart");
23 }
24 }
25
26 public plugin_init() {
27 plugin_registerinfo("Testplugin","Ein Testplugin!","1.0");
28 plugin_registercmd("admin_test","test",ACCESS_ALL,"Restartvote");
29 return PLUGIN_CONTINUE;
30 }
Um den Vote ausführen zu können, braucht man ein Event. Es wurde zu diesem Zweck ein
Befehl eingefügt (Zeile 28), der auf die „test“ Funktion verweist. Natürlich lässt sich der Vote
auch mit anderen Events koppeln.
Zunächst muss überprüft werden, ob ein Vote überhaupt erlaubt ist.
7 if (vote_allowed()!=1) {
8 selfmessage( "Vote noch nicht erlaubt.");
9 return PLUGIN_HANDLED;
10 }
Die Funktion vote_allowed überprüft, ob die in der Variablen vote_freq festgelegte Zeit seit
dem letzten Vote bzw. des Mapchanges abgelaufen ist. Ist dies nicht der Fall, wird dem
Aufrufenden ein Nachricht in die Console gesendet (selfmessage) und anschließend die
Ausführung mit „return“ abgebrochen. Diese Routine verhindert, dass der unzulässige Aufruf
von vote zu einer Fehlermeldung führt.
Anschließend wird der Vote mit der Funktion vote gestartet. Vote benötigt eine Frage, bis zu
neun Optionen, die aufzurufende Funktion und Zusatzdaten.
12 vote("Restart?","Ja","Nein","HandleVsay","");
Hier wird gefragt, ob ein Restart durchgeführt werden soll, es gibt zwei Optionen (Ja oder
Nein), die aufzurufende Funktion heißt „HandleVsay“ und es werden keine Zusatzdaten
übertragen. Es ist zu beachten, dass keine Vote-Dauer festgelegt werden kann. Hierzu zieht
Admin Mod die Variable amv_vote_duration heran. Auch die Schriftfarbe kann nicht
verändert werden (weiß).
Der Vote-Event wird mit Ablauf des Vote-Timers ausgelöst.
16 public HandleVsay(WinningOption,HLData,VoteCount,UserCount) {
17 if (WinningOption == 1) {
18 say("Mehrheit wollte Restart");
19 setstrvar("sv_restart","1");
20 }
21 else {
22 say("Mehrheit wollte keinen Restart");
23 }
24 }
Einige Variablen werden bei diesem Event mitgeliefert. „WinningOption“ gibt die Nummer
der Option an, die gewonnen hat. Dies wird über die Variable admin_vote_ratio
vorab festgelegt. „HLData“ gibt die Zusatzoptionen zurück, die hier nicht genutzt
wurden (muss konvertiert werden). Außerdem bekommt man die Anzahl der Stimmen,
die auf die Option gefallen sind (VoteCount) sowie die Gesamtzahl der Stimmen
(UserCount).
Die erste Option „Ja“ ist die „1“. Wenn Option 1 gewonnen hat, gibt Admin Mod im Chat aus
(say), dass sich die Mehrheit für einen Restart entschieden hat. Anschließend wird die Variable
„sv_restart“ auf 1 gesetzt (setstrvar), was mit einem Restart nach einer Sekunde
gleichzusetzen ist. Gewinnt Option 2 wird dies ebenfalls den Spielern mitgeteilt, aber keine
weitere Aktion ausgeführt. Ein „return“ ist hier nicht notwendig, da Admin Mod beim
Vote-Event keine Rückgabe benötigt.
Variablen lassen sich bequem in Plugins speichern. Die Inhalte gehen jedoch beim Mapwechsel
oder beim Abschalten des Servers verloren. Einige der Standardplugins dürfen sich über
Servervariablen glücklich schätzen, die für sie von Admin Mod erstellt wurden. Um
auch anderen Programmierern die Möglichkeit zu geben, Einstellungen dauerhaft
zu speichern, wurde die vault.ini geschaffen. Mit einigen wenigen Befehlen lassen
sich bequem Zahlen und Strings abspeichern. Man sollte diese Funktionen allen
Textdateispielereien vorziehen. Sie sind wesentlich schneller als die zum Lesen und Schreiben
von Textdateien.
Das folgende Beispiel schreibt einen zufälligen Wert zwischen 0 und 9 in einen Vault-Eintrag.
Es wird dabei die Funktion set_vaultnumdata nachgebaut.
1 #include <core>
2 #include <string>
3 #include <admin>
4 #include <adminlib>
5
6 public write_entry(HLCommand,HLData,HLUserName,UserIndex) {
7 new_set_vaultnumdata("TEST_ENTRY",random(9));
8 return PLUGIN_HANDLED;
9 }
10
11 new_set_vaultnumdata(sEntry[],iContent){
12 new sContent[MAX_DATA_LENGTH];
13 snprintf(sContent,MAX_DATA_LENGTH,"%d",iContent);
14 set_vaultdata(sEntry,sContent);
15 return PLUGIN_CONTINUE;
16 }
17
18 public plugin_init() {
19 plugin_registerinfo("Testplugin","Ein Testplugin!","1.0");
20 plugin_registercmd("admin_write","write_entry",ACCESS_ALL,"Schreibe Eintrag");
21 return PLUGIN_CONTINUE;
22 }
Auch in diesem Beispiel muss wieder ein Befehl registriert werden (Zeile 20). Um den
Quellcode transparenter zu machen, wurde der Nachbau der Funktion set_vaultnumdata in
eine interne Funktion ausgelagert.
11 new_set_vaultnumdata(sEntry[],iContent){
12 new sContent[MAX_DATA_LENGTH];
13 snprintf(sContent,MAX_DATA_LENGTH,"%d",iContent);
14 set_vaultdata(sEntry,sContent);
15 return PLUGIN_CONTINUE;
16 }
Die neue Funktion erwartet einen String (sEntry) und eine Zahl (iContent) als Eingabe. Die
Zahl iContent wird über die Funktion „snprintf“ in einen String umgewandelt. Man kann
selbstverständlich auch numtostr verwenden. Anschließend wird mit set_vaultdata der
Variablenname (sEntry) und sein Wert (sContent) in die vault.ini geschrieben. Pro forma
wurde ein PLUGIN_CONTINUE als Rückgabewert angegeben.
Es ist zu beachten, dass die Funktion nicht öffentlich ist. Sie hat kein „public“ vorangestellt.
Dies ist nicht notwendig, da sie ein integraler Bestandteil des Plugins ist, und nur von diesem
selbst aufgerufen wird.
Die neue Funktion „new_set_vaultnumdata“ wird aus „write_entry“ aufgerufen.
6 public write_entry(HLCommand,HLData,HLUserName,UserIndex) {
7 new_set_vaultnumdata("TEST_ENTRY",random(9));
8 return PLUGIN_HANDLED;
9 }
Als Eintrag wurde „TEST_ENTRY“ verwendet und eine weitere Funktion (random) direkt
eingebunden, die eine Zahl zwischen 0 und 9 ausgibt. Die direkte Einbindung funktioniert bei
allen Funktionen. Da Small aber nur Zahlen als direkten Rückgabewert verwendet, können auf
diese Art keine Strings eingebunden werden. Strings die übergeben wurden, sind jedoch
automatisch referenziert, d.h. Änderungen in der Child-Funktion werden automatisch an die
Parent-Funktion weitergeleitet. Bei Zahlen muss ein kaufmännisches Und voranstellt
werden.
new_set_vaultnumdata(sEntry[],&iContent){
In diesem Abschnitt soll beschrieben werden, wie die Admin Mod Events durch weitere
ergänzt werden können. Dazu ist das Metamod-Plugin LogD notwendig. Dieses Plugin erkennt
Damages in Counter-Strike und schreibt sie in den Chat.
1 #include <core>
2 #include <string>
3 #include <admin>
4 #include <adminlib>
5
6 #define ACCESS_CONSOLE 131072
7 #define MNL 33
8
9 public damages(HLCommand,HLData,HLUserName,UserIndex) {
10 new sData[MAX_DATA_LENGTH];
11 new sA[MNL];
12 new sV[MNL];
13 new sW[MNL];
14 new sD[MNL];
15
16 convert_string(HLData,sData,MAX_DATA_LENGTH);
17 strsep(sData," ",sA,MNL,sV,MNL,sW,MNL,sD,MNL,sData,MAX_DATA_LENGTH);
18 strsep(sData,"#",sData,MAX_DATA_LENGTH,sD,MNL);
19
20 playerinfo(strtonum(sA),sA,MNL);
21 playerinfo(strtonum(sV),sV,MNL);
22
23 snprintf(sData,MAX_DATA_LENGTH,"%s traf %s mit %s (-%s hp)",sA,sV,sW,sD);
24 say(sData);
25
26 return PLUGIN_HANDLED;
27 }
28
29 public plugin_init() {
30 plugin_registerinfo("Testplugin","Ein Testplugin!","1.0");
31 plugin_registercmd("test_damages","damages",ACCESS_CONSOLE);
32
33 exec("logd_reg 58 admin_command test_damages",1);
34 return PLUGIN_CONTINUE;
35 }
Das sieht im ersten Moment etwas komplexer aus. Die eigentliche Funktionsweise lässt sich
aber schon mittels der plugin_init erklären.
29 public plugin_init() {
30 plugin_registerinfo("Testplugin","Ein Testplugin!","1.0");
31 plugin_registercmd("test_damages","damages",ACCESS_CONSOLE);
32
33 exec("logd_reg 58 admin_command test_damages",1);
34 return PLUGIN_CONTINUE;
35 }
In Zeile 33 wird ein Serverbefehl abgesetzt. LogD wird mitgeteilt, dass es bei Event 58
(Damages) den Befehl „admin_command test_damages“ ausführen soll. Die „1“ bei der exec
sagt lediglich aus, dass die Ausführung der Eventregistrierung mitgelogged wird. Weitere
LogD-Events werden im Abschnitt 8.13 vorgestellt.
Damit Admin Mod auch auf den Serverbefehl reagiert, muss der Befehl „test_damages“ bei
Admin Mod registriert werden. Der Access Level „ACCESS_CONSOLE“ wurde
bewusst über die üblichen Access Level gesetzt (Zeile 6), da kein User diesen Befehl
manuell ausführen können darf. Aus dem gleichen Grund wurde auch der Hilfetext
weggelassen.
Zusammengefasst wird auf diese Art beim Zufügen von Schaden automatisch die Funktion
„damages“ ausgeführt.
Zwei Besonderheiten sind noch in diesem Plugin zu finden.
6 #define ACCESS_CONSOLE 131072
7 #define MNL 33
Es wird wie beschrieben ein neuer Access Level definiert. Alle Befehle, die von der
Serverconsole ausgeführt werden (z.B. über RCon oder anderen Plugins), haben alle
theoretischen Rechte. Normalerweise hat kein User den Access Level 131072. Damit wird
sichergestellt, dass kein User einen Pseudoevent absetzen kann. Allerdings ist ein solcher
Access Level nicht in der admin.inc definiert, so dass man dies selbst durchführen
muss.
Der zweite Eintrag ist ein Alias für MAX_NAME_LENGTH, der wegen Darstellungsgründen
für dieses Tutorial eingesetzt werden musste. Anderenfalls wäre die Zeile 17 zu lang geraten.
Das ist also normalerweise nicht notwendig.
Die Funktion „damages“ nimmt letztlich den von LogD gelieferten String auseinander und
setzt ihn neu zusammen.
9 public damages(HLCommand,HLData,HLUserName,UserIndex) {
10 new sData[MAX_DATA_LENGTH];
11 new sA[MNL];
12 new sV[MNL];
13 new sW[MNL];
14 new sD[MNL];
15
16 convert_string(HLData,sData,MAX_DATA_LENGTH);
17 strsep(sData," ",sA,MNL,sV,MNL,sW,MNL,sD,MNL,sData,MAX_DATA_LENGTH);
18 strsep(sD,"#",sData,MAX_DATA_LENGTH,sD,MNL);
19
20 playerinfo(strtonum(sA),sA,MNL);
21 playerinfo(strtonum(sV),sV,MNL);
22
23 snprintf(sData,MAX_DATA_LENGTH,"%s traf %s mit %s (-%s hp)",sA,sV,sW,sD);
24 say(sData);
25
26 return PLUGIN_HANDLED;
27 }
Für Damages sieht der String beispielhaft so aus:
3 1 p228 damage#28 damage_armor#12 health#72 armor#34.
Der String beginnt mit dem Userindex des Angreifers, gefolgt von dem des Opfers und der
genutzten Waffe. Anschließend kommt der Lebensschaden, der Rüstungsschaden, die
verbleibenden Lebenspunkte und die verbleibenden Rüstungspunkte des Opfers. Option und
Wert sind hier durch Hashes (#) getrennt. Für die Ausgabe werden in diesem Fall nur die
ersten vier Werte benötigt.
Zunächst wird der String an den ersten 4 Leerzeichen getrennt (Zeile 17). sData wird hier als
Abfalleimer wiederverwendet (der Restsring wird nicht benötigt). Anschließend wird sD am
Hash getrennt (Zeile 18). Auch hier ist sData wieder Abfalleimer verwendet. Auf diese
Weise spart man sich Speicher, da keine zusätzlichen Variablen definiert werden
müssen.
Aus den Userindizes sollen nun Namen ermittelt werden (playerinfo). Dazu müssen die Strings
aber zuvor in Zahlen umgewandelt werden strtonum.
Der String wird dann in Zeile 23 neu zusammengesetzt und könnte dann mit obigen LogD
String folgendermaßen aussehen:
Player(2) traf Player mit p228 (-28 hp)
Dieser Text wird abschließend in den Chat geschrieben.
Die Verwendung von Menüs muss unter Admin Mod als höhere Programmierkunst bezeichnet
werden. Es gibt diverse Fallstricke, die zu beachten sind. Gerade komplexe Menüstrukturen
bedingen ein hohes Abstraktionsvermögen. Auch kann man mit anderen Menüs kollidieren
(auch die von Half-Life; z.B. Teamauswahl oder Waffenkauf). Nicht jedes Plugin benötigt ein
Menü. Man sollte sich genau überlegen, ob man eines verwenden möchte. Üblicherweise
verdoppelt sich der Code. Außerdem muss der Serveradmin die Variable amv_enable_beta
um „menu1“ ergänzt haben.
Nachdem genügend Angst gesäht wurde, soll nun ein Beispiel folgen, dass eine simple
Verwendung des Menüs demonstrieren soll. Dem Spieler soll nach Eingabe von „admin_test“
in der Console ein Menü präsentiert werden, das ihn auswählen lässt, ob er einen Maprestart
nach 10, 5 oder 2 Sekunden durchführen möchte. Als letzte Auswahlmöglichkeit kann er das
Menü auch einfach schließen.
1 #include <core>
2 #include <console>
3 #include <string>
4 #include <plugin>
5 #include <admin>
6 #include <adminlib>
7
8 new giMenu[MAX_PLAYERS];
9
10 public test(HLCommand,HLData,HLUsername,UserIndex) {
11 new sUser[MAX_NAME_LENGTH];
12 convert_string(HLUsername,sUser,MAX_NAME_LENGTH);
13 new sMenu[MAX_DATA_LENGTH]="sv_restart?:^n1. 10s^n2. 5s^n3. 2s^n8. Close";
14 giMenu[UserIndex]=1;
15 menu(sUser,sMenu,135);
16 return PLUGIN_HANDLED;
17 }
18
19 public menuselect(HLCommand,HLData,HLUserName,UserIndex){
20 new sOption[MAX_DATA_LENGTH];
21 new iOption;
22 if(giMenu[UserIndex]){
23 convert_string(HLData,sOption,MAX_DATA_LENGTH);
24 iOption=strtonum(sOption);
25 switch(iOption){
26 case 1:{
27 setstrvar("sv_restart","10");
28 }
29 case 2:{
30 setstrvar("sv_restart","5");
31 }
32 case 3:{
33 setstrvar("sv_restart","2");
34 }
35 }
36 giMenu[UserIndex]=0;
37 return PLUGIN_HANDLED;
38 }
39 return PLUGIN_CONTINUE;
40 }
41
42 public plugin_disconnect(HLUserName,UserIndex){
43 giMenu[UserIndex]=0;
44 return PLUGIN_CONTINUE;
45 }
46
47 public plugin_connect(HLUserName,HLIP, UserIndex) {
48 giMenu[UserIndex]=0;
49 return PLUGIN_CONTINUE;
50 }
51
52 public plugin_init() {
53 plugin_registerinfo("Test","Testplugin","1.0");
54 plugin_registercmd("admin_test","test",ACCESS_CONFIG,"Ein Menue");
55 plugin_registercmd("menuselect","menuselect",ACCESS_ALL);
56
57 return PLUGIN_CONTINUE;
58 }
Zunächst soll wieder mit der plugin_init begonnen werden:
52 public plugin_init() {
53 plugin_registerinfo("Test","Testplugin","1.0");
54 plugin_registercmd("admin_test","test",ACCESS_CONFIG,"Ein Menue");
55 plugin_registercmd("menuselect","menuselect",ACCESS_ALL);
56
57 return PLUGIN_CONTINUE;
58 }
Es werden zwei Befehle registriert. Zum einen ist das der Befehl „admin_test“,
der die Menüauswahl öffnet. Damit nicht jeder ihn ausführen kann, wurde er nur
demjenigen zugreifbar gemacht, der Accesslevel 512 hat. Zum anderen wird der Befehl
„menuselect“ registriert, der für alle Menüauswahlen in Half-Life verwendet wird. Er darf
nicht eingeschränkt werden (ACCESS_ALL), da ansonsten selbst das Team nicht
auswählbar ist. Beide Registrierungen verweisen auf entsprechende Funktionen (test und
menuselect).
10 public test(HLCommand,HLData,HLUsername,UserIndex) {
11 new sUser[MAX_NAME_LENGTH];
12 convert_string(HLUsername,sUser,MAX_NAME_LENGTH);
13 new sMenu[MAX_DATA_LENGTH]="sv_restart?:^n1. 10s^n2. 5s^n3. 2s^n8. Close";
14 giMenu[UserIndex]=1;
15 menu(sUser,sMenu,135);
16 return PLUGIN_HANDLED;
17 }
Es wird der Username vom HL Format ins Small Format konvertiert. Anschließend wird
der Menütext mit einigen Umbrüchen erstellt, damit die Frage und die Optionen
jeweils in einer eigenen Zeile stehen. In Zeile 14 wird eine Zelle des globalen Feldes
giMenu auf 1 gesetzt. Der Zellenindex wird durch den Userindex definiert. Auf diese
Weise kann festgehalten werden, ob sich der jeweilige Spieler gerade in einem Menü
befindet. Das Feld giMenu wurde in Zeile 8 definiert und ist in allen Funktionen
gültig.
8 new giMenu[MAX_PLAYERS];
Schlussendlich wird nun beim aufrufenden Spieler ein Menü mit dem angegebenen Text
ausgegeben (Zeile 15, menu). Es wird dabei auch festgelegt, welche Menüauswahlen erlaubt
sind. Bei den Optionen 1, 2, 3 und 8 ergibt sich:
21-1 + 22-1 + 23-1 + 28-1 = 1 + 2 + 4 + 128 = 135
Genaueres darüber ist der Funktionsbeschreibung von menu zu entnehmen. Andere
Auswahlmöglichkeiten sind geblockt, während das Menü geöffnet ist.
Um die Menüauswahl auszuwerten, wird die Funktion menuselect benötigt.
19 public menuselect(HLCommand,HLData,HLUserName,UserIndex){
20 new sOption[MAX_DATA_LENGTH];
21 new iOption;
22 if(giMenu[UserIndex]){
23 convert_string(HLData,sOption,MAX_DATA_LENGTH);
24 iOption=strtonum(sOption);
25 switch(iOption){
26 case 1:{
27 setstrvar("sv_restart","10");
28 }
29 case 2:{
30 setstrvar("sv_restart","5");
31 }
32 case 3:{
33 setstrvar("sv_restart","2");
34 }
35 }
36 giMenu[UserIndex]=0;
37 return PLUGIN_HANDLED;
38 }
39 return PLUGIN_CONTINUE;
40 }
Wichtig zu beachten ist, dass diese Funktion durch alle Auswahlen ausgeführt wird. Daher
sollte der Code minimiert werden, der ausgeführt wird, wenn das eigene Plugin nicht gemeint
ist. Daher wird zunächst überprüft, ob die die Zelle des Feldes giMenu auf 1 gesetzt ist (Zeile
22), der Spieler sich also im eigenen Menü befindet. Anderenfalls wird der menuselect Befehl
durchgelassen. Hier ist auch das PLUGIN_CONTINUE am Ende der Funktion wichtig.
Ein PLUGIN_HANDLED würde die weitere Ausführung des menuselect Befehls
unterbinden.
Nachdem die Überprüfung positiv verlaufen ist, wird die übergebene Option HLData in
sOption konvertiert und anschließend in eine Ganzzahl umgewandelt. Die Switch-Verzweigung
verweist auf setstrvar Funktionen mit unterschiedlichen Werten für die Servervariable
sv_restart wie sie im Menütext angegeben waren. Wenn diese gesetzt werden, erfolgt ein
Restart nach der angegeben Anzahl an Sekunden. Entspricht iOption keiner Option, wird
dafür kein Code ausgeführt. Das Menü wird aber nach jedem menuselect automatisch
geschlossen. Die Angabe von der Option 8 schließt also nur das Menü.
Dem Feld giMenu muss noch mitgeteilt werden, dass der Spieler das Menü verlassen hat.
Daher wird die dem Spieler zugewiesene Zelle auf 0 gesetzt (Zeile 36). Die weitere Ausführung
von menuselect wird mit PLUGIN_HANDLED unterbunden, da das Menü abgearbeitet
wurde.
Es gibt Fälle, wo der Spieler das Spiel bei offenem Menü beendet. Es verbleibt eine 1 im Feld,
die derjenige erbt, der in den gleichen Slot kommt.
42 public plugin_disconnect(HLUserName,UserIndex){
43 giMenu[UserIndex]=0;
44 return PLUGIN_CONTINUE;
45 }
46
47 public plugin_connect(HLUserName,HLIP, UserIndex) {
48 giMenu[UserIndex]=0;
49 return PLUGIN_CONTINUE;
50 }
Aus diesem Grunde ist es notwendig, plugin_disconnect zu definieren, damit bei jedem
Disconnect die Zelle auf 0 gesetzt wird. Zur Sicherheit wird dies auch überlicherweise für
plugin_connect wiederholt.
Damit erhält man ein funktionsfähiges Menü. Es lässt sich das Prinzip aber auch beliebig
verkomplizieren. Untermenüs, zweite Seiten, Eingaben im Chat als Optionsparameter sind nur
einige wenige Beispiele, wie das Menüprinzip schnell große Ausmaße annimmt. Menüs sind
aber ein i-Tüpfelchen auf jedem Plugin, das viel Spielerbeteiligung benötigt.
Die Includes beinhalten alle von Admin Mod zur Verfügung gestellten Funktion, aber auch
solche, die erst aus anderen Funktion gebildet werden (z.B. in adminlib.inc oder math.inc. Die
Includes befinden sich im Verzeichnis „scripting/include“. Man kann sie wie auch
schon den Quellcode der Admin Mod Plugins mit jedem handelsüblichen Editor
öffnen.
Um Includes zu nutzen, müssen sie mit der include-Direktive in das Plugin eingebunden
werden.
Eine kurze Beschreibung zu den einzelnen Funktionen eines Includes kann manchmal auch als
Kommentar dem Quellcode der Includes selber entnommen werden. Die Beschreibung ist
jedoch relativ kurz.
Im Weiteren werden die einzelnen Includes kurz vorgestellt und die zugehörigen
Funktionen aufgelistet. Die Beschreibung und Beispiele zu einzelnen Funktionen sind der
Funktionsreferenz zu entnehmen.
Die admin.inc ist das Basis-Include, welches für alle Plugins benötigt wird. Dies liegt schon
allein daran, dass sie das Event plugin_init zur Verfügung stellt. Aber auch andere essentielle
Events und Funktionen werden hier definiert.
Weiterhin sind diverse Konstanten an dieser Stelle definiert (z.B. Access Level). Auch
augewählte Enums sind dort zu finden.
Es ist daher notwendig das Include in das eigene Plugin einzubinden. Eine Liste der
zur Verfügung gestellten Events und Funktionen ist der anschließenden Tabelle zu
entnehmen.
Das adminlib Include beinhaltet Funktionen, die nicht von Admin Mod selber zur Verfügung
gestellt werden. Vielmehr liegen diese Funktionen als Small-Code vor, der wiederum auf den
Basisfunktionen und -operatoren aufbaut. Die Admin Mod Programmierer banden diese
Funktionen ein, da sie häufig benötigt wurden jedoch nicht nativ über Admin Mod zur
Verfügung standen. Sie sind im Laufe der Zeit auch nicht in Admin Mod übernommen
worden.
Man wird dieses Include nicht immer benötigen, aber es ist zu empfehlen das Include stets
einzubinden. Funktionen wie numtostr oder max werden sehr häufig verwendet.
Das Include console ist in Admin Mod mehr oder weniger nutzlos. Die zugehörigen Funktionen
interagieren mit Betriebsystemconsole. Es werden Keyboard-Eingaben gelesen und Text
ausgegeben. Unter Umständen lassen sich diese Funktionen zu Debuggingzwecken
nutzen.
Es ist nicht nötig dieses Include einzubinden.
Das core Include beinhaltet Funktionen, die direkt (also nicht von Admin Mod) von Small zur
Verfügung gestellt werden.
Genutzt werden die Funktionen nur selten (z.B. clamp oder random), aber zur Sicherheit
sollte man auch dieses Include einbinden.
Das Include fixed stellt die Grundrechenarten für Festkommazahlen und einige
Konvertierungsfunktionen zur Verfügung.
Das Include wird nur dann benötigt, wenn man mit Festkommazahlen arbeiten oder
Funktionen aus dem math Include nutzen möchte.
Die Nutzung von Festkommazahlen ist eigentlich nur sinnvoll, wenn man auf Funktionen
zurückgreifen will, die über die einfachen Grundrechenarten hinausgehen. Mit Ganzzahlen
(Integer) ist man auf die Grundrechenarten beschränkt.
Da eine native Implementierung der Funktionen höherer Mathematik in Admin Mod nicht in
Aussicht gestellt wurde, entstand dieses Include, welches die Funktionen aus den
Grundrechenarten nachbildet. Das Include ist mehr oder weniger ein Proof of Concept, hatte
aber auch das Ziel z.B. Statistiken oder Distanzrechnungen in Admin Mod zu ermöglichen.
Bis dato ist kein Plugin bekannt, das dieses Include nutzt. Die Genauigkeit der
Berechnungen ist ausreichend genau bis mindestens zur zweiten Nachkommastelle (je nach
Funktion).
Wenn mit Festkommazahlen gerechnet werden soll, ist dieses Include wahrscheinlich
notwendig. Dann muss aber auch das fixed Include eingebunden werden.
Das Include plugin hat nur zwei selten verwendete Funktionen.
In der Regel muss dieses Include nicht eingebunden werden.
Das string Include beschäftigt sich mit Stringauswertungen und -manipulationen. Besonders
Funktionen wie snprintf machen das Include fast unentbehrlich.
Es ist sinnvoll dieses Include standardmäßig in das eigene Plugin aufzunehmen.
access( iAccess, sName[]= “” );
iAccess
Typ: Integer (0 - 2147483647)
sName[]= “”
Typ: String (33)
Mit der Funktion kann man den Accesslevel der Person abfragen, die entweder direkt die
Funktion im Plugin aufgerufen hat (sName braucht dann nicht angegegeben werden) oder der
Person, die man mit sName angibt. Man erhält einen Integer mit Wert 1 zurück, wenn die
Person den Rechtelevel iAccess besitzt und eine 0, wenn die Person diesen Rechtelevel nicht
besitzt.
Beispiel aus plugin_base (Funktion: admin_chat):
110 for(i=1; i<=maxplayers; i++) {
111 strinit(Name);
112 if(playerinfo(i,Name,MAX_NAME_LENGTH)==1) {
113 if(access(ACCESS_CHAT,Name)!=0) {
114 messageex(Name, Text, print_chat);
115 }
116 }
117 }
Es werden alle Playerslots abgefragt, ob ein Spieler vorhanden ist. Wenn ja, wird überprüft, ob
er den Rechtelevel (ACCESS_CHAT = 64) hat, um Nachrichten, die über admin_chat
abgesetzt wurden, lesen zu dürfen. Erst wenn Admin Mod dies auch bestätigt, wird die
Nachricht an den Spieler ausgegeben.
auth( sName[]= “” );
sName[]= “”
Typ: String (33)
Mit der Funktion auth kann man abfragen, ob eine Person (sName) als Admin authentifiziert
wurde (d.h. in der users.ini steht und sich angemeldet hat). Es spielt dabei keine Rolle,
welchen Access Level die Person hat. Die Funktion wird selten für eine vereinfachte
Administratorüberprüfung genutzt.
Liefert als Integerwert 1 zurück, wenn die Personen authentifiziert wurde. Andernfalls wird
eine 0 zurückgeliefert.
Beispiel aus plugin_bk_hltvannounce
(Funktion: admin_hltv_connect):
185 if(auth(User)){
186 hltvconnect(Data);
187 }
Erst wenn der Spieler (User), der den Befehl zum Umleiten eines anderen Spielers (Data)
abgesetzt hat, nachweisen kann, dass er in der plugin.ini steht, d.h. authentifiziert ist, wird
dieser Spieler auch auf den HLTV umgeleitet.
8.10.3 ban
ban( sPlayer[], iTime, bBanBy = bBanByID );
sPlayer[]
Typ: String (33)
iTime
Typ: Integer (0 - 2147483647)
bBanBy = bBanByID
Typ: Enum (0=bBanByID; bBanByIP, bBanBoth)
Die Funktion bannt eine Person unter sPlayer angegebene Person. sPlayer kann der
Spielername, die SessionID oder die Steam ID sein. iTime ist der Integerwert in Minuten, wie
lange der Spieler gebannt werden soll. Der Wert 0 bedeutet, dass die Person permanent vom
Server verbannt wird. Wenn als bBanBy die bBanByID angegeben wird, wird die Steam
ID gebannt. Bei LAN-Servern, wo es keine eindeutige Steam ID gibt, muss man
bBanByIP verwenden. Dies bestimmt auch, in welche Banliste der Eintrag eingefügt wird.
Entweder banned.cfg oder listip.cfg. Der Spieler wird zusätzlich sofort vom Server
gekickt.
Beispiel aus plugin_base (Funktion: admin_ban):
71 if(check_immunity(ban_user)==1) {
72 snprintf(Text, MAX_TEXT_LENGTH, "You can’t ban ’%s’.", TargetName);
73 messageex(User,Text,print_chat);
74 } else {
75 ban(ban_user,BanTime,iBanType);
76 }
Zunächst wird überprüft, ob der zu bannende Spieler evtl. immun gegen Aktionen ihn
betreffend ist. Wenn dies der Fall ist, weist eine mehr oder weniger freundliche Meldung
den aufrufenden Spieler auf seine nutzlose Aktion hin. Anderenfalls wird der Bann
anhand der ID/IP für die angegebene Zeit ausgeführt und der Spieler vom Server
geworfen.
censor_words( sString[] );
sString[]
Typ: String (100)
Die zensierten Wörter werden in der Datei angegeben, die in der adminmod.cfg mittels
words_file definiert wird. Man kann mit censor_words einen Text untersuchen, ob sich darin
ein zensiertes Wort befindet. Ist eines vorhanden, werden die Buchstaben durch „*“
ersetzt.
Beispiel aus plugin_retribution (Funktion: Handle_say):
643 if (check_immunity(User)==0) {
644 messageex(User, "Swearing not allowed on this server", print_center);
645
646 new SwearMsg[MAX_TEXT_LENGTH];
647 censor_words(Data);
648 new i;
649 new c=strlen(Data);
650 for (i=0;i<c;i++) {
651 if (Data[i] == ’"’) {
652 Data[i]=’^’’;
653 }
654 }
655
656 snprintf(SwearMsg, MAX_TEXT_LENGTH, "%s ^"%s^"", Command, Data);
657 execclient(User, SwearMsg);
658 return PLUGIN_HANDLED;
659 }
Nach dem Check, dass der schreibende Spieler keine Immunitität besitzt, gibt es einen Hinweis
in der Mitte des Bildschirms, dass Fluchen auf dem Server nicht erlaubt ist. Danach wird
das Geschriebene zensiert, die Anführungszeichen ausgetauscht und die bereinigte
Chat-Nachricht nochmals vom Spieler abgeschickt (execclient). Um zu verhindern, dass die
unzensierte Nachricht versandt wird, muss die weitere Abarbeitung der Nachricht mittels
PLUGIN_HANDLED unterbunden werden.
centersay( sText[], iTime, iRed, iGreen, iBlue );
sText[]
Typ: String (500) (max. Zeilenlänge: 80)
iTime
Typ: Integer (0 - 2147483647)
iRed
Typ: Integer (0 - 255)
iGreen
Typ: Integer (0 - 255)
iBlue
Typ: Integer (0 - 255)
Mit dieser Funktion kann man eine bunte Nachricht (sText) für alle Spieler in der Mitte des
Bildschirms produzieren. iTime ist die Einblendzeit in Sekunden. iRed ist der Rotanteil,
iGreen der Grünanteil und iBlue der Blauanteil in der Nachricht. Die Funktion centersayex
ermöglicht die gleiche Funktionalität für einzelne Spieler.
Beispiel aus plugin_base (Funktion: admin_csay):
136 if (streq(Color,"red")==1) {
137 centersay(Message,10,250,10,10);
Wenn der Text Color gleich „red“ ist, wird die Nachricht in Message für 10 Sekunden in einen
hellem Rot dargestellt. Es ist zu beachten, dass eine Zeile maximal 80 Zeichen lang sein darf.
Mit Zeilenumbrüchen sind bis zu 500 Zeichen möglich.
centersayex( sUser[], sText[], iTime, iRed, iGreen, iBlue );
sUser[]
Typ: String (33)
sText[]
Typ: String (500) (max. Zeilenlänge: 80)
iTime
Typ: Integer (0 - 2147483647)
iRed
Typ: Integer (0 - 255)
iGreen
Typ: Integer (0 - 255)
iBlue
Typ: Integer (0 - 255)
Mit dieser Funktion kann man eine bunte Nachricht (sText) für einzelne Spieler in der Mitte
des Bildschirms produzieren. iTime ist die Einblendzeit in Sekunden. iRed ist der Rotanteil,
iGreen der Grünanteil und iBlue der Blauanteil in der Nachricht. Die Funktion centersay
ermöglicht die gleiche Funktionalität für alle Spieler.
Beispiel aus plugin_cw_creator3
(Funktion: kickplayers):
256 if(Team!=TEAM_PROXY){
257 get_vaultdata("CWC_PASS",Text,MAX_TEXT_LENGTH);
258 snprintf(Text,MAX_TEXT_LENGTH,"password %s",Text);
259 execclient(Target,Text);
260 centersayex(Target,sMessage,10,68,255,125);
261 }
Der Auszug stammt aus einer For-Schleife über alle Spieler. Der Server soll für einen Clanwar
geschlossen werden. Um Spielern auf einem HLTV nicht das Passwort zu präsentieren, wird
das Passwort nur echten Spielern als Centersay gezeigt. Vorab wurde das neue Passwort aus
der vault.ini geladen und bei den Spielern gesetzt.
changelevel( sMap[], iIntermissionPause = 0 );
sMap[]
Typ: String (100)
iIntermissionPause = 0
Typ: Integer (0 - 2147483647)
Die Funktion lässt den Server zur angegebenen Map (sMap) wechseln. iIntermissionPause ist
ein Integerwert in Sekunden, wie lange gewartet werden soll, bis die Map gewechselt
wird.
Beispiel aus plugin_base (Funktion: admin_map):
307 if (valid_map(Data)==1) {
308 say_command(User,Command,Data);
309 changelevel(Data, 4);
Wenn es sich bei Data um eine gültige Map handelt, wird dies öffentlich gemacht und nach 4
Sekunden ein Mapwechsel durchgeführt.
ChangeMap( Timer, Repeat, HLUser, HLParam );
Bei dieser Funktion handelt es sich ein Timer-Event, das früher statt der direkten Verwendung
von changelevel genutzt wurde. Inzwischen ist sie nur noch aus Kompatibilitätsgründen
vorhanden.
check_auth( iAuthLevel );
iAuthLevel
Typ: Integer (0 - 2147483647)
Die Funktion liefert eine 1 zurück, wenn die Person, die diese Funktion aufgerufen hat, den
Accesslevel iAuthlevel besitzt, andernfalls eine 0. Mit der Funktion access können auch die
Rechte anderer ermittelt werden.
Beispiel aus plugin_base (Funktion: admin_rcon):
435 if (check_auth(ACCESS_RCON)==0) {
436 selfmessage("Laf. Silly bear.");
437 return PLUGIN_HANDLED;
438 }
Um zu verhindern, dass jemand auf die Idee kommt aus der Serverconsole den Befehl
admin_rcon aufzurufen, was möglich aber unsinnig ist, wurde eine Abfangroutine
implementiert. Nur wenn der User den Access Level 65536 (ACCESS_RCON) besitzt, wird
der RCon-Befehl über Admin Mod abgesetzt. Anderenfalls wird man etwas unhöflich auf das
unsinnige Ansinnen hingewiesen.
check_immunity( sTarget[] );
sTarget[]
Typ: String (33)
Die Funktion überprüft, ob der Spieler (sTarget) den Rechtelevel für Immunität (4096)
besitzt. Dieses und andere Rechtelevel lassen sich auch mit der Funktion access
überprüfen.
Beispiel aus plugin_base (Funktion: admin_ban):
71 if(check_immunity(ban_user)==1) {
72 snprintf(Text, MAX_TEXT_LENGTH, "Laf. You can’t ban ’%s’.", TargetName);
73 messageex(User,Text,print_chat);
74 } else {
75 ban(ban_user,BanTime,iBanType);
76 }
Zunächst wird überprüft, ob der zu bannende Spieler immun gegen Aktionen ihn betreffend
ist. Je nach Ausfallen der Überprüfung wird entweder eine Meldung über den Fehlschlag des
Banns oder der Bann selbst abgesetzt.
check_param( sParam[] );
sParam[]
Typ: String (100)
Die Funktion überprüft, ob der String sParam gleich dem String „on“ ist. Bei „on“ gibt die
Funktion 1 anderenfalls 0 zurück.
Beispiel aus plugin_fun (Funktion: admin_fun):
203 if(check_param(Data)==1) {
204 execute_command(User,Command,"admin_fun_mode","1");
205 } else {
206 execute_command(User,Command,"admin_fun_mode","0");
207 KillGlow();
208 }
Wenn der Befehl admin_fun abgesetzt wurde, wird überprüft, ob als Option „on“ übergeben
wurde. Wenn dies der Fall ist, wird der Fun Mode aktiviert, anderenfalls deaktiviert und alle
aktiven Glows abgeschaltet.
check_user( sPlayer[] );
sPlayer[]
Typ: String (33)
Überprüft, ob sich ein Spieler mit dem Namen (auch Teil), ID oder IP (sPlayer) auf dem
Server befindet. Ein positive Überprüfung gibt eine 1 eine negative eine 0 zurück. Die
Funktion wird gern für die Bot oder HLTV-Erkennung eingesetzt.
Beispiel aus plugin_base (Funktion: admin_ban):
68 if (check_user(ban_user)==1) {
69 get_username(ban_user,TargetName,MAX_NAME_LENGTH);
Es wird überprüft, ob ein entsprechender Spieler auf dem Server existiert. In dem Fall wird
über die Funktion get_username aus der ID oder IP ein Name gemacht oder zu einem Namen
ergänzt.
check_words( sData[] );
sData[]
Typ: String (100)
Die zensierten Wörter werden in der Datei angegeben, die in der adminmod.cfg mittels
words_file definiert wird. Man kann mit check_words einen Text untersuchen, ob sich darin
ein zensiertes Wort befindet. Ist eines vorhanden, wird eine 0 zurückgegeben.
Beispiel aus plugin_retribution (Funktion: Handle_say):
726 if(check_words(NewName)==0) {
727 execclient(OldName,"name OldName");
728 return PLUGIN_HANDLED;
729 }
Wenn der neue Spielername ein verbotenes Wort enthält, wird veranlasst, dass er seinen
Namen wieder zurücksetzt.
clamp( value, min=cellmin, max=cellmax );
value
Typ: Integer (-2147483648 - 2147483647)
min=cellmin
Typ: Integer (-2147483648 - 2147483647)
max=cellmax
Typ: Integer (-2147483648 - 2147483647)
Manchmal ist es gewünscht, dass sich ein Zahl (value) innerhalb eines bestimmten Bereichs
befindet. Liegt sie oberhalb des Bereichs wird sie durch die obere Bereichsgrenze (max)
bzw. unterhalb durch die untere Bereichsgrenze (min) ersetzt.
Beispiel aus plugin_CS (Funktion: menuselect):
1512 new Team;
1513 get_userTeam(UserName,Team);
1514 Team = clamp(Team,1,2) - 1;
Zunächst wird das Team des Spielers ermittelt. Anschließend wird zur Vermeidung einer
Feldadressierung außerhalb des gültigen Bereichs (4 - AMX_ERR_BOUNDS) die möglichen
Teams auf 1 und 2 begrenzt. Zur weiteren Bearbeitung werden die Teamnummern
dekrementiert.
consgreet( sMessage[] );
sMessage[]
Typ: String (256)
Mit der consgreet Funktion kann man Nachrichten (sMessage) in der Konsole des Spielers
anzeigen, der sich gerade mit dem Server verbindet (zum Lesen der Serverregeln etc.). Man
kann mit der Funktion auch ein Textfile anzeigen lassen. Dann muss sMessage den Pfad und
die Textdatei mit Endung txt enthalten.
Inzwischen wird die Console beim Connect nicht mehr angezeigt. Die Funktion ist daher als
obsolet anzusehen.
Beispiel aus plugin_dale_consgreet
(Funktion: plugin_connect):
186 if(fileexists("consgreet.txt")==1) {
187 consgreet("================================================================");
188 consgreet("------------------------Server Stuff--------------------------");
189 consgreet("consgreet.txt");
190 consgreet("");
191 }
Zunächst wird überprüft, ob die Datei consgreet.txt existiert. Anschließend wird eine
Überschrift generiert und der Inhalt der Datei consgreet.txt in die Console geschrieben. Eine
Leerzeile schließt den Code ab.
convert_string( HLString, sSmallString[], iMaxLength );
iHLString
Typ: String (variabel, theoretisch: 2147483647)
sSmallString[]
Typ: String (iMaxLength)
iMaxLength
Typ: Integer (variabel, theoretisch: 1 - 2147483647)
Admin Mod erhält von der Engine den HLString, der nicht direkt nutzbar ist. Daher muss der
Inhalt mit convert_string in einen SmallString umgewandelt werden.
Beispiel aus plugin_base (Funktion: admin_ban):
45 public admin_ban(HLCommand,HLData,HLUserName,UserIndex) {
46 new ban_user[MAX_DATA_LENGTH];
47 new BanTime = 0;
48 new iBanType = bBanByID;
49 new Command[MAX_COMMAND_LENGTH];
50 new Data[MAX_DATA_LENGTH];
51 new strTime[MAX_NUMBER_LENGTH];
52 new strType[MAX_NAME_LENGTH];
53 new Text[MAX_TEXT_LENGTH];
54 new TargetName[MAX_NAME_LENGTH];
55 new User[MAX_NAME_LENGTH];
56
57 convert_string(HLCommand,Command,MAX_COMMAND_LENGTH);
58 convert_string(HLData,Data,MAX_DATA_LENGTH);
59 convert_string(HLUserName,User,MAX_NAME_LENGTH);
Nach einigen Variablendeklaration werden die übergebenen HL-Strings (HLCommand,
HLData, HLUserName) zur weiteren Bearbeitung in einen Small-String umgewandelt. Dabei
wird auf die maximale Stringlänge aus den Deklarationen Rücksicht genommen.
currentmap( sMap[], iMaxLength );
sMap[]
Typ: String (iMaxLength)
iMaxLength
Typ: Integer (variabel, theoretisch: 1 - 2147483647), praktisch: 33)
Mit der Funktion currentmap wird die aktuell laufende Map (sMap) zurückgegeben.
Beispiel aus plugin_chat (Funktion: SayCurrentMap):
43 SayCurrentMap() {
44 new Text[MAX_TEXT_LENGTH];
45 new CurrentMap[MAX_NAME_LENGTH];
46
47 currentmap(CurrentMap,MAX_NAME_LENGTH);
48 snprintf(Text, MAX_TEXT_LENGTH, "The current map is: %s", CurrentMap);
49 say(Text);
50 }
Die derzeit auf dem Server gespielte Map wird ermittelt. Die maximale Stringlänge von 33
(MAX_NAME_LENGTH) sollte völlig ausreichend sein. Anschließend wird allen Spielern
mitgeteilt, auf welcher Map sie gerade spielen.
cvar_exists( sCvar[] );
sMap[]
Typ: String (variabel, theoretisch: 1 - 2147483647, praktisch: 33)
Die Funktion dient der Überprüfung, ob eine bestimmte Servervariable existiert.
U.U. kann man durch diese Funktion herausbekommen, welche HL-Modifikation
läuft.
Beispiel aus plugin_CS (Funktion: GetVersion):
1550 GetVersion() {
1551 if( cvar_exists("sv_region") ) {
1552 return V15 + 1;
1553 }
1554 return V15;
1555 }
In diesem Fall wird überprüft, ob die Variable „sv_region“ existiert. Diese wurde erst in der
Counter-Strike Version 1.6 eingeführt. Da sich einiges im Handling zwischen CS 1.5 und CS
1.6 unterscheidet, müssen einige Funktionen für beide Versionen funktional bleiben. Mittels
Verzweigungen auf Basis des Versionschecks kann diese Problematik bequem umschifft
werden.
deletefile( sFilename[] );
sFilename[]
Typ: String (200)
Löscht die Datei (sFilename), wenn sie existiert. Relative Pfade vom Modverzeichnis aus sind
erlaubt. Es muss file_access_write auf 1 gesetzt sein, damit die Funktion wirksam wird.
Es ist nur möglich Dateien im Modverzeichnis oder darunter zu schreiben und zu
löschen.
Beispiel aus plugin_bk_res
(Funktion: admin_res_refresh):
184 if(fileexists(sMap)){
185 deletefile(sMap);
186 }
Zunächst wird überprüft, ob die Datei (sMap) überhaupt existiert. Erst bei einer positiven
Überprüfung wird sie gelöscht.
deleteproperty( id=0, const name[]=“”, value=cellmin );
id=0
Typ: Integer (-2147483648 - 2147483647)
const name[]=“”
Typ: String (variabel)
value=cellmin
Typ: Integer (-2147483648 - 2147483647)
Mit dieser Funktion kann eine so genannte Property bei gegebenem Schlüssel gelöscht werden.
Es handelt sich dabei um eine Funktion, deren Benutzung unter Admin Mod vermieden
werden sollte. Stattdessen wird empfohlen z.B. die Funktionen get_vaultdata oder
set_vaultdata zurückzugreifen.
Mehr Informationen zum Thema sind im Abschnitt 8.14 nachzulesen.
Beispiel:
deleteproperty(2,“test_prop”);
deleteproperty(3,15);
Das erste Beispiel löscht die in ID 2 befindliche Property „test_prop“, während das zweite
Beispiel die in ID 3 befindliche Property 15 löscht.
directmessage( sMessage[], iUserID = -1, uid:tUidType =
uid:uid_SessionID );
sMessage[]
Typ: String (100)
iUserID = -1
Typ: Integer (-1 - 2147483647)
uid:tUidType = uid:uid_SessionID
Typ: Enum (0=uid_none, uid_invalid, uid_index, uid_SessionID, uid_wonID)
Die Nachricht sMessage kann direkt an den Spieler mit dem angegebenen Userindex bzw. der
Session ID geschickt werden. Ob es sich um den Userindex oder um die Session
ID handelt, muss mit „uid_index“ bzw. „uid_SessionID“ angegeben werden. Die
weiteren Optionen „uid_none“, „uid_invalid“, „uid_wonID“ werden nicht (mehr)
genutzt.
Beispiel aus plugin_base (Funktion: admin_dmsg):
179 switch( sType[0] ) {
180 case ’i’:
181 tType = uid_index;
182 case ’s’:
183 tType = uid_SessionID;
184 case ’w’:
185 tType = uid_wonID;
186 default:
187 tType = uid_invalid;
188 } // switch()
189
190
191 strstripquotes(sMessage);
192 directmessage( sMessage, iUid, tType );
Abhängig vom Buchstaben, der sich in der ersten Zelle von sType befindet, wird der UID Typ
festgelegt. Die um Anführungszeichen befreite Nachricht (Zeile 191: strstripquotes) wird der
ID (Session ID oder Userindex) geschickt.
distance( x1, x2, y1=0, y2=0, z1=0, z2=0 );
x1
Typ: Integer (-2147483648 - 2147483647)
x2
Typ: Integer (-2147483648 - 2147483647)
y1=0
Typ: Integer (-2147483648 - 2147483647)
y2=0
Typ: Integer (-2147483648 - 2147483647)
z1=0
Typ: Integer (-2147483648 - 2147483647)
z2=0
Typ: Integer (-2147483648 - 2147483647)
Die Funktion „distance“ berechnet die Entfernung zwischen zwei Punkten auf der
Map.
Bei großen Entfernungen zwischen zwei Punkten, kann es zu Problemen kommen. Die
Berechnung ermittelt die Summe der Quadrate der Abstände in x-, y- und z-Richtung. Sollte
diese Summe größer als 2147483647 sein, kommt es zu einem Overflow, der zwar das Plugin
nicht abstürzen lässt, aber falsche Ergebnisse liefert. Es wird daher empfohlen die Summe
vorab abzuschätzen (z.B. sollte die Summe der Abstände 46340 nicht überschreiten). Man
kann dann die Punkte durch einen festen Faktor teilen und ihn nach der Berechnung wieder
aufschlagen.
Beispiel aus plugin_sdal_logd_hp50
(Funktion: get_user_distance):
487 get_userorigin(Attacker,ax,ay,az);
488 get_userorigin(Victim,vx,vy,vz);
489 g_PlayerEnemyDistance[iVID]= distance(ax,vx,ay,vy,az,vz);
Der Funktion „get_user_distance“ wird der Name des Siegers und des Verlierers des Duells
und der Userindex des Verlierers übergeben. Mittels get_userorigin werden die Positionen der
Spieler auf der Map ermittelt und der Abstand zwischen den Spielern in einer Zelle eines
Feldes gespeichert.
exec( sCommand[], bWriteLogEntry = 1 );
sCommand[]
Typ: String (256)
bWriteLogEntry = 1
Typ: Integer (0 - 1)
Führt einen beliebigen Serverbefehl aus, kann aber auch Variablen setzen. Ausgenommen sind
Admin Mod Befehle. Diese müssen mit plugin_exec ausgeführt werden, damit das
Rechtesystem nicht über Plugins ausgehebelt werden kann.
Mit bWriteLogEntry = 0 kann man bewirken, dass keine Logzeile, beginnend mit
„[ADMIN]Executing command:“ in die Logs eingetragen wird.
Beispiel aus plugin_base (Funktion: admin_pass):
359 snprintf(Msg, MAX_DATA_LENGTH, "sv_password %s", Data);
360 exec(Msg);
Der Inhalt aus „Data“ wird „sv_password“ angehängt und ausgeführt, so dass nun das
Passwort gilt, das in „Data“ steht. Auf die Logentry Einstellung wurde verzichtet, so dass die
Ausführung geloggt wird.
execclient( sPlayer[], sCommand[] );
sPlayer[]
Typ: String (100)
sCommand[]
Typ: String (100)
Führt einen Befehl beim Spieler aus. Dabei muss der Spielername und der auszuführende
Befehl angegeben werden. In der adminmod.cfg muss allow_client_exec auf 1 gesetzt
sein.
Beispiel aus plugin_retribution (Funktion: admin_bury):
510 snprintf(Text, MAX_TEXT_LENGTH, "%s has broke the rules!", TargetName);
511 say(Text);
512
513 messageex(TargetName, "Please obey our rules!", print_chat);
514 execclient(TargetName, "say Help! I’m stuck!");
Allen Spielern wird im Chat mitgeteilt, dass der eingegrabene Spieler gegen die Regeln
verstoßen hat. Dieses wird ihm ebenfalls im Chat gesagt. Zusätzlich lässt man den Spieler
mittels execclient „Help! I’m stuck!“ sagen.
execclient_all( sCommand[] );
sCommand[]
Typ: String (100)
Führt bei allen Spielern den selben Befehl aus. allow_client_exec 1 muss dazu in der
adminmod.cfg gesetzt sein.
Beispiel aus plugin_cw_creator/plugin_logd_cwcaddon
(Funktion: logd_cwc_score):
305 if(maxrounds==0){
306 execclient_all("timeleft");
307 }
Falls die Variable „maxrounds“ auf 0 gesetzt ist, wird bei allen Spielern der Befehl „timeleft“
ausgeführt, der die verbleibende Restzeit auf der Map beim Spieler anzeigt.
execute_command( sUser[], sCommand[], sHalfLifeCmd[], sData[] );
sUser[]
Typ: String (33)
sCommand[]
Typ: String (30)
sHalfLifeCmd[]
Typ: String (30)
sData[]
Typ: String (200)
Führt einen Befehl auf dem Server aus und gibt zusätzlich eine formatierte Nachricht am
Bildschirm oder in den Logdateien aus, wenn admin_quiet entsprechend in der adminmod.cfg
gesetzt ist.
Zum Ausführen wird der Adminname (sUser), der Admin Mod Befehl (sCommand), den er
ausgeführt hat, der zu setzende Serverbefehl bzw. die Servervariable (sHalfLifeCmd) und die
Option (sData) benötigt.
Beispiel aus plugin_base (Funktion: admin_hostname):
243 convert_string(HLCommand,Command,MAX_COMMAND_LENGTH);
244 convert_string(HLData,Data,MAX_DATA_LENGTH);
245 convert_string(HLUserName,User,MAX_NAME_LENGTH);
246 snprintf(sHostName, MAX_DATA_LENGTH, "^"%s^"", Data);
247 execute_command(User,Command,"hostname",sHostName);
Zunächst werden die Half-Life Strings konvertiert. „Data“ sollte dabei den neuen Servernamen
beinhalten und wird wegen möglicher Leerzeichen in Anführungszeichen gesetzt (Zeile:
246). Anschließend werden die Daten „execute_command“ übergeben. „User“ und
„Command“ geben ausführlich Auskunft darüber, wer welchen Befehl ausgeführt
hat.
existproperty( id=0, const name[]=“”, value=cellmin );
id=0
Typ: Integer (-2147483648 - 2147483647)
const name[]=“”
Typ: String (variabel)
value=cellmin
Typ: Integer (-2147483648 - 2147483647)
Mit dieser Funktion kann die Existenz einer so genannten Property bei gegebenem Schlüssel
überprüft werden. Es handelt sich dabei um eine Funktion, deren Benutzung unter Admin
Mod vermieden werden sollte. Stattdessen wird empfohlen z.B. die Funktionen get_vaultdata
oder set_vaultdata zurückzugreifen.
Mehr Informationen zum Thema sind im Abschnitt 8.14 nachzulesen.
Beispiel:
bBoolean = existproperty(2,“test_prop”);
bBoolean = existproperty(3,15);
Das erste Beispiel überprüft, ob die in ID 2 befindliche Property „test_prop“ existiert,
während das zweite Beispiel überprüft, ob die in ID 3 befindliche Property 15 gesetzt
wurde.
fileexists( sFilename[] );
sFilename[]
Typ: String (100)
Überprüft unter Angabe von „sFilename“, ob die Datei vorhanden ist. Dazu muss die
Variable file_access_read auf 1 in der adminmod.cfg gesetzt sein. Als Rückgabewert
erhält man eine 1, wenn die Datei vorhanden, anderenfalls bekommt man eine 0
zurück.
Beispiel aus plugin_base (Funktion: plugin_init):
870 currentmap(strMap, MAX_DATA_LENGTH);
871 snprintf(ExecCommand, MAX_DATA_LENGTH, "%s.cfg", strMap);
872 if ( fileexists(ExecCommand) ) {
873 snprintf(ExecCommand, MAX_DATA_LENGTH, "exec %s.cfg", strMap);
874 log(ExecCommand);
875 exec(ExecCommand);
876 }
Es wird die aktuelle Map ermittelt und überprüft, ob sich im Modverzeichnis eine
Konfiguartionsdatei für diese spezielle Map befindet. Existiert die Datei, wird sie ausgeführt.
Dies ist eine oftmals übersehene Funktion Admin Mods, die der Basisfunktionalität des
HL-Servers zugeschlagen wird.
filesize( sFilename[], fsize_unit:Unit = 1 );
sFilename[]
Typ: String (100)
fsize_unit:Unit = 1
Typ: Enum (0=bytes, lines)
Man erhält die Anzahl der Zeilen oder die Größe in Byte der unter sFilename angegebenen
Datei. Wird „fsize_unit“ nicht angegeben, wird die Anzahl der Zeilen bei „bytes“ hingegen die
Dateigröße in Bytes zurückgegeben.
Zum Ausführen der Funktion muss file_access_read auf 1 in der adminmod.cfg gesetzt
sein.
Beispiel aus plugin_bk_cron
(Funktion: admin_cron_refresh):
187 if(fileexists(filename)==0){
188 /* log("plugin_bk_cron found no schedule.ini."); */
189 log(cron_nosched);
190 return PLUGIN_CONTINUE;
191 }
192 sizeoffile=filesize(filename,lines);
Ist die unter „filename“ angegebene Datei nicht existent, wird eine Fehlermeldung in den
Logdateien ausgegeben und die weitere Ausführung des Befehls abgebrochen. Wird die Datei
hingegen gefunden, wird die Anzahl der Zeilen ausgelesen und in die Variable „sizeoffile“
geschrieben.
f_abs( fixed:fNum );
fixed:fNum
Typ: Fixed (-2147482 - 2147482)
Die Funktion f_abs gibt den Absolutwert einer Festkommazahl aus.
Beispiel aus math.inc (Funktion: f_sqrt):
296 if(f_abs(fNum)!=fNum){
297 iError=1;
298 return -1.000;
299 }
Hier wird die Funktion f_abs benutzt, um zu überprüfen, ob der Wert fNum negativ ist. Ist er
negativ, wird die Funktion abgebrochen und -1 zurückgegeben, um zu verhindern, dass die
Wurzel aus einer negativen Zahl gezogen wird.
f_arccos( fixed:fNum, &iError=0 );
fixed:fNum
Typ: Fixed (-2147482 - 2147482)
iError=0
Typ: Integer (0 - 3)
Die Funktion f_arccos gibt den Arkuskosinus Wert als eine Festkommazahl zurück.
Darüber hinaus wird bei einer fehlgeschlagenen Berechnung ein Fehlerwert iError
zurückgegeben.
Beispiel:
fNum = f_arccos(fNum,iError);
matherror(iError);
Aus fNum wird der Arkuskosinus gebildet und anschließend eine mögliche Fehlermeldung mit
matherror in die Logdateien geschrieben.
f_arccot( fixed:fNum );
fixed:fNum
Typ: Fixed (-2147482 - 2147482)
Die Funktion f_arccot gibt den Arkuskotangens Wert als eine Festkommazahl zurück.
Beispiel:
fNum = f_arccot(fNum);
Aus fNum wird der Arkuskotangens gebildet.
f_arcosh( fixed:fNum, &iError=0 );
fixed:fNum
Typ: Fixed (-2147482 - 2147482)
iError=0
Typ: Integer (0 - 3)
Die Funktion f_arcosh gibt den Areakosinus Hyperbolicus Wert als eine Festkommazahl
zurück. Darüber hinaus wird bei einer fehlgeschlagenen Berechnung ein Fehlerwert iError
zurückgegeben.
Beispiel:
fNum = f_arcosh(fNum,iError);
matherror(iError);
Aus fNum wird der Areakosinus Hyperbolicus gebildet und anschließend eine mögliche
Fehlermeldung mit matherror in die Logdateien geschrieben.
f_arcoth( fixed:fNum, &iError=0 );
fixed:fNum
Typ: Fixed (-2147482 - 2147482)
iError=0
Typ: Integer (0 - 3)
Die Funktion f_arcoth gibt den Areatangens Hyperbolicus Wert als eine Festkommazahl
zurück. Darüber hinaus wird bei einer fehlgeschlagenen Berechnung ein Fehlerwert iError
zurückgegeben.
Beispiel:
fNum = f_arcoth(fNum,iError);
matherror(iError);
Aus fNum wird der Areatangens Hyperbolicus gebildet und anschließend eine mögliche
Fehlermeldung mit matherror in die Logdateien geschrieben.
f_arcsin( fixed:fNum, &iError=0 );
fixed:fNum
Typ: Fixed (-2147482 - 2147482)
iError=0
Typ: Integer (0 - 3)
Die Funktion f_arcsin gibt den Arkussinus Wert als eine Festkommazahl zurück.
Darüber hinaus wird bei einer fehlgeschlagenen Berechnung ein Fehlerwert iError
zurückgegeben.
Beispiel aus math.inc (Funktion: f_arccos):
478 return fdiv(f_pi(),2.000)-f_arcsin(fNum);
Der Arkuskosinus wird aus der Berechnung arccos x = - arcsin x gebildet.
f_arctan( fixed:fNum, &iError=0 );
fixed:fNum
Typ: Fixed (-2147482 - 2147482)
iError=0
Typ: Integer (0 - 3)
Die Funktion f_arctan gibt den Arkustangens Wert als eine Festkommazahl zurück.
Darüber hinaus wird bei einer fehlgeschlagenen Berechnung ein Fehlerwert iError
zurückgegeben.
Beispiel aus math.inc (Funktion: f_arccot):
481 stock fixed:f_arccot(fixed:fNum){
482 return fdiv(f_pi(),2.000)-f_arctan(fNum);
483 }
Der Arkuskotangens wird aus der Berechnung arccot x = - arctan x gebildet.
f_arctan_help( fixed:fNum );
fixed:fNum
Typ: Fixed (-2147482 - 2147482)
Die Funktion f_arctan_help ist lediglich eine Unterfunktion von f_arctan und ist für eine
Verwendung in einem Plugin nicht sinnvoll.
f_arsinh( fixed:fNum, &iError=0 );
fixed:fNum
Typ: Fixed (-2147482 - 2147482)
iError=0
Typ: Integer (0 - 3)
Die Funktion f_arsinh gibt den Areasinus Hyperbolicus Wert als eine Festkommazahl zurück.
Darüber hinaus wird bei einer fehlgeschlagenen Berechnung ein Fehlerwert iError
zurückgegeben.
Beispiel:
fNum = f_arsinh(fNum,iError);
matherror(iError);
Aus fNum wird der Areasinus Hyperbolicus gebildet und anschließend eine mögliche
Fehlermeldung mit matherror in die Logdateien geschrieben.
f_artanh( fixed:fNum, &iError=0 );
fixed:fNum
Typ: Fixed (-2147482 - 2147482)
iError=0
Typ: Integer (0 - 3)
Die Funktion f_artanh gibt den Areatangens Hyperbolicus Wert als eine Festkommazahl
zurück. Darüber hinaus wird bei einer fehlgeschlagenen Berechnung ein Fehlerwert iError
zurückgegeben.
Beispiel:
fNum = f_artanh(fNum,iError);
matherror(iError);
Aus fNum wird der Areatangens Hyperbolicus gebildet und anschließend eine mögliche
Fehlermeldung mit matherror in die Logdateien geschrieben.
f_cos( fixed:fNum );
fixed:fNum
Typ: Fixed (-2147482 - 2147482)
Die Funktion f_cos gibt den Kosinus Wert als eine Festkommazahl zurück.
Beispiel aus math.inc (Funktion: f_tan):
398 stock fixed:f_tan(fixed:fNum){
399 return fdiv(f_sin(fNum),f_cos(fNum));
400 }
Der Tangens wird aus der Berechnung tan x = gebildet.
f_cosh( fixed:fNum );
fixed:fNum
Typ: Fixed (-2147482 - 2147482)
Die Funktion f_cosh gibt den Kosinus Hyperbolicus Wert als eine Festkommazahl
zurück.
Beispiel aus math.inc (Funktion: f_tanh):
493 stock fixed:f_tanh(fixed:fNum){
494 return fdiv(f_sinh(fNum),f_cosh(fNum));
495 }
Der Tangens Hyperbolicus wird aus der Berechnung tanh x = gebildet.
f_cot( fixed:fNum );
fixed:fNum
Typ: Fixed (-2147482 - 2147482)
Die Funktion f_cot gibt den Kotangens Wert als eine Festkommazahl zurück.
Beispiel:
fNum = f_cot(fNum);
Aus fNum wird der Kotangens gebildet.
f_coth( fixed:fNum, &iError=0 );
fixed:fNum
Typ: Fixed (-2147482 - 2147482)
iError=0
Typ: Integer (0 - 3)
Die Funktion f_coth gibt den Kotangens Hyperbolicus Wert als eine Festkommazahl zurück.
Darüber hinaus wird bei einer fehlgeschlagenen Berechnung ein Fehlerwert iError
zurückgegeben.
Beispiel:
fNum = f_coth(fNum,iError);
matherror(iError);
Aus fNum wird der Kotangens Hyperbolicus gebildet und anschließend eine mögliche
Fehlermeldung mit matherror in die Logdateien geschrieben.
f_degtorad( fixed:fNum );
fixed:fNum
Typ: Fixed (-2147482 - 2147482)
Die Funktion f_degtorad rechnet einen Winkel von Grad in Radiant um.
Beispiel:
fNum = f_degtorad(fNum);
Der Winkel fNum wird in Radiant umgerechnet.
f_euler( );
Die Funktion f_euler gibt die Eulersche Zahl (2,718) zurück.
Beispiel:
fEuler = f_euler();
In die Variable fEuler wird die Eulersche Zahl geschrieben.
f_faculty( fixed:fValue, &iError=0 );
fixed:fValue
Typ: Fixed (-2147482 - 2147482)
iError=0
Typ: Integer (0 - 3)
Die Funktion f_faculty gibt die Fakultät einer Zahl als eine Festkommazahl zurück.
Darüber hinaus wird bei einer fehlgeschlagenen Berechnung ein Fehlerwert iError
zurückgegeben.
Beispiel:
fNum = f_faculty(fNum,iError);
matherror(iError);
Aus fNum wird die Fakultät ermittelt und anschließend eine mögliche Fehlermeldung mit
matherror in die Logdateien geschrieben.
f_ln( fixed:fValue, &iError=0 );
fixed:fValue
Typ: Fixed (-2147482 - 2147482)
iError=0
Typ: Integer (0 - 3)
Die Funktion f_ln ermittelt den natürlichen Logarithmus einer Zahl und gibt diesen als eine
Festkommazahl zurück. Darüber hinaus wird bei einer fehlgeschlagenen Berechnung ein
Fehlerwert iError zurückgegeben.
Beispiel aus math.inc (Funktion: f_arsinh):
510 return f_ln(fNum+f_sqrt(fmul(fNum,fNum)+1.000));
Der Areasinus Hyperbolicus wird aus der Berechnung arsinh x = ln(x + )
gebildet.
f_log10( fixed:fValue, &iError=0 );
fixed:fValue
Typ: Fixed (-2147482 - 2147482)
iError=0
Typ: Integer (0 - 3)
Die Funktion f_log10 ermittelt den Zehner-Logarithmus einer Zahl und gibt diesen als eine
Festkommazahl zurück. Darüber hinaus wird bei einer fehlgeschlagenen Berechnung ein
Fehlerwert iError zurückgegeben.
Beispiel aus math.inc (Funktion: f_logab):
163 fBase=f_log10(fBase,iError);
164 if(iError>0){
165 return fBase;
166 }
Die Basis für den beliebigen Logarithmus wird mit dem Zehnerlogarithmus vorbereitet. Ist ein
Fehler aufgetreten, wird die Ausführung abgebrochen.
f_log10( fixed:fBase, fixed:fValue, &iError=0 );
fixed:fBase
Typ: Fixed (-2147482 - 2147482)
fixed:fValue
Typ: Fixed (-2147482 - 2147482)
iError=0
Typ: Integer (0 - 3)
Die Funktion f_logab ermittelt den Logarithmus einer Zahl auf einer beliebigen
Basis und gibt diesen als eine Festkommazahl zurück. Darüber hinaus wird bei einer
fehlgeschlagenen Berechnung ein Fehlerwert iError zurückgegeben. Benötigt man den
natürlichen oder den Zehnerlogarithmus, sollte man auf die Funktionen f_ln und f_log10
zurückgreifen.
Beispiel:
fNum = f_logab(fBasis,fNum,iError);
matherror(iError);
Aus fNum wird der Logarithmus auf der Basis fBasis gebildet und anschließend eine mögliche
Fehlermeldung mit matherror in die Logdateien geschrieben.
f_max( fixed:fNum, fixed:fNum2 );
fixed:fNum
Typ: Fixed (-2147482 - 2147482)
fixed:fNum2
Typ: Fixed (-2147482 - 2147482)
Die Funktion f_max gibt aus zwei Festkommazahlen die größte aus. Für Ganzzahlen kann
man max nutzen.
Beispiel aus math.inc (Funktion: f_arctan):
424 fRange=f_max(fNum,0.000);
Es wird sichergestellt, dass keine negativen Werte auftreten können. Negative Werte werden
auf 0 gesetzt.
f_min( fixed:fNum, fixed:fNum2 );
fixed:fNum
Typ: Fixed (-2147482 - 2147482)
fixed:fNum2
Typ: Fixed (-2147482 - 2147482)
Die Funktion f_min gibt aus zwei Festkommazahlen die kleinste aus. Für Ganzzahlen kann
man min nutzen.
Beispiel:
fMin = f_min(fNum1,fNum2);
Der kleinste Wert aus fNum1 und fNum2 wird an fMin übergeben.
f_pi( );
Die Funktion f_pi gibt die Zahl Pi (3,142) zurück.
Beispiel:
fPi = f_pi();
In die Variable fPi wird die Zahl Pi geschrieben.
f_power( fixed:fBasis, fixed:fExponent, &iError=0 );
fixed:fBasis
Typ: Fixed (-2147482 - 2147482)
fixed:fExponent
Typ: Fixed (-2147482 - 2147482)
iError=0
Typ: Integer (0 - 3)
Die Funktion f_power exponiert (fExponent) den in fBasis gegebenen Wert. Will man nur die
Eulerzahl exponieren, sollte man auf f_powere zurückgreifen.
Beispiel:
fNum = f_power(fBasis,fExponent,iError);
matherror(iError);
Die Basis (fBasis) wird mit fExponent exponiert und das Ergebnis in fNum geschrieben. Eine
mögliche Fehlermeldung wird mit matherror in die Logdateien geschrieben.
f_powere( fixed:fExponent, &iError=0 );
fixed:fExponent
Typ: Fixed (-2147482 - 2147482)
iError=0
Typ: Integer (0 - 3)
Die Funktion f_power exponiert (fExponent) den die Eulersche Zahl. Will man eine beliebige
Zahl exponieren, sollte man auf f_power zurückgreifen.
Beispiel aus math.inc (Funktion: f_sinh):
424 stock fixed:f_sinh(fixed:fNum){
425 return fdiv(f_powere(fNum)-f_powere(fmul(fNum,-1.000)),2.000);
426 }
Der Sinus Hyperbolicus wird aus der Berechnung sinh x = gebildet.
f_radtodeg( fixed:fNum );
fixed:fNum
Typ: Fixed (-2147482 - 2147482)
Die Funktion f_radtodeg rechnet einen Winkel von Radiant in Grad um.
Beispiel:
fNum = f_radtodeg(fNum);
Der Winkel fNum wird in Grad umgerechnet.
f_sin( fixed:fNum );
fixed:fNum
Typ: Fixed (-2147482 - 2147482)
Die Funktion f_sin gibt den Sinus Wert als eine Festkommazahl zurück.
Beispiel aus math.inc (Funktion: f_cos):
394 stock fixed:f_cos(fixed:fNum){
395 return f_sin(fNum+fdiv(f_pi(),2.000));
396 }
Der Kosinus wird aus der Berechnung cos x = sin(x + ) gebildet.
f_sinh( fixed:fNum );
fixed:fNum
Typ: Fixed (-2147482 - 2147482)
Die Funktion f_sinh gibt den Sinus Hyperbolicus Wert als eine Festkommazahl
zurück.
Beispiel aus math.inc (Funktion: f_tanh):
493 stock fixed:f_tanh(fixed:fNum){
494 return fdiv(f_sinh(fNum),f_cosh(fNum));
495 }
Der Tangens Hyperbolicus wird aus der Berechnung tanh x = gebildet.
f_sqrt( fixed:fNum, &iError=0, fixed:fNumStart=1.000 );
fixed:fNum
Typ: Fixed (-2147482 - 2147482)
iError=0
Typ: Integer (0 - 3)
fixed:fNumStart
Typ: Fixed (-2147482 - 2147482)
Die Funktion f_sqrt zieht aus einer gegebenen Zahl fNum die Quadratwurzel. Da die
Ermittlung der Quadratwurzel eine iterative Berechnung ist, kann die Berechnung
beschleunigt werden, in dem ein sinnvoller Startwert für fNumStart angegeben wird
(Standard: 1.000). Außerdem wird über iError ein Fehlerwert zurückgegeben.
Beispiel aus math.inc (Funktion: f_arsinh):
510 return f_ln(fNum+f_sqrt(fmul(fNum,fNum)+1.000));
Der Areasinus Hyperbolicus wird aus der Berechnung arsinh x = ln(x + )
gebildet.
f_tan( fixed:fNum );
fixed:fNum
Typ: Fixed (-2147482 - 2147482)
Die Funktion f_tan gibt den Tangens Wert als eine Festkommazahl zurück.
Beispiel:
fNum = f_tan(fNum);
Aus fNum wird der Tangens gebildet.
f_tanh( fixed:fNum );
fixed:fNum
Typ: Fixed (-2147482 - 2147482)
Die Funktion f_tanh gibt den Tangens Hyperbolicus Wert als eine Festkommazahl
zurück.
Beispiel:
fNum = f_tanh(fNum);
Aus fNum wird der Tangens Hyperbolicus gebildet.
fixed:fdiv( fixed:dividend, fixed:divisor );
fixed:dividend
Typ: Fixed (-2147482 - 2147482)
fixed:divisor
Typ: Fixed (-2147482 - 2147482)
Die Funktion fdiv führt eine Divison zweier Zahlen durch. Theoretisch steht auch „/“ als
Operatorzeichen zur Verfügung. Die Erkennung durch den Compiler ist leider nicht
zuverlässig, so dass die Funktion fdiv empfohlen wird.
Beispiel aus math.inc (Funktion: f_cos):
394 stock fixed:f_cos(fixed:fNum){
395 return f_sin(fNum+fdiv(f_pi(),2.000));
396 }
Hier wird der Kosinus durch die Berechnung cos x = sin(x + ) ermittelt.
fixed:ffract( fixed:value );
fixed:value
Typ: Fixed (-2147482 - 2147482)
Mit ffract werden die drei Nachkommastellen als Zahl ermittelt. Dabei wird auch das
Vorzeichen des Gesamtwertes übertragen.
Beispiel aus math.inc (Funktion: fixtorstr):
26 iFrac=ffract(fNumber);
27 if(iFrac<0){
28 iFrac*=-1;
29 iSign=-1;
30 }
Im Beispiel werden die Nachkommastellen als Zahl ermittelt. Ist die Zahl negativ wird sie
negiert und das Vorzeichen in iSign gespeichert.
fixed:fixed( value );
value
Typ: Integer (-2147482 - 2147482)
Die Funktion fixed wandelt eine Ganzzahl in eine Festkommazahl um.
Beispiel aus math.inc (Funktion: f_faculty):
181 iValue=fround(fValue);
182 fValue=1.000;
183 for(new i=2;i<=iValue;i++){
184 fValue=fmul(fValue,fixed(i));
185 }
Zunächst wird zur Ermittlung der Fakultät der Wert auf eine Ganzzahl gerundet. Der
Ausgangswert wird auf 1 gesetzt. Die Fakultät wird durch eine For Schleife durch
Multiplikation ermittelt. Dabei muss das aktuelle Inkrement bei jedem Durchlauf in eine
Festkommazahl mittels der Funktion fixed umgewandelt werden.
fixed:fixedstr( const string[] );
string
Typ: String (20)
Die Funktion fixedstr wandelt einen String in eine Festkommazahl um. Dabei geht
aber ein mögliches Vorzeichen verloren. Das Ergebnis ist immer positiv. Daher wird
empfohlen statt fixedstr die Funktion strtofix zu verwenden, die auch das Vorzeichen
berücksichtigt.
Beispiel aus math.inc (Funktion: strtofix):
49 if(strtrim(sNumber,"-",0)>0){
50 fNumber=fmul(fixedstr(sNumber),-1.000);
51 }
52 else{
53 fNumber=fixedstr(sNumber);
54 }
Wenn ein negatives Vorzeichen existiert, wird die aus dem String umgewandelte Zahl negiert.
Anderenfalls wird nur der String in eine Festkommazahl umgewandelt.
fixed:fmul( fixed:oper1, fixed:oper2 );
fixed:oper1
Typ: Fixed (-2147482 - 2147482)
fixed:oper2
Typ: Fixed (-2147482 - 2147482)
Die Funktion fmul führt eine Multiplikation zweier Zahlen durch. Theoretisch steht auch „*“
als Operatorzeichen zur Verfügung. Die Erkennung durch den Compiler ist leider nicht
zuverlässig, so dass die Funktion fmul empfohlen wird.
Beispiel aus math.inc (Funktion: f_abs):
320 stock fixed:f_abs(fixed:fNum) {
321 if(fNum >= 0.000) {
322 return fNum;
323 }
324 return fmul(fNum,-1.000);
325 }
Ist die Zahl positiv, wird sie unbearbeitet zurückgegeben. Anderenfalls wird sie mit -1
multipliziert (also negiert), so dass stets der Absolutwert zurückgegeben wird.
fixed:strtofix( sNumber[] );
string
Typ: String (20)
Die Funktion strtofix wandelt einen String in eine Festkommazahl um. Im Gegensatz zu
fixedstr wird ein mögliches Vorzeichen berücksichtigt.
Beispiel:
new sNumber[MAX_NUMBER_LENGTH];
strcpy(sNumber,“-1.378”,MAX_NUMBER_LENGTH);
fNumber = strtofix(sNumber);
Es wird ein String definiert und anschließend mittels der Funktion strcpy mit „-1.378“ befüllt.
Aus diesem String (sNumber) wird eine Festkommazahl gebildet (fNumber).
fixtostr( fixed:fNumber, sNumber[], iMaxLength );
fixed:fNumber
Typ: Fixed (-2147482 - 2147482)
string
Typ: String (20)
iMaxLength
Typ: Integer (0 - 20)
Die Funktion fixtostr wandelt eine Festkommazahl in einen String um.
Beispiel aus plugin_sdal_logd_hp50
(Funktion: display_victim):
723 if(g_display_distance){
724 new Meters[MAX_NUMBER_LENGTH];
725 fixtostr(fixed:g_PlayerEnemyDistance[UserID],Meters,MAX_NUMBER_LENGTH);
Wenn die Entfernung zum Gegner nach dem eigenen Ableben angezeigt werden soll, wird
zunächst die gespeicherte Entfernung (g_PlayerEnemyDistance[UserID]) in einen String
umgewandelt (Meters). Die Textausgabe erfolgt später im Code.
format_command( sUser[],sCommand[],sData[],sText[] );
sUser[]
Typ: String (33)
sCommand[]
Typ: String (30)
sData[]
Typ: String (200)
sText[]
Typ: String (200)
Die Funktion bereitet einen Text zur Darstellung im Chat oder in den Logdateien auf, wenn
ein Admin Mod Befehl ausgeführt wird. Dazu muss der ausführende Admin (sUser), der
ausgeführte Befehl (sCommand) und die Parameter (sData) angegeben werden. Die Rückgabe
erfolgt über sText.
Die Funktion wird üblicherweise nicht allein eingesetzt, da sie eine Unterfunktion von
log_command und say_command ist.
Beispiel aus adminlib.inc (Funktion: format_command):
320 stock log_command(sUser[],sCommand[],sData[]) {
321 new sText[MAX_TEXT_LENGTH];
322 format_command(sUser,sCommand,sData,sText);
323 log(sText);
324 }
Username (sUser), der aufgerufende Befehl (sCommand) und die zugehörigen Parameter
(sData) werden an format_command übergeben, der formatierte Text (sText) geloggt.
fround( fixed:value, fround_method:method=fround_round );
fixed:value
Typ: Fixed (-2147482 - 2147482)
fround_method:method=fround_round
Typ: Enum (0=fround_round, fround_floor, fround_ceil)
Diese Funktion rundet eine Festkommazahl. Sie wird als Integer ausgegeben. Es gibt drei
verschiedene Methoden zum Runden. Die Methode fround_round rundet ab 0,5 auf und
darunter ab, bei fround_floor wird grundsätzlich abgerundet, bei fround_ceil wird
aufgerundet.
Beispiel aus math.inc (Funktion: fixtostr):
20 if(fNumber<0.000){
21 iNumber=fround(fNumber,fround_ceil);
22 }
23 else{
24 iNumber=fround(fNumber,fround_floor);
25 }
Wenn die Zahl fNumber negativ ist, wird aufgerundet, wenn sie positiv ist, wird
abgerundet.
funcidx( const name[] );
const name[]
Typ: String (20)
Die Funktion liefert den interen Index einer öffentlichen Funktion. Wird die angegebene
Funktion nicht gefunden, gibt funcidx -1 zurück.
Ein sinnvoller Einsatz unter Admin Mod ist nicht gegeben.
Beispiel:
iID=funcidx(“admin_ban”);
Im Beispiel wird die interne ID der Funktion admin_ban aus dem Base Plugin
ausgegeben.
get_serverinfo( sKey[], sValue[], iMaxLength );
sKey[]
Typ: String (100)
sValue[]
Typ: String (200)
iMaxLength
Typ: Integer (0 - 200)
Die Funktion liest die Daten (sValue), die mit dem Schlüssel (sKey) hinterlegt wurden, aus.
Der Schlüssel und die Daten werden mit set_serverinfo gesetzt. Die Daten werden beim
Mapwechsel nicht gelöscht. Der Speicher ist jedoch nur sehr gering bemessen, so dass die
Verwendung dieser Funktion vermieden werden sollte.
Beispiel aus plugin_bk_cron
(Funktion: lag_check):
463 get_serverinfo("last_cron",slastcheck,3);
464 lastcheck=strtonum(slastcheck);
Der Inhalt des Schlüssels (last_cron) wird ausgelesen und mit einer maximalen Länge von 3 in
die Variable slastcheck geschrieben. Der String wird anschließend in eine Ganzzahl
umgewandelt. Auf diese Art und Weise kann insbesondere überprüft werden, wie lang der
letzte Durchlauf vor dem Mapwechsel her ist. Beim Serverstart ist die Variable noch nicht
gesetzt, so dass 0 zurückgegeben wird. Die Nutzung der vault.ini verbietet sich, da der
Wert beim Beenden bzw. Absturz des Servers nicht automatisch auf 0 zurückgesetzt
wird.
get_timer( iTimer );
iTimer
Typ: Integer (0 - 511)
Die Funktion get_timer gibt den Status eines Timers aus (läuft (1), läuft nicht (0), gehört
nicht dem Plugin (-1))
Beispiel:
if (get_timer(iTimer)) {
kill_timer(iTimer);
}
Nur wenn der Timer mit dem Index (iTimer) aktuell läuft und dem eigenen Plugin gehört,
wird der Timer gestoppt (kill_timer).
get_userArmor( sPlayer[], &armor );
sPlayer[]
Typ: String (33)
&armor
Typ: Integer (0 - 2147483647)
Die Funktion liefert den momentanen Wert der Rüstung des Spielers als Integerwert (armor)
zurück.
Beispiel aus plugin_sdal_logd_hp50
(Funktion: hp_kill):
441 playerinfo(iAID,Attacker,MAX_NAME_LENGTH,_,_,iATeam);
442 playerinfo(iVID,Victim,MAX_NAME_LENGTH,_,_,iVTeam);
443
444 get_userHealth(Attacker, iAHealth);
445 get_userArmor(Attacker, iAArmor);
Die Spielernamen des Angreifers und des Opfers sowie deren Teamzugehörigkeit werden über
playerinfo ermittelt. Nicht benötigte Variablen werden durch Unterstriche von der
Verarbeitung ausgeklammert. Diese Methode sollte nur auf Admin Mod 2.60.42 und
neuer angewendet werden, da es schon einmal Probleme mit Memory Leaks gegeben
hat.
Anschließend werden die verbleibenden Lebens- und Rüstungspunkte des Angreifers zur
späteren Anzeige beim Opfer ausgelesen.
get_userAuthID( sPlayer[], sAuthid[], iMaxLength = MAX_AUTHID_LENGTH
);
sPlayer[]
Typ: String (33)
sAuthid[]
Typ: String (39)
iMaxLength = MAX_AUTHID_LENGTH
Typ: Integer (0 - 39)
Die Funktion liefert die Steam ID des angegebenen Spielers (sPlayer) und speichert diese als
String (sAuthid). Sollte es sich um einen Bot handeln, dann wird BOT als AuthID
zurückgeliefert. Die Länge des Strings muss nicht angegeben werden, bzw. sollte stets gleich
MAX_AUTHID_LENGTH (39) sein.
Beispiel aus plugin_base.inc (Funktion: admin_vote_kick):
625 get_userAuthID(real_user,sAuthID);
626 if (vote(Text,"Yes","No","HandleKickVote",sAuthID)) {
627 g_VoteInProgress = 1;
628 g_AbortVote = 0;
629 }
Es wird die AuthID (i.d.R. die Steam ID) eines Spielers (real_user) ermittelt. Ein Vote zum
Kicken des Spielers wird angestoßen, wobei der späteren Voteauswertung die AuthID
mitgeliefert wird. Des Weiteren werden 2 globale Variablen gesetzt, wenn der Vote erfolgreich
abgesetzt wurde.
get_userFrags( sPlayer[], &frags );
sPlayer[]
Typ: String (33)
&frags
Typ: Integer (0 - 2147483647)
Die Funktion liefert die Anzahl der Frags (frags) des Spieler (sPlayer) über die gesamte
Mapzeit als Integerwert.
Beispiel aus plugin_sdal_logd_hp50
(Funktion: best_player):
994 for(j=1;j<=maxplayers;j++){
995 if(playerinfo(j,Player,MAX_NAME_LENGTH)){
996 get_userFrags(Player,PlayerPoints[j]);
997 if(PlayerPoints[j]>mostfrags){
998 mostfrags=PlayerPoints[j];
999 }
1000 }
1001 }
Mittels einer For-Schleife soll der Spieler mit den meisten Frags ermittelt werden. Die
For-Schleife überprüft alle Slots. Nur Slots, die mit Spielern bestückt sind, werden ausgewertet
(Zeile 995). Wurde ein Spieler gefunden, werden seine Frags (get_userFrags) ermittelt. Falls
die Anzahl seiner Frags größer als der bisherige Bestwert sind, wird die Anzahl seiner Frags
zum neuen Bestwert.
get_userHealth( sPlayer[], &health );
sPlayer[]
Typ: String (33)
&health
Typ: Integer (0 - 2147483647)
Die Funktion liefert die momentanen Lebenspunkte des Spielers als Integerwert.
Beispiel aus plugin_sdal_logd_hp50
(Funktion: hp_kill):
441 playerinfo(iAID,Attacker,MAX_NAME_LENGTH,_,_,iATeam);
442 playerinfo(iVID,Victim,MAX_NAME_LENGTH,_,_,iVTeam);
443
444 get_userHealth(Attacker, iAHealth);
445 get_userArmor(Attacker, iAArmor);
Die Spielernamen des Angreifers und des Opfers sowie deren Teamzugehörigkeit werden über
playerinfo ermittelt. Nicht benötigte Variablen werden durch Unterstriche von der
Verarbeitung ausgeklammert. Diese Methode sollte nur auf Admin Mod 2.60.42 und
neuer angewendet werden, da es schon einmal Probleme mit Memory Leaks gegeben
hat.
Anschließend werden die verbleibenden Lebens- und Rüstungspunkte des Angreifers zur
späteren Anzeige beim Opfer ausgelesen.
get_userindex( sPlayer[], &iIndex );
sPlayer[]
Typ: String (33)
&iIndex
Typ: Integer (0 - 32)
Die Funktion liefert auf Basis des Spielernamens seinen UserIndex (Server-Slot) als
Integerwert.
Beispiel aus plugin_retribution (Funktion: admin_bury):
499 get_userindex(Data, nIndex);
500 playerinfo(nIndex, TargetName, MAX_NAME_LENGTH, _, _, _, nDead);
Der Status eines Spielers (lebend oder tot) lässt sich mit Admin Mod nur mit der Funktion
playerinfo ermitteln. Da sie den Userindex benötigt, muss zunächst aus dem Namen (Data)
der Userindex (nIndex) ermittelt werden. Anschließend kann der Status abgefragt werden.
TargetName ist eigentlich nicht notwendig, ist jedoch eine Pflichtrückgabe. Auf die
weiteren Variablen kann verzichtet werden. Als Auslassungszeichen wird der Unterstrich
verwendet.
get_userinfo( sPlayer[], sKey[], sInfo[], iMaxLength );
sPlayer[]
Typ: String (33) max. Länge: 100
sKey[]
Typ: String (100)
sInfo[]
Typ: String (200)
iMaxLength
Typ: Integer (0 - 200)
Mit der Funktion get_userinfo lassen sich einige wenige Usereinstellungen abfragen. Diese
Daten werden oftmals mit setinfo angelegt. Die Funktion benötigt einen Schlüssel (sKey),
dessen Daten (sInfo) ausgelesen werden können. Um mögliche Schlüssel zu ermitteln, kann
man den Serverbefehl user <username / Session ID> auf einen bestimmten Spieler
anwenden.
Der für diese Usereinstellungen zur Verfügung gestellte Speicher ist extrem klein. Statsme
schaffte es in der Vergangenheit mit seinen Usereinstellungen die Admin Mod Anmeldung
unmöglich zu machen. Die Fehlermeldung „info string length exceeded“ zeigte dann, dass der
geringe Speicher gänzlich aufgebraucht war.
Man kann mit der Funktion execclient und dem Setzen von setinfo Usereinstellungen
verankern, man sollte dies aber unter allen Umständen vermeiden, sofern es nicht einer
übergeordneten Aufgabe zuträglich ist. Mehr zu diesem Thema ist dem Abschnitt Was macht
eigentlich Setinfo? zu entnehmen.
Beispiel aus plugin_bk_hltvannounce
(Funktion: a_hltv):
56 get_userinfo(hltvname,hspecs,hltvspecs,MAX_NAME_LENGTH);
57 get_userinfo(hltvname,hslots,hltvslots,MAX_NAME_LENGTH);
58 get_userinfo(hltvname,hdelay,hltvdelay,MAX_NAME_LENGTH);
59 get_userIP(hltvname,hltvip,MAX_IP_LENGTH,iPort);
Das erste get_userinfo ruft die belegten Slots des HLTV-Servers, das zweite die maximale
Slotzahl und das dritte den eingestellten Delay in Sekunden ab. Die Variablennamen der
Schlüsselnamen stimmen mit ihrem Inhalt überein (hspecs z.B. hat den Inhalt „hspecs“).
Anschließend wird noch die IP-Adresse des HLTVs ermittelt (get_userIP).
get_userIP( sPlayer[], sIP[], iMaxLength, &iPort = 0 );
sPlayer[]
Typ: String (33)
sIP[]
Typ: String (22)
iMaxLength Typ: Integer (0 - 22)
&iPort = 0 Typ: Integer (0 - 65535)
Diese Funktion liefert die IP des Spielers als String (sIP) auf Basis des Namens (sPlayer).
Neben der IP wird auch der genutzte Port (iPort) ausgegeben.
Beispiel aus plugin_bk_hltvannounce
(Funktion: hltvconnect):
205 get_userIP(hltvname,hltvip,MAX_IP_LENGTH,iPort);
206 get_userinfo(hltvname,hslots,hltvinfo,MAX_NAME_LENGTH);
207 ihltv=strtonum(hltvinfo);
208 get_userinfo(hltvname,hspecs,hltvinfo,MAX_NAME_LENGTH);
209 ihltv-=strtonum(hltvinfo);
Zunächst wird die IP des HLTV-Servers ermittelt. Anschließend werden die genutzte und die
maximale Slotzahl ermittelt. Aus der Subtraktion ergibt sich die Anzahl der freien Plätze auf
dem HLTV-Server.
get_username( sPlayer[], sName[], iMaxLength );
sPlayer[]
Typ: String (33)
sName[]
Typ: String (33)
iMaxLength
Typ: Integer (0 - 33)
Mit dieser Funktion kann aus einem Teil des Spielernamens der gesamte Name ermittelt
werden, sofern der Teil des Namens eindeutig ist. D.h. der Teil darf nicht gleichzeitig Teil des
Namens eines anderen Spielers sein. Statt des Teilnamens kann auch die IP, Steam ID oder
Session ID angegeben werden.
Beispiel aus plugin_base (Funktion: admin_vote_kick):
612 get_username(Data,real_user,MAX_NAME_LENGTH);
613 say_command(User,Command,Data);
614 if(check_immunity(real_user)!=0) {
Aus Data (ob Teil-/Name, IP oder ID) wird der vollständige Spielername ermittelt. Den
Einstellungen admin_quiet folgend wird die Ausführung des Befehls im Chat kommentiert
(say_command). Anschließend wird über die Funktion check_immunity überprüft, ob einer
Spieler dieses Namens Immunitätsrechte besitzt.
get_userorigin( sPlayer[], &iX, &iY, &iZ );
sPlayer[]
Typ: String (33)
&iX
Typ: Integer (-2147483648 - 2147483647)
&iY
Typ: Integer (-2147483648 - 2147483647)
&iZ
Typ: Integer (-2147483648 - 2147483647)
Die Funktion gibt die Position des angegebenen Spielers (sPlayer) auf der Map zurück. Die
Rückgabe erfolgt in kartesischen Koordinaten (x, y, z).
Beispiel aus plugin_retribution (Funktion: admin_bury):
507 get_userorigin(TargetName, x, y, z);
508 teleport(TargetName, x, y, (z-25));
Zunächst werden die Koordinaten des Spielers (TargetName) ermittelt. Anschließend wird er
um 25 Einheiten tiefer gesetzt (teleport). Sofern sich der Spieler zu diesem Zeitpunkt nicht
hoch in der Luft befindet, wird er in den Boden versetzt, so dass er sich nicht mehr bewegen
kann.
get_userSessionID( sPlayer[], &iSessionID );
sPlayer[]
Typ: String (33)
&iSessionID
Typ: Integer (0 - 2147483647)
Liefert die Session ID des Spielers als Integerwert zurück. Die Session ID ist eindeutig und
wird während der gesamten Laufzeit des Servers nur einmal vergeben. Die Nutzung der
Session ID für Plugins ist eher ungewöhnlich, da sie nur über get_username in einen Namen
umgewandelt werden kann.
Beispiel aus plugin_spooge_AR
(Funktion: HandleSay):
334 new SessionID;
335 get_userSessionID (User,SessionID);
336 numtostr(SessionID,CmdBuffer);
337 plugin_exec("admin_slap",CmdBuffer);
Die Session ID wird aus dem Spielernamen (User) ermittelt und anschließend von einer
Ganzzahl in einen String umgewandelt (numtostr). Abschließend wird die Session ID an den
Admin Mod Befehl admin_slap weitergeleitet (plugin_exec)
get_userTeam( sPlayer[], &team );
sPlayer[]
Typ: String (33)
&team
Typ: Integer (0 - 4, 500, 600)
Die Funktion ermittelt die Team ID des Spielers (sPlayer). Die Teamzugehörigkeit kann auch
über die Funktion playerinfo ermittelt werden.
Sonderteams sind kein Team (0), Spectator (500) und HLTV (600). Verschiedene
Modifikationen haben unterschiedliche Teams:
|
|
|
|
|
Mod | Team 1 | Team 2 | Team 3 | Team 4 |
|
|
|
|
|
CS | Terrorist | Counter-Terrorist | - | VIP |
TFC | Team Blau | Team Rot | Team Gelb | Team Grün |
DoD | Axis | Allies | - | - |
|
|
|
|
|
|
Beispiel aus plugin_CS (Funktion: menuselect):
1512 new Team;
1513 get_userTeam(UserName,Team);
1514 Team = clamp(Team,1,2) - 1;
Zunächst wird das Team des Spielers ermittelt. Anschließend wird zur Vermeidung einer
Feldadressierung außerhalb des gültigen Bereichs (4 - AMX_ERR_BOUNDS) die möglichen
Teams auf 1 und 2 begrenzt. Zur weiteren Bearbeitung werden die Teamnummern
dekrementiert.
get_userWONID( sPlayer[], &iWONID );
sPlayer[]
Typ: String (33)
&iWONID
Typ: Integer (0 - 2147483647)
Die Funktion gibt die WONID (iWONID) des Spielers (sPlayer) als Integerwert zurück. Da das WON-System
von Valve inzwischen
durch Steam
ersetzt wurde, ist die Funktion nutzlos geworden. Statt dessen sollte get_userAuthID genutzt
werden.
Beispiel aus plugin_sdal_look
(Funktion: ann_timer):
246 get_userWONID( Player, iWon );
247
248 if(iWon!=0){
249 numtostr(iWon,strWON);
Auf Basis des Spielernamens (Player) wird seine WONID (iWon) ermittelt. Falls die WONID
nicht 0 ist, wird sie in einen String umgewandelt.
get_vaultdata( sKey[], sData[], iMaxLength );
sKey[]
Typ: String (100)
sData[]
Typ: String (200)
iMaxLength
Typ: Integer (0 - 200)
Die Funktion liest die Daten, die unter dem Schlüssel (sKey) stehen, als String (sData) aus der
vault.ini aus. Die Daten bleiben über einen Mapchange bzw. einen Serverneustart erhalten.
Das Schlüssel-Daten-Paar wird mit set_vaultdata oder set_vaultnumdata angelegt. Die
Funktion ist ideal um pluginspezifische Einstellungen zu speichern.
Weiß man bereits, dass die ausgelesenen Daten als Ganzzahl vorliegen, sollte man der
Funktion get_vaultnumdata den Vorzug geben.
Beispiel aus plugin_retribution (Funktion: AddUserFlag):
69 if(get_vaultdata(sAuthID,VaultData,MAX_DATA_LENGTH) != 0) {
70 if (strcasestr(VaultData," llama") == -1) {
71 strcat(VaultData," llama", MAX_DATA_LENGTH);
72 set_vaultdata(sAuthID,VaultData);
73 }
Es wird versucht den Schlüssel mit der Steam ID des Spielers zu finden. Ist dies der Fall, wird
das Ergebnis in VaultData zwischengespeichert. Falls das Ergebnis nicht bereits den Teilstring
„ llama“ beinhaltet, wird dies dem Ergebis angehängt (strcat) und zurück in die vault.ini
geschrieben.
get_vaultnumdata( sKey[], &iData );
sKey[]
Typ: String (100)
&iData
Typ: Integer (-2147483648 - 2147483647)
Die Funktion liest die Daten, die unter dem Schlüssel (sKey) stehen, als Ganzzahl
(iData) aus der vault.ini aus. Die Daten bleiben über einen Mapchange bzw. einen
Serverneustart erhalten. Das Schlüssel-Daten-Paar wird mit set_vaultdata oder
set_vaultnumdata angelegt. Die Funktion ist ideal um pluginspezifische Einstellungen zu
speichern.
Ist im Schlüssel ein String hinterlegt, darf man die Funktion nicht anwenden. Statt dessen ist
get_vaultdata zu verwenden.
Beispiel aus plugin_bk_botmanager
(Funktion: addbot):
150 if(get_vaultnumdata("BK_BM_BOTS",iBots) && iBots<=playercount()){
151 return PLUGIN_CONTINUE;
152 }
Der Schlüssel BK_BM_BOTS wird ausgelesen und die Daten in iBots geschrieben. Wenn der
Schlüssel vorhanden und iBots kleiner gleich der Spieleranzahl ist, wird die Ausführung der
Funktion addbot gestoppt und somit kein weiterer Bot hinzugefügt.
getarg( arg, index=0 );
arg
Typ: Integer
Wertebreich: (0 - 2147483647)
index=0
Typ: Integer (0 - 2147483647)
Diese Funktion wird nur Fällen gebraucht, wenn man die Argumente einer Funktion mit
variabler Argumentanzahl auslesen möchte. Dabei gibt „arg“ die Position des Arguments
beginnend mit 0 an. Das Argument „index“ wird nur benötigt, wenn arg ein Feld (z.B. ein
String) ist. Es gibt die auszulesende Zelle des Feldes an.
Beispiel:
sum(...){
new result = 0 ;
for (new i = 0; i < numargs(); ++i) {
result += getarg(i);
}
return result;
}
Eine Funktion „sum“ mit variabler Argumentanzahl (...) wird definiert. Eine For-Schleife fragt
die einzelnen Argumente ab und addiert sie. Die Summe wird zurückgegeben. Die Anzahl der
übergebenen Argumente wird mit numargs ermittelt.
getchar( echo=true );
echo=true
Typ: Integer (0 - 1)
Diese Funktion liest die Tastatureingabe eines Zeichens aus und schreibt es bei der Option 1 in
die Befehlszeile zurück. Mangels einer solchen Befehlszeile ist die Funktion in Admin Mod
nutzlos.
getproperty( id=0, const name[]=“”, value=cellmin, string[]=“” );
id=0
Typ: Integer (-2147483648 - 2147483647)
const name[]=“”
Typ: String (variabel)
value=cellmin
Typ: Integer (-2147483648 - 2147483647)
const string[]=“”
Typ: String (variabel)
Mit dieser Funktion kann eine sogenannte Property bei gegebenem Schlüssel (name oder
value) ausgelesen werden. Die Property wird als String im Speicher abgelegt. Es handelt sich
um eine Funktion, deren Benutzung unter Admin Mod vermieden werden sollte.
Stattdessen wird empfohlen z.B. auf die Funktionen get_vaultdata oder set_vaultdata
zurückzugreifen.
Mehr Informationen zum Thema sind im Abschnitt 8.14 nachzulesen.
Beispiel:
getproperty(2,“test_prop”,sString);
getproperty(3,15,sString);
Das erste Beispiel liest die in ID 2 befindliche Property „test_prop“ in die Variable sString
aus, während das zweite Beispiel die in ID 3 befindliche Property 15 ausliest.
getstring( string[], size=sizeof string, bool:pack=false );
string
Typ: String (200)
size=sizeof string
Typ: Integer (0 - 200)
bool:pack=false
Typ: Integer (0 - 1)
Diese Funktion liest die Tastatureingabe komplett als String aus. Mit bool:pack kann
definiert werden, ob der String gepackt oder ungepackt erwartet und ausgelesen wird.
Mangels einer Befehlszeile für diese Tastatureingabe ist die Funktion in Admin Mod
nutzlos.
getstrvar( sVarname[], sValue[], iMaxLength );
sVarname[]
Typ: String (100)
sValue[]
Typ: String (200)
iMaxLength
Typ: Integer (0 - 200)
Mit der Funktion kann man eine Servervariable (sVarname) als String (sValue) auslesen.
Beispiel aus plugin_base (Funktion: admin_pass):
344 new sPasswd[MAX_NAME_LENGTH];
345 getstrvar( "sv_password", sPasswd, MAX_NAME_LENGTH );
346 snprintf(Text, MAX_TEXT_LENGTH, "The password is: %s.", sPasswd);
347 selfmessage(Text);
Die Servervariable „sv_password“ wird in sPasswd ausgelesen, formatiert (snprintf) und
anschließend beim Spieler, der den Befehl ausgeführt hat, ausgegeben.
gettarget( sPlayer[], sTargetName[], iMaxLength, iRange = 2048 );
sPlayer[]
Typ: String (33)
sTargetName[]
Typ: String (33)
iMaxLength
Typ: Integer (0 - 33)
iRange = 2048
Typ: Integer (0 - 2147483647)
Mit dieser Funktion kann man ermitteln, auf welchen Gegner (sTargetName) der Spieler
(sPlayer) zielt. Sie gibt auch den Userindex des Spielers direkt zurück. Das Argument iRange
definiert die Blickweite.
Beispiel aus plugin_blatt_monster
(Funktion: BBMonsterSpawn):
430 if (strlen(TargetName) ==0) {
431 gettarget(UserName,TargetName,MAX_DATA_LENGTH);
432 if (strlen(TargetName) ==0) {
433 return PLUGIN_HANDLED;
434 }
435 }
Wenn kein Spieler angegeben wurde, wird überprüft, auf welchen Spieler der Admin schaut.
Schaut er niemanden an, bricht das Plugin die Ausführung ab.
getteamcount( iTeam );
&team
Typ: Integer (0 - 4, 500, 600)
Die Funktion ermittelt die Anzahl der Spieler eines Teams auf Basis der Team ID
(iTeam).
Sonderteams sind kein Team (0), Spectator (500) und HLTV (600). Verschiedene
Modifikationen haben unterschiedliche Teams:
|
|
|
|
|
Mod | Team 1 | Team 2 | Team 3 | Team 4 |
|
|
|
|
|
CS | Terrorist | Counter-Terrorist | - | VIP |
TFC | Team Blau | Team Rot | Team Gelb | Team Grün |
DoD | Axis | Allies | - | - |
|
|
|
|
|
|
Beispiel aus plugin_bk_botmanager
(Funktion: addbot):
144 new iTplayers=getteamcount(TERROR);
145 new iCTplayers=getteamcount(CT);
Die Variablen iTplayers und iCTplayers werden deklariert und gleichzeitig mit der Spielerzahl
des jeweiligen Teams gefüllt. Dabei sind TERROR und CT jeweils Konstanten (1
bzw. 2).
getvalue( base=10, end=’^r’, ... );
base
Typ: Integer (2 - 32)
end
Typ: String (1)
Diese Funktion liest die Tastatureingabe als Ganzzahl aus. Dabei kann die Basis (base)
definiert werden, sowie Abschlusszeichen für die Eingabe. Mangels einer Befehlszeile für diese
Tastatureingabe ist die Funktion in Admin Mod nutzlos.
getvar( sVarname[] );
sVarname[]
Typ: String (100)
Mit der Funktion kann man eine Servervariable (sVarname) als Ganzzahl auslesen.
Beispiel aus plugin_CS (Funktion: HandleKickVote):
648 new Ratio = getvar("kick_ratio");
649 if (VoteCount >= Ratio*UserCount/100) {
650 if (g_AbortVote) {
651 say("Kick vote was aborted by an admin");
652 } else {
653 set_timer("KickUser",10,1,VoteUser);
654 }
Die Servervariable „kick_ratio“ wird als Ganzzahl in Ratio ausgelesen. Falls genügend
Stimmen für den Kick zusammengekommen sind, wird entweder der Kick abgebrochen, weil
ein Admin ihn aufgehalten hat, oder nach 10 Sekunden der entsprechende Spieler vom Server
geworfen.
glow( sTarget[], iRed = 0, iGreen = 0, iBlue = 0 );
sTarget[]
Typ: String (33)
iRed = 0
Typ: Integer (0 - 255)
iGreen = 0
Typ: Integer (0 - 255)
iBlue = 0
Typ: Integer (0 - 255)
Die Funktion lässt den Spieler sTarget in einer Farbe leuchten. Die Farbanteile werden über
RGB (Rot, Grün, Blau) angegeben. Das Glühen wird abgeschaltet, indem alle Farbwerte auf 0
gesetzt werden.
Beispiel aus plugin_fun (Funktion: GlowHelper):
82 GlowHelper(User[], Color[]) {
83 new iGoodColor = 1;
84
85 if (streq(Color,"red")==1) {
86 glow(User,250,10,10);
87 } else if ( streq(Color, "blue")==1) {
88 glow(User,10,10,250);
89 } else if ( streq(Color, "green")==1) {
90 glow(User,10,250,10);
91 } else if ( streq(Color, "white")==1) {
92 glow(User,250,250,250);
93 } else if ( streq(Color, "yellow")==1) {
94 glow(User,250,250,10);
95 } else if ( streq(Color, "purple")==1) {
96 glow(User,250,10,250);
97 } else if ( streq(Color, "off")==1) {
98 glow(User,0,0,0);
99 } else {
100 iGoodColor = 0;
101 }
102 return iGoodColor;
103 }
Die Funktion GlowHelper wandelt Farben, die in einem String (Color) übergeben werden, in
einen RGB-Wert um und lässt den entsprechenden Spieler (User) in dieser Farbe glühen. Bei
„off“ wird das Glühen abgeschaltet. Ist die übergebende Farbe nicht definiert gibt die
Funktion einen Fehlerwert (iGoodColor) zurück.
godmode( sPlayer[], iOnOff );
sPlayer[]
Typ: String (33)
iOnOff
Typ: Integer (0 - 1)
Die Funktion macht den Spieler (sPlayer) unverwundbar, wenn man als iOnOff eine 1
übergibt. Mit 0 stellt man den Godmode wieder aus. Es wird eine Nachricht allen Spielern auf
dem Server angezeigt, dass der Spieler diese Fähigkeit erhalten hat. Diese Nachricht kann
nicht ausgeschaltet werden!
Beispiel aus plugin_cheat (Funktion: admin_godmode):
61 if (check_user(strGodModeUser)==1) {
62 say_command(User,Command,Data,1);
63 godmode(strGodModeUser,iGodMode);
64 } else {
65 selfmessage("Unrecognized player: ");
66 selfmessage(strGodModeUser);
67 }
Wenn der entsprechende Spieler (strGodModeUser) auf dem Server ist, wird die Verwendung
des Godmodes bekannt gegeben. Aber auch ohne say_command wird eine Meldung an alle
Spieler abgesetzt. Da hier erheblich in die Spielmechanik eingegriffen wird, kann die Meldung
nicht unterdrückt werden. Anschließend wird der Godmode für den entsprechenden Spieler
ausgeführt.
Ist der Spieler nicht auf dem Server, wird das dem aufrufenden Admin in der Console
mitgeteilt.
heapspace( );
Die Funktion gibt die Größe des freien Heap-Speichers in Zellen zurück.
Diese Funktion wird verwendet, um Speicherlöcher in Scripten aufzuspüren. Speicherlöcher
sind Fehler im Programm, die den verwendeten Speicher immer weiter anwachsen
lassen, bis keiner mehr zur Verfügung steht und die Scriptausführung mit dem Fehler
AMX_ERR_STACKERR beendet werden muss.
Üblicherweise liegt der Fehler allerdings nicht am Script selber, sondern am Wirtsprogramm
(= Adminmod). Der Stack und der Heap belegen einen gemeinsamen Speicherbereich im
Script, in dem dynamische Daten abgelegt werden (z.B. Funktionsparameter, lokale
Variablen). Die Größe dieses Speicherbereiches kann durch die Präprozessordirektive #pragma
dynamic n verändert werden, wobei n die Größe in Zellen ist. Die Standardgröße ist 2048
Zellen.
Beispiel aus plugin_blatt_map
(Funktion: DebugHeap):
3641 DebugHeap(context[]) {
3642 if (g_DebugLevel >= 2) {
3643 new heapsize[MAX_TEXT_LENGTH];
3644 snprintf(heapsize,MAX_TEXT_LENGTH,"[%s] %i free bytes.",context,heapspace());
3645 plugin_message(heapsize);
3646 }
3647 return 0;
3648 }
Wenn der in der globalen Variable (g_DebugLevel) Debuglevel größer oder gleich zwei ist,
wird der noch verbleibende Heap-Speicher ermittelt und mittels plugin_message in der
Console (Spieler- oder Serverconsole) ausgegeben.
help( sKeyword[]);
sKeyword[]
Typ: String (100)
Diese Funktion ist veraltet und wird nicht mehr in Scripts verwendet.
Wenn früher in der adminmod.cfg ein help_file gesetzt wurde, konnte man z.B. per Script
help(“vote”) ausführen, um sich alle Beschreibungen zu „vote“ in der Konsole anzeigen zu
lassen. Wenn kein Schlüsselwort (sKeyword) angegeben wurde, wurden alle Funktionen
angezeigt.
Die Funktionalität wurde durch den direkten Admin Mod Befehl admin_help und die
Funktionen plugin_registercmd und plugin_registerhelp ersetzt.
index( sSource[], iChar );
sSource[]
Typ: String (200)
iChar
Typ: Integer (0 - 256)
Die Funktion ermittelt die Position des ersten Vorkommens des Zeichens (iChar) im String
(sSource) von links beginnend. Für das Zeichen muss die ASCII-Nummer angegeben werden.
Vereinfacht kann auch das entsprechende Zeichen in einfache Anführungszeichen
gesetzt werden. Die Funktion liefert -1 zurück, falls das Zeichen nicht gefunden
wurde.
Die Funktion ist ein Alias für strchr.
Beispiel aus plugin_blatt_map
(Funktion: ReadMapLine):
3004 pos=index(Line,’ ’);
3005 if (pos>0) {
3006 Line[pos]=NULL_CHAR;
3007 }
3008
Es wird das erste Leerzeichen von links in Line gesucht. Wurde ein Leerzeichen gefunden, wird
es durch ein String-Endzeichen (NULL_CHAR) ersetzt. Alle Funktionen, die den String von
links zu lesen beginnen, werden an dieser Stelle beendet. Beginnt man von rechts, werden die
Zeichen hinter dem String-Endzeichen zuerst gelesen. Man sollte daher genau wissen, was man
tut, wenn man ein String-Endzeichen manuell setzt. Die Verwendung von strsep wäre eine
Alternative.
8.10.101 kick
kick( sPlayer[] );
sPlayer[]
Typ: String (33)
Die Funktion wirft den Spieler (sPlayer) vom Server.
Beispiel aus plugin_base (Funktion: admin_kick):
272 if (strlen(Reason) != 0) {
273 snprintf(Text, MAX_TEXT_LENGTH, "You have been kicked because %s", Reason);
274 message(real_user, Text);
275 }
276 kick(real_user);
Es wird überprüft, ob ein Grund für den Kick angegeben wurde. Wenn es der Fall ist, wird
dies dem Spieler mitgeteilt (message). Anschließend wird der Spieler vom Server
geworfen.
kill_timer( iTimer );
iTimer
Typ: Integer (0 - 512)
Mit dieser Funktion kann man einen laufenden Timer abbrechen. Dafür wird der Timer-Index
(iTimer) benötigt, den man beim Ausführen des Timers set_timer zurückgeliefert
bekommt. Es können nur Timer abgebrochen werden, die vom selben Plugin ausgeführt
wurden.
Beispiel aus plugin_fun (Funktion: KillDisco):
122 for (i = 1; i <= iMaxPlayers; i++) {
123 if(playerinfo(i,Name,MAX_NAME_LENGTH)==1) {
124 glow(Name,0,0,0);
125 }
126 }
127 centersay("Disco . . . Is Dead.",10,0,255,0);
128 kill_timer(iDiscoTimer);
Alle Plätze des Servers werden überprüft. Falls ein Platz durch einen Spieler belegt wird, wird
ein eventuelles Glühen abgestellt. Eine zehnsekündige Nachricht in Grün verkündet,
dass Disco tot ist. Anschließend wird der Discotimer mit dem Index iDiscoTimer
abgebrochen.
list_maps( );
Die Funktion zeigt dem ausführenden Spieler alle Maps aus der mapcycle.txt in der
Console.
Beispiel aus plugin_base (Funktion: admin_listmaps):
122 selfmessage("The maps on the mapcycle are:");
123 list_maps();
124 selfmessage("and the current map is:");
125 currentmap(curmap,100);
126 selfmessage(curmap);
Es wird eine Überschrift für die zur Verfügung stehenden Maps im Cycle in der Console
ausgegeben. Es folgt die Ausgabe dieser Maps und die Überschrift für die aktuelle Map. Die
aktuelle Map wird ermittelt und in der Console ausgegeben.
listspawn( sClass[] );
sClass[]
Typ: String (100)
Die Funktion gibt alle Items an, die gespawned wurden. Man kann aber auch nur nach einem
Teil (sClass) suchen.
Die Funktionalität steht mittlerweile nicht mehr zur Verfügung.
Beispiel aus plugin_spawn (Funktion: admin_listspawn):
61 convert_string(HLData,Data,MAX_DATA_LENGTH);
62 listspawn(Data);
Der Suchtext wird von einem HL- in einen Small-String konvertiert (convert_string).
Anschließend werden die in das Muster fallenden Items in der Console angezeigt.
8.10.105 log
log( sLogEntry[] );
sLogEntry[]
Typ: String (256)
Mit dieser Funktion können Daten (sLogEntry) in die Logdateien geschrieben werden.
Beispiel aus plugin_base (Funktion: plugin_init):
870 currentmap(strMap, MAX_DATA_LENGTH);
871 snprintf(ExecCommand, MAX_DATA_LENGTH, "%s.cfg", strMap);
872 if ( fileexists(ExecCommand) ) {
873 snprintf(ExecCommand, MAX_DATA_LENGTH, "exec %s.cfg", strMap);
874 log(ExecCommand);
875 exec(ExecCommand);
876 }
Es wird die aktuelle Map ermittelt und überprüft, ob sich im Modverzeichnis eine
Konfiguartionsdatei für diese spezielle Map befindet. Existiert die Datei, wird sie ausgeführt.
Dies ist eine oftmals übersehene Funktion Admin Mods, die der Basisfunktionalität des
HL-Servers zugeschlagen wird.
Unter anderem wird der ausgeführte Befehl in die Logdateien geschrieben (Zeile
874).
log_command( sUser[],sCommand[],sData[] );
sUser[]
Typ: String (33)
sCommand[]
Typ: String (30)
sData[]
Typ: String (200)
Die Funktion schreibt einen formatierten Text in die Logdateien. Dazu muss der ausführende
Admin (sUser), der ausgeführte Befehl (sCommand) und die Parameter (sData)
angegeben werden. Die Ausgabe kann durch die Einstellung von admin_quiet beeinflusst
werden.
Beispiel aus plugin_base (Funktion: admin_ssay):
496 strstripquotes(Data);
497 say(Data);
498 log_command(User,Command,Data);
Der in den Chat zu schreibende Text (Data) wird möglicher Anführungszeichen befreit und
ausgegeben. Anschließend wird der Text inklusive Admin und dem genutzten Befehl in die
Logdateien geschrieben.
look_in_dir( sDirectory[], sMatch[], sFilename [], iNumber );
sDirectory[]
Typ: String (100)
sMatch[]
Typ: String (100)
sFilename []
Typ: String (100)
iNumber
Typ: Integer (0 - 2147483647)
Diese Funktion ist nur unter dem Betriebssystem Windows möglich. Unter Angabe des
Verzeichnisses (sDirectory) wird überprüft, ob eine Datei unter Angabe eines Musters
(sMatch) existiert. Wenn dies der Fall ist, wird der Dateiname an einen String (sFileName)
übergeben. Es ist auch möglich „*“ als Joker im Muster zu verwenden. Die Ausgabe des x-ten
Eintrags kann über iNumber eingestellt werden.
Beispiel aus plugin_rules
(Funktion: showrules):
17 new i = 0;
18 rulefound = look_in_dir("rules", "*.cfg", strRule, i);
19
20 while (rulefound == 1 && i < 100) {
21 len = strlen(strRule)-3;
22 strncpy(strRule, strRule, len, len);
23 selfmessage(strRule);
24 i++;
25 rulefound = look_in_dir("rules", "*.cfg", strRule, i);
26 }
Es wird im Verzeichnis „rules“ nach allen Konfigurationsdateien („*.cfg“) gesucht. Dabei wird
das erste Vorkommen (i) in strRule zurückgegeben. In einer While-Schleife werden
weitere Dateien ermittelt. Dabei wird vor der Ausgabe des Dateinamens dieser Suffix
entfernt.
maptime( iWhichtime, iPrintToConsole = 0 );
iWhichtime
Typ: Integer (0 - 1)
iPrintToConsole = 0
Typ: Integer (0 - 1)
Die Funktion kann die abgelaufene und die verbleibende Spielzeit (in Sekunden) auf der
aktuellen Map angeben. Es ist zu definieren (iWhichtime), ob die abgelaufene (0) oder die
verbleibende (1) Zeit ausgegeben werden soll. Man kann auch optional angeben, ob die Zeit in
die Console geschrieben werden soll.
Die Funktion erkennt nicht den Restart einer Map in Counter-Strike. In diesem Fall sollte auf
timeleft oder LogD basierte Berechnungen zurückgegriffen werden.
Beispiel aus plugin_wm_chat
(Funktion: wmtl_check):
99 public wmtl_check() {
100 new iTmp = maptime(1, 0);
101 switch(iTmp) {
102 case 1200: {wm_timeleft(1);}
103 case 600: {wm_timeleft(1);}
104 case 300: {wm_timeleft(1);}
105 case 150: {wm_timeleft(1);}
106 case 60: {wm_timeleft(1);}
107 case 5: {execall("speak five");}
108 case 4: {execall("speak four");}
109 case 3: {execall("speak three");}
110 case 2: {execall("speak two");}
111 case 1: {
112 execall("speak one");
113 kill_timer(TV[0]);
114 kill_timer(TV[1]);
115 }
116 }
117 }
Im Beispiel wird die verbleibende Mapzeit ermittelt, ohne sie in die Console zu schreiben.
Über eine Switch-Verzweigung wird eine userspezifische Funktion angesprochen
bzw. via HL-Speech (vox) von fünf auf eins heruntergezählt. Bei 1 werden zwei Timer
abgebrochen.
matherror( iError );
iError
Typ: Integer (0 - 3)
Wandelt einen Fehlercode aus den Festkommaberechnungen der math.inc in lesbaren Text
um und schreibt diesen in die Logdateien. Kann in Kombination mit den meisten
Festkommaberechnungen verwendet werden.
Beispiel:
new fixed:fNegative=-4.000;
new iError=0;
iError=f_sqrt(fNegative);
matherror(iError);
Es wird versucht aus einer negativen Zahl (fNegative), die Wurzel zu ziehen. Die Variable
fNegative wird auf -1 und der Fehlercode (iError) auf 1 gesetzt. Mit matherror wird die
Meldung „No valid value for function input!“ in die Logs geschrieben.
8.10.110 max
max( a, b );
a
Typ: Integer (-2147483648 - 2147483647)
b
Typ: Integer (-2147483648 - 2147483647)
Die Funktion liefert den Maximalwert zweier Ganzzahlen. Warum nicht auf die
nativen Funktionen zurückgegriffen wird (core.inc), entzieht sich der Kenntnis des
Autors.
Eine vergleichbare Funktion f_max gibt es auch für Festkommazahlen.
Beispiel aus plugin_bk_botmanager
(Funktion: admin_bot_set):
270 if(strcasecmp(sBotCvar,"bots")==0){
271 iValue=min(max(strtonum(sValue),0),maxplayercount());
272 if(get_vaultnumdata("BK_BM_BOTS",iBots) && iBots<iValue){
273 set_vaultnumdata("BK_BM_BOTS",iValue);
Wenn die Option, die übergeben wurde, gleich „bots“ ist, wird die übergebene Botanzahl
zunächst durch eine Max-Auswahl mit 0 nach unten und anschließend durch eine
Min-Auswahl gegen die maximale Spielerzahl (maxplayercount) begrenzt. Dies hätte man auch
über die Funktion clamp lösen können.
Anschließend wird überprüft, ob der Eintrag „BK_BM_BOTS“ in der vault.ini existiert, und
ob die bisherige dort abgelegte Botanzahl kleiner als der neue Wert ist. Der neue Wert wird
anschließend in „BK_BM_BOTS“ geschrieben.
maxplayercount( );
Die Funktion ermittelt die maximale mögliche Spielerzahl auf dem Server.
Beispiel aus plugin_fun (Funktion: KillGlow):
105 KillGlow() {
106 new i;
107 new iMaxPlayers = maxplayercount();
108 new Name[MAX_NAME_LENGTH];
109
110 for (i = 1; i <= iMaxPlayers; i++) {
111 if(playerinfo(i,Name,MAX_NAME_LENGTH)==1) {
112 glow(Name,0,0,0);
113 }
114 }
115 }
Die maximale Spielerzahl wird ermittelt und als Maximalwert für die For-Schleife verwendet.
Auf diese Weise muss man nicht alle 32 theoretisch möglichen Slots durchsuchen. In dieser
For-Schleife wird bei allen Spielern das Glühen abgeschaltet.
8.10.112 menu
menu( username[],text[],keys ,time=0 );
username[]
Typ: String (33)
text[]
Typ: String (512)
keys
Typ: Integer (0 - 1024)
time=0
Typ: Integer (0 - 2147483647)
Unter Angabe des Spielers (username) kann man eine Nachricht (text) in Form eines
Menüs anzeigen lassen. Mit dem der Variable keys wird definiert, welche Ziffertasten
als Eingabe-Optionen verwendet werden sollen. Die Zahl errechnet sich aus der
Summe der Zweierpotenzen von 2n-1. Die Zahl n steht für die jeweilige Ziffertaste. Die
Ziffer 0 ist für die Variable keys eine 10 (210-1 = 512). Der Wert 1024 sperrt alle
Ziffertasten.
Sollen z.B. nur die Tasten 0 bis 3 auswählbar sein, ergibt sich
keys = 210-1 + 21-1 + 22-1 + 23-1 = 512 + 1 + 2 + 4 = 519
Mit der Variable time definiert man die Dauer der Bildschirmausgabe. Wird der Wert nicht
angegeben oder wird eine 0 übergeben, bleibt das Menü offen bis etwas ausgewählt wurde oder
das Menü von einem anderen überschrieben wurde. Es gibt keine Überprüfungsmöglichkeit, ob
beim Spieler bereits ein Menü geöffnet ist.
Die Auswertung erfolgt über den registrierten HL-Befehl „menuselect“ (Tutorial).
Beispiel aus plugin_CS (Funktion: DrawSubMenu):
1625 strcat(Menutext,"^n^n\w0. Back",512);
1626 Keys |= 512;
1627 playerinfo(UserIndex,UserName,MAX_NAME_LENGTH);
1628 g_UserMenuSelected[UserIndex] = -Menu;
1629 menu(UserName,Menutext,Keys,0);
Es wird an den Menütext (Menutext) die Option 0 (Back) angehängt. Ein bitweises
„Oder“ wird auf Keys und 512 angesetzt und das Ergebnis in Keys geschrieben. Hier
hätte man auch einfach addieren können. Mittels playerinfo wird der Spielername
ermittelt und die negative Nummer des Menüs wird in das globale Feld eingetragen,
damit man weiß, in welchem Menü der Spieler sich befindet. Abschließend wird das
Menü permanent bis zu einer Optionsauswahl bzw. einem überschreibenden Menü
angezeigt.
message( sTarget[], sMessage[] );
sTarget[]
Typ: String (33)
sMessage[]
Typ: String (100)
Die Funktion schreibt eine Nachricht (sMessage) in die Console der angegebenen Person
(sTarget). Die Funktion messageex bietet einen größeren Umfang.
Beispiel aus plugin_base (Funktion: admin_kick):
272 if (strlen(Reason) != 0) {
273 snprintf(Text, MAX_TEXT_LENGTH, "You have been kicked because %s", Reason);
274 message(real_user, Text);
275 }
276 kick(real_user);
Es wird überprüft, ob ein Grund für den Kick angegeben wurde. Wenn dies der Fall ist, wird
dies dem Spieler in der Konsole mitgeteilt. Anschließend wird der Spieler vom Server geworfen
(kick).
messageex( sTarget[],sMessage[], print_type:iMessageType );
sTarget[]
Typ: String (33)
sMessage[]
Typ: String (100)
print_type:iMessageType
Typ: Enum (0=print_console, print_center, print_chat, print_tty, print_pretty)
Die Funktion schreibt eine Nachricht (sMessage) an die angegebene Person (sTarget). Die Art,
wie sie dem Spieler angezeigt werden soll, wird mit print_type definiert.
Es gibt 5 Darstellungen:
-
print_console
- Anzeige in der Konsole
-
print_center
- Anzeige in normaler Schrift in der Mitte des Bildschirmes
-
print_chat
- Anzeige im Chat
-
print_tty
- Anzeige in gelb am linken, unteren Bildschirmrand
-
print_pretty
- Anzeige in grün in der Mitte des Bildschirmes
Beispiel aus plugin_base (Funktion: admin_psay):
413 snprintf(Text, MAX_TEXT_LENGTH, "(Private Msg From %s): %s", User, Msg);
414 if (iMsgToAdmin == 1) {
415 log(Text);
416 } else {
417 messageex(TargetName, Text, print_chat);
418 }
Stellt einen Präfix mit dem Absender (User) vor die eigentliche Nachricht (Msg). Wenn die
Nachricht an einen Admin in der Serverconsole gehen soll, wird der Text in die Logdateien
geschrieben. Anderenfalls wird dem Empfänger (TargetName) die Nachricht im Chat
präsentiert.
8.10.115 min
min( a, b );
a
Typ: Integer (-2147483648 - 2147483647)
b
Typ: Integer (-2147483648 - 2147483647)
Die Funktion liefert den Minimalwert zweier Ganzzahlen. Warum nicht auf die nativen
Funktionen zurückgegriffen wird (core.inc), entzieht sich der Kenntnis des Autors.
Eine vergleichbare Funktion f_min gibt es auch für Festkommazahlen.
Beispiel aus plugin_bk_botmanager
(Funktion: admin_bot_set):
270 if(strcasecmp(sBotCvar,"bots")==0){
271 iValue=min(max(strtonum(sValue),0),maxplayercount());
272 if(get_vaultnumdata("BK_BM_BOTS",iBots) && iBots<iValue){
273 set_vaultnumdata("BK_BM_BOTS",iValue);
Wenn die Option, die übergeben wurde, gleich „bots“ ist, wird die übergebene Botanzahl
zunächst durch eine Max-Auswahl mit 0 nach unten und anschließend durch eine
Min-Auswahl gegen die maximale Spielerzahl (maxplayercount) begrenzt. Dies hätte man auch
über die Funktion clamp lösen können.
Anschließend wird überprüft, ob der Eintrag „BK_BM_BOTS“ in der vault.ini existiert, und
ob die bisherige dort abgelegte Botanzahl kleiner als der neue Wert ist. Der neue Wert wird
anschließend in „BK_BM_BOTS“ geschrieben.
8.10.116 motd
motd( sTarget[],sMessage[] );
sTarget[]
Typ: String (33)
sMessage[]
Typ: String (1536)
Sofern die Modifikation es unterstützt, kann man mit dieser Funktion ein „Message of the
Day“ Fenster mit einer Nachricht (sMessage) bei einem bestimmten Spieler (sTarget)
öffnen. Die Anzahl der Zeichen ist äußerst begrenzt. Insbesondere bei HTML-Seiten
sollte man besser nur eine automatische Weiterleitung auf eine echte HTML-Seite
generieren.
Beispiel aus plugin_base (Funktion: admin_motd):
810 strbreak(Data, Target, Msg, MAX_TEXT_LENGTH);
811 if (strlen(Msg) == 0) {
812 selfmessage( "Unparsable format: no message found.");
813 return PLUGIN_HANDLED;
814 } else if (check_user(Target) == 0) {
815 selfmessage("Unrecognized player: ");
816 selfmessage(Target);
817 return PLUGIN_HANDLED;
818 }
819 get_username(Target,TargetName,MAX_NAME_LENGTH);
820
821 motd( TargetName, Msg );
Zunächst werden die übergebenen Daten aus dem Befehl in einen Spieler- und einen
Nachrichtteil getrennt. Trennzeichen ist das erste Leerzeichen (strbreak). Wenn keine
Nachricht gefunden wurde oder der Spieler nicht auffindbar ist, wird die Abarbeitung mit
einer Fehlermeldung an den aufrufenden Admin abgebrochen. Die Funktion get_username
macht aus einer ID oder einer IP einen Namen und nutzt diesen zur Ausgabe der
Nachricht.
movespawn( iIdentity, iX, iY, iZ, iXAngle, iYAngle, iZAngle );
iIdentity
Typ: Integer (0 - 2147483647)
iX
Typ: Integer (-2147483648 - 2147483647)
iY
Typ: Integer (-2147483648 - 2147483647)
iZ
Typ: Integer (-2147483648 - 2147483647)
iXAngle
Typ: Integer (0 - 359)
iYAngle
Typ: Integer (0 - 359)
iZAngle
Typ: Integer (0 - 359)
Die Funktion verschiebt ein Item (iIdentity) auf eine bestimmte Position (iX, iY, iZ) und in
einer bestimmten Ausrichtung (iXAngle, iYAngle, iZAngle).
Die Funktionalität steht mittlerweile nicht mehr zur Verfügung.
Beispiel aus plugin_spawn (Funktion: admin_movespawn):
143 if(movespawn(iIdentity,X,Y,Z,XAngle,YAngle,ZAngle)==1) {
144 selfmessage("Success.");
145 say_command(User,Command,Data);
146 } else {
147 selfmessage("Failed.");
148 }
Es wird versucht ein Item zu verschieben. Falls dies erfolgreich war, wird eine Erfolgsmeldung
an den Admin und alle anderen Spieler ausgegeben. Anderenfalls wird nur der Admin über
den fehlgeschlagenen Versuch informiert.
nextmap( sMap[], iMaxLength );
sMap[]
Typ: String (100)
iMaxLength
Typ: Integer (0 - 100)
Die Funktion gibt die nach der aktuellen geladene Map (sMap) aus. Sie berücksichtigt keine
Plugins, die in den Mapwechsel eingreifen, sondern geht in der Ermittlung nach der Methode
des HL-Servers vor. Nur bei der ersten Map nach dem Serverstart stimmt die Anzeige
nicht.
Beispiel aus plugin_chat (Funktion: SayNextMap):
52 SayNextMap() {
53 nextmap(NextMap,MAX_NAME_LENGTH);
54 snprintf(Text, MAX_TEXT_LENGTH, "The next map will be: %s", NextMap);
55 say(Text);
56 }
Die nächste Map wird ermittelt, in einen Text eingebettet und im Chat an alle Spieler
ausgegeben.
noclip( sPlayer[], iOnOff );
sPlayer[]
Typ: String (33)
iOnOff
Typ: Integer (0 - 1)
Die Funktion lässt den Spieler (sPlayer) durch Wände gehen, wenn man als iOnOff eine 1
übergibt. Mit 0 stellt man den Noclip Modus wieder aus. Es wird eine Nachricht allen Spielern
auf dem Server angezeigt, dass der Spieler diese Fähigkeit erhalten hat. Diese Nachricht kann
nicht ausgeschaltet werden!
Beispiel aus plugin_cheat (Funktion: admin_noclip):
86 if (check_user(strNoclipUser)==1) {
87 say_command(User,Command,Data,1);
88 noclip(strNoclipUser,iNoclip);
89 } else {
90 selfmessage("Unrecognized player: ");
91 selfmessage(strNoclipUser);
92 }
Wenn der entsprechende Spieler (strNoclipUser) auf dem Server ist, wird die Verwendung des
Noclip Modus bekannt gegeben. Aber auch ohne say_command wird eine Meldung an alle
Spieler abgesetzt. Da hier erheblich in die Spielmechanik eingegriffen wird, kann die Meldung
nicht unterdrückt werden. Anschließend wird der Noclip Modus für den entsprechenden Spieler
ausgeführt.
Ist der Spieler nicht auf dem Server wird das dem aufrufenden Admin in der Console
mitgeteilt.
numargs( );
Diese Funktion wird nur Fällen gebraucht, wenn man die Anzahl der Argumente einer
Funktion mit variabler Anzahl auslesen möchte.
Beispiel:
sum(...){
new result = 0 ;
for (new i = 0; i < numargs(); ++i) {
result += getarg(i);
}
return result;
}
Eine Funktion „sum“ mit variabler Argumentanzahl (...) wird definiert. Eine For-Schleife fragt
die einzelnen Argumente ab (getarg) und addiert sie. Die Summe wird zurückgegeben. Die
Anzahl der übergebenen Argumente wurde dabei mit numargs ermittelt.
numtostr( num, str[] );
num
Typ: Integer (-2147483648 - 2147483647)
str[]
Typ: String (20)
Die Funktion wandelt eine Ganzzahl (num) in einen String (str) um.
Beispiel aus plugin_CS (Funktion: HandleRestartVote):
544 new Timelimit[MAX_NUMBER_LENGTH];
545 numtostr((getvar("mp_timelimit") * 60 - timeleft() + 10) / 60,Timelimit);
546 setstrvar("mp_timelimit",Timelimit);
547 setstrvar("sv_restartround","10");
548 say("Round restart vote succeeded.");
Vom aktuellen Zeitlimit auf dem Server wird die Restzeit abgezogen und 10 Sekunden addiert.
Dieser Wert wird als neues Zeitlimit eingetragen. Anschließend wird ein Maprestart nach 10
Sekunden angefordert und der Restart allen Spielern mitgeteilt.
playercount( );
Die Funktion gibt die Anzahl der Spieler auf dem Server als Ganzzahl zurück.
Beispiel aus plugin_logd_redirect
(Funktion: logd_redirect):
71 Count = maxplayercount();
72 Count2 = playercount();
73
74 snprintf(Text,MAX_TEXT_LENGTH,"Maxplayers = %i^nPlayerCount = %i",Count,Count2);
75 messageex(User,Text,print_chat);
Es wird die maximal mögliche (Count) und die tatsächliche Spielerzahl (Count2)
ermittelt. Die Ausgabe wird formatiert und im Chat des entsprechenden Spielers
ausgegeben.
playerinfo( iPlayerIndex, sName[], iLength, &iUserID = 0, &iWONID =
0,
&iTeam = 0, &iDead = 0, sAuthID[MAX_AUTHID_LENGTH] = “” );
iPlayerIndex
Typ: Integer (1 - 32)
sName[]
Typ: String (33)
iLength
Typ: Integer (0 - 33)
&iUserID = 0
Typ: Integer (0 - 2147483647)
&iWONID = 0
Typ: Integer (0 - 2147483647)
&iTeam = 0
Typ: Integer (0 - 4, 500, 600)
&iDead = 0
Typ: Integer (0 - 1)
sAuthID[MAX_AUTHID_LENGTH] = “”
Typ: String (39)
Diese Funktion dient zur umfassenden Ermittlung diverser Spielerinformation. Dies sind Name
(sName), Session ID (iUserID), WONID (iWONID), Teamzugehörigkeit (iTeam),
Lebensstatus (iDead) und die Steam ID (sAuthID). Sie gibt darüber hinaus direkt
aus, ob ein Spieler mit dem zugehörigen Userindex existiert. Optionale Argumente
können mit „_“ ausgespart werden, wenn nicht sie sondern die nachfolgenden benötigt
werden.
Beispiel aus plugin_retribution (Funktion: admin_bury):
499 get_userindex(Data, nIndex);
500 playerinfo(nIndex, TargetName, MAX_NAME_LENGTH, _, _, _, nDead);
Der Status eines Spielers (lebend oder tot) lässt sich mit Admin Mod nur mit der Funktion
playerinfo ermitteln. Da sie den Userindex benötigt, muss zunächst aus dem Namen (Data)
der Userindex (nIndex) ermittelt werden. Anschließend kann der Status abgefragt werden.
TargetName ist eigentlich nicht notwendig, ist jedoch eine Pflichtrückgabe. Auf die weiteren
Variablen kann verzichtet werden. Als Auslassungszeichen wird der Unterstrich verwendet. Die
Steam ID wurde ebenfalls ausgelassen.
playsound( sTarget[], sSound[] );
sTarget[]
Typ: String (33)
sSound[]
Typ: String (100)
Die Funktion spielt eine Wave Datei (sSound) beim angegebenen Spieler (sTarget)
ab. Der Spieler muss diese Datei bereits auf dem Rechner haben. Bei der Angabe
der Wavedatei darf der Pfad nicht vergessen werden. Der Pfad beginnt im „sound“
Verzeichnis.
Beispiel aus plugin_retribution (Funktion: PlaySoundToAll):
98 PlaySoundToAll(sSound[]) {
99 new i;
100 new iMaxPlayers = maxplayercount();
101 new Name[MAX_NAME_LENGTH];
102
103 if (getvar("admin_fx") != 0) {
104 for (i = 1; i <= iMaxPlayers; i++) {
105 if (playerinfo(i,Name,MAX_NAME_LENGTH) != 0) {
106 playsound(Name, sSound);
107 }
108 }
109 }
110 }
Das Abspielen der Sounddatei (sSound) wird nur durchgeführt, wenn admin_fx angeschaltet
ist. Anschließend werden mit einer For-Schleife alle Serverslots nach Spielern durchsucht.
Wenn ein Spieler gefunden wurde, wird bei im die Sounddatei (sofern auf seinem Rechner
vorhanden) abgespielt.
plugin_checkcommand( sCommand[], &iAccess = 0 );
sCommand[]
Typ: String (30)
&iAccess = 0
Typ: Integer (0 - 2147483647)
Die Funktion gibt zurück, wieviele Plugins den Admin Mod Befehl (sCommand)
registriert haben. Darüber hinaus wird der dafür notwendige Access Level (iAccess)
zurückgegeben. In Kombination mit plugin_exec lässt sich ein Plugin-Addon-System
aufbauen.
Beispiel aus plugin_cw_creator
(Funktion: warmup_end):
628 if (plugin_checkcommand("cwc_addon_start",iAccess)>0){
629 plugin_exec("cwc_addon_start","");
630 iAccess=0;
631 }
In diesem Fall wird ausgewertet, ob mindestens ein Plugin den Admin Mod Befehl
„cwc_addon_start“ registriert hat. Falls mindestens ein Plugin gefunden wurde, wird der
Befehl ausgeführt.
plugin_command( HLCommand, HLData, HLUserName, UserIndex )
HLCommand
Typ: HLString (33)
HLData
Typ: HLString (200)
HLUserName
Typ: HLString (30)
UserIndex
Typ: Integer (0 - 32)
Bei der Funktion plugin_command handelt es sich um ein Event, mit dem alle Befehle
abgefangen werden können. Sie wird vor allem in Antiflood Plugins eingesetzt.
Beispiel aus plugin_blatt_map
(Funktion: plugin_command):
98 public plugin_command(HLCommand,HLData,HLUserName,UserIndex) {
99 if (g_BuySupressed==0) {
100 return PLUGIN_CONTINUE;
101 }
102
103 new Command[MAX_COMMAND_LENGTH];
104 safe_convert(HLCommand,Command,MAX_COMMAND_LENGTH);
105
106 if (strmatch(Command,"say",3)==1) {
107 return PLUGIN_CONTINUE;
108 }
109 if (streq(Command,"drop")) {
110 return PLUGIN_CONTINUE;
111 }
112
113 return PLUGIN_HANDLED;
114 }
In diesem Beispiel wird die Ausführung aller Befehle außer „say“ und „drop“ unterbunden
(PLUGIN_HANDLED). Außerdem kann eine globale Variable (g_BuySupressed) das
Unterbinden verhindern.
Dieser Code macht nur Sinn, wenn das Plugin als zweites (hinter plugin_antiflood ausgeführt
wird. Nur Befehle aus Plugins, die sich in der Ladereihenfolge hinter plugin_blatt_map
befinden, können blockiert werden.
plugin_connect( HLUserName, HLIP, UserIndex )
HLUserName
Typ: HLString (30)
HLIP
Typ: HLIP (22)
UserIndex
Typ: Integer (0 - 32)
Bei der Funktion plugin_connect handelt es sich um ein Event, mit dem man Informationen
zum den Server beitretenden Spieler erhalten (Name, IP, Slot) kann. Leider ist der Event in
der Regel zu früh, so dass weder Spielername noch seine IP zurückgegeben werden. Nur der
Slot (UserIndex) lässt sich zuverlässig nutzen. Mehr Informationen sind dem Tutorial zu
entnehmen.
Beispiel aus plugin_message (Funktion: plugin_connect):
60 public plugin_connect(HLUserName, HLIP, UserIndex) {
61 set_timer("say_hello",45,0);
62 return PLUGIN_CONTINUE;
63 }
Beim Beitreten eines Spielers wird ein 45 Sekunden Timer auf die Funktion „say_hello“
ausgelöst.
plugin_disconnect( HLUserName, UserIndex )
HLUserName
Typ: HLString (30)
UserIndex
Typ: Integer (0 - 32)
Bei der Funktion plugin_disconnect handelt es sich um ein Event, mit dem man
Informationen zum den Server verlassenden Spieler erhalten (Name, Slot) kann.
Beispiel aus plugin_bk_hltvannounce
(Funktion: plugin_disconnect):
81 public plugin_disconnect(HLUserName, UserIndex){
82 if (hltvid==UserIndex){
83 hltvid=0;
84 hltvteam=0;
85 #if LANG==1
86 typesay("Der HLTV ist jetzt offline!",3,181,40,44);
87 #else
88 typesay("The HLTV is offline!",3,181,40,44);
89 #endif
90 }
91 return PLUGIN_CONTINUE;
92 }
Falls es sich beim übergebenen Userindex (UserIndex) um den des HLTV-Servers (hltvid)
handelt, wird Verlassen des HLTV-Servers mit typesay bekannt gegeben. Die Sprache wird
beim Compilieren des Plugins durch die Direktive LANG eingestellt.
plugin_exec( sCommand[], sArguments[] );
sCommand[]
Typ: String (30)
sArguments[]
Typ: String (200)
Um zu verhindern, dass man mit der Funktion exec pluginübergreifend das Rechtesystem
untergräbt, wurde plugin_exec eingeführt. Diese Funktion überprüft, ob der ausführende
Spieler auch die Rechte für den Befehl des anderen Admin Mod Plugins hat.
Beispiel aus plugin_cw_creator
(Funktion: warmup_end):
628 if (plugin_checkcommand("cwc_addon_start",iAccess)>0){
629 plugin_exec("cwc_addon_start","");
630 iAccess=0;
631 }
In diesem Beispiel wird ausgewertet, ob mindestens ein Plugin den Admin Mod Befehl
„cwc_addon_start“ registriert hat. Falls mindestens ein Plugin gefunden wurde, wird der
Befehl mit plugin_exec ausgeführt. Der Befehl erwartet keine Argumente, so dass sie leer
gelassen wurden.
plugin_info( HLOldName, HLNewName, UserIndex )
HLOldName
Typ: HLString (33)
HLNewName
Typ: HLString (33)
UserIndex
Typ: Integer (0 - 32)
Bei der Funktion plugin_info handelt es sich um ein Event, mit dem man den Namenswechsel
eines Spielers auswerten kann. Das Event wird auch beim Connect mehrfach ausgeführt, so
dass es hin und wieder als Ersatz für plugin_connect herangezogen wird. Da der Event nicht
immer mit einem echten Namenswechsel verbunden ist, sollte man ihn mit Weitsicht
verwenden.
Beispiel aus plugin_retribution (Funktion: plugin_info):
683 public plugin_info(HLOldName,HLNewName,UserIndex) {
684 new iIgnoreGag = 0;
685 new GagTime;
686 new Command[MAX_TEXT_LENGTH];
687 new NewName[MAX_NAME_LENGTH];
688 new OldName[MAX_NAME_LENGTH];
689
690 convert_string(HLNewName, NewName, MAX_NAME_LENGTH);
691 convert_string(HLOldName, OldName, MAX_NAME_LENGTH);
692
693 /* Only bother if the name has changed. */
694 if(streq(OldName,NewName)==0) {
Der alte und der neue Spielername (HLNewName und HLOldName) werden in Small Strings
konvertiert (convert_string). Die weitere Auswertung erfolt nur, wenn der alte nicht dem
neuen Namen entspricht (streq).
plugin_init( )
Bei der Funktion plugin_init handelt es sich um ein Event, das nur beim Plugin Start
ausgeführt. Es entspricht der main Funktion in der Sprache C. Jedes Plugin muss diese
Funktion besitzen (siehe auch im Tutorial).
Beispiel aus plugin_antiflood (Funktion: plugin_init):
217 public plugin_init()
218 {
219
plugin_registerinfo("Admin Anti-Flood Plugin", "Auto kicks flooders", VERSION);
220
221 return PLUGIN_CONTINUE;
222 }
Dieses Beispiel zeigt die simpelste Form von plugin_init. Es wird lediglich das Plugin bei
Admin Mod registriert (plugin_registerinfo). Es können außerdem Befehle registriert aber
auch beliebiger Code ausgeführt werden. Die Funktion plugin_exec funktioniert allerdings zu
diesem Zeitpunkt prinzipbedingt noch nicht.
plugin_message( sMessage[] );
sMessage[]
Typ: String (100)
Die Funktion schreibt eine Nachricht (sMessage) in Console des aufrufenden Spielers. Im
Gegensatz zur Funktion selfmessage wird auch das Plugin genannt, das die Nachricht
ausgibt.
Beispiel aus plugin_CS (Funktion: LoadDefaultRestrictions):
937 if(get_vaultdata(strName,strKey,MAX_ITEMS+1)) {
938 plugin_message("Map-specific saved weapon restrictions found.");
939 } else if(get_vaultdata("WeaponRestrictions",strKey,MAX_ITEMS+1)) {
940 plugin_message("Default saved weapon restrictions found.");
941 } else {
942 plugin_message("No saved weapon restrictions found.");
943 }
Es wird nach mapspezifischen und allgemeinen Waffeneinschränkungen gesucht. Wenn der
Eintrag (strName) in der vault.ini gefunden wurde, wird in der Console ausgegeben, dass
mapspezifische Restriktionen geladen wurden. Beim Eintrag „WeaponRestrictions“ wird
ausgegeben, dass die Standardeinschränkungen geladen wurden. Wurde kein Eintrag
ausgemacht, erscheint in der Console, dass keine Restriktionen geladen wurden.
plugin_registercmd( Command[], Function[], RequiredAccess,
HelpMessage[]= “” );
Command[]
Typ: String (30)
Function[]
Typ: String (19)
RequiredAccess
Typ: Integer (0 - 2147483647)
HelpMessage[]= “”
Typ: String (150)
Die Funktion dient der Registrierung eines Befehls (Command), der z.B. in der Console
eingegeben wird. Als Argumente müssen die aufzurufende Funktion (Function) und der nötige
Access Level (RequiredAccess) angegeben werden. Optional kann ein Hilfetext (z.B. die
Syntax) angegeben werden, der dann beim Aufruf von admin_help ausgegeben wird. Man
verwendet diesen Befehl üblicherweise nur in plugin_init. Mehr zu diesem Befehl ist auch dem
Tutorial zu entnehmen.
Beispiel aus plugin_bk_alltalk
(Funktion: plugin_init):
27 plugin_registerinfo("Alltalk changer","Switches sv_alltalk",STRING_VERSION);
28
plugin_registercmd("admin_alltalk","admin_alltalk",A_KICK,"Switches sv_alltalk.");
Zunächst wird das Plugin registriert. Anschließend wird der Befehl „admin_alltalk“ mit der
gleichnamigen Funktion registriert. Der Spieler benötigt Kickrechte. Hier wurde aus
Darstellungsgründen „A_KICK“ geschrieben. Richtig ist jedoch „ACCESS_KICK“. Einen
Überblick über die Access Level und die zugehörigen Direktiven ist der admin.inc zu
entnehmen. Zu letzt wird ein Hilfetext für die Anzeige in admin_help festgelegt.
plugin_registerhelp( Command[], RequiredAccess, HelpMessage[] );
Command[]
Typ: String (30)
RequiredAccess
Typ: Integer (0 - 2147483647)
HelpMessage[]
Typ: String (150)
Einen Hilfetext kann man bereits mit plugin_registercmd anlegen. Es gibt jedoch auch Fälle,
bei denen z.B. zwei Argumente übergeben werden müssen. Basierend auf dem ersten
Argument müssen unterschiedliche zweite Argumente eingegeben werden. Man kann dann
für alle ersten Argumente Hilfetexte anlegen. Wichtig ist die Funktion auch beim
Abfangen von „say“ Nachrichten. Da viele Plugins den Chat für die Befehlseingabe
nutzen, sollte man die eigenen Chatbefehle mittels plugin_registerhelp mit einem
Hilfetext ausstatten. Die Registrierung von „say“ sollte hingegen keinen Hilfetext
beinhalten.
Es muss der dem Hilfetext (HelpMessage) zugehörige Befehl (Command) und der notwendige
Access Level (RequiredAccess) angegeben werden. Beim Aufruf von admin_help wird der
Hilfetext dann angezeigt.
Beispiel aus plugin_bk_timeleft
(Funktion: plugin_init):
36 plugin_registerinfo("Akurates Timeleft","Genaue Restzeitangabe.",STRING_VERSION);
37 plugin_registercmd("say","HandleSay",ACCESS_ALL);
38 plugin_registerhelp("say",ACCESS_ALL,"say timeleft: Gibt die Restzeit an.");
Zunächst wird das Plugin registriert und anschließend der „say“ Befehl. D.h. alle
Chatnachrichten (außer der Teamnachrichten) werden abgefangen. Da auch andere Plugins
„say“ abfangen könnten, wird die Hilfe in plugin_registerhelp beschrieben.
plugin_registerinfo( Name[], Description[], Version[] );
Name[]
Typ: String (100)
Description[]
Typ: String (200)
Version[]
Typ: String (150)
Dies Funktion registriert ein Plugin bei Admin Mod. Es muss ein Pluginname (Name), eine
Beschreibung (Description) und eine Versionsnummer (Version) angegeben werden. Diese
Informationen lassen sich mit admin_version abrufen.
Beispiel aus plugin_bk_alltalk
(Funktion: plugin_init):
27 plugin_registerinfo("Alltalk changer","Switches sv_alltalk",STRING_VERSION);
28
plugin_registercmd("admin_alltalk","admin_alltalk",A_KICK,"Switches sv_alltalk.");
Zunächst wird das Plugin registriert. Der Name ist „Alltalk changer“, die Beschreibung
lautet „Switches sv_alltalk“ und die Versionsnummer entstammt einer globalen
Variable (STRING_VERSION). Anschließend wird der Befehl „admin_alltalk“
registriert.
pointto( iRange = 2048 );
iRange = 2048
Typ: Integer (0 - 2147483647)
Mit dieser Funktion kann man ermitteln, auf welchen Spieler der den Befehl aufrufende Spieler
zielt. Die Funktion gibt die Session ID des anderen Spielers zurück. Die Session ID für eine
ungültige Figur (z.B. Geisel) ist -1. Ist keine Figur im Blickfeld, wird eine 0 zurückgegeben.
Das Argument iRange definiert die Blickweite.
Um auch den Blick anderer Spieler zu untersuchen, sollte man die Funktion gettarget nutzen.
Zudem erspart man sich die Umwandlung der Session ID.
Beispiel aus plugin_seeuser
(Funktion: admin_seeuser):
35 targetnumber = pointto();
36 numtostr(targetnumber, numstring);
37 get_username(numstring,targetname,MAX_NAME_LENGTH);
38 get_userindex(targetname,targetnumber);
Zunächst wird die Session ID (targetnumber) des gegenüberstehenden Spielers ermittelt. Diese
wird in einen String umgewandelt (numtostr), in einen Namen (targetname) und schließlich in
einen Userindex (targetnumber) umgewandelt.
print( const string[], foreground=-1, background=-1 );
string[]
Typ: String (0 - 2147483647)
foreground=-1
Typ: Integer (-1 - 7)
background=-1
Typ: String (-1 - 7)
Diese Funktion schreibt einen Text (string) in die Befehlszeile. Es können auch Vorder- und
Hintergrundfarben (foreground und background) genutzt werden. Mangels einer solchen
Befehlszeile ist die Funktion in Admin Mod nutzlos.
printf( const format[], ... );
format[]
Typ: String (0 - 2147483647)
Diese Funktion schreibt einen Text (format) in die Befehlszeile. Es können andere Strings
unterschiedlicher Datentypen in format eingebettet werden. Mangels einer solchen Befehlszeile
ist die Funktion in Admin Mod nutzlos.
rainbow( sText[], iTime, iRedStart, iGreenStart, iBlueStart, iRedEnd,
iGreenEnd, iBlueEnd );
sText[]
Typ: String (80)
iTime
Typ: Integer (0 - 2147483647)
iRedStart
Typ: Integer (0 - 255)
iGreenStart
Typ: Integer (0 - 255)
iBlueStart
Typ: Integer (0 - 255)
iRedEnd
Typ: Integer (0 - 255)
iGreenEnd
Typ: Integer (0 - 255)
iBlueEnd
Typ: Integer (0 - 255)
Mit dieser Funktion kann man eine Nachricht (sText) mit Farbverlauf in der Mitte des
Bildschirmes produzieren. Das Argument iTime legt die Anzeigezeit in Sekunden fest. Die
Start- und die Endfarbe werden in RGB vorgegeben (iRedStart, iGreenStart, iBlueStart
bzw. iRedEnd, iGreenEnd, iBlueEnd).
Es ist kein Zeilenumbruch mit ^n möglich.
Beispiel aus plugin_budfroggy_rainbow
(Funktion: admin_rsay):
155 if(ic1==1 && ic2==1){
156 rainbow(Text,10,iRedS,iGreenS,iBlueS,iRedE,iGreenE,iBlueE);
157 }else{
158 iRedS = 255;
159 iGreenS = 10;
160 iBlueS = 10;
161 iRedE = 10;
162 iGreenE = 10;
163 iBlueE = 255;
164 rainbow( Data, 10, iRedS, iGreenS, iBlueS, iRedE, iGreenE, iBlueE);
165 }
Falls Farben definiert wurden (ic1 und ic2 müssen 1 sein), wird die Nachricht für zehn
Sekunden mit diesem Farbverlauf dargestellt. Anderenfalls wird ein Verlauf von Rot nach Blau
durchgeführt.
random( max );
max
Typ: Integer (1 bis 2147483647)
Die Funktion gibt eine Pseudo-Zufallszahl zurück. Der Bereich der Zufallszahlen ist zum einen
durch 0 und zum anderen durch max - 1 begrenzt. Man darf von dieser Funktion keine
Zufallszahlen erwarten, die wissenschaftlichen Ansprüchen genügen. Aber dafür ist sie bei
Admin Mod auch nicht gedacht.
Beispiel aus plugin_fun (Funktion: DiscoInferno):
937 for (i = 1; i <= iMaxPlayers; i++) {
938 if(playerinfo(i,Name,MAX_NAME_LENGTH)==1) {
939 Red = random(256);
940 Green = random(256);
941 Blue = random(256);
942 glow(Name,Red,Green,Blue);
943 }
944 }
Mittels For-Schleife und der Funktion playerinfo werden alle Serverslots auf existierende
Spieler überprüft. Ist ein Spieler gefunden worden, werden für jeden Farbanteil eine Zufallszahl
für den Bereich 0 bis 255 erzeugt. Der Spieler glüht dann in der Farbe, die sich aus den
Zufallszahlen ergab (glow).
readfile( sFilename[], sLine[], iLineNum, iMaxLength );
sFilename[]
Typ: String (200)
sLine[]
Typ: String (200)
iLineNum
Typ: Integer (0 - 2147483647)
iMaxLength
Typ: Integer (0 - 200)
Mit dieser Funktion kann eine Zeile (iLineNum) aus einer Datei (sFilename) ausgelesen
werden. Die Zeile darf nicht länger als 200 Zeichen sein (iMaxLength). Die Rückgabe wird in
der Variable sLine gespeichert.
Die Funktion ist sehr zeitintensiv, da gewartet werden muss bis der Festplattenzugriff erfolgt
ist. Lädt man mehrere Zeilen mit einer For-Schleife, wird bei jeder Zeile die Datei neu
geöffnet, was weitere Verzögerungen verursacht. Man sollte sich daher genau überlegen, ob
man diese Funktion nutzen möchte. Beim Auslesen während des Serverstarts ist dies noch
akzeptabel, ein Auslesen während der Spielzeit kann bei einer For-Schleife durchaus zu
Aussetzern im Spiel führen (Lag). Wenn möglich sollte man seine Einstellungen über die
vault.ini lesen und schreiben.
Beispiel aus plugin_bk_res
(Funktion: add_res_data):
155 iLines=filesize(sMap,lines);
156 for(i=1;i<=iLines;i++){
157 readfile(sMap,sLine,i,MAX_DATA_LENGTH);
158 writefile(sMap2,sLine,-1);
159 }
Es wird die Anzahl der Zeilen der Datei (sMap) ausgelesen. Anschließend werden die Daten
über eine For-Schleife zeilenweise von einer Datei (sMap) in eine andere (sMap2) kopiert. Die
Zeilen übernehmen nicht unbedingt die Zeilennummer der Ursprungsdatei. Die Zeilen werden
beim Schreiben nur angehängt (-1).
reject_message( iPublic = 0 );
iPublic = 0
Typ: Integer (0 - 1)
Die Funktion gibt eine Fehlermeldung an den Spieler aus „You do not have access to this
command“, wenn ein Spieler ohne die notwendigen Rechte versucht einen Befehlauszuführen.
Diese Funktion greift auf die in admin_reject_msg definierte Nachricht zurück. Ist diese dort
nicht definiert, wird dem Spieler „You do not have access to this command“ in der
Konsole angezeigt. Verwendet man iPublic = 1, wird die Nachricht serverweit im Chat
ausgegeben.
Beispiel aus plugin_base (Funktion: admin_rcon):
443 if (strstr(Data, "rcon_password") >= 0) {
444 reject_message();
445 return PLUGIN_HANDLED;
446 }
Hierbei handelt es sich um eine Absicherung, dass kein Admin, der Zugriff zu admin_rcon hat,
sich unberechtigt Zugriff zu RCon verschafft, indem er das Passwort ändert. Falls
der String Data die Servervariable rcon_password beinhaltet, wird die Meldung
„You do not have access to this command“ angezeigt und die weitere Abarbeitung
abgebrochen.
reload( );
Die Funktion lädt alle Ini-Dateien von Admin Mod neu, wenn diese in der adminmod.cfg
definiert wurden.
Dies kann sinnvoll sein, wenn man mit dem Plugin Änderungen an den Dateien vorgenommen
hat und diese aktivieren möchte.
Beispiel aus plugin_base (Funktion: admin_reload):
452 public admin_reload(HLCommand,HLData,HLUserName,UserIndex) {
453 reload();
454 return PLUGIN_HANDLED;
455 }
Hier werden auf Befehl einfach die Dateien neu geladen. Dies ist z.B. interessant, wenn man
Änderungen an der users_ini vorgenommen hat und diese ohne Serverneustart oder
Mapchange übernehmen möchte.
removespawn( iIdentity );
iIdentity
Typ: Integer (0 - 2147483647)
Die Funktion löscht ein Item (iIdentity).
Die Funktionalität steht mittlerweile nicht mehr zur Verfügung.
Beispiel aus plugin_spawn (Funktion: admin_removespawn):
168 if(removespawn(iIdentity)==1) {
169 say_command(User,Command,Data);
170 selfmessage( "Success.");
171 } else {
172 selfmessage( "Failed.");
173 }
Es wird versucht ein Item zu löschen. Falls dies erfolgreich war, wird eine Erfolgsmeldung an
den Admin und alle anderen Spieler ausgegeben. Anderenfalls wird nur der Admin über den
fehlgeschlagenen Versuch informiert.
resetfile( sFilename[] );
sFilename[]
Typ: String (100)
Unter Angabe des Dateinamens löscht die Funktion den Inhalt komplett. Die Datei bleibt
jedoch im Gegensatz zu deletefile erhalten.
Beispiel aus plugin_cw_creator3
(Funktion: create_mapcycle):
338 resetfile(sPath);
339 get_vaultdata("CWC_MAP1",Text,MAX_DATA_LENGTH);
340 writefile(sPath,Text,-1);
Die Datei (sPath) wird geleert. Aus der vault.ini wird ein Mapname in Text eingelesen und
anschließend in die leere Datei geschrieben.
rindex( sSource[], iChar );
sSource[]
Typ: String (200)
iChar
Typ: Integer (0 - 256)
Die Funktion ermittelt die Position des ersten Vorkommens des Zeichens (iChar) im String
(sSource) von rechts beginnend. Für das Zeichen muss die ASCII-Nummer angegeben werden.
Vereinfacht kann auch das entsprechende Zeichen in einfache Anführungszeichen
gesetzt werden. Die Funktion liefert -1 zurück, falls das Zeichen nicht gefunden
wurde.
Die Funktion ist ein Alias für strrchr.
Beispiel:
new sTest[MAX_TEXT_LENGTH];
strcpy(sTest,"Dies ist ein Test.",MAX_TEXT_LENGTH);
new iTest=0;
iTest=rindex(sTest,’ ’);
Es wird zunächst „Dies ist ein Test.“ in die Variable sTest geschrieben (strcpy). Nun wird von
rechts nach dem ersten Auftreten eines Leerzeichens gesucht. Leerzeichen gibt es an den
Positionen 4, 8 und 12. Dem entsprechend wird an iTest 12 übergeben.
8.10.147 say
say( sMessage[] );
sMessage[]
Typ: String (100)
Die Funktion gibt einen vorgegebenen Text (sMessage) im Chat aus.
Beispiel aus plugin_CS (Funktion: HandleKickVote):
648 new Ratio = getvar("kick_ratio");
649 if (VoteCount >= Ratio*UserCount/100) {
650 if (g_AbortVote) {
651 say("Kick vote was aborted by an admin");
652 } else {
653 set_timer("KickUser",10,1,VoteUser);
654 }
Die Servervariable „kick_ratio“ wird als Ganzzahl in Ratio ausgelesen. Falls genügend
Stimmen für den Kick zusammengekommen sind, wird entweder der Kick abgebrochen, weil
ein Admin ihn aufgehalten hat, oder nach 10 Sekunden der entsprechende Spieler vom Server
geworfen. Falls ein Admin den Vote aufgehalten hat, wird dies allen Spielern im Chat
mitgeteilt (Zeile 651).
say_command( sUser[], sCommand[], sData[], iOverride = 0 );
sUser[]
Typ: String (33)
sCommand[]
Typ: String (19)
sData[]
Typ: String (200)
iOverride = 0
Typ: Integer (0 - 1)
Die Funktion schreibt einen formatierten Text in den Chat. Dazu muss der ausführende
Admin (sUser), der ausgeführte Befehl (sCommand) und die Parameter (sData) angegeben
werden. Die Ausgabe kann durch die Einstellung von admin_quiet beeinflusst werden.
Optional kann diese Einstellung auch ignoriert werden (iOverride = 1).
Beispiel aus plugin_base (Funktion: admin_map):
307 if (valid_map(Data)==1) {
308 say_command(User,Command,Data);
309 changelevel(Data, 4);
Wenn es sich bei Data um eine gültige Map handelt, wird basierend auf der Einstellung von
admin_quiet im Chat mit Adminnamen und Befehl ausgegeben und nach 4 Sekunden ein
Mapwechsel durchgeführt.
selfmessage( sMessage[] );
sMessage[]
Typ: String (100)
Die Funktion schreibt dem Spieler, der den zugehörigen Befehl ausgeführt hat, eine Nachricht
(sMessage) in die Console.
Beispiel aus plugin_base (Funktion: admin_rcon):
435 if (check_auth(ACCESS_RCON)==0) {
436 selfmessage("Laf. Silly bear.");
437 return PLUGIN_HANDLED;
438 }
Um zu verhindern, dass jemand auf die Idee kommt aus der Serverconsole den Befehl
admin_rcon aufzurufen, was möglich aber unsinnig ist, wurde eine Abfangroutine
implementiert. Nur wenn der User den Access Level 65536 (ACCESS_RCON) besitzt, wird
der RCon-Befehl über Admin Mod abgesetzt. Anderenfalls wird der Admin, der den Befehl
ausführte, etwas unhöflich in der Console auf das unsinnige Ansinnen hingewiesen
(selfmessage).
servertime( sTimeString[], iMaxLen, sFormat[] = „none” );
sTimeString[]
Typ: String (100)
iMaxLen[]
Typ: String (1 - 100)
sFormat[]
Typ: String (100)
Die Funktion gibt das aktuelle Datum und die Uhrzeit zurück (sTimeString mit
Länge iMaxLen). Die Rückgabe erfolgt über die Formatvorgabe (sFormat). Falls
diese nicht vorgegeben wurde, werden die abgelaufenen Sekunden seit dem 1.1.1970
ausgegeben.
In der folgenden Liste sind die Formatierungszeichen beschrieben:
-
%a
- Wochentag (abgekürzt) (z.B. Mon für Montag)
-
%A
- Wochentag (ausgeschrieben)
-
%b
- Monat (abgekürzt) (z.B. Aug für August)
-
%B
- Monat (ausgeschrieben)
-
%c
- Vorgefertigtes Datums- und Zeitformat (%a %b %d %H:%M:%M %Y)
-
%d
- Tag im Monat (01 - 31)
-
%H
- Stunde im 24h Format (00 - 23)
-
%I
- Stunde im 12h Format (00 - 12)
-
%j
- Tag im Jahr (001 - 366)
-
%m
- Monat (als Zahl) (01 - 12)
-
%M
- Minute (00 - 59)
-
%p
- Vor- und Nachmittagsperiode (AM oder PM)
-
%S
- Sekunden (00 - 61)
-
%U
- Kalenderwoche (Woche beginnt am ersten Sonntag) (00 - 53)
-
%w
- Wochentag (als Zahl, Sonntag = 0) (0 - 6)
-
%W
- Kalenderwoche (Woche beginnt am ersten Montag) (00 - 53)
-
%x
- Vorgefertigtes Datumsformat (%m/%d/%y)
-
%X
- Vorgefertigtes Zeitformat (%H:%M:%M)
-
%y
- Jahr (letzten zwei Ziffern) (z.B. 09)
-
%Y
- Jahr (alle Ziffern) (z.B. 2009)
-
%Z
- Zeitzone (z.B. CET)
Beispiel aus plugin_dotw
(Funktion: admin_time):
208 servertime(t_time, MAX_DATA_LENGTH, "%I:%M %p");
209 servertime(t_date, MAX_DATA_LENGTH, "%A, %B %d %Y");
210
211 snprintf(Text, MAX_TEXT_LENGTH, "%s %s", t_time, t_date);
212 selfmessage(Text);
Es wird die Serverzeit (t_time) und das Datum (t_date) ermittelt. Anschließend werden die
beiden Zeitstrings mit einem Leerzeichen verknüpft und an den admin_time ausführenden
Spieler in der Console ausgegeben. Dieser Code hätte auch mit nur einer servertime Abfrage
und ohne snprintf geschrieben werden können.
set_serverinfo( sKey[], sValue[] );
sKey[]
Typ: String (100)
sValue[]
Typ: String (200)
Die Funktion schreibt die Daten (sValue) mit dem Schlüssel (sKey) in ein kleinen
Speicherbereich. Die Daten werden beim Mapwechsel nicht gelöscht. Der Speicher ist jedoch
nur sehr gering bemessen, so dass die Verwendung dieser Funktion vermieden werden
sollte.
Beispiel aus plugin_bk_cron
(Funktion: lag_check):
499 numtostr(iTime,sTime);
500 set_serverinfo("last_cron",sTime);
Die Sekundenzahl der aktuellen Minute (iTime) wird in einen String (sTime) umgewandelt.
Anschließend wird ein Schlüssel „last_cron“ erstellt oder mit diesem String überschrieben.
Auf diese Art und Weise kann insbesondere überprüft werden, wie lang der letzte
Durchlauf vor dem Mapwechsel her ist. Beim Serverstart ist die Variable noch nicht
gesetzt, so dass 0 zurückgegeben wird. Die Nutzung der vault.ini verbietet sich, da der
Wert beim Beenden bzw. Absturz des Servers nicht automatisch auf 0 zurückgesetzt
wird.
set_timer( sFunction[], iWaitSeconds, iRepeatCount, sParameter[]= “”
);
sFunction[]
Typ: String (19)
iWaitSeconds
Typ: Integer (0 - 2147483647)
iRepeatCount
Typ: Integer (0 - 2147483647)
sParameter[]
Typ: String (200)
Mit dieser Funktion wird ein Timer erstellt. Dabei muss die bei Ablauf des Timers
aufzurufende Funktion (sFunction), die Ablaufzeit (iWaitSeconds) und die Anzahl der
Wiederholungen (iRepeatCount) übergeben werden. Die definierte Funktion muss öffentlich
(public) sein. Unendlich viele Wiederholungen erreicht man durch die Angabe von
99999. Um nur einen einzigen Ablauf zu erreichen kann iRepeatCount auf 0 oder 1
gesetzt werden. Optional kann ein String (sParameter) an die aufzurufende Funktion
übergeben werden. Die Funktion set_timer gibt die erstellte Timer ID direkt zurück.
Mehr Informationen zur Verwendung von Timern können dem Tutorial entnommen
werden.
Beispiel aus plugin_CS (Funktion: HandleKickVote):
648 new Ratio = getvar("kick_ratio");
649 if (VoteCount >= Ratio*UserCount/100) {
650 if (g_AbortVote) {
651 say("Kick vote was aborted by an admin");
652 } else {
653 set_timer("KickUser",10,1,VoteUser);
654 }
Die Servervariable „kick_ratio“ wird als Ganzzahl in Ratio ausgelesen. Falls genügend
Stimmen für den Kick zusammengekommen sind, wird entweder der Kick abgebrochen, weil
ein Admin ihn aufgehalten hat, oder ein Timer ausgelöst, der einmal nach 10 Sekunden die
Funktion „KickUser“ ausführt. Der entsprechende Spieler wird von dieser Funktion dann vom
Server geworfen.
set_vaultdata( sKey[], sData[] );
sKey[]
Typ: String (100)
sData[]
Typ: String (200)
Die Funktion schreibtDaten (sData) mit dem Schlüssel (sKey) in die vault.ini. Die Daten
bleiben über einen Mapchange bzw. einen Serverneustart erhalten. Das Schlüssel-Daten-Paar
kann mit set_vaultdata oder get_vaultnumdata ausgelesen werden. Die Funktion ist ideal um
pluginspezifische Einstellungen zu speichern.
Weiß man bereits, dass die zu schreibenden Daten als Ganzzahl vorliegen, sollte man der
Funktion set_vaultnumdata den Vorzug geben.
Mit set_vaultdata kann auch ein Schlüssel gelöscht werden. Dazu muss ein leerer Datenstring
übergeben werden.
Beispiel aus plugin_retribution (Funktion: AddUserFlag):
69 if(get_vaultdata(sAuthID,VaultData,MAX_DATA_LENGTH) != 0) {
70 if (strcasestr(VaultData," llama") == -1) {
71 strcat(VaultData," llama", MAX_DATA_LENGTH);
72 set_vaultdata(sAuthID,VaultData);
73 }
Es wird versucht den Schlüssel mit der Steam ID des Spielers zu finden. Ist dies der Fall, wird
das Ergebnis in VaultData zwischengespeichert. Falls das Ergebnis nicht bereits den Teilstring
„ llama“ beinhaltet, wird dies dem Ergebis angehängt (strcat) und zurück in die vault.ini
geschrieben.
set_vaultnumdata( sKey[], iData );
sKey[]
Typ: String (100)
iData
Typ: Integer (0 - 2147483647)
Die Funktion schreibt Daten (sData) mit dem Schlüssel (sKey) als Ganzzahl (iData) in die
vault.ini. Die Daten bleiben über einen Mapchange bzw. einen Serverneustart erhalten. Das
Schlüssel-Daten-Paar wird mit get_vaultdata oder get_vaultnumdata ausgelesen. Die
Funktion ist ideal um pluginspezifische Einstellungen zu speichern.
Ist im Schlüssel ein String hinterlegt, darf man die Funktion nicht anwenden. Statt dessen ist
set_vaultdata zu verwenden.
Beispiel aus plugin_bk_botmanager
(Funktion: plugin_init):
346 if(!get_vaultnumdata("BK_BM_BOTS",iBots)){
347 set_vaultnumdata("BK_BM_BOTS",0);
348 if(getvar("admin_debug")>0){
349 log("[BK_BM] Basic setting missing in vault.ini. Creating new.");
350 }
351 }
Es wird überprüft, ob der Schlüssel BK_BM_BOTS existiert. Wenn dies nicht der Fall ist,
wird der Schlüssel angelegt und eine 0 hineingeschrieben. Falls admin_debug größer als 0 ist,
wird dies auch in den Logdateien dokumentiert.
setarg( arg, index=0, value );
arg
Typ: Integer (0 - 2147483647)
index=0
Typ: Integer (0 - 2147483647)
value
Typ: Integer (-2147483648 - 2147483647)
Diese Funktion wird nur Fällen gebraucht, wenn man die Argumente einer Funktion mit
variabler Argumentanzahl verändern möchte. Dabei gibt „arg“ die Position des Arguments
beginnend mit 0 an. Das Argument „index“ wird nur benötigt, wenn arg ein Feld (z.B. ein
String) ist. Es gibt die zu schreibende Zelle des Feldes an. Das Argument „value“ ist der neue
Wert, der zurückzuschreiben ist.
Beispiel:
sum(...){
new result = 0 ;
for (new i = 0; i < numargs(); ++i) {
result += getarg(i);
}
setarg(0,result);
return 1;
}
Eine Funktion „sum“ mit variabler Argumentanzahl (...) wird definiert. Eine For-Schleife fragt
die einzelnen Argumente ab und addiert sie. Die Summe wird über das erste Argument der
Funktion „sum“ zurückgegeben. Die direkte Rückgabe ist immer 1. Die Anzahl der
übergebenen Argumente wird mit numargs ermittelt.
setproperty( id=0, const name[]=“”, value=cellmin, const string[]=“”
);
id=0
Typ: Integer (-2147483648 - 2147483647)
const name[]=“”
Typ: String (variabel)
value=cellmin
Typ: Integer (-2147483648 - 2147483647)
const string[]=“”
Typ: String (variabel)
Mit dieser Funktion kann eine so genannte Property bei gegebenem Schlüssel (name oder
value) erstellt werden. Die Property wird als String im Speicher abgelegt. Es handelt sich
um eine Funktion, deren Benutzung unter Admin Mod vermieden werden sollte.
Stattdessen wird empfohlen z.B. die Funktionen get_vaultdata oder set_vaultdata
zurückzugreifen.
Mehr Informationen zum Thema sind im Abschnitt 8.14 nachzulesen.
Beispiel:
setproperty(2,“test_prop”,sString);
setproperty(3,15,sString);
Das erste Beispiel erstellt unter der ID 2 die Property „test_prop“ mit dem Inhalt aus der
Variable sString, während das zweite Beispiel unter der ID 3 die Property 15 mit dem gleichen
Inhalt erstellt.
setstrvar( cvar[], value[] );
cvar[]
Typ: String (100)
value[]
Typ: String (100)
Mit dieser Funktion können Servervariablen (cvar) gesetzt werden. Der Inhalt (value) muss als
String vorliegen. Eine äquivalente Funktion für Ganzzahlen existiert nicht, so dass diese vorab
in einen String umgewandelt werden müssen (numtostr).
Beispiel aus plugin_CS (Funktion: HandleRestartVote):
544 new Timelimit[MAX_NUMBER_LENGTH];
545 numtostr((getvar("mp_timelimit") * 60 - timeleft() + 10) / 60,Timelimit);
546 setstrvar("mp_timelimit",Timelimit);
547 setstrvar("sv_restartround","10");
548 say("Round restart vote succeeded.");
Vom aktuellen Zeitlimit auf dem Server wird die Restzeit abgezogen und 10 Sekunden addiert.
Dieser Wert wird in einen String umgewandelt (numtostr) und in die Servervariable
„mp_timelimit“ als neues Zeitlimit eingetragen. Anschließend wird mit dem Setzen der
Variable „sv_restartround“ auf 10 ein Maprestart nach 10 Sekunden angefordert und der
Restart allen Spielern mitgeteilt.
8.10.158 slap
slap( sPlayer[] );
sPlayer[]
Typ: String (33)
Die Funktion schlägt den angegebenen Spieler (sPlayer). Er wird dabei leicht in eine zufällige
Richtung gestoßen, und es werden ihm fünf Lebenspunkte abgezogen. Ein Spieler kann durch
diese Aktion nie weniger als einen Lebenspunkt bekommen. Der Schlag wird bei einem
Lebenspunkt als abzugsfreier Stoß durchgeführt.
Beispiel aus plugin_retribution (Funktion: admin_slap):
317 if(check_immunity(Data)!=0) {
318 snprintf(Text, MAX_TEXT_LENGTH, "Laf. You can’t slap %s", TargetName);
319 messageex(User, Text, print_chat);
320 } else {
321 slap(Data);
322 }
Hat die Person (Data) Immunitätsrechte, wird eine Fehlermeldung an den Admin ausgegeben.
Anderenfalls wird die Person geschlagen.
8.10.159 slay
slay( sPlayer[] );
sPlayer[]
Typ: String (33)
Der Spieler (sPlayer) wird durch diese Funktion getötet. Wenn admin_fx aktiviert ist, wird
die Aktion durch zusätzliche Effekte untermalt.
Beispiel aus plugin_retribution (Funktion: admin_slap):
317 if(check_immunity(TargetName)!=0) {
318 snprintf(Text, MAX_TEXT_LENGTH, "Laf. You can’t slay %s", TargetName);
319 messageex(User, Text, print_chat);
320 } else {
321 if ( slay(TargetName) ) {
322 PlaySoundToAll("ambience/thunder_clap.wav");
Hat die Person (Data) Immunitätsrechte, wird eine Fehlermeldung an den Admin ausgegeben.
Anderenfalls wird die Person getötet. Wenn die Aktion erfolgreich war, wird darüber hinaus
über eine pluginspezifische Funktion (PlaySoundToAll) eine Sounddatei bei allen Spielern
abgespielt.
snprintf( sDest[], iLength, sFormat[], ... );
sDest[]
Typ: String (200)
iLength
Typ: Integer (0 - 200)
sFormat[]
Typ: String (200)
...
variable Anzahl an Argumenten (kommagetrennt)
Mit dieser Funktion können auf einfache Weise Variablen unterschiedlicher Datentypen (...) in
einen String (sDest mit Länge iLength) eingebettet werden. Über einen weiteren String
sFormat wird festgelegt, wie die Variablen eingebunden werden sollen. Die Reihenfolge der
Platzhalter im Format-String muss der Reihenfolger der Argumente im Anschluss an selbigen
entsprechen.
Folgende Platzhalter stehen zur Verfügung:
-
%c
- Einzelnes Zeichen
-
%d
- Ganzzahl (man sieht oft %i, was aber nicht korrekt ist, aber trotzdem funktioniert)
-
%q
- Festkommazahl
-
%s
- Zeichenkette (String)
Beispiel aus plugin_blatt_map
(Funktion: DebugHeap):
3641 DebugHeap(context[]) {
3642 if (g_DebugLevel >= 2) {
3643 new heapsize[MAX_TEXT_LENGTH];
3644 snprintf(heapsize,MAX_TEXT_LENGTH,"[%s] %i free bytes.",context,heapspace());
3645 plugin_message(heapsize);
3646 }
3647 return 0;
3648 }
Wenn der in der globalen Variable (g_DebugLevel) Debuglevel größer oder gleich zwei ist,
wird der noch verbleibende Heap-Speicher ermittelt (Ganzzahl). Mit dem String (context) soll
diese Ganzzahl in der Variable heapsize eingebettet werden. Die Reihenfolge der Platzhalter
(%s vor %i) bestimmt die Reihenfolge der Argumente (context vor heapspace()). Ist context
gleich „Test“ und die Rückgabe von heapspace gleich 936, dann sähe der String heapsize
folgendermaßen aus:
[Test] 936 free bytes.
Zuletzt wird dieser Text in der Console unter Angabe des Pluginnamens ausgegeben
(plugin_message).
spawn( sClass[], iX, iY, iZ, iXAngle, iYAngle, iZAngle );
sClass[]
Typ: String (100)
iX
Typ: Integer (-2147483648 - 2147483647)
iY
Typ: Integer (-2147483648 - 2147483647)
iZ
Typ: Integer (-2147483648 - 2147483647)
iXAngle
Typ: Integer (0 - 359)
iYAngle
Typ: Integer (0 - 359)
iZAngle
Typ: Integer (0 - 359)
Die Funktion erstellt ein Item (iClass) auf einer bestimmten Position (iX, iY, iZ) und in einer
bestimmten Ausrichtung (iXAngle, iYAngle, iZAngle). Es wird die ID des Items
zurückgegeben.
Die Funktionalität steht mittlerweile nicht mehr zur Verfügung.
Beispiel aus plugin_spawn (Funktion: admin_spawn):
143 iIdentity = spawn(strClass,X,Y,Z,XAngle,YAngle,ZAngle);
144 if (iIdentity != 0) {
145 snprintf(Text,MAX_TEXT_LENGTH,"Spawn created with ID %i.",iIdentity);
146 selfmessage(Text);
147 say_command(User,Command,Data);
148 } else {
149 selfmessage("Failed.");
150 }
Es wird versucht ein Item an den genannten Koordinaten und in den gegebenen Winkeln zu
erstellen. Falls dies erfolgreich war, wird eine Erfolgsmeldung an den Admin und alle anderen
Spieler ausgegeben. Anderenfalls wird nur der Admin über den fehlgeschlagenen Versuch
informiert.
speakto( sTarget[], sSentence[] );
sTarget[]
Typ: String (33)
sSentence[]
Typ: String (100)
Mit dieser Funktion kann man bei einem Spieler (sTarget) die in Half-Life integrierte
Sprachausgabe nutzen. Dafür muss der Soundtyp und der zu sprechende Satz definiert werden
(sSentence). Ein Überblick über die zur Verfügung stehenden Soundtypen und der jeweiligen
Sounds kann dem Anhang entnommen werden.
Beispiel aus plugin_sdal_time_manager
(Funktion: speak_timeleft):
717 numtoword(minutes,Min,MAX_NUMBER_LENGTH);
718 numtoword(seconds,Sec,MAX_NUMBER_LENGTH);
719 snprintf(Text,MAX_DATA_LENGTH,"fvox/%s minutes %s seconds remaining",Min,Sec);
720 speakto(User,Text);
Mit der userdefinierten Funktion numtoword werden die Minuten und Sekunden von
Ganzzahlen in ausgeschriebene, englischsprachige Strings umgewandelt (z.B. 10 in
„ten“ oder 3 in „three“). Diese können von den Soundtypen vox (männliche Stimme)
und fvox (weibliche Stimme) wiedergegeben werden. Da hier die weibliche Stimme
benötigt wird, stellt man „fvox/“ dem Satz voran. Durch das Einbetten der Minuten
und Sekunden kann der Satz (Text) beim Spieler (User) ausgegeben werden. Es
können nur Wörter verwendet werden, die für den jeweiligen Soundtyp vorhanden
sind.
strbreak( str[], first[], second[], maxlen, flen=sizeof first,
slen=sizeof second );
str[]
Typ: String (200)
first[]
Typ: String (200)
second[]
Typ: String (200)
maxlen Typ: Integer (1 - 200)
flen=sizeof first Typ: Integer (1 - 200)
slen=sizeof second Typ: Integer (1 - 200)
Diese Funktion teilt einen gegebenen String (str mit der Länge maxlen) beim ersten
Leerzeichen in zwei Teile (first und second). Die Längen der zwei Teile sind optional, und im
Allgemeinen nicht notwendig zu definieren. Es gibt allerdings mittlerweile bessere Funktionen
(strsep und strsplit), die das Gleiche und noch mehr können.
Beispiel aus plugin_base (Funktion: admin_ban):
57 convert_string(HLCommand,Command,MAX_COMMAND_LENGTH);
58 convert_string(HLData,Data,MAX_DATA_LENGTH);
59 convert_string(HLUserName,User,MAX_NAME_LENGTH);
60
61 strbreak(Data,ban_user,strTime, MAX_DATA_LENGTH);
62 strbreak(strTime, strTime, strType, MAX_DATA_LENGTH);
Zunächst werden die HL Strings in Small Strings konvertiert (convert_string). Anschließend
wird der zu bannende Spieler (ban_user) von der Dauer des Banns (strTime) getrennt. Ein
weiterer Trennversuch sorgt dafür, dass der gegebenenfalls in strTime vorhandene Typ des
Banns (ID oder IP) in strType abgetrennt wird. Ist er nicht angegeben, ist der String
leer.
strcasecmp( sString1[], sString2[] );
sString1[]
Typ: String (200)
sString2[]
Typ: String (200)
Die Funktion vergleicht zwei Strings (sString1 und sString2) über ihre gesamte Länge.
Groß- und Kleinschreibung wird nicht beachtet. Sind beide Strings identisch, wird
eine 0 zurückgegeben. Man erhält eine 0 zurück, wenn beide Strings gleich sind.
Ist das erste ungleiche Zeichen in den Strings bei sString1 größer als bei sString2,
wird eine Zahl größer als 0 zurückgegeben. Umgekehrt wird eine Zahl kleiner als 0
zurückgegeben.
Beispiel aus plugin_bk_botmanager
(Funktion: admin_bot_set):
266 strbreak(sValue,sBotCvar,sValue,MAX_DATA_LENGTH);
267 strtrim(sValue," ",2);
268 strtrim(sBotCvar," ",2);
269
270 if(strcasecmp(sBotCvar,"bots")==0){
Der Wert sValue wird in sBotCvar und sValue aufgeteilt (strbreak). Beiden Variablen werden
am Anfang und am Ende von möglichen Leerzeichen befreit (strtrim). Die Ausführung der
If-Verzweigung erfolgt nur, wenn die Variable sBotCvar genau dem String „bots“ entspricht,
wobei die Groß- und Kleinschreibung keine Rolle spielt.
strcasestr( sSource[], sSearch[] );
sSource[]
Typ: String (200)
sSearch[]
Typ: String (200)
Die Funktion sucht einen String (sSearch) in einem anderen String (sSource). Groß-
und Kleinschreibung wird nicht beachtet. Wird der Suchstring gefunden, gibt die
Funktion eine Zahl größer als 0 zurück. Wenn der String nicht gefunden wurde, gibt die
Funktion eine -1 zurück. Ist der Suchstring gleich dem anderen String wird eine 0
zurückgegeben.
Beispiel aus plugin_chat (Funktion: HandleSay):
57 if ( strcasestr(MessageMode[UserIndex], "admin_") >= 0 ) {
58 plugin_exec( MessageMode[UserIndex], Data );
59 return PLUGIN_HANDLED;
Es wird ohne Beachtung der Groß- und Kleinschreibung der String „admin_“ im
Admin Mod Befehl (in MessageMode[UserIndex]) gesucht. Ist er enthalten, wird der
Befehl mit den Parametern (Data) ausgeführt (plugin_exec) und die Ausführung
beendet.
strcasestrx( sSource[], sSearch[] );
sSource[]
Typ: String (200)
sSearch[]
Typ: String (200)
Die Funktion sucht einen String (sSearch) in einem anderen String (sSource). Groß- und
Kleinschreibung wird nicht beachtet. Wird der Suchstring gefunden, gibt die Funktion eine
Zahl größer als 0 zurück. Wenn der String nicht gefunden wurde oder leer ist, gibt die
Funktion eine -1 zurück. Ist der Suchstring gleich dem anderen String wird eine 0
zurückgegeben.
Beispiel aus plugin_sdal_logd_hp50
(Funktion: HandleSay):
677 if (strcasestrx(Data, "hp")!=-1){
678 if(g_PlayerEnemyID[UserIndex]!=0 && IsDead == 1){
679 display_victim(User,UserIndex);
680 }else{
681 display_statistik(User,UserIndex);
682 }
683 }else if (strcasestrx(Data, "myhits")!=-1){
684 own_statistic(User,UserIndex);
685 }else if (strcasestrx(Data, "hits")!=-1){
686 most_damage(User,UserIndex);
687 }else if (strcasestrx(Data, "weapon")!=-1){
688 most_used_weapon(User,UserIndex);
689 }
Die If-Verzweigung überprüft, ob einige Begriffe in Data vorkommen oder den gleichen Inhalt
haben. Ist dies der Fall, werden entsprechende Unterfunktionen aufgerufen, die dem Spieler
unterschiedliche Statistikinformationen auf dem Bildschirm darstellen.
strcat( sDest[], sSource[], iMaxLen );
sDest[]
Typ: String (200)
sSearch[]
Typ: String (200)
iMaxLen
Typ: Integer (0 - 200)
Diese Funktion fügt einen String (sSource mit der Länge iMaxLen) an einen anderen (sDest)
an.
Beispiel aus plugin_CS (Funktion: LoadDefaultRestrictions):
934 currentmap(strMap,100);
935 strcpy(strName,"WeaponRestrictions_",100);
936 strcat(strName,strMap,100);
Zunächst wird die aktuelle Map ermittelt und in strMap geschrieben. Danach wird die
Zeichenkette „WeaponRestrictions_“ in die Variable strName geschrieben. Abschließend wird
der String strName durch den String strMap erweitert. Ist die aktuelle Map „de_dust“, ist
strName am Ende „WeaponRestrictions_de_dust“.
strchr( sSource[], iChar );
sSource[]
Typ: String (200)
iChar
Typ: Integer (0 - 256)
Die Funktion ermittelt die Position des ersten Vorkommens des Zeichens (iChar) im String
(sSource) von links beginnend. Für das Zeichen muss die ASCII-Nummer angegeben werden.
Vereinfacht kann auch das entsprechende Zeichen in einfache Anführungszeichen
gesetzt werden. Die Funktion liefert -1 zurück, falls das Zeichen nicht gefunden
wurde.
Beispiel aus plugin_blatt_map
(Funktion: GetShortName):
3022 new pos = strchr(fullname,’_’);
3023 if (pos>0) {
3024 pos = pos +1;
3025 }
3026 else {
3027 pos = 0;
3028 }
Es wird das erste Vorkommen vom Unterstrich im String fullname gesucht. Ist die Position
größer als 0, wird die Position inkrementiert. Andernfalls wird die Position auf 0
gesetzt.
strcmp( sString1[], sString2[] );
sString1[]
Typ: String (200)
sString2[]
Typ: String (200)
Die Funktion vergleicht zwei Strings (sString1 und sString2) über ihre gesamte Länge. Groß-
und Kleinschreibung wird beachtet. Sind beide Strings identisch, wird eine 0 zurückgegeben.
Man erhält eine 0 zurück, wenn beide Strings gleich sind. Ist das erste ungleiche Zeichen in
den Strings bei sString1 größer als bei sString2, wird eine Zahl größer als 0 zurückgegeben.
Umgekehrt wird eine Zahl kleiner als 0 zurückgegeben.
Beispiel aus plugin_CS (Funktion: SetRestrictions):
609 } else if(strcmp(Data,"help") == 0) {
610 ShowHelp(Status);
Falls Data „help“ unter Berücksichtigung der Groß- und Kleinschreibung entspricht, wird eine
pluginspezifische Funktion zur Darstellungen der Optionen ausgeführt.
strcount( sSource[], iChar );
sSource[]
Typ: String (200)
iChar
Typ: Integer (1 - 256)
Die Funktion zählt das Vorkommen eines Zeichens (iChar) in einem String (sSource).
Vereinfacht kann auch das entsprechende Zeichen in einfache Anführungszeichen gesetzt
werden.
Beispiel aus plugin_bk_cron
(Funktion: admin_cron_add):
648 if(strcount(task,’ ’)<6){
649 /* selfmessage("Task not valid!"); */
650 selfmessage(cron_tnv);
651 /* selfmessage("Usage: admin_cron_add <min> <h> <d> <mo> <wd> <cv> <cmd>"); */
652 selfmessage(cron_adduse);
653 return PLUGIN_HANDLED;
654 }
Die Anzahl der Leerzeichen wird im String task gesucht. Falls die Anzahl kleiner als 6 ist, wird
eine zweizeilige Fehlermeldung in der Console des Admins ausgegeben.
strcpy( sDest[], sSource[], iMaxLen );
sDest[]
Typ: String (200)
sSource[]
Typ: String (200)
iMaxLen
Typ: Integer (0 - 200)
Kopiert einen String (sSource) über einen anderen (sDest mit der Länge iMaxLen).
Beispiel aus plugin_base (Funktion: admin_pass):
338 if (streq(Command, "admin_nopass")==1) {
339 strcpy(Data,"^"^"",MAX_DATA_LENGTH);
Wenn der ausgeführte Befehl „admin_nopass“ lautet, werden keine Parameter erwartet. Um
der Servervariable „sv_password“ später auf einen leeren Wert zu setzen, wird Data auf zwei
Anführungszeichen gesetzt (“”).
strcspn( sSource[], sSearch[] );
sSource[]
Typ: String (200)
sSearch[]
Typ: String (200)
Die Funktion sucht Zeichen aus einem String (sSearch) in einem anderen String (sSource). Sie
gibt die Länge des Teilstrings zurück, der von links beginnend, kein Zeichen aus sSearch
besitzt. Da Strings Felder sind, ist die Länge gleichzeitig die Position des ersten in sSearch
vorhandenen Zeichens.
Beispiel:
new sTest[MAX_TEXT_LENGTH]="Test123Test";
new iTest=strcspn(sTest,"1234567890");
Im Beispiel wird im String sTest nach Zahlen gesucht werden. Da die erste Zahl an der
Position 4 liegt, wird als Länge 4 ausgegeben.
streq( strOne[], strTwo[] );
strOne[]
Typ: String (200)
strTwo[]
Typ: String (200)
Die Funktion überprüft unter Berücksichtigung der Groß- und Kleinschreibung, ob zwei
Strings (strOne und strTwo) identisch sind. Sind sie identisch wird eine 0, wenn nicht wird
eine 1 zurückgegeben.
Beispiel aus plugin_base (Funktion: admin_csay):
136 if (streq(Color,"red")==1) {
137 centersay(Message,10,250,10,10);
Wenn der Text Color gleich „red“ ist, wird die Nachricht in Message für 10 Sekunden in einen
hellem Rot dargestellt.
strgsep( sSource[], sDelimiters[], sGrouping[], ... );
sSource[]
Typ: String (200)
sDelimiters[]
Typ: String (200)
sGrouping[]
Typ: String (200)
...
variable Anzahl an Argumenten und Stringlängen (kommagetrennt)
Diese Funktion trennt einen String (sSource) an im String (sDelimitiers) angegebenen Zeichen.
Die Trennung wird dort nicht ausgeführt, wo die Zeichenkette von den im String (sGrouping)
angegebenen Zeichen umschlossen wird. Werden nicht ausreichend Argumente (...) für die
Aufnahme der Teilstrings angegeben, wird der Rest ungetrennt im letzten Argument
übergeben.
Die Funktion gibt zurück, wieviele Teilstrings gefunden wurden bzw. -1, wenn kein Teilstring
gefunden wurde.
Beispiel aus plugin_CS (Funktion: SetRestrictions):
710 strgsep(Data[7]," ","’",sPlayer,MAX_AUTHID_LENGTH,sWhat,MAX_DATA_LENGTH);
711 if(check_user(sPlayer) == 0) {
712 selfmessage("Unrecognized player: ");
713 selfmessage(sPlayer);
714 selfmessage("If the player name you specified containes spaces");
715 selfmessage("try encosing it with single quotes (’).");
716 return PLUGIN_HANDLED;
717 }
Der String Data[7] wird an den Leerzeichen getrennt. Es werden nur zwei Argumente definiert
(sPlayer und sWhat). Falls mehr als ein Leerzeichen auftritt, wird nur am ersten getrennt und
der Rest in sWhat geschrieben. Hat ein Spieler ein Leerzeichen im Namen, würde der
Spielername getrennt und der zweite Teil des Namens mit in sWhat geschrieben. Daher
wurden als Gruppierungszeichen die einfachen Anführungszeichen gewählt. Ist der Spielername
von diesen Zeichen umschlossen, wird dieser Teil für die Trennung ausgeschlossen und die
Trennung am nächsten Leerzeichen durchgeführt.
Anschließend wird überprüft, ob eine Spieler dieses Namens existiert. Wenn nicht, wird eine
vierzeilige Fehlermeldung in der Console ausgegeben.
strgsplit( sSource[], sDelimiters[], sGrouping[], ... );
sSource[]
Typ: String (200)
sDelimiters[]
Typ: String (200)
sGrouping[]
Typ: String (200)
...
variable Anzahl an Argumenten und Stringlängen (kommagetrennt)
Diese Funktion trennt einen String (sSource) an im String (sDelimitiers) angegebenen Zeichen.
Die Trennung wird dort nicht ausgeführt, wo die Zeichenkette von den im String (sGrouping)
angegebenen Zeichen umschlossen wird. Werden nicht ausreichend Argumente (...) für die
Aufnahme der Teilstrings angegeben, wird der Rest verworfen.
Die Funktion gibt zurück, wieviele Teilstrings gefunden wurden bzw. -1, wenn kein Teilstring
gefunden wurde.
Beispiel aus plugin_gnc_filtersay
(Funktion: readcfg):
72 for (new i=0;(i<MAX_WORDS && readfile(filename,sData,(i+1),MAX_DATA_LENGTH));i++){
73 strgsplit(sData, " ", "^"", BadWord[i], MAX_PL, GoodWord[i], MAX_PL);
74
75 }
Wenn der Dateiname existiert (fileexists), wird die gesamte Datei zeilenweise ausgelesen. Jede
Zeile wird an den Leerzeichen getrennt, wobei in Begriffe in doppelten Anführungszeichen
nicht getrennt werden. Ist ein zweites Leerzeichen außerhalb der Anführungszeichen
vorhanden, wird der letzte Teilstring ignoriert.
strgtok( sSource[], sDelimiters[], sGrouping[], sToken[], iMaxLen );
sSource[]
Typ: String (200)
sDelimiters[]
Typ: String (200)
sGrouping[]
Typ: String (200)
sToken[]
Typ: String (200)
iMaxLen
Typ: Integer (0 - 200)
Diese Funktion trennt einen String (sSource) am ersten im String (sDelimitiers) angegebenen
Zeichen. Die Trennung wird dort nicht ausgeführt, wo die Zeichenkette von den im
String (sGrouping) angegebenen Zeichen umschlossen wird. Sollen weitere Teilstrings
abgetrennt werden, kann die Funktion wiederholt ausgeführt werden. Dabei darf
sSource nicht angegeben werden. Ein möglicher Reststring kann mit strgtokrest
ausgegeben werden. Bequemer sind die Funktionen strgsep und strgsplit für mehrere
Trennungen.
Die Funktion gibt -1 zurück, wenn kein Trennzeichen gefunden wurde.
Beispiel:
new sTest[MAX_TEXT_LENGTH]="?Test/12?/3/Test";
strgtok(sTest,"/","?",sToken1,MAX_DATA_LENGTH);
strgtok("","/","?",sToken2,MAX_DATA_LENGTH);
strgtokrest(sToken3,MAX_DATA_LENGTH);
Der String (sTest) soll getrennt an allen Slashes getrennt werden. Dabei sind mit Fragezeichen
umrahmte Zeichenketten ausgenommen. Die Aktion wird dann wiederholt und am Ende der
Rest ausgegeben. Demnach ist sToken1 = „Test/12“, sToken2 = „3“ und sToken3
=“Test“.
strgtokrest( sRest[], iMaxLen );
sRest[]
Typ: String (200)
iMaxLen
Typ: Integer (0 - 200)
Die Funktion gibt den Reststring (sRest mit der Länge iMaxLen) nach Ausführung von
strgtok aus. Ist strgtok oder der Reststring leer, wird -1 zurückgegeben.
Beispiel:
new sTest[MAX_TEXT_LENGTH]="?Test/12?/3/Test";
strgtok(sTest,"/","?",sToken1,MAX_DATA_LENGTH);
strgtok("","/","?",sToken2,MAX_DATA_LENGTH);
strgtokrest(sToken3,MAX_DATA_LENGTH);
Der String (sTest) soll getrennt an allen Slashes getrennt werden. Dabei sind mit Fragezeichen
umrahmte Zeichenketten ausgenommen. Die Aktion wird dann wiederholt und am Ende der
Rest ausgegeben. Demnach ist sToken1 = „Test/12“, sToken2 = „3“ und sToken3
=“Test“.
strinit( sString[] );
sString[]
Typ: String (200)
Die Funktion löscht den Inhalt des angegebenen Strings (sString).
Beispiel aus plugin_hldsld_mapvote (Funktion: ResetVoteData):
277 new i;
278 for(i=0;i<MAX_MAPS;i++) {
279 strinit(Maps[i]);
280 }
Die For-Schleife löscht alle Mapnamen aus dem Feld Maps.
strlen( const string[] );
const string[]
Typ: String (200)
Die Funktion gibt die Länge der in einem String (string) abgelegten Zeichenkette aus. Sie kann
auch mit gepackten Strings umgehen (siehe dazu strpack).
Beispiel aus plugin_base (Funktion: admin_kick):
272 if (strlen(Reason) != 0) {
273 snprintf(Text, MAX_TEXT_LENGTH, "You have been kicked because %s", Reason);
274 message(real_user, Text);
275 }
276 kick(real_user);
Über die Länge des Strings Reason wird überprüft, ob ein Grund für den Kick angegeben
wurde. Wenn es der Fall ist, wird dies dem Spieler mitgeteilt (message). Anschließend wird der
Spieler vom Server geworfen.
strmatch( sOne[], sTwo[], iLength);
strOne[]
Typ: String (200)
strTwo[]
Typ: String (200)
iLength
Typ: Integer (1 - 200)
Die Funktion überprüft unter Berücksichtigung der Groß- und Kleinschreibung, ob zwei
Strings (strOne und strTwo) für die ersten x Zeichen (iLength) identisch sind. Sind sie
identisch wird eine 1, wenn nicht wird eine 0 zurückgegeben.
Beispiel aus plugin_fun (Funktion: HandleSay):
242 convert_string(HLCommand,Command,MAX_COMMAND_LENGTH);
243 convert_string(HLData,Data,MAX_DATA_LENGTH);
244 convert_string(HLUserName,User,MAX_NAME_LENGTH);
245
246 strstripquotes(Data);
247
248 if (strmatch(Data, "glow ", strlen("glow "))==1) {
Zunächst werden die Funktionsargumente in Small-Strings konvertiert (convert_string).
Danach werden mögliche Anführungszeichen um den String entfernt (strstripquotes).
Abschließend wird nur dann die If-Verzweigung ausgeführt, wenn die ersten 5 Zeichen von
Data mit „glow „ übereinstimmen.
strncasecmp( sString1[], sString2[], iNum );
sString1[]
Typ: String (200)
sString2[]
Typ: String (200)
iNum
Typ: Integer (0 - 200)
Die Funktion vergleicht zwei Strings (sString1 und sString2) über die Länge (iNum).
Groß- und Kleinschreibung wird nicht beachtet. Sind beide Strings identisch, wird
eine 0 zurückgegeben. Man erhält eine 0 zurück, wenn beide Strings gleich sind.
Ist das erste ungleiche Zeichen in den Strings bei sString1 größer als bei sString2,
wird eine Zahl größer als 0 zurückgegeben. Umgekehrt wird eine Zahl kleiner als 0
zurückgegeben.
Beispiel aus plugin_dio_motm
(Funktion: say_motm):
210 if (strncasecmp(strColor,"!red",4)==0) {
211 Red = 250;
212 Green = 10;
213 Blue =10;
Es wird überprüft, ob die ersten 4 Zeichen in strColor „!red“ entsprechen. Nur dann werden
die Farbanteile (Red, Green und Blue) definiert.
strncat( sDest[], sSource[], iNum, iMaxLen );
sDest[]
Typ: String (200)
sSearch[]
Typ: String (200)
iNum
Typ: Integer (0 - 200)
iMaxLen
Typ: Integer (0 - 200)
Diese Funktion fügt einen String (sSource mit der Länge iMaxLen) an einen anderen (sDest)
an. Es werden jedoch nur eine bestimmte Anzahl an Zeichen (iNum) vom String (sSource)
angehängt.
Beispiel:
new sTest1[MAX_TEXT_LENGTH]="Test123";
new sTest2[MAX_TEXT_LENGTH]="Test456";
strncat(sTest1,Test2,5,MAX_TEXT_LENGTH);
Es werden nur die ersten 5 Zeichen von sTest2 an sTest1 angehängt. Der String sTest1 ist nach
der Anwendung von strncat „Test123Test4“.
strncmp( sString1[], sString2[], iNum );
sString1[]
Typ: String (200)
sString2[]
Typ: String (200)
iNum
Typ: Integer (0 - 200)
Die Funktion vergleicht zwei Strings (sString1 und sString2) über eine bestimmte Länge
(iNum). Groß- und Kleinschreibung wird beachtet. Sind beide Strings identisch, wird
eine 0 zurückgegeben. Man erhält eine 0 zurück, wenn beide Strings gleich sind.
Ist das erste ungleiche Zeichen in den Strings bei sString1 größer als bei sString2,
wird eine Zahl größer als 0 zurückgegeben. Umgekehrt wird eine Zahl kleiner als 0
zurückgegeben.
Beispiel aus plugin_CS (Funktion: SetRestrictions):
679 if(strncmp(Data,"team ",5) == 0) {
680 new sTeam[3];
681 new sWhat[MAX_DATA_LENGTH];
682 new iTeam;
683 strsep(Data[5]," ",sTeam,3,sWhat,MAX_DATA_LENGTH);
Falls die ersten fünf Zeichen von Data unter Berücksichtigung der Groß- und Kleinschreibung
„team “ entsprechen, wird der String Data[5] über ein Leerzeichen in sTeam und sWhat
geteilt.
strncpy( sDest[], sSource[], iNum, iMaxLen );
sDest[]
Typ: String (200)
sSource[]
Typ: String (200)
iNum
Typ: Integer (0 - 200)
iMaxLen
Typ: Integer (0 - 200)
Kopiert einen String (sSource) über einen anderen (sDest mit der Länge iMaxLen), wobei nur
eine bestimmte Anzahl an Zeichen (iNum) kopiert werden.
Beispiel aus plugin_jack9_chime
(Funktion: SpeakTime):
93 if(streq(THour, "12")==1) {
94 strncpy(words[1], "twelve ", strlen("twelve "),MAX_DATA_LENGTH);
95 }
Wenn der String THour „12“ entspricht, werden nur die ersten 7 Zeichen von „twelve „ in
words[1] geschrieben.
strpack( dest[], const source[] );
dest[]
Typ: String (200)
const source[]
Typ: String (200)
Durch diese Funktion wird ein String (source) gepackt und in einen anderen (dest)
geschrieben. Der neue String benötigt nur ein Viertel des Speicherplatzes. Unter Umständen
kann man ein wenig Speicher sparen. Es rentiert sich aber nur, wenn nicht gleichzeitig der
gleiche String ungepackt definiert wird. Außerdem sollte man in Admin Mod seine
Plugins auf Geschwindigkeit nicht Speicher optimieren. Speicher ist eigentlich nie ein
Problem.
Beispiel:
new spTest[7 char];
strpack(spTest,"Test123");
Es wird ein Feld spTest für einen gepackten String von sieben Zeichen länge definiert.
Anschließend wird „Test123“ gepackt und in spTest geschrieben.
strrchr( sSource[], iChar );
sSource[]
Typ: String (200)
iChar
Typ: Integer (0 - 256)
Die Funktion ermittelt die Position des ersten Vorkommens des Zeichens (iChar) im String
(sSource) von rechts beginnend. Für das Zeichen muss die ASCII-Nummer angegeben werden.
Vereinfacht kann auch das entsprechende Zeichen in einfache Anführungszeichen
gesetzt werden. Die Funktion liefert -1 zurück, falls das Zeichen nicht gefunden
wurde.
Die Funktion ist ein Alias für rindex.
Beispiel aus plugin_rindy_chasecam
(Funktion: plugin_connect):
46 convert_string(HLIP,UserIP,MAX_IP_LENGTH);
47 if(strrchr(UserIP,’:’) != -1) UserIP[strrchr(UserIP,’:’)] = 0;
Es wird zunächst der HL String HLIP in den Small String UserIP konvertiert. Anschließend
wird überprüft, ob der Doppelpunkt in UserIP zu finden ist. Ist dies der Fall wird anstelle des
Doppelpunktes ein 0 in die Zelle des Strings geschrieben, was den String an dieser Stelle
beendet. Auf diese Weise wird der übergebene Port abgetrennt.
strsep( sSource[], sDelimiters[], ... );
sSource[]
Typ: String (200)
sDelimiters[]
Typ: String (200)
...
variable Anzahl an Argumenten und Stringlängen (kommagetrennt)
Diese Funktion trennt einen String (sSource) an im String (sDelimitiers) angegebenen Zeichen.
Werden nicht ausreichend Argumente (...) für die Aufnahme der Teilstrings angegeben, wird
der Rest ungetrennt im letzten Argument übergeben.
Die Funktion gibt zurück, wieviele Teilstrings gefunden wurden bzw. -1, wenn kein Teilstring
gefunden wurde.
Beispiel aus plugin_CS (Funktion: SetRestrictions):
679 if(strncmp(Data,"team ",5) == 0) {
680 new sTeam[3];
681 new sWhat[MAX_DATA_LENGTH];
682 new iTeam;
683 strsep(Data[5]," ",sTeam,3,sWhat,MAX_DATA_LENGTH);
Falls die ersten fünf Zeichen von Data „team “ unter Berücksichtigung der Groß- und
Kleinschreibung entsprechen, wird der String Data[5] über ein Leerzeichen in sTeam und
sWhat geteilt.
strsplit( sSource[], sDelimiters[], ... );
sSource[]
Typ: String (200)
sDelimiters[]
Typ: String (200)
...
variable Anzahl an Argumenten und Stringlängen (kommagetrennt)
Diese Funktion trennt einen String (sSource) an im String (sDelimitiers) angegebenen Zeichen.
Werden nicht ausreichend Argumente (...) für die Aufnahme der Teilstrings angegeben, wird
der Rest verworfen.
Die Funktion gibt zurück, wieviele Teilstrings gefunden wurden bzw. -1, wenn kein Teilstring
gefunden wurde.
Beispiel aus plugin_bk_cron
(Funktion: admin_cron_refresh):
229 strsplit(timevar[j],"/",szaehler,3,snenner,3);
230 zaehler=strtonum(szaehler);
231 nenner=strtonum(snenner);
Der String timevar[j] wird über den Slash als Trennzeichen in zwei Strings (Länge jeweils 3)
szaehler und snenner aufgeteilt. Beide Strings werden in Ganzzahlen umgewandelt
(strtonum).
strspn(sSource[], sSearch[] );
sSource[]
Typ: String (200)
sSearch[]
Typ: String (200)
Die Funktion sucht Zeichen aus einem String (sSearch) in einem anderen String (sSource). Sie
gibt die Länge des Teilstrings zurück, der von links beginnend, nur Zeichen aus sSearch
besitzt. Da Strings Felder sind, ist die Länge gleichzeitig die Position des ersten in sSearch
vorhandenen Zeichens.
Beispiel aus
plugin_rindy_advretribution
(Funktion: AdminSlapTeam):
91 if(strlen(Data) == 0 || strlen(Data) != strspn(Data,"1234")) {
92 selfmessage("Wrong syntax");
93 selfmessage("You must enter the team number (1 - 4).");
Es wird überprüft, ob die Stringlänge von Data 0 ist. Weiterhin wird überprüft, wie lang der
Teilstring von Data ist, der nur die Zahlen von 1 bis 4 beinhalten. Ist die Länge des Teilstrings
ungleich der Gesamtlänge, besteht der String nicht nur aus den Zahlen 1 bis 4. Es wird dann
eine zweizeilige Fehlermeldung ausgegeben.
strstr( sSource[], sSearch[] );
sSource[]
Typ: String (200)
sSearch[]
Typ: String (200)
Die Funktion sucht einen String (sSearch) in einem anderen String (sSource). Groß- und
Kleinschreibung wird beachtet. Wird der Suchstring gefunden, gibt die Funktion eine Zahl
größer als 0 zurück. Wenn der String nicht gefunden wurde, gibt die Funktion eine -1 zurück.
Ist der Suchstring gleich dem anderen String wird eine 0 zurückgegeben.
Beispiel aus plugin_base (Funktion: admin_rcon):
443 if (strstr(Data, "rcon_password") >= 0) {
444 reject_message();
445 return PLUGIN_HANDLED;
446 }
Hierbei handelt es sich um eine Absicherung, dass kein Admin, der Zugriff zu admin_rcon hat,
sich unberechtigt Zugriff zu RCon verschafft, indem er das Passwort ändert. Falls
der String Data die Servervariable rcon_password beinhaltet, wird die Meldung
„You do not have access to this command“ angezeigt und die weitere Abarbeitung
abgebrochen.
strstripquotes( str[] );
str[]
Typ: String (200)
Die Funktion löscht eventuell vorhandene Anführungszeichen am Anfang und am Ende eines
Strings. Es ist zwingend notwendig bei der Abarbeitung von Chatnachrichten (say, say_team)
diese Funktion auszuführen. Der Text ist immer in Anführungszeichen.
Für beliebige Zeichen am Stringanfang und Ende kann auch strtrim verwendet werden.
Beispiel aus plugin_base (Funktion: admin_dmsg):
179 switch( sType[0] ) {
180 case ’i’:
181 tType = uid_index;
182 case ’s’:
183 tType = uid_SessionID;
184 case ’w’:
185 tType = uid_wonID;
186 default:
187 tType = uid_invalid;
188 } // switch()
189
190
191 strstripquotes(sMessage);
192 directmessage( sMessage, iUid, tType );
Abhängig vom Buchstaben, der sich in der ersten Zelle von sType befindet, wird der UID Typ
festgelegt. Die um Anführungszeichen befreite Nachricht (Zeile 191: strstripquotes) wird der
ID (Session ID oder Userindex) geschickt.
strstrx( sSource[], sSearch[] );
sSource[]
Typ: String (200)
sSearch[]
Typ: String (200)
Die Funktion sucht einen String (sSearch) in einem anderen String (sSource). Groß- und
Kleinschreibung wird beachtet. Wird der Suchstring gefunden, gibt die Funktion eine Zahl
größer als 0 zurück. Wenn der String nicht gefunden wurde oder leer ist, gibt die
Funktion eine -1 zurück. Ist der Suchstring gleich dem anderen String wird eine 0
zurückgegeben.
Beispiel aus plugin_sdal_allowsounds
(Funktion: plugin_init):
677 new sValue[MAX_TEXT_LENGTH];
678 getstrvar( "amv_enable_beta", sValue, MAX_TEXT_LENGTH );
679 if(strstrx(sValue,"menu1")!=-1){
680 g_menuenabled=1;
681 }
Der Inhalt der Servervariablen amv_enable_beta wird ausgelesen. Wenn der „menu1“ in
sValue gefunden wurde, wird g_menuenabled auf 1 gesetzt.
strsubst( sString[], sSubst[], sWith[], iMaxLen );
sString[]
Typ: String (200)
sSubst[]
Typ: String (200)
sWith[]
Typ: String (200)
iMaxLen
Typ: String (1 - 200)
Die Funktion erkennt, wo sich in einem String (sString mit der Länge iMaxLen) ein anderer
String (sSubst) befindet. Alle Vorkommen von sSubst werden durch den String sWith
ersetzt.
Beispiel aus plugin_retribution (Funktion: RemoveUserFlag):
179 if(get_vaultdata(sAuthID,VaultData,MAX_DATA_LENGTH) != 0) {
180 if (strcasestr(VaultData," llama") != -1) {
181 strsubst(VaultData," llama", "", MAX_DATA_LENGTH);
182 set_vaultdata(sAuthID,VaultData);
183 }
184 }
Wenn eine Eintrag mit der AuthID in der vault.ini gefunden wurde, wird überprüft, ob die
Zeichenkette „ llama“ enthalten ist. Ist dies der Fall, wird im String VaultData „ llama“ durch
eine leere Zeichenkette ersetzt und somit gelöscht. Abschließend wird der Text zurück in die
vault.ini geschrieben.
strtok( sSource[], sDelimiters[], sToken[], iMaxLen );
sSource[]
Typ: String (200)
sDelimiters[]
Typ: String (200)
sToken[]
Typ: String (200)
iMaxLen
Typ: Integer (0 - 200)
Diese Funktion trennt einen String (sSource) am ersten im String (sDelimitiers) angegebenen
Zeichen. Sollen weitere Teilstrings abgetrennt werden, kann die Funktion wiederholt
ausgeführt werden. Dabei darf sSource nicht angegeben werden. Ein möglicher Reststring kann
mit strtokrest ausgegeben werden. Bequemer sind die Funktionen strsep und strsplit für
mehrere Trennungen.
Die Funktion gibt -1 zurück, wenn kein Trennzeichen gefunden wurde.
Beispiel aus plugin_showip
(Funktion: admin_showip):
102 strtok(UserIP[i], ":", IP, MAX_IPADDRESS);
103 strcat(Name,IP,MAX_NAME_LENGTH);
Der String UserIP[i] wird am ersten Doppelpunkt geteilt und der erste Teil in den String IP
geschrieben. Anschließend wird dieser an den String Name angehängt.
strtokrest( sRest[], iMaxLen );
sRest[]
Typ: String (200)
iMaxLen
Typ: Integer (0 - 200)
Die Funktion gibt den Reststring (sRest mit der Länge iMaxLen) nach Ausführung von
strgtok aus. Ist strgtok oder der Reststring leer, wird -1 zurückgegeben.
Beispiel aus plugin_prison2
(Funktion: admin_showip):
102 strtok(line,":",storedmap,MAX_DATA_LENGTH);
103 strtok("",":",tmp,MAX_DATA_LENGTH);
104 x = strtonum(tmp);
105 strtok("",":",tmp,MAX_DATA_LENGTH);
106 y = strtonum(tmp);
107 strtok("",":",tmp,MAX_DATA_LENGTH);
108 z = strtonum(tmp);
109 strtokrest(tmp,MAX_DATA_LENGTH);
Aus dem String line werden über den Doppelpunkt als Trennzeichen Stück für Stück Daten
extrahiert und teilweise in Ganzzahlen (x, y, z) umgewandelt. Am Ende wird der Reststring
ausgelesen.
strtonum( sString[] );
sString[]
Typ: String (200)
Die Funktion wandelt eine als String vorliegende Zahl (sString) in eine Ganzzahl
um.
Beispiel aus plugin_retribution (Funktion: admin_execteam):
207 strbreak(Data, strTeam, Cmd, MAX_TEXT_LENGTH);
208 if (strlen(Cmd) == 0) {
209 selfmessage( "Unparsable format: no command found.");
210 return PLUGIN_HANDLED;
211 }
212 ExecTeam = strtonum(strTeam);
Der String Data wird am ersten Leerzeichen in strTeam und Cmd geteilt. Ist Cmd leer, wird
eine Fehlermeldung in der Console ausgegeben. Anderenfalls wird strTeam in eine Ganzzahl
umgewandelt.
strtrim( sString[], sTrim[], iWhere = 2 );
sString[]
Typ: String (200)
sTrim[]
Typ: String (200)
iWhere = 2
Typ: Integer (0 - 2)
Die Funktion entfernt die in einem String aufgeführten Zeichen (sTrim) am Anfang
(iWhere=0), am Ende (iWhere=1) oder am Anfang und Ende (iWhere=2) eines Strings
(sString). Sie gibt darüber hinaus die Anzahl der entfernten Zeichen an oder -1, wenn kein
Zeichen entfernt wurde.
Beispiel aus plugin_bk_botmanager
(Funktion: admin_bot_set):
266 strbreak(sValue,sBotCvar,sValue,MAX_DATA_LENGTH);
267 strtrim(sValue," ",2);
268 strtrim(sBotCvar," ",2);
Der Wert sValue wird in sBotCvar und sValue aufgeteilt (strbreak). Beiden Variablen werden
am Anfang und am Ende von möglichen Leerzeichen befreit.
strunpack( dest[], const source[] );
dest[]
Typ: String (200)
const source[]
Typ: String (200)
Durch diese Funktion wird ein String (source) entpackt und in einen anderen (dest)
geschrieben. Die meisten Funktionen benötigen ungepackte Strings.
Unter Umständen kann man ein wenig Speicher sparen. Es rentiert sich aber nur, wenn nicht
gleichzeitig der gleiche String ungepackt definiert wird. Außerdem sollte man in Admin Mod
seine Plugins auf Geschwindigkeit nicht Speicher optimieren. Speicher ist eigentlich nie ein
Problem.
Beispiel:
new spTest[7 char]=!"Test123";
new sTest[7];
strunpack(sTest,spTest);
Es wird ein gepackter String der Länge 7 definiert. Es ist das Ausrufezeichen vor der
Zeichenkette „Test123“ zu beachten, das den Compiler anweist den Text als gepackt zu
handhaben. Zu Letzt wird der String spTest in sTest entpackt.
swapchars( c );
c
Typ: Integer (-2147483648 bis 2147483647)
Die Funktion dreht die Bytes in einem Wert (c) um.
new iTest=33;
iTest=swapchars( iTest );
Als zu drehender Wert wird 33 verwendet. Es handelt sich dabei um das Bitmuster
„0000000000000000000000000100001“. Als Ergebnis wird wieder in iTest das Bitmuster
„1000010000000000000000000000000“ geliefert (entspricht 553648128). Anhand des Bitmusters
kann man die Funktionsweise von swapchars erkennen.
systemtime( );
Die Funktion liefert die Sekunden seit dem 1.1.1970 zurück.
Beispiel aus plugin_retribution (Funktion: admin_gag):
207 if (strlen(strTime) != 0) {
208 new Time = systemtime();
209 GagTime = strtonum(strTime) * 60;
210 GagTime += Time;
211 }
Wenn der String strTime nicht leer ist, wird die aktuelle Sekundenzahl ermittelt. Anschließend
wird der String strTime in eine Zahl umgewandelt und mit 60 multipliziert. Abschließend wird
die Sekundenzahl zur Variable GagTime addiert.
teleport( sPlayer[], iX, iY, iZ );
sPlayer[]
Typ: String (33)
iX
Typ: Integer (-2147483648 - 2147483647)
iY
Typ: Integer (-2147483648 - 2147483647)
iZ
Typ: Integer (-2147483648 - 2147483647)
Diese Funktion teleportiert einen Spieler (sPlayer) zu den angegebenen Koordinaten (iX,
iY, iZ). Wenn admin_fx in der adminmod.cfg aktiviert wurde, gibt es zusätzliche
Effekte.
Valide Koordinaten kann man über die Funktion get_userorigin erhalten.
Beispiel aus plugin_retribution (Funktion: admin_bury):
507 get_userorigin(TargetName, x, y, z);
508 teleport(TargetName, x, y, (z-25));
Zunächst werden die Koordinaten des Spielers (TargetName) ermittelt (get_userorigin).
Anschließend wird er um 25 Einheiten tiefer gesetzt. Sofern sich der Spieler zu diesem
Zeitpunkt nicht hoch in der Luft befindet, wird er in den Boden versetzt, so dass er sich nicht
mehr bewegen kann.
timeleft( iPrintToConsole = 1 );
iPrintToConsole = 1
Typ: Integer (0 - 1)
Die Funktion ermittelt die verbleibenden Sekunden bis zum Mapwechsel. Über das Argument
iPrintToConsole wird eingestellt, ob die Restzeit in Minuten und Sekunden auch in der
Console angezeigt wird, wobei 0 keine Anzeige bedeutet.
Beispiel aus plugin_chat (Funktion: SayTimeleft):
61 SayTimeleft() {
62 new Text[MAX_TEXT_LENGTH];
63 new Seconds = timeleft(0);
64
65 Seconds /= 60;
66 snprintf(Text, MAX_TEXT_LENGTH, "Time remaining on map: %i minutes", Seconds);
67 say(Text);
68 }
Die Anzahl der bis zum Mapende verbleibenden Sekunden wird ermittelt und in die
Variable Seconds geschrieben. Diese wird durch 60 geteilt, um Minuten zu erhalten. Die
Minutenzahl wird in den String Text eingebettet, der abschließend im Chat ausgegeben
wird.
tolower( c );
c
Typ: Integer (0 - 256)
Wenn es sich bei einem Zeichen (c) um einen Großbuchstaben handelt, wandelt die Funktion
dieses in einen Kleinbuchstaben um. Um nicht den ASCII-Code verwenden zu müssen, kann
vereinfacht auch das entsprechende Zeichen in einfache Anführungszeichen gesetzt
werden.
Beispiel aus plugin_CS (Funktion: strtolower):
1566 strtolower(String[]) {
1567 new i;
1568 for(i=0;String[i];i++) {
1569 String[i] = tolower(String[i]);
1570 }
1571 }
Diese Funktion wandelt über ein For-Schleife alle Zeichen des Strings String in Kleinbuchstaben
um.
toupper( c ); Typ: Integer (0 - 256)
Wenn es sich bei einem Zeichen (c) um einen Kleinbuchstaben handelt, wandelt die Funktion
dieses in einen Großbuchstaben um. Um nicht den ASCII-Code verwenden zu müssen, kann
vereinfacht auch das entsprechende Zeichen in einfache Anführungszeichen gesetzt
werden.
Beispiel aus plugin_CS (Funktion: ShowClass):
1343 Message[0] = toupper(Message[0]);
1344 selfmessage(Message);
Diese Funktion wandelt den ersten Buchstaben des Strings Message in einen Großbuchstaben,
um ihn dann auf der Console des Admins auszugeben.
typesay( sMessage[], iTime, iRed, iGreen, iBlue );
sText[]
Typ: String (500) (max. Zeilenlänge: 80)
iTime
Typ: Integer (0 - 2147483647)
iRed
Typ: Integer (0 - 255)
iGreen
Typ: Integer (0 - 255)
iBlue
Typ: Integer (0 - 255)
Mit dieser Funktion kann man eine bunte Nachricht (sText) für alle Spieler in der linken
unteren Ecke des Bildschirms produzieren. iTime ist die Einblendzeit in Sekunden. iRed ist der
Rotanteil, iGreen der Grünanteil und iBlue der Blauanteil in der Nachricht. Die Funktion
messageex ermöglicht die gleiche Funktionalität jedoch ohne Farbwahl für einzelne
Spieler.
Beispiel aus plugin_base (Funktion: admin_tsay):
549 if (streq(Color,"red")==1) {
550 typesay(Message,10,250,10,10);
Wenn der Text Color gleich „red“ ist, wird die Nachricht in Message für 10 Sekunden in einen
hellem Rot dargestellt. Es ist zu beachten, dass eine Zeile maximal 80 Zeichen lang sein darf.
Mit Zeilenumbrüchen sind bis zu 500 Zeichen möglich.
unban( sWONID[] );
sWONID[]
Typ: String (39)
Die Funktion entbannt den Spieler unter Angabe der Steam ID oder IP (sWONID).
Beispiel aus plugin_base (Funktion: admin_unban):
572 public admin_unban(HLCommand,HLData,HLUserName,UserIndex) {
573 new Command[MAX_COMMAND_LENGTH];
574 new Data[MAX_DATA_LENGTH];
575 new User[MAX_NAME_LENGTH];
576
577 convert_string(HLCommand,Command,MAX_COMMAND_LENGTH);
578 convert_string(HLData,Data,MAX_DATA_LENGTH);
579 convert_string(HLUserName,User,MAX_NAME_LENGTH);
580 unban(Data);
581 log_command(User,Command,Data);
582 return PLUGIN_HANDLED;
583 }
Alle HL Strings werden in Small Strings umgewandelt. In der Variable Data wird die Steam
ID oder die IP erwartet. Abschließend wird die Aktion basierend auf admin_quiet in die
Logdateien geschrieben.
userlist( sPattern[]= “” );
sPattern[]
Typ: String (33)
Diese Funktion gibt in der Console des aufrufenden Admins einen Überblick über die
momentan Spielenden. Dabei wird der Name, die Session ID, die Steam ID, der Accesslevel
und der Immunitätsstatus des Spielers angegeben. Man kann auch die Spielerausgabe über ein
optionales Muster einschränken.
Beispiel aus plugin_base (Funktion: admin_userlist):
586 public admin_userlist(HLCommand,HLData,HLUserName,UserIndex) {
587 new Data[MAX_DATA_LENGTH];
588
589 convert_string(HLData,Data,MAX_DATA_LENGTH);
590 userlist(Data);
591 return PLUGIN_HANDLED;
592 }
Es wird die Spielerliste ausgegeben, die ggf. durch ein Muster (z.B. „a“ für alle Spieler, die ein
„a“ im Namen haben) eingeschränkt wurde.
valid_map( sMap[] );
sMap[]
Typ: String (100)
Die Funktion überprüft, ob sich eine angegebene Map (sMap) auf dem Server befindet. Ist eine
maps.ini in der adminmod.cfg definiert, gelten nur die dort eingetragenen Maps als gültig.
Dieser Check lässt sich mit valid_mapex umgehen.
Beispiel aus plugin_base (Funktion: admin_map):
307 if (valid_map(Data)==1) {
308 say_command(User,Command,Data);
309 changelevel(Data, 4);
Falls es sich bei Data um eine gültige Map (auch unter Berücksichtigung der maps.ini)
handelt, wird abhängig von der Einstellung admin_quiet eine Nachricht in den Chat
geschrieben und nach vier Sekunden ein Wechsel auf die Map initiiert.
valid_mapex( sMap[] );
sMap[]
Typ: String (100)
Die Funktion überprüft, ob sich eine angegebene Map (sMap) auf dem Server befindet. Ein
zusätzlicher Check, ob die Map auch in der maps.ini steht, kann mit valid_map durchgeführt
werden.
Beispiel:
if (valid_mapex(Data)==1) {
say_command(User,Command,Data);
changelevel(Data, 4);
Falls es sich bei Data um eine gültige Map (unter Ausschluss der maps.ini) handelt, wird
abhängig von der Einstellung admin_quiet eine Nachricht in den Chat geschrieben und nach
vier Sekunden ein Wechsel auf die Map initiiert.
version( );
Diese Funktion gibt die aktuelle Admin Mod Version in der Spielerconsole aus.
Beispiel:
public admin_ver(HLCommand,HLData,HLUserName,UserIndex) {
version();
return PLUGIN_HANDLED;
}
Es wird die Versionsnummer Admin Mods beim aufrufenden Admin in der Console
ausgegeben.
8.10.211 vote
vote( sVoteString[], ... );
sVoteString[]
Typ: String (500)
...
variable Anzahl (max. 12) an Argumenten (kommagetrennt)
Diese Funktion führt einen Vote aus. Dabei muss eine Frage gestellt werden (sVoteString).
Anschließend folgen kommagetrennt, die möglichen Anworten (max. 10). Die letzten zwei
Argumente beinhalten die nach dem Vote aufzurufende Funktion und die an diese Funktion zu
übergebenen Parameter. Mehr zur Verwendung dieser Funktion ist dem Tutorial zu
entnehmen.
Beispiel aus plugin_base (Funktion: admin_vsay):
765 if (vote_allowed()!=1) {
766 selfmessage( "Vote not allowed at this time.");
767 return PLUGIN_HANDLED;
768 }
769
770 log_command(User,Command,Data);
771 vote(Data,"Yes","No","HandleVsay", Data);
772 return PLUGIN_HANDLED;
Zunächst wird überprüft, ob überhaupt ein Vote erlaubt ist (vote_allowed). Wenn dies nicht
der Fall ist, wird dem Admin eine Fehlermeldung ausgegeben. Anderenfalls wird der Befehl
in die Logdateien geschrieben und ein Vote mit der in Data stehenden Frage und
den Antwortmöglichkeiten „Yes“ und „No“ ausgeführt. Die aufzurufende Funktion
lautet dabei „HandleVsay“, und die Frage wird als Parameter an diese Funktion
übertragen.
vote_allowed( );
Diese Funktion überprüft, ob ein Vote ausgeführt werden darf. Sie gibt 1 zurück, wenn ein
Vote erlaubt ist. Anderenfalls gibt sie 0 zurück.
Beispiel aus plugin_base (Funktion: admin_vsay):
765 if (vote_allowed()!=1) {
766 selfmessage( "Vote not allowed at this time.");
767 return PLUGIN_HANDLED;
768 }
769
770 log_command(User,Command,Data);
771 vote(Data,"Yes","No","HandleVsay", Data);
772 return PLUGIN_HANDLED;
Zunächst wird überprüft, ob überhaupt ein Vote erlaubt ist (vote_allowed). Wenn dies nicht
der Fall ist, wird dem Admin eine Fehlermeldung ausgegeben. Anderenfalls wird der Befehl in
die Logdateien geschrieben und ein Vote mit der in Data stehenden Frage und den
Antwortmöglichkeiten „Yes“ und „No“ ausgeführt.
writefile( sFilename[], sLine[], iLineNum = -1 );
sFilename[]
Typ: String (200)
sLine[]
Typ: String (200)
iLineNum
Typ: Integer (0 - 2147483647)
Die Funktion schreibt einen Text (sLine) in eine Zeile (iLineNum) einer Datei (sFilename).
Wird iLineNum nicht oder als -1 angegeben, wird der Text als neue Zeile an die Datei
angehängt.
Die Funktion ist sehr zeitintensiv, da gewartet werden muss bis der Festplattenzugriff erfolgt
ist. Schreibt man mehrere Zeilen mit einer For-Schleife, wird bei jeder Zeile die Datei neu
geöffnet, was weitere Verzögerungen verursacht. Man sollte sich daher genau überlegen, ob
man diese Funktion nutzen möchte. Beim Schreiben während des Serverstarts bzw. beim
vereinzelten Anhängen von Text ist dies noch akzeptabel, ein Schreiben während
der Spielzeit kann bei einer For-Schleife durchaus zu Aussetzern im Spiel führen
(Lag). Wenn möglich sollte man seine Einstellungen über die vault.ini lesen und
schreiben.
Beispiel aus plugin_bk_res
(Funktion: add_res_data):
155 iLines=filesize(sMap,lines);
156 for(i=1;i<=iLines;i++){
157 readfile(sMap,sLine,i,MAX_DATA_LENGTH);
158 writefile(sMap2,sLine,-1);
159 }
Es wird die Anzahl der Zeilen der Datei (sMap) ausgelesen. Anschließend werden die Daten
über eine For-Schleife zeilenweise von einer Datei (sMap) in eine andere (sMap2) kopiert. Die
Zeilen übernehmen nicht unbedingt die Zeilennummer der Ursprungsdatei. Die Zeilen werden
beim Schreiben nur angehängt (-1).
Niemand arbeitet fehlerfrei. Einige Tipp- oder auch Denkfehler sorgen für Compilerfehler oder
-warnungen. U.U. kann man auch den Compiler zum Absturz bringen. Oftmals sind die
Rückmeldungen auf den ersten Blick nicht besonders verständlich.
Die Syntax der Fehlermeldungen lässt sich am besten an Hand eines Beispiels erklären:
plugin_test.sma(13) Warning [217]]: loose indentation
Zunächst wird angegeben, in welchem Quellcode der Fehler auftritt. In den runden Klammern
wird die Zeile angegeben, in der der Fehler aufgefallen ist. Meistens muss man sich die
vorhergehende Zeile ansehen. Insbesondere bei Klammersetzungsfehlern im Quellcode
kann der Fehler aber auch an einer gänzlich anderen Stelle oberhalb der gemeldeten
liegen.
Es wird weiterhin angegeben, ob es sich um einen Fehler oder nur eine Warnung handelt. Bei
Warnungen wird zwar der Compiliervorgang weitergeführt, ob dieser aber auch fehlerfrei
durchgeführt wurde, ist nicht garantiert. Es gibt keinen Grund eine Warnung zu ignorieren.
Jedes saubere Plugin muss sich warnungsfrei compilieren lassen. In eckigen Klammern ist die
Fehler- bzw. Warnungsnummer gegeben, an die sich die ausgeschriebene Fehlermeldung
anschließt.
Die folgenden Meldungen wird man häufiger finden:
-
Error [001]
- Die Meldung „expected token: “;”, but found “-identifier-”“ deutet darauf
hin, dass am Ende der vorhergehenden Zeile ein Semikolon vergessen wurde.
-
Error [010]
- Der Hinweis auf „invalid function or declaration“ hat meistens den Grund,
dass man sich in der angegebenen Zeile vertippt hat.
-
Error [021]
- Die Meldung „symbol already defined: “set_timer”“ bedeutet, dass man
versucht, eine bereits definierte Funktion neu zu definieren.
-
Error [029]
- Die Nachricht „invalid expression, assumed zero“ deutet auf ein
Klammersetzungsproblem hin.
-
Error [039]
- Die Meldung „argument type mismatch (argument 1)“ bedeutet, dass einer
Funktion eine Variable mit falschem Datentyp übergeben wurde (z.B. Integer
statt String). Als Hilfestellung wird auch angegeben, bei welchem Argument dies
geschehen ist.
-
Warning [209]
- Die Meldung „number of arguments does not match definition“ sagt
aus, dass man einer Funktion zu wenige oder zu viele Argumente übergeben hat.
-
Warning [209]
- Beim Hinweis „symbol is never used: “test”“ wird darauf hingewiesen,
dass eine als privat definierte Funktion von keiner anderen Funktion aus dem
Plugin aufgerufen wird. Der Code sollte dann entfernt oder die Funktion „public“
gemacht werden.
-
Warning [215]
- Der Ausdruck „expression has no effect“ meint meistens, dass in der
Zeile ein Vergleich nur mit einem Gleichheitszeichen angestellt wurde („=“ statt
„==“).
-
Warning [217]
- Die Meldung „loose indentation“ sollte bei konsequenter Anwendung
von Klammern nicht mehr auftreten. Man kann aber auch auf Klammern verzichten
und Tabulatoren nutzen. Dafür müssen dann aber auch die Einrückungen komplett
stimmen. Auf Grund der besseren Übersicht und der geringeren Fehlerträchtigkeit
sind aber Klammern zu empfehlen.
-
Warning [219]
- Wenn die Meldung „local variable identifier shadows a symbol at a
preceding level“ erscheint, versucht man eine Variable zu definieren, die bereits
global genutzt wird. Meistens wurde sie in einer der Includes definiert und ist daher
nicht gleich ersichtlich. Es sollte ausreichen, den Variablennamen zu ändern.
Der Compiler kann aber auch ganz unvermutet abstürzen. Dies kann in den folgenden Fällen
auftreten:
- Doppelt definierte globale Variablen
- Irtümlich doppelt definierte Variablen. Eine Variable darf maximal 31 Zeichen lang
sein. Ist sie länger als 31 Zeichen, wird sie abgeschnitten. Sind dann zwei Variablen
in den ersten 31 Zeichen gleich, führt das zum Absturz.
- Wenn bei großen Plugins in einer der ersten Zeilen ein abschließendes
Anführungszeichen vergessen wurde, kann dies zum Absturz führen.
Neben den Fehlern beim Compilieren können auch Fehler während der Laufzeit
des Plugins auftreten. Die Meldungen können dann den Logdateien entnommen
werden.
-
3 - AMX_ERR_STACKERR
- Dem Plugin ist der Speicher für lokale Variablen
ausgegangen (Standard: 8 kB). Mittels der Definition #pragma dynamic 4096
kann man den Speicher auf 16 kB (4096 Cells) erhöhen. Dies erfordert in jedem
Fall ein Neucompilieren des Plugins.
-
4 - AMX_ERR_BOUNDS
- Es wurde versucht auf eine Zelle eines Feldes zuzugreifen,
das nicht existiert. Meistens ist eine For-Schleife einen Schritt zu lang gewählt
worden.
-
10 - AMX_ERR_NATIVE
- Einer Admin Mod Funktion wurden ungültige Argumente
(z.B. außerhalb des Gültigkeitbereichs) übergeben. Dies kann auch passieren, wenn
man eine Zeile aus einer Datei liest (readfile), die länger als die maximal definierte
Stringlänge ist.
-
11 - AMX_ERR_DIVIDE
- Bei einer Berechnung wurde versucht durch Null zu teilen.
-
17 - AMX_ERR_FORMAT
- Beim Plugin handelt es sich nicht um ein gültiges.
Als Gründe kommen in Frage, dass man die SMA-Datei hochgeladen hat, ein
fehlerhaftes Plugin oder aber auch ein AMXMod(X) Plugin versucht zu laden.
-
19 - AMX_ERR_NOTFOUND
- Ein Befehl wurde in Admin Mod definiert und auf
eine öffentliche Funktion verwiesen, die von Admin Mod aber nicht gefunden
wurde. Mögliche Gründe dafür können eine fehlende „public“ Deklaration oder ein
Tippfehler beim Funktionsnamen sein.
-
122 - AMX_ERR_INIT
- Ein interner Admin Mod Fehler ist aufgetreten. Einziger
bekannter Grund ist der Inkrementierungsversuch bei einer Feldzelle mittels „++“,
was auf Grund eines Compilerbugs fehlschlägt. Oft stürzt der Server aber auch
einfach sang- und klanglos ohne Fehlermeldung ab.
Zum Komplettabsturz des Servers können auch Endlosschleifen führen. Auch sollte man
vermeiden Variablen direkt in Schleifen zu definieren.
1 for(new i=1;i<10;i++) {
2 say(‘‘Test’’);
3 }
Die Variablen werden dann nicht immer im Speicher freigegeben. Inbesondere in Kombination
mit einer „break“ Anweisung kann es zu einem Absturz kommen. Man sollte daher stets die
Variablen vor der Schleife definieren.
Wie im Tutorial gezeigt, kann man die in Admin Mod vorhandenen Events durch LogD
erweitern. Jeder LogD-Event hat eine bestimmte Nummer und eine dafür festgelegte
Rückgabesyntax, die als Gesamtstring zurückgegeben wird. Der String muss im Plugin an den
Leerzeichen getrennt und ggf. in Integer umgewandelt werden. Im Folgenden sollen die zur
Verfügung stehenden Events mit ihrer Rückgabesyntax aufgelistet werden (Tabelle
8.1).
Tabelle 8.1.: | LogD Events
|
|
|
|
|
Event | Name | Variablen | Beispiel |
|
|
|
|
5 | Servername | sHostname | Mein$Server |
|
|
|
|
50 | Connect | iPlayerUI | 12 1.2.3.4:12345 |
| | iPlayerIP | |
|
|
|
|
51 | Enter Game | iPlayerUI | 16 |
|
|
|
|
52 | Disconnect | iPlayerUI | 11 |
|
|
|
|
53 | Suicide | iPlayerUI | 9 grenade |
| | sWaffe | |
|
|
|
|
54 | Team Select | iPlayerUI | 5 TERRORIST |
| | sTeam | |
|
|
|
|
55 | Role Select | iPlayerUI | 2 Medic |
| | sRole | |
|
|
|
|
56 | Change Name | iPlayerUI | 6 Me$Admin |
| | sNewName | |
|
|
|
|
57 | Kill | iKillerUI | 6 4 p228 |
| | iVictimUI | |
| | sWaffe | |
|
|
|
|
58 | Damage | iAttackerUI | 3 1 p228 damage#28 |
| | iVictimUI | damage_armor#0 |
| | damage#iDamage | health#72 armor#0 |
| | damage_armor#iDA | |
| | health#iHealth | |
| | armor#iArmor | |
|
|
|
|
59 | PvP Action | iInvokerUI | 5 10 Medic_Heal |
| | iReceiverUI | |
| | sAction | |
|
|
|
|
60 | Player Action | iPlayerUI | 1 Planted_The_Bomb |
| | sAction | |
|
|
|
|
61 | Team Action | sTeam | CT Target_Saved CT#1 T#0 |
| | sAction | |
| | CT#iScoreCT | |
| | T#iScoreT | |
|
|
|
|
62 | World Action | sAction | Round_Start |
|
|
|
|
63 | Chat | n/t (Normal/Team) | n 7 Wer$ist$Admin? |
| | iPlayerUI | |
| | sText | |
|
|
|
|
64 | Team Alliance | sInvokerTeam | Red Blue |
| | sReceiverTeam | |
|
|
|
|
65 | Team Score Report | sTeam | TERRORIST 9 7 |
| | iScore | |
| | iNumTeamPlayer | |
|
|
|
|
66 | Private Chat | iInvokerUI | 5 3 Wer$ist$Admin? |
| | iReceiverUI | |
| | sText | |
|
|
|
|
|
Die Variablen werden in der angegebenen Reihenfolge mit Leerzeichen als Trennzeichen im
Rückgabestring zurückgegeben. Die Bezeichnung der Variablen ist in diesem Fall willkürlich.
Das „s“ deutet an, dass der Wert als String in Admin Mod ausgewertet werden soll.
Entsprechend steht das „i“ für einen Zahlenwert. Der eigentliche Name der Variablen soll den
Zweck andeuten. „UI“ steht dabei verkürzt für den Userindex.
Um Leerzeichen (z.B. beim Chat) darstellen zu können, ohne dass diese beim Trennen Ärger
bereiten, werden diese durch „$“ ersetzt. Optionen im String werden von ihrem Wert mit
einem „#“ abgesetzt.
Als Schlüssel kann entweder der Name oder der Wert der Property benutzt werden. Properties
sind Schlüssel-Wert-Paare, die in der AMX-Scriptengine gespeichert werden. Jede Property
hat eine Zeichenkette und eine Ganzzahl. Welches davon der Schlüssel, und welches der Wert
ist, kann der Scriptautor bestimmen, indem er einen der beiden Parameter leer lässt. Die
ID der Property dient dazu, dass verschiedene Scripte ihre Propertys auseinander
halten können. Eine Property wird durch ihre ID und ihren Schlüssel eindeutig
identifiziert.
Die Vorteile von Properties gegebnüber globalen Variablen sind, dass der Speicherplatz
dynamisch verwaltet wird, und somit praktisch unbegrenzt Daten gespeichert werden können.
Weiterhin bleiben die Daten auch über einen Kartenwechsel hinaus erhalten. Die Nachteile
sind, dass mit zunehmender Benutzung von Properties die Zugriffsgeschwindigkeit abnimmt,
da diese als einfach verkettete Liste implementiert sind. Ausserdem gibt es keine Möglichkeit
festzustellen, ob im Propertybereich einer ID bereits Werte liegen. Zuletzt obliegt es dem
Script-Autor, die angelegten Properties wieder zu löschen, da ansonsten der Speicherverbrauch
immer weiter anwächst. Properties sollten in Adminmod daher z.Z. nicht verwendet
werden.
Es wird empfohlen stattdessen auf die Befehle zur Vault Datei (vault.ini) zurückzugreifen
(z.B. get_vaultdata). Wer dennoch die Properties nutzen möchte, kann die Funktionen
deleteproperty, existproperty, getproperty und setproperty verwenden.