Jetzt wird’s praktisch: Du erstellst deine erste LPC-Datei, lädst sie als Objekt,
erzeugst einen Clone und testest alles Schritt für Schritt – aber korrekt für das Midgard MUD:
mit der Lupe.c (Lens/Stack-Tool) und dem MGtool (Xtool).
Als Nächstes: Datentypen, Variablen und einfache Logik.
2.1 Ziel dieses Kapitels
Nach diesem Kapitel kannst du:
eine neue .c-Datei anlegen und sauber strukturieren
verstehen, was Masterobjekt und Clone sind
ein Objekt laden und klonen
Änderungen zuverlässig aktivieren (Update/Reload)
erste Tests durchführen: Funktionen aufrufen, Ergebnisse prüfen
die zwei wichtigsten Werkzeugwelten unterscheiden: Lupe.c vs. MGtool
Wir machen alles in kleinen Schritten. Du musst nicht „alles können“ – aber du brauchst einen stabilen Workflow.
2.2 Die zwei wichtigsten Werkzeuge: Lupe.c & MGtool
Lupe.c (Lens-Objekt): Stack-basiert
Die Lupe ist ein Objekt, das dir eine Sammlung von Befehlen gibt, um Objekte zu laden, zu klonen,
im Stack zu halten und Funktionen darauf aufzurufen. Das Herzstück ist ein Stack:
Manche Befehle pushen Objekte drauf, andere poppen sie wieder runter und arbeiten damit.
Wichtig für Anfänger:
Du kannst mehrere Lupe-Kommandos in einer Zeile schreiben (durch Leerzeichen getrennt).
Die Anzahl der Leerzeichen ist egal.
Wenn ein Argument Leerzeichen oder Punkte enthält, musst du es in "...", '...' oder |...| setzen.
Lupe: Notation (Merken!)
<filename> kann sein:
/pfad/objekt (absolut)
~/work/objekt (relativ zu deinem Home)
~name/work/objekt (Home eines anderen Magiers)
Wenn der Name Punkte oder Leerzeichen hat:
me."bag 2" inv
me.'bag 2' inv
me.|bag 2| inv
MGtool (Xtool): Kommandos mit x...
Das MGtool ist ein mächtiges Werkzeugpaket mit vielen Befehlen wie
xload, xclone, xupdate, xcall, xlook, xgrep usw.
Es hat außerdem eine History/Quicktype-Funktion (sehr praktisch, sobald du öfter testest).
In diesem Kurs nutzen wir beide Tools – aber so, dass du nie durcheinanderkommst:
Lupe ist super für „Objekt auf den Stack → untersuchen → Funktion testen“.
MGtool ist super für „Alltagsarbeit“ (laden, klonen, updaten, suchen, Skripten).
2.3 Vorbereitung: Arbeitsordner & Dateiname
Wir arbeiten in einem klaren Übungsordner. Falls du ihn noch nicht hast:
Arbeitsordner anlegen
cd
mkdir work
cd work
pwd
Achte auf einfache Dateinamen: Kleinbuchstaben, Zahlen, Unterstrich.
Wir nehmen: hello.c.
2.4 Masterobjekt & Clone – die eine Sache, die du wirklich verstehen musst
Eine LPC-Datei ist erst einmal nur Text. Wenn der Driver sie lädt, entsteht ein Objekt im Speicher:
das Masterobjekt. Wenn du daraus ein „Exemplar“ brauchst, erzeugst du einen Clone.
Der typische Anfängerfehler ist:
„Ich habe die Datei geändert, aber mein Clone macht noch das Alte.“
Das ist normal – denn der Clone ist schon im Speicher. Lösung: Update/Reload oder neu klonen.
2.5 Deine erste Datei: hello.c
Wir bauen ein Minimalobjekt, das zwei Dinge kann:
es initialisiert sich und es liefert eine Testausgabe.
Zusätzlich bauen wir eine Debug-Abfrage ein, damit du jederzeit prüfen kannst, ob du wirklich die neue Version testest.
~/work/hello.c (Startversion)
#pragma strict_types
int Inited;
int CreateCount;
void create()
{
Inited = 1;
CreateCount++;
}
int query_inited()
{
return Inited;
}
int query_create_count()
{
return CreateCount;
}
string hello()
{
return "Hallo! Dein erstes Objekt lebt.\n";
}
Speichern. Fertig. Jetzt testen wir – erst mit der Lupe (Stack), dann mit dem MGtool (X-Kommandos).
2.6 Testen mit der Lupe.c (Stack-Workflow)
Die Lupe arbeitet mit einem Stack. Du „pushst“ ein Objekt auf den Stack und kannst dann Aktionen darauf ausführen.
Hier sind die wichtigsten Befehle für den Start:
me – pusht dich selbst auf den Stack
here – pusht den Raum, in dem du bist
ob <file> – lädt und pusht das Objekt (Masterobjekt)
new <file> – klont und pusht (und bewegt den Clone in dein Inventory)
= – zeigt das Top-of-Stack (TOS)
info – detaillierte Infos zum TOS
stk – zeigt den ganzen Stack
[<function>] – ruft eine Funktion im TOS auf
make – zerstört TOS und baut es aus der Datei neu (Update)
Schritt 1: Masterobjekt laden und anschauen
Lupe: hello laden → anzeigen → Infos
ob ~/work/hello
=
info
stk
Du solltest jetzt sehen, dass das Objekt auf dem Stack liegt.
ob ~/work/hello [query_inited]
ob ~/work/hello [hello]
ob ~/work/hello [query_create_count]
Erwartung:
query_inited → 1
hello → dein Text
query_create_count → beim Laden typischerweise 1 (bei erneutem Neuaufbau kann sich das ändern)
Schritt 3: Clone erzeugen (damit du ein Exemplar im Inventory hast)
Lupe: Clone erzeugen (landet im Inventory)
new ~/work/hello
Jetzt liegt ein Clone in deinem Inventory. (Je nach MUD-Befehl z.B. i/inv anzeigen.)
Schritt 4: Den Clone auf den Stack holen und testen
Der Trick bei der Lupe ist: Du kannst aus einem bekannten Objekt (z.B. du selbst) Dinge „auswählen“.
Lupe: dein Inventory anzeigen
me inv
Wenn dein neuer Clone z.B. der 4. Gegenstand im Inventory ist, kannst du ihn so auswählen:
Lupe: 4. Objekt aus deinem Inventory auswählen und Funktion rufen
me .4 [hello]
Falls du nicht sicher bist, welches Objekt welche Nummer hat: nutze me inv und/oder info auf dem ausgewählten Objekt.
2.7 Änderungen übernehmen (Update richtig machen)
Jetzt kommt der wichtigste Praxispart. Änderst du den Text in hello(), musst du dafür sorgen,
dass dein Testobjekt im Speicher wirklich neu gebaut wird.
Variante A: Masterobjekt neu bauen (Lupe: make)
make zerstört das Top-of-Stack-Objekt und baut es aus der Datei neu.
Für Räume ist das extrem praktisch; für Lernobjekte ebenso.
Lupe: Master laden → update
ob ~/work/hello
make
[hello]
Variante B: Neuen Clone erzeugen
Wenn du einen Clone testest, ist der einfachste Weg oft: alten Clone ignorieren, neuen Clone erzeugen.
Lupe: nach Änderung neu klonen
new ~/work/hello
Profi-Tipp für Anfänger:
Nutze den Debug-Zähler query_create_count(), um zu sehen, ob du wirklich die neue Instanz hast.
Debug: Bin ich wirklich „neu“?
ob ~/work/hello [query_create_count]
2.8 Dasselbe mit MGtool (Xtool) – der Alltag
Viele Entwickler nutzen im Alltag oft das MGtool, weil es extrem viel kann (History, Pipelines, Grep, Skripte, …).
Die konkreten Befehle und Optionen können je nach Version variieren – aber diese „Grundfamilie“ ist typisch:
xload – laden
xclone – klonen
xupdate – updaten
xcall – Funktion aufrufen
xlook – Objekt/Container ansehen
MGtool: Hilfe zu einem Befehl
xman xload
xman xclone
xman xupdate
xman xcall
Und die Magier-Shell hat eine eingebaute History — die kannst du
unabhängig vom Tool nutzen, sie funktioniert für alle Befehle:
history // (oder kurz: hist) — letzte Befehle anzeigen
&<nr> // Befehl Nummer nr aus der History wiederholen
&<text> // letzten Befehl, der mit <text> anfaengt
^alt^neu^ // letzten Befehl mit Ersetzung wiederholen
histlen <n> // History-Länge setzen
histmin <n> // minimale Länge für History-Eintrag
Praktisch ist auch
[ alias ]
— damit kannst du dir Kurzformen für oft genutzte Befehle anlegen (und mit
[ unalias ]
wieder entfernen).
Für diesen Kurs gilt: Wenn du mit der Lupe sicher bist, wirst du MGtool lieben –
aber die Lupe ist der perfekte Einstieg, weil sie das „Objekt-denken“ sehr klar macht.
2.8a Lupe-Befehle im Detail
Die Lupe (/obj/tools/lupe) ist ein Stack-Werkzeug.
Du legst Objekte oben drauf (Push), schaust sie an, rufst Funktionen, nimmst sie
wieder runter (Pop). Das ist deutlich anders als ein normaler Befehlsstil — aber
wenn man es einmal verstanden hat, ist es unschlagbar schnell. Die volle Befehlsreferenz
bekommst du im MUD mit hilfe lupe oder in /doc/wiz/lupe.
Stack-Operationen
me // ich selbst auf den Stack
here // der aktuelle Raum auf den Stack
= // TOS anzeigen (Stack bleibt erhalten)
stk // ganzen Stack zeigen (Stack bleibt erhalten)
pop // TOS entfernen
swap // TOS und Element darunter tauschen
dup // TOS verdoppeln
clr // Stack komplett leeren
copy // Kopie von TOS anlegen (geht ins eigene Inventar)
over // Element unter TOS nochmal pushen
@<n> // n-tes Element von oben (0 = TOS) nochmal pushen
Objekte auf den Stack schieben
ob <file> // load_object - Blueprint laden und pushen
new <file> // clone_object - klonen, pushen, ins eigene Inventar
creat <file> // wie new, aber NICHT ins Inventar
push <file> // findet existierendes Objekt und pusht es
pl <name> // Spieler mit Namen pushen (auch netztote)
lv <name> // Lebewesen mit living_name pushen
env // environment(TOS) auf Stack (TOS wird ersetzt)
result // letztes Objekt-Ergebnis einer Funktion pushen
Inventar von TOS
inv // Inventar von TOS auflisten (TOS bleibt)
.<n> // n-tes Objekt im Inventar von TOS pushen (TOS weg)
.<id> // Objekt mit ID im Inventar von TOS pushen
me .knochennadel // Knochennadel im eigenen Inventar
here .ork // Ork im aktuellen Raum
Funktionen aufrufen
[funktion] // funktion() auf TOS
[funktion arg1 arg2] // funktion(arg1, arg2) auf TOS
[QueryProp P_NAME] // QueryProp(P_NAME)
[SetProp P_HP 100] // SetProp(P_HP, 100)
Updaten und zerstören
make // TOS destructen und neu laden (Update)
// Achtung: NICHT für Spieler — dafür: renew
renew // Update für Spieler (vorsichtig benutzen!)
dest // remove() + destruct() von TOS
Dest // hartes destruct() (KEIN Spieler/Lupe)
cln // alle Objekte aus TOS-Inventar entfernen (außer Spieler)
clnof <arg> // alle Objekte mit ID <arg> aus TOS-Inv entfernen
Variablen (10 Slots: 0..9)
><n> // TOS in Variable n speichern (z.B. >0)
<<n> // Variable n auf den Stack pushen (z.B. <0)
Info-Befehle
info // Standardinfos zu TOS
dinfo // Driver-interne Infos (next reset, eval_cost)
minfo // Speicherverbrauch von TOS
inherit_list // Vererbungsbaum von TOS
stat / sc // Spieler-/NPC-Status (Equipment, Quests etc.)
idle // Idle-Zeit (TOS muss Spieler sein)
Quoting bei Sonderzeichen
Wenn IDs Punkte oder Leerzeichen haben, musst du quoten:
me ."bag 2" inv // doppelte Anführungszeichen
me .'bag 2' inv // einfache Anführungszeichen
me .|bag 2| inv // Pipe-Quoting (praktisch in Shells)
Mehrere Befehle in einer Zeile
Lupe-Befehle werden durch Whitespace getrennt. Du kannst lange Pipelines bauen:
me here inv .1 [QueryProp P_SHORT]
// 1. me - ich auf Stack
// 2. here - Raum auf Stack
// 3. inv - Raum-Inventar auf Stack
// 4. .1 - 1. Element davon
// 5. [QueryProp P_SHORT] - dessen Kurzbeschreibung
2.8b MGtool / Xtool im Detail
Das MGtool (im Code /obj/tools/MGtool, früher Xtool genannt)
ist das Schweizer Taschenmesser des Magiers. Anders als die Lupe ist es nicht
stack-basiert, sondern arbeitet mit benannten Variablen wie $me,
$here, $result, $clone und einer langen Liste
spezialisierter x*-Befehle.
Die wichtigsten X-Befehle (existieren wirklich!)
xhelp // Befehlsübersicht
xman <befehl> // Detail-Hilfe (z.B. xman xcall)
xtool // Tool selbst konfigurieren / save / load
// Objekte erzeugen und updaten
xclone <file> // klont, setzt $clone, bewegt in dein Inventar
xload <file> // lädt/aktualisiert (Räume: Spieler in /std/void)
xupdate <file> // remove() + destruct() für ein Objekt
xdes <file> // hartes destruct()
xclean // alle eigenen Clones aufräumen
// Funktionen aufrufen — Syntax: xcall <obj>-><fun>(<args>)
xcall $me->QueryProp(P_LEVEL)
xcall $here->QueryProp(P_INT_LONG)
xcall /std/thing#145->SetProp(P_SHORT,"a small thing")
xcall $clone->DoWield()
xeval ... // wie xcall, aber freier LPC-Ausdruck
// Inspektion
xlook [<obj>] // Objekt anschauen (default: hier)
xprops [<obj>] // alle Properties auflisten
xids [<obj>] // alle IDs eines Objekts
xinherit [<obj>] // Vererbungsbaum anzeigen
xscan [<obj>] // tiefes Scannen eines Objekts
xtrace <obj> // Funktion/Aufruf tracen
xgoto <ziel> // teleportieren
// Code-Suche und Doku
xgrep <pattern> <datei> // Code-Suche
xman <name> // sucht in /doc/efun/, /doc/lfun/, /doc/std/, ...
// Variablen merken (eigene)
xset $deep=deepthought // $deep = Spieler "deepthought"
xset $tuer=$here.tuer // $tuer = Tür im aktuellen Raum
xset // alle Variablen anzeigen
Vordefinierte Variablen
$me — du selbst
$here — der aktuelle Raum
$clone — der zuletzt geklonte Clone (wird von xclone gesetzt)
Die volle Befehlsreferenz mit allen X-Befehlen, Aliases und der eigenen kleinen
Skriptsprache findest du im MUD mit xhelp.
Eine vollständige Liste der verfügbaren xman-Seiten liegt unter
/obj/tools/MGtool/man.d/.
2.8c Magier-Standardbefehle (außerhalb der Tools)
Das Midgard MUD bringt einige eingebaute Befehle mit, die du auch ohne Lupe/MGtool
kennen solltest. Sie funktionieren in der Magiershell direkt:
Dateisystem
pwd // Aktuelles Verzeichnis
cd <pfad> // wechseln
ls [<pfad>] // Verzeichnis listen
cat <datei> // Inhalt anzeigen
more <datei> // seitenweise
head <datei> // Anfang anzeigen
tail <datei> // Ende anzeigen
ed <datei> // im ed-Editor öffnen (siehe hilfe editor)
mv <alt> <neu> // umbenennen
cp <quelle> <ziel> // kopieren
rm <datei> // löschen (Vorsicht!)
mkdir <name> // Verzeichnis anlegen
rmdir <name> // leeres Verzeichnis löschen
grep <muster> <datei> // Code-Suche
man <befehl> // Doku zu LPC-Funktion / Befehl
Objekte
load <file> // Blueprint laden (siehe hilfe load)
clone <file> // Clone erzeugen (siehe hilfe clone)
upd <file> // destructen + neu laden (siehe hilfe upd)
destruct <objekt> // Objekt zerstören
goto <raum|spieler> // teleportieren
home // ins eigene Home teleportieren
people // Spieler online auflisten
do <befehl> // Befehl als anderer Spieler/NPC ausführen
zwinge <wer> zu <was> // jemanden zu einem Befehl zwingen
trans <wen> [zu] // Spieler zu sich teleportieren
Eine komplette Liste aller Magier-Befehle findest du unter /doc/mcmd/
oder im MUD mit hilfe magierbefehle.
Driver-Status (im Driver eingebaut)
Der LDMud-Driver kennt einen eingebauten status-Befehl, der
Speicher, Eval-Costs und Tabellen anzeigt:
status // Driver-Status (Memory, Objekte, Eval-Limits)
status tables // Hashtables, Speicher-Auslastung
status malloc // Detail-Memory
Welche Befehle es genau gibt, hängt vom Level ab (Spieler/Seher/Magier/EM).
hilfe magierbefehle oder ein Blick in /doc/mcmd/ zeigen die volle Liste.
2.8d Debugging-Workflow: Wenn etwas nicht funktioniert
Statt blind zu raten, geh systematisch vor. Dieser Ablauf erspart dir
endlose Frustration:
Schritt 1: Compile-Errors zuerst
Beim Laden gibt der Driver Fehlermeldungen aus. Lies die oberste
Fehlermeldung — alle weiteren sind oft Folgefehler.
*Compiler error: /players/dein/work/hello.c line 12: parse error
// Zeile 12 angucken — meist fehlt ; oder } davor
Schritt 2: Existiert das Objekt überhaupt?
xinfo // im MGtool
[find_object "/players/.../hello"] // in der Lupe
Wenn nicht: load oder xob erst.
Schritt 3: Werte schrittweise prüfen
// In der Lupe:
ob ~/work/hello [QueryProp P_HP]
ob ~/work/hello [QueryProp P_NAME]
// Im MGtool:
xob /players/dein/work/hello
xqp P_HP
xqp P_NAME
xlook // alle Properties auf einen Blick
Schritt 4: Logging
Wenn du nicht siehst, was passiert, lass dein Code es selbst sagen:
log_file("debug/hello", sprintf("create() ran at %d\n", time()));
log_file("debug/hello", sprintf("hp=%d, name=%s\n", hp, name));
Anschauen mit cat /log/debug/hello. Das ist im MUD oft schneller
als jeder Online-Debugger.
Schritt 5: Eval-Cost messen
Wenn dein Code „too long evaluation“ wirft:
int prev = get_eval_cost();
// dein Code
write("Hat " + (prev - get_eval_cost()) + " Ticks gebraucht.\n");
2.8e Master-Update vs. Clone-Update — die wichtige Unterscheidung
Das ist eine der häufigsten Verwirrungen am Anfang. Wenn du eine
.c-Datei änderst, sind alte Objekte im MUD nicht automatisch
auf dem neuen Stand.
Was passiert beim update/make?
Driver zerstört das alte Master-Objekt im Speicher.
Beim nächsten Zugriff wird die Datei neu kompiliert und geladen.
Bestehende Clones behalten den alten Code, bis sie selbst neu erzeugt werden.
Konsequenz: Wenn du das Verhalten von Items ändern willst, die Spieler bereits im Inventar haben,
musst du sie zerstören und neu erzeugen — oder du baust Versionierung ein. Bei Räumen ist das einfacher,
weil Räume meist als Blueprint genutzt werden.
Trick mit query_create_count()
Bau in dein Lernobjekt einen Versionszähler ein, dann siehst du sofort, ob du die neue Version testest:
private int CreateCount;
protected void create() {
::create();
CreateCount++;
log_file("debug/hello", "create #" + CreateCount + "\n");
}
public int query_create_count() { return CreateCount; }
Meist falscher Pfad. Nutze pwd, ls und arbeite anfangs lieber mit ~/work/....
„Ich teste noch die alte Version“
Klassiker. Lösung: make (Lupe) oder neu klonen. Nutze query_create_count().
„Compile error“
Meist Syntax: Semikolon vergessen, Klammern falsch, Tippfehler.
Semikolon vergessen (Klassiker)
// falsch
int x = 1
// richtig
int x = 1;
„Runtime error“
Kompiliert, aber zur Laufzeit stimmt etwas nicht (z.B. 0 statt Objekt).
Lösung: kleiner testen, Werte abfragen, Zwischenschritte sichtbar machen.
2.10 Mini-Aufgaben (zum Festigen)
Ändere den Text in hello() und aktualisiere sauber mit make oder neuem Clone.
Füge eine Funktion int add(int a, int b) hinzu und rufe sie über die Lupe auf.
Füge eine Variable string Name hinzu, setze sie in create() und gib sie per query_name() zurück.
Beispiel: add-Funktion
int add(int a, int b)
{
return a + b;
}
Tipp: Wenn du add testen willst, kannst du in der Lupe Argumente mitgeben:
Lupe: Funktionsaufruf mit Argumenten
ob ~/work/hello [add 2 40]
2.11 Checkliste: Der sichere Anfänger-Workflow
Wenn du unsicher bist: mach genau das
1) pwd / ls (bin ich im richtigen Verzeichnis?)
2) Datei editieren und speichern
3) Lupe: ob ~/work/objekt
4) Lupe: make (wenn du updaten willst)
5) Lupe: new ~/work/objekt (neuen Clone zum Testen)
6) Tests: [funktion] aufrufen, info/=/stk nutzen
Damit bist du für die nächsten Kapitel stabil aufgestellt.
Ab jetzt geht’s mehr um LPC selbst – und weniger um „wo ist meine Datei?!“.
Ausblick
In Kapitel 3 gehen wir in die Sprache: Datentypen, Variablen, Arrays, Mappings – und wie du sie
im Midgard-Stil sauber einsetzt (mit Übungen).