| // MorgenGrauen MUDlib |
| // |
| // unit.c -- Basisklasse fuer Mengenobjekte |
| // (neue Version von Padreic) |
| // |
| // $Id: unit.c 9077 2015-01-16 23:26:00Z Zesstra $ |
| #pragma strong_types,save_types,rtt_checks |
| #pragma range_check |
| #pragma no_clone |
| |
| inherit "/std/thing"; |
| |
| #define NEED_PROTOTYPES |
| #include <unit.h> |
| #undef NEED_PROTOTYPES |
| |
| #include <properties.h> |
| #include <thing/properties.h> |
| #include <defines.h> |
| #include <language.h> |
| #include <moving.h> |
| #include <wizlevels.h> |
| #include <debug_info.h> |
| |
| // zum debuggen und extra public |
| public string debugmode; |
| public string __set_debug(string recv) {return debugmode=recv;} |
| #include <living/comm.h> |
| #define ZDEBUG(x) if (stringp(debugmode) && find_player(debugmode)) \ |
| find_player(debugmode)->ReceiveMsg(x,MT_DEBUG,0,object_name()+": ",ME) |
| //#define ZDEBUG(x) |
| |
| private void _call_DoDecay(object *klone); |
| |
| private nosave string lastverb; |
| private nosave int lastevalnumber; |
| |
| protected void create() |
| { |
| ::create(); |
| SetProp(U_IDS,({({}),({})})); |
| SetProp(P_GENDER, 1); |
| SetProp(P_AMOUNT, 1); |
| // Props sollten nicht direkt manipuliert werden, nur ueber Set-Methoden |
| Set(P_UNIT_DECAY_INTERVAL, PROTECTED, F_MODE_AS); |
| Set(P_UNIT_DECAY_QUOTA, PROTECTED, F_MODE_AS); |
| } |
| |
| protected void create_super() { |
| set_next_reset(-1); |
| } |
| |
| //// Query und Set Funktionen fuer die Propertys |
| |
| static void check_leave() |
| { if (Query(P_AMOUNT,F_VALUE)<1) remove(1); } |
| |
| static int _query_invis() |
| { |
| if (QueryProp(P_AMOUNT) < 1) |
| return 1; |
| return Query(P_INVIS, F_VALUE); |
| } |
| |
| static int _set_amount(int am) |
| { |
| if (am<1) |
| call_out("check_leave",1); |
| SetProp(U_REQ, am); |
| return Set(P_AMOUNT,am, F_VALUE); |
| } |
| |
| static int _set_u_req(int ureq) |
| { |
| lastverb = query_verb(); |
| lastevalnumber = debug_info(DINFO_EVAL_NUMBER); |
| return Set(U_REQ, ureq, F_VALUE); |
| } |
| |
| static int _query_u_req() |
| { |
| // Zwei Dinge benutzten, um zu entscheiden, ob U_REQ noch gueltig ist oder |
| // besser auf P_AMOUNT zurueckgesetzt werden sollte: die DINFO_EVAL_NUMBER |
| // und das Kommandoverb. Wenn eines von beiden sich geaendert hat, wird |
| // U_REQ als ungueltig betrachtet. (Und dies bleibt ein uebler Hack.) |
| if (lastevalnumber != debug_info(DINFO_EVAL_NUMBER) |
| || lastverb != query_verb()) |
| { |
| return SetProp(U_REQ, Query(P_AMOUNT, F_VALUE)); |
| } |
| return Query(U_REQ, F_VALUE); |
| } |
| |
| // Gesamtwert der gerade mit U_REQ ausgewaehlten unitobjekte |
| static int _query_value() |
| { |
| mixed cpu; |
| cpu=Query(U_CPU); |
| if (intp(cpu)) return QueryProp(U_REQ) * cpu; |
| if (!pointerp(cpu)) return 0; |
| return (QueryProp(U_REQ) * cpu[0])/cpu[1]; |
| } |
| |
| static int _set_value(int num) { |
| // Setzt den Wert fuer die derzeitige Anzahl |
| SetCoinsPerUnits(num, QueryProp(U_REQ)); |
| return QueryProp(P_VALUE); |
| } |
| |
| static int _query_weight() |
| { |
| int req = QueryProp(U_REQ); |
| if (req<1) |
| return 0; |
| int|int* gpu=Query(U_GPU, F_VALUE); |
| if (pointerp(gpu)) |
| return MAX(1,(req*gpu[0])/gpu[1]); |
| return req * gpu; |
| } |
| |
| static int _set_weight(int num) { |
| // Setzt das Gewicht fuer die derzeitige Anzahl |
| SetGramsPerUnits(num, QueryProp(U_REQ)); |
| return QueryProp(P_WEIGHT); |
| } |
| |
| static int _query_total_weight() |
| { |
| int amount = Query(P_AMOUNT); |
| if (amount<1) |
| return 0; |
| int|int* gpu=Query(U_GPU, F_VALUE); |
| if (pointerp(gpu)) |
| return MAX(1,(amount*gpu[0])/gpu[1]); |
| return amount*gpu; |
| } |
| |
| static int _query_plural() |
| { |
| int i = QueryProp(U_REQ); |
| return (i<=1 ? 0 : i); |
| } |
| |
| // gibt string | string* zurueck. |
| static string|string* _query_name() |
| { |
| if (QueryProp(U_REQ)==1) |
| return "%s%s"+Query(P_NAME)[0]; |
| return "%d %s"+Query(P_NAME)[1]; |
| } |
| |
| // gibt string | string* zurueck. |
| static string|string* _set_name(mixed names) |
| { |
| if(!names) |
| return Set(P_NAME,({"",""})); |
| if(stringp(names)) |
| return Set(P_NAME,({names,names})); |
| if(pointerp(names)) |
| switch(sizeof(names)) { |
| case 0: return Set(P_NAME,({"",""})); |
| case 1: if(!stringp(names[0])) |
| names[0]=""; |
| return Set(P_NAME,({names[0],names[0]})); |
| default: if(!stringp(names[0])) |
| names[0]=""; |
| if(!stringp(names[1])) |
| names[1]=""; |
| return Set(P_NAME,names[0..1]); |
| } |
| return QueryProp(P_NAME); |
| } |
| |
| // die Funktionen |
| |
| void AddSingularId(mixed str) |
| { |
| string **ids=Query(U_IDS); |
| if (!pointerp(str)) |
| str=({str}); |
| Set(U_IDS,({ids[0]+str,ids[1]})); |
| } |
| |
| void RemoveSingularId(mixed str) |
| { |
| if(stringp(str)) |
| str=({str}); |
| if(pointerp(str)) |
| Set(U_IDS,({Query(U_IDS)[0]-str,Query(U_IDS)[1]})); |
| } |
| |
| void AddPluralId(mixed str) |
| { |
| string **ids; |
| if (!pointerp(str)) |
| str=({str}); |
| ids=Query(U_IDS); |
| Set(U_IDS,({ids[0],ids[1]+str})); |
| } |
| |
| void RemovePluralId(mixed str) |
| { |
| if(stringp(str)) |
| str=({str}); |
| if(pointerp(str)) |
| Set(U_IDS,({Query(U_IDS)[0],Query(U_IDS)[1]-str})); |
| } |
| |
| void SetCoinsPerUnits(int coins,int units) |
| { |
| if (coins<0||units<=0) return; |
| if (units==1) |
| Set(U_CPU, coins); |
| else Set(U_CPU,({coins,units})); |
| } |
| |
| void SetGramsPerUnits(int grams, int units) |
| { |
| if (grams<0||units<=0) return; |
| if (units==1) |
| Set(U_GPU, grams); |
| else Set(U_GPU,({grams,units})); |
| } |
| |
| int *QueryCoinsPerUnits() |
| { |
| mixed cpu; |
| cpu=Query(U_CPU); |
| if (intp(cpu)) return ({ cpu, 1 }); |
| return cpu; |
| } |
| |
| int *QueryGramsPerUnits() |
| { |
| mixed gpu; |
| gpu=Query(U_GPU); |
| if (intp(gpu)) return ({ gpu, 1 }); |
| return gpu; |
| } |
| |
| void AddAmount(int am) { |
| SetProp(P_AMOUNT, am+Query(P_AMOUNT)); |
| } |
| |
| int IsUnit() { |
| return 1; |
| } |
| |
| int IsEqual(object ob) |
| // haben ob und dieses Objekte die gleiche Blueprint? |
| { |
| if (ob==this_object()) return 0; // das ist ZU gleich :) |
| return (BLUE_NAME(ME)==BLUE_NAME(ob)); |
| } |
| |
| // ueberschreiben von Standardmethoden |
| |
| varargs string name(int fall, int demo) |
| { |
| int req; |
| mixed n_adj; |
| string adj; |
| |
| if ((req=QueryProp(U_REQ))<1) return 0; |
| if (fall!=RAW && |
| pointerp(n_adj=QueryProp(P_NAME_ADJ)) && sizeof(n_adj) ) |
| adj = implode(map(n_adj, #'DeclAdj, fall, demo && req==1), ""); |
| else |
| adj = ""; |
| |
| if (req==1) |
| return sprintf(QueryProp(P_NAME), |
| (fall==RAW || !QueryProp(P_ARTICLE) |
| ? "" : QueryArticle(fall,demo,1)), adj) /* +korrektur */; |
| |
| if (fall!=WEM) |
| return sprintf(QueryProp(P_NAME), req, adj); |
| else { |
| int last; |
| last=Query(P_NAME)[1][<1]; |
| return sprintf(QueryProp(P_NAME), req, adj) |
| +(last!='s' && last!='n' ? "n" : ""); |
| } |
| } |
| |
| varargs string QueryPronoun(int casus) |
| { |
| if (QueryProp(U_REQ)==1) |
| return ::QueryPronoun(casus); |
| switch(casus) { |
| case WESSEN: return "ihrer"; |
| case WEM: return "ihnen"; |
| //default: return "sie"; |
| } |
| return("sie"); //fall-through |
| } |
| |
| string short() |
| { |
| if (QueryProp(U_REQ)<1 || QueryProp(P_INVIS)) return 0; |
| return capitalize(name(WER,0))+".\n"; |
| /* |
| if (req>1) return sprintf(QueryProp(P_NAME), req)+".\n"; |
| return capitalize(sprintf(QueryProp(P_NAME), QueryArticle(WER,0,1)))+".\n"; |
| */ |
| } |
| |
| varargs string long() |
| { |
| return (QueryProp(P_LONG) ? process_string(QueryProp(P_LONG)) : "")+ |
| sprintf("Du siehst %s.\n",name(WEN)); |
| } |
| |
| varargs int id(string str,int lvl) |
| { |
| |
| string s1,s2,**ids; |
| int i; |
| |
| if (!str) return 0; |
| |
| // Wenn kein pos. Amount, hat dieses Objekt keine IDs mehr, damit es nicht |
| // mehr ansprechbar ist. |
| int amount=QueryProp(P_AMOUNT); |
| if (amount < 1) |
| return 0; |
| |
| if (::id(str)) { |
| SetProp(U_REQ, Query(P_AMOUNT,F_VALUE)); |
| return 1; |
| } |
| |
| ids=Query(U_IDS); |
| if (!ids) |
| return 0; |
| |
| if (match_item(str, ids[1] )) { |
| SetProp(U_REQ, amount); |
| return 1; |
| } |
| if (match_item(str, ids[0] )) { |
| SetProp(U_REQ,1); |
| return 1; |
| } |
| if (sscanf(str,"%s %s",s1,s2) && s1[0..3]=="alle" && |
| match_item(s2, ids[1] )) { |
| SetProp(U_REQ, amount); |
| return 1; |
| } |
| if (sscanf(str,"%d %s",i,s1)==2 && i==1 && match_item(s1, ids[0] )) { |
| SetProp(U_REQ,1); |
| return 1; |
| } |
| if (sscanf(str,"%d %s",i,s1)==2 && match_item(s1, ids[1] ) && |
| i<=amount && i>0) { |
| SetProp(U_REQ,i); |
| return 1; |
| } |
| return 0; |
| } |
| |
| // Status fuer move... *seufz* |
| int _orig_amount, _move_requested; |
| |
| varargs int move(object|string dest,int method) |
| { |
| _orig_amount = QueryProp(P_AMOUNT); |
| // Wenn M_MOVE_ALL gesetzt ist, wird IMMER ALLES bewegt. |
| if (method & M_MOVE_ALL) |
| _move_requested = _orig_amount; |
| else |
| _move_requested = QueryProp(U_REQ); |
| |
| ZDEBUG(sprintf("move from %O to %O: amount %d, req %d\n",environment(),dest,_orig_amount,_move_requested)); |
| // Wenn nicht alles bewegt werden soll, wird die Menge dieses Objektes |
| // erstmal reduziert und bewegt. Erst nach der Bewegung wird der Rest dann |
| // im alten Environment neu erzeugt. |
| if ( _orig_amount > _move_requested ) |
| { |
| // wenn in einem alten Paket das Gewicht noch nicht neu berechnet |
| // wurde muss dies geschehn solange die Muenzen im Paket noch das |
| // volle Gewicht haben... |
| if ( environment() ) |
| environment()->query_weight_contents(); |
| // ab jetzt nur auf <_move_requested> Einheiten arbeiten |
| Set( P_AMOUNT, _move_requested, F_VALUE); |
| ZDEBUG(sprintf("move: amount set to %d\n",_move_requested)); |
| } |
| |
| int res = ::move( dest, method ); |
| |
| if ( res != MOVE_OK ) |
| { |
| // Fehlgeschlagene Bewegung ist doof. |
| // ggf. verfruehte Aenderung (P_AMOUNT oben auf <U_REQ> Einheiten |
| // reduziert) rueckgaengig machen |
| Set( P_AMOUNT, _orig_amount, F_VALUE ); |
| ZDEBUG(sprintf("move: not OK, amount restored to %d\n",_orig_amount)); |
| return res; |
| } |
| |
| // TODO: eigentlich sollte es nicht passieren, dass die Menge jetzt negagtiv |
| // ist. Aber bei Geld kann es durch vereinigen mit Geldboerse/Geldkarten |
| // passieren und das ist kein Fehler. Koennte man evtl. mal differenziert |
| // pruefen. |
| int finalamount= QueryProp(P_AMOUNT); |
| /*if ( finalamount < 1 ) |
| { |
| ZDEBUG(sprintf("move: zerstoerung, amount %d\n",finalamount)); |
| remove(1); |
| return ME_WAS_DESTRUCTED; |
| } |
| */ |
| ZDEBUG(sprintf("move: OK, amount %d\n",finalamount)); |
| return res; |
| } |
| |
| |
| protected void NotifyMove(object dest, object oldenv, int method) |
| { |
| // Erst einen evtl. nicht zu bewegenden Rest im alten Environment wieder erzeugen. |
| if (oldenv && _orig_amount > _move_requested) |
| { |
| if ( oldenv == dest ) |
| { |
| // Objekt wurde nur an den Anfang des inventory bewegt, sonst nichts. |
| // ggf. verfruehte Aenderung (oben auf <req> Einheiten reduziert) |
| // rueckgaengig machen |
| ZDEBUG(sprintf("move: same env, amount restored to %d\n",_orig_amount)); |
| Set( P_AMOUNT, _orig_amount, F_VALUE ); |
| } |
| else |
| { |
| // verbleibende Einheiten in einem neuen Objekte wieder zurueck ins |
| // alte Environment zurueck bewgen |
| object temp; |
| temp = clone_object(BLUE_NAME(ME)); |
| temp->SetProp( P_AMOUNT, _orig_amount-_move_requested ); |
| temp->move( oldenv, M_NOCHECK ); |
| ZDEBUG(sprintf("move: Restmenge im alten Env erzeugt, amount %d\n",_orig_amount-_move_requested)); |
| } |
| } |
| |
| // Und jetzt ggf. mit den anderen Units gleichen Typs im neuen Environment |
| // vereinigen. |
| foreach(object item: all_inventory(environment())) |
| { |
| if ( IS_EQUAL(item) ) |
| { |
| // Es ist ein Feature, dass auch mit Objekten mit negativen Amount |
| // vereinigt wird. |
| ZDEBUG(sprintf("move: vereinige mit %O (%d)\n", |
| item,item->QueryProp(P_AMOUNT))); |
| int mergedamount = QueryProp(P_AMOUNT) + item->QueryProp(P_AMOUNT); |
| item->Set( P_AMOUNT, 0, F_VALUE); |
| item->remove(1); |
| |
| SetProp( P_AMOUNT, mergedamount); |
| // U_REQ ist jetzt auch zurueckgesetzt. |
| |
| ZDEBUG(sprintf("move: nach vereinigung, amount %d\n",mergedamount)); |
| } |
| } |
| |
| // wenn man in frisch geclonten Units die noch kein environment haben |
| // per Hand U_REQ auf einen Wert != P_AMOUNT setzt, so gehen die |
| // restlichen Einheiten verloren (es gibt kein Environment, in das man die |
| // Resteinheiten zurueck bewegen koennte). |
| |
| // Und jetzt mal Decaykrams machen... |
| |
| // wenn NO_DECAY_UNTIL_MOVE an ist und dieses ein Move ist, was von einem |
| // Env in ein anderes Env geht, loeschen. Nicht geloescht wird |
| // hingegen, wenn das move() in das allererste Env erfolgt (nach dem Clonen) |
| if ( (QueryProp(P_UNIT_DECAY_FLAGS) & NO_DECAY_UNTIL_MOVE) |
| && objectp(dest) && objectp(oldenv) && dest != oldenv) |
| SetProp(P_UNIT_DECAY_FLAGS, |
| QueryProp(P_UNIT_DECAY_FLAGS) & ~NO_DECAY_UNTIL_MOVE ); |
| ::NotifyMove(dest, oldenv, method); |
| } |
| |
| |
| void reset() { |
| if (!clonep(ME)) { |
| // Blueprint ist Master fuer zerfallende Unitobjekte |
| // das Decay sollte besser nicht durch manuellen Aufruf in der BP |
| // ausgeloest werden, daher Pruefung hier (PO == ME, falls der Reset vom |
| // Driver kommt). |
| if (previous_object() && previous_object() != ME) |
| return; |
| int zeit = QueryProp(P_UNIT_DECAY_INTERVAL); |
| if (zeit > 0) |
| { |
| set_next_reset(zeit); |
| // Das Callout muss auf jeden Fall gemacht werden, wenn ein Decay |
| // Intervall gesetzt ist, damit die Blueprint auch den naechsten Reset |
| // kriegt, auch wenn es jetzt keine Clone gibt. Wenn es kein Quota gibt, |
| // kann der Callout wegfallen, beim Setzen eines Quota wird ja eine |
| // Funktion an diesem Objekt gerufen. |
| if (QueryProp(P_UNIT_DECAY_QUOTA) > 0) |
| call_out(#'_call_DoDecay, 1, 0); |
| } |
| } |
| else { |
| // Clones |
| if (Query(P_AMOUNT,F_VALUE)<1) remove(1); |
| else ::reset(); |
| } |
| } |
| |
| varargs int remove(int silent) |
| { |
| int amount = QueryProp(P_AMOUNT); |
| int req = QueryProp(U_REQ); |
| if (amount > req) |
| { |
| ZDEBUG(sprintf("remove: reduziere amount %d um %d -> %d\n", |
| amount, req, amount-req )); |
| SetProp(P_AMOUNT, amount - req); |
| return 1; |
| } |
| ZDEBUG(sprintf("remove: restlos weg.\n")); |
| return ::remove(silent); |
| } |
| |
| // sollte nicht von aussen gerufen werden. |
| private void _call_DoDecay(object *klone) { |
| ZDEBUG(sprintf("call_DoDecay() in %O\n",ME)); |
| // Clone oder kein Decay konfiguriert? |
| if (clonep() |
| || QueryProp(P_UNIT_DECAY_FLAGS) & NO_DECAY) |
| return; |
| |
| if (!pointerp(klone)) |
| klone = clones(2); |
| // Klone da? |
| int i=sizeof(klone); |
| if (!i) |
| return; |
| |
| // in allen Klonen DoDecay rufen |
| while(get_eval_cost() > __MAX_EVAL_COST__/2 && i--) { |
| if (objectp(klone[i])) |
| catch(call_other(klone[i],"DoDecay", 0);publish); |
| } |
| // das i ist schon abgearbeitet. |
| i--; |
| // noch was uebrig? |
| if (i >= 0) |
| call_out(#'_call_DoDecay, 4, klone[0..i]); |
| } |
| |
| // zerstoert quota Prozent der vorhandenen Units, liefert die Restmenge |
| // zurueck. Ruft ggf. DoDecayMessage() |
| public int DoDecay(int silent) { |
| // nur fuer Clones |
| if (!clonep()) |
| return 0; |
| ZDEBUG(sprintf("DoDecay() in %O\n",ME)); |
| |
| // wenn das Objekt NO_DECAY oder NO_DECAY_UNTIL_MOVE in den Flags |
| // zerfaellt nix. |
| int flags = QueryProp(P_UNIT_DECAY_FLAGS); |
| if ((flags & NO_DECAY) || (flags & NO_DECAY_UNTIL_MOVE) ) |
| return QueryProp(P_AMOUNT); |
| |
| int quota = QueryProp(P_UNIT_DECAY_QUOTA); |
| |
| // Zugewinn ist nicht. Ausserdem kann nicht mehr zerfallen, als da ist... |
| // Also ohne gueltiges Quota raus. Nur bei abs. Zerfall sind Zahlen > 10000 |
| // erlaubt, bei relativen Zerfall waere das sinnlos. |
| if (quota <= 0 || |
| (quota > 10000 && !(flags & ABSOLUTE_DECAY) ) ) |
| return QueryProp(P_AMOUNT); |
| |
| int amount = QueryProp(P_AMOUNT); |
| int minimum = QueryProp(P_UNIT_DECAY_MIN); |
| // Zerfall nur, wenn man mehr als das Minimum hat. |
| if (amount > minimum) { |
| int zerfall; |
| if (flags & ABSOLUTE_DECAY) { |
| // Decay Quota soll einfach als abs. Zahl aufgefasst werden: |
| zerfall = quota; |
| } |
| else if (flags & INACCURATE_DECAY) { |
| // Rundungsfehler ignorieren und dafuer immer min. eine Einheit |
| // zerfallen lassein |
| zerfall = (amount * quota) / 10000; |
| if (zerfall <= 0) zerfall = 1; |
| } |
| else { |
| // Standardfall: |
| // nicht-ganzzahligen Rest als Wahrscheinlichkeit fuer den Zerfall einer |
| // Einheit auffassen |
| float tmp = amount * quota / 10000.0; |
| zerfall = to_int(tmp); |
| tmp -= zerfall; // Rest in tmp |
| // tmp*n ist eine Zahl zwischen 0 und n, wenn tmp*n > random(n)+1, |
| // dann zerfaellt eine Einheit extra. Da das Random fuer grosse Zahlen |
| // besser verteilt ist, nehm ich n = __INT_MAX__ |
| if (ceil(tmp * __INT_MAX__) > random(__INT_MAX__) + 1) |
| zerfall++; |
| } |
| |
| // nicht unter Minimum zerfallen |
| if (amount - zerfall < minimum) |
| zerfall = amount - minimum; |
| |
| // erst ggf. Meldung ausgeben. |
| if (!silent && zerfall > 0) |
| DoDecayMessage(amount, zerfall); |
| // dann runtersetzen. |
| SetProp(P_AMOUNT, amount - zerfall); |
| ZDEBUG(sprintf("%O decayed by %d\n",ME, zerfall)); |
| return amount-zerfall; |
| } |
| else if (amount < 0) |
| return 0; // neg. Anzahl gilt als "0 uebrig". |
| |
| // sonst ists wohl zwischen 0 und minimum, nix aendert sich. |
| return amount; |
| } |
| |
| // gibt die Zerfallsmeldung aus. Wenn man mit der Standardmeldung nicht zufrieden |
| // ist (duerfte der Normalfall sein), sollte man diese Funktion |
| // ueberschreiben. Bekommt bisherige und jetzt gerade zerfallene Menge |
| // uebergeben. Wichtig: zu diesem Zeitpunkt hat sich an der Unit noch nix (!) |
| // geaendert! |
| protected void DoDecayMessage(int oldamount, int zerfall) { |
| string msg; |
| if (oldamount == zerfall) { |
| if (living(environment())) { |
| tell_object(environment(), break_string(sprintf( |
| "Auf einmal %s%s zu Staub!", |
| (oldamount>1?"zerfallen Deine ":"zerfaellt D"), name(WER)),78)); |
| } |
| // das tell_room() muss auf jeden fall sein, weil es "lebende" Raeume |
| // gibt. Liegt der KRam in einem solchen wuerden die Livings in diesem Raum |
| // sonst keine meldung kriegen. |
| tell_room(environment(), break_string(sprintf( |
| "Auf einmal %s %s zu Staub!", |
| (oldamount>1?"zerfallen":"zerfaellt"), name(WER)),78), |
| ({environment()})); |
| } |
| else { |
| if (living(environment())) { |
| tell_object(environment(), break_string(sprintf( |
| "Auf einmal %s %d Deiner %s zu Staub!", |
| (zerfall>1?"zerfallen":"zerfaellt"), |
| zerfall, Query(P_NAME)[1]),78)); |
| } |
| // das tell_room() muss auf jeden fall sein, weil es "lebende" Raeume |
| // gibt. Liegt der KRam in einem solchen wuerden die Livings in diesem Raum |
| // sonst keine meldung kriegen. |
| tell_room(environment(), break_string(sprintf( |
| "Auf einmal %s %d %s zu Staub!", |
| (zerfall>1?"zerfallen":"zerfaellt"), |
| zerfall, Query(P_NAME)[1]),78), ({environment()}) ); |
| } |
| } |
| |
| static int _query_unit_decay_interval() { |
| if (clonep()) { |
| // fuer clones den Wert aus der BP liefern, der Wert in Clones ist eh |
| // uninteressant. |
| if (objectp(blueprint())) |
| return blueprint()->QueryProp(P_UNIT_DECAY_INTERVAL); |
| else |
| return load_object(load_name())->QueryProp(P_UNIT_DECAY_INTERVAL); |
| } |
| return Query(P_UNIT_DECAY_INTERVAL); |
| } |
| |
| static int _set_unit_decay_interval(int zeit) { |
| // fuer Clones ist die Prop sinnlos und kann nicht gesetzt werden. |
| if (clonep()) { |
| if (objectp(blueprint())) |
| return blueprint()->QueryProp(P_UNIT_DECAY_INTERVAL); |
| else |
| return load_object(load_name())->QueryProp(P_UNIT_DECAY_INTERVAL); |
| } |
| // ueber diese Prop liesse sich der Reset relativ beliebig veraendern, |
| // verhindern, etc. Daher darf sie nur von diesem Objekt gesetzt werden, von |
| // Weisen+ oder eines Objektes, das die gleiche UID hat wie dieses hier oder |
| // des Programmieres dieses Objekts oder eines Magiers, der berechtigt fuer |
| // die jeweilige UID ist. Letztere beiden werden ueber den Ruf von |
| // QueryUIDsForWizard() ermittelt. |
| // erstes fremdes Objekt finden und pruefen. |
| foreach(object po: caller_stack(1)) { |
| if (po != ME) { |
| // fremden Aufrufer gefunden |
| if (getuid(po) != getuid(ME) |
| && member(master()->QueryUIDsForWizard(getuid(po)),getuid(ME)) == -1 |
| && (!this_interactive() || !IS_ELDER(this_interactive()) ) ) |
| // unberechtigt, Abbruch |
| return QueryProp(P_UNIT_DECAY_INTERVAL); |
| else |
| // nur das erste ext. Objekt in der Callkette wird geprueft, raus. |
| break; |
| } |
| } |
| set_next_reset(zeit); |
| // falls dies aus dem create() gesetzt wird, muss zeitverzoegert eine |
| // Funktion von aussen am Objekt gerufen werden, da nach einem create() das |
| // Objekt als resettet gilt und sonst keinen Reset kriegt. |
| call_out("_query_unit_decay_interval",1); |
| return Set(P_UNIT_DECAY_INTERVAL, zeit, F_VALUE); |
| } |
| |
| static int _query_unit_decay_quota() { |
| if (clonep()) { |
| // hat dieses Objekt einen eigenen wert gespeichert? |
| int quota=Query(P_UNIT_DECAY_QUOTA, F_VALUE); |
| if (quota) |
| return quota; |
| // sonst den Wert aus der Blueprint |
| if (objectp(blueprint())) |
| return blueprint()->QueryProp(P_UNIT_DECAY_QUOTA); |
| else |
| return load_object(load_name())->QueryProp(P_UNIT_DECAY_QUOTA); |
| } |
| return Query(P_UNIT_DECAY_QUOTA, F_VALUE); |
| } |
| |
| static int _set_unit_decay_quota(int quota) { |
| // momentan nur quota zwischen 0 und 10000 |
| if (quota >= 0 && quota <=10000) |
| return Set(P_UNIT_DECAY_QUOTA, quota, F_VALUE); |
| else |
| return Query(P_UNIT_DECAY_QUOTA, F_VALUE); |
| } |
| |
| static int _query_unit_decay_min() { |
| if (clonep()) { |
| // hat dieses Objekt einen eigenen wert gespeichert? |
| int minimum=Query(P_UNIT_DECAY_MIN, F_VALUE); |
| if (minimum) |
| return minimum; |
| // sonst den Wert aus der Blueprint |
| if (objectp(blueprint())) |
| return blueprint()->QueryProp(P_UNIT_DECAY_MIN); |
| else |
| return load_object(load_name())->QueryProp(P_UNIT_DECAY_MIN); |
| } |
| return Query(P_UNIT_DECAY_MIN, F_VALUE); |
| } |
| |
| static int _query_unit_decay_flags() { |
| if (clonep()) { |
| // hat dieses Objekt einen eigenen wert gespeichert? |
| int flags=Query(P_UNIT_DECAY_FLAGS, F_VALUE); |
| if (flags) |
| return flags; |
| // sonst den Wert aus der Blueprint |
| if (objectp(blueprint())) |
| return blueprint()->QueryProp(P_UNIT_DECAY_FLAGS); |
| else |
| return load_object(load_name())->QueryProp(P_UNIT_DECAY_FLAGS); |
| } |
| // Die BP liefert den Wert auf jeden Fall ohne NO_DECAY_UNTIL_MOVE zurueck, |
| // weil dieses Flag im Falle der BP nicht zurueckgesetzt wird und bei Clients |
| // ohne eigene Flags der Zerfall stoppen wuerde. |
| return Query(P_UNIT_DECAY_FLAGS, F_VALUE) & ~NO_DECAY_UNTIL_MOVE; |
| } |
| |