blob: b6f63c26077f53e830d09188c4e6a93f79c2b960 [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
27public string _query_internal_extralook() {
28 mixed xl;
29 int zeit;
30 string res, look="";
31
32 xl=Query(P_INTERNAL_EXTRA_LOOK,F_VALUE);
33 if (!mappingp(xl))
34 return(0);
35
36 foreach(string key, mapping xld: xl) {
37 if (intp(zeit=xld["xlduration"])) {
38 //hat offenbar nen Ablaufdatum
39 if ( (zeit > 0 && zeit < time()) ||
40 (zeit < 0 && abs(zeit) < object_time(ME)) ) {
41 // Zeit abgelaufen oder
42 // negative "Ablaufzeit" und das Objekt ist neuer als die
43 // Eintragzeit, also loeschen und weiter (ja, das geht. ;-) und xld
44 // hat das Eintragsmapping ja noch, weitere Benutzung also moeglich.)
45 m_delete(xl,key);
46 // ggf. Meldung ausgeben
47 if (interactive(ME)) {
48 if (sizeof(xld["xlende"])) {
49 tell_object(ME,xld["xlende"]);
50 }
51 //kein einfacher String, aber Objekt+Funktion gegeben?
52 else if (sizeof(xld["xlendefun"]) && sizeof(xld["xlobjectname"]) &&
53 (!catch(res=call_other(xld["xlobjectname"],xld["xlendefun"],ME)
54 ;publish))) {
55 if (stringp(res) && sizeof(res))
56 tell_object(ME,res);
57 }
58 }
59 continue;
60 }
61 }
62 // Der Eintrag ist offenbar noch gueltig, Meldung anhaengen, bzw. via
63 // Funktionsaufruf beschaffen.
64 if (sizeof(xld["xllook"]))
65 look+=xld["xllook"];
66 else if (sizeof(xld["xlfun"]) && sizeof(xld["xlobjectname"])) {
67 closure cl;
68 if (catch(cl=symbol_function(xld["xlfun"],xld["xlobjectname"]);publish)
69 || !cl) {
70 // wenn Fehler beim Laden/Closure erstellen, dann Eintrag loeschen
71 // -> Annahme, dass dieser Fehler permanent sein wird, z.B. Eintrag
72 // von Clonen
73 m_delete(xl,key);
74 continue;
75 }
76 else if (!catch(res=funcall(cl, ME); publish)) {
77 if (!stringp(res) || !sizeof(res)) {
78 // keinen String oder leeren String gekriegt -> ueberspringen.
79 continue;
80 }
81 else
82 look+=res;
83 }
84 }
85 }
86 // fertig. Wenn look nicht leer ist, zurueckgeben, sonst 0.
87 if (sizeof(look))
88 return(look);
89 else
90 return(0);
91}
92
93public varargs int AddExtraLook(string look, int duration, string key,
94 string lookende, object ob) {
95 mapping xl;
96 string oname;
97 if (!stringp(key) || !sizeof(key)) {
98 // Automatisch erzeugen, wenn moeglich
99 if (!objectp(previous_object()) ||
100 !stringp(key=object_name(previous_object())) || !sizeof(key))
101 return(-1);
102 }
103
104 if (!stringp(look) || !sizeof(look))
105 return(-2);
106 if (!intp(duration))
107 return(-3);
108
109 xl=Query(P_INTERNAL_EXTRA_LOOK,F_VALUE); // dran denken: liefert referenz zurueck
110 if (!mappingp(xl)) {
111 Set(P_INTERNAL_EXTRA_LOOK, xl=([]) );
112 }
113
114 // kein Automatisches Ueberschreiben.
115 if (member(xl,key))
116 return(-4);
117
118 // neg. Werte: "bis Ende/reboot", abs(duration) == Eintragzeit
119 // 0: "fuer ewig", >0: Zeitdauer in Sekunden
120 if (duration > 0)
121 duration+=time(); // hoffentlich gibt es reichtzeitig 64bit-Ints
122 else if (duration < 0)
123 duration=negate(time());
124 // 0 bleibt, wie es ist.
125
126 if (objectp(ob)) {
127 // Funktionsname und Objektname (als Name, damit es auch noch geht, wenn
128 // das Objekt entladen wurde, Crash/reboot war etc.) speichern
129 // Clone werden auch gespeichert, aber es wird direkt ein harter Fehler
130 // ausgeloest, wenn ein permanenter Xlook fuer einen Clone registriert
131 // werden soll: das kann nicht gehen.
132 if (!duration && clonep(ob))
133 raise_error(sprintf(
134 "AddExtraLook(): Fehlerhaftes Argument <duration>: %d, "
135 "permanente Extralooks durch Clone (%s) nicht registrierbar.\n",
136 duration, object_name(ob)));
137
138 xl[key]=(["xlobjectname":object_name(ob),
139 "xlfun": look,
140 ]);
141 // ggf. Name der Funktion speichern, die bei Ablauf aufgerufen wird.
142 if (stringp(lookende) && sizeof(lookende))
143 xl[key]["xlendefun"]=lookende;
144 }
145 else {
146 // Einfacher Eintrag, nur den bearbeiteten String merken. ;-)
147 xl[key]=(["xllook": break_string(replace_personal(look,({ME}),1),78,
148 "",BS_LEAVE_MY_LFS),
149 ]);
150 // ggf. Meldung speichern, die bei Ablauf ausgegeben werden soll.
151 if (stringp(lookende) && sizeof(lookende)) {
152 xl[key]["xlende"]=break_string(replace_personal(lookende,({ME}),1),78,
153 "",BS_LEAVE_MY_LFS);
154 }
155 }
156 // Endezeit vermerken.
157 if (duration != 0)
158 xl[key]["xlduration"]=duration;
159
160 // Kein Set noetig, weil Query das Mapping ja als Referenz lieferte.
161 return(1);
162}
163
164public int RemoveExtraLook(string key) {
165 mapping xl;
166 if (!stringp(key) || !sizeof(key)) {
167 // Automatisch erzeugen, wenn moeglich
168 if (!objectp(previous_object()) ||
169 !stringp(key=object_name(previous_object())) || !sizeof(key))
170 return(-1);
171 }
172 xl=Query(P_INTERNAL_EXTRA_LOOK,F_VALUE); // dran denken: liefert referenz zurueck
173 if (!mappingp(xl))
174 return (-2);
175 if (!member(xl,key))
176 return(-2);
177
178 m_delete(xl,key);
179 // Kein Set noetig, weil Query das Mapping ja als Referenz lieferte.
180 return(1);
181}
182
183void create()
184{
185 ::create();
186 Set(P_GENDER, SAVE, F_MODE);
187 // Extralook-Property speichern und vor manueller Aenderung schuetzen
188 // EMs duerfen, die wissen hoffentlich, was sie tun.
189 Set(P_INTERNAL_EXTRA_LOOK, SAVE|PROTECTED, F_MODE_AS);
Bugfix5a9775f2017-02-17 13:48:56 +0100190 SetProp(P_EXTRA_LOOK_OBS,({}));
191 Set(P_EXTRA_LOOK, PROTECTED, F_MODE_AS);
MG Mud User88f12472016-06-24 23:31:02 +0200192 SetProp(P_CLOTHING,({}));
193 AddId("Living");
194}
195
196string condition()
197{
198 int hpnt, max_hpnt, perc;
199
200 hpnt = QueryProp( P_HP );
201 max_hpnt = QueryProp( P_MAX_HP );
202
203 if(max_hpnt>0 && hpnt>0)
204 perc=100*hpnt/max_hpnt;
205
206 switch(perc) {
207 case 0..9:
208 return capitalize(QueryPronoun(WER))+" steht auf der Schwelle des Todes.\n";
209 case 10..19:
210 return capitalize(QueryPronoun(WER))+" braucht dringend einen Arzt.\n";
211 case 20..29:
212 return capitalize(QueryPronoun(WER))+" ist in keiner guten Verfassung.\n";
213 case 30..39:
214 return capitalize(QueryPronoun(WER))+" wankt bereits bedenklich.\n";
215 case 40..49:
216 return capitalize(QueryPronoun(WER))+" macht einen mitgenommenen Eindruck.\n";
217 case 50..59:
218 return capitalize(QueryPronoun(WER))+" sieht nicht mehr taufrisch aus.\n";
219 case 60..69:
220 return capitalize(QueryPronoun(WER))+" ist leicht angeschlagen.\n";
221 case 70..79:
222 return capitalize(QueryPronoun(WER))+" fuehlte sich heute schon besser.\n";
223 case 80..89:
224 return capitalize(QueryPronoun(WER))+" ist schon etwas geschwaecht.\n";
225 }
226 //fall-through
227 return capitalize(QueryPronoun(WER))+" ist absolut fit.\n";
228}
229
230varargs string long() {
231 string str, cap_pronoun;
232 string descr, invl,tmp,exl;
233 int hpnt, max_hpnt;
234 mixed filter_ldfied;
235 object ob;
236
237 str = process_string( QueryProp(P_LONG) );
238 if(!stringp(str)) str = "";
239
240 str += condition();
241
242 // Extralook
243 if(stringp(tmp = QueryProp(P_EXTRA_LOOK)))
244 str += tmp;
245 if (stringp(tmp = QueryProp(P_INTERNAL_EXTRA_LOOK)))
246 str += tmp;
Bugfix5a9775f2017-02-17 13:48:56 +0100247 foreach(ob : QueryProp(P_EXTRA_LOOK_OBS))
248 {
249 if(objectp(ob) && environment(ob)==ME)
250 {
Bugfix7a9961f2017-02-28 10:37:55 +0100251 exl=ob->QueryProp(P_EXTRA_LOOK);
252 if(stringp(exl) && sizeof(exl))
Bugfix5a9775f2017-02-17 13:48:56 +0100253 {
Zesstrab6a6eab2017-02-27 21:39:29 +0100254 exl=replace_personal(exl, ({ME}), 1);
Bugfix967926a2017-02-27 16:51:10 +0100255 // Ist das letzte Zeichen kein \n, brechen wir um.
256 if(exl[<1]!='\n')
257 {
258 exl=break_string(exl,78);
259 }
Bugfix5a9775f2017-02-17 13:48:56 +0100260 str += exl;
261 }
262 else if(stringp(exl = ob->extra_look()))
263 {
264 str += exl; // TO BE REMOVED
265 }
266 }
267 else
268 {
269 // Bereinigen
270 SetProp(P_EXTRA_LOOK_OBS,QueryProp(P_EXTRA_LOOK_OBS)-({ob}));
271 }
272 }
MG Mud User88f12472016-06-24 23:31:02 +0200273
274 if(filter_ldfied = QueryProp(P_TRANSPARENT))
275 {
276 invl = make_invlist(PL, all_inventory(ME));
277 if(invl != "")
278 str += capitalize(QueryPronoun(WER))+" traegt bei sich:\n" + invl;
279 }
280 return str;
281}
282
283varargs string name(int casus, int demonst)
284{
285 if( QueryProp( P_INVIS ) )
286 {
287 if( casus == RAW ) return "Jemand";
288 return ({"Jemand","Jemands","Jemandem","Jemanden"})[casus];
289 }
290 if (QueryProp(P_FROG) && casus != RAW )
291 {
292 string s=QueryArticle(casus, 0, 1)+"Frosch";
293 if (casus==WESSEN) s += "es";
294 return s;
295 }
296 return ::name( casus, demonst );
297}
298
299static int _query_gender()
300{
301 if (QueryProp(P_FROG)) return 1;
302 return Query(P_GENDER);
303}
304
305// NPC sollen aus Kompatibilitaetsgruenden auch eine "echte" Rasse haben.
306// Default ist hier die Rasse, man kann aber hiermit auch einen NPC faken,
307// der sich tarnt, indem man P_REAL_RACE per Hand setzt.
308static string _query_real_race()
309{
310 return Query(P_REAL_RACE,F_VALUE)||QueryProp(P_RACE);
311}
312
313static mixed _set_name(mixed nm )
314{
315 string lvnam;
316 lvnam = nm;
317 if(pointerp(nm)) lvnam = nm[0];
318 set_living_name(lower_case(lvnam));
319 return Set(P_NAME, nm);
320}
321
322int _query_container()
323{
324 return 0;
325}
326
327int is_class_member(mixed str) {
328 // Keine Klasse, keine Mitgliedschaft ...
329 if (!str || (!stringp(str) && !pointerp(str)) || str=="")
330 return 0;
331
332 if (::is_class_member(str))
333 return 1;
334
335 if (stringp(str))
336 str = ({str});
337
338 // Rassen werden als implizite Klassen aufgefasst.
339 // TODO: Pruefen, ob das unbedingt hart-kodiert sein muss.
340 string race = QueryProp(P_RACE);
341 if ( stringp(race) && member( str, lower_case(race) ) > -1 )
342 return 1;
343 else
344 return 0;
345}
346
347mapping _query_material() {
348 mixed res;
349
350 if (mappingp(res=Query(P_MATERIAL)))
351 return res;
352 return ([MAT_MISC_LIVING:100]);
353}
354
Bugfix5a9775f2017-02-17 13:48:56 +0100355public void NotifyInsert(object ob, object oldenv)
356{
Dominik Schäfer5bfa1282017-02-27 11:40:40 +0100357 // Unterstuetzung dyn. Querymethoden (z.B. bei Kleidung, welche nur in
358 // getragenem Zustand nen Extralook hat).
359 if(stringp(ob->QueryProp(P_EXTRA_LOOK))
360 || ob->Query(P_EXTRA_LOOK, F_QUERY_METHOD))
Bugfix5a9775f2017-02-17 13:48:56 +0100361 {
362 SetProp(P_EXTRA_LOOK_OBS,QueryProp(P_EXTRA_LOOK_OBS)+({ob}));
363 }
Dominik Schäfer5bfa1282017-02-27 11:40:40 +0100364
Bugfix5a9775f2017-02-17 13:48:56 +0100365 // Muss leider auch beachtet werden, sollte aber mal raus fliegen ...
366 if(function_exists("extra_look",ob))
367 {
368 SetProp(P_EXTRA_LOOK_OBS,QueryProp(P_EXTRA_LOOK_OBS)+({ob}));
369 catch(raise_error(
370 "Obsolete lfun extra_look() in "+load_name(ob));
371 publish);
372 }
373}
374
375public void NotifyLeave(object ob, object dest)
376{
377 object *els=QueryProp(P_EXTRA_LOOK_OBS);
378 if(member(els,ob)!=-1)
379 {
Zesstrab716ff82017-02-27 10:31:49 +0100380 SetProp(P_EXTRA_LOOK_OBS, els-({ob}) );
Bugfix5a9775f2017-02-17 13:48:56 +0100381 }
382}