Added public files
Roughly added all public files. Probably missed some, though.
diff --git a/std/container/description.c b/std/container/description.c
new file mode 100644
index 0000000..c4f7b5c
--- /dev/null
+++ b/std/container/description.c
@@ -0,0 +1,103 @@
+// MorgenGrauen MUDlib
+//
+// container/description.c -- standard description for containers
+//
+// $Id: description.c 8755 2014-04-26 13:13:40Z Zesstra $
+
+inherit "/std/thing/description";
+
+#pragma strict_types
+#pragma save_types
+#pragma range_check
+#pragma no_clone
+#pragma pedantic
+
+#define NEED_PROTOTYPES
+
+#include <container.h>
+#include <properties.h>
+#include <defines.h>
+#include <wizlevels.h>
+
+
+void create()
+{
+ ::create();
+ SetProp(P_TRANSPARENT, 1);
+ AddId("Container");
+}
+
+varargs string long(int mode) {
+ string descr, inv_descr;
+
+ descr = process_string(QueryProp(P_LONG));
+ if(!QueryProp(P_TRANSPARENT)) return descr;
+
+ inv_descr = make_invlist(PL, all_inventory(ME), mode );
+ if ( inv_descr != "" )
+ descr += capitalize(QueryPronoun(WER)) + " enthaelt:\n" + inv_descr;
+ return descr;
+}
+
+// flags: 1 - wizard, 2 - don't collect equal objects '
+// flags: 4 - don't append infos for wizards
+private void stringenize(mixed obj, int flags, mixed objs, mixed info)
+{
+ string id, tmp;
+ int idx;
+
+ if ( (!(flags & 4) && (flags & 1))) {
+ //wenn Magier und Magierinfos angehaengt werden sollen:
+ tmp = capitalize(obj->short()||"")[0..<2]
+ + " ["+object_name(obj)+"]";
+ }
+ else if (obj->QueryProp(P_INVIS)) {
+ //keine Ausgabe bzw. leerer String, wird dann von collect rausgeschmissen
+ tmp="";
+ }
+ else {
+ //Spieler, Magier ohne P_WANTS_TO_LEARN etc.
+ tmp = capitalize(obj->short()||"")[0..<2];
+ }
+ //wenn wizard und 'dont collect equal objects': id ist object_name()
+ if(flags & 3 || living(obj))
+ id = object_name(obj);
+ //sonst nehmen wir den Namen der Blueprint ->zusammenfassen der Objekte
+ else
+ id = BLUE_NAME(obj) + tmp;
+ // Anzahl des jeweiligen Objekts (anhand von id) zaehlen.
+ if((idx = member(objs, id)) == -1)
+ {
+ objs += ({ id });
+ info += ({ ({ tmp, 1, obj}) });
+ }
+ else
+ info[idx][1]++;
+}
+
+private string collect(mixed obj)
+{
+ //bekommt ein Array ({name,anzahl,objekt})
+ //Objekte ohne Namen (P_SHORT==0 oder P_INVIS) wegwerfen
+ if(!sizeof(obj[0])) return 0;
+ // Objektname + (Anzahl) zurueckgeben.
+ return obj[0] + (obj[1] > 1 ? " ("+obj[1]+")" : "");
+}
+
+// flags: 1 - return array, 2 - don't collect equal objects '
+// flags: 4 - don't append infos for wizards
+varargs mixed make_invlist(object viewer, mixed inv, int flags)
+{
+ int iswiz;
+ mixed objs, info;
+
+ iswiz = IS_LEARNER( viewer ) && viewer->QueryProp(P_WANTS_TO_LEARN);
+ objs = ({}); info = ({});
+ map(inv, #'stringenize/*'*/, iswiz | (flags & 2) | (flags & 4), &objs, &info);
+ if(flags & 1) return info;
+ inv = map(info, #'collect/*'*/) - ({ 0 });
+ if(!sizeof(inv)) return "";
+ return sprintf("%"+(sizeof(inv) > 6 ? "#" : "=")+"-78s",
+ implode(inv, "\n")) + "\n";
+}
+
diff --git a/std/container/inventory.c b/std/container/inventory.c
new file mode 100644
index 0000000..0a057b7
--- /dev/null
+++ b/std/container/inventory.c
@@ -0,0 +1,128 @@
+// MorgenGrauen MUDlib
+//
+// container/inventory.c -- Umgang mit besonderen Objekten im Inventory
+//
+// $Id: inventory.c 6379 2007-07-20 22:32:02Z Zesstra $
+
+#pragma strict_types
+#pragma save_types
+//#pragma range_check
+#pragma no_clone
+#pragma pedantic
+
+#define NEED_PROTOTYPES
+
+#include <thing.h>
+#include <properties.h>
+#include <sensitive.h>
+
+#define ME this_object()
+
+void RemoveSensitiveObjectFromList(object ob, string list) {
+ mixed a,b,c;
+ int i,f;
+
+ if (!pointerp(a=QueryProp(SENS_PROP_PREFIX+list)))
+ return;
+ f=1;
+ for (i=sizeof(a)-1;i>=0;i--)
+ if (!pointerp(b=a[i]) ||
+ !sizeof(b) ||
+ !objectp(c=b[0]) ||
+ environment(c)!=ME ||
+ c==ob)
+ a[i]=f=0;
+ if (f)
+ return;
+ a-=({0});
+ if (!sizeof(a))
+ a=0;
+ SetProp(SENS_PROP_PREFIX+list,a);
+}
+
+void RemoveSensitiveObject(object ob) {
+ RemoveSensitiveObjectFromList(ob,SENSITIVE_INVENTORY);
+ RemoveSensitiveObjectFromList(ob,SENSITIVE_INVENTORY_TRIGGER);
+}
+
+varargs void InsertSensitiveObjectToList(object ob, string list, string key,
+ int threshold, mixed *opt) {
+ mixed a;
+ int i;
+
+ if (!pointerp(a=QueryProp(SENS_PROP_PREFIX+list)))
+ a=({});
+ for (i=sizeof(a)-1;i>=0;i--)
+ if (a[i][SENS_OBJECT]==ob && a[i][SENS_KEY]==key)
+ return;
+ a+=({({ob,symbol_function(SENS_TRIGGER_PREFIX+list,ob),
+ key,threshold,opt})});
+ SetProp(SENS_PROP_PREFIX+list,a);
+}
+
+void InsertSensitiveObject(object ob, mixed arg) {
+ int i;
+ mixed x;
+ mapping map_ldfied;
+
+ if (!pointerp(arg))
+ return;
+ for (i=sizeof(arg)-1;i>=0;i--)
+ if (pointerp(x=arg[i]) &&
+ sizeof(x)>=3 &&
+ stringp(x[0]) &&
+ stringp(x[1]) &&
+ intp(x[2])) {
+ InsertSensitiveObjectToList(ob,x[0],x[1],x[2],x[3..]);
+ call_other(ME,SENS_INSERT_PREFIX+x[0],ob,x[1],x[2],x[3..]);
+ }
+}
+
+varargs void insert_sensitive_inv(object ob, string key,
+ int threshold, mixed *opt) {
+ // Diese Funktion sucht, ob beim Hinzufuegen eines sensitiven Objekts
+ // schon ein Objekt da ist, dass dieses ausloest.
+ // z.B. (dynamit, feuer, 100, opt_dynamit) sorgt fuer
+ // dynamit->trigger_sensitive_inv(fackel,feuer,120,opt_fackel,opt_dynamit)
+ // wenn eine Fackel vorher mit Wert 120 eingetragen war.
+ mixed a,x;
+ int i;
+
+ if (!pointerp(a=QueryProp(P_SENSITIVE_INVENTORY_TRIGGER)) ||
+ !objectp(ob))
+ return;
+ for (i=sizeof(a)-1;i>=0;i--)
+ if (pointerp(x=a[i]) &&
+ x[SENS_KEY]==key &&
+ x[SENS_THRESHOLD]>threshold && // Ist der Ausloeser gross genug?
+ objectp(x[SENS_OBJECT]) &&
+ environment(x[SENS_OBJECT])==environment(ob))
+ ob->trigger_sensitive_inv(x[SENS_OBJECT],x[SENS_KEY],x[SENS_THRESHOLD],
+ x[SENS_OPT],opt);
+ // Zuerst Trigger-Optionen, dann Optionen des sensitiven Objekts
+}
+
+varargs void insert_sensitive_inv_trigger(object ob, string key,
+ int threshold, mixed *opt) {
+ // Diese Funktion sucht, ob ein sensitives Objekt im Inventory ist,
+ // das durch dieses Objekt ausgeloest wird.
+ // z.B. (fackel, feuer, 120, opt_fackel) sorgt fuer
+ // dynamit->trigger_sensitive_inv(fackel,feuer,120,opt_fackel,opt_dynamit)
+ // wenn Dynamit mit Wert<120 eingetragen war
+ mixed a,x;
+ int i;
+
+ if (!pointerp(a=QueryProp(P_SENSITIVE_INVENTORY)) ||
+ !objectp(ob))
+ return;
+ for (i=sizeof(a)-1;i>=0;i--)
+ if (pointerp(x=a[i]) &&
+ x[SENS_KEY]==key &&
+ x[SENS_THRESHOLD]<threshold && // Ausloeser gross genug?
+ objectp(x[SENS_OBJECT]) &&
+ environment(x[SENS_OBJECT])==environment(ob) &&
+ closurep(x[SENS_CLOSURE]))
+ funcall(x[SENS_CLOSURE],
+ ob,key,threshold,opt,x[SENS_OPT]);
+ // Zuerst Trigger-Optionen, dann Optionen des sensitiven Objekts
+}
diff --git a/std/container/items.c b/std/container/items.c
new file mode 100644
index 0000000..9961bfe
--- /dev/null
+++ b/std/container/items.c
@@ -0,0 +1,256 @@
+// MorgenGrauen MUDlib
+//
+// container/items.c -- creating extra items in room
+//
+// $Id: items.c 8811 2014-05-09 17:30:37Z Zesstra $
+
+// extra items handling
+//
+// AddItem(string filename, int refresh)
+// Clones an item and puts it into the room. <refresh> may be
+// on of the following:
+// REFRESH_NONE: No refresh done until reboot.
+// REFRESH_DESTRUCT: Refresh on reset if item was destructed.
+// REFRESH_REMOVE: Refresh on reset if item was removed from room.
+// REFRESH_ALWAYS: Create a new clone on every reset.
+//
+// The commands are implemented as properties P_ITEMS as mapping. They are
+// stored locally (_set_xx) as mapping to speed up the routines
+// in this module.
+//
+// Format of key and data in the P_ITEMS mapping:
+//
+// ([ key1 : refresh1; obp1; arr1, ..., keyn : refreshn; obpn; arrn ])
+
+#include <sys_debug.h>
+#pragma strict_types
+#pragma save_types
+#pragma range_check
+#pragma no_clone
+#pragma pedantic
+
+#define NEED_PROTOTYPES
+#include <thing/properties.h>
+#include <rooms.h>
+#include <container.h>
+#undef NEED_PROTOTYPES
+#include <defines.h>
+#include <config.h>
+#include <properties.h>
+#include <moving.h>
+#include <daemon.h>
+
+protected void create()
+{
+ Set( P_ITEMS, ({}) );
+ Set( P_ITEMS, SECURED, F_MODE_AS );
+
+ OBJECTD->QueryObject(); // querying general objects
+}
+
+protected void create_super() {
+ set_next_reset(-1);
+}
+
+/* Kram zum Aufraeumen von multiplen gleichen Items im Container. */
+private object removeable_ob( object ob )
+{
+ if ( !query_once_interactive(ob) && !living(ob) )
+ return ob;
+
+ return 0;
+}
+
+protected varargs void remove_multiple(int limit, mixed fun)
+{
+ object *inh = all_inventory(this_object()) - ({0});
+
+ inh = filter( inh, #'removeable_ob );
+ foreach(mixed item : QueryProp(P_ITEMS))
+ inh -= ({ item[0] });
+
+ if (!stringp(fun) && !closurep(fun))
+ fun = "description_id";
+ inh = unique_array(inh, fun, 0);
+ foreach(mixed arr: inh)
+ {
+ if (sizeof(arr) <= limit)
+ continue;
+ catch(call_other(arr[limit ..], "remove"); publish);
+ }
+}
+
+
+/* Item handling */
+public varargs object AddItem( mixed filename, int refresh, mixed props )
+{
+ string file;
+ object ob;
+ int i;
+
+ if( pointerp(filename) ) {
+ for( i = sizeof(filename); i--; )
+ filename[i] = (string)master()->_get_path( filename[i], "?" );
+
+ file = filename[random( sizeof(filename) )];
+ }
+ else
+ file = filename = (string)master()->_get_path( filename, "?" );
+
+ if ( props == 1 )
+ catch(ob = load_object( file); publish);
+ else
+ catch(ob = clone_object(file); publish);
+
+ if (objectp(ob)) {
+ ob->move( this_object(), M_NOCHECK|M_NO_ATTACK );
+ // mit Absicht keine Pruefung aufs Move, wenns nicht geht, solls 2s
+ // spaeter auf der Ebene buggen, weil praktisch niemand im create() das
+ // Ergebnis vom AddItem() prueft.
+ }
+
+ // In P_ITEMS vermerken, es sei denn, REFRESH_NONE ist gegeben, in dem
+ // Fall ist die Speicherung voellig unnoetig.
+ // TODO: Pruefen, ob das wirklich problemlos geht. Bis dahin werden auch
+ // TODO::REFRESH_NONE-Items vermerkt. (s. clean_up() in /std/room.c)
+ //if (!(refresh & REFRESH_NONE)) {
+ SetProp( P_ITEMS, QueryProp(P_ITEMS) +
+ ({ ({ ob, // RITEM_OBJECT
+ filename, // RITEM_FILE
+ refresh // RITEM_REFRESH
+ }) +
+ ((mappingp(props) || props == 1) ? ({ props }) : ({})) }) );
+ //}
+
+ if ( ob && mappingp(props) )
+ walk_mapping( props, symbol_function( "SetProp", ob ) );
+
+ return ob;
+}
+
+
+private void ri_rem_ob( object ob )
+{
+ object *inv;
+ int i;
+
+ if ( objectp(ob) && present(ob, this_object()) ) {
+ inv = deep_inventory(ob);
+
+ for ( i = sizeof(inv); i--; )
+ if ( inv[i] ) {
+ inv[i]->remove(1);
+
+ if ( inv[i] )
+ destruct(inv[i]);
+ }
+
+ ob->remove(1);
+
+ if ( ob )
+ destruct(ob);
+ }
+}
+
+
+private int ri_filter( mixed *ritem, mixed file )
+{
+ object ob, *inv;
+ int i;
+
+ ob = ritem[RITEM_OBJECT];
+
+ if ( stringp(file) && ritem[RITEM_FILE] == file )
+ return ri_rem_ob(ob), 0;
+ else if ( pointerp(ritem[RITEM_FILE]) && pointerp(file) &&
+ sizeof(file & ritem[RITEM_FILE]) == sizeof(ritem[RITEM_FILE]) )
+ return ri_rem_ob(ob), 0;
+
+ return 1;
+}
+
+
+public void RemoveItem( mixed filename )
+{
+ mixed *items;
+ int i;
+
+ if ( !pointerp(items = QueryProp(P_ITEMS)) || !sizeof(items) )
+ return;
+
+ if ( pointerp(filename) )
+ for ( i = sizeof(filename); i--; )
+ filename[i] = (string)master()->_get_path( filename[i], "?" );
+ else
+ filename = (string)master()->_get_path( filename, "?" );
+
+ SetProp( P_ITEMS, filter( items, #'ri_filter/*'*/, filename ) );
+}
+
+
+private mixed _do_refresh( mixed item )
+{
+ string file;
+ object ob;
+
+ if ( !pointerp(item) || item[RITEM_REFRESH] == REFRESH_NONE )
+ return item;
+
+ if ( pointerp(item[RITEM_FILE]) )
+ file = item[RITEM_FILE][random( sizeof(item[RITEM_FILE]) )];
+ else
+ file = item[RITEM_FILE];
+
+ switch( item[RITEM_REFRESH] ){
+ case REFRESH_MOVE_HOME:
+ if ( objectp(item[RITEM_OBJECT]) &&
+ environment(item[RITEM_OBJECT]) != ME ) {
+ item[RITEM_OBJECT]->move( ME, M_GO|M_NO_ATTACK );
+ break;
+ }
+
+ // fall through
+ case REFRESH_DESTRUCT:
+ if ( objectp(item[RITEM_OBJECT]) )
+ break; // else FALL THROUGH
+
+ case REFRESH_REMOVE:
+ if ( objectp(item[RITEM_OBJECT]) &&
+ environment(item[RITEM_OBJECT]) == ME )
+ break; // else FALL THROUGH
+
+ default:
+ if ( sizeof(item) > RITEM_PROPS && item[RITEM_PROPS] == 1 ) {
+ ob = load_object(file);
+ }
+ else
+ ob = clone_object(file);
+
+ ob->move( ME, M_NOCHECK|M_NO_ATTACK );
+ break;
+ }
+
+ if ( ob ){
+ item[RITEM_OBJECT] = ob;
+
+ if ( sizeof(item) > RITEM_PROPS && mappingp(item[RITEM_PROPS]) )
+ walk_mapping( item[RITEM_PROPS], symbol_function( "SetProp", ob ) );
+ }
+
+ return item;
+}
+
+
+// reset handling: check how the items should be refreshed.
+void reset()
+{
+ mixed *items;
+
+ if ( !pointerp(items = QueryProp(P_ITEMS)) ){
+ SetProp( P_ITEMS, ({}) );
+ return;
+ }
+
+ SetProp( P_ITEMS, map( items, #'_do_refresh/*'*/ ) - ({0}) );
+}
+
diff --git a/std/container/light.c b/std/container/light.c
new file mode 100644
index 0000000..435400f
--- /dev/null
+++ b/std/container/light.c
@@ -0,0 +1,149 @@
+// MorgenGrauen MUDlib
+//
+// container/light.c -- Lichtsystem fuer Container
+//
+// $Id: description.c 6986 2008-08-22 21:32:15Z Zesstra $
+
+inherit "/std/thing/light";
+
+#pragma strict_types
+#pragma save_types,rtt_checks
+#pragma range_check
+#pragma no_clone
+#pragma pedantic
+
+#define NEED_PROTOTYPES
+
+#include <container.h>
+#include <properties.h>
+
+// BTW: _query_last_content_change() sollte bloss nie auch -1 fuer
+// uninitialisiert zurueckliefern...
+private nosave int last_light_calc = -1;
+
+protected void create()
+{
+ ::create();
+ // wieviel Licht schluckt der Container _muss_ > 0 sein!
+ SetProp(P_LIGHT_TRANSPARENCY, 2);
+}
+
+protected void create_super() {set_next_reset(-1);}
+
+
+static mixed _query_light_transparency()
+{
+ if (QueryProp(P_TRANSPARENT))
+ return Query(P_LIGHT_TRANSPARENCY,F_VALUE);
+ return 999;
+}
+
+public int add_light_sources(int * sources) {
+ float light = 0.0;
+ //printf("als(%O): %O\n",this_object(),sources);
+ // Alle Lichtlevel werden als Exponent von e aufgefasst und die Summe dieser
+ // Potenzen gebildet.
+ foreach(int l : sources) {
+ if (l > 0)
+ light += exp(l);
+ else if (l < 0)
+ light -= exp(abs(l));
+ // l==0 muss ignoriert werden
+ }
+ // anschliessend wird aus dieser Summe der natuerliche Logarithmus
+ // berechnet.
+ // auf diese Weise haben hoehere Lichtlevel ueberproportional viel Einfluss
+ // auf die Helligkeit im Raum, kleine Lichtlevel fallen aber nicht komplett
+ // raus.
+ if (light > 0) {
+ light = log(light);
+ }
+ else if (light < 0) {
+ light = -log(abs(light));
+ }
+
+ //printf("als(): %O\n",light);
+ // runden und als int zurueckgeben.
+ if (light >= 0)
+ return to_int(light+0.5);
+ //else
+ return to_int(light-0.5);
+}
+
+static int _query_total_light()
+{
+ int totallight;
+
+ if ( _query_last_content_change() == last_light_calc )
+ return Query(P_TOTAL_LIGHT);
+
+ // eigenes P_LIGHT und P_TOTAL_LIGHT der enthaltenen Objekte verrechnen
+ int intlight = add_light_sources(
+ all_inventory()->QueryProp(P_TOTAL_LIGHT) + ({QueryProp(P_LIGHT)}));
+ // P_INT_LIGHT (gerundet) abspeichern
+ Set(P_INT_LIGHT, intlight, F_VALUE);
+
+ // Licht nach aussen muss Containertransparenz beruecksichtigen.
+ if (intlight > 0) {
+ totallight = intlight - QueryProp(P_LIGHT_TRANSPARENCY);
+ if (totallight < 0)
+ totallight = 0;
+ }
+ else {
+ totallight = intlight + QueryProp(P_LIGHT_TRANSPARENCY);
+ if (totallight > 0)
+ totallight = 0;
+ }
+ //printf("_query_total_light(%O): %O\n",this_object(),totallight);
+
+ last_light_calc = _query_last_content_change();
+
+ // Runden und Konversion nach int nicht vergessen...
+ if (totallight > 0)
+ return SetProp(P_TOTAL_LIGHT, to_int(totallight + 0.5));
+ //else
+ return SetProp(P_TOTAL_LIGHT, to_int(totallight - 0.5));
+}
+
+static int _query_int_light()
+{
+ int intlight, envlight;
+
+ if ( _query_last_content_change() != last_light_calc )
+ _query_total_light();
+
+ // P_INT_LIGHT des environments kann sich natuerlich aendern _ohne_ das
+ // etwas an einem container geaendert wird. Daher Auswertung jedes mal
+ // neu aktualisieren.
+ if (!environment()
+ || !(envlight=(int)environment()->QueryProp(P_INT_LIGHT)))
+ return Query(P_INT_LIGHT, F_VALUE);
+ else {
+ intlight = Query(P_INT_LIGHT, F_VALUE);
+ int transparency = QueryProp(P_LIGHT_TRANSPARENCY);
+
+ // bei einem transparentem Container kann natuerlich das Licht des
+ // environments den Container auch ausleuchten....
+ // (Anmerkung: in dem Licht von draussen ist unser Lichtanteil
+ // natuerlich auch drin, gedaempft um die Transparenz (raus und rein).
+ // Ich vernachlaessige das.)
+ if (abs(envlight) > transparency) {
+ if (envlight > 0)
+ envlight -= transparency;
+ else
+ envlight += transparency;
+ // jetzt Licht von aussen und innen verrechnen
+ intlight = add_light_sources(({intlight, envlight}));
+ }
+ // else: nur P_INT_LIGHT, Licht des Environments keine Bedeutung
+ }
+ return intlight;
+}
+
+static int _set_light(int light)
+{
+ last_light_calc=-1;
+
+ return ::_set_light(light);
+}
+
diff --git a/std/container/moneyhandler.c b/std/container/moneyhandler.c
new file mode 100644
index 0000000..ae25453
--- /dev/null
+++ b/std/container/moneyhandler.c
@@ -0,0 +1,53 @@
+// MorgenGrauen MUDlib
+//
+// container/moneyhandler.c -- money handler for container
+//
+// $Id: moneyhandler.c 6738 2008-02-19 18:46:14Z Humni $
+#pragma strong_types
+#pragma save_types
+#pragma range_check
+#pragma no_clone
+#pragma pedantic
+
+#define NEED_PROTOTYPES
+#include <thing/properties.h>
+#undef NEED_PROTOTYPES
+
+#include <properties.h>
+#include <moving.h>
+#include <money.h>
+
+public int AddMoney( int amount )
+{
+ object ob;
+ int ret;
+
+ if ( !amount )
+ return 1;
+
+ ob = clone_object( GELD );
+ ob->SetProp( P_AMOUNT, amount );
+
+ ret=ob->move( this_object(), M_PUT|M_MOVE_ALL );
+ // Bei fehlerhaftem move ggf. wieder zerstoeren.
+ if ((ret != MOVE_OK)
+ && ob)
+ {
+ ob->remove(1);
+ }
+ return ret;
+}
+
+public int QueryMoney()
+{
+ object money;
+ int geld;
+
+ if ( money = present_clone(GELD, this_object()) )
+ geld = money->QueryProp(P_AMOUNT);
+
+ if ( money = present(GELDBOERSE_MIT_GELD, this_object()) )
+ geld += money->QueryProp(P_AMOUNT);
+
+ return geld;
+}
diff --git a/std/container/restrictions.c b/std/container/restrictions.c
new file mode 100644
index 0000000..3da5c9d
--- /dev/null
+++ b/std/container/restrictions.c
@@ -0,0 +1,480 @@
+// MorgenGrauen MUDlib
+//
+// container/restrictions.c -- container restrictions
+//
+// $Id: restrictions.c 9020 2015-01-10 21:49:41Z Zesstra $
+
+// This is a simple container to put objects in. It defines all functions
+// which are necessary to describe an object which can be filled with
+// other things.
+//
+// It will support restrictions for volume, weight etc.
+//
+// The following properties are defined:
+// P_MAX_WEIGHT - maximum weight which container can carry
+// P_TOTAL_WEIGHT - total weight, with contents.
+// P_WEIGHT - the weight of the container without contents
+//
+// Functions for manipulation of weight
+// MayAddWeight(weight) - Can <weight> be inserted?
+// AddWeight(weight) - Add an amount of <weight>
+//
+// IMPORTANT: unit equals 1 gram
+
+#pragma strict_types
+#pragma save_types
+//#pragma range_check
+#pragma no_clone
+#pragma pedantic
+
+#define NEED_PROTOTYPES
+
+#include "/sys/thing/properties.h"
+#include <properties.h>
+#include <defines.h>
+#include <thing/description.h>
+
+// local properties prototypes
+static int _query_total_weight();
+
+
+private nosave int LastWeightCalc, contents, LastObjectCount, objcount;
+private nosave int last_content_change;
+
+
+void create()
+{
+ Set( P_WEIGHT_PERCENT, 50 );
+ Set( P_TOTAL_WEIGHT, NOSETMETHOD, F_SET_METHOD );
+ Set( P_TOTAL_WEIGHT, PROTECTED, F_MODE );
+ Set( P_MAX_OBJECTS, 100 );
+ Set( P_TOTAL_OBJECTS, NOSETMETHOD, F_SET_METHOD );
+ Set( P_TOTAL_OBJECTS, PROTECTED, F_MODE );
+ LastWeightCalc = -1;
+ LastObjectCount = -1;
+}
+
+
+static int _query_last_content_change()
+{
+ return last_content_change;
+}
+
+
+// absichtlich public, da es von der simul_efun.c *direkt* aufgerufen
+// wird aus Performancegruenden!
+public varargs int _set_last_content_change( mixed wert )
+{
+ // Der uebergebene Wert ist unerheblich. Die Property
+ // P_LAST_CONTENT_CHANGE wird so oder so bei jedem SetProp()-
+ // Aufruf um eins erhoeht, um der 2s-"Unschaerfe" von time()
+ // aus dem Weg zu gehen.
+ return ++last_content_change;
+}
+
+
+int query_weight_contents()
+{
+ object *objs;
+ int w, w2, i;
+
+ if ( last_content_change == LastWeightCalc )
+ return contents;
+
+ w = 0;
+ objs = all_inventory(this_object());
+ i = sizeof(objs);
+
+ while ( i-- ){
+ if ( !(w2 = (int)objs[i]->QueryProp(P_TOTAL_WEIGHT)) )
+ w2 = (int)objs[i]->QueryProp(P_WEIGHT);
+ w += w2;
+ }
+
+ LastWeightCalc = last_content_change;
+ return contents = w;
+}
+
+
+static int _query_total_objects()
+{
+ if ( last_content_change == LastObjectCount )
+ return objcount;
+
+ objcount = sizeof( filter_objects( all_inventory(), "short" ) );
+ LastObjectCount = last_content_change;
+ return objcount;
+}
+
+
+// diese Funktion sollte von Raeumen natuerlich ueberschrieben werden...
+int MayAddObject( object ob )
+{
+ if (ob) {
+ if ( !ob->short() )
+ return 1; // invis-Objekte duerfen immer
+
+ if ( ob == ME || environment(ob) == ME)
+ return 1; // objekt ist schon drin
+ }
+
+ return (QueryProp(P_TOTAL_OBJECTS) < QueryProp(P_MAX_OBJECTS));
+}
+
+
+#define ENV environment
+#define PO previous_object()
+
+int MayAddWeight( int w )
+{
+ int nw, aw;
+
+ // was nix wiegt, passt
+ if ( w <= 0 )
+ return 0;
+
+ nw = w; // Gewicht im neuen Container
+ aw = 0; // Gewicht fuer das env()
+
+ // Von Raum in Behaelter im Spieler: Container sieht volles Gewicht (nw=w),
+ // Check im env() (Spieler) mit reduziertem Gewicht.
+ if ( ENV() && PO && ENV(PO) != ENV() )
+ aw = QueryProp(P_WEIGHT_PERCENT) * w / 100 || 1;
+
+ if ( PO && ENV(PO) && ENV(ENV(PO)) ){
+ // Wenn das Objekt ein env() hochbewegt wird, wird das Gewicht im alten
+ // Container abgezogen. Weiterer Check im env() ist unnoetig (aw=0).
+ if ( ENV(ENV(PO)) == ME )
+ nw = w - (int)ENV(PO)->QueryProp(P_WEIGHT_PERCENT) * w / 100;
+ // Eine Ebene tiefer bewegen: Test im neuen Container mit unveraendertem
+ // Gewicht; Check im env() mit um Gewichtsreduktion verringertem Gewicht
+ else if ( present( ME, ENV(PO) ) )
+ aw = QueryProp(P_WEIGHT_PERCENT) * w / 100 - w;
+ // Auf derselben Ebene verschieben (von Paket in Beutel):
+ // Neuer Container sieht volles Gewicht (nw=w), Check im env() mit
+ // Differenz aus Gewicht in Container1 und in Container2.
+ else if ( ENV(ENV(ENV(PO))) && ENV() == ENV(ENV(PO)) )
+ aw = QueryProp(P_WEIGHT_PERCENT) * w / 100
+ - ((int)ENV(PO)->QueryProp(P_WEIGHT_PERCENT) * w / 100 || 1);
+ }
+
+ if ( query_weight_contents() + nw > QueryProp(P_MAX_WEIGHT) )
+ // Container kann Gewicht nicht mehr aufnehmen
+ return -1;
+
+ if ( aw && ENV()->MayAddWeight(aw) < 0 )
+ // Umgebung des Containers kann Gewicht nicht mehr aufnehmen
+ return -2;
+
+ return 0;
+}
+
+
+/* Redefine PreventInsert() to prevent inserting of special objects. If
+ * a value greater 0 is returned the object ob can't be inserted in the
+ * container.
+ */
+public int PreventInsert( object ob ) { return 0; }
+public int PreventLeave( object ob, mixed dest ) { return 0; }
+public int PreventInsertLiving( object ob ) { return 0; }
+public int PreventLeaveLiving( object ob, mixed dest ) { return 0; }
+public void NotifyInsert(object ob, object oldenv) { }
+
+// **** local property methods
+static int _query_total_weight()
+{
+ return QueryProp(P_WEIGHT) +
+ (QueryProp(P_WEIGHT_PERCENT) * query_weight_contents() / 100);
+}
+
+
+// Hilfsfunktion
+static int _behalten( object ob, string uid )
+{
+ return (string)ob->QueryProp(P_KEEP_ON_SELL) == uid;
+}
+
+
+/*
+ *
+ * get a list of all contained objects matching a complex description
+ *
+ */
+
+#define POS_INVERS 0x01 /* nur zur funktionsinternen Verwendung */
+#define POS_LETZTES 0x02 /* nur zur funktionsinternen Verwendung */
+
+object *present_objects( string complex_desc )
+{
+ int i; // Zaehlervariable
+ int meth; // 0x01 = invers?, 0x02 = letztes?
+ object ob; // einzelnes temporaeres Objekt
+ object *obs; // liste der ausgewaehlten Objekte
+ object *erg; // zum sammeln bis es nachher zurueckgegeben wird...
+ string *strlst; // liste aller Gruppen die mit AND verknuepft sind
+ object haufen;
+
+ strlst = allocate(2);
+
+ if ( sscanf( complex_desc, "%s ausser %s", strlst[0], strlst[1]) == 2 ){
+ erg = present_objects( strlst[0] );
+ obs = present_objects( strlst[1] );
+ return erg-obs;
+ }
+
+ strlst = explode( complex_desc, " und " );
+ erg = ({});
+
+ for ( i = sizeof(strlst); i--; )
+ {
+ complex_desc = strlst[i];
+ // auf letzte/letztes/letzten pruefen...
+ if ( complex_desc[0..5] == "letzte" ){
+ switch( complex_desc[6..6] ){
+ case " ":
+ meth |= POS_LETZTES;
+ complex_desc = complex_desc[7..];
+ break;
+ case "s":
+ case "n":
+ case "m":
+ case "r":
+ if ( complex_desc[7..7] != " " )
+ break;
+ meth |= POS_LETZTES;
+ complex_desc = complex_desc[8..];
+ break;
+ default:
+ }
+ }
+
+ // auf verneinung pruefen
+ if ( complex_desc[0..5] == "nicht " ){
+ meth |= POS_INVERS;
+ complex_desc = complex_desc[6..];
+ }
+
+ obs=({});
+ // nun nach Main-Ids (Gruppen) suchen...
+ if ( meth & POS_LETZTES )
+ { // geht es nur um den letzten Gegenstand?
+ switch( complex_desc ){
+ case "waffe":
+ obs = filter_objects( all_inventory(), "QueryProp",
+ P_WEAPON_TYPE );
+ break;
+
+ case "ruestung":
+ obs = filter_objects( all_inventory(), "QueryProp",
+ P_ARMOUR_TYPE );
+ break;
+
+ case "kleidung":
+ obs = filter_objects( all_inventory(), "IsClothing");
+ break;
+
+ case "verschiedenem":
+ case "verschiedenes":
+ obs = all_inventory();
+ obs -= filter_objects( obs, "QueryProp", P_WEAPON_TYPE );
+ obs -= filter_objects( obs, "QueryProp", P_ARMOUR_TYPE );
+ obs -= filter_objects( obs, "IsClothing");
+ obs -= filter( obs, #'living/*'*/ );
+ break;
+
+ case "eigenes":
+ case "meins":
+ if (objectp(haufen=present("\nhaufen "+
+ this_player()->name(WEM)))) {
+ obs = all_inventory(haufen);
+ }
+ // kein break;, Fall-through!
+ case "behaltenem":
+ case "behaltenes":
+ obs += filter( all_inventory(), "_behalten", ME,
+ getuid(this_player() || previous_object()) );
+
+ obs += (QueryProp(P_ARMOURS) || ({}))
+ + ({ QueryProp(P_WEAPON) }) - ({ 0 });
+ break;
+
+ case "gegenstand":
+ obs = all_inventory() -
+ filter( all_inventory(), #'living/*'*/ );
+ break;
+
+ default:
+ obs = filter_objects( all_inventory(), "id", complex_desc );
+ }
+
+ // unsichtbare objekte entfernen
+ obs = filter_objects( obs, "short" );
+
+ // letzten Gegenstand raussuchen
+ obs = obs[0..0];
+ } // if (letzter Gegenstand)
+ else
+ { // ganze Gruppen und nicht nur das letzte Objekt
+ switch ( complex_desc )
+ {
+ case "allem":
+ case "alles":
+ case "jeden gegenstand":
+ case "jedem gegenstand":
+ case "gegenstaende":
+ case "alle gegenstaende":
+ case "allen gegenstaenden":
+ if ( meth & POS_INVERS )
+ continue; // alles nicht = nichts :)
+
+ obs = all_inventory() -
+ filter( all_inventory(), #'living/*'*/ );
+ break;
+
+ case "waffen":
+ case "jede waffe":
+ case "jeder waffe":
+ case "alle waffen":
+ case "allen waffen":
+ obs = filter_objects( all_inventory(), "QueryProp",
+ P_WEAPON_TYPE );
+ break;
+
+ case "ruestungen":
+ case "jede ruestung":
+ case "jeder ruestung":
+ case "alle ruestungen":
+ case "allen ruestungen":
+ obs = filter_objects( all_inventory(), "QueryProp",
+ P_ARMOUR_TYPE );
+ break;
+
+ case "kleidung":
+ case "jede kleidung":
+ case "jeder kleidung":
+ case "alle kleidung":
+ case "allen kleidung":
+ obs = filter_objects( all_inventory(), "IsClothing");
+ break;
+
+ case "gegenstand":
+ obs = filter_objects( all_inventory() -
+ filter( all_inventory(),
+ #'living/*'*/ ),
+ "short" )[0..0];
+ break;
+
+ case "verschiedenem":
+ case "verschiedenes":
+ obs = all_inventory();
+ obs -= filter_objects( obs, "QueryProp", P_WEAPON_TYPE );
+ obs -= filter_objects( obs, "QueryProp", P_ARMOUR_TYPE );
+ obs -= filter_objects( obs, "IsClothing");
+ obs -= filter( obs, #'living/*'*/ );
+ break;
+
+ case "eigenes":
+ case "eigenem":
+ case "eigenen":
+ case "meins":
+ case "alles eigene":
+ if (objectp(haufen=present("\nhaufen "+
+ this_player()->name(WEM)))) {
+ obs = all_inventory(haufen);
+ }
+ // kein break;, Fall-through!
+ case "behaltenem":
+ case "behaltenen":
+ case "behaltenes":
+ case "alles behaltene":
+ obs += filter( all_inventory(), "_behalten", ME,
+ getuid(this_player() || previous_object()) );
+
+ obs += (QueryProp(P_ARMOURS) || ({}))
+ + ({ QueryProp(P_WEAPON) }) - ({ 0 });
+ break;
+
+ default:
+ if ( complex_desc[0..3] == "jede" ||
+ complex_desc[0..4] == "alle ")
+ {
+ if ( complex_desc[4..4] == " " )
+ {
+ obs = filter_objects( all_inventory(), "id",
+ complex_desc[5..] );
+ break;
+ }
+ else
+ {
+ switch( complex_desc[4..5] )
+ {
+ case "m ":
+ case "r ":
+ case "n ":
+ case "s ":
+ obs = filter_objects( all_inventory(), "id",
+ complex_desc[6..] );
+ break;
+
+ default:
+ obs = 0;
+ }
+ if (obs)
+ break;
+ }
+ }
+
+ // Der Normalfall: einzelne ID...
+ ob = present( complex_desc, ME );
+ // Achtung: dieser Teil setzt das for() fort (continue) und
+ // umgeht dabei die Pruefung auf Sichtbarkeit nach dem Ende vom
+ // switch(). Aus diesem Grunde muss hier selber geprueft
+ // werden.
+ if ( meth & POS_INVERS )
+ {
+ if ( ob && ob != ME )
+ erg += (filter_objects( all_inventory(), "short" )
+ - ({ ob }) );
+ else
+ erg += filter_objects( all_inventory(), "short" );
+ }
+ else if ( ob && ob != ME && !ob->QueryProp(P_INVIS) )
+ erg += ({ ob }); //Normalfall: einzelne ID
+
+ continue;
+
+ } // switch
+ // unsichtbare objekte entfernen
+ obs = filter_objects( obs, "short" );
+ } // else
+
+ if ( meth & POS_INVERS )
+ erg += ( filter_objects( all_inventory(), "short" ) - obs );
+ else
+ erg += obs;
+ } // for
+ return erg;
+}
+
+/*
+ * returns a list of all found objects inside itself
+ * may call same function in objects inside
+ *
+ * Funktion wird nicht mehr von put_and_get aufgerufen, stattdessen wird
+ * direkt present_objects benutzt!
+ */
+object *locate_objects( string complex_desc, int info ) {
+ string was, wo;
+
+ if ( sscanf( complex_desc, "%s in %s", was, wo ) == 2 ){
+ object *found_obs = ({});
+ foreach(object invob: present_objects(wo)) {
+ // || ({}) weil invob ein Objekt ohne locate_objects() sein koennte.
+ found_obs += (object *)invob->locate_objects( was, info) || ({});
+ }
+ return found_obs;
+ }
+ // kein "in" gefunden
+ return present_objects( complex_desc );
+}
+