blob: d66ee26484a56a1b60b3a8150f81c5d858bb5190 [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001// MorgenGrauen MUDlib
2//
3// npc/info.c -- Behandeln von Fragen an den NPC
4//
5// $Id: info.c 9522 2016-03-01 19:20:10Z Arathorn $
6
7/* Letzte Aenderungen von Wim 8.1.99
8 *
9 * AddInfo( schluessel, antwort [, indent [, [silent [, casebased] ] ] )
10 * Wenn ein Spieler dieses Monster nach "schluessel" fragt, so gib die
11 * Programmierte Antwort aus.
12 * Erweiterung von Wim: ist silent gesetzt, so erfolgt eine "persoenliche"
13 * Antwort. d.h. umstehende Personen bekommen bei silent==1 keinen, bei
14 * stringp(silent), den String ausgegeben, dabei kann er auch die Schluessel-
15 * Worte @WER @WESSEN @WEM @WEN enthalten.
16 * - Ergaenzt um @CAP_WER... fuer zwangs-capitalisierte Namen an Satzanfaengen.
17 * ist bei fragenden NPCs und PCs mit Tarnkappe wichtig! (Silvana)
18 * - Auch in der Antwort des fragenden wird nun ersetzt (Vanion)
19 * Enthaelt casedbased einen Funktionsnamen oder verweist auf eine closure, so
20 * wird die Beantwortung der Frage von dem return-Wert abhaengig gemacht.
21 * Bei 0 wird die Frage normal beantwortet, bei 1 erfolgt die Ausgabe des
22 * unter DEFAULT_NOINFO gespeicherten Textes.
23 * Wird ein String zurueckgegeben, so wird er unter Beachtung von ident an
24 * Stelle der urspruenglichen Information ausgegeben.
25 *
26 * RemoveInfo( schluessel )
27 * Das Monster antwortet nicht mehr auf diesen Schluessel.
28 *
29 * SetProp( P_DEFAULT_INFO, antwort [, indent ] )
30 * Setze die Antwort, die das Monster auf unverstaendliche Fragen geben
31 * soll. (Diese Funktion ist obsolet! Benutze stattdessen
32 * AddInfo( "\ndefault info", antwort [, indent ] );
33 *
34 * GetInfo( [schluessel] )
35 * Wenn Schluessel gesetzt ist, so wird die dazugehoerige Info,
36 * ansonsten werden alle Infos zurueckgegeben.
37 *
38 * Die Antworten sollten wie emote - kommandos aussehen.
39 * Der optionale Indent wird zum Umbrechen von langen Infos benutzt.
40 * (Typischerweise sollte indent="sagt: " sein.)
41 *
42 * In den Infos darf mit process_string gearbeitet werden. Das Ergebnis von
43 * process_string wird dann mit umgebrochen!
44 *
45 *---------------------------------------------------------------------------
46 */
47#pragma strong_types
48#pragma save_types
49#pragma range_check
50#pragma no_clone
51#pragma pedantic
52
53#define NEED_PROTOTYPES
54#include <thing/description.h>
55#include <thing/properties.h>
56#include <npc.h>
57#undef NEED_PROTOTYPES
58
59#include <properties.h>
60#include <language.h>
61#include <defines.h>
62#include <config.h>
63#include <exploration.h>
64
65// TODO: langfristig waer hier private schoen.
66nosave mapping infos;
67
68protected void create()
69{
70 // Initialisierung nur wenn noetig, damit beim virtuellen Erben von
71 // /std/npc in npc1 und npc2 dann in npc3 beim npc1::create();
72 // npc2:create(); im zweiten create() die Infos nicht
73 // ueberschrieben/geloescht werden.
74 if (!mappingp(infos)) {
75 infos = ([
76 DEFAULT_INFO:"schaut Dich fragend an.\n";0;
77 "schaut @WEN fragend an.\n";0,
78 DEFAULT_NOINFO:"moechte Dir nicht antworten.\n";0;
79 "verweigert @WEM die Antwort.\n";1
80 ]);
81 }
82}
83
84
85void init() {
86 add_action( "frage", "frag", 1 );
87}
88
89
90static void smart_npc_log(string str)
91{
92 string creat, creat_det;
93
94 if (!stringp(creat=QueryProp(P_LOG_INFO))) {
95 creat = MASTER->creator_file(this_object());
96 if (creat == ROOTID)
97 creat = "ROOT";
98 else if( creat==BACKBONEID )
99 creat="STD";
100 creat_det="report/"+explode(creat, ".")[<1]+"_INFO.rep";
101 creat="report/"+explode(creat, ".")[<1]+".rep";
102 }
103 log_file(creat,
104 sprintf("INFO von %s [%s] (%s):\n%s\n",
105 getuid(this_interactive()),
106 explode(object_name(this_object()),"#")[0],
107 strftime("%d. %b %Y"),
108 str));
109 if (stringp(creat_det) && sizeof(creat_det))
110 log_file(creat_det,
111 sprintf("INFO von %s [%s] (%s):\n%s\n",
112 getuid(this_interactive()),
113 explode(object_name(this_object()),"#")[0],
114 strftime("%d. %b %Y"),
115 str));
116}
117
118public int frage(string str) {
119 string myname, text;
120
121 str=(extern_call()?this_player()->_unparsed_args():str);
122 if( !str || sscanf( str, "%s nach %s", myname, text ) != 2 ) {
123 _notify_fail( "WEN willst Du nach WAS fragen?\n" );
124 return 0;
125 }
126
127 if( !id( lower_case(myname) )
128 || QueryProp(P_INVIS) ) {
129 _notify_fail( "So jemanden findest Du hier nicht.\n" );
130 return 0;
131 }
132 say( capitalize(this_player()->name(WER))+" fragt " +
133 name(WEN,2)+" nach "+capitalize(text)+".\n",
134 this_player() );
135
136 text = lower_case(text);
137 GiveEP(EP_INFO, text);
138
139 return do_frage( text );
140}
141
142static string infoDefaultReplace(string pstring, object pl)
143{
144 pstring=" "+pstring;
145 if (strstr(pstring,"@WER",0) >-1 )
146 pstring= regreplace(pstring,"@WER",pl->name(WER,1),1);
147 if (strstr(pstring,"@WESSEN",0) >-1 )
148 pstring= regreplace(pstring,"@WESSEN",pl->name(WESSEN,1),1);
149 if (strstr(pstring,"@WEM",0) >-1 )
150 pstring= regreplace(pstring,"@WEM",pl->name(WEM,1),1);
151 if (strstr(pstring,"@WEN",0) >-1 )
152 pstring= regreplace(pstring,"@WEN",pl->name(WEN,1),1);
153 if (strstr(pstring,"@CAP_WER",0) >-1 )
154 pstring= regreplace(pstring,"@CAP_WER",pl->Name(WER,1),1);
155 if (strstr(pstring,"@CAP_WESSEN",0) >-1 )
156 pstring= regreplace(pstring,"@CAP_WESSEN",pl->Name(WESSEN,1),1);
157 if (strstr(pstring,"@CAP_WEM",0) >-1 )
158 pstring= regreplace(pstring,"@CAP_WEM",pl->Name(WEM,1),1);
159 if (strstr(pstring,"@CAP_WEN",0) >-1 )
160 pstring= regreplace(pstring,"@CAP_WEN",pl->Name(WEN,1),1);
161
162 return pstring[1..];
163}
164
165static mixed *GetInfoArr(string str)
166{
167 return ({ infos[str, 0], infos[str, 1], infos[str,2], infos[str, 3] });
168}
169
170public int do_frage(string text)
171{
172 string indent,answer;
173 mixed silent, preinfo, noanswer;
174 mixed *info;
175
176 if (stringp(preinfo = QueryProp(P_PRE_INFO)))
177 {
178 // Die message action wird auf "frage" fixiert, damit dies immer das
179 // gleiche ist, egal, mit welchem Verb man in diese Funktion kommt.
180 this_player()->ReceiveMsg(preinfo, MT_LISTEN, "frage",
181 Name(WER,2)+" ",this_object());
182 send_room(environment(this_object()),
183 "ist nicht gewillt, "+this_player()->Name(WEM,2)
184 +" zu antworten.",
185 MT_LISTEN, "frage",
186 Name(WER,2)+" ",
187 ({this_player()}) );
188 return 1;
189 }
190 else
191 {
192 if (intp(preinfo) && preinfo > 0)
193 return 1;
194 }
195
196 info=GetInfoArr(text);
197 if (!info[0])
198 {
199 if( this_interactive() && QueryProp(P_LOG_INFO) )
200 smart_npc_log(text);
201 text = DEFAULT_INFO;
202 info=GetInfoArr(text);
203 }
204
205 if (closurep(info[0]) ) {
206 answer=funcall(info[0]);
207 if( !answer || answer=="") return 1;
208 } else {
209 answer=process_string(info[0]);
210 }
211
212 if (closurep(info[3]) )
213 {
214 noanswer=funcall(info[3]);
215 if ( intp(noanswer) && noanswer > 0)
216 {
217 text = DEFAULT_NOINFO;
218 info = GetInfoArr(text);
219 if (closurep(info[0]) ) {
220 answer=funcall(info[0]);
221 if( !answer || answer=="") return 1;
222 } else {
223 answer=process_string(info[0]);
224 }
225 }
226 else if ( stringp(noanswer) )
227 answer = noanswer;
228 }
229
230 silent=info[2];
231
232 // Replacements gehen auch in der Antwort des NPC. Das gibt den Antworten
233 // eine persoenliche Note, und so teuer is das auch nicht :)
234 answer = infoDefaultReplace(answer, this_player());
235
236 if( indent=info[1] )
237 {
238 if (stringp(silent) || (intp(silent) && silent > 0) )
239 { // Persoenliche Antwort mit indent
240 this_player()->ReceiveMsg(answer, MT_LISTEN|MSG_BS_LEAVE_LFS,
241 "frage",
242 Name(WER,2)+" "+indent,
243 this_object());
244 if (stringp(silent))
245 {
246 silent=infoDefaultReplace(silent, this_player());
247 send_room(environment(), silent, MT_LISTEN, "frage",
248 Name(WER,2)+" ", ({this_player()}));
249 }
250 }
251 else // "normale Antwort" mit Indent
252 {
253 send_room(environment(), answer, MT_LISTEN|MSG_BS_LEAVE_LFS,
254 "frage",
255 Name(WER,2)+" "+indent, ({this_object()}));
256 }
257 }
258 else
259 {
260 if (stringp(silent) || (intp(silent) && silent > 0) )
261 { // Persoenliche Antwort ohne indent
262 this_player()->ReceiveMsg(answer, MT_LISTEN|MSG_DONT_WRAP,
263 "frage",
264 Name(WER,2)+" ",
265 this_object());
266 if (stringp(silent))
267 {
268 silent=infoDefaultReplace(silent, this_player());
269 send_room(environment(), silent, MT_LISTEN, "frage",
270 Name(WER,2)+" ", ({this_player()}) );
271 }
272 }
273 else // "normale Antwort" ohne Indent
274 send_room(environment(), answer, MT_LISTEN|MSG_DONT_WRAP,
275 "frage", Name(WER,2)+" ");
276 }
277 return 1;
278}
279
280/*
281 *---------------------------------------------------------------------------
282 * Setzen von Infos
283 *---------------------------------------------------------------------------
284 */
285
286public varargs void AddInfo(mixed key, mixed info, string indent,
287 mixed silent, mixed casebased ) {
288
289 if (stringp(casebased))
290 casebased=symbol_function(casebased,this_object());
291
292 if( pointerp( key ) ) {
293 int i;
294 for ( i=sizeof( key )-1; i>=0; i-- )
295 infos += ([ key[i]: info; indent; silent; casebased ]);
296 }
297 else
298 infos += ([ key: info; indent; silent; casebased ]);
299}
300
301public varargs void AddSpecialInfo(mixed keys, string functionname,
302 string indent, mixed silent, mixed casebased )
303{
304 int i;
305 closure cl;
306
307 if(!(cl=symbol_function(functionname,this_object()))) return;
308 return AddInfo(keys,cl,indent,silent,casebased);
309}
310
311
312public void RemoveInfo( string key )
313{
314 m_delete(infos,key);
315}
316
317static varargs void _set_default_info( mixed info )
318{
319 if (pointerp(info))
320 apply(#'AddInfo/*'*/,DEFAULT_INFO,info);
321 else
322 AddInfo(DEFAULT_INFO,info);
323}
324
325public varargs mixed GetInfo(string str)
326{
327 if (!str) return deep_copy(infos);
328 return infos[str];
329}
330
331
332static mapping _query_npc_info()
333{
334 return deep_copy(infos);
335}
336
337
338static mapping _set_npc_info( mapping map_ldfied )
339{
340 if ( !mappingp(map_ldfied) )
341 return 0;
342
343 return infos = map_ldfied;
344}
345