blob: 6353ca90ed4e39e17070d22727037bfa8c76f696 [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);
190 SetProp(P_CLOTHING,({}));
191 AddId("Living");
192}
193
194string condition()
195{
196 int hpnt, max_hpnt, perc;
197
198 hpnt = QueryProp( P_HP );
199 max_hpnt = QueryProp( P_MAX_HP );
200
201 if(max_hpnt>0 && hpnt>0)
202 perc=100*hpnt/max_hpnt;
203
204 switch(perc) {
205 case 0..9:
206 return capitalize(QueryPronoun(WER))+" steht auf der Schwelle des Todes.\n";
207 case 10..19:
208 return capitalize(QueryPronoun(WER))+" braucht dringend einen Arzt.\n";
209 case 20..29:
210 return capitalize(QueryPronoun(WER))+" ist in keiner guten Verfassung.\n";
211 case 30..39:
212 return capitalize(QueryPronoun(WER))+" wankt bereits bedenklich.\n";
213 case 40..49:
214 return capitalize(QueryPronoun(WER))+" macht einen mitgenommenen Eindruck.\n";
215 case 50..59:
216 return capitalize(QueryPronoun(WER))+" sieht nicht mehr taufrisch aus.\n";
217 case 60..69:
218 return capitalize(QueryPronoun(WER))+" ist leicht angeschlagen.\n";
219 case 70..79:
220 return capitalize(QueryPronoun(WER))+" fuehlte sich heute schon besser.\n";
221 case 80..89:
222 return capitalize(QueryPronoun(WER))+" ist schon etwas geschwaecht.\n";
223 }
224 //fall-through
225 return capitalize(QueryPronoun(WER))+" ist absolut fit.\n";
226}
227
228varargs string long() {
229 string str, cap_pronoun;
230 string descr, invl,tmp,exl;
231 int hpnt, max_hpnt;
232 mixed filter_ldfied;
233 object ob;
234
235 str = process_string( QueryProp(P_LONG) );
236 if(!stringp(str)) str = "";
237
238 str += condition();
239
240 // Extralook
241 if(stringp(tmp = QueryProp(P_EXTRA_LOOK)))
242 str += tmp;
243 if (stringp(tmp = QueryProp(P_INTERNAL_EXTRA_LOOK)))
244 str += tmp;
245 for(ob = first_inventory(ME); ob; ob = next_inventory(ob))
246 if(exl = ob->QueryProp(P_EXTRA_LOOK))
247 str += exl;
248 else if(exl = ob->extra_look())
249 str += exl; // TO BE REMOVED
250
251
252 if(filter_ldfied = QueryProp(P_TRANSPARENT))
253 {
254 invl = make_invlist(PL, all_inventory(ME));
255 if(invl != "")
256 str += capitalize(QueryPronoun(WER))+" traegt bei sich:\n" + invl;
257 }
258 return str;
259}
260
261varargs string name(int casus, int demonst)
262{
263 if( QueryProp( P_INVIS ) )
264 {
265 if( casus == RAW ) return "Jemand";
266 return ({"Jemand","Jemands","Jemandem","Jemanden"})[casus];
267 }
268 if (QueryProp(P_FROG) && casus != RAW )
269 {
270 string s=QueryArticle(casus, 0, 1)+"Frosch";
271 if (casus==WESSEN) s += "es";
272 return s;
273 }
274 return ::name( casus, demonst );
275}
276
277static int _query_gender()
278{
279 if (QueryProp(P_FROG)) return 1;
280 return Query(P_GENDER);
281}
282
283// NPC sollen aus Kompatibilitaetsgruenden auch eine "echte" Rasse haben.
284// Default ist hier die Rasse, man kann aber hiermit auch einen NPC faken,
285// der sich tarnt, indem man P_REAL_RACE per Hand setzt.
286static string _query_real_race()
287{
288 return Query(P_REAL_RACE,F_VALUE)||QueryProp(P_RACE);
289}
290
291static mixed _set_name(mixed nm )
292{
293 string lvnam;
294 lvnam = nm;
295 if(pointerp(nm)) lvnam = nm[0];
296 set_living_name(lower_case(lvnam));
297 return Set(P_NAME, nm);
298}
299
300int _query_container()
301{
302 return 0;
303}
304
305int is_class_member(mixed str) {
306 // Keine Klasse, keine Mitgliedschaft ...
307 if (!str || (!stringp(str) && !pointerp(str)) || str=="")
308 return 0;
309
310 if (::is_class_member(str))
311 return 1;
312
313 if (stringp(str))
314 str = ({str});
315
316 // Rassen werden als implizite Klassen aufgefasst.
317 // TODO: Pruefen, ob das unbedingt hart-kodiert sein muss.
318 string race = QueryProp(P_RACE);
319 if ( stringp(race) && member( str, lower_case(race) ) > -1 )
320 return 1;
321 else
322 return 0;
323}
324
325mapping _query_material() {
326 mixed res;
327
328 if (mappingp(res=Query(P_MATERIAL)))
329 return res;
330 return ([MAT_MISC_LIVING:100]);
331}
332