Added Abenteuergilde
diff --git a/gilden/abenteurer.c b/gilden/abenteurer.c
new file mode 100644
index 0000000..313e755
--- /dev/null
+++ b/gilden/abenteurer.c
@@ -0,0 +1,374 @@
+// Ich fand es ein wenig langweilig in der Gilde, also habe ich ein wenig daran
+// gebastelt.
+//  Hate.
+// 2002-12-06 Mandragons Projektbrett eingebaut, Humni.
+// 2003-07-11 Bugfix
+// 2005-08-19 Miril Arks Bienen eingebaut
+// 2007-08-03 Zesstra, PFad fuers Vereinsbuero angepasst.
+inherit  "/std/gilden_room";
+
+#include <properties.h>
+#include <rooms.h>
+#include <wizlevels.h>
+#include <language.h>
+#include <defines.h>
+#include <moving.h>
+#include <new_skills.h>
+#include <events.h>
+#include <player/fao.h>
+
+#define P_ANFAENGER_BIENENORT_ "anfaenger_bienenort_"
+#define P_ANFAENGER_BIENENZIEL_ "anfaenger_bienenziel_"
+
+string Funktion(); // Funktion der Gilde
+string Schmutz();  // Wohl bald ein Zaubertrank
+
+int _query_light() {return 20;}
+
+void create() {
+  ::create();
+
+  SetProp(P_GUILD_DEFAULT_SPELLBOOK,"ab_spells");
+  SetProp(P_LIGHT,20);
+  SetProp(P_INDOORS,1);
+  AddSpell("steinschlag");
+  AddSpell("licht");
+  AddSpell("kampfschrei");
+  AddSpell("ausweichen");
+  AddSpell("schaetz");
+  AddSpell("pfeil");
+  AddSpell("identifiziere");
+  AddSpell("feuerball");
+  AddSpell("schnell");
+  AddSpell("saeurestrahl");
+
+  SetProp(P_GUILD_MALE_TITLES, ([
+       1 : "der hoffnungsvolle Anfaenger",
+       2 : "der Landstreicher",
+       3 : "der Streuner",
+       4 : "der Wandergeselle",
+       5 : "der Waldlaeufer",
+       6 : "der Faehrtensucher",
+       7 : "der Wegekundige",
+       8 : "der Jaeger",
+       9 : "der Kundschafter",
+      10 : "der Reisende",
+      11 : "der Abenteurer",
+      12 : "der Weltenbummler",
+      13 : "der Draufgaenger",
+      14 : "der Schatzsucher",
+      15 : "der Feuerbaendiger",
+      16 : "der Entdecker",
+      17 : "der Eroberer",
+      18 : "der Held",
+      19 : "der angehende Seher",
+      20 : "der Seher",
+      ]) );
+  SetProp(P_GUILD_FEMALE_TITLES, ([
+       1 : "die hoffnungsvolle Anfaengerin",
+       2 : "die Landstreicherin",
+       3 : "die Streunerin",
+       4 : "die Wandergesellin",
+       5 : "die Waldlaeuferin",
+       6 : "die Faehrtensucherin",
+       7 : "die Wegekundige",
+       8 : "die Jaegerin",
+       9 : "die Kundschafterin",
+      10 : "die Reisende",
+      11 : "die Abenteurerin",
+      12 : "die Weltenbummlerin",
+      13 : "die Draufgaengerin",
+      14 : "die Schatzsucherin",
+      15 : "die Feuerbaendigerin",
+      16 : "die Entdeckerin",
+      17 : "die Erobererin",
+      18 : "die Heldin",
+      19 : "die angehende Seherin",
+      20 : "die Seherin",
+      ]) );
+
+  SetProp(P_INT_SHORT,"Die beruehmte Abenteurergilde");
+  SetProp(P_INT_LONG,
+ "Der grosse Raum mit seiner niedrigen Decke und den grob geschnittenen\n"
++"Querbalken hat Platz fuer sehr viele Personen. Knarrende Dielen erzaehlen\n"
++"ueber Heldentaten laengst vergessener Abenteurer, beruehmter als mancher\n"
++"Weise unserer Zeit.\n"
++"Abenteurer, aber auch andere Bewohner dieser Welt kommen hierher, um\n"
++"sich zu informieren, ihre Erfahrungen auszutauschen oder sich in den\n"
++"verschiedensten Wissenschaften zu verbessern.\n"
++"Durch die immer offene Tuer scheint die aufgehende Sonne herein und fuellt\n"
++"den Raum mit ihrem goldenen Licht. Sonst gibt es hier nur noch den Ausgang\n"
++"im Norden, welcher auf die Hafenstrasse fuehrt und Bilder an den Waenden,\n"
++"mit Zeichnungen und Gemaelden vom MorgenGrauen. Eins der Bilder erlaeutert\n"
++"die Funktion der Gilde und eine grosse Uhr an der Wand zeigt, was die\n"
+//+"Stunde schlaegt. In einer Ecke steht ein kleines Projektbrett.\n"
++"Stunde schlaegt.\n"
++"Nach oben fuehrt eine Treppe in das Buero des Foerdervereins Projekt\n"
++"MorgenGrauen e.V., das Du unbedingt besuchen solltest.\n");
+
+  AddDetail(({"raum", "gilde", "abenteurergilde", "haus", "gildenhaus",
+              "gildehaus"}),
+  "Du stehst mitten in der Abenteurergilde. Hier trifft man sich und kann\n"
+ +"auch seine persoenlichen Werte verbessern.\n");
+  AddDetail(({"tuer", "ausgang"}),
+  "Der immer offenstehende Ausgang fuehrt hinaus auf die Hafenstrasse.\n"
+ +"Goldenes Licht einer ewig aufgehenden Sonne scheint herein.\n");
+  AddSpecialDetail(({"bild", "bilder", "zeichnungen", "gemaelde", "karten",
+              "landschaftsbilder"}),"det_bild");
+  AddDetail(({"funktion", "schild"}), #'Funktion);
+  AddDetail(({"wand", "waende"}),
+  "Aus fein saeuberlich geschlagenen Steinen sind die Waende der Gilde\n"+
+ "zusammengesetzt. Viele interessante Bilder haengen daran.\n");
+  AddDetail(({"stein", "steine"}), "Es sind ganz einfache Sandsteine.\n");
+  AddDetail(({"fenster"}),
+  "Eine wundervolle Welt eroeffnet sich Dir, genannt Realitaet. Aber gibt es\n"
+ +"diese wirklich? Ist sie nicht voller Gefahren und Stress?\n");
+  AddDetail(({"seite", "suedseite"}),
+  "Am Suedende des Raumes ist ein eigenartiges Fenster auszumachen.\n");
+  AddDetail(({"balken", "querbalken", "holzbalken", "deckenbalken"}),
+  "Diese Balken halten das Obergeschoss des Gildenhauses, wohin nur Magier\n"
+ +"kommen und sind an manchen Stellen ganz schoen durchgebogen. Das grob ge-\n"
+ +"schnittene Holz ist teilweise von Schwertstreichen zernarbt.\n");
+  AddDetail(({"hafen", "hafenstrasse", "strasse"}),
+  "Zur Tuer hinaus gelangt man ueber die Hafenstrasse zum Hafen von Port Vain"
+ +"\n");
+  AddDetail(({"boden", "fussboden", "dielen"}),
+  "Die knarrenden Dielen der Gilde sind schon alt und abgeschabt. In den\n"
+ +"Ritzen zwischen ihnen ist viel Dreck von den Stiefeln der Abenteurer.\n");
+  AddDetail(({"decke"}),
+  "Die Decke des Raumes wird von Holzbalken gehalten.\n");
+  AddDetail(({"licht", "sonnenlicht", "sonne"}),
+  "Warmes Sonnenlicht scheint durch den Ausgang zur Strasse herein. Jedesmal\n"
+ +"wenn jemand hereinkommt wird er vom Licht umspuelt und erscheint Gott-\n"
+ +"gleich mit dieser Aura.\n");
+  AddDetail(({"ebene"}),
+  "Du betrachtest das Bild der Ebene und denkst, welche Schaetze in dieser\n"
+ +"flachen, gruenen Landschaft verborgen sein muessen.\n");
+  AddDetail(({"gebirge", "huegel", "berge", "berg"}),
+  "Das Bild der Huegel und Berge betrachtend, schleicht sich ein wenig Sehn-\n"
+ +"sucht nach dieser herrlichen, aber gefaehrlichen Landschaft ein.\n");
+  AddDetail(({"perspektiven", "perspektive", "darstellung", "landschaft"}),
+  "Manche der Landschaftsbilder sind aus der Vogelperspektive oder von\n"
+ +"hohen Bergen aus oder von Zwergen gemalt worden.\n");
+  AddDetail(({"see", "meer", "wellen"}),
+  "Die Wellen auf dem Meer glitzern wie tausend Edelsteine.\n");
+  AddDetail(({"spritzer", "lichtspritzer"}),
+  "Wie tausend kleine Edelsteine verteilen sich diese winzigen, gluehenden\n"
+ +"Lichtspritzer ueber das wundervolle Gemaelde\n");
+  AddDetail(({"geschoss", "obergeschoss"}),
+  "Ins obere Geschoss der Gilde kommen nur Magier, mittels eines besonderen\n"
+ +"Zauberspruchs, der die Decke durchlaessig fuer sie macht.\n");
+  AddDetail(({"ritzen", "fugen"}),
+  "In den Fugen zwischen den Dielen befindet sich eine Menge Schmutz und\n"
+ +"Dreck von den Besuchern der Gilde.\n");
+  AddDetail(({"fugen", "dreck", "schmutz"}), #'Schmutz);
+  AddDetail(({"holz"}), "Die Dielen und die Deckenbalken sind aus Holz.\n");
+  AddDetail(({"kartograph", "kartographen"}),
+  "Dieselben laufen hier zwar im Moment nicht herum, aber ihre Karten sehen\n"
+ +"ziemlich verwirrend aus mit den ganzen Linien, welche diese Welt "
+  "darstellen.\n");
+  AddDetail(({"stellen", "stelle"}),
+  "Nichts sieht aus wie das andere, und die Ecken sind da keine Ausnahmen.\n");
+  AddDetail(({"ecken","ecke"}),
+  "In einer der Ecken, gleich neben der Treppe, steht ein kleines braunes\n"
+ +"Holzbrett, das sofort Deine Aufmerksamkeit erregt. Wozu es wohl dient?\n");
+  AddDetail("aufmerksamkeit",
+  "Du beschliesst, Dir das Brett sofort naeher zu betrachten, um sie zu\n"
+      +"befriedigen.\n");
+/*
+  AddDetail(({"brett","holzbrett"}),
+  "Ein unscheinbares kleines Brett steht in der Ecke des Raumes. Wenn man\n"
+ +"bedenkt, wie viele kleine Zettel daran befestigt wurden, kann es sich\n"
+ +"nur um ein schwarzes Brett handeln. Welche Informationen hier wohl\n"
+ +"ausgetauscht werden? Du koenntest natuerlich anfangen, die Zettel zu\n"
+ +"lesen, um das herauszufinden ...\n");
+  AddDetail("zettel",
+  "Viele verschiedene Zettel stecken an dem Brett. Rote, gelbe, blaue,\n"
+ +"jeder scheint eine andere Farbe zu haben. Auf jedem von ihnen scheint\n"
+ +"etwas geschrieben zu sein.\n");
+  AddDetail(({"farbe","farben"}),
+  "Es sind so viele, Du wuerdest bestimmt jahrelang zaehlen.\n");
+  AddDetail("informationen",
+  "Wenn Du die Zettel liest, findest Du bestimmt welche.");
+*/
+  AddDetail(({"wissenschaften", "eigenschaften"}), #'Funktion); //');
+  AddDetail(({"narben", "schwertstreich"}),
+  "Die Narben in den Holzbalken sind schon recht alt. Es ist lange her, dass\n"
+   +"hier richtig gekaempft wurde.\n");
+  AddDetail(({"aura"}),
+ "Eine Aura von Licht umgibt jeden, der von der Strasse ins Haus kommt.\n");
+  AddDetail(({"bewohner", "abenteurer"}),
+ "Hier, im Gildenhaus, ist jeder gern willkommen.\n");
+  AddDetail(({"weise", "weiser", "recken"}),
+  "Die Weisen dieses Landes sind beruehmt, kommen aber nicht an die Be-\n"
+  +"ruehmtheit ihrer Vorfahren, die grossen Recken der ersten Jahre, heran.\n");
+  AddDetail(({"realitaet"}), "Was ist schon real?\n");
+  AddSpecialDetail("uhr","zeige_reboot");
+
+
+  AddDetail(({"buero","foerderverein"}),
+    "Wichtige Informationen warten auf Dich im Buero des Foerdervereins!\n");
+  AddDetail("informationen", "Du musst schon ins Buero gehen, wenn Du "
+      "die Informationen erhalten willst.\n");
+  AddDetail("treppe","Die Treppe fuehrt nach Oben in das Buero des "
+      "Foerdervereins Projekt MorgenGrauen e.V.\n");
+  AddExit("norden", "/d/ebene/room/PortVain/po_haf1");
+  AddExit("oben","/p/verein/room/buero");
+
+  AddCmd("gehe|geh&\ngehtnicht",0,"Um Dich hier fortzubewegen, "
+      "solltest Du direkt das Kommando der Richtung eingeben,"
+      " wie ,,norden'' oder ,,suedwesten''. Du kannst das auch "
+      "abkuerzen, durch ,,n'' oder ,,sw''.");
+
+  AddItem("/obj/zeitungsautomat", REFRESH_REMOVE);
+
+  AddSpecialDetail("karte","karte");
+  AddSpecialDetail("brett","brett_fun");
+
+  EVENTD->RegisterEvent(EVT_LIB_ADVANCE, "handle_advance", this_object());
+
+  // nur auf dem Mudrechner laden (Stichwort: oeffentlich Mudlib)
+#if MUDHOST == __HOST_NAME__
+  AddItem("/p/service/troy/obj/buchautomat", REFRESH_REMOVE);
+//  AddItem("/p/service/mandragon/projektbrett/board", REFRESH_REMOVE);
+  // Die Biene fuer den Transport zur Wonnewichtlichtung.
+  // Ark, 19.08.05
+  AddItem("/d/anfaenger/ark/mon/mantisbiene",REFRESH_DESTRUCT,
+   ([P_ANFAENGER_BIENENORT_:"Mensch",
+     P_ANFAENGER_BIENENZIEL_:({"/d/anfaenger/ark/rooms/wald16",
+                               "zum Wald der Wonnewichte",
+                               "/gilden/abenteurer"})]));
+#endif
+}
+
+string det_bild()
+{
+  return
+   "Die Zeichnung und Gemaelde stellen MorgenGrauen aus den verschiedensten\n"
+   "Perspektiven dar. Einige davon zeigen abstrakte Darstellungen, wie sie\n"
+   "gerne von Kartographen gemacht werden, und andere zeigen wunderschoene\n"
+   "Darstellungen von Landschaften, wie dem Gebirge oder der Ebene. Besonders\n"
+   "schoen ist ein Bild der See. Tausende von Lichtspritzern verteilen sich\n"
+   "ueber die Wellen.\n"
+   "Ein kleines Schild zeigt folgendes:\n"+Funktion();
+}
+
+string brett_fun()
+{
+  if (present("party\nbrett",this_object()))
+    return "Welches Brett meinst Du denn? Das Partybrett oder das Holzbrett?\n";
+  return GetDetail("holzbrett");
+}
+
+int beitreten()
+{
+  if (::beitreten()<1)
+    return 1; // Meldung vom Gildenmaster oder Gildenobjekt
+  write("Du bist jetzt ein Abenteurer.\n");
+  adjust_title(PL);
+  return 1;
+}
+
+varargs int austreten(int loss)
+{
+  if (::austreten()<1)
+    return 1; // Meldung kommt vom Gildenmaster
+  write("Du bist nun kein Abenteurer mehr.\n");
+  return 1;
+}
+
+string Funktion()
+{   string re;
+  re = ("Moegliche Befehle sind:\n"
+        +"                liste\n"
+        +"                erhoehe (stufe)\n"
+        +"                kosten\n"
+        +"                lerne\n");
+  if (this_player()->QueryProp(P_GUILD)!="abenteurer")
+  re += ("                trete in gilde ein\n"+
+         "                trete aus gilde aus\n");
+  return re;
+}
+
+string Schmutz()
+{
+  // hier sollte sich doch glatt ein Zaubertrank lohnen!!
+  return "In den Fugen befindet sich viel Schmutz.\n";
+}
+
+// Fuer Spielerstufenaufstiege gerufen - egal in welcher Gilde.
+public void handle_advance(string eid, object trigob, mixed data) {
+
+  object pl = data[E_OBJECT];
+  if (!pl || !IsGuildMember(pl) || !interactive(pl))
+    return;
+
+  int lvl=pl->QueryProp(P_LEVEL);
+  // nicht fuer Level 1, da ist genug scroll...
+  if (lvl == 1) return;
+
+  // Alle Spells raussuchen, die der Spieler lernen kann.
+  string *spells=filter(m_indices(Query(P_GUILD_SKILLS,F_VALUE)), 
+      function int (string sp)
+      {
+        mapping ski = QuerySpell(sp);
+        if (!ski) return 0; // kein Spell
+        if (pl->QuerySkillAbility(sp) > 0
+            || check_restrictions(pl, ski[SI_SKILLRESTR_LEARN]))
+          return 0; // Vorraussetzungen nicht erfuellt oder schon gelernt.
+        return 1; // offenbar ist sp lernbar.
+      }
+      );
+
+  int count=sizeof(spells);
+  if (!count)
+    return;
+  
+  if (count == 1) {
+    tell_object(pl, break_string("Dir faellt auf einmal auf, dass Du "
+       "versuchen koenntest, den Zauberspruch \"" + spells[0] 
+       + "\" in der Abenteurergilde zu erlernen.",78));
+  }
+  else {
+     tell_object(pl, break_string("Dir faellt auf einmal auf, dass Du "
+       "versuchen koenntest, die folgenden Zaubersprueche in der "
+       "Abenteurergilde zu erlernen:",78));
+     tell_object(pl, CountUp(spells) + "\n");
+  }
+}
+
+// wird aus Spielerobjekt, /std/gilde.c und Gildenmaster gerufen (mindestens)
+// aktualisiert den Gildenlevel auf den Spielerlevel und setzt den per
+// get_new_title() aus den Gildentiteln ermittelten Gildentitel.
+void adjust_title(object pl) {
+  int lv;
+
+  // bei P_LEVEL < 0 ist der Spieler noch "nicht fertig".
+  // Der Titel wird anschliessend noch korrekt gesetzt.
+  if (!pl || !IsGuildMember(pl) || (lv=pl->QueryProp(P_LEVEL)) < 0)
+    return;
+
+  pl->SetProp(P_GUILD_LEVEL,lv);
+  if (!lv) lv=1;
+  pl->SetProp(P_GUILD_TITLE, get_new_title(lv,pl));
+  // Spielertitel nullen, damit der Gildentitel angezeigt wird.
+  if (!IS_SEER(pl) && !FAO_HAS_TITLE_GIFT(pl))
+    pl->SetProp(P_TITLE,0);
+}
+
+string karte() {
+  if (this_player() && present("karte",this_player())) return 0;
+  return GetDetail("karten");
+}
+
+void init() {
+  int res;
+  object ob;
+
+  ::init();
+
+  // Von Ark, an alle Rassenstartpunkte
+  if (ob=present("\nentdecker_obj",this_player()))
+      ob->Check_And_Update(this_player(),"Menschen");
+}
+
diff --git a/spellbooks/ab_spells.c b/spellbooks/ab_spells.c
new file mode 100644
index 0000000..e65af3f
--- /dev/null
+++ b/spellbooks/ab_spells.c
@@ -0,0 +1,535 @@
+/* Gildenobjekt fuer Abenteurer - MorgenGrauen */
+/* Boing, 1993-1998                                */
+/* Sprueche:
+     Lichtkugel herbeizaubern: licht
+       Magiepunkte 5, Stufe 4
+       Dauer: Level * 20 Sekunden
+     Identifizieren: identifiziere
+       Magiepunkte 10, Stufe 3
+     Monster einschaetzen: schaetz <name>
+       Magiepunkte 3, Stufe 10
+     Pfeilangriff: pfeil <name>
+       Schaden maximal 20, Magiepunkte 10, Stufe 11
+     Gegenstaende untersuchen: identifiziere <objekt>
+       Wenn P_INFO exisitiert, wird dies ausgegeben
+       Magiepunkte 10, stufe 8
+     Ausweichen: ausweichen
+       Geht nur im Kampf, genau einer Attacke wird ausgewichen.
+       Magiepunkte 10, Stufe 12
+     Kampfschrei: kampfschrei <opfer> bzw. kampfschrei meldung <meldung>
+       Der Kampfschrei wird ausgestossen und verlangsamt den Gegner.
+       Magiepunkte 30, stufe 13
+     Feuerball: feuerball <name>
+       Schaden maximal 40, Magiepunkte 20, Stufe 15
+     Schnelligkeit: schnell
+       Gibt fuer eine bestimmte Zeit zusaetzliche Angriffe
+       Magiepunkte 100, Stufe 17
+     Saeurestrahl: saeurestrahl <name>
+       Schaden maximal 60, Magiepunkte 25, Stufe 30
+*/
+
+#include <properties.h>
+#include <language.h>
+#include <attributes.h>
+#include <combat.h>
+#include <wizlevels.h>
+#include <new_skills.h>
+
+#define LICHTKUGEL "/gilden/files.abenteurer/lichtkugel"
+
+inherit "/std/spellbook";
+
+void create() {
+  ::create();
+  SetProp(P_GLOBAL_SKILLPROPS,
+          ([SI_SPELLFATIGUE:2,       // 2 Sekunden kein neuer Spell
+            SI_SKILLLEARN:5,         // 0.05% pro 2 A_INT
+            OFFSET(SI_SKILLLEARN):10 // plus 0.1% in jedem Fall
+            ]));
+
+    AddSpell("steinschlag",5,
+        ([SI_SKILLRESTR_LEARN:([P_LEVEL:1]),
+         SI_SKILLDAMAGE:40,
+         OFFSET(SI_SKILLDAMAGE):40,
+         SI_SKILLDAMAGE_TYPE: ({DT_BLUDGEON}),
+         SI_MAGIC_TYPE:({MT_ANGRIFF}),
+         SI_SPELL:([SP_NAME:"steinschlag"])]));
+
+  AddSpell("identifiziere",10,
+       ([SI_SKILLRESTR_LEARN:([P_LEVEL:3]),
+         SI_MAGIC_TYPE: ({ MT_HELLSICHT }),
+         SI_SPELL: ([P_NAME: "identifiziere"]),
+         ]) );
+  AddSpell("licht",5,
+      ([SI_SKILLRESTR_LEARN:([P_LEVEL:6]),
+        SI_SPELL: ([P_NAME: "licht"]) 
+       ]) );
+  AddSpell("schaetz",3,
+       ([SI_SKILLRESTR_LEARN:([P_LEVEL:8]),
+         SI_MAGIC_TYPE: ({ MT_HELLSICHT }),
+         SI_SPELL: ([SP_NAME: "schaetz"]),
+         ]));
+  AddSpell("pfeil",10,
+           ([SI_SKILLRESTR_LEARN:([P_LEVEL:10]),
+             // Um diesen Spruch lernen zu koennen muss
+             // der Level mindestens 11 sein
+             SI_SKILLDAMAGE:200,
+             // Schaden: Random(200) ...
+             SI_SKILLDAMAGE_TYPE:({DT_MAGIC}),
+             // Damage Type: Magic
+             SI_MAGIC_TYPE: ({ MT_ANGRIFF }),
+             SI_SPELL: ([ SP_NAME: "pfeil" ]),
+             // Boni für hintere Kampfreihen
+             SI_SKILLDAMAGE_BY_ROW: ([2:110,3:50,4:10]),
+             OFFSET(SI_SKILLDAMAGE_BY_ROW): ([2:50,3:20,4:5])
+             ]));
+  AddSpell("ausweichen", 10,
+      ([SI_SKILLRESTR_LEARN:([P_LEVEL:13]),
+        SI_SPELL: ([P_NAME: "ausweichen"]),
+        ]));
+  AddSpell("kampfschrei", 30,
+       ([SI_SKILLRESTR_LEARN:([P_LEVEL:16]),
+         SI_MAGIC_TYPE: ({ MT_PSYCHO }),
+         SI_SPELL: ([SP_NAME: "kampfschrei"]),
+         ]));
+  AddSpell("feuerball",20,
+           ([SI_SKILLRESTR_LEARN:([P_LEVEL:18]),
+             SI_SKILLDAMAGE:300,
+             // Schaden: Random(300) ...
+             OFFSET(SI_SKILLDAMAGE):100,
+             // ... plus 100
+             SI_SKILLDAMAGE_TYPE:({DT_FIRE}),
+             // Damage Type: Fire
+            SI_MAGIC_TYPE: ({ MT_ANGRIFF }),
+            SI_SPELL: ([SP_NAME: "feuerball"]),
+            SI_SKILLDAMAGE_BY_ROW: ([2:80,3:150,4:80,5:20]),
+            OFFSET(SI_SKILLDAMAGE_BY_ROW): ([2:30,3:80,4:30,5:10])
+             ]));
+  AddSpell("schnell",100,
+      ([SI_SKILLRESTR_LEARN:([P_LEVEL:21]),
+        SI_SPELL: ([P_NAME: "schnell"]) ]));
+  AddSpell("saeurestrahl",25,
+       ([SI_SKILLRESTR_LEARN:([P_LEVEL:28]),
+             OFFSET(SI_SKILLLEARN):1,
+             FACTOR(SI_SKILLLEARN):20,
+             SI_SKILLDAMAGE:400,
+             // Schaden: Random(400) ...
+             OFFSET(SI_SKILLDAMAGE):200,
+             // ... plus 200
+             SI_SKILLDAMAGE_TYPE:({DT_ACID}),
+             // Damage Type: Saeure
+             SI_MAGIC_TYPE: ({ MT_ANGRIFF }),
+             SI_SPELL: ([SP_NAME: "saeurestrahl"]),
+             SI_SKILLDAMAGE_BY_ROW:([2:60,3:150,4:210,5:150,6:60]),
+             OFFSET(SI_SKILLDAMAGE_BY_ROW):([2:30,3:80,4:120,5:80,6:30])
+             ]));
+
+}
+
+int
+steinschlag(object caster, mapping sinfo) {
+  object victim;
+  int hands;
+  string vn, vnw, cn;
+  int suc;
+
+  victim=FindEnemyVictim(sinfo[SI_SKILLARG],caster,
+         "Ueber wem willst Du einen Steinschlag niedergehen lassen?\n");
+  if (!victim)
+    return 0;
+  if ((suc=SpellSuccess(caster,sinfo))<=0)
+    return MISSERFOLG;
+  if (suc < victim->SpellDefend(caster, sinfo))
+  {
+    tell_object(caster, victim->Name() + " wehrt Deinen Spruch ab.\n");
+    return ERFOLG;
+  }
+
+  cn = caster->Name();
+  vnw = victim->name(WEN, 2);
+  say(sprintf("%s laesst kleine Kiesel auf %s fallen.\n",cn, vnw),
+      victim);
+  printf("Du konzentrierst Dich darauf, kleine Kiesel auf %s fallen zu lassen.\n", vnw);
+  tell_object(victim,sprintf("%s laesst kleine Kiesel auf Dich fallen.\n",
+                             cn));
+  TryDefaultAttackSpell(victim,caster,sinfo,
+            ([SP_NAME:"steinschlag", SP_PHYSICAL_ATTACK:1,SP_SHOW_DAMAGE:1]));
+  return ERFOLG;
+}
+
+int
+schaetz(object caster, mapping sinfo) {
+   object victim;
+   int hpdiff, wcdiff, acdiff;
+   int hp, vhp, wc, vwc, ac, vac;
+   string result;
+   string vname, vnamegen;
+   int suc;
+
+   victim=FindLivingVictim(sinfo[SI_SKILLARG],caster,
+                           "Wen moechtest Du einschaetzen?\n");
+   if (!victim)
+     return 0;
+   if ((suc=SpellSuccess(caster,sinfo))<=0)
+      return MISSERFOLG;
+   if (suc < victim->SpellDefend(caster, sinfo))
+   {
+     tell_object(caster, victim->Name() + " wehrt Deinen Spruch ab.\n");
+     return ERFOLG;
+   }
+
+   hp = caster->QueryProp(P_HP);    vhp = victim->QueryProp(P_HP);
+   wc = caster->QueryProp(P_TOTAL_WC);  vwc = victim->QueryProp(P_TOTAL_WC);
+   ac = caster->QueryProp(P_TOTAL_AC);  vac = victim->QueryProp(P_TOTAL_AC);
+   hpdiff = hp - vhp;
+   wcdiff = wc - vwc;
+   acdiff = ac - vac;
+   vname = victim->name(WER, 1);
+   vnamegen = victim->name(WESSEN, 1);
+
+   if (hpdiff > 10*vhp)
+      result = capitalize(victim->name(WER, 1))+" sollte sich besser schon mal einen Sarg besorgen.\n";
+   else if (hpdiff > 7*vhp)
+      result = "Du bist " + victim->name(WEM, 1) + " haushoch ueberlegen.\n";
+   else if (hpdiff > 4*vhp)
+      result = "Du bist sehr viel staerker als " + vname + ".\n";
+   else if (hpdiff > 2*vhp)
+      result = "Du bist viel staerker als " + vname + ".\n";
+   else if (2*hpdiff > 3*vhp)
+      result = "Du bist spuerbar staerker als " + vname + ".\n";
+   else if (hpdiff > vhp)
+      result = "Du bist staerker als " + vname + ".\n";
+   else if (hpdiff > vhp/5)
+      result = "Du bist etwas staerker als " + vname + ".\n";
+   else if (-hpdiff > 10*hp)
+      result = "Besorg Dir besser schon mal einen Sarg.\n";
+   else if (-hpdiff > 7*hp)
+      result = capitalize(vname) + " ist Dir haushoch ueberlegen.\n";
+   else if (-hpdiff > 4*hp)
+      result = capitalize(vname) + " ist sehr viel staerker als Du.\n";
+   else if (-hpdiff > 2*hp)
+      result = capitalize(vname) + " ist viel staerker als Du.\n";
+   else if (-2*hpdiff > 3*hp)
+      result = capitalize(vname) + " ist spuerbar staerker als Du.\n";
+   else if (-hpdiff > hp)
+      result = capitalize(vname) + " ist staerker als Du.\n";
+   else if (-hpdiff > hp/5)
+      result = capitalize(vname) + " ist etwas staerker als Du.\n";
+   else
+      result = capitalize(vname) + " ist etwa gleich stark wie Du.\n";
+   write(result);
+
+   if (acdiff > 2*vac)
+      result = "Deine Ruestung ist unglaublich viel besser als die "
+     + vnamegen + ".\n";
+   else if (acdiff > vac)
+      result = "Deine Ruestung ist viel besser als die " + vnamegen + ".\n";
+   else if (acdiff >vac/5)
+      result = "Deine Ruestung ist besser als die " + vnamegen + ".\n";
+   else if (-acdiff > 2*ac)
+      result = "Die Ruestung " + vnamegen
+     + " ist unglaublich viel besser als Deine.\n";
+   else if (-acdiff > ac)
+      result = "Die Ruestung " + vnamegen + " ist viel besser als Deine.\n";
+   else if (-acdiff > ac/5)
+      result = "Die Ruestung " + vnamegen + " ist besser als Deine.\n";
+   else
+      result = "Eure Ruestungen sind etwa gleich gut.\n";
+   write(result);
+
+   if (wcdiff > 2*vwc)
+      result = "Deine Waffe ist eigentlich zu gut fuer diesen Gegner.\n";
+   else if (wcdiff > vwc)
+      result = "Deine Waffe ist viel besser als die " +vnamegen + ".\n";
+   else if (wcdiff > vwc/5)
+      result = "Deine Waffe ist besser als die " +vnamegen + ".\n";
+   else if (-wcdiff > 2*wc)
+      result = "Die Waffe " + vnamegen
+     + " laesst Deine ganz mickrig aussehen.\n";
+   else if (-wcdiff > wc)
+      result = "Die Waffe " + vnamegen + " ist viel besser als Deine.\n";
+   else if (-wcdiff > wc/5)
+      result = "Die Waffe " + vnamegen + " ist besser als Deine.\n";
+   else
+      result = "Eure Waffen sind etwa gleich gut.\n";
+   write(result);
+   return ERFOLG;
+}
+
+int kampfschrei(object caster, mapping sinfo)
+{
+  object ob;
+  string cmdline, meldung;
+  int    suc, dauer;
+
+  cmdline = this_player()->_unparsed_args();
+  if (cmdline)
+  {
+    if (sscanf(cmdline, "meldung %s", meldung))
+    {
+      caster->Set("ab_kampfschrei", SAVE, F_MODE_AS);
+      caster->SetProp("ab_kampfschrei", meldung);
+      printf("Dein Kampfschrei ist jetzt: %s\n", meldung);
+      return 0;
+    }
+  }
+  ob = FindEnemyVictim(sinfo[SI_SKILLARG], caster,
+          "Wem willst Du Deinen Kampfschrei entgegenschleudern?\n");
+
+  if (!ob)
+    return 0;
+
+  if ((suc=SpellSuccess(caster, sinfo)) <= 0)
+    return MISSERFOLG;
+  if (suc < ob->SpellDefend(caster, sinfo))
+  {
+    tell_object(caster, ob->Name() + " wehrt Deinen Spruch ab.\n");
+    return ERFOLG;
+  }
+
+  meldung = caster->QueryProp("ab_kampfschrei");
+  if (!meldung)
+    meldung = "Aaaaaaaiiiiieeeeeeeeeeeeeeeehhhhhhhhhhhhhhh!!!!!!!\n";
+
+  write(break_string(meldung, 78, "Du kreischst: "));
+  tell_room(environment(caster),
+        break_string(meldung, 78, caster->Name()+" kreischt: "),
+        ({caster}));
+  tell_object(ob, "Du fuehlst Dich wie gelaehmt.\n");
+
+  dauer = 1 + (suc/1000 + random(caster->QueryProp(P_LEVEL)/2))/2;
+  if (dauer>25)
+    dauer = 25;
+  ob->ModifySkillAttribute(SA_SPEED, -50, dauer);
+
+  return ERFOLG;
+}
+
+int ausweichen(object caster, mapping sinfo)
+{
+  if (!caster->InFight())
+  {
+    write("Ausweichen ausserhalb eines Kampfes ist ziemlich sinnlos.\n");
+    return 0;
+  }
+
+  if (caster->QueryProp(P_TMP_DEFEND_HOOK))
+  {
+    write("Das geht momentan nicht, Du wunderst Dich wieso!\n");
+    return 0;
+  }
+
+  if (SpellSuccess(caster,sinfo)<=0)
+    return MISSERFOLG;
+
+  caster->SetProp(P_TMP_DEFEND_HOOK, ({ time()+4, this_object(), "Deckung" }));
+  return ERFOLG;
+}
+
+mixed Deckung(int dam, mixed dam_type, mixed spell, object enemy)
+{
+  if (!pointerp(dam_type))
+    dam_type = ({ dam_type });
+  if (sizeof(dam_type & m_indices(PHYSICAL_DAMAGE_TYPES)))
+  {
+    tell_object(previous_object(), "Du weichst gekonnt aus.\n");
+    if (previous_object()->QueryProp(P_TMP_DEFEND_HOOK)[1] == this_object())
+      previous_object()->SetProp(P_TMP_DEFEND_HOOK, 0);
+    return 0;
+  }
+  tell_object(previous_object(), "Dein Ausweichversuch ist vergebens.\n");
+  return ({ dam, dam_type, spell, enemy });
+}
+
+int
+identifiziere(object caster, mapping sinfo) {
+  object ob;
+  string* fi;
+  string cn;
+  string result, info;
+  int suc;
+  ob=FindVictim(sinfo[SI_SKILLARG], caster,
+                "Was moechtest Du identifizieren?\n");
+  if (!ob)
+    return 0;
+
+  cn = caster->name();
+  if ((suc=SpellSuccess(caster,sinfo))<=0)
+    return MISSERFOLG;
+  if (suc < ob->SpellDefend(caster, sinfo))
+  {
+    tell_object(caster, ob->Name() + " wehrt Deinen Spruch ab.\n");
+    return ERFOLG;
+  }
+
+  result="Du identifizierst "+ob->name(WEN,1)+". "
+        +capitalize(ob->QueryPronoun())
+        +" besteh"
+        +(ob->QueryProp(P_PLURAL) ? "en" : "t")
+        +" aus "
+        +(ob->MaterialList(WEM, caster))+". ";
+  if (info=ob->QueryProp(P_INFO))
+    result+="Ausserdem bemerkst Du folgendes:\n"+info;
+  else result+="Du kannst sonst nichts besonderes an "+ob->QueryPronoun(WEM)
+              +" erkennen.";
+  write(break_string(result, 78, 0, 1));
+  return ERFOLG;
+}
+
+int
+licht(object caster, mapping sinfo)
+{
+   object l;
+
+   tell_object(caster, "Du machst eine magische Bewegung.\n");
+   tell_room(environment(caster),
+       sprintf("%s macht eine magische Bewegung.\n",
+           capitalize(caster->name(WER))), ({caster}));
+   
+   int suc=SpellSuccess(caster,sinfo);
+   if (suc<=0)
+      return MISSERFOLG;
+
+   l = clone_object(LICHTKUGEL);
+   if (l->move(this_player()) > 0)
+   {
+      int lvl;
+      // fuer Spruchrollen-Support.
+      if (!sinfo[SI_USR] || !(lvl=sinfo[SI_USR][P_LEVEL]) )
+        lvl = caster->QueryProp(P_LEVEL);
+      lvl = min(lvl,42);
+      // wenn der Spell nicht ganz so gut gelingt, ist die Kugel auch etwas
+      // dunkler.
+      if (suc<6000)
+      {
+        l->SetProp(P_LIGHT,1);
+        tell_object(caster,
+            "Wie aus dem Nichts erscheint eine leuchtende Kugel.\n");
+      }
+      else
+        tell_object(caster,
+            "Wie aus dem Nichts erscheint eine hell leuchtende Kugel.\n");
+      l->start_remove(lvl * 20 * min(suc+3333,10000) / 10000);
+   }
+   else
+   {
+      l->remove();
+      tell_object(caster,
+          "Eine Lichtkugel erscheint, zerplatzt aber sofort mit einem sanften 'plopp'.\n");
+   }
+
+   return ERFOLG;
+}
+
+int
+saeurestrahl(object caster, mapping sinfo) {
+  object victim;
+  int hands;
+  string vnw;
+  int suc;
+
+  victim=FindEnemyVictim(sinfo[SI_SKILLARG],caster,
+                     "Wen willst Du mit einem Saeurestrahl beschiessen?\n");
+  if (!victim)
+    return 0;
+  if ((suc=SpellSuccess(caster,sinfo))<=0)
+    return MISSERFOLG;
+  if (suc < victim->SpellDefend(caster, sinfo))
+  {
+    tell_object(caster, victim->Name() + " wehrt Deinen Spruch ab.\n");
+    return ERFOLG;
+  }
+
+  vnw = victim->name(WEN, 2);
+  say(break_string(
+   sprintf(
+   "%s fuchtelt seltsam in der Luft herum und schiesst einen Saeurestrahl auf %s.\n",
+       caster->Name(), vnw), 78), victim);
+  printf("Du schiesst einen Saeurestrahl auf %s.\n", vnw);
+  tell_object(victim, sprintf("%s schiesst einen Saeurestrahl auf Dich.\n",
+                              caster->Name()));
+
+  TryDefaultAttackSpell(victim,caster,sinfo,
+            ([SP_NAME:"Saeurestrahl", SP_SHOW_DAMAGE:1]));
+
+  return ERFOLG;
+}
+
+int
+feuerball(object caster, mapping sinfo) {
+  object victim;
+  int hands;
+  string vnw;
+  int suc;
+
+  victim=FindEnemyVictim(sinfo[SI_SKILLARG],caster,
+                         "Auf wen willst Du einen Feuerball schleudern?\n");
+  if (!victim)
+    return 0;
+  if ((suc=SpellSuccess(caster,sinfo))<=0)
+    return MISSERFOLG;
+  if (suc < victim->SpellDefend(caster, sinfo))
+  {
+    tell_object(caster, victim->Name() + " wehrt Deinen Spruch ab.\n");
+    return ERFOLG;
+  }
+
+  vnw = victim->name(WEM, 2);
+  say(sprintf("%s wirft einen Feuerball nach %s.\n",
+              caster->Name(), vnw), victim);
+  printf("Du wirfst einen Feuerball nach %s.\n", vnw);
+  tell_object(victim, sprintf("%s wirft einen Feuerball nach Dir.\n",
+                              caster->Name()));
+
+  TryDefaultAttackSpell(victim,caster,sinfo,
+            ([SP_NAME:"Feuerball", SP_SHOW_DAMAGE:1]));
+
+  return ERFOLG;
+}
+
+int
+pfeil(object caster, mapping sinfo) {
+  object victim;
+  int hands;
+  string vn, vnw, cn;
+  int suc;
+
+  victim=FindEnemyVictim(sinfo[SI_SKILLARG],caster,
+                         "Nach wem willst Du einen magischen Pfeil werfen?\n");
+  if (!victim)
+    return 0;
+  if ((suc=SpellSuccess(caster,sinfo))<=0)
+    return MISSERFOLG;
+  if (suc < victim->SpellDefend(caster, sinfo))
+  {
+    tell_object(caster, victim->Name() + " wehrt Deinen Spruch ab.\n");
+    return ERFOLG;
+  }
+
+  cn = caster->Name();
+  vnw = victim->name(WEN, 2);
+  say(sprintf("%s feuert einen magischen Pfeil auf %s ab.\n",cn, vnw),
+      victim);
+  printf("Du feuerst einen magischen Pfeil auf %s ab.\n", vnw);
+  tell_object(victim,sprintf("%s feuert einen magischen Pfeil auf Dich ab.\n",
+                             cn));
+  TryDefaultAttackSpell(victim,caster,sinfo,
+            ([SP_NAME:"Pfeil", SP_SHOW_DAMAGE:1]));
+  return ERFOLG;
+}
+
+int
+schnell(object caster, mapping sinfo) {
+  int dauer;
+
+  if (SpellSuccess(caster,sinfo)<=0)
+    return MISSERFOLG;
+  write("Du fuehlst Dich ploetzlich deutlich schneller.\n");
+  dauer = 2 * (caster->QueryAttribute(A_DEX) +
+           random(sinfo[SI_SKILLABILITY]/1000));
+  if (dauer>60)
+    dauer = 60;
+  caster->ModifySkillAttribute(SA_SPEED, 100, dauer);
+
+  return ERFOLG;
+}