Added public files
Roughly added all public files. Probably missed some, though.
diff --git a/std/living/attributes.c b/std/living/attributes.c
new file mode 100644
index 0000000..90027a4
--- /dev/null
+++ b/std/living/attributes.c
@@ -0,0 +1,671 @@
+// MorgenGrauen MUDlib
+//
+// living/attributes.c -- attributes for living objects
+//
+// $Id: attributes.c 8375 2013-02-12 21:52:58Z Zesstra $
+
+#include <sys_debug.h>
+
+// attribute handling
+//
+// filter_ldfied: str, dex, con, int
+//
+// In den Attributen und Abilites werden Rassenspzifische und erworbene
+// Faehigkeiten (mit autoload-Eigenschaft) abgepseichert.
+//
+// Funktionen:
+// SetAttribute( attr, val ) (Erzeuge und) setze das Attribut auf val.
+// QueryAttribute( attr ) Gebe den Wert des Attributes zurueck.
+//
+// Wenn ein Objekt eine Funktion _filterattr_<name> beitzt, wird beim Setzen
+// des Attributes <name>, der vorgeschlagene Wert uebergeben und der von
+// dieser Funktion zurueckgegebene gesetzt. (fuer ueberpruefungszwecke)
+// Gleiches gilt fuer _filterabil_<name>.
+
+#pragma strict_types
+#pragma save_types
+#pragma range_check
+#pragma no_clone
+#pragma pedantic
+
+#define NEED_PROTOTYPES
+#include <thing/properties.h>
+#include <attributes.h>
+#include <player/gmcp.h>
+#undef NEED_PROTOTYPES
+
+#include <config.h>
+#include <properties.h>
+
+mapping attributes; // Dies sind die mit ZTs veraenderbaren Attribute
+mapping attributes_modifier; // Modifier sollen gespeichert werden
+nosave mixed* attributes_timed_mods; //P_TIMED_ATTR_MOD
+nosave mapping attributes_offsets; // Offsets NICHT speichern!
+nosave mapping used_attributes_offsets; // Zur Beschleunigung der Berechnung
+nosave object* all_modifiers; // objekte mit P_X/M_ATTR_MOD, P_X/M_HEALTH_MOD
+nosave object* invalid_modifiers; // objekte welche das limit ueberschreiten
+nosave int cumulative_mod; // bilanz der P_X/M_ATTR_MOD
+nosave int hp_off;
+nosave int sp_off;
+
+
+nomask public int SetTimedAttrModifier(string key, mapping modifier,
+ int outdated, object dependent, mixed notify) {
+ if(!key || key=="" || !modifier || (outdated>0 && outdated<time()) ||
+ (notify && !stringp(notify) && !objectp(notify)) ) {
+ return TATTR_INVALID_ARGS;
+ }
+
+
+ if(member(attributes_timed_mods[TATTR_ENTRIES],key)) {
+ // change entry
+ attributes_timed_mods[TATTR_ENTRIES][key,TATTR_MOD]=modifier;
+ attributes_timed_mods[TATTR_ENTRIES][key,TATTR_OUTDATED]=outdated;
+ attributes_timed_mods[TATTR_ENTRIES][key,TATTR_DEPENDENT]=dependent;
+ attributes_timed_mods[TATTR_ENTRIES][key,TATTR_NOTIFY]=notify;
+ }
+ else {
+ // add entry
+ attributes_timed_mods[TATTR_ENTRIES]+=([key:modifier;outdated;dependent;notify]);
+ }
+
+ // add outdate
+ if(outdated>0 && member(attributes_timed_mods[TATTR_OUTDATE],outdated)==-1)
+ {
+ attributes_timed_mods[TATTR_OUTDATE]+=({outdated});
+ attributes_timed_mods[TATTR_OUTDATE]=
+ sort_array(attributes_timed_mods[TATTR_OUTDATE],#'<);
+ }
+
+ // add dependent
+ if(objectp(dependent))
+ {
+ if(member(attributes_timed_mods[TATTR_DEPENDENTS],key))
+ {
+ attributes_timed_mods[TATTR_DEPENDENTS][key]=dependent;
+ }
+ else
+ {
+ attributes_timed_mods[TATTR_DEPENDENTS]+=([key:dependent]);
+ }
+ }
+ else
+ {
+ // remove previously set dependent
+ if(member(attributes_timed_mods[TATTR_DEPENDENTS],key))
+ {
+ attributes_timed_mods[TATTR_DEPENDENTS]-=([key]);
+ }
+ }
+
+ UpdateAttributes();
+
+ return TATTR_OK;
+}
+
+nomask public mapping QueryTimedAttrModifier(string key)
+{
+ int outdated;
+ object dependent;
+ mixed notify;
+ mapping mod;
+
+ if(!key || key=="")
+ {
+ return ([]);
+ }
+
+ if(!member(attributes_timed_mods[TATTR_ENTRIES],key))
+ {
+ return ([]);
+ }
+
+ mod=deep_copy(attributes_timed_mods[TATTR_ENTRIES][key,TATTR_MOD]);
+ outdated=attributes_timed_mods[TATTR_ENTRIES][key,TATTR_OUTDATED];
+ dependent=attributes_timed_mods[TATTR_ENTRIES][key,TATTR_DEPENDENT];
+ notify=attributes_timed_mods[TATTR_ENTRIES][key,TATTR_NOTIFY];
+
+ return ([key:mod;outdated;dependent;notify ]);
+}
+
+nomask public int DeleteTimedAttrModifier(string key)
+{
+ if(!key || key=="")
+ {
+ return TATTR_INVALID_ARGS;
+ }
+
+ if(!member(attributes_timed_mods[TATTR_ENTRIES],key))
+ {
+ return TATTR_NO_SUCH_MODIFIER;
+ }
+
+ attributes_timed_mods[TATTR_DEPENDENTS]-=([key]);
+ attributes_timed_mods[TATTR_ENTRIES]-=([key]);
+ UpdateAttributes();
+
+ return TATTR_OK;
+}
+
+nomask protected void attribute_hb()
+{
+ int now,i,k,update,outdated;
+ string* keys;
+ mapping tonotify;
+
+ // initialize
+ now=time();
+ tonotify=([]);
+
+ keys=m_indices(attributes_timed_mods[TATTR_ENTRIES]);
+
+ // delete outdated
+ for(i=sizeof(attributes_timed_mods[TATTR_OUTDATE])-1;i>=0;i--)
+ {
+ outdated=attributes_timed_mods[TATTR_OUTDATE][i];
+ if(outdated>now)
+ {
+ break;
+ }
+
+ for(k=sizeof(keys)-1;k>=0;k--)
+ {
+ if(attributes_timed_mods[TATTR_ENTRIES][keys[k],TATTR_OUTDATED]==outdated)
+ {
+ // bei fehlendem notifier wurde das zum verhaengnis
+ // dank an gloinson
+ /*
+ if(objectp(attributes_timed_mods[TATTR_ENTRIES][keys[k],TATTR_NOTIFY]))
+ {
+ */
+ tonotify+=([keys[k]:attributes_timed_mods[TATTR_ENTRIES][keys[k],TATTR_NOTIFY]]);
+ //}
+
+ attributes_timed_mods[TATTR_DEPENDENTS]-=([keys[k]]);
+ attributes_timed_mods[TATTR_ENTRIES]-=([keys[k]]);
+ keys-=({keys[k]});
+ }
+ }
+
+ attributes_timed_mods[TATTR_OUTDATE]-=({outdated});
+ }
+
+ // delete depending
+ keys=m_indices(attributes_timed_mods[TATTR_DEPENDENTS]);
+ for(i=sizeof(keys)-1;i>=0;i--)
+ {
+ if(!objectp(attributes_timed_mods[TATTR_DEPENDENTS][keys[i]]))
+ {
+ // siehe oben
+ /*
+ if(objectp(attributes_timed_mods[TATTR_ENTRIES][keys[i],TATTR_NOTIFY]))
+ {
+ */
+ tonotify+=([keys[i]:attributes_timed_mods[TATTR_ENTRIES][keys[i],TATTR_NOTIFY]]);
+ //}
+
+ attributes_timed_mods[TATTR_DEPENDENTS]-=([keys[i]]);
+ attributes_timed_mods[TATTR_ENTRIES]-=([keys[i]]);
+ keys-=({keys[i]});
+ }
+ }
+
+
+ // update
+ if(sizeof(tonotify))
+ {
+ UpdateAttributes();
+ call_out(#'notifyExpiredModifiers,0,tonotify);
+ }
+}
+
+nomask protected void notifyExpiredModifiers(mapping nots)
+{
+ int i;
+ string* keys;
+ while(remove_call_out(#'notifyExpiredModifiers)!=-1);
+
+ if(!nots)
+ {
+ return;
+ }
+
+ keys=m_indices(nots);
+ for(i=sizeof(nots)-1;i>=0;i--)
+ {
+ if(nots[keys[i]] &&
+ ( objectp(nots[keys[i]])||stringp(nots[keys[i]]) ) )
+ {
+ call_other(nots[keys[i]],"NotifyTimedAttrModExpired",keys[i]);
+ }
+ }
+}
+
+
+// invalide modifier benachrichtigen
+nomask protected void notifyInvalidModifiers() {
+
+ while(remove_call_out(#'notifyInvalidModifiers)!=-1);
+
+ if(!invalid_modifiers) {
+ invalid_modifiers=({});
+ }
+
+ call_other(invalid_modifiers,"NotifyXMAttrModLimitViolation");
+
+}
+
+
+// welche Modifier / modif. Objekte wirken nun?
+protected nomask void calculate_valid_modifiers() {
+ closure qp;
+ mapping res;
+ string key;
+ int wert;
+ // Unterscheidung Bonus <-> Malus, weil der Malus voll eingehen soll
+ int hp_malus, sp_malus;
+
+ used_attributes_offsets=([]);
+ cumulative_mod=0;
+ hp_off=sp_off=0;
+ invalid_modifiers=({});
+
+ // rassenspezifische boni P_ATTRIBUTES_OFFSETS
+ if ( mappingp(attributes_offsets) )
+ used_attributes_offsets+=attributes_offsets;
+
+ if (!pointerp(all_modifiers) || !sizeof(all_modifiers)) {
+ // in diesem Fall koennen wir hier direkt mit dieser Funktion Schluss
+ // machen. ;-)
+ return;
+ }
+ else
+ all_modifiers-=({0}); //zerstoerte Objekte rauswerfen.
+
+ // einmal ueber alle modifizierenden Objekt iterieren und aufaddieren
+ foreach(object ob: all_modifiers) {
+ qp = symbol_function("QueryProp",ob);
+
+ if (!objectp(ob) || environment(ob)!=this_object()) {
+ all_modifiers-=({ob});
+ continue;
+ }
+
+ // ext. Attribut-Modifier
+ if ( mappingp(res=funcall(qp,P_X_ATTR_MOD)) ) {
+ foreach(key, wert: res) {
+ cumulative_mod+=wert;
+ }
+ }
+
+ // magic Attribut-Modifier
+ if ( mappingp(res=funcall(qp,P_M_ATTR_MOD))
+ && ( funcall(qp,P_WORN)
+ || funcall(qp,P_WIELDED) ) ) {
+ foreach(key, wert: res) {
+ cumulative_mod+=wert;
+ }
+ }
+ // Magic Health-Modifier
+ if ( mappingp(res=funcall(qp,P_M_HEALTH_MOD))
+ && ( funcall(qp,P_WORN)
+ || funcall(qp,P_WIELDED) ) ) {
+ if (res[P_HP] < 0)
+ hp_malus += res[P_HP];
+ else
+ hp_off+=res[P_HP];
+
+ if (res[P_SP] < 0)
+ sp_malus += res[P_SP];
+ else
+ sp_off+=res[P_SP];
+ }
+
+ // external Health Modifier
+ if ( mappingp(res=funcall(qp,P_X_HEALTH_MOD)) ) {
+ if (res[P_HP] < 0)
+ hp_malus += res[P_HP];
+ else
+ hp_off+=res[P_HP];
+
+ if (res[P_SP] < 0)
+ sp_malus += res[P_SP];
+ else
+ sp_off+=res[P_SP];
+ }
+
+ } // Ende 1. foreach()
+
+
+ // und nochmal, soviele Objekt wieder rausschmeissen, bis das Limit wieder
+ // unterschritten wird. (Verbesserungsvorschlaege erwuenscht.) :-(
+ foreach(object ob: all_modifiers) {
+
+ qp = symbol_function("QueryProp",ob);
+
+ if ( mappingp(res=funcall(qp,P_X_ATTR_MOD)) ) {
+ if(cumulative_mod>CUMULATIVE_ATTR_LIMIT) {
+ invalid_modifiers+=({ob});
+ foreach(key, wert: res) {
+ cumulative_mod-=wert;
+ }
+ }
+ else {
+ add_offsets(res);
+ }
+ }
+
+ if ( mappingp(res=funcall(qp,P_M_ATTR_MOD))
+ && ( funcall(qp,P_WORN)
+ || funcall(qp,P_WIELDED) ) ) {
+ if(cumulative_mod>CUMULATIVE_ATTR_LIMIT) {
+ if(member(invalid_modifiers,ob)==-1) {
+ invalid_modifiers+=({ob});
+ }
+ foreach(key, wert: res) {
+ cumulative_mod-=wert;
+ }
+ }
+ else {
+ add_offsets(res);
+ }
+ }
+ }
+
+ // HEALTH_MOD werden durch eine Formel 'entschaerft', damit man nur schwer
+ // das Maximum von 150 erreichen kann. (Formel von Humni, beschlossen auf 3.
+ // EM-Treffen)
+ // Mali gehen aber voll ein
+ hp_off = (int)(150 - (150*150.0/(150 + hp_off))) + hp_malus;
+ sp_off = (int)(150 - (150*150.0/(150 + sp_off))) + sp_malus;
+
+ /* alte Version
+ hp_off += hp_malus;
+ sp_off += sp_malus;
+ */
+
+ // notify invalid modifiers
+ if(sizeof(invalid_modifiers)>0) {
+ call_out(#'notifyInvalidModifiers,0);
+ }
+}
+
+// abmelden eines modifiers
+nomask public void deregister_modifier(object modifier)
+{
+ if (!pointerp(all_modifiers)) {
+ return;
+ }
+
+ // valid object?
+ if (!objectp(modifier) || member(all_modifiers,modifier)==-1) {
+ return;
+ }
+
+ all_modifiers-=({modifier});
+ if (invalid_modifiers) {
+ invalid_modifiers-=({modifier});
+ }
+}
+
+// anmelden eines modifiers
+nomask public void register_modifier(object modifier) {
+ closure qp;
+
+ if (!pointerp(all_modifiers)) {
+ all_modifiers=({});
+ }
+
+ // valid object?
+ if (!objectp(modifier) || environment(modifier)!=this_object() ||
+ member(all_modifiers,modifier)!=-1) {
+ return;
+ }
+
+ qp = symbol_function("QueryProp",modifier);
+ // modifier after all? Die P_M_* muessen getragen/gezueckt sein.
+ if(mappingp(funcall(qp,P_X_ATTR_MOD)) ||
+ mappingp(funcall(qp,P_X_HEALTH_MOD)) ||
+ ((mappingp(funcall(qp,P_M_ATTR_MOD)) ||
+ mappingp(funcall(qp,P_M_HEALTH_MOD))) &&
+ (funcall(qp,P_WORN) || funcall(qp,P_WIELDED)) ) ) {
+ all_modifiers+=({modifier});
+ }
+}
+
+protected void add_offsets(mapping arr) {
+ mixed *ind;
+ int i;
+
+ if ( !mappingp(arr) )
+ return;
+
+ foreach(string key, int wert: arr) {
+ used_attributes_offsets[key]+=wert;
+ }
+}
+
+public void UpdateAttributes() {
+ mixed *ind;
+ int i;
+
+ // alle gueltigen Modifier ermitteln aus Objekten im Inventar.
+ calculate_valid_modifiers();
+
+ // persistente modifier drauf (frosch zb)
+ // aus P_ATTRIBUTES_MODIFIERS
+ if ( mappingp(attributes_modifier) ) {
+ foreach(mixed key, mapping wert: attributes_modifier) {
+ add_offsets(wert); // Modifier addieren...
+ }
+ }
+ // timed modifier drauf aus P_TIMED_ATTR_MOD
+ ind=m_indices(attributes_timed_mods[TATTR_ENTRIES]);
+ for ( i=sizeof(ind)-1 ; i>=0 ; i-- ) {
+ // Modifier addieren...
+ add_offsets(attributes_timed_mods[TATTR_ENTRIES][ind[i],0]);
+ }
+ // Bei Monstern werden die HP/SP ueblicherweise selbst gesetzt
+ if ( !query_once_interactive(this_object()))
+ return;
+
+ SetProp(P_MAX_HP, QueryAttribute(A_CON)*8+42+hp_off);
+ SetProp(P_MAX_SP, QueryAttribute(A_INT)*8+42+sp_off);
+
+ if(QueryProp(P_HP)>QueryProp(P_MAX_HP)) {
+ SetProp(P_HP,QueryProp(P_MAX_HP));
+ }
+
+ if(QueryProp(P_SP)>QueryProp(P_MAX_SP)) {
+ SetProp(P_SP,QueryProp(P_MAX_SP));
+ }
+
+ GMCP_Char( ([ A_INT: QueryAttribute(A_INT),
+ A_DEX: QueryAttribute(A_DEX),
+ A_STR: QueryAttribute(A_STR),
+ A_CON: QueryAttribute(A_CON) ]) );
+}
+
+
+protected void create() {
+ hp_off=sp_off=0;
+ used_attributes_offsets=([]);
+ all_modifiers=({});
+ invalid_modifiers=({});
+ cumulative_mod=0;
+
+ Set(P_ATTRIBUTES_MODIFIER, attributes_modifier=([])); // nicht geschuetzt
+ Set(P_ATTRIBUTES_OFFSETS, attributes_offsets=([]));
+ Set(P_ATTRIBUTES_OFFSETS, PROTECTED, F_MODE);
+ Set(P_ATTRIBUTES, attributes=([]));
+ Set(P_ATTRIBUTES, PROTECTED, F_MODE);
+
+ Set(P_TIMED_ATTR_MOD, attributes_timed_mods=({ ({}),([]),([]) }));
+ Set(P_TIMED_ATTR_MOD, NOSETMETHOD|SECURED, F_MODE_AS);
+}
+
+static mixed _query_timed_attr_mod() {
+ mixed ret;
+ return Set(P_TIMED_ATTR_MOD,
+ ({attributes_timed_mods[0],
+ deep_copy(attributes_timed_mods[1]),
+ deep_copy(attributes_timed_mods[2])}));
+}
+
+static mapping _set_attributes(mapping arr)
+{
+ Set(P_ATTRIBUTES, attributes=arr);
+ UpdateAttributes();
+ return arr;
+}
+
+static mapping _query_attributes()
+{
+ return deep_copy(Set(P_ATTRIBUTES, attributes));
+}
+
+static mapping _set_attributes_offsets(mapping arr)
+{
+ Set(P_ATTRIBUTES_OFFSETS, attributes_offsets=arr);
+ UpdateAttributes();
+ return attributes_offsets;
+}
+
+static mapping _query_attributes_offsets()
+{
+ return deep_copy(Set(P_ATTRIBUTES_OFFSETS, attributes_offsets));
+}
+
+static mixed _set_attributes_modifier(mixed arr)
+{ string fn;
+ mixed pre;
+ mapping map_ldfied;
+
+ if ( pointerp(arr) && (sizeof(arr)>=2) )
+ {
+ pre=arr[0];
+ map_ldfied=arr[1];
+ }
+ else
+ {
+ pre=previous_object();
+ map_ldfied=arr;
+ }
+
+ if ( objectp(pre) )
+ fn=old_explode(object_name(pre),"#")[0];
+ else
+ fn=pre;
+
+ if ( !stringp(fn) )
+ return 0;
+
+ // wenn Modifier kein mapping oder ein leeres Mapping: loeschen
+ if ( !mappingp(map_ldfied) || !sizeof(map_ldfied))
+ m_delete(attributes_modifier,fn);
+ else
+ attributes_modifier[fn]=map_ldfied;
+
+ Set(P_ATTRIBUTES_MODIFIER, attributes_modifier);
+ UpdateAttributes();
+ return attributes_modifier[fn];
+}
+
+static mapping _query_attributes_modifier()
+{
+ return deep_copy(attributes_modifier);
+}
+
+public int SetAttr(string attr, int val)
+{ closure filter_ldfied;
+
+ if ( filter_ldfied = symbol_function("_filterattr_"+attr, this_object()) )
+ val = funcall(filter_ldfied, val );
+
+ attributes[attr] = val;
+ UpdateAttributes();
+ return val;
+}
+
+public int SetAttribute(string attr, int val)
+{
+ return SetAttr(attr, val-used_attributes_offsets[attr]);
+}
+
+// Diese Funktion sollte zum Abfragen verwendet werden:
+public int QueryAttribute(string attr)
+{ int re;
+
+ re=attributes[attr]+used_attributes_offsets[attr];
+
+ if ( query_once_interactive(this_object()) && (re>30) )
+ re=30;
+
+ return re;
+}
+
+public int QueryRealAttribute(string attr)
+{
+ return attributes[attr];
+}
+
+public int SetRealAttribute(string attr, int val)
+{
+ return SetAttr(attr, val);
+}
+
+public int QueryAttributeOffset(string attr)
+{
+ return used_attributes_offsets[attr];
+}
+
+public status TestLimitViolation(mapping check)
+{
+ int k,test;
+ mixed* ind;
+
+ if(!check || !mappingp(check))
+ {
+ return 0;
+ }
+
+ test=0;
+ ind=m_indices(check);
+ for( k=sizeof(ind)-1 ; k>=0 ; k-- )
+ {
+ test+=check[ind[k]];
+ }
+
+ test+=cumulative_mod;
+ if(test>CUMULATIVE_ATTR_LIMIT)
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ *------------------------------------------------------------
+ * attributes compatibility functions
+ */
+
+protected int _filterattr_str(int val)
+{
+ return ( (val<0) ? 0 : (val>20) ? 20 : val );
+}
+
+protected int _filterattr_dex(int val)
+{
+ return ( (val<0) ? 0 : (val>20) ? 20 : val );
+}
+
+protected int _filterattr_int(int val)
+{
+ return ( (val<0) ? 0 : (val>20) ? 20 : val );
+}
+
+protected int _filterattr_con(int val)
+{
+ return ( (val<0) ? 0 : (val>20) ? 20 : val );
+}