blob: 302471470b0034bfc444d72dbfdb2d1dd96bc76d [file] [log] [blame]
// 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;
}