blob: 9961bfeaec28f5e07c94149fc283bb6bad2236b9 [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(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}) );
}