blob: 08bad24fce9f9aaf8b2db8c580bf550c183aa3b6 [file] [log] [blame]
// 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(ME)-({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()->make_path_absolute( filename[i] );
}
file=filename[random(sizeof(filename))];
}
else
{
file=filename=(string)master()->make_path_absolute(filename);
}
if(props==1)
{
catch(ob=load_object(file); publish);
}
else
{
catch(ob=clone_object(file); publish);
}
if(objectp(ob))
{
ob->move(ME,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;
if(objectp(ob) && environment(ob)==this_object())
{
inv=deep_inventory(ob);
foreach(object o : inv)
{
o->remove(1);
if(objectp(o))
{
destruct(o);
}
}
ob->remove(1);
if(ob)
{
destruct(ob);
}
}
}
private int ri_filter(<int|<string|string*>|object|mapping>* ritem,
string|string* file)
{
object ob;
ob=ritem[RITEM_OBJECT];
if(stringp(file) && ritem[RITEM_FILE]==file)
{
ri_rem_ob(ob);
return 0;
}
else if(pointerp(ritem[RITEM_FILE]) && pointerp(file) &&
sizeof(file & ritem[RITEM_FILE])==sizeof(ritem[RITEM_FILE]))
{
ri_rem_ob(ob);
return 0;
}
return 1;
}
public void RemoveItem(string|string* filename)
{
< <int|<string|string*>|object>* >* items=QueryProp(P_ITEMS);
if(!pointerp(items) || !sizeof(items))
{
return;
}
if(pointerp(filename))
{
foreach(string fn: &filename)
{
fn=master()->make_path_absolute(fn);
}
}
else
{
filename=master()->make_path_absolute( 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}));
}