blob: 4802a1b93abf1ea76d2204b5518439e22b1b36cc [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001// MorgenGrauen MUDlib
2//
3// living/description.c -- description for living objects
4//
5// $Id: description.c 9395 2015-12-08 23:04:38Z Zesstra $
6#pragma strong_types
7#pragma save_types
8#pragma range_check
9#pragma no_clone
10#pragma pedantic
11
12inherit "/std/container/description";
13
14#define NEED_PROTOTYPES
15
16#include <living/skills.h>
17#include <living/clothing.h>
18#include <thing/properties.h>
19#include <wizlevels.h>
20#include <new_skills.h>
21#include <properties.h>
22#include <language.h>
23#include <defines.h>
24#include <class.h>
25#include <sys_debug.h>
26
Christian Georg Beckerea699e22017-06-16 23:48:17 +020027#define XL_DURATION "xlduration"
28#define XL_LOOKSTR "xllook"
29#define XL_FUN "xlfun"
30#define XL_ENDMSG "xlende"
31#define XL_ENDFUN "xlendefun"
32#define XL_OBJNAME "xlobjectname"
33
MG Mud User88f12472016-06-24 23:31:02 +020034public string _query_internal_extralook() {
35 mixed xl;
36 int zeit;
37 string res, look="";
38
39 xl=Query(P_INTERNAL_EXTRA_LOOK,F_VALUE);
40 if (!mappingp(xl))
41 return(0);
42
43 foreach(string key, mapping xld: xl) {
Christian Georg Beckerea699e22017-06-16 23:48:17 +020044 if (intp(zeit=xld[XL_DURATION])) {
MG Mud User88f12472016-06-24 23:31:02 +020045 //hat offenbar nen Ablaufdatum
46 if ( (zeit > 0 && zeit < time()) ||
47 (zeit < 0 && abs(zeit) < object_time(ME)) ) {
48 // Zeit abgelaufen oder
49 // negative "Ablaufzeit" und das Objekt ist neuer als die
50 // Eintragzeit, also loeschen und weiter (ja, das geht. ;-) und xld
51 // hat das Eintragsmapping ja noch, weitere Benutzung also moeglich.)
52 m_delete(xl,key);
53 // ggf. Meldung ausgeben
54 if (interactive(ME)) {
Christian Georg Beckerea699e22017-06-16 23:48:17 +020055 if (sizeof(xld[XL_ENDMSG])) {
56 tell_object(ME,xld[XL_ENDMSG]);
MG Mud User88f12472016-06-24 23:31:02 +020057 }
58 //kein einfacher String, aber Objekt+Funktion gegeben?
Christian Georg Beckerea699e22017-06-16 23:48:17 +020059 else if (sizeof(xld[XL_ENDFUN]) && sizeof(xld[XL_OBJNAME]) &&
60 (!catch(res=call_other(xld[XL_OBJNAME],xld[XL_ENDFUN],ME)
MG Mud User88f12472016-06-24 23:31:02 +020061 ;publish))) {
62 if (stringp(res) && sizeof(res))
63 tell_object(ME,res);
64 }
65 }
66 continue;
67 }
68 }
69 // Der Eintrag ist offenbar noch gueltig, Meldung anhaengen, bzw. via
70 // Funktionsaufruf beschaffen.
Christian Georg Beckerea699e22017-06-16 23:48:17 +020071 if (sizeof(xld[XL_LOOKSTR]))
72 look+=xld[XL_LOOKSTR];
73 else if (sizeof(xld[XL_FUN]) && sizeof(xld[XL_OBJNAME])) {
MG Mud User88f12472016-06-24 23:31:02 +020074 closure cl;
Christian Georg Beckerea699e22017-06-16 23:48:17 +020075 if (catch(cl=symbol_function(xld[XL_FUN],xld[XL_OBJNAME]);publish)
MG Mud User88f12472016-06-24 23:31:02 +020076 || !cl) {
77 // wenn Fehler beim Laden/Closure erstellen, dann Eintrag loeschen
78 // -> Annahme, dass dieser Fehler permanent sein wird, z.B. Eintrag
79 // von Clonen
80 m_delete(xl,key);
81 continue;
82 }
83 else if (!catch(res=funcall(cl, ME); publish)) {
84 if (!stringp(res) || !sizeof(res)) {
85 // keinen String oder leeren String gekriegt -> ueberspringen.
86 continue;
87 }
88 else
89 look+=res;
90 }
91 }
92 }
93 // fertig. Wenn look nicht leer ist, zurueckgeben, sonst 0.
94 if (sizeof(look))
95 return(look);
96 else
97 return(0);
98}
99
Christian Georg Beckerea699e22017-06-16 23:48:17 +0200100
MG Mud User88f12472016-06-24 23:31:02 +0200101public varargs int AddExtraLook(string look, int duration, string key,
102 string lookende, object ob) {
103 mapping xl;
104 string oname;
105 if (!stringp(key) || !sizeof(key)) {
106 // Automatisch erzeugen, wenn moeglich
107 if (!objectp(previous_object()) ||
108 !stringp(key=object_name(previous_object())) || !sizeof(key))
Christian Georg Beckerea699e22017-06-16 23:48:17 +0200109 return XL_NOKEY;
MG Mud User88f12472016-06-24 23:31:02 +0200110 }
111
112 if (!stringp(look) || !sizeof(look))
Christian Georg Beckerea699e22017-06-16 23:48:17 +0200113 return XL_INVALIDEXTRALOOK;
MG Mud User88f12472016-06-24 23:31:02 +0200114 if (!intp(duration))
Christian Georg Beckerea699e22017-06-16 23:48:17 +0200115 return XL_INVALIDDURATION;;
MG Mud User88f12472016-06-24 23:31:02 +0200116
117 xl=Query(P_INTERNAL_EXTRA_LOOK,F_VALUE); // dran denken: liefert referenz zurueck
118 if (!mappingp(xl)) {
Christian Georg Beckerea699e22017-06-16 23:48:17 +0200119 Set(P_INTERNAL_EXTRA_LOOK, xl=([]));
MG Mud User88f12472016-06-24 23:31:02 +0200120 }
121
122 // kein Automatisches Ueberschreiben.
123 if (member(xl,key))
Christian Georg Beckerea699e22017-06-16 23:48:17 +0200124 return XL_KEYEXISTS;
MG Mud User88f12472016-06-24 23:31:02 +0200125
126 // neg. Werte: "bis Ende/reboot", abs(duration) == Eintragzeit
127 // 0: "fuer ewig", >0: Zeitdauer in Sekunden
128 if (duration > 0)
129 duration+=time(); // hoffentlich gibt es reichtzeitig 64bit-Ints
130 else if (duration < 0)
131 duration=negate(time());
132 // 0 bleibt, wie es ist.
133
134 if (objectp(ob)) {
135 // Funktionsname und Objektname (als Name, damit es auch noch geht, wenn
136 // das Objekt entladen wurde, Crash/reboot war etc.) speichern
137 // Clone werden auch gespeichert, aber es wird direkt ein harter Fehler
138 // ausgeloest, wenn ein permanenter Xlook fuer einen Clone registriert
139 // werden soll: das kann nicht gehen.
140 if (!duration && clonep(ob))
141 raise_error(sprintf(
142 "AddExtraLook(): Fehlerhaftes Argument <duration>: %d, "
143 "permanente Extralooks durch Clone (%s) nicht registrierbar.\n",
144 duration, object_name(ob)));
145
Christian Georg Beckerea699e22017-06-16 23:48:17 +0200146 xl[key]=([XL_OBJNAME:object_name(ob),
147 XL_FUN: look,
MG Mud User88f12472016-06-24 23:31:02 +0200148 ]);
149 // ggf. Name der Funktion speichern, die bei Ablauf aufgerufen wird.
150 if (stringp(lookende) && sizeof(lookende))
Christian Georg Beckerea699e22017-06-16 23:48:17 +0200151 xl[key][XL_ENDFUN]=lookende;
MG Mud User88f12472016-06-24 23:31:02 +0200152 }
153 else {
154 // Einfacher Eintrag, nur den bearbeiteten String merken. ;-)
Christian Georg Beckerea699e22017-06-16 23:48:17 +0200155 xl[key]=([XL_LOOKSTR: break_string(replace_personal(look,({ME}),1),78,
MG Mud User88f12472016-06-24 23:31:02 +0200156 "",BS_LEAVE_MY_LFS),
157 ]);
158 // ggf. Meldung speichern, die bei Ablauf ausgegeben werden soll.
159 if (stringp(lookende) && sizeof(lookende)) {
Christian Georg Beckerea699e22017-06-16 23:48:17 +0200160 xl[key][XL_ENDMSG]=break_string(replace_personal(lookende,({ME}),1),78,
MG Mud User88f12472016-06-24 23:31:02 +0200161 "",BS_LEAVE_MY_LFS);
162 }
163 }
164 // Endezeit vermerken.
165 if (duration != 0)
Christian Georg Beckerea699e22017-06-16 23:48:17 +0200166 xl[key][XL_DURATION]=duration;
MG Mud User88f12472016-06-24 23:31:02 +0200167
168 // Kein Set noetig, weil Query das Mapping ja als Referenz lieferte.
Christian Georg Beckerea699e22017-06-16 23:48:17 +0200169 return XL_OK;
MG Mud User88f12472016-06-24 23:31:02 +0200170}
171
172public int RemoveExtraLook(string key) {
173 mapping xl;
174 if (!stringp(key) || !sizeof(key)) {
175 // Automatisch erzeugen, wenn moeglich
176 if (!objectp(previous_object()) ||
177 !stringp(key=object_name(previous_object())) || !sizeof(key))
Christian Georg Beckerea699e22017-06-16 23:48:17 +0200178 return XL_NOKEY;
MG Mud User88f12472016-06-24 23:31:02 +0200179 }
180 xl=Query(P_INTERNAL_EXTRA_LOOK,F_VALUE); // dran denken: liefert referenz zurueck
181 if (!mappingp(xl))
Christian Georg Beckerea699e22017-06-16 23:48:17 +0200182 return XL_KEYDOESNOTEXIST;
MG Mud User88f12472016-06-24 23:31:02 +0200183 if (!member(xl,key))
Christian Georg Beckerea699e22017-06-16 23:48:17 +0200184 return XL_KEYDOESNOTEXIST;
MG Mud User88f12472016-06-24 23:31:02 +0200185
186 m_delete(xl,key);
187 // Kein Set noetig, weil Query das Mapping ja als Referenz lieferte.
Christian Georg Beckerea699e22017-06-16 23:48:17 +0200188 return XL_OK;
MG Mud User88f12472016-06-24 23:31:02 +0200189}
190
Arathorn65a38202019-08-28 19:21:26 +0200191// Ist ein bestimmter, nicht bereits abgelaufener Eintrag in den
192// Extralooks vorhanden?
193public int HasExtraLook(string key) {
194 // abgelaufene Extralooks austragen
195 QueryProp(P_INTERNAL_EXTRA_LOOK);
196 return member(Query(P_INTERNAL_EXTRA_LOOK) || ([]), key);
197}
198
MG Mud User88f12472016-06-24 23:31:02 +0200199void create()
200{
201 ::create();
202 Set(P_GENDER, SAVE, F_MODE);
203 // Extralook-Property speichern und vor manueller Aenderung schuetzen
204 // EMs duerfen, die wissen hoffentlich, was sie tun.
205 Set(P_INTERNAL_EXTRA_LOOK, SAVE|PROTECTED, F_MODE_AS);
Bugfix5a9775f2017-02-17 13:48:56 +0100206 SetProp(P_EXTRA_LOOK_OBS,({}));
207 Set(P_EXTRA_LOOK, PROTECTED, F_MODE_AS);
MG Mud User88f12472016-06-24 23:31:02 +0200208 SetProp(P_CLOTHING,({}));
209 AddId("Living");
210}
211
212string condition()
213{
214 int hpnt, max_hpnt, perc;
215
216 hpnt = QueryProp( P_HP );
217 max_hpnt = QueryProp( P_MAX_HP );
218
219 if(max_hpnt>0 && hpnt>0)
220 perc=100*hpnt/max_hpnt;
221
222 switch(perc) {
223 case 0..9:
224 return capitalize(QueryPronoun(WER))+" steht auf der Schwelle des Todes.\n";
225 case 10..19:
226 return capitalize(QueryPronoun(WER))+" braucht dringend einen Arzt.\n";
227 case 20..29:
228 return capitalize(QueryPronoun(WER))+" ist in keiner guten Verfassung.\n";
229 case 30..39:
230 return capitalize(QueryPronoun(WER))+" wankt bereits bedenklich.\n";
231 case 40..49:
232 return capitalize(QueryPronoun(WER))+" macht einen mitgenommenen Eindruck.\n";
233 case 50..59:
234 return capitalize(QueryPronoun(WER))+" sieht nicht mehr taufrisch aus.\n";
235 case 60..69:
236 return capitalize(QueryPronoun(WER))+" ist leicht angeschlagen.\n";
237 case 70..79:
238 return capitalize(QueryPronoun(WER))+" fuehlte sich heute schon besser.\n";
239 case 80..89:
240 return capitalize(QueryPronoun(WER))+" ist schon etwas geschwaecht.\n";
241 }
242 //fall-through
243 return capitalize(QueryPronoun(WER))+" ist absolut fit.\n";
244}
245
246varargs string long() {
247 string str, cap_pronoun;
248 string descr, invl,tmp,exl;
249 int hpnt, max_hpnt;
250 mixed filter_ldfied;
251 object ob;
252
253 str = process_string( QueryProp(P_LONG) );
254 if(!stringp(str)) str = "";
255
256 str += condition();
257
258 // Extralook
259 if(stringp(tmp = QueryProp(P_EXTRA_LOOK)))
260 str += tmp;
261 if (stringp(tmp = QueryProp(P_INTERNAL_EXTRA_LOOK)))
262 str += tmp;
Bugfix5a9775f2017-02-17 13:48:56 +0100263 foreach(ob : QueryProp(P_EXTRA_LOOK_OBS))
264 {
265 if(objectp(ob) && environment(ob)==ME)
266 {
Bugfix7a9961f2017-02-28 10:37:55 +0100267 exl=ob->QueryProp(P_EXTRA_LOOK);
268 if(stringp(exl) && sizeof(exl))
Bugfix5a9775f2017-02-17 13:48:56 +0100269 {
Zesstrab6a6eab2017-02-27 21:39:29 +0100270 exl=replace_personal(exl, ({ME}), 1);
Bugfix967926a2017-02-27 16:51:10 +0100271 // Ist das letzte Zeichen kein \n, brechen wir um.
272 if(exl[<1]!='\n')
273 {
274 exl=break_string(exl,78);
275 }
Bugfix5a9775f2017-02-17 13:48:56 +0100276 str += exl;
277 }
278 else if(stringp(exl = ob->extra_look()))
279 {
280 str += exl; // TO BE REMOVED
281 }
282 }
283 else
284 {
285 // Bereinigen
286 SetProp(P_EXTRA_LOOK_OBS,QueryProp(P_EXTRA_LOOK_OBS)-({ob}));
287 }
288 }
MG Mud User88f12472016-06-24 23:31:02 +0200289
290 if(filter_ldfied = QueryProp(P_TRANSPARENT))
291 {
292 invl = make_invlist(PL, all_inventory(ME));
293 if(invl != "")
294 str += capitalize(QueryPronoun(WER))+" traegt bei sich:\n" + invl;
295 }
296 return str;
297}
298
299varargs string name(int casus, int demonst)
300{
301 if( QueryProp( P_INVIS ) )
302 {
303 if( casus == RAW ) return "Jemand";
304 return ({"Jemand","Jemands","Jemandem","Jemanden"})[casus];
305 }
306 if (QueryProp(P_FROG) && casus != RAW )
307 {
308 string s=QueryArticle(casus, 0, 1)+"Frosch";
309 if (casus==WESSEN) s += "es";
310 return s;
311 }
312 return ::name( casus, demonst );
313}
314
315static int _query_gender()
316{
317 if (QueryProp(P_FROG)) return 1;
318 return Query(P_GENDER);
319}
320
321// NPC sollen aus Kompatibilitaetsgruenden auch eine "echte" Rasse haben.
322// Default ist hier die Rasse, man kann aber hiermit auch einen NPC faken,
323// der sich tarnt, indem man P_REAL_RACE per Hand setzt.
324static string _query_real_race()
325{
326 return Query(P_REAL_RACE,F_VALUE)||QueryProp(P_RACE);
327}
328
Zesstra0d1bd1d2019-11-23 10:19:15 +0100329static <string|string*> _set_name(<string|string*> nm )
MG Mud User88f12472016-06-24 23:31:02 +0200330{
331 string lvnam;
Zesstra0d1bd1d2019-11-23 10:19:15 +0100332 if (pointerp(nm))
333 lvnam = nm[WER];
334 else
335 lvnam = nm;
MG Mud User88f12472016-06-24 23:31:02 +0200336 set_living_name(lower_case(lvnam));
Zesstra0d1bd1d2019-11-23 10:19:15 +0100337 return Set(P_NAME, nm, F_VALUE);
MG Mud User88f12472016-06-24 23:31:02 +0200338}
339
340int _query_container()
341{
342 return 0;
343}
344
Zesstra0d1bd1d2019-11-23 10:19:15 +0100345int is_class_member(<string|string*> str) {
MG Mud User88f12472016-06-24 23:31:02 +0200346 // Keine Klasse, keine Mitgliedschaft ...
347 if (!str || (!stringp(str) && !pointerp(str)) || str=="")
348 return 0;
349
350 if (::is_class_member(str))
351 return 1;
352
353 if (stringp(str))
354 str = ({str});
355
356 // Rassen werden als implizite Klassen aufgefasst.
357 // TODO: Pruefen, ob das unbedingt hart-kodiert sein muss.
358 string race = QueryProp(P_RACE);
359 if ( stringp(race) && member( str, lower_case(race) ) > -1 )
360 return 1;
361 else
362 return 0;
363}
364
365mapping _query_material() {
366 mixed res;
367
368 if (mappingp(res=Query(P_MATERIAL)))
369 return res;
370 return ([MAT_MISC_LIVING:100]);
371}
372
Bugfix5a9775f2017-02-17 13:48:56 +0100373public void NotifyInsert(object ob, object oldenv)
374{
Dominik Schäfer5bfa1282017-02-27 11:40:40 +0100375 // Unterstuetzung dyn. Querymethoden (z.B. bei Kleidung, welche nur in
376 // getragenem Zustand nen Extralook hat).
377 if(stringp(ob->QueryProp(P_EXTRA_LOOK))
378 || ob->Query(P_EXTRA_LOOK, F_QUERY_METHOD))
Bugfix5a9775f2017-02-17 13:48:56 +0100379 {
380 SetProp(P_EXTRA_LOOK_OBS,QueryProp(P_EXTRA_LOOK_OBS)+({ob}));
381 }
Dominik Schäfer5bfa1282017-02-27 11:40:40 +0100382
Bugfix5a9775f2017-02-17 13:48:56 +0100383 // Muss leider auch beachtet werden, sollte aber mal raus fliegen ...
384 if(function_exists("extra_look",ob))
385 {
386 SetProp(P_EXTRA_LOOK_OBS,QueryProp(P_EXTRA_LOOK_OBS)+({ob}));
387 catch(raise_error(
388 "Obsolete lfun extra_look() in "+load_name(ob));
389 publish);
390 }
391}
392
393public void NotifyLeave(object ob, object dest)
394{
395 object *els=QueryProp(P_EXTRA_LOOK_OBS);
396 if(member(els,ob)!=-1)
397 {
Zesstrab716ff82017-02-27 10:31:49 +0100398 SetProp(P_EXTRA_LOOK_OBS, els-({ob}) );
Bugfix5a9775f2017-02-17 13:48:56 +0100399 }
400}