Richtlinien zur Programmierung von NPCs
======================================= 

1. Was sind NPCs?
-----------------

NPCs sind sogenannte "Non Playing Characters", also Lebewesen,
die keine Spieler sind. Meist werden NPCs staendig von Spielern
gekillt, um an Erfahrungspunkte und Ausruestung oder Geld zu
kommen. Aber auch als Informationsquelle kann man NPCs einbauen.
NPCs inheriten /std/npc und koennen geclont werden, es existiert
also immer eine Bluprint und mehere Clones. Die Blueprint 
befindet sich aber nur zur Erzeugung von Clones im Speicher, 
deshalb sollte man in der Funktion create() immer zuerst auf 
is_clone() abfragen, denn die Blueprint braucht z.B. keine 
Properties gesetzt zu bekommen.

create()
{
  if( !is_clone(this_object()) ) return;
  ::create(); 
...


2. Welche Eigenschaften sollte ein NPC unbedingt definieren?
------------------------------------------------------------

Folgende Properties sollten in create() unbedingt gesetzt werden:

P_SHORT            Kurzbeschreibung (ohne Punkt und \n !!),
                   Dieser Text wird angezeigt, wenn der NPC
                   in einem Raum steht.
  
P_LONG             Langbeschreibung (sollte auf 78 Zeichen pro
                   Zeile umgebrochen werden, am besten mit
                   break_string()). Dieser Text beschreibt den
                   NPC genau und wird ausgegeben, wenn man
                   ihn untersucht.
                   Dieser Text wird beim Setzen automatisch auf
                   78 Zeichen pro Zeile umgebrochen, hierbei
                   bleiben vorhandene \n erhalten. Man kann das
                   automatische Umbrechen mit einem \t (Tabulator)
                   als allererstes Zeichen unterdruecken, sollte
                   dies unbedingt notwendig sein.

P_INFO             Hier kann man Besonderheiten angeben, die man
                   mittels Zauberspruch 'identifiziere' bekommt.
                   Hier sollte man anmerken, wenn der NPC
                   spezielle Eigenschaften hat, z.B.:
                   "Dieser Elf ist von einer magischen Aura umgeben.\n"

P_NAME             Dieser Text wird verwendet, wenn der NPC Aktionen
                   macht, z.B. angreift, entspricht also dem Namen
                   eines Spielers. Hierbei versucht die Mudlib, die
                   vier Faelle automatisch abzuleiten (bei Verwendung
                   von name() bzw. Name()), was manchmal aber auch
                   schiefgehen kann - man sollte daher vorsichtshalber
                   die 8 moeglichen Faelle (1.-4., bestimmter sowie
                   unbestimmter Artikel) von name() haendisch aus-
                   testen - gegebenenfalls kann man dann P_NAME auch
                   auf ein Array mit den vier Faellen setzen.

P_GENDER           Das Geschlecht des NPCs (DER Ork, DAS Kaninnchen).
                   Wird durch die Konstanten MALE, FEMALE und NEUTER
                   bestimmt. (/sys/thing/language.h)

P_IDS              Diese Property sollte nur mittels AddId() gesetzt
                   werden. Es handelt sich hier um die Woerter, mit 
                   denen man den NPC ansprechen kann. Dieser sollte
                   mit dem Namen identisch sein. Wenn man den NPC
                   einmal anhand seiner ID identifizieren will, sollte
                   man eine ID angeben, die Sonderzeichen enthaelt,
                   z.B. '\n', um eine Verwechslung auzuschliessen.
                   IDs werden immer klein geschrieben. Man sollte auch
                   beachten, dass man andere Faelle einbaut, z.B.
                   Akkusativ. (Beispiel: "identifiziere wilden")

set_living_name()  Mit dieser Funktion gibt man dem NPC einen
                   living_name. Dieser Name wird bei der Funktion
                   find_living() benutzt. Diese braucht man z.B. als
                   Magier bei 'goto' oder 'trans'. Man sollte auch 
                   hier den gleichen oder einen aehnlichen Text wie
                   bei P_NAME verwenden, aber klein geschrieben.
                   Den Living-Name sollte man aber nur bei wichtigen
                   NPCs setzen, z.B. ganz harte Monster oder fuer
                   Quests wichtige, keinesfalls fuer Standard- oder
                   Massen-NPCs wie Soeldner, Soldaten, Hasen, etc.,
                   da hier Speicherplatz fuer eine globale Liste im
                   Driver verbraten wird.

create_default_npc(level)
                   Diese Funktion erzeugt einen Standard-NPC, bei
                   dem die wichtigsten Werte gesetzt sind. Bei den
                   folgenen Properties wird das jeweils angegeben.

P_LEVEL = level    Die Stufe des NPCs. Entspricht in etwa der Stufe
                   der Spieler.

P_ATTRIBUTES       Enthaelt ein Mapping mit den Attributwerten des
                   NPCs. A_INT (Intelligenz) A_STR (Staerke),
                   A_DEX (Geschicklichkeit), A_CON (Ausdauer).
                   Diese entsprechen den Werten bei Spielern.
                   Sie werden defaultmaessig auf P_LEVEL gesetzt.
                   Zu beachten ist, dass fuer das Zuecken einer
                   Waffe A_DEX einen bestimmten Wert haben muss.
                   (A_DEX+5)*10 >= WC . Mit A_DEX 15 kann man 
                   also Waffen mit WC 200 zuecken. A_STR geht auch
                   stark in die Berechnung des Schadens ein, den
                   ein NPC macht. (siehe /std/living/combat.c)
                   damage = (2*damage + 10*QueryAttribute(A_STR))/3;
                   Die Attribute kann man mittels SetAttribute setzen.

P_MAX_HP = level*level+10
                   Die Lebenspunkte des NPCs. Dies entspricht den
                   LPs eines Spielers mit A_CON=x. Die Lebenspunkte
                   kann man eventuell noch weiter hinaufsetzen, wenn
                   der NPC etwas mehr aushalten soll.

P_MAX_SP = level*level+10
                   Die Magiepunkte des NPCs. Dies entspricht den
                   MPs eines Spielers mit A_INT=x. Zur Zeit verwenden
                   NPCs ihre Magiepunkte noch nicht automatisch. Wenn
                   der NPC mit Magiepunkten zaubern soll, muss man
                   das selber programmieren.

P_HP/P_SP          Diese Werte werden auf die jeweiligen Maximalwerte
                   gesetzt.

P_HANDS = ({" mit blossen Haenden", level*10, DT_BLDUGEON })
                   Die Hands bestimmen den Angriff des NPCs, solange
                   er keine Waffe zueckt. Der erste Wert ist der 
                   Angriffstext: Der NPC greift Dich an. Das
                   Leerzeichen am Anfang ist sehr wichtig!
                   Der zweite Wert entspricht der WC einer Waffe, und
                   der dritte der Schadensart. Als Schadensart sollte
                   man eine zum NPC passende waehlen.

P_BODY = level*3
                   Der Body ist sowas wie eine natuerliche Ruestung
                   des NPCs. Bei Spielern ist der BODY auf 0, dafuer
                   tragen sie ja auch viel mehr Ruestungen als NPCs.
                   Wenn man den Body weit hoeher als 200 setzt, dann
                   kann der NPC fast nicht mehr mit normalen Waffen
                   verletzt werden, sondern nur noch mit magischen
                   Schadenstypen, z.B. Feuerball. Fuer normale Monster
                   sollte P_BODY im Bereich von 50-100 sein, damit man
                   sie mit normalen Waffen bekaempfen kann.

P_XP = P_MAX_HP*P_HANDS*5
                   Von diesen Erfahrungspunkten bekommt man 1/100,
                   wenn man den NPC toetet. Wenn der NPC zusaetzliche
                   Spells hat oder besonders gefaehrlich ist, sollte
                   man die XP entsprechend erhoehen. Ansonsten sollte
                   man sich in etwa an HP*HANDS*5 halten. Bei NPCs die
                   ein Spieler nicht killen soll, sollte man die XP 
                   auf Null setzten (z.B. der Muellschlucker im Laden).
                   Man sollte das in der Form "SetProp(P_XP, 500*100);"
                   angeben, dann sieht man sofort, wie hoch der Kill-
                   Bonus ist. Das ist uebersichtlicher als 50000.

P_RACE             Die Rasse des NPCs in Einzahl, z.B "Ork". Die Rasse
                   wird verwendet, um z.B. Waffen gegen bestimmte Gegner
                   staerker zu machen, z.B. ein Drachentoeter-Schwert.
                   Die Rasse ist auch beim Wuscheln wichtig, da man zB
                   bei einem Vogel automatisch die Federn verwuschelt,
                   bei einem Drachen die Schuppen und bei einem Pferd
                   die Maehne. Falls man die Rasse anders setzen will,
                   und trotzdem das richtige wuscheln soll, kann man
                   auch IDs mit AddId() angeben: FELL_WUSCHEL,
                   FEDERN_WUSCHEL, MAEHNE_WUSCHEL, HAARE_WUSCHEL und
                   SCHUPPEN_WUSCHEL. Siehe auch: man AddClass

P_SIZE             Die Groesse des NPCs in cm an.

P_ALIGN            Das Alignment des NPCs. Es sollte zwischen 
                   +1000 (heilig) und -1000 (satanisch) sein.
                   Der Defaultwert ist 0. Beim Kill des NPCs wird das
                   neue Alignment des Spielers so berechnet:
                   new_align=9*old_algin/10-enemy_algin/4;
                   Beim Killen von guten Mostern wird man also schlechter
                   und umgekehrt.

P_MAX_HANDS        Dieser Wert gibt an, wieviele Haende der NPC
                   hat. Dies ist vor allem wichtig fuer das
                   Benutzen von Waffe und Schild. Hier sollte
                   man den echten Wert eintragen. Menschen haben
                   2 Haende, Insekten 6, Schlangen dagegen 0.
                   Defaultwert ist 2. (Spinnen haben 8 Beine!)


3. Weitere moegliche Eigenschaften
----------------------------------

P_HEAL             Gibt an, um wieviele Punkte die Leiche des NPCs
                   beim Essen heilt. (kann auch negativ sein).
                   Bei leichten Monster sollte er immer 0 sein.

P_ARTICLE          Gibt an, ob in der Beschreibung ein Artikel
                   ausgegeben werden soll oder nicht.

P_NAME_ADJ         Adjektiv, zb "wuetend" fuer "ein wuetender Ork".
                   Hier sollte man auch zusaetzlich AddAdjective()
                   verwenden, denn dann werden die IDs automatisch
                   angepasst.

P_AGGRESSIVE       Wenn man diese Property setzt, greift der NPC
                   jeden an, der den Raum betritt, in dem er sich
                   gerade aufhaelt. Es ist aber besser, das erst
                   beim AddItem anzugeben, dann kann man den NPC
                   einmal autoattack und einmal friedlich machen.
                   Die Moeglichkeiten von P_AGGRESSIVE sind auch
                   relativ variabel, man kann auch Wahrscheinlich-
                   keiten angeben oder bestimmte Bedingungen defi-
                   nieren - naeheres ist der Hilfeseite zu dieser
                   Property zu entnehmen.

P_NOATTACK         Der Npc kann nicht angegriffen werden.
                   Hier kann man einen Text angeben, der ausgegeben
                   werden soll, wenn man es trotzdem macht. Gibt 
                   man nur 1 an, so wird " springt geschickt aus "
                   "Deiner Reichweite." ausgegeben.


4. NPCs und Interaktion mit Spielern
------------------------------------

AddInfo(,,)
                   Damit NPCs nicht ganz dumm sind, kann man ihnen
                   bestimmte Begriffe vorgeben, auf die sie dann 
                   antworten koennen. 
                   Hierbei wird der Text  automatisch
                   umgebrochen, am Anfang jeder Zeile steht dann
                   immer: ....
                    ist meist "sagt: "
                   Statt einem String kann man auch einen Array von
                   Strings ausgeben, aus dem bei Befragung des NPCs
                   zufaellig ein Element ausgewaehlt wird, das bringt
                   dann mehr Abwechslung.

AddLibrary(,,)
                   Will man die Begriffe, die NPCs kennen, extern
                   verwalten, so kann man sie in eine eigene Library
                   (Bibliothek) auslagern - dies ist eine Datei, die
                   einer bestimmten Syntax folgt. Besonders interessant
                   ist dies, wenn man alle Einwohner eines Ortes mit
                   Informationen zu diesem Ort versorgen will, aber
                   nicht jedem NPC die Hundertschar an AddInfo()'s
                   mitgeben will. Ist localflag nicht definiert, so
                   werden diese Texte auch nur an einer einzigen Stelle
                   (naemlich im Librarymaster /obj/libmaster) verwaltet
                   und benoetigen weniger Speicherplatz. Mit dem 
                   ist es zusaetzlich moeglich, einen Begriff qualitativ
                   zu bewerten und duemmere und kluegere NPCs mit der-
                   selben Bibliothek zu unterscheiden.

P_DEFAULT_INFO     Dieser Text wird augegeben, wenn der NPC keine
                   Info zu dieser Frage hat. (siehe /sys/npc/info.h)
                   Defaultwert ist: "schaut Dich fragend an.\n".
                   Man sollte diese Property am besten mit
                   AddInfo( DEFAULT_INFO,"text" ); setzen. Hier lohnt
                   sich ein Array von Strings statt einer Antwort.

P_LOG_INFO         Will man wissen, welche Fragen Spieler einem
                   NPC stellen, so kann man hier einen Filenamen
                   angeben, in dem diese Fragen mitgeloggt werden.
                   (Das sollte man nur bei wichtigen NPCs machen,
                   z.B. fuer Quest.) Das File findet man im
                   Verzeichnis /log/loginfo. Gibt man 1 an, so 
                   werden die Fragen ins rep-file des Magiers
                   geschrieben. ( /log/report/.rep )

P_REJECT           Hier kann man festlegen, wie NPCs reagieren, wenn
                   man ihnen Gegenstaende gibt. Folgenen Makros sind
                   in /sys/moving.h definiert (/std/npc/put_and_get.c)
                   REJECT_KEEP : Der Gegenstand wird behalten (standard)
                   REJECT_DROP : Der Gegenstand wird fallengelassen
                   REJECT_GIVE : Der Gegenstand wird zurueck gegeben
                   Mittels give_notify() kann man auf einzelne 
                   Gegenstande spezeille reagieren.
                   siehe /std/npc/put_and_get.c
                   
SetChats(chance, ({CHATS}) ); // P_CHAT_CHANCE, P_CHATS
                   Hier kann man angeben, ob der NPC von sich aus
                   etwas sagen soll. Dabei ist chance die prozentuelle
                   Wahrscheinlichkeit fuer jede Runde, dass der NPC
                   etwas sagt. CHATS ist ein Array mit allen moeglichen
                   Meldungen, aus denen zufaellig eine ausgewaehlt wird.

SetAttackChats(chance, ({CHATS}) ); // P_ACHAT_CHANCE, P_ACHATS
                   Dies ist das selbe wie die normalen Chats, nur
                   werden die AttackChats im Kapf ausgegeben.
                   (siehe /sys/npc/chat.h und /std/npc/chat.c )


5. Weitere Einstellungen fuer den Kampf
---------------------------------------

P_RESISTANCE       Hier koennen verschiedene Schadenstypen
                   angegeben werden, gegen die der NPC
                   resistent ist, d.h. der Schaden wird
                   halbiert. z.B.  ({DT_MAGIC})

P_VULNERABILITY    Hier kann man Schadenstypen angeben, gegen
                   die der NPC empfindlich ist, d.h. der 
                   Schaden wird verdoppelt.

P_RESISTANCE_STRENGTHS
                   In diesem Mapping kann man die Resistenz oder
                   Verwundbarkeit des NPCs gegen bestimmte
                   Schadenstypen einstellen. P_RESISTANCE und
                   P_VULNERABILITY sind im Grunde genommen nur
                   ein einfacheres Interface zu dieser Property.

P_TEMPERATURE_RANGE
                   NPCs in extremen Regionen(Polar, Wueste) sollten ihre
                   Umweltbedingungen auch aushalten, dazu einfach die
                   Temperaturwerte auf den richtigen Bereich legen.
                   Defaultwert: ([T_RANGE_MIN:0,T_RANGE_MAX:40]) 
                   
P_NOMAGIC          Hier kann man die prozentuelle Wahrscheinlichkeit
                   angeben, dass der NPC einen Spruch abwehrt.

AddSpell(chance,schaden,,,damage_type,fun);
                   Mit dieser Funktio kann man einem NPC
                   einen Spell geben, d.h. eine zusaetzliche
                   Attacke. Je hoeher chance ist, desto oefters
                   wird dieser Spell unter mehereren ausgewaehlt.
                   Schaden wird WC Einheiten angegeben.
                   string1 bekommt der betroffenen Spieler angezeigt,
                   string2 die anderen Spieler im Raum.
                   damage_typ gibt den Schadenstyp an.
                   fun ist entweder eine Funktion, die spezielle
                   Sachen machen kann oder eine Spell-Info.
                   mit ([SP_SHOW_DAMAGE:1]) bekommt der Spieler
                   eine Trefferanzeige.

P_SPELLRATE        Dieser Wert bestimmt die prozentuelle
                   Wahrscheinlichkeit, mit der der NPC einen
                   Spruch macht.

P_WIMPY            Hier kann man die Anzahl der Lebenspunkte
                   einstellen, bei denen der NPC flieht. Das
                   entspricht der Vorsicht bei Spielern.

P_DIE_MSG          Die Meldung, die der Spieler beim Tod des
                   NPCs bekommt, ( " faellt tot zu Boden.\n") 

P_NOCORPSE         Wenn man diesen Wert setzt, bleibt keine Leiche
                   zurueck. Ist z.B. sinnvoll bei Geistern.
                   Allerdings kommt dann auch keine Meldung auf
                   dem Moerderkanel.

P_MURDER_MSG       Meldung, die auf [Moerder:] erscheinen soll.
                   Ansonsten wird einen zufaellige Meldung aus
                   /std/corpse.c ausgegeben.

P_KILL_NAME        Name, mit der der NPC auf dem Todeskanal 
                   erscheint. Ansonsten wird P_NAME verwendet.

P_KILL_MSG         Diese Meldung erscheint auf [Tod:] nach
                   [Tod:]  hat gerade  umgebracht.
                   [Tod:] 

P_MSG_FLAGS        Hier kann man festlegen, ob die Ausgabe auf dem
                   Todes- oder Moerderkanal normal (0), als 'emote' (1)
                   oder als 'gemote' (2) erfolgt; 
                   zum Beispiel :  ([P_KILL_MSG:1,P_MURDER_MSG:2])
                   ( Auf dem Todeskanal ist gemote nicht moeglich. )


6. Ausruestung fuer NPCs
------------------------

Am Effektivsten nutzt man AddItem, um ein Objekt in den NPC zu packen, 
damit er nicht ganz nackt da steht.

Die Syntaxt ist hierfuer AddItem(FILENAME,METHODE);
Als FILENAME ist der Filename des Objektes (zB "/obj/misc/wuerfel")
zu verwenden.
Als Methode sind folgende drei Methoden definiert:

	CLONE_MOVE   Das Objekt wird nur in den NPC reingemoved
	CLONE_WEAR   Es wird versucht, das Objekt anzuziehen
	CLONE_WIELD  Es wird versucht, das Objekt zu zuecken

Mehr Informationen sind auf der Man-Page zu AddInfo zu finden.

7. Moving NPCs
--------------

Um einen echten Moving-NPC zu machen, muss man std/mnpc inheriten.
Dann muss man noch folgende Properties setzen:
(siehe  /sys/mnpc.h  und  /std/mnpc.c )

P_MNPC_AREA        Hier kann man das Gebiet definieren, in dem
                   der NPC herumlaufen soll. Das kann der
                   gemeinsame Teil des Dateinamens sein oder
                   ein Array von Raeumen.

P_MNPC_WAIT        Wie lange soll der NPC warten. Entweder eine
                   einfache Zahl oder drei Zahlen mit der Bedeutung:
                   ({ WaitBeforeFirstMove, WaitBeforeMove, WaitRandom })

P_MNPC_DEFAULTROOM Hier gibt man den Raum an, an den der NPC
                   zurueckkehrt, wenn er sich verlaufen hat.

P_MNPC_FLAGS       Einige Einstellungen mit folgender Bedeutung:
                    MOV_BACKWARDS: MNPC darf auch zurueck gehen
                    MOV_INDOORS: MNPC darf in geschlossene Raeume
                    MOV_OUTDOORS: MNPC darf ins Freie
                    MOV_SPECIAL: MNPC darf special exits verwenden
                    MOV_MAYLOAD: MNPC darf Raeume bei Bedarf laden
                                 (nur wenn wirklich notwendig!!)
                    MOV_MOVES: MNPC ist aktiv, muss gesetzt sein,
                               damit er sich bewegt
                    MOV_CMDS: MNPC verwendet Kommandoabfolge 
                              statt random move
                    MOV_INFIGHT: MNPC bewegt sich auch im Kampf

P_MNPC_CMDS        Hier kann man z.B. einen richtigen Weg angeben,
                   den der MNPC laeuft statt der zufaelligen Bewegung.


Nun muessen noch die Bewegungsmeldungen definiert werden:      

P_MSGIN            Meldung, wenn der NPC in den Raum kommt.
                   Default: "kommt an"

P_MSGOUT           Meldung, wenn der NPC aus dem Raum geht.
                   Default: "geht" , dahinter wird dann die
                   Richtung angehaengt, z.B. "nach Norden."

P_MMSGIN           Meldung, wenn der NPC in den Raum
                   teleportiert wird. Default :
                   "erscheint in einer Rauchwolke"

P_MMSGOUT          Meldung, wenn der NPC aus den Raum hinaus
                   teleportiert wird. Default :
                   "verschwindet mit Knall und Schwefelduft"


8. Details
----------

Genau wie in Raeumen kann man in NPCs auch Details angeben.
Smell und Sound kann man mittels P_SMELL und P_SOUND angeben.


Autor: Feyaria
Letzte Aenderung: 23. Dezember 2023, Gralkor
mud.tamedhon.de:4711 ON
mud.tamedhon.de:4712 (TLS) ON
mud.tamedhon.de:4713 (Webclient) ON