blob: 32ac2c51363b38aae3611f8d563d9ea311ee1390 [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 {
Zesstrab716ff82017-02-27 10:31:49 +0100251 if(stringp(exl = ob->QueryProp(P_EXTRA_LOOK)))
Bugfix5a9775f2017-02-17 13:48:56 +0100252 {
253 str += exl;
254 }
255 else if(stringp(exl = ob->extra_look()))
256 {
257 str += exl; // TO BE REMOVED
258 }
259 }
260 else
261 {
262 // Bereinigen
263 SetProp(P_EXTRA_LOOK_OBS,QueryProp(P_EXTRA_LOOK_OBS)-({ob}));
264 }
265 }
MG Mud User88f12472016-06-24 23:31:02 +0200266
267 if(filter_ldfied = QueryProp(P_TRANSPARENT))
268 {
269 invl = make_invlist(PL, all_inventory(ME));
270 if(invl != "")
271 str += capitalize(QueryPronoun(WER))+" traegt bei sich:\n" + invl;
272 }
273 return str;
274}
275
276varargs string name(int casus, int demonst)
277{
278 if( QueryProp( P_INVIS ) )
279 {
280 if( casus == RAW ) return "Jemand";
281 return ({"Jemand","Jemands","Jemandem","Jemanden"})[casus];
282 }
283 if (QueryProp(P_FROG) && casus != RAW )
284 {
285 string s=QueryArticle(casus, 0, 1)+"Frosch";
286 if (casus==WESSEN) s += "es";
287 return s;
288 }
289 return ::name( casus, demonst );
290}
291
292static int _query_gender()
293{
294 if (QueryProp(P_FROG)) return 1;
295 return Query(P_GENDER);
296}
297
298// NPC sollen aus Kompatibilitaetsgruenden auch eine "echte" Rasse haben.
299// Default ist hier die Rasse, man kann aber hiermit auch einen NPC faken,
300// der sich tarnt, indem man P_REAL_RACE per Hand setzt.
301static string _query_real_race()
302{
303 return Query(P_REAL_RACE,F_VALUE)||QueryProp(P_RACE);
304}
305
306static mixed _set_name(mixed nm )
307{
308 string lvnam;
309 lvnam = nm;
310 if(pointerp(nm)) lvnam = nm[0];
311 set_living_name(lower_case(lvnam));
312 return Set(P_NAME, nm);
313}
314
315int _query_container()
316{
317 return 0;
318}
319
320int is_class_member(mixed str) {
321 // Keine Klasse, keine Mitgliedschaft ...
322 if (!str || (!stringp(str) && !pointerp(str)) || str=="")
323 return 0;
324
325 if (::is_class_member(str))
326 return 1;
327
328 if (stringp(str))
329 str = ({str});
330
331 // Rassen werden als implizite Klassen aufgefasst.
332 // TODO: Pruefen, ob das unbedingt hart-kodiert sein muss.
333 string race = QueryProp(P_RACE);
334 if ( stringp(race) && member( str, lower_case(race) ) > -1 )
335 return 1;
336 else
337 return 0;
338}
339
340mapping _query_material() {
341 mixed res;
342
343 if (mappingp(res=Query(P_MATERIAL)))
344 return res;
345 return ([MAT_MISC_LIVING:100]);
346}
347
Bugfix5a9775f2017-02-17 13:48:56 +0100348public void NotifyInsert(object ob, object oldenv)
349{
Dominik Schäfer5bfa1282017-02-27 11:40:40 +0100350 // Unterstuetzung dyn. Querymethoden (z.B. bei Kleidung, welche nur in
351 // getragenem Zustand nen Extralook hat).
352 if(stringp(ob->QueryProp(P_EXTRA_LOOK))
353 || ob->Query(P_EXTRA_LOOK, F_QUERY_METHOD))
Bugfix5a9775f2017-02-17 13:48:56 +0100354 {
355 SetProp(P_EXTRA_LOOK_OBS,QueryProp(P_EXTRA_LOOK_OBS)+({ob}));
356 }
Dominik Schäfer5bfa1282017-02-27 11:40:40 +0100357
Bugfix5a9775f2017-02-17 13:48:56 +0100358 // Muss leider auch beachtet werden, sollte aber mal raus fliegen ...
359 if(function_exists("extra_look",ob))
360 {
361 SetProp(P_EXTRA_LOOK_OBS,QueryProp(P_EXTRA_LOOK_OBS)+({ob}));
362 catch(raise_error(
363 "Obsolete lfun extra_look() in "+load_name(ob));
364 publish);
365 }
366}
367
368public void NotifyLeave(object ob, object dest)
369{
370 object *els=QueryProp(P_EXTRA_LOOK_OBS);
371 if(member(els,ob)!=-1)
372 {
Zesstrab716ff82017-02-27 10:31:49 +0100373 SetProp(P_EXTRA_LOOK_OBS, els-({ob}) );
Bugfix5a9775f2017-02-17 13:48:56 +0100374 }
375}