blob: 113f3c458be047411cf0275fc95aa5f0591b86aa [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
MG Mud User88f12472016-06-24 23:31:02 +020010
11inherit "/std/container/description";
12
13#define NEED_PROTOTYPES
14
15#include <living/skills.h>
16#include <living/clothing.h>
17#include <thing/properties.h>
18#include <wizlevels.h>
19#include <new_skills.h>
20#include <properties.h>
21#include <language.h>
22#include <defines.h>
23#include <class.h>
24#include <sys_debug.h>
25
Christian Georg Beckerea699e22017-06-16 23:48:17 +020026#define XL_DURATION "xlduration"
27#define XL_LOOKSTR "xllook"
28#define XL_FUN "xlfun"
29#define XL_ENDMSG "xlende"
30#define XL_ENDFUN "xlendefun"
31#define XL_OBJNAME "xlobjectname"
32
MG Mud User88f12472016-06-24 23:31:02 +020033public string _query_internal_extralook() {
34 mixed xl;
35 int zeit;
36 string res, look="";
37
38 xl=Query(P_INTERNAL_EXTRA_LOOK,F_VALUE);
39 if (!mappingp(xl))
40 return(0);
41
42 foreach(string key, mapping xld: xl) {
Christian Georg Beckerea699e22017-06-16 23:48:17 +020043 if (intp(zeit=xld[XL_DURATION])) {
MG Mud User88f12472016-06-24 23:31:02 +020044 //hat offenbar nen Ablaufdatum
45 if ( (zeit > 0 && zeit < time()) ||
46 (zeit < 0 && abs(zeit) < object_time(ME)) ) {
47 // Zeit abgelaufen oder
48 // negative "Ablaufzeit" und das Objekt ist neuer als die
49 // Eintragzeit, also loeschen und weiter (ja, das geht. ;-) und xld
50 // hat das Eintragsmapping ja noch, weitere Benutzung also moeglich.)
51 m_delete(xl,key);
52 // ggf. Meldung ausgeben
53 if (interactive(ME)) {
Christian Georg Beckerea699e22017-06-16 23:48:17 +020054 if (sizeof(xld[XL_ENDMSG])) {
55 tell_object(ME,xld[XL_ENDMSG]);
MG Mud User88f12472016-06-24 23:31:02 +020056 }
57 //kein einfacher String, aber Objekt+Funktion gegeben?
Christian Georg Beckerea699e22017-06-16 23:48:17 +020058 else if (sizeof(xld[XL_ENDFUN]) && sizeof(xld[XL_OBJNAME]) &&
59 (!catch(res=call_other(xld[XL_OBJNAME],xld[XL_ENDFUN],ME)
MG Mud User88f12472016-06-24 23:31:02 +020060 ;publish))) {
61 if (stringp(res) && sizeof(res))
62 tell_object(ME,res);
63 }
64 }
65 continue;
66 }
67 }
68 // Der Eintrag ist offenbar noch gueltig, Meldung anhaengen, bzw. via
69 // Funktionsaufruf beschaffen.
Christian Georg Beckerea699e22017-06-16 23:48:17 +020070 if (sizeof(xld[XL_LOOKSTR]))
71 look+=xld[XL_LOOKSTR];
72 else if (sizeof(xld[XL_FUN]) && sizeof(xld[XL_OBJNAME])) {
MG Mud User88f12472016-06-24 23:31:02 +020073 closure cl;
Christian Georg Beckerea699e22017-06-16 23:48:17 +020074 if (catch(cl=symbol_function(xld[XL_FUN],xld[XL_OBJNAME]);publish)
MG Mud User88f12472016-06-24 23:31:02 +020075 || !cl) {
76 // wenn Fehler beim Laden/Closure erstellen, dann Eintrag loeschen
77 // -> Annahme, dass dieser Fehler permanent sein wird, z.B. Eintrag
78 // von Clonen
79 m_delete(xl,key);
80 continue;
81 }
82 else if (!catch(res=funcall(cl, ME); publish)) {
83 if (!stringp(res) || !sizeof(res)) {
84 // keinen String oder leeren String gekriegt -> ueberspringen.
85 continue;
86 }
87 else
88 look+=res;
89 }
90 }
91 }
92 // fertig. Wenn look nicht leer ist, zurueckgeben, sonst 0.
93 if (sizeof(look))
94 return(look);
95 else
96 return(0);
97}
98
Christian Georg Beckerea699e22017-06-16 23:48:17 +020099
MG Mud User88f12472016-06-24 23:31:02 +0200100public varargs int AddExtraLook(string look, int duration, string key,
101 string lookende, object ob) {
102 mapping xl;
103 string oname;
104 if (!stringp(key) || !sizeof(key)) {
105 // Automatisch erzeugen, wenn moeglich
106 if (!objectp(previous_object()) ||
107 !stringp(key=object_name(previous_object())) || !sizeof(key))
Christian Georg Beckerea699e22017-06-16 23:48:17 +0200108 return XL_NOKEY;
MG Mud User88f12472016-06-24 23:31:02 +0200109 }
110
111 if (!stringp(look) || !sizeof(look))
Christian Georg Beckerea699e22017-06-16 23:48:17 +0200112 return XL_INVALIDEXTRALOOK;
MG Mud User88f12472016-06-24 23:31:02 +0200113 if (!intp(duration))
Christian Georg Beckerea699e22017-06-16 23:48:17 +0200114 return XL_INVALIDDURATION;;
MG Mud User88f12472016-06-24 23:31:02 +0200115
116 xl=Query(P_INTERNAL_EXTRA_LOOK,F_VALUE); // dran denken: liefert referenz zurueck
117 if (!mappingp(xl)) {
Christian Georg Beckerea699e22017-06-16 23:48:17 +0200118 Set(P_INTERNAL_EXTRA_LOOK, xl=([]));
MG Mud User88f12472016-06-24 23:31:02 +0200119 }
120
121 // kein Automatisches Ueberschreiben.
122 if (member(xl,key))
Christian Georg Beckerea699e22017-06-16 23:48:17 +0200123 return XL_KEYEXISTS;
MG Mud User88f12472016-06-24 23:31:02 +0200124
125 // neg. Werte: "bis Ende/reboot", abs(duration) == Eintragzeit
126 // 0: "fuer ewig", >0: Zeitdauer in Sekunden
127 if (duration > 0)
128 duration+=time(); // hoffentlich gibt es reichtzeitig 64bit-Ints
129 else if (duration < 0)
130 duration=negate(time());
131 // 0 bleibt, wie es ist.
132
133 if (objectp(ob)) {
134 // Funktionsname und Objektname (als Name, damit es auch noch geht, wenn
135 // das Objekt entladen wurde, Crash/reboot war etc.) speichern
136 // Clone werden auch gespeichert, aber es wird direkt ein harter Fehler
137 // ausgeloest, wenn ein permanenter Xlook fuer einen Clone registriert
138 // werden soll: das kann nicht gehen.
139 if (!duration && clonep(ob))
140 raise_error(sprintf(
141 "AddExtraLook(): Fehlerhaftes Argument <duration>: %d, "
142 "permanente Extralooks durch Clone (%s) nicht registrierbar.\n",
143 duration, object_name(ob)));
144
Christian Georg Beckerea699e22017-06-16 23:48:17 +0200145 xl[key]=([XL_OBJNAME:object_name(ob),
146 XL_FUN: look,
MG Mud User88f12472016-06-24 23:31:02 +0200147 ]);
148 // ggf. Name der Funktion speichern, die bei Ablauf aufgerufen wird.
149 if (stringp(lookende) && sizeof(lookende))
Christian Georg Beckerea699e22017-06-16 23:48:17 +0200150 xl[key][XL_ENDFUN]=lookende;
MG Mud User88f12472016-06-24 23:31:02 +0200151 }
152 else {
153 // Einfacher Eintrag, nur den bearbeiteten String merken. ;-)
Christian Georg Beckerea699e22017-06-16 23:48:17 +0200154 xl[key]=([XL_LOOKSTR: break_string(replace_personal(look,({ME}),1),78,
MG Mud User88f12472016-06-24 23:31:02 +0200155 "",BS_LEAVE_MY_LFS),
156 ]);
157 // ggf. Meldung speichern, die bei Ablauf ausgegeben werden soll.
158 if (stringp(lookende) && sizeof(lookende)) {
Christian Georg Beckerea699e22017-06-16 23:48:17 +0200159 xl[key][XL_ENDMSG]=break_string(replace_personal(lookende,({ME}),1),78,
MG Mud User88f12472016-06-24 23:31:02 +0200160 "",BS_LEAVE_MY_LFS);
161 }
162 }
163 // Endezeit vermerken.
164 if (duration != 0)
Christian Georg Beckerea699e22017-06-16 23:48:17 +0200165 xl[key][XL_DURATION]=duration;
MG Mud User88f12472016-06-24 23:31:02 +0200166
167 // Kein Set noetig, weil Query das Mapping ja als Referenz lieferte.
Christian Georg Beckerea699e22017-06-16 23:48:17 +0200168 return XL_OK;
MG Mud User88f12472016-06-24 23:31:02 +0200169}
170
171public int RemoveExtraLook(string key) {
172 mapping xl;
173 if (!stringp(key) || !sizeof(key)) {
174 // Automatisch erzeugen, wenn moeglich
175 if (!objectp(previous_object()) ||
176 !stringp(key=object_name(previous_object())) || !sizeof(key))
Christian Georg Beckerea699e22017-06-16 23:48:17 +0200177 return XL_NOKEY;
MG Mud User88f12472016-06-24 23:31:02 +0200178 }
179 xl=Query(P_INTERNAL_EXTRA_LOOK,F_VALUE); // dran denken: liefert referenz zurueck
180 if (!mappingp(xl))
Christian Georg Beckerea699e22017-06-16 23:48:17 +0200181 return XL_KEYDOESNOTEXIST;
MG Mud User88f12472016-06-24 23:31:02 +0200182 if (!member(xl,key))
Christian Georg Beckerea699e22017-06-16 23:48:17 +0200183 return XL_KEYDOESNOTEXIST;
MG Mud User88f12472016-06-24 23:31:02 +0200184
185 m_delete(xl,key);
186 // Kein Set noetig, weil Query das Mapping ja als Referenz lieferte.
Christian Georg Beckerea699e22017-06-16 23:48:17 +0200187 return XL_OK;
MG Mud User88f12472016-06-24 23:31:02 +0200188}
189
Arathorn65a38202019-08-28 19:21:26 +0200190// Ist ein bestimmter, nicht bereits abgelaufener Eintrag in den
191// Extralooks vorhanden?
192public int HasExtraLook(string key) {
193 // abgelaufene Extralooks austragen
194 QueryProp(P_INTERNAL_EXTRA_LOOK);
195 return member(Query(P_INTERNAL_EXTRA_LOOK) || ([]), key);
196}
197
MG Mud User88f12472016-06-24 23:31:02 +0200198void create()
199{
200 ::create();
201 Set(P_GENDER, SAVE, F_MODE);
202 // Extralook-Property speichern und vor manueller Aenderung schuetzen
203 // EMs duerfen, die wissen hoffentlich, was sie tun.
204 Set(P_INTERNAL_EXTRA_LOOK, SAVE|PROTECTED, F_MODE_AS);
Bugfix5a9775f2017-02-17 13:48:56 +0100205 SetProp(P_EXTRA_LOOK_OBS,({}));
206 Set(P_EXTRA_LOOK, PROTECTED, F_MODE_AS);
MG Mud User88f12472016-06-24 23:31:02 +0200207 SetProp(P_CLOTHING,({}));
208 AddId("Living");
209}
210
211string condition()
212{
213 int hpnt, max_hpnt, perc;
214
215 hpnt = QueryProp( P_HP );
216 max_hpnt = QueryProp( P_MAX_HP );
217
218 if(max_hpnt>0 && hpnt>0)
219 perc=100*hpnt/max_hpnt;
220
221 switch(perc) {
222 case 0..9:
223 return capitalize(QueryPronoun(WER))+" steht auf der Schwelle des Todes.\n";
224 case 10..19:
225 return capitalize(QueryPronoun(WER))+" braucht dringend einen Arzt.\n";
226 case 20..29:
227 return capitalize(QueryPronoun(WER))+" ist in keiner guten Verfassung.\n";
228 case 30..39:
229 return capitalize(QueryPronoun(WER))+" wankt bereits bedenklich.\n";
230 case 40..49:
231 return capitalize(QueryPronoun(WER))+" macht einen mitgenommenen Eindruck.\n";
232 case 50..59:
233 return capitalize(QueryPronoun(WER))+" sieht nicht mehr taufrisch aus.\n";
234 case 60..69:
235 return capitalize(QueryPronoun(WER))+" ist leicht angeschlagen.\n";
236 case 70..79:
237 return capitalize(QueryPronoun(WER))+" fuehlte sich heute schon besser.\n";
238 case 80..89:
239 return capitalize(QueryPronoun(WER))+" ist schon etwas geschwaecht.\n";
240 }
241 //fall-through
242 return capitalize(QueryPronoun(WER))+" ist absolut fit.\n";
243}
244
245varargs string long() {
246 string str, cap_pronoun;
247 string descr, invl,tmp,exl;
248 int hpnt, max_hpnt;
249 mixed filter_ldfied;
250 object ob;
251
252 str = process_string( QueryProp(P_LONG) );
253 if(!stringp(str)) str = "";
254
255 str += condition();
256
257 // Extralook
258 if(stringp(tmp = QueryProp(P_EXTRA_LOOK)))
259 str += tmp;
260 if (stringp(tmp = QueryProp(P_INTERNAL_EXTRA_LOOK)))
261 str += tmp;
Bugfix5a9775f2017-02-17 13:48:56 +0100262 foreach(ob : QueryProp(P_EXTRA_LOOK_OBS))
263 {
264 if(objectp(ob) && environment(ob)==ME)
265 {
Bugfix7a9961f2017-02-28 10:37:55 +0100266 exl=ob->QueryProp(P_EXTRA_LOOK);
267 if(stringp(exl) && sizeof(exl))
Bugfix5a9775f2017-02-17 13:48:56 +0100268 {
Zesstrab6a6eab2017-02-27 21:39:29 +0100269 exl=replace_personal(exl, ({ME}), 1);
Bugfix967926a2017-02-27 16:51:10 +0100270 // Ist das letzte Zeichen kein \n, brechen wir um.
271 if(exl[<1]!='\n')
272 {
273 exl=break_string(exl,78);
274 }
Bugfix5a9775f2017-02-17 13:48:56 +0100275 str += exl;
276 }
277 else if(stringp(exl = ob->extra_look()))
278 {
279 str += exl; // TO BE REMOVED
280 }
281 }
282 else
283 {
284 // Bereinigen
285 SetProp(P_EXTRA_LOOK_OBS,QueryProp(P_EXTRA_LOOK_OBS)-({ob}));
286 }
287 }
MG Mud User88f12472016-06-24 23:31:02 +0200288
289 if(filter_ldfied = QueryProp(P_TRANSPARENT))
290 {
291 invl = make_invlist(PL, all_inventory(ME));
292 if(invl != "")
293 str += capitalize(QueryPronoun(WER))+" traegt bei sich:\n" + invl;
294 }
295 return str;
296}
297
298varargs string name(int casus, int demonst)
299{
300 if( QueryProp( P_INVIS ) )
301 {
302 if( casus == RAW ) return "Jemand";
303 return ({"Jemand","Jemands","Jemandem","Jemanden"})[casus];
304 }
305 if (QueryProp(P_FROG) && casus != RAW )
306 {
307 string s=QueryArticle(casus, 0, 1)+"Frosch";
308 if (casus==WESSEN) s += "es";
309 return s;
310 }
311 return ::name( casus, demonst );
312}
313
314static int _query_gender()
315{
316 if (QueryProp(P_FROG)) return 1;
317 return Query(P_GENDER);
318}
319
320// NPC sollen aus Kompatibilitaetsgruenden auch eine "echte" Rasse haben.
321// Default ist hier die Rasse, man kann aber hiermit auch einen NPC faken,
322// der sich tarnt, indem man P_REAL_RACE per Hand setzt.
323static string _query_real_race()
324{
325 return Query(P_REAL_RACE,F_VALUE)||QueryProp(P_RACE);
326}
327
Zesstra0d1bd1d2019-11-23 10:19:15 +0100328static <string|string*> _set_name(<string|string*> nm )
MG Mud User88f12472016-06-24 23:31:02 +0200329{
330 string lvnam;
Zesstra0d1bd1d2019-11-23 10:19:15 +0100331 if (pointerp(nm))
332 lvnam = nm[WER];
333 else
334 lvnam = nm;
MG Mud User88f12472016-06-24 23:31:02 +0200335 set_living_name(lower_case(lvnam));
Zesstra0d1bd1d2019-11-23 10:19:15 +0100336 return Set(P_NAME, nm, F_VALUE);
MG Mud User88f12472016-06-24 23:31:02 +0200337}
338
339int _query_container()
340{
341 return 0;
342}
343
Zesstra0d1bd1d2019-11-23 10:19:15 +0100344int is_class_member(<string|string*> str) {
MG Mud User88f12472016-06-24 23:31:02 +0200345 // Keine Klasse, keine Mitgliedschaft ...
346 if (!str || (!stringp(str) && !pointerp(str)) || str=="")
347 return 0;
348
349 if (::is_class_member(str))
350 return 1;
351
352 if (stringp(str))
353 str = ({str});
354
355 // Rassen werden als implizite Klassen aufgefasst.
356 // TODO: Pruefen, ob das unbedingt hart-kodiert sein muss.
357 string race = QueryProp(P_RACE);
358 if ( stringp(race) && member( str, lower_case(race) ) > -1 )
359 return 1;
360 else
361 return 0;
362}
363
364mapping _query_material() {
365 mixed res;
366
367 if (mappingp(res=Query(P_MATERIAL)))
368 return res;
369 return ([MAT_MISC_LIVING:100]);
370}
371
Bugfix5a9775f2017-02-17 13:48:56 +0100372public void NotifyInsert(object ob, object oldenv)
373{
Dominik Schäfer5bfa1282017-02-27 11:40:40 +0100374 // Unterstuetzung dyn. Querymethoden (z.B. bei Kleidung, welche nur in
375 // getragenem Zustand nen Extralook hat).
376 if(stringp(ob->QueryProp(P_EXTRA_LOOK))
377 || ob->Query(P_EXTRA_LOOK, F_QUERY_METHOD))
Bugfix5a9775f2017-02-17 13:48:56 +0100378 {
379 SetProp(P_EXTRA_LOOK_OBS,QueryProp(P_EXTRA_LOOK_OBS)+({ob}));
380 }
Dominik Schäfer5bfa1282017-02-27 11:40:40 +0100381
Bugfix5a9775f2017-02-17 13:48:56 +0100382 // Muss leider auch beachtet werden, sollte aber mal raus fliegen ...
383 if(function_exists("extra_look",ob))
384 {
385 SetProp(P_EXTRA_LOOK_OBS,QueryProp(P_EXTRA_LOOK_OBS)+({ob}));
386 catch(raise_error(
387 "Obsolete lfun extra_look() in "+load_name(ob));
388 publish);
389 }
390}
391
392public void NotifyLeave(object ob, object dest)
393{
394 object *els=QueryProp(P_EXTRA_LOOK_OBS);
395 if(member(els,ob)!=-1)
396 {
Zesstrab716ff82017-02-27 10:31:49 +0100397 SetProp(P_EXTRA_LOOK_OBS, els-({ob}) );
Bugfix5a9775f2017-02-17 13:48:56 +0100398 }
399}