blob: ae715f2eb5bcaaa09b5c1e5ac780d2806652d882 [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001// MorgenGrauen MUDlib
2//
3// unit.c -- Basisklasse fuer Mengenobjekte
4// (neue Version von Padreic)
5//
6// $Id: unit.c 9077 2015-01-16 23:26:00Z Zesstra $
7#pragma strong_types,save_types,rtt_checks
8#pragma range_check
9#pragma no_clone
10#pragma pedantic
11
12inherit "/std/thing";
13
14#define NEED_PROTOTYPES
15#include <unit.h>
16#undef NEED_PROTOTYPES
17
18#include <properties.h>
19#include <thing/properties.h>
20#include <defines.h>
21#include <language.h>
22#include <moving.h>
23#include <wizlevels.h>
24#include <debug_info.h>
25
26// zum debuggen und extra public
27public string debugmode;
28public string __set_debug(string recv) {return debugmode=recv;}
29#include <living/comm.h>
30#define ZDEBUG(x) if (stringp(debugmode) && find_player(debugmode)) \
31 find_player(debugmode)->ReceiveMsg(x,MT_DEBUG,0,object_name()+": ",ME)
32//#define ZDEBUG(x)
33
34private void _call_DoDecay(object *klone);
35
36private nosave string lastverb;
37private nosave int lastevalnumber;
38
39protected void create()
40{
41 ::create();
42 SetProp(U_IDS,({({}),({})}));
43 SetProp(P_GENDER, 1);
44 SetProp(P_AMOUNT, 1);
45 // Props sollten nicht direkt manipuliert werden, nur ueber Set-Methoden
46 Set(P_UNIT_DECAY_INTERVAL, PROTECTED, F_MODE_AS);
47 Set(P_UNIT_DECAY_QUOTA, PROTECTED, F_MODE_AS);
48}
49
50protected void create_super() {
51 set_next_reset(-1);
52}
53
54//// Query und Set Funktionen fuer die Propertys
55
56static void check_leave()
57{ if (Query(P_AMOUNT,F_VALUE)<1) remove(1); }
58
59static int _query_invis()
60{
61 if (QueryProp(P_AMOUNT) < 1)
62 return 1;
63 return Query(P_INVIS, F_VALUE);
64}
65
66static int _set_amount(int am)
67{
68 if (am<1)
69 call_out("check_leave",1);
70 SetProp(U_REQ, am);
71 return Set(P_AMOUNT,am, F_VALUE);
72}
73
74static int _set_u_req(int ureq)
75{
76 lastverb = query_verb();
77 lastevalnumber = debug_info(DINFO_EVAL_NUMBER);
78 return Set(U_REQ, ureq, F_VALUE);
79}
80
81static int _query_u_req()
82{
83 // Zwei Dinge benutzten, um zu entscheiden, ob U_REQ noch gueltig ist oder
84 // besser auf P_AMOUNT zurueckgesetzt werden sollte: die DINFO_EVAL_NUMBER
85 // und das Kommandoverb. Wenn eines von beiden sich geaendert hat, wird
86 // U_REQ als ungueltig betrachtet. (Und dies bleibt ein uebler Hack.)
87 if (lastevalnumber != debug_info(DINFO_EVAL_NUMBER)
88 || lastverb != query_verb())
89 {
90 return SetProp(U_REQ, Query(P_AMOUNT, F_VALUE));
91 }
92 return Query(U_REQ, F_VALUE);
93}
94
95// Gesamtwert der gerade mit U_REQ ausgewaehlten unitobjekte
96static int _query_value()
97{
98 mixed cpu;
99 cpu=Query(U_CPU);
100 if (intp(cpu)) return QueryProp(U_REQ) * cpu;
101 if (!pointerp(cpu)) return 0;
102 return (QueryProp(U_REQ) * cpu[0])/cpu[1];
103}
104
105static int _set_value(int num) {
106// Setzt den Wert fuer die derzeitige Anzahl
107 SetCoinsPerUnits(num, QueryProp(U_REQ));
108 return QueryProp(P_VALUE);
109}
110
111static int _query_weight()
112{
113 mixed gpu, req;
114 if ((req=QueryProp(U_REQ))<1) return 0;
115 gpu=Query(U_GPU);
116 if (intp(gpu)) return req * gpu;
117 if (!pointerp(gpu)) return 0;
118 return MAX(1,(req*gpu[0])/gpu[1]);
119}
120
121static int _set_weight(int num) {
122// Setzt das Gewicht fuer die derzeitige Anzahl
123 SetGramsPerUnits(num, QueryProp(U_REQ));
124 return QueryProp(P_WEIGHT);
125}
126
127static int _query_total_weight()
128{
129 mixed gpu, amount;
130 if ((amount=Query(P_AMOUNT))<1) return 0;
131 gpu=Query(U_GPU);
132 if (intp(gpu))
133 return amount*(int)gpu;
134 if (!pointerp(gpu)) return 0;
135 return MAX(1,(amount*gpu[0])/gpu[1]);
136}
137
138static int _query_plural()
139{
140 int i;
141 i=QueryProp(U_REQ); // wichtig _nicht_ QueryProp
142 return (i<=1 ? 0 : i);
143}
144
145// gibt string | string* zurueck.
146static string|string* _query_name()
147{
148 if (QueryProp(U_REQ)==1)
149 return "%s%s"+((string *)Query(P_NAME))[0];
150 return "%d %s"+((string *)Query(P_NAME))[1];
151}
152
153// gibt string | string* zurueck.
154static string|string* _set_name(mixed names)
155{
156 if(!names)
157 return Set(P_NAME,({"",""}));
158 if(stringp(names))
159 return Set(P_NAME,({names,names}));
160 if(pointerp(names))
161 switch(sizeof(names)) {
162 case 0: return Set(P_NAME,({"",""}));
163 case 1: if(!stringp(names[0]))
164 names[0]="";
165 return Set(P_NAME,({names[0],names[0]}));
166 default: if(!stringp(names[0]))
167 names[0]="";
168 if(!stringp(names[1]))
169 names[1]="";
170 return Set(P_NAME,names[0..1]);
171 }
172 return QueryProp(P_NAME);
173}
174
175// die Funktionen
176
177void AddSingularId(mixed str)
178{
179 string *ids;
180 if (!pointerp(str))
181 str=({str});
182 ids=Query(U_IDS);
183 Set(U_IDS,({ids[0]+str,ids[1]}));
184}
185
186void RemoveSingularId(mixed str)
187{
188 if(stringp(str))
189 str=({str});
190 if(pointerp(str))
191 Set(U_IDS,({Query(U_IDS)[0]-str,Query(U_IDS)[1]}));
192}
193
194void AddPluralId(mixed str)
195{
196 string *ids;
197
198 if (!pointerp(str))
199 str=({str});
200 ids=Query(U_IDS);
201 Set(U_IDS,({ids[0],ids[1]+str}));
202}
203
204void RemovePluralId(mixed str)
205{
206 if(stringp(str))
207 str=({str});
208 if(pointerp(str))
209 Set(U_IDS,({Query(U_IDS)[0],Query(U_IDS)[1]-str}));
210}
211
212void SetCoinsPerUnits(int coins,int units)
213{
214 if (coins<0||units<=0) return;
215 if (units==1)
216 Set(U_CPU, coins);
217 else Set(U_CPU,({coins,units}));
218}
219
220void SetGramsPerUnits(int grams, int units)
221{
222 if (grams<0||units<=0) return;
223 if (units==1)
224 Set(U_GPU, grams);
225 else Set(U_GPU,({grams,units}));
226}
227
228int *QueryCoinsPerUnits()
229{
230 mixed cpu;
231 cpu=Query(U_CPU);
232 if (intp(cpu)) return ({ cpu, 1 });
233 return cpu;
234}
235
236int *QueryGramsPerUnits()
237{
238 mixed gpu;
239 gpu=Query(U_GPU);
240 if (intp(gpu)) return ({ gpu, 1 });
241 return gpu;
242}
243
244void AddAmount(int am) {
245 SetProp(P_AMOUNT, am+Query(P_AMOUNT));
246}
247
248int IsUnit() {
249 return 1;
250}
251
252int IsEqual(object ob)
253// haben ob und dieses Objekte die gleiche Blueprint?
254{
255 if (ob==this_object()) return 0; // das ist ZU gleich :)
256 return (BLUE_NAME(ME)==BLUE_NAME(ob));
257}
258
259// ueberschreiben von Standardmethoden
260
261varargs string name(int fall, int demo)
262{
263 int req;
264 mixed n_adj;
265 string adj;
266
267 if ((req=QueryProp(U_REQ))<1) return 0;
268 if (fall!=RAW &&
269 pointerp(n_adj=QueryProp(P_NAME_ADJ)) && sizeof(n_adj) )
270 adj = implode(map(n_adj, #'DeclAdj, fall, demo && req==1), "");
271 else
272 adj = "";
273
274 if (req==1)
275 return sprintf(QueryProp(P_NAME),
276 (fall==RAW || !QueryProp(P_ARTICLE)
277 ? "" : QueryArticle(fall,demo,1)), adj) /* +korrektur */;
278
279 if (fall!=WEM)
280 return sprintf(QueryProp(P_NAME), req, adj);
281 else {
282 int last;
283 last=Query(P_NAME)[1][<1];
284 return sprintf(QueryProp(P_NAME), req, adj)
285 +(last!='s' && last!='n' ? "n" : "");
286 }
287}
288
289varargs string QueryPronoun(int casus)
290{
291 if (QueryProp(U_REQ)==1)
292 return ::QueryPronoun(casus);
293 switch(casus) {
294 case WESSEN: return "ihrer";
295 case WEM: return "ihnen";
296 //default: return "sie";
297 }
298 return("sie"); //fall-through
299}
300
301string short()
302{
303 if (QueryProp(U_REQ)<1 || QueryProp(P_INVIS)) return 0;
304 return capitalize(name(WER,0))+".\n";
305 /*
306 if (req>1) return sprintf(QueryProp(P_NAME), req)+".\n";
307 return capitalize(sprintf(QueryProp(P_NAME), QueryArticle(WER,0,1)))+".\n";
308 */
309}
310
311varargs string long()
312{
313 return (QueryProp(P_LONG) ? process_string(QueryProp(P_LONG)) : "")+
314 sprintf("Du siehst %s.\n",name(WEN));
315}
316
317varargs int id(string str,int lvl)
318{
319
320 string s1,s2,*ids;
321 int i;
322
323 if (!str) return 0;
324
325 // Wenn kein pos. Amount, hat dieses Objekt keine IDs mehr, damit es nicht
326 // mehr ansprechbar ist.
327 int amount=QueryProp(P_AMOUNT);
328 if (amount < 1)
329 return 0;
330
331 if (::id(str)) {
332 SetProp(U_REQ, Query(P_AMOUNT,F_VALUE));
333 return 1;
334 }
335
336 ids=Query(U_IDS);
337 if (!ids)
338 return 0;
339
340 //die casts auf 'mixed' sind absicht. Sonst geht der Driver offenbar davon
341 //aus, dass ids[1] ein String ist. Es ist aber aber ein Array von Strings
342 //und genau das will auch match_item() haben. ;-) Zesstra
343 if (match_item(str,(mixed)ids[1] )) {
344 SetProp(U_REQ, amount);
345 return 1;
346 }
347 if (match_item(str,(mixed)ids[0] )) {
348 SetProp(U_REQ,1);
349 return 1;
350 }
351 if (sscanf(str,"%s %s",s1,s2) && s1[0..3]=="alle" &&
352 match_item(s2,(mixed)ids[1] )) {
353 SetProp(U_REQ, amount);
354 return 1;
355 }
356 if (sscanf(str,"%d %s",i,s1)==2 && i==1 && match_item(s1,(mixed)ids[0] )) {
357 SetProp(U_REQ,1);
358 return 1;
359 }
360 if (sscanf(str,"%d %s",i,s1)==2 && match_item(s1,(mixed)ids[1] ) &&
361 i<=amount && i>0) {
362 SetProp(U_REQ,i);
363 return 1;
364 }
365 return 0;
366}
367
368// Status fuer move... *seufz*
369int _orig_amount, _move_requested;
370
371varargs int move(object|string dest,int method)
372{
373 _orig_amount = QueryProp(P_AMOUNT);
374 // Wenn M_MOVE_ALL gesetzt ist, wird IMMER ALLES bewegt.
375 if (method & M_MOVE_ALL)
376 _move_requested = _orig_amount;
377 else
378 _move_requested = QueryProp(U_REQ);
379
380 ZDEBUG(sprintf("move from %O to %O: amount %d, req %d\n",environment(),dest,_orig_amount,_move_requested));
381 // Wenn nicht alles bewegt werden soll, wird die Menge dieses Objektes
382 // erstmal reduziert und bewegt. Erst nach der Bewegung wird der Rest dann
383 // im alten Environment neu erzeugt.
384 if ( _orig_amount > _move_requested )
385 {
386 // wenn in einem alten Paket das Gewicht noch nicht neu berechnet
387 // wurde muss dies geschehn solange die Muenzen im Paket noch das
388 // volle Gewicht haben...
389 if ( environment() )
390 environment()->query_weight_contents();
391 // ab jetzt nur auf <_move_requested> Einheiten arbeiten
392 Set( P_AMOUNT, _move_requested, F_VALUE);
393 ZDEBUG(sprintf("move: amount set to %d\n",_move_requested));
394 }
395
396 int res = ::move( dest, method );
397
398 if ( res != MOVE_OK )
399 {
400 // Fehlgeschlagene Bewegung ist doof.
401 // ggf. verfruehte Aenderung (P_AMOUNT oben auf <U_REQ> Einheiten
402 // reduziert) rueckgaengig machen
403 Set( P_AMOUNT, _orig_amount, F_VALUE );
404 ZDEBUG(sprintf("move: not OK, amount restored to %d\n",_orig_amount));
405 return res;
406 }
407
408 // TODO: eigentlich sollte es nicht passieren, dass die Menge jetzt negagtiv
409 // ist. Aber bei Geld kann es durch vereinigen mit Geldboerse/Geldkarten
410 // passieren und das ist kein Fehler. Koennte man evtl. mal differenziert
411 // pruefen.
412 int finalamount= QueryProp(P_AMOUNT);
413 /*if ( finalamount < 1 )
414 {
415 ZDEBUG(sprintf("move: zerstoerung, amount %d\n",finalamount));
416 remove(1);
417 return ME_WAS_DESTRUCTED;
418 }
419 */
420 ZDEBUG(sprintf("move: OK, amount %d\n",finalamount));
421 return res;
422}
423
424
425protected void NotifyMove(object dest, object oldenv, int method)
426{
427 // Erst einen evtl. nicht zu bewegenden Rest im alten Environment wieder erzeugen.
428 if (oldenv && _orig_amount > _move_requested)
429 {
430 if ( oldenv == dest )
431 {
432 // Objekt wurde nur an den Anfang des inventory bewegt, sonst nichts.
433 // ggf. verfruehte Aenderung (oben auf <req> Einheiten reduziert)
434 // rueckgaengig machen
435 ZDEBUG(sprintf("move: same env, amount restored to %d\n",_orig_amount));
436 Set( P_AMOUNT, _orig_amount, F_VALUE );
437 }
438 else
439 {
440 // verbleibende Einheiten in einem neuen Objekte wieder zurueck ins
441 // alte Environment zurueck bewgen
442 object temp;
443 temp = clone_object(BLUE_NAME(ME));
444 temp->SetProp( P_AMOUNT, _orig_amount-_move_requested );
445 temp->move( oldenv, M_NOCHECK );
446 ZDEBUG(sprintf("move: Restmenge im alten Env erzeugt, amount %d\n",_orig_amount-_move_requested));
447 }
448 }
449
450 // Und jetzt ggf. mit den anderen Units gleichen Typs im neuen Environment
451 // vereinigen.
452 foreach(object item: all_inventory(environment()))
453 {
454 if ( IS_EQUAL(item) )
455 {
456 // Es ist ein Feature, dass auch mit Objekten mit negativen Amount
457 // vereinigt wird.
458 ZDEBUG(sprintf("move: vereinige mit %O (%d)\n",
459 item,item->QueryProp(P_AMOUNT)));
460 int mergedamount = QueryProp(P_AMOUNT) + item->QueryProp(P_AMOUNT);
461 item->Set( P_AMOUNT, 0, F_VALUE);
462 item->remove(1);
463
464 SetProp( P_AMOUNT, mergedamount);
465 // U_REQ ist jetzt auch zurueckgesetzt.
466
467 ZDEBUG(sprintf("move: nach vereinigung, amount %d\n",mergedamount));
468 }
469 }
470
471 // wenn man in frisch geclonten Units die noch kein environment haben
472 // per Hand U_REQ auf einen Wert != P_AMOUNT setzt, so gehen die
473 // restlichen Einheiten verloren (es gibt kein Environment, in das man die
474 // Resteinheiten zurueck bewegen koennte).
475
476 // Und jetzt mal Decaykrams machen...
477
478 // wenn NO_DECAY_UNTIL_MOVE an ist und dieses ein Move ist, was von einem
479 // Env in ein anderes Env geht, loeschen. Nicht geloescht wird
480 // hingegen, wenn das move() in das allererste Env erfolgt (nach dem Clonen)
481 if ( (QueryProp(P_UNIT_DECAY_FLAGS) & NO_DECAY_UNTIL_MOVE)
482 && objectp(dest) && objectp(oldenv) && dest != oldenv)
483 SetProp(P_UNIT_DECAY_FLAGS,
484 QueryProp(P_UNIT_DECAY_FLAGS) & ~NO_DECAY_UNTIL_MOVE );
485 ::NotifyMove(dest, oldenv, method);
486}
487
488
489void reset() {
490 if (!clonep(ME)) {
491 // Blueprint ist Master fuer zerfallende Unitobjekte
492 // das Decay sollte besser nicht durch manuellen Aufruf in der BP
493 // ausgeloest werden, daher Pruefung hier (PO == ME, falls der Reset vom
494 // Driver kommt).
495 if (previous_object() && previous_object() != ME)
496 return;
497 int zeit = QueryProp(P_UNIT_DECAY_INTERVAL);
498 if (zeit > 0)
499 {
500 set_next_reset(zeit);
501 // Das Callout muss auf jeden Fall gemacht werden, wenn ein Decay
502 // Intervall gesetzt ist, damit die Blueprint auch den naechsten Reset
503 // kriegt, auch wenn es jetzt keine Clone gibt. Wenn es kein Quota gibt,
504 // kann der Callout wegfallen, beim Setzen eines Quota wird ja eine
505 // Funktion an diesem Objekt gerufen.
506 if (QueryProp(P_UNIT_DECAY_QUOTA) > 0)
507 call_out(#'_call_DoDecay, 1, 0);
508 }
509 }
510 else {
511 // Clones
512 if (Query(P_AMOUNT,F_VALUE)<1) remove(1);
513 else ::reset();
514 }
515}
516
517varargs int remove(int silent)
518{
519 int amount = QueryProp(P_AMOUNT);
520 int req = QueryProp(U_REQ);
521 if (amount > req)
522 {
523 ZDEBUG(sprintf("remove: reduziere amount %d um %d -> %d\n",
524 amount, req, amount-req ));
525 SetProp(P_AMOUNT, amount - req);
526 return 1;
527 }
528 ZDEBUG(sprintf("remove: restlos weg.\n"));
529 return ::remove(silent);
530}
531
532// sollte nicht von aussen gerufen werden.
533private void _call_DoDecay(object *klone) {
534 ZDEBUG(sprintf("call_DoDecay() in %O\n",ME));
535 // Clone oder kein Decay konfiguriert?
536 if (clonep()
537 || QueryProp(P_UNIT_DECAY_FLAGS) & NO_DECAY)
538 return;
539
540 if (!pointerp(klone))
541 klone = clones(2);
542 // Klone da?
543 int i=sizeof(klone);
544 if (!i)
545 return;
546
547 // in allen Klonen DoDecay rufen
548 while(get_eval_cost() > __MAX_EVAL_COST__/2 && i--) {
549 if (objectp(klone[i]))
550 catch(call_other(klone[i],"DoDecay", 0);publish);
551 }
552 // das i ist schon abgearbeitet.
553 i--;
554 // noch was uebrig?
555 if (i >= 0)
556 call_out(#'_call_DoDecay, 4, klone[0..i]);
557}
558
559// zerstoert quota Prozent der vorhandenen Units, liefert die Restmenge
560// zurueck. Ruft ggf. DoDecayMessage()
561public int DoDecay(int silent) {
562 // nur fuer Clones
563 if (!clonep())
564 return 0;
565 ZDEBUG(sprintf("DoDecay() in %O\n",ME));
566
567 // wenn das Objekt NO_DECAY oder NO_DECAY_UNTIL_MOVE in den Flags
568 // zerfaellt nix.
569 int flags = QueryProp(P_UNIT_DECAY_FLAGS);
570 if ((flags & NO_DECAY) || (flags & NO_DECAY_UNTIL_MOVE) )
571 return QueryProp(P_AMOUNT);
572
573 int quota = QueryProp(P_UNIT_DECAY_QUOTA);
574
575 // Zugewinn ist nicht. Ausserdem kann nicht mehr zerfallen, als da ist...
576 // Also ohne gueltiges Quota raus. Nur bei abs. Zerfall sind Zahlen > 10000
577 // erlaubt, bei relativen Zerfall waere das sinnlos.
578 if (quota <= 0 ||
579 (quota > 10000 && !(flags & ABSOLUTE_DECAY) ) )
580 return QueryProp(P_AMOUNT);
581
582 int amount = QueryProp(P_AMOUNT);
583 int minimum = QueryProp(P_UNIT_DECAY_MIN);
584 // Zerfall nur, wenn man mehr als das Minimum hat.
585 if (amount > minimum) {
586 int zerfall;
587 if (flags & ABSOLUTE_DECAY) {
588 // Decay Quota soll einfach als abs. Zahl aufgefasst werden:
589 zerfall = quota;
590 }
591 else if (flags & INACCURATE_DECAY) {
592 // Rundungsfehler ignorieren und dafuer immer min. eine Einheit
593 // zerfallen lassein
594 zerfall = (amount * quota) / 10000;
595 if (zerfall <= 0) zerfall = 1;
596 }
597 else {
598 // Standardfall:
599 // nicht-ganzzahligen Rest als Wahrscheinlichkeit fuer den Zerfall einer
600 // Einheit auffassen
601 float tmp = amount * quota / 10000.0;
602 zerfall = to_int(tmp);
603 tmp -= zerfall; // Rest in tmp
604 // tmp*n ist eine Zahl zwischen 0 und n, wenn tmp*n > random(n)+1,
605 // dann zerfaellt eine Einheit extra. Da das Random fuer grosse Zahlen
606 // besser verteilt ist, nehm ich n = __INT_MAX__
607 if (ceil(tmp * __INT_MAX__) > random(__INT_MAX__) + 1)
608 zerfall++;
609 }
610
611 // nicht unter Minimum zerfallen
612 if (amount - zerfall < minimum)
613 zerfall = amount - minimum;
614
615 // erst ggf. Meldung ausgeben.
616 if (!silent && zerfall > 0)
617 DoDecayMessage(amount, zerfall);
618 // dann runtersetzen.
619 SetProp(P_AMOUNT, amount - zerfall);
620 ZDEBUG(sprintf("%O decayed by %d\n",ME, zerfall));
621 return amount-zerfall;
622 }
623 else if (amount < 0)
624 return 0; // neg. Anzahl gilt als "0 uebrig".
625
626 // sonst ists wohl zwischen 0 und minimum, nix aendert sich.
627 return amount;
628}
629
630// gibt die Zerfallsmeldung aus. Wenn man mit der Standardmeldung nicht zufrieden
631// ist (duerfte der Normalfall sein), sollte man diese Funktion
632// ueberschreiben. Bekommt bisherige und jetzt gerade zerfallene Menge
633// uebergeben. Wichtig: zu diesem Zeitpunkt hat sich an der Unit noch nix (!)
634// geaendert!
635protected void DoDecayMessage(int oldamount, int zerfall) {
636 string msg;
637 if (oldamount == zerfall) {
638 if (living(environment())) {
639 tell_object(environment(), break_string(sprintf(
640 "Auf einmal %s%s zu Staub!",
641 (oldamount>1?"zerfallen Deine ":"zerfaellt D"), name(WER)),78));
642 }
643 // das tell_room() muss auf jeden fall sein, weil es "lebende" Raeume
644 // gibt. Liegt der KRam in einem solchen wuerden die Livings in diesem Raum
645 // sonst keine meldung kriegen.
646 tell_room(environment(), break_string(sprintf(
647 "Auf einmal %s %s zu Staub!",
648 (oldamount>1?"zerfallen":"zerfaellt"), name(WER)),78),
649 ({environment()}));
650 }
651 else {
652 if (living(environment())) {
653 tell_object(environment(), break_string(sprintf(
654 "Auf einmal %s %d Deiner %s zu Staub!",
655 (zerfall>1?"zerfallen":"zerfaellt"),
656 zerfall, Query(P_NAME)[1]),78));
657 }
658 // das tell_room() muss auf jeden fall sein, weil es "lebende" Raeume
659 // gibt. Liegt der KRam in einem solchen wuerden die Livings in diesem Raum
660 // sonst keine meldung kriegen.
661 tell_room(environment(), break_string(sprintf(
662 "Auf einmal %s %d %s zu Staub!",
663 (zerfall>1?"zerfallen":"zerfaellt"),
664 zerfall, Query(P_NAME)[1]),78), ({environment()}) );
665 }
666}
667
668static int _query_unit_decay_interval() {
669 if (clonep()) {
670 // fuer clones den Wert aus der BP liefern, der Wert in Clones ist eh
671 // uninteressant.
672 if (objectp(blueprint()))
673 return blueprint()->QueryProp(P_UNIT_DECAY_INTERVAL);
674 else
675 return load_object(load_name())->QueryProp(P_UNIT_DECAY_INTERVAL);
676 }
677 return Query(P_UNIT_DECAY_INTERVAL);
678}
679
680static int _set_unit_decay_interval(int zeit) {
681 // fuer Clones ist die Prop sinnlos und kann nicht gesetzt werden.
682 if (clonep()) {
683 if (objectp(blueprint()))
684 return blueprint()->QueryProp(P_UNIT_DECAY_INTERVAL);
685 else
686 return load_object(load_name())->QueryProp(P_UNIT_DECAY_INTERVAL);
687 }
688 // ueber diese Prop liesse sich der Reset relativ beliebig veraendern,
689 // verhindern, etc. Daher darf sie nur von diesem Objekt gesetzt werden, von
690 // Weisen+ oder eines Objektes, das die gleiche UID hat wie dieses hier oder
691 // des Programmieres dieses Objekts oder eines Magiers, der berechtigt fuer
692 // die jeweilige UID ist. Letztere beiden werden ueber den Ruf von
693 // QueryUIDsForWizard() ermittelt.
694 // erstes fremdes Objekt finden und pruefen.
695 foreach(object po: caller_stack(1)) {
696 if (po != ME) {
697 // fremden Aufrufer gefunden
698 if (getuid(po) != getuid(ME)
699 && member(master()->QueryUIDsForWizard(getuid(po)),getuid(ME)) == -1
700 && (!this_interactive() || !IS_ELDER(this_interactive()) ) )
701 // unberechtigt, Abbruch
702 return QueryProp(P_UNIT_DECAY_INTERVAL);
703 else
704 // nur das erste ext. Objekt in der Callkette wird geprueft, raus.
705 break;
706 }
707 }
708 set_next_reset(zeit);
709 // falls dies aus dem create() gesetzt wird, muss zeitverzoegert eine
710 // Funktion von aussen am Objekt gerufen werden, da nach einem create() das
711 // Objekt als resettet gilt und sonst keinen Reset kriegt.
712 call_out("_query_unit_decay_interval",1);
713 return Set(P_UNIT_DECAY_INTERVAL, zeit, F_VALUE);
714}
715
716static int _query_unit_decay_quota() {
717 if (clonep()) {
718 // hat dieses Objekt einen eigenen wert gespeichert?
719 int quota=Query(P_UNIT_DECAY_QUOTA, F_VALUE);
720 if (quota)
721 return quota;
722 // sonst den Wert aus der Blueprint
723 if (objectp(blueprint()))
724 return blueprint()->QueryProp(P_UNIT_DECAY_QUOTA);
725 else
726 return load_object(load_name())->QueryProp(P_UNIT_DECAY_QUOTA);
727 }
728 return Query(P_UNIT_DECAY_QUOTA, F_VALUE);
729}
730
731static int _set_unit_decay_quota(int quota) {
732 // momentan nur quota zwischen 0 und 10000
733 if (quota >= 0 && quota <=10000)
734 return Set(P_UNIT_DECAY_QUOTA, quota, F_VALUE);
735 else
736 return Query(P_UNIT_DECAY_QUOTA, F_VALUE);
737}
738
739static int _query_unit_decay_min() {
740 if (clonep()) {
741 // hat dieses Objekt einen eigenen wert gespeichert?
742 int minimum=Query(P_UNIT_DECAY_MIN, F_VALUE);
743 if (minimum)
744 return minimum;
745 // sonst den Wert aus der Blueprint
746 if (objectp(blueprint()))
747 return blueprint()->QueryProp(P_UNIT_DECAY_MIN);
748 else
749 return load_object(load_name())->QueryProp(P_UNIT_DECAY_MIN);
750 }
751 return Query(P_UNIT_DECAY_MIN, F_VALUE);
752}
753
754static int _query_unit_decay_flags() {
755 if (clonep()) {
756 // hat dieses Objekt einen eigenen wert gespeichert?
757 int flags=Query(P_UNIT_DECAY_FLAGS, F_VALUE);
758 if (flags)
759 return flags;
760 // sonst den Wert aus der Blueprint
761 if (objectp(blueprint()))
762 return blueprint()->QueryProp(P_UNIT_DECAY_FLAGS);
763 else
764 return load_object(load_name())->QueryProp(P_UNIT_DECAY_FLAGS);
765 }
766 // Die BP liefert den Wert auf jeden Fall ohne NO_DECAY_UNTIL_MOVE zurueck,
767 // weil dieses Flag im Falle der BP nicht zurueckgesetzt wird und bei Clients
768 // ohne eigene Flags der Zerfall stoppen wuerde.
769 return Query(P_UNIT_DECAY_FLAGS, F_VALUE) & ~NO_DECAY_UNTIL_MOVE;
770}
771