blob: fd3820a16fd45743c2b389e17613e0ef519edde8 [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{
Zesstra117e5f62019-11-23 10:19:15 +0100179 string **ids=Query(U_IDS);
MG Mud User88f12472016-06-24 23:31:02 +0200180 if (!pointerp(str))
181 str=({str});
MG Mud User88f12472016-06-24 23:31:02 +0200182 Set(U_IDS,({ids[0]+str,ids[1]}));
183}
184
185void RemoveSingularId(mixed str)
186{
187 if(stringp(str))
188 str=({str});
189 if(pointerp(str))
190 Set(U_IDS,({Query(U_IDS)[0]-str,Query(U_IDS)[1]}));
191}
192
193void AddPluralId(mixed str)
194{
Zesstra117e5f62019-11-23 10:19:15 +0100195 string **ids;
MG Mud User88f12472016-06-24 23:31:02 +0200196 if (!pointerp(str))
197 str=({str});
198 ids=Query(U_IDS);
199 Set(U_IDS,({ids[0],ids[1]+str}));
200}
201
202void RemovePluralId(mixed str)
203{
204 if(stringp(str))
205 str=({str});
206 if(pointerp(str))
207 Set(U_IDS,({Query(U_IDS)[0],Query(U_IDS)[1]-str}));
208}
209
210void SetCoinsPerUnits(int coins,int units)
211{
212 if (coins<0||units<=0) return;
213 if (units==1)
214 Set(U_CPU, coins);
215 else Set(U_CPU,({coins,units}));
216}
217
218void SetGramsPerUnits(int grams, int units)
219{
220 if (grams<0||units<=0) return;
221 if (units==1)
222 Set(U_GPU, grams);
223 else Set(U_GPU,({grams,units}));
224}
225
226int *QueryCoinsPerUnits()
227{
228 mixed cpu;
229 cpu=Query(U_CPU);
230 if (intp(cpu)) return ({ cpu, 1 });
231 return cpu;
232}
233
234int *QueryGramsPerUnits()
235{
236 mixed gpu;
237 gpu=Query(U_GPU);
238 if (intp(gpu)) return ({ gpu, 1 });
239 return gpu;
240}
241
242void AddAmount(int am) {
243 SetProp(P_AMOUNT, am+Query(P_AMOUNT));
244}
245
246int IsUnit() {
247 return 1;
248}
249
250int IsEqual(object ob)
251// haben ob und dieses Objekte die gleiche Blueprint?
252{
253 if (ob==this_object()) return 0; // das ist ZU gleich :)
254 return (BLUE_NAME(ME)==BLUE_NAME(ob));
255}
256
257// ueberschreiben von Standardmethoden
258
259varargs string name(int fall, int demo)
260{
261 int req;
262 mixed n_adj;
263 string adj;
264
265 if ((req=QueryProp(U_REQ))<1) return 0;
266 if (fall!=RAW &&
267 pointerp(n_adj=QueryProp(P_NAME_ADJ)) && sizeof(n_adj) )
268 adj = implode(map(n_adj, #'DeclAdj, fall, demo && req==1), "");
269 else
270 adj = "";
271
272 if (req==1)
273 return sprintf(QueryProp(P_NAME),
274 (fall==RAW || !QueryProp(P_ARTICLE)
275 ? "" : QueryArticle(fall,demo,1)), adj) /* +korrektur */;
276
277 if (fall!=WEM)
278 return sprintf(QueryProp(P_NAME), req, adj);
279 else {
280 int last;
281 last=Query(P_NAME)[1][<1];
282 return sprintf(QueryProp(P_NAME), req, adj)
283 +(last!='s' && last!='n' ? "n" : "");
284 }
285}
286
287varargs string QueryPronoun(int casus)
288{
289 if (QueryProp(U_REQ)==1)
290 return ::QueryPronoun(casus);
291 switch(casus) {
292 case WESSEN: return "ihrer";
293 case WEM: return "ihnen";
294 //default: return "sie";
295 }
296 return("sie"); //fall-through
297}
298
299string short()
300{
301 if (QueryProp(U_REQ)<1 || QueryProp(P_INVIS)) return 0;
302 return capitalize(name(WER,0))+".\n";
303 /*
304 if (req>1) return sprintf(QueryProp(P_NAME), req)+".\n";
305 return capitalize(sprintf(QueryProp(P_NAME), QueryArticle(WER,0,1)))+".\n";
306 */
307}
308
309varargs string long()
310{
311 return (QueryProp(P_LONG) ? process_string(QueryProp(P_LONG)) : "")+
312 sprintf("Du siehst %s.\n",name(WEN));
313}
314
315varargs int id(string str,int lvl)
316{
317
Zesstra117e5f62019-11-23 10:19:15 +0100318 string s1,s2,**ids;
MG Mud User88f12472016-06-24 23:31:02 +0200319 int i;
320
321 if (!str) return 0;
322
323 // Wenn kein pos. Amount, hat dieses Objekt keine IDs mehr, damit es nicht
324 // mehr ansprechbar ist.
325 int amount=QueryProp(P_AMOUNT);
326 if (amount < 1)
327 return 0;
328
329 if (::id(str)) {
330 SetProp(U_REQ, Query(P_AMOUNT,F_VALUE));
331 return 1;
332 }
333
Zesstra117e5f62019-11-23 10:19:15 +0100334 ids=Query(U_IDS);
MG Mud User88f12472016-06-24 23:31:02 +0200335 if (!ids)
336 return 0;
Zesstra117e5f62019-11-23 10:19:15 +0100337
338 if (match_item(str, ids[1] )) {
MG Mud User88f12472016-06-24 23:31:02 +0200339 SetProp(U_REQ, amount);
340 return 1;
341 }
Zesstra117e5f62019-11-23 10:19:15 +0100342 if (match_item(str, ids[0] )) {
MG Mud User88f12472016-06-24 23:31:02 +0200343 SetProp(U_REQ,1);
344 return 1;
345 }
346 if (sscanf(str,"%s %s",s1,s2) && s1[0..3]=="alle" &&
Zesstra117e5f62019-11-23 10:19:15 +0100347 match_item(s2, ids[1] )) {
MG Mud User88f12472016-06-24 23:31:02 +0200348 SetProp(U_REQ, amount);
349 return 1;
350 }
Zesstra117e5f62019-11-23 10:19:15 +0100351 if (sscanf(str,"%d %s",i,s1)==2 && i==1 && match_item(s1, ids[0] )) {
MG Mud User88f12472016-06-24 23:31:02 +0200352 SetProp(U_REQ,1);
353 return 1;
354 }
Zesstra117e5f62019-11-23 10:19:15 +0100355 if (sscanf(str,"%d %s",i,s1)==2 && match_item(s1, ids[1] ) &&
MG Mud User88f12472016-06-24 23:31:02 +0200356 i<=amount && i>0) {
357 SetProp(U_REQ,i);
358 return 1;
359 }
360 return 0;
361}
362
363// Status fuer move... *seufz*
364int _orig_amount, _move_requested;
365
366varargs int move(object|string dest,int method)
367{
368 _orig_amount = QueryProp(P_AMOUNT);
369 // Wenn M_MOVE_ALL gesetzt ist, wird IMMER ALLES bewegt.
370 if (method & M_MOVE_ALL)
371 _move_requested = _orig_amount;
372 else
373 _move_requested = QueryProp(U_REQ);
374
375 ZDEBUG(sprintf("move from %O to %O: amount %d, req %d\n",environment(),dest,_orig_amount,_move_requested));
376 // Wenn nicht alles bewegt werden soll, wird die Menge dieses Objektes
377 // erstmal reduziert und bewegt. Erst nach der Bewegung wird der Rest dann
378 // im alten Environment neu erzeugt.
379 if ( _orig_amount > _move_requested )
380 {
381 // wenn in einem alten Paket das Gewicht noch nicht neu berechnet
382 // wurde muss dies geschehn solange die Muenzen im Paket noch das
383 // volle Gewicht haben...
384 if ( environment() )
385 environment()->query_weight_contents();
386 // ab jetzt nur auf <_move_requested> Einheiten arbeiten
387 Set( P_AMOUNT, _move_requested, F_VALUE);
388 ZDEBUG(sprintf("move: amount set to %d\n",_move_requested));
389 }
390
391 int res = ::move( dest, method );
392
393 if ( res != MOVE_OK )
394 {
395 // Fehlgeschlagene Bewegung ist doof.
396 // ggf. verfruehte Aenderung (P_AMOUNT oben auf <U_REQ> Einheiten
397 // reduziert) rueckgaengig machen
398 Set( P_AMOUNT, _orig_amount, F_VALUE );
399 ZDEBUG(sprintf("move: not OK, amount restored to %d\n",_orig_amount));
400 return res;
401 }
402
403 // TODO: eigentlich sollte es nicht passieren, dass die Menge jetzt negagtiv
404 // ist. Aber bei Geld kann es durch vereinigen mit Geldboerse/Geldkarten
405 // passieren und das ist kein Fehler. Koennte man evtl. mal differenziert
406 // pruefen.
407 int finalamount= QueryProp(P_AMOUNT);
408 /*if ( finalamount < 1 )
409 {
410 ZDEBUG(sprintf("move: zerstoerung, amount %d\n",finalamount));
411 remove(1);
412 return ME_WAS_DESTRUCTED;
413 }
414 */
415 ZDEBUG(sprintf("move: OK, amount %d\n",finalamount));
416 return res;
417}
418
419
420protected void NotifyMove(object dest, object oldenv, int method)
421{
422 // Erst einen evtl. nicht zu bewegenden Rest im alten Environment wieder erzeugen.
423 if (oldenv && _orig_amount > _move_requested)
424 {
425 if ( oldenv == dest )
426 {
427 // Objekt wurde nur an den Anfang des inventory bewegt, sonst nichts.
428 // ggf. verfruehte Aenderung (oben auf <req> Einheiten reduziert)
429 // rueckgaengig machen
430 ZDEBUG(sprintf("move: same env, amount restored to %d\n",_orig_amount));
431 Set( P_AMOUNT, _orig_amount, F_VALUE );
432 }
433 else
434 {
435 // verbleibende Einheiten in einem neuen Objekte wieder zurueck ins
436 // alte Environment zurueck bewgen
437 object temp;
438 temp = clone_object(BLUE_NAME(ME));
439 temp->SetProp( P_AMOUNT, _orig_amount-_move_requested );
440 temp->move( oldenv, M_NOCHECK );
441 ZDEBUG(sprintf("move: Restmenge im alten Env erzeugt, amount %d\n",_orig_amount-_move_requested));
442 }
443 }
444
445 // Und jetzt ggf. mit den anderen Units gleichen Typs im neuen Environment
446 // vereinigen.
447 foreach(object item: all_inventory(environment()))
448 {
449 if ( IS_EQUAL(item) )
450 {
451 // Es ist ein Feature, dass auch mit Objekten mit negativen Amount
452 // vereinigt wird.
453 ZDEBUG(sprintf("move: vereinige mit %O (%d)\n",
454 item,item->QueryProp(P_AMOUNT)));
455 int mergedamount = QueryProp(P_AMOUNT) + item->QueryProp(P_AMOUNT);
456 item->Set( P_AMOUNT, 0, F_VALUE);
457 item->remove(1);
458
459 SetProp( P_AMOUNT, mergedamount);
460 // U_REQ ist jetzt auch zurueckgesetzt.
461
462 ZDEBUG(sprintf("move: nach vereinigung, amount %d\n",mergedamount));
463 }
464 }
465
466 // wenn man in frisch geclonten Units die noch kein environment haben
467 // per Hand U_REQ auf einen Wert != P_AMOUNT setzt, so gehen die
468 // restlichen Einheiten verloren (es gibt kein Environment, in das man die
469 // Resteinheiten zurueck bewegen koennte).
470
471 // Und jetzt mal Decaykrams machen...
472
473 // wenn NO_DECAY_UNTIL_MOVE an ist und dieses ein Move ist, was von einem
474 // Env in ein anderes Env geht, loeschen. Nicht geloescht wird
475 // hingegen, wenn das move() in das allererste Env erfolgt (nach dem Clonen)
476 if ( (QueryProp(P_UNIT_DECAY_FLAGS) & NO_DECAY_UNTIL_MOVE)
477 && objectp(dest) && objectp(oldenv) && dest != oldenv)
478 SetProp(P_UNIT_DECAY_FLAGS,
479 QueryProp(P_UNIT_DECAY_FLAGS) & ~NO_DECAY_UNTIL_MOVE );
480 ::NotifyMove(dest, oldenv, method);
481}
482
483
484void reset() {
485 if (!clonep(ME)) {
486 // Blueprint ist Master fuer zerfallende Unitobjekte
487 // das Decay sollte besser nicht durch manuellen Aufruf in der BP
488 // ausgeloest werden, daher Pruefung hier (PO == ME, falls der Reset vom
489 // Driver kommt).
490 if (previous_object() && previous_object() != ME)
491 return;
492 int zeit = QueryProp(P_UNIT_DECAY_INTERVAL);
493 if (zeit > 0)
494 {
495 set_next_reset(zeit);
496 // Das Callout muss auf jeden Fall gemacht werden, wenn ein Decay
497 // Intervall gesetzt ist, damit die Blueprint auch den naechsten Reset
498 // kriegt, auch wenn es jetzt keine Clone gibt. Wenn es kein Quota gibt,
499 // kann der Callout wegfallen, beim Setzen eines Quota wird ja eine
500 // Funktion an diesem Objekt gerufen.
501 if (QueryProp(P_UNIT_DECAY_QUOTA) > 0)
502 call_out(#'_call_DoDecay, 1, 0);
503 }
504 }
505 else {
506 // Clones
507 if (Query(P_AMOUNT,F_VALUE)<1) remove(1);
508 else ::reset();
509 }
510}
511
512varargs int remove(int silent)
513{
514 int amount = QueryProp(P_AMOUNT);
515 int req = QueryProp(U_REQ);
516 if (amount > req)
517 {
518 ZDEBUG(sprintf("remove: reduziere amount %d um %d -> %d\n",
519 amount, req, amount-req ));
520 SetProp(P_AMOUNT, amount - req);
521 return 1;
522 }
523 ZDEBUG(sprintf("remove: restlos weg.\n"));
524 return ::remove(silent);
525}
526
527// sollte nicht von aussen gerufen werden.
528private void _call_DoDecay(object *klone) {
529 ZDEBUG(sprintf("call_DoDecay() in %O\n",ME));
530 // Clone oder kein Decay konfiguriert?
531 if (clonep()
532 || QueryProp(P_UNIT_DECAY_FLAGS) & NO_DECAY)
533 return;
534
535 if (!pointerp(klone))
536 klone = clones(2);
537 // Klone da?
538 int i=sizeof(klone);
539 if (!i)
540 return;
541
542 // in allen Klonen DoDecay rufen
543 while(get_eval_cost() > __MAX_EVAL_COST__/2 && i--) {
544 if (objectp(klone[i]))
545 catch(call_other(klone[i],"DoDecay", 0);publish);
546 }
547 // das i ist schon abgearbeitet.
548 i--;
549 // noch was uebrig?
550 if (i >= 0)
551 call_out(#'_call_DoDecay, 4, klone[0..i]);
552}
553
554// zerstoert quota Prozent der vorhandenen Units, liefert die Restmenge
555// zurueck. Ruft ggf. DoDecayMessage()
556public int DoDecay(int silent) {
557 // nur fuer Clones
558 if (!clonep())
559 return 0;
560 ZDEBUG(sprintf("DoDecay() in %O\n",ME));
561
562 // wenn das Objekt NO_DECAY oder NO_DECAY_UNTIL_MOVE in den Flags
563 // zerfaellt nix.
564 int flags = QueryProp(P_UNIT_DECAY_FLAGS);
565 if ((flags & NO_DECAY) || (flags & NO_DECAY_UNTIL_MOVE) )
566 return QueryProp(P_AMOUNT);
567
568 int quota = QueryProp(P_UNIT_DECAY_QUOTA);
569
570 // Zugewinn ist nicht. Ausserdem kann nicht mehr zerfallen, als da ist...
571 // Also ohne gueltiges Quota raus. Nur bei abs. Zerfall sind Zahlen > 10000
572 // erlaubt, bei relativen Zerfall waere das sinnlos.
573 if (quota <= 0 ||
574 (quota > 10000 && !(flags & ABSOLUTE_DECAY) ) )
575 return QueryProp(P_AMOUNT);
576
577 int amount = QueryProp(P_AMOUNT);
578 int minimum = QueryProp(P_UNIT_DECAY_MIN);
579 // Zerfall nur, wenn man mehr als das Minimum hat.
580 if (amount > minimum) {
581 int zerfall;
582 if (flags & ABSOLUTE_DECAY) {
583 // Decay Quota soll einfach als abs. Zahl aufgefasst werden:
584 zerfall = quota;
585 }
586 else if (flags & INACCURATE_DECAY) {
587 // Rundungsfehler ignorieren und dafuer immer min. eine Einheit
588 // zerfallen lassein
589 zerfall = (amount * quota) / 10000;
590 if (zerfall <= 0) zerfall = 1;
591 }
592 else {
593 // Standardfall:
594 // nicht-ganzzahligen Rest als Wahrscheinlichkeit fuer den Zerfall einer
595 // Einheit auffassen
596 float tmp = amount * quota / 10000.0;
597 zerfall = to_int(tmp);
598 tmp -= zerfall; // Rest in tmp
599 // tmp*n ist eine Zahl zwischen 0 und n, wenn tmp*n > random(n)+1,
600 // dann zerfaellt eine Einheit extra. Da das Random fuer grosse Zahlen
601 // besser verteilt ist, nehm ich n = __INT_MAX__
602 if (ceil(tmp * __INT_MAX__) > random(__INT_MAX__) + 1)
603 zerfall++;
604 }
605
606 // nicht unter Minimum zerfallen
607 if (amount - zerfall < minimum)
608 zerfall = amount - minimum;
609
610 // erst ggf. Meldung ausgeben.
611 if (!silent && zerfall > 0)
612 DoDecayMessage(amount, zerfall);
613 // dann runtersetzen.
614 SetProp(P_AMOUNT, amount - zerfall);
615 ZDEBUG(sprintf("%O decayed by %d\n",ME, zerfall));
616 return amount-zerfall;
617 }
618 else if (amount < 0)
619 return 0; // neg. Anzahl gilt als "0 uebrig".
620
621 // sonst ists wohl zwischen 0 und minimum, nix aendert sich.
622 return amount;
623}
624
625// gibt die Zerfallsmeldung aus. Wenn man mit der Standardmeldung nicht zufrieden
626// ist (duerfte der Normalfall sein), sollte man diese Funktion
627// ueberschreiben. Bekommt bisherige und jetzt gerade zerfallene Menge
628// uebergeben. Wichtig: zu diesem Zeitpunkt hat sich an der Unit noch nix (!)
629// geaendert!
630protected void DoDecayMessage(int oldamount, int zerfall) {
631 string msg;
632 if (oldamount == zerfall) {
633 if (living(environment())) {
634 tell_object(environment(), break_string(sprintf(
635 "Auf einmal %s%s zu Staub!",
636 (oldamount>1?"zerfallen Deine ":"zerfaellt D"), name(WER)),78));
637 }
638 // das tell_room() muss auf jeden fall sein, weil es "lebende" Raeume
639 // gibt. Liegt der KRam in einem solchen wuerden die Livings in diesem Raum
640 // sonst keine meldung kriegen.
641 tell_room(environment(), break_string(sprintf(
642 "Auf einmal %s %s zu Staub!",
643 (oldamount>1?"zerfallen":"zerfaellt"), name(WER)),78),
644 ({environment()}));
645 }
646 else {
647 if (living(environment())) {
648 tell_object(environment(), break_string(sprintf(
649 "Auf einmal %s %d Deiner %s zu Staub!",
650 (zerfall>1?"zerfallen":"zerfaellt"),
651 zerfall, Query(P_NAME)[1]),78));
652 }
653 // das tell_room() muss auf jeden fall sein, weil es "lebende" Raeume
654 // gibt. Liegt der KRam in einem solchen wuerden die Livings in diesem Raum
655 // sonst keine meldung kriegen.
656 tell_room(environment(), break_string(sprintf(
657 "Auf einmal %s %d %s zu Staub!",
658 (zerfall>1?"zerfallen":"zerfaellt"),
659 zerfall, Query(P_NAME)[1]),78), ({environment()}) );
660 }
661}
662
663static int _query_unit_decay_interval() {
664 if (clonep()) {
665 // fuer clones den Wert aus der BP liefern, der Wert in Clones ist eh
666 // uninteressant.
667 if (objectp(blueprint()))
668 return blueprint()->QueryProp(P_UNIT_DECAY_INTERVAL);
669 else
670 return load_object(load_name())->QueryProp(P_UNIT_DECAY_INTERVAL);
671 }
672 return Query(P_UNIT_DECAY_INTERVAL);
673}
674
675static int _set_unit_decay_interval(int zeit) {
676 // fuer Clones ist die Prop sinnlos und kann nicht gesetzt werden.
677 if (clonep()) {
678 if (objectp(blueprint()))
679 return blueprint()->QueryProp(P_UNIT_DECAY_INTERVAL);
680 else
681 return load_object(load_name())->QueryProp(P_UNIT_DECAY_INTERVAL);
682 }
683 // ueber diese Prop liesse sich der Reset relativ beliebig veraendern,
684 // verhindern, etc. Daher darf sie nur von diesem Objekt gesetzt werden, von
685 // Weisen+ oder eines Objektes, das die gleiche UID hat wie dieses hier oder
686 // des Programmieres dieses Objekts oder eines Magiers, der berechtigt fuer
687 // die jeweilige UID ist. Letztere beiden werden ueber den Ruf von
688 // QueryUIDsForWizard() ermittelt.
689 // erstes fremdes Objekt finden und pruefen.
690 foreach(object po: caller_stack(1)) {
691 if (po != ME) {
692 // fremden Aufrufer gefunden
693 if (getuid(po) != getuid(ME)
694 && member(master()->QueryUIDsForWizard(getuid(po)),getuid(ME)) == -1
695 && (!this_interactive() || !IS_ELDER(this_interactive()) ) )
696 // unberechtigt, Abbruch
697 return QueryProp(P_UNIT_DECAY_INTERVAL);
698 else
699 // nur das erste ext. Objekt in der Callkette wird geprueft, raus.
700 break;
701 }
702 }
703 set_next_reset(zeit);
704 // falls dies aus dem create() gesetzt wird, muss zeitverzoegert eine
705 // Funktion von aussen am Objekt gerufen werden, da nach einem create() das
706 // Objekt als resettet gilt und sonst keinen Reset kriegt.
707 call_out("_query_unit_decay_interval",1);
708 return Set(P_UNIT_DECAY_INTERVAL, zeit, F_VALUE);
709}
710
711static int _query_unit_decay_quota() {
712 if (clonep()) {
713 // hat dieses Objekt einen eigenen wert gespeichert?
714 int quota=Query(P_UNIT_DECAY_QUOTA, F_VALUE);
715 if (quota)
716 return quota;
717 // sonst den Wert aus der Blueprint
718 if (objectp(blueprint()))
719 return blueprint()->QueryProp(P_UNIT_DECAY_QUOTA);
720 else
721 return load_object(load_name())->QueryProp(P_UNIT_DECAY_QUOTA);
722 }
723 return Query(P_UNIT_DECAY_QUOTA, F_VALUE);
724}
725
726static int _set_unit_decay_quota(int quota) {
727 // momentan nur quota zwischen 0 und 10000
728 if (quota >= 0 && quota <=10000)
729 return Set(P_UNIT_DECAY_QUOTA, quota, F_VALUE);
730 else
731 return Query(P_UNIT_DECAY_QUOTA, F_VALUE);
732}
733
734static int _query_unit_decay_min() {
735 if (clonep()) {
736 // hat dieses Objekt einen eigenen wert gespeichert?
737 int minimum=Query(P_UNIT_DECAY_MIN, F_VALUE);
738 if (minimum)
739 return minimum;
740 // sonst den Wert aus der Blueprint
741 if (objectp(blueprint()))
742 return blueprint()->QueryProp(P_UNIT_DECAY_MIN);
743 else
744 return load_object(load_name())->QueryProp(P_UNIT_DECAY_MIN);
745 }
746 return Query(P_UNIT_DECAY_MIN, F_VALUE);
747}
748
749static int _query_unit_decay_flags() {
750 if (clonep()) {
751 // hat dieses Objekt einen eigenen wert gespeichert?
752 int flags=Query(P_UNIT_DECAY_FLAGS, F_VALUE);
753 if (flags)
754 return flags;
755 // sonst den Wert aus der Blueprint
756 if (objectp(blueprint()))
757 return blueprint()->QueryProp(P_UNIT_DECAY_FLAGS);
758 else
759 return load_object(load_name())->QueryProp(P_UNIT_DECAY_FLAGS);
760 }
761 // Die BP liefert den Wert auf jeden Fall ohne NO_DECAY_UNTIL_MOVE zurueck,
762 // weil dieses Flag im Falle der BP nicht zurueckgesetzt wird und bei Clients
763 // ohne eigene Flags der Zerfall stoppen wuerde.
764 return Query(P_UNIT_DECAY_FLAGS, F_VALUE) & ~NO_DECAY_UNTIL_MOVE;
765}
766