| // MorgenGrauen MUDlib |
| // |
| // living/description.c -- description for living objects |
| // |
| // $Id: description.c 9395 2015-12-08 23:04:38Z Zesstra $ |
| #pragma strong_types |
| #pragma save_types |
| #pragma range_check |
| #pragma no_clone |
| #pragma pedantic |
| |
| inherit "/std/container/description"; |
| |
| #define NEED_PROTOTYPES |
| |
| #include <living/skills.h> |
| #include <living/clothing.h> |
| #include <thing/properties.h> |
| #include <wizlevels.h> |
| #include <new_skills.h> |
| #include <properties.h> |
| #include <language.h> |
| #include <defines.h> |
| #include <class.h> |
| #include <sys_debug.h> |
| |
| public string _query_internal_extralook() { |
| mixed xl; |
| int zeit; |
| string res, look=""; |
| |
| xl=Query(P_INTERNAL_EXTRA_LOOK,F_VALUE); |
| if (!mappingp(xl)) |
| return(0); |
| |
| foreach(string key, mapping xld: xl) { |
| if (intp(zeit=xld["xlduration"])) { |
| //hat offenbar nen Ablaufdatum |
| if ( (zeit > 0 && zeit < time()) || |
| (zeit < 0 && abs(zeit) < object_time(ME)) ) { |
| // Zeit abgelaufen oder |
| // negative "Ablaufzeit" und das Objekt ist neuer als die |
| // Eintragzeit, also loeschen und weiter (ja, das geht. ;-) und xld |
| // hat das Eintragsmapping ja noch, weitere Benutzung also moeglich.) |
| m_delete(xl,key); |
| // ggf. Meldung ausgeben |
| if (interactive(ME)) { |
| if (sizeof(xld["xlende"])) { |
| tell_object(ME,xld["xlende"]); |
| } |
| //kein einfacher String, aber Objekt+Funktion gegeben? |
| else if (sizeof(xld["xlendefun"]) && sizeof(xld["xlobjectname"]) && |
| (!catch(res=call_other(xld["xlobjectname"],xld["xlendefun"],ME) |
| ;publish))) { |
| if (stringp(res) && sizeof(res)) |
| tell_object(ME,res); |
| } |
| } |
| continue; |
| } |
| } |
| // Der Eintrag ist offenbar noch gueltig, Meldung anhaengen, bzw. via |
| // Funktionsaufruf beschaffen. |
| if (sizeof(xld["xllook"])) |
| look+=xld["xllook"]; |
| else if (sizeof(xld["xlfun"]) && sizeof(xld["xlobjectname"])) { |
| closure cl; |
| if (catch(cl=symbol_function(xld["xlfun"],xld["xlobjectname"]);publish) |
| || !cl) { |
| // wenn Fehler beim Laden/Closure erstellen, dann Eintrag loeschen |
| // -> Annahme, dass dieser Fehler permanent sein wird, z.B. Eintrag |
| // von Clonen |
| m_delete(xl,key); |
| continue; |
| } |
| else if (!catch(res=funcall(cl, ME); publish)) { |
| if (!stringp(res) || !sizeof(res)) { |
| // keinen String oder leeren String gekriegt -> ueberspringen. |
| continue; |
| } |
| else |
| look+=res; |
| } |
| } |
| } |
| // fertig. Wenn look nicht leer ist, zurueckgeben, sonst 0. |
| if (sizeof(look)) |
| return(look); |
| else |
| return(0); |
| } |
| |
| public varargs int AddExtraLook(string look, int duration, string key, |
| string lookende, object ob) { |
| mapping xl; |
| string oname; |
| if (!stringp(key) || !sizeof(key)) { |
| // Automatisch erzeugen, wenn moeglich |
| if (!objectp(previous_object()) || |
| !stringp(key=object_name(previous_object())) || !sizeof(key)) |
| return(-1); |
| } |
| |
| if (!stringp(look) || !sizeof(look)) |
| return(-2); |
| if (!intp(duration)) |
| return(-3); |
| |
| xl=Query(P_INTERNAL_EXTRA_LOOK,F_VALUE); // dran denken: liefert referenz zurueck |
| if (!mappingp(xl)) { |
| Set(P_INTERNAL_EXTRA_LOOK, xl=([]) ); |
| } |
| |
| // kein Automatisches Ueberschreiben. |
| if (member(xl,key)) |
| return(-4); |
| |
| // neg. Werte: "bis Ende/reboot", abs(duration) == Eintragzeit |
| // 0: "fuer ewig", >0: Zeitdauer in Sekunden |
| if (duration > 0) |
| duration+=time(); // hoffentlich gibt es reichtzeitig 64bit-Ints |
| else if (duration < 0) |
| duration=negate(time()); |
| // 0 bleibt, wie es ist. |
| |
| if (objectp(ob)) { |
| // Funktionsname und Objektname (als Name, damit es auch noch geht, wenn |
| // das Objekt entladen wurde, Crash/reboot war etc.) speichern |
| // Clone werden auch gespeichert, aber es wird direkt ein harter Fehler |
| // ausgeloest, wenn ein permanenter Xlook fuer einen Clone registriert |
| // werden soll: das kann nicht gehen. |
| if (!duration && clonep(ob)) |
| raise_error(sprintf( |
| "AddExtraLook(): Fehlerhaftes Argument <duration>: %d, " |
| "permanente Extralooks durch Clone (%s) nicht registrierbar.\n", |
| duration, object_name(ob))); |
| |
| xl[key]=(["xlobjectname":object_name(ob), |
| "xlfun": look, |
| ]); |
| // ggf. Name der Funktion speichern, die bei Ablauf aufgerufen wird. |
| if (stringp(lookende) && sizeof(lookende)) |
| xl[key]["xlendefun"]=lookende; |
| } |
| else { |
| // Einfacher Eintrag, nur den bearbeiteten String merken. ;-) |
| xl[key]=(["xllook": break_string(replace_personal(look,({ME}),1),78, |
| "",BS_LEAVE_MY_LFS), |
| ]); |
| // ggf. Meldung speichern, die bei Ablauf ausgegeben werden soll. |
| if (stringp(lookende) && sizeof(lookende)) { |
| xl[key]["xlende"]=break_string(replace_personal(lookende,({ME}),1),78, |
| "",BS_LEAVE_MY_LFS); |
| } |
| } |
| // Endezeit vermerken. |
| if (duration != 0) |
| xl[key]["xlduration"]=duration; |
| |
| // Kein Set noetig, weil Query das Mapping ja als Referenz lieferte. |
| return(1); |
| } |
| |
| public int RemoveExtraLook(string key) { |
| mapping xl; |
| if (!stringp(key) || !sizeof(key)) { |
| // Automatisch erzeugen, wenn moeglich |
| if (!objectp(previous_object()) || |
| !stringp(key=object_name(previous_object())) || !sizeof(key)) |
| return(-1); |
| } |
| xl=Query(P_INTERNAL_EXTRA_LOOK,F_VALUE); // dran denken: liefert referenz zurueck |
| if (!mappingp(xl)) |
| return (-2); |
| if (!member(xl,key)) |
| return(-2); |
| |
| m_delete(xl,key); |
| // Kein Set noetig, weil Query das Mapping ja als Referenz lieferte. |
| return(1); |
| } |
| |
| void create() |
| { |
| ::create(); |
| Set(P_GENDER, SAVE, F_MODE); |
| // Extralook-Property speichern und vor manueller Aenderung schuetzen |
| // EMs duerfen, die wissen hoffentlich, was sie tun. |
| Set(P_INTERNAL_EXTRA_LOOK, SAVE|PROTECTED, F_MODE_AS); |
| SetProp(P_CLOTHING,({})); |
| AddId("Living"); |
| } |
| |
| string condition() |
| { |
| int hpnt, max_hpnt, perc; |
| |
| hpnt = QueryProp( P_HP ); |
| max_hpnt = QueryProp( P_MAX_HP ); |
| |
| if(max_hpnt>0 && hpnt>0) |
| perc=100*hpnt/max_hpnt; |
| |
| switch(perc) { |
| case 0..9: |
| return capitalize(QueryPronoun(WER))+" steht auf der Schwelle des Todes.\n"; |
| case 10..19: |
| return capitalize(QueryPronoun(WER))+" braucht dringend einen Arzt.\n"; |
| case 20..29: |
| return capitalize(QueryPronoun(WER))+" ist in keiner guten Verfassung.\n"; |
| case 30..39: |
| return capitalize(QueryPronoun(WER))+" wankt bereits bedenklich.\n"; |
| case 40..49: |
| return capitalize(QueryPronoun(WER))+" macht einen mitgenommenen Eindruck.\n"; |
| case 50..59: |
| return capitalize(QueryPronoun(WER))+" sieht nicht mehr taufrisch aus.\n"; |
| case 60..69: |
| return capitalize(QueryPronoun(WER))+" ist leicht angeschlagen.\n"; |
| case 70..79: |
| return capitalize(QueryPronoun(WER))+" fuehlte sich heute schon besser.\n"; |
| case 80..89: |
| return capitalize(QueryPronoun(WER))+" ist schon etwas geschwaecht.\n"; |
| } |
| //fall-through |
| return capitalize(QueryPronoun(WER))+" ist absolut fit.\n"; |
| } |
| |
| varargs string long() { |
| string str, cap_pronoun; |
| string descr, invl,tmp,exl; |
| int hpnt, max_hpnt; |
| mixed filter_ldfied; |
| object ob; |
| |
| str = process_string( QueryProp(P_LONG) ); |
| if(!stringp(str)) str = ""; |
| |
| str += condition(); |
| |
| // Extralook |
| if(stringp(tmp = QueryProp(P_EXTRA_LOOK))) |
| str += tmp; |
| if (stringp(tmp = QueryProp(P_INTERNAL_EXTRA_LOOK))) |
| str += tmp; |
| for(ob = first_inventory(ME); ob; ob = next_inventory(ob)) |
| if(exl = ob->QueryProp(P_EXTRA_LOOK)) |
| str += exl; |
| else if(exl = ob->extra_look()) |
| str += exl; // TO BE REMOVED |
| |
| |
| if(filter_ldfied = QueryProp(P_TRANSPARENT)) |
| { |
| invl = make_invlist(PL, all_inventory(ME)); |
| if(invl != "") |
| str += capitalize(QueryPronoun(WER))+" traegt bei sich:\n" + invl; |
| } |
| return str; |
| } |
| |
| varargs string name(int casus, int demonst) |
| { |
| if( QueryProp( P_INVIS ) ) |
| { |
| if( casus == RAW ) return "Jemand"; |
| return ({"Jemand","Jemands","Jemandem","Jemanden"})[casus]; |
| } |
| if (QueryProp(P_FROG) && casus != RAW ) |
| { |
| string s=QueryArticle(casus, 0, 1)+"Frosch"; |
| if (casus==WESSEN) s += "es"; |
| return s; |
| } |
| return ::name( casus, demonst ); |
| } |
| |
| static int _query_gender() |
| { |
| if (QueryProp(P_FROG)) return 1; |
| return Query(P_GENDER); |
| } |
| |
| // NPC sollen aus Kompatibilitaetsgruenden auch eine "echte" Rasse haben. |
| // Default ist hier die Rasse, man kann aber hiermit auch einen NPC faken, |
| // der sich tarnt, indem man P_REAL_RACE per Hand setzt. |
| static string _query_real_race() |
| { |
| return Query(P_REAL_RACE,F_VALUE)||QueryProp(P_RACE); |
| } |
| |
| static mixed _set_name(mixed nm ) |
| { |
| string lvnam; |
| lvnam = nm; |
| if(pointerp(nm)) lvnam = nm[0]; |
| set_living_name(lower_case(lvnam)); |
| return Set(P_NAME, nm); |
| } |
| |
| int _query_container() |
| { |
| return 0; |
| } |
| |
| int is_class_member(mixed str) { |
| // Keine Klasse, keine Mitgliedschaft ... |
| if (!str || (!stringp(str) && !pointerp(str)) || str=="") |
| return 0; |
| |
| if (::is_class_member(str)) |
| return 1; |
| |
| if (stringp(str)) |
| str = ({str}); |
| |
| // Rassen werden als implizite Klassen aufgefasst. |
| // TODO: Pruefen, ob das unbedingt hart-kodiert sein muss. |
| string race = QueryProp(P_RACE); |
| if ( stringp(race) && member( str, lower_case(race) ) > -1 ) |
| return 1; |
| else |
| return 0; |
| } |
| |
| mapping _query_material() { |
| mixed res; |
| |
| if (mappingp(res=Query(P_MATERIAL))) |
| return res; |
| return ([MAT_MISC_LIVING:100]); |
| } |
| |