// File: _call.c
// Mudlib: Nightmare (but see credits)
// Purpose: allow wizards to call functions in objects
// Credits: see _refs.c
#include <daemons.h>
#include <std.h>
inherit DAEMON;
inherit REFS_D;
#define SYNTAX "Syntax: call <object>;<function>;<arg>;<arg>\n"
#define FUNC_LIST ({\
"query_rname",\
"query_title",\
"query_email",\
"query_ip",\
"query_class",\
"query_race",\
"query_guild",\
"query_level",\
"query_hp",\
"query_max_hp",\
"query_attackers",\
"query_hunted",\
})
#define TAB "\t"
mixed do_call( object ob, string func, mixed args );
cmd_call( string a )
{
string str, *exp_a;
mixed objs, funcs, args, tmp, ret, rets;
object ob;
int i, s, fi, fs;
if( !a ) { notify_fail( SYNTAX ); return 0; }
if((string)previous_object()->query_position() == "ambassador") return 0;
// In general logging calls is a bad idea since the effect can be duplicated
// very easily by eval or by an object in the wizards directory
// *shrug* Nightmare wanted it however, so I've #ifdef'ed it.
log_file( "adm/calls",
this_player()-> query_name() + " under privs " + query_privs(previous_object()) + " " +
ctime( time() ) + "\n" + a + "\n"
);
exp_a = explode( a, ";" );
s = sizeof( exp_a );
objs = exp_a[0];
if( s > 1 ) funcs = exp_a[1];
else funcs = FUNC_LIST;
if( s == 3 ) args = ({ exp_a[2] });
if( s > 3 ) args = exp_a[2..(s-1)];
objs = resolv_ref( objs );
if( objs == "users" ) objs = users();
if( !pointerp( objs ) ) objs = ({ objs });
tmp = ({ });
s = sizeof( objs );
for( i = 0 ; i < s ; i++ )
{
if( stringp( objs[i] ) ) ob = get_objects( objs[i],0,1 );
else if( objectp( objs[i] ) ) ob = objs[i];
if( !ob ) write( "Can't identify " + identify( objs[i] ) +
" as an object." );
else tmp += ({ ob });
}
if( !sizeof( tmp ) ) return 1;
objs = tmp;
funcs = resolv_ref( funcs );
if( !pointerp( funcs ) ) funcs = ({ funcs });
tmp = ({ });
s = sizeof( funcs );
for( i = 0 ; i < s ; i ++ )
{
if( stringp( funcs[i] ) ) tmp += ({ funcs[i] });
else write( "Can't identify " + identify( funcs[i] )+
" as a string." );
}
if( !sizeof( tmp ) ) return 1;
funcs = tmp;
if( pointerp( args ) && ( s = sizeof( args ) ) )
for( i = 0 ; i < s ; i++ )
args[i] = resolv_ref( resolv_str( args[i] ) );
rets = ({ });
s = sizeof( objs );
fs = sizeof( funcs );
for( i = 0 ; i < s ; i++ )
{
str = identify( objs[i] );
for( fi = 0 ; fi < fs ; fi++ )
{
ret = do_call( objs[i], funcs[fi], args );
if( ret[0] ) rets += ({ ret[0] });
if( fs == 1 ) str = wrap( str + ret[1] );
else str += (fi?"":"\n") + wrap( ret[1] );
}
message("Ninfo", str, this_player());
}
switch( sizeof( rets ) )
{
case 0: rets = 0; break;
case 1: rets = rets[0];
}
set_ref( 0, rets );
return 1;
}
do_call( object ob, string func, mixed args )
{
mixed ret, err;
int i, s;
string str;
object shad;
function f;
if( !function_exists( func, ob ) )
{
// This needs #ifdef HAS_SHADOW (MudOS driver 0.9.17.3 onwards)
if( ob != shad ) return ({ 0, "- does not contain " + func + "()" });
}
str = "-> " + func;
if( pointerp( args ) && ( s = sizeof( args ) ) )
{
str += "( ";
for( i = 0 ; i < s ; i++ )
{
if( i ) str += ", ";
str += identify( args[i] );
}
str += " )";
} else str += "()";
/*
// how does one do this using function type variables?
f = (: ob, func :);
switch( s )
{
case 0: err=catch(ret=(*f));break;
case 1: err=catch(ret=(*f)(args[0]));break;
case 2: err=catch(ret=(*f)(args[0],args[1]));break;
case 3: err=catch(ret=(*f)(args[0],args[1],args[2]));break;
case 4: err=catch(ret=(*f)(args[0],args[1],args[2],args[3]));break;
default: err=catch(ret=(*f)(args[0],args[1],args[2],args[3],args[4]));break;
}
*/
switch( s )
{
case 0: err=catch(ret=call_other(ob,func));break;
case 1: err=catch(ret=call_other(ob,func,args[0]));break;
case 2: err=catch(ret=call_other(ob,func,args[0],args[1]));break;
case 3: err=catch(ret=call_other(ob,func,args[0],args[1],args[2]));break;
default: err=catch(ret=call_other(ob,func,args[0],args[1],args[2],args[3]));
}
if( err ) return ({ 0, str + TAB + "= ERR(" + identify( err ) + ")" });
return ({ ret, str + TAB + "= " + identify( ret ) });
}
int help()
{
message("Nhelp", SYNTAX+
"Effect: Calls the function <function> in object <object>,\n"+
"passing as many arguments <arg> as you give.\n"+
"If no function is specified a dump of the object is given.\n"+
"<object> and <function> can be arrays (eg \"users\")\n"+
"See also: refs\n", this_player());
return 1;
}