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