# define A_OBJ 0
# define A_NEXT 1
# define A_VERB 2
# define A_FUNC 3
private int alive; /* living flag */
private mixed *chunks; /* array of action chunks */
private mapping actions; /* objects:actions mapping */
private string saved_action; /* action saved by add_action with 1 argument */
/*
* NAME: _Q_alive()
* DESCRIPTION: return the living status of this object
*/
nomask int _Q_alive()
{
return alive;
}
/*
* NAME: _Q_actions()
* DESCRIPTION: return the action chunks of this object
*/
nomask mixed *_Q_actions()
{
if (PRIVILEGED()) {
return chunks;
}
}
/*
* NAME: _F_add_action()
* DESCRIPTION: define an action for this object
*/
nomask void _F_add_action(object obj, string verb, string func, int flag)
{
if (PRIVILEGED()) {
mixed chunk;
if (flag) {
chunk = ({ obj, actions[obj], verb, func });
chunks = ({ chunk }) + chunks;
actions[obj] = chunk;
} else if (sizeof(chunks) != 0 && mappingp(chunk=chunks[0]) &&
chunk[A_OBJ] == obj && chunk[verb] == 0) {
chunk[verb] = func;
} else {
chunk = ([ A_OBJ:obj, A_NEXT:actions[obj], verb:func ]);
chunks = ({ chunk }) + chunks;
actions[obj] = chunk;
}
}
}
/*
* NAME: _F_remove_actions()
* DESCRIPTION: remove the actions defined by obj
*/
nomask void _F_remove_actions(object obj)
{
if (PRIVILEGED()) {
mixed *removed, chunk;
removed = ({ });
for (chunk = actions[obj]; chunk != 0; chunk = chunk[A_NEXT]) {
chunk[A_OBJ] = 0;
removed += ({ chunk });
}
chunks -= removed;
actions[obj] = 0;
}
}
/*
* NAME: _F_checkfunc()
* DESCRIPTION: check if a function exists
*/
nomask string _F_checkfunc(string func)
{
if (PRIVILEGED()) {
return function_object(func, this_object());
}
}
/*
* NAME: _F_call()
* DESCRIPTION: handle the calling of a function
*/
nomask int _F_call(string func, string args)
{
if (previous_object() == this_user()) {
return call_other(this_object(), func, args);
}
}
/*
* NAME: remove_actions
* DESCRIPTION: remove the actions defined for player by obj
*/
private void remove_actions(object player, object obj)
{
player->_F_remove_actions(obj);
}
/*
* NAME: enable_commands()
* DESCRIPTION: mark this object as living
*/
static void enable_commands()
{
alive = 1;
set_this_player(this_object());
}
/*
* NAME: disable_commands()
* DESCRIPTION: mark this object as non-living
*/
static void disable_commands()
{
if (this_player() == this_object()) {
set_this_player(0);
}
alive = 0;
}
/*
* NAME: living()
* DESCRIPTION: determine if an object is alive
*/
static int living(object obj)
{
ARGCHECK(obj, living, 1);
return obj->_Q_alive();
}
/*
* NAME: add_action()
* DESCRIPTION: add an action for the current player
*/
static varargs void add_action(string func, string verb, int flag)
{
object player, e1, e2;
ARGCHECK(func && function_object(func, this_object()) != AUTO,
add_action, 1);
player = this_player();
if (player == 0) {
return;
}
if (this_object() != player && (e1=environment()) != player &&
e1 != (e2=environment(player)) && this_object() != e2) {
error("add_action from object that was not present");
}
if (func == "exit") {
error("Illegal to define a command to the exit() function");
}
if (verb == 0) {
saved_action = func;
} else {
rlimits (-1; -1) {
player->_F_add_action(this_object(), verb, func, flag);
saved_action = 0;
}
}
}
/*
* NAME: add_verb()
* DESCRIPTION: add a verb for the current player (most follow add_action()
* with one argument)
*/
static void add_verb(string verb)
{
object player;
ARGCHECK(verb, add_verb, 1);
player = this_player();
if (player != 0 && saved_action != 0) {
rlimits (-1; -1) {
player->_F_add_action(this_object(), verb, saved_action, 0);
saved_action = 0;
}
}
}
/*
* NAME: command()
* DESCRIPTION: force a given player to execute a command
*/
static varargs int command(string cmd, object obj)
{
mixed *list, chunk;
string arg, verb, func, prog;
object player, save_player;
int i, sz, exec_cost;
ARGCHECK(cmd, command, 1);
if (this_object() == 0) {
return 0;
}
player = (obj != 0) ? obj : this_object();
save_player = this_player();
if (player != save_player && !player->_Q_alive()) {
return 0;
}
set_this_player(player);
notify_fail("What ?\n");
list = player->_Q_actions();
for (i = strlen(cmd); --i >= 0 && cmd[i] == ' '; ) ;
if (i < 0) {
return 0;
}
cmd = cmd[0 .. i];
switch (cmd) {
case "n": cmd = "north"; break;
case "s": cmd = "south"; break;
case "e": cmd = "east"; break;
case "w": cmd = "west"; break;
case "ne": cmd = "northeast"; break;
case "nw": cmd = "northwest"; break;
case "se": cmd = "southeast"; break;
case "sw": cmd = "southwest"; break;
case "u": cmd = "up"; break;
case "d": cmd = "down"; break;
default:
sscanf(cmd, "%s %s", cmd, arg);
break;
}
exec_cost = 1000 + get_exec_cost();
for (i = 0, sz = sizeof(list); i < sz; i++) {
if (player == 0 || this_object() == 0) {
return 0;
}
chunk = list[i];
if (arrayp(chunk)) {
verb = chunk[A_VERB];
if (strlen(verb) > strlen(cmd) ||
(cmd[0 .. strlen(verb) - 1] != verb && verb != "")) {
continue;
}
func = chunk[A_FUNC];
} else {
func = chunk[cmd];
if (func == 0) {
continue;
}
}
obj = chunk[A_OBJ];
if (obj == 0) {
continue;
}
set_verb(cmd);
prog = obj->_F_checkfunc(func);
if (prog != 0) {
if (this_object() == this_user()) {
if (obj->_F_call(func, arg)) {
set_verb(0);
set_this_player(save_player);
return exec_cost - get_exec_cost();
}
continue;
} else if (function_object(func, obj) != 0) {
if (call_other(obj, func, arg)) {
set_verb(0);
set_this_player(save_player);
return exec_cost - get_exec_cost();
}
continue;
}
}
write("Error: function " + func + " not found.\n");
set_verb(0);
set_this_player(save_player);
return exec_cost - get_exec_cost();
}
if (player != 0 && (player=interactive(player)) != 0) {
player->notify_fail();
}
set_verb(0);
set_this_player(save_player);
return 0;
}
/*
* NAME: localcmd()
* DESCRIPTION: show the current verbs defined
*/
static void localcmd()
{
string list;
int i, sz;
mixed chunk;
list = "Local commands:\n";
for (i = 0, sz = sizeof(chunks); i < sz; i++) {
chunk = chunks[i];
if (mappingp(chunk)) {
mapping m;
m = chunk + ([ ]);
m[A_OBJ] = 0;
m[A_NEXT] = 0;
list += implode(map_indices(m), " ") + " ";
} else {
list += chunk[A_VERB] + " ";
}
}
write(list[0 .. strlen(list) - 2] + "\n");
}