MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame^] | 1 | // 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 | |
| 12 | inherit "/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 | |
| 27 | public 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 | |
| 93 | public 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 | |
| 164 | public 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 | |
| 183 | void 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 | |
| 194 | string 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 | |
| 228 | varargs 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 | |
| 261 | varargs 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 | |
| 277 | static 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. |
| 286 | static string _query_real_race() |
| 287 | { |
| 288 | return Query(P_REAL_RACE,F_VALUE)||QueryProp(P_RACE); |
| 289 | } |
| 290 | |
| 291 | static 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 | |
| 300 | int _query_container() |
| 301 | { |
| 302 | return 0; |
| 303 | } |
| 304 | |
| 305 | int 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 | |
| 325 | mapping _query_material() { |
| 326 | mixed res; |
| 327 | |
| 328 | if (mappingp(res=Query(P_MATERIAL))) |
| 329 | return res; |
| 330 | return ([MAT_MISC_LIVING:100]); |
| 331 | } |
| 332 | |