/* Primitives package */
#include "copyright.h"
#include "config.h"
#include "params.h"
#include <sys/types.h>
#include <stdio.h>
#include <time.h>
#include "db.h"
#include "tune.h"
#include "props.h"
#include "inst.h"
#include "externs.h"
#include "match.h"
#include "interface.h"
#include "fbstrings.h"
#include "dbsearch.h"
#include "interp.h"
static struct inst *oper1, *oper2, *oper3, *oper4;
static int tmp, result;
static dbref ref;
static char buf[BUFFER_LEN];
extern struct line* get_new_line(void);
void
copyobj(dbref player, dbref old, dbref nu)
{
struct object *newp = DBFETCH(nu);
NAME(nu) = alloc_string(NAME(old));
if (Typeof(old) == TYPE_THING) {
ALLOC_THING_SP(nu);
THING_SET_HOME(nu, player);
THING_SET_VALUE(nu, 1);
}
newp->properties = copy_prop(old);
newp->exits = NOTHING;
newp->contents = NOTHING;
newp->next = NOTHING;
newp->location = NOTHING;
moveto(nu, player);
#ifdef DISKBASE
newp->propsfpos = 0;
newp->propsmode = PROPS_UNLOADED;
newp->propstime = 0;
newp->nextold = NOTHING;
newp->prevold = NOTHING;
dirtyprops(nu);
#endif
DBDIRTY(nu);
}
void
prim_addpennies(PRIM_PROTOTYPE)
{
CHECKOP(2);
oper1 = POP();
oper2 = POP();
if (mlev < 2)
abort_interp("Requires Mucker Level 2 or better.");
if (!valid_object(oper2))
abort_interp("Invalid object.");
if (oper1->type != PROG_INTEGER)
abort_interp("Non-integer argument (2)");
ref = oper2->data.objref;
if (Typeof(ref) == TYPE_PLAYER) {
result = PLAYER_PENNIES(ref);
if (mlev < 4) {
if (oper1->data.number > 0) {
if (result > (result + oper1->data.number))
abort_interp("Would roll over player's score.");
if ((result + oper1->data.number) > tp_max_pennies)
abort_interp("Would exceed MAX_PENNIES.");
} else {
if (result < (result + oper1->data.number))
abort_interp("Would roll over player's score.");
if ((result + oper1->data.number) < 0)
abort_interp("Result would be negative.");
}
}
result += oper1->data.number;
PLAYER_ADD_PENNIES(ref, oper1->data.number);
DBDIRTY(ref);
} else if (Typeof(ref) == TYPE_THING) {
if (mlev < 4)
abort_interp("Permission denied.");
result = THING_VALUE(ref) + oper1->data.number;
if (result < 1)
abort_interp("Result must be positive.");
THING_SET_VALUE(ref, (THING_VALUE(ref) + oper1->data.number));
DBDIRTY(ref);
} else {
abort_interp("Invalid object type.");
}
CLEAR(oper1);
CLEAR(oper2);
}
void
prim_moveto(PRIM_PROTOTYPE)
{
struct inst *oper1=NULL, *oper2=NULL, *oper3=NULL, *oper4=NULL;
CHECKOP(2);
oper1 = POP();
oper2 = POP();
if (fr->level > 8)
abort_interp("Interp call loops not allowed.");
/* Needs to be an object, and object needs to be valid */
if (!(oper2->type == PROG_OBJECT && valid_object(oper2)))
abort_interp("Non-object argument. (2)");
/* Needs to be an object, and object needs to be valid or HOME */
if (!(oper1->type == PROG_OBJECT && (valid_object(oper1) || is_home(oper1))))
abort_interp("Non-object argument. (1)");
{
dbref victim, dest;
victim = oper2->data.objref;
dest = oper1->data.objref;
if (Typeof(dest) == TYPE_EXIT)
abort_interp("Destination argument is an exit.");
if (Typeof(victim) == TYPE_EXIT && (mlev < 3))
abort_interp("Permission denied.");
if (!(FLAGS(victim) & JUMP_OK)
&& !permissions(ProgUID, victim) && (mlev < 3))
abort_interp("Object can't be moved.");
switch (Typeof(victim)) {
case TYPE_PLAYER:
if (Typeof(dest) != TYPE_ROOM &&
!(Typeof(dest) == TYPE_THING && (FLAGS(dest) & VEHICLE)))
abort_interp("Bad destination.");
/* Check permissions */
if (parent_loop_check(victim, dest))
abort_interp("Things can't contain themselves.");
if ((mlev < 3)) {
if (!(FLAGS(DBFETCH(victim)->location) & JUMP_OK)
&& !permissions(ProgUID, DBFETCH(victim)->location))
abort_interp("Source not JUMP_OK.");
if (!is_home(oper1) && !(FLAGS(dest) & JUMP_OK)
&& !permissions(ProgUID, dest))
abort_interp("Destination not JUMP_OK.");
if (Typeof(dest) == TYPE_THING && getloc(victim) != getloc(dest))
abort_interp("Not in same location as vehicle.");
}
enter_room(fr->descr, victim, dest, program);
break;
case TYPE_THING:
if (parent_loop_check(victim, dest))
abort_interp("A thing cannot contain itself.");
if (mlev < 3 && (FLAGS(victim) & VEHICLE) &&
(FLAGS(dest) & VEHICLE) && Typeof(dest) != TYPE_THING)
abort_interp("Destination doesn't accept vehicles.");
if (mlev < 3 && (FLAGS(victim) & ZOMBIE) &&
(FLAGS(dest) & ZOMBIE) && Typeof(dest) != TYPE_THING)
abort_interp("Destination doesn't accept zombies.");
ts_lastuseobject(victim);
case TYPE_PROGRAM:
{
dbref matchroom = NOTHING;
if (Typeof(dest) != TYPE_ROOM && Typeof(dest) != TYPE_PLAYER
&& Typeof(dest) != TYPE_THING) abort_interp("Bad destination.");
if ((mlev < 3)) {
if (permissions(ProgUID, dest))
matchroom = dest;
if (permissions(ProgUID, DBFETCH(victim)->location))
matchroom = DBFETCH(victim)->location;
if (matchroom != NOTHING && !(FLAGS(matchroom) & JUMP_OK)
&& !permissions(ProgUID, victim))
abort_interp("Permission denied.");
}
}
if (Typeof(victim) == TYPE_THING &&
(tp_thing_movement || (FLAGS(victim) & ZOMBIE))) {
enter_room(fr->descr, victim, dest, program);
} else {
moveto(victim, dest);
}
break;
case TYPE_EXIT:
if ((mlev < 3) && (!permissions(ProgUID, victim)
|| !permissions(ProgUID, dest)))
abort_interp("Permission denied.");
if ((Typeof(dest) != TYPE_ROOM && Typeof(dest) != TYPE_THING &&
Typeof(dest) != TYPE_PLAYER) || dest == HOME)
abort_interp("Bad destination object.");
if (!unset_source(ProgUID, getloc(player), victim))
break;
set_source(ProgUID, victim, dest);
SetMLevel(victim, 0);
break;
case TYPE_ROOM:
if (!tp_thing_movement && Typeof(dest) != TYPE_ROOM)
abort_interp("Bad destination.");
if (victim == GLOBAL_ENVIRONMENT)
abort_interp("Permission denied.");
if (dest == HOME) {
/* Allow the owner of the room or the owner of
the room's location to reparent the room to
#0 */
if ((mlev < 3) && (!permissions(ProgUID,victim)
&& !permissions(ProgUID,getloc(victim))))
abort_interp("Permission denied.");
dest = GLOBAL_ENVIRONMENT;
} else {
if ((mlev < 3) && (!permissions(ProgUID, victim)
|| !can_link_to(ProgUID, NOTYPE, dest)))
abort_interp("Permission denied.");
if (parent_loop_check(victim, dest)) {
abort_interp("Parent room would create a loop.");
}
}
ts_lastuseobject(victim);
moveto(victim, dest);
break;
default:
abort_interp("Invalid object type (1)");
}
}
CLEAR(oper1);
CLEAR(oper2);
}
void
prim_pennies(PRIM_PROTOTYPE)
{
CHECKOP(1);
oper1 = POP();
if (!valid_object(oper1))
abort_interp("Invalid argument.");
CHECKREMOTE(oper1->data.objref);
switch (Typeof(oper1->data.objref)) {
case TYPE_PLAYER:
result = PLAYER_PENNIES(oper1->data.objref);
break;
case TYPE_THING:
result = THING_VALUE(oper1->data.objref);
break;
default:
abort_interp("Invalid argument.");
}
CLEAR(oper1);
PushInt(result);
}
void
prim_dbcomp(PRIM_PROTOTYPE)
{
CHECKOP(2);
oper1 = POP();
oper2 = POP();
if (oper1->type != PROG_OBJECT || oper2->type != PROG_OBJECT)
abort_interp("Invalid argument type.");
result = oper1->data.objref == oper2->data.objref;
CLEAR(oper1);
CLEAR(oper2);
PushInt(result);
}
void
prim_dbref(PRIM_PROTOTYPE)
{
CHECKOP(1);
oper1 = POP();
if (oper1->type != PROG_INTEGER)
abort_interp("Non-integer argument.");
ref = (dbref) oper1->data.number;
CLEAR(oper1);
PushObject(ref);
}
void
prim_contents(PRIM_PROTOTYPE)
{
CHECKOP(1);
oper1 = POP();
if (!valid_object(oper1))
abort_interp("Invalid argument type.");
CHECKREMOTE(oper1->data.objref);
ref = DBFETCH(oper1->data.objref)->contents;
while (mlev < 2 && ref != NOTHING && (FLAGS(ref) & DARK) && !controls(ProgUID, ref))
ref = DBFETCH(ref)->next;
/* if (Typeof(oper1->data.objref) != TYPE_PLAYER &&
Typeof(oper1->data.objref) != TYPE_PROGRAM) ts_lastuseobject(oper1->data.objref); */
CLEAR(oper1);
PushObject(ref);
}
void
prim_exits(PRIM_PROTOTYPE)
{
CHECKOP(1);
oper1 = POP();
if (!valid_object(oper1))
abort_interp("Invalid object.");
ref = oper1->data.objref;
CHECKREMOTE(ref);
if ((mlev < 3) && !permissions(ProgUID, ref))
abort_interp("Permission denied.");
switch (Typeof(ref)) {
case TYPE_ROOM:
case TYPE_THING:
/* ts_lastuseobject(ref); */
case TYPE_PLAYER:
ref = DBFETCH(ref)->exits;
break;
default:
abort_interp("Invalid object.");
}
CLEAR(oper1);
PushObject(ref);
}
void
prim_next(PRIM_PROTOTYPE)
{
CHECKOP(1);
oper1 = POP();
if (!valid_object(oper1))
abort_interp("Invalid object.");
CHECKREMOTE(oper1->data.objref);
ref = DBFETCH(oper1->data.objref)->next;
while (mlev < 2 && ref != NOTHING && Typeof(ref) != TYPE_EXIT &&
((FLAGS(ref) & DARK) || Typeof(ref) == TYPE_ROOM) && !controls(ProgUID, ref))
ref = DBFETCH(ref)->next;
CLEAR(oper1);
PushObject(ref);
}
void
prim_nextowned(PRIM_PROTOTYPE)
{
dbref ownr;
CHECKOP(1);
oper1 = POP();
if (!valid_object(oper1))
abort_interp("Invalid object.");
if (mlev < 2)
abort_interp("Permission denied.");
ref = oper1->data.objref;
CHECKREMOTE(ref);
ownr = OWNER(ref);
if (Typeof(ref) == TYPE_PLAYER) {
ref = 0;
} else {
ref++;
}
while (ref < db_top && (OWNER(ref) != ownr || ref == ownr))
ref++;
if (ref >= db_top) {
ref = NOTHING;
}
CLEAR(oper1);
PushObject(ref);
}
void
prim_truename(PRIM_PROTOTYPE)
{
CHECKOP(1);
oper1 = POP();
if (oper1->type != PROG_OBJECT)
abort_interp("Invalid argument type.");
ref = oper1->data.objref;
if (ref < 0 || ref >= db_top)
abort_interp("Invalid object.");
if (Typeof(ref) == TYPE_GARBAGE) {
strcpy(buf, "<garbage>");
} else {
CHECKREMOTE(ref);
/* if ((Typeof(ref) != TYPE_PLAYER) && (Typeof(ref) != TYPE_PROGRAM))
ts_lastuseobject(ref); */
if (NAME(ref)) {
strcpy(buf, NAME(ref));
} else {
buf[0] = '\0';
}
}
CLEAR(oper1);
PushString(buf);
}
void
prim_name(PRIM_PROTOTYPE)
{
CHECKOP(1);
oper1 = POP();
if (oper1->type != PROG_OBJECT)
abort_interp("Invalid argument type.");
ref = oper1->data.objref;
if (ref < 0 || ref >= db_top)
abort_interp("Invalid object.");
if (Typeof(ref) == TYPE_GARBAGE) {
strcpy(buf, "<garbage>");
} else {
CHECKREMOTE(ref);
/* if ((Typeof(ref) != TYPE_PLAYER) && (Typeof(ref) != TYPE_PROGRAM))
ts_lastuseobject(ref); */
if (NAME(ref)) {
strcpy(buf, PNAME(ref));
} else {
buf[0] = '\0';
}
}
CLEAR(oper1);
PushString(buf);
}
void
prim_setname(PRIM_PROTOTYPE)
{
char *password;
CHECKOP(2);
oper1 = POP();
oper2 = POP();
if (!valid_object(oper2))
abort_interp("Invalid argument type (1)");
if (oper1->type != PROG_STRING)
abort_interp("Non-string argument (2)");
ref = oper2->data.objref;
if ((mlev < 4) && !permissions(ProgUID, ref))
abort_interp("Permission denied.");
{
const char *b = DoNullInd(oper1->data.string);
if (Typeof(ref) == TYPE_PLAYER) {
strcpy(buf, b);
b = buf;
if (mlev < 4) {
abort_interp("Permission denied.");
}
/* split off password */
for (password = buf; *password && !isspace(*password); password++) ;
/* eat whitespace */
if (*password) {
*password++ = '\0'; /* terminate name */
while (*password && isspace(*password)) {
password++;
}
}
/* check for null password */
if (!*password) {
abort_interp("Player namechange requires password.");
} else if (!check_password(ref, password)) {
abort_interp("Incorrect password.");
} else if (string_compare(b, NAME(ref)) && !ok_player_name(b)) {
abort_interp("You can't give a player that name.");
}
/* everything ok, notify */
log_status("NAME CHANGE (MUF): %s(#%d) to %s\n", NAME(ref), ref, b);
delete_player(ref);
if (NAME(ref)) {
free((void *) NAME(ref));
}
NAME(ref) = alloc_string(b);
add_player(ref);
ts_modifyobject(ref);
} else {
if (!ok_name(b)) {
abort_interp("Invalid name.");
}
if (NAME(ref)) {
free((void *) NAME(ref));
}
NAME(ref) = alloc_string(b);
ts_modifyobject(ref);
if (MLevRaw(ref)) {
SetMLevel(ref, 0);
}
}
}
CLEAR(oper1);
CLEAR(oper2);
}
void
prim_pmatch(PRIM_PROTOTYPE)
{
dbref ref;
CHECKOP(1);
oper1 = POP();
if (oper1->type != PROG_STRING)
abort_interp("Non-string argument.");
if (!oper1->data.string)
abort_interp("Empty string argument.");
strip_ansi(buf, oper1->data.string->data);
if (!string_compare(buf, "me")) {
ref = player;
} else {
ref = lookup_player(buf);
}
CLEAR(oper1);
PushObject(ref);
}
void
prim_match(PRIM_PROTOTYPE)
{
struct inst *oper1=NULL, *oper2=NULL, *oper3=NULL, *oper4=NULL;
dbref ref;
char buf2[BUFFER_LEN];
CHECKOP(1);
oper1 = POP();
if (oper1->type != PROG_STRING)
abort_interp("Non-string argument.");
if (!oper1->data.string)
abort_interp("Empty string argument.");
{
char tmppp[BUFFER_LEN];
struct match_data md;
(void) strcpy(buf, match_args);
(void) strcpy(tmppp, match_cmdname);
strip_ansi(buf2, oper1->data.string->data);
init_match(fr->descr, player, buf2, NOTYPE, &md);
if (buf2[0] == REGISTERED_TOKEN) {
match_registered(&md);
} else {
match_all_exits(&md);
match_neighbor(&md);
match_possession(&md);
match_me(&md);
match_here(&md);
match_home(&md);
}
if (Wizard(ProgUID) || (mlev >= 4)) {
match_absolute(&md);
match_player(&md);
}
ref = match_result(&md);
(void) strcpy(match_args, buf);
(void) strcpy(match_cmdname, tmppp);
}
CLEAR(oper1);
PushObject(ref);
}
void
prim_rmatch(PRIM_PROTOTYPE)
{
struct inst *oper1=NULL, *oper2=NULL, *oper3=NULL, *oper4=NULL;
dbref ref;
CHECKOP(2);
oper1 = POP();
oper2 = POP();
if (oper1->type != PROG_STRING)
abort_interp("Invalid argument (2)");
if (oper2->type != PROG_OBJECT
|| oper2->data.objref < 0
|| oper2->data.objref >= db_top
|| Typeof(oper2->data.objref) == TYPE_PROGRAM
|| Typeof(oper2->data.objref) == TYPE_EXIT) abort_interp("Invalid argument (1)");
CHECKREMOTE(oper2->data.objref);
{
char tmppp[BUFFER_LEN];
struct match_data md;
(void) strcpy(buf, match_args);
(void) strcpy(tmppp, match_cmdname);
init_match(fr->descr, player, DoNullInd(oper1->data.string), TYPE_THING, &md);
match_rmatch(oper2->data.objref, &md);
ref = match_result(&md);
(void) strcpy(match_args, buf);
(void) strcpy(match_cmdname, tmppp);
}
CLEAR(oper1);
CLEAR(oper2);
PushObject(ref);
}
void
prim_copyobj(PRIM_PROTOTYPE)
{
CHECKOP(1);
oper1 = POP();
if (!valid_object(oper1))
abort_interp("Invalid object.");
CHECKREMOTE(oper1->data.objref);
if ((mlev < 3) && (fr->already_created))
abort_interp("Can't create any more objects.");
ref = oper1->data.objref;
if (Typeof(ref) != TYPE_THING)
abort_interp("Invalid object type.");
if ((mlev < 3) && !permissions(ProgUID, ref))
abort_interp("Permission denied.");
if (!ok_name(NAME(oper1->data.objref)))
abort_interp("Invalid name.");
fr->already_created++;
{
dbref newobj;
newobj = new_object();
*DBFETCH(newobj) = *DBFETCH(ref);
copyobj(player, ref, newobj);
CLEAR(oper1);
PushObject(newobj);
}
}
void
prim_set(PRIM_PROTOTYPE)
/* SET */
{
CHECKOP(2);
oper1 = POP();
oper2 = POP();
if (oper1->type != PROG_STRING)
abort_interp("Invalid argument type (2)");
if (!(oper1->data.string))
abort_interp("Empty string argument (2)");
if (!valid_object(oper2))
abort_interp("Invalid object.");
ref = oper2->data.objref;
CHECKREMOTE(ref);
tmp = 0;
result = (*oper1->data.string->data == '!');
{
char *flag = oper1->data.string->data;
if (result)
flag++;
if (string_prefix("dark", flag)
|| string_prefix("debug", flag))
tmp = DARK;
else if (string_prefix("abode", flag)
|| string_prefix("autostart", flag)
|| string_prefix("abate", flag))
tmp = ABODE;
else if (string_prefix("chown_ok", flag)
|| string_prefix("color", flag))
tmp = CHOWN_OK;
else if (string_prefix("haven", flag)
|| string_prefix("harduid", flag))
tmp = HAVEN;
else if (string_prefix("jump_ok", flag))
tmp = JUMP_OK;
else if (string_prefix("link_ok", flag))
tmp = LINK_OK;
else if (string_prefix("kill_ok", flag))
tmp = KILL_OK;
else if (string_prefix("builder", flag))
tmp = BUILDER;
else if (string_prefix("mucker", flag))
tmp = MUCKER;
else if (string_prefix("nucker", flag))
tmp = SMUCKER;
else if (string_prefix("interactive", flag))
tmp = INTERACTIVE;
else if (string_prefix("sticky", flag)
|| string_prefix("silent", flag))
tmp = STICKY;
else if (string_prefix("wizard", flag))
tmp = WIZARD;
else if (string_prefix("truewizard", flag))
tmp = WIZARD;
else if (string_prefix("xforcible", flag))
tmp = XFORCIBLE;
else if (string_prefix("zombie", flag))
tmp = ZOMBIE;
else if (string_prefix("vehicle", flag)
|| string_prefix("viewable", flag))
tmp = VEHICLE;
else if (string_prefix("quell", flag))
tmp = QUELL;
}
if (!tmp)
abort_interp("Unrecognized flag.");
if ((mlev < 4) && !permissions(ProgUID, ref))
abort_interp("Permission denied.");
if (((mlev < 4) && ((tmp == DARK && ((Typeof(ref) == TYPE_PLAYER)
|| (!tp_exit_darking && Typeof(ref) == TYPE_EXIT)
|| (!tp_thing_darking && Typeof(ref) == TYPE_THING)
)
)
|| ((tmp == ZOMBIE) && (Typeof(ref) == TYPE_THING)
&& (FLAGS(ProgUID) & ZOMBIE))
|| ((tmp == ZOMBIE) && (Typeof(ref) == TYPE_PLAYER))
|| (tmp == BUILDER)
)
)
|| (tmp == WIZARD) || (tmp == QUELL) || (tmp == INTERACTIVE)
|| ((tmp == ABODE) && (Typeof(ref) == TYPE_PROGRAM))
|| (tmp == MUCKER) || (tmp == SMUCKER) || (tmp == XFORCIBLE)
)
abort_interp("Permission denied.");
if (result && Typeof(ref) == TYPE_THING && tmp == VEHICLE) {
dbref obj = DBFETCH(ref)->contents;
for (; obj != NOTHING; obj = DBFETCH(obj)->next) {
if (Typeof(obj) == TYPE_PLAYER) {
abort_interp("That vehicle still has players in it!");
}
}
}
if (!result) {
FLAGS(ref) |= tmp;
DBDIRTY(ref);
} else {
FLAGS(ref) &= ~tmp;
DBDIRTY(ref);
}
CLEAR(oper1);
CLEAR(oper2);
}
void
prim_mlevel(PRIM_PROTOTYPE)
/* MLEVEL */
{
CHECKOP(1);
oper1 = POP();
if (!valid_object(oper1))
abort_interp("Invalid object.");
ref = oper1->data.objref;
CHECKREMOTE(ref);
result = MLevRaw(ref);
CLEAR(oper1);
PushInt(result);
}
void
prim_flagp(PRIM_PROTOTYPE)
/* FLAG? */
{
int truwiz = 0;
CHECKOP(2);
oper1 = POP();
oper2 = POP();
if (oper1->type != PROG_STRING)
abort_interp("Invalid argument type (2)");
if (!(oper1->data.string))
abort_interp("Empty string argument (2)");
if (!valid_object(oper2))
abort_interp("Invalid object.");
ref = oper2->data.objref;
CHECKREMOTE(ref);
tmp = 0;
result = 0;
{
char *flag = oper1->data.string->data;
while (*flag == '!') {
flag++;
result = (!result);
}
if (!*flag)
abort_interp("Unknown flag.");
if (string_prefix("dark", flag)
|| string_prefix("debug", flag))
tmp = DARK;
else if (string_prefix("abode", flag)
|| string_prefix("autostart", flag)
|| string_prefix("abate", flag))
tmp = ABODE;
else if (string_prefix("chown_ok", flag)
|| string_prefix("color", flag))
tmp = CHOWN_OK;
else if (string_prefix("haven", flag)
|| string_prefix("harduid", flag))
tmp = HAVEN;
else if (string_prefix("jump_ok", flag))
tmp = JUMP_OK;
else if (string_prefix("link_ok", flag))
tmp = LINK_OK;
else if (string_prefix("kill_ok", flag))
tmp = KILL_OK;
else if (string_prefix("builder", flag))
tmp = BUILDER;
else if (string_prefix("mucker", flag))
tmp = MUCKER;
else if (string_prefix("nucker", flag))
tmp = SMUCKER;
else if (string_prefix("interactive", flag))
tmp = INTERACTIVE;
else if (string_prefix("sticky", flag)
|| string_prefix("silent", flag))
tmp = STICKY;
else if (string_prefix("wizard", flag))
tmp = WIZARD;
else if (string_prefix("truewizard", flag)) {
tmp = WIZARD;
truwiz = 1;
} else if (string_prefix("zombie", flag))
tmp = ZOMBIE;
else if (string_prefix("xforcible", flag))
tmp = XFORCIBLE;
else if (string_prefix("vehicle", flag)
|| string_prefix("viewable", flag))
tmp = VEHICLE;
else if (string_prefix("quell", flag))
tmp = QUELL;
}
if (result) {
if ((!truwiz) && (tmp == WIZARD)) {
result = (!Wizard(ref));
} else {
result = (tmp && ((FLAGS(ref) & tmp) == 0));
}
} else {
if ((!truwiz) && (tmp == WIZARD)) {
result = Wizard(ref);
} else {
result = (tmp && ((FLAGS(ref) & tmp) != 0));
}
}
CLEAR(oper1);
CLEAR(oper2);
PushInt(result);
}
void
prim_playerp(PRIM_PROTOTYPE)
{
CHECKOP(1);
oper1 = POP();
if (oper1->type != PROG_OBJECT)
abort_interp("Invalid argument type.");
if (!valid_object(oper1) && !is_home(oper1)) {
result = 0;
} else {
ref = oper1->data.objref;
CHECKREMOTE(ref);
result = (Typeof(ref) == TYPE_PLAYER);
}
CLEAR(oper1);
PushInt(result);
}
void
prim_thingp(PRIM_PROTOTYPE)
{
CHECKOP(1);
oper1 = POP();
if (oper1->type != PROG_OBJECT)
abort_interp("Invalid argument type.");
if (!valid_object(oper1) && !is_home(oper1)) {
result = 0;
} else {
ref = oper1->data.objref;
CHECKREMOTE(ref);
result = (Typeof(ref) == TYPE_THING);
}
CLEAR(oper1);
PushInt(result);
}
void
prim_roomp(PRIM_PROTOTYPE)
{
CHECKOP(1);
oper1 = POP();
if (oper1->type != PROG_OBJECT)
abort_interp("Invalid argument type.");
if (!valid_object(oper1) && !is_home(oper1)) {
result = 0;
} else {
ref = oper1->data.objref;
CHECKREMOTE(ref);
result = (Typeof(ref) == TYPE_ROOM);
}
CLEAR(oper1);
PushInt(result);
}
void
prim_programp(PRIM_PROTOTYPE)
{
CHECKOP(1);
oper1 = POP();
if (oper1->type != PROG_OBJECT)
abort_interp("Invalid argument type.");
if (!valid_object(oper1) && !is_home(oper1)) {
result = 0;
} else {
ref = oper1->data.objref;
CHECKREMOTE(ref);
result = (Typeof(ref) == TYPE_PROGRAM);
}
CLEAR(oper1);
PushInt(result);
}
void
prim_exitp(PRIM_PROTOTYPE)
{
CHECKOP(1);
oper1 = POP();
if (oper1->type != PROG_OBJECT)
abort_interp("Invalid argument type.");
if (!valid_object(oper1) && !is_home(oper1)) {
result = 0;
} else {
ref = oper1->data.objref;
CHECKREMOTE(ref);
result = (Typeof(ref) == TYPE_EXIT);
}
CLEAR(oper1);
PushInt(result);
}
void
prim_okp(PRIM_PROTOTYPE)
{
CHECKOP(1);
oper1 = POP();
result = (valid_object(oper1));
CLEAR(oper1);
PushInt(result);
}
void
prim_location(PRIM_PROTOTYPE)
{
CHECKOP(1);
oper1 = POP();
if (!valid_object(oper1))
abort_interp("Invalid object.");
CHECKREMOTE(oper1->data.objref);
ref = DBFETCH(oper1->data.objref)->location;
CLEAR(oper1);
PushObject(ref);
}
void
prim_owner(PRIM_PROTOTYPE)
{
CHECKOP(1);
oper1 = POP();
if (!valid_object(oper1))
abort_interp("Invalid object.");
CHECKREMOTE(oper1->data.objref);
ref = OWNER(oper1->data.objref);
CLEAR(oper1);
PushObject(ref);
}
void
prim_controls(PRIM_PROTOTYPE)
{
CHECKOP(2);
oper1 = POP();
oper2 = POP();
if (!valid_object(oper1))
abort_interp("Invalid object. (2)");
if (!valid_object(oper2))
abort_interp("Invalid object. (1)");
CHECKREMOTE(oper1->data.objref);
result = controls(oper2->data.objref, oper1->data.objref);
CLEAR(oper1);
CLEAR(oper2);
PushInt(result);
}
void
prim_getlink(PRIM_PROTOTYPE)
{
CHECKOP(1);
oper1 = POP();
if (!valid_object(oper1))
abort_interp("Invalid object.");
CHECKREMOTE(oper1->data.objref);
if (Typeof(oper1->data.objref) == TYPE_PROGRAM)
abort_interp("Illegal object referenced.");
switch (Typeof(oper1->data.objref)) {
case TYPE_EXIT:
ref = (DBFETCH(oper1->data.objref)->sp.exit.ndest) ?
(DBFETCH(oper1->data.objref)->sp.exit.dest)[0] : NOTHING;
break;
case TYPE_PLAYER:
ref = PLAYER_HOME(oper1->data.objref);
break;
case TYPE_THING:
ref = THING_HOME(oper1->data.objref);
break;
case TYPE_ROOM:
ref = DBFETCH(oper1->data.objref)->sp.room.dropto;
break;
default:
ref = NOTHING;
break;
}
CLEAR(oper1);
PushObject(ref);
}
void
prim_getlinks(PRIM_PROTOTYPE)
{
int i, count;
dbref my_obj;
CHECKOP(1);
oper1 = POP();
if (!valid_object(oper1))
abort_interp("Invalid object.");
CHECKREMOTE(oper1->data.objref);
if (Typeof(oper1->data.objref) == TYPE_PROGRAM)
abort_interp("Illegal object referenced.");
my_obj = oper1->data.objref;
CLEAR(oper1);
switch (Typeof(my_obj)) {
case TYPE_EXIT:
count = DBFETCH(my_obj)->sp.exit.ndest;
for (i = 0; i < count; i++) {
PushObject((DBFETCH(my_obj)->sp.exit.dest)[i]);
}
PushInt(count);
break;
case TYPE_PLAYER:
ref = PLAYER_HOME(my_obj);
count = 1;
PushObject(ref);
PushInt(count);
break;
case TYPE_THING:
ref = THING_HOME(my_obj);
count = 1;
PushObject(ref);
PushInt(count);
break;
case TYPE_ROOM:
ref = DBFETCH(my_obj)->sp.room.dropto;
if (ref != NOTHING) {
count = 0;
PushInt(count);
} else {
count = 1;
PushObject(ref);
PushInt(count);
}
break;
default:
count = 0;
PushInt(count);
break;
}
}
int
prog_can_link_to(int mlev, dbref who, object_flag_type what_type, dbref where)
{
if (where == HOME)
return 1;
if (where < 0 || where > db_top)
return 0;
switch (what_type) {
case TYPE_EXIT:
return (mlev > 3 || permissions(who, where) || (FLAGS(where) & LINK_OK));
/* NOTREACHED */
break;
case TYPE_PLAYER:
return (Typeof(where) == TYPE_ROOM && (mlev > 3 || permissions(who, where)
|| Linkable(where)));
/* NOTREACHED */
break;
case TYPE_ROOM:
return ((Typeof(where) == TYPE_ROOM || Typeof(where) == TYPE_THING)
&& (mlev > 3 || permissions(who, where) || Linkable(where)));
/* NOTREACHED */
break;
case TYPE_THING:
return ((Typeof(where) == TYPE_ROOM || Typeof(where) == TYPE_PLAYER || Typeof(where) == TYPE_THING)
&& (mlev > 3 || permissions(who, where) || Linkable(where)));
/* NOTREACHED */
break;
case NOTYPE:
return (mlev > 3 || permissions(who, where) || (FLAGS(where) & LINK_OK) ||
(Typeof(where) != TYPE_THING && (FLAGS(where) & ABODE)));
/* NOTREACHED */
break;
}
return 0;
}
void
prim_setlink(PRIM_PROTOTYPE)
{
CHECKOP(2);
oper1 = POP(); /* dbref: destination */
oper2 = POP(); /* dbref: source */
if ((oper1->type != PROG_OBJECT) || (oper2->type != PROG_OBJECT))
abort_interp("setlink requires two dbrefs.");
if (!valid_object(oper2))
abort_interp("Invalid object. (1)");
ref = oper2->data.objref;
if (oper1->data.objref == NOTHING) {
if ((mlev < 4) && !permissions(ProgUID, ref))
abort_interp("Permission denied.");
switch (Typeof(ref)) {
case TYPE_EXIT:
DBSTORE(ref, sp.exit.ndest, 0);
if (DBFETCH(ref)->sp.exit.dest) {
free((void *) DBFETCH(ref)->sp.exit.dest);
DBSTORE(ref, sp.exit.dest, NULL);
}
if (MLevRaw(ref))
SetMLevel(ref, 0);
break;
case TYPE_ROOM:
DBSTORE(ref, sp.room.dropto, NOTHING);
break;
default:
abort_interp("Invalid object. (1)");
}
} else {
if (oper1->data.objref != HOME && !valid_object(oper1))
abort_interp("Invalid object. (2)");
if (Typeof(ref) == TYPE_PROGRAM)
abort_interp("Program objects are not linkable. (1)");
if (!prog_can_link_to(mlev, ProgUID, Typeof(ref), oper1->data.objref))
abort_interp("Can't link source to destination.");
switch (Typeof(ref)) {
case TYPE_EXIT:
if ((mlev < 4) && !permissions(ProgUID, ref))
abort_interp("Permission denied.");
if (DBFETCH(ref)->sp.exit.ndest != 0)
abort_interp("Exit is already linked.");
if (exit_loop_check(ref, oper1->data.objref))
abort_interp("Link would cause a loop.");
DBFETCH(ref)->sp.exit.ndest = 1;
DBFETCH(ref)->sp.exit.dest = (dbref *) malloc(sizeof(dbref));
(DBFETCH(ref)->sp.exit.dest)[0] = oper1->data.objref;
DBDIRTY(ref);
break;
case TYPE_PLAYER:
if ((mlev < 4) && !permissions(ProgUID, ref))
abort_interp("Permission denied.");
if (oper1->data.objref == HOME)
abort_interp("Cannot link player to HOME.");
PLAYER_SET_HOME(ref, oper1->data.objref);
DBDIRTY(ref);
break;
case TYPE_THING:
if ((mlev < 4) && !permissions(ProgUID, ref))
abort_interp("Permission denied.");
if (oper1->data.objref == HOME)
abort_interp("Cannot link thing to HOME.");
if (parent_loop_check(ref, oper1->data.objref))
abort_interp("That would cause a parent paradox.");
THING_SET_HOME(ref, oper1->data.objref);
DBDIRTY(ref);
break;
case TYPE_ROOM:
if ((mlev < 4) && !permissions(ProgUID, ref))
abort_interp("Permission denied.");
DBFETCH(ref)->sp.room.dropto = oper1->data.objref;
DBDIRTY(ref);
break;
}
}
CLEAR(oper1);
CLEAR(oper2);
}
void
prim_setown(PRIM_PROTOTYPE)
{
CHECKOP(2);
oper1 = POP(); /* dbref: new owner */
oper2 = POP(); /* dbref: what */
if (!valid_object(oper2))
abort_interp("Invalid argument (1)");
if (!valid_player(oper1))
abort_interp("Invalid argument (2)");
ref = oper2->data.objref;
if ((mlev < 4) && oper1->data.objref != player)
abort_interp("Permission denied. (2)");
if ((mlev < 4) && (!(FLAGS(ref) & CHOWN_OK) ||
!test_lock(fr->descr, player, ref, "_/chlk")))
abort_interp("Permission denied. (1)");
switch (Typeof(ref)) {
case TYPE_ROOM:
if ((mlev < 4) && DBFETCH(player)->location != ref)
abort_interp("Permission denied: not in room. (1)");
break;
case TYPE_THING:
if ((mlev < 4) && DBFETCH(ref)->location != player)
abort_interp("Permission denied: object not carried. (1)");
break;
case TYPE_PLAYER:
abort_interp("Permission denied: cannot set owner of player. (1)");
case TYPE_EXIT:
case TYPE_PROGRAM:
break;
case TYPE_GARBAGE:
abort_interp("Permission denied: who would want to own garbage? (1)");
}
OWNER(ref) = OWNER(oper1->data.objref);
DBDIRTY(ref);
CLEAR(oper1);
CLEAR(oper2);
}
void
prim_newobject(PRIM_PROTOTYPE)
{
CHECKOP(2);
oper1 = POP(); /* string: name */
oper2 = POP(); /* dbref: location */
if ((mlev < 3) && (fr->already_created))
abort_interp("An object was already created this program run.");
CHECKOFLOW(1);
ref = oper2->data.objref;
if (!valid_object(oper2) || !(valid_player(oper2) || (Typeof(ref) == TYPE_ROOM)))
abort_interp("Invalid argument (1)");
if (oper1->type != PROG_STRING)
abort_interp("Invalid argument (2)");
CHECKREMOTE(ref);
if ((mlev < 3) && !permissions(ProgUID, ref))
abort_interp("Permission denied.");
{
const char *b = DoNullInd(oper1->data.string);
dbref loc;
if (!ok_name(b))
abort_interp("Invalid name. (2)");
ref = new_object();
/* initialize everything */
NAME(ref) = alloc_string(b);
ALLOC_THING_SP(ref);
DBFETCH(ref)->location = oper2->data.objref;
OWNER(ref) = OWNER(ProgUID);
THING_SET_VALUE(ref, 1);
DBFETCH(ref)->exits = NOTHING;
FLAGS(ref) = TYPE_THING;
if ((loc = DBFETCH(player)->location) != NOTHING && controls(player, loc)) {
THING_SET_HOME(ref, loc); /* home */
} else {
THING_SET_HOME(ref, PLAYER_HOME(player));
/* set to player's home instead */
}
}
/* link it in */
PUSH(ref, DBFETCH(oper2->data.objref)->contents);
DBDIRTY(ref);
DBDIRTY(oper2->data.objref);
CLEAR(oper1);
CLEAR(oper2);
PushObject(ref);
}
void
prim_newroom(PRIM_PROTOTYPE)
{
CHECKOP(2);
oper1 = POP(); /* string: name */
oper2 = POP(); /* dbref: location */
if ((mlev < 3) && (fr->already_created))
abort_interp("An object was already created this program run.");
CHECKOFLOW(1);
ref = oper2->data.objref;
if (!valid_object(oper2) || (Typeof(ref) != TYPE_ROOM))
abort_interp("Invalid argument (1)");
if (oper1->type != PROG_STRING)
abort_interp("Invalid argument (2)");
if ((mlev < 3) && !permissions(ProgUID, ref))
abort_interp("Permission denied.");
{
const char *b = DoNullInd(oper1->data.string);
if (!ok_name(b))
abort_interp("Invalid name. (2)");
ref = new_object();
/* Initialize everything */
NAME(ref) = alloc_string(b);
DBFETCH(ref)->location = oper2->data.objref;
OWNER(ref) = OWNER(ProgUID);
DBFETCH(ref)->exits = NOTHING;
DBFETCH(ref)->sp.room.dropto = NOTHING;
FLAGS(ref) = TYPE_ROOM | (FLAGS(player) & JUMP_OK);
PUSH(ref, DBFETCH(oper2->data.objref)->contents);
DBDIRTY(ref);
DBDIRTY(oper2->data.objref);
CLEAR(oper1);
CLEAR(oper2);
PushObject(ref);
}
}
void
prim_newexit(PRIM_PROTOTYPE)
{
CHECKOP(2);
oper1 = POP(); /* string: name */
oper2 = POP(); /* dbref: location */
if (mlev < 3)
abort_interp("Requires Mucker Level 3.");
CHECKOFLOW(1);
ref = oper2->data.objref;
if (!valid_object(oper2) ||
((!valid_player(oper2)) && (Typeof(ref) != TYPE_ROOM) && (Typeof(ref) != TYPE_THING)))
abort_interp("Invalid argument (1)");
if (oper1->type != PROG_STRING)
abort_interp("Invalid argument (2)");
CHECKREMOTE(ref);
if ((mlev < 4) && !permissions(ProgUID, ref))
abort_interp("Permission denied.");
{
const char *b = DoNullInd(oper1->data.string);
if (!ok_name(b))
abort_interp("Invalid name. (2)");
ref = new_object();
/* initialize everything */
NAME(ref) = alloc_string(oper1->data.string->data);
DBFETCH(ref)->location = oper2->data.objref;
OWNER(ref) = OWNER(ProgUID);
FLAGS(ref) = TYPE_EXIT;
DBFETCH(ref)->sp.exit.ndest = 0;
DBFETCH(ref)->sp.exit.dest = NULL;
/* link it in */
PUSH(ref, DBFETCH(oper2->data.objref)->exits);
DBDIRTY(oper2->data.objref);
CLEAR(oper1);
CLEAR(oper2);
PushObject(ref);
}
}
void
prim_lockedp(PRIM_PROTOTYPE)
{
struct inst *oper1 = NULL; /* prevents re-entrancy issues! */
struct inst *oper2 = NULL; /* prevents re-entrancy issues! */
/* d d - i */
CHECKOP(2);
oper1 = POP(); /* objdbref */
oper2 = POP(); /* player dbref */
if (fr->level > 8)
abort_interp("Interp call loops not allowed.");
if (!valid_object(oper2))
abort_interp("invalid object (1).");
if (!valid_player(oper2) && Typeof(oper2->data.objref) != TYPE_THING)
abort_interp("Non-player argument (1).");
CHECKREMOTE(oper2->data.objref);
if (!valid_object(oper1))
abort_interp("invalid object (2).");
CHECKREMOTE(oper1->data.objref);
result = !could_doit(fr->descr, oper2->data.objref, oper1->data.objref);
CLEAR(oper1);
CLEAR(oper2);
PushInt(result);
}
void
prim_recycle(PRIM_PROTOTYPE)
{
/* d -- */
CHECKOP(1);
oper1 = POP(); /* object dbref to recycle */
if (oper1->type != PROG_OBJECT)
abort_interp("Non-object argument (1).");
if (!valid_object(oper1))
abort_interp("Invalid object (1).");
result = oper1->data.objref;
if ((mlev < 3) || ((mlev < 4) && !permissions(ProgUID, result)))
abort_interp("Permission denied.");
if ((result == tp_player_start) || (result == GLOBAL_ENVIRONMENT))
abort_interp("Cannot recycle that room.");
if (Typeof(result) == TYPE_PLAYER)
abort_interp("Cannot recycle a player.");
if (result == program)
abort_interp("Cannot recycle currently running program.");
{
int ii;
for (ii = 0; ii < fr->caller.top; ii++)
if (fr->caller.st[ii] == result)
abort_interp("Cannot recycle active program.");
}
if (Typeof(result) == TYPE_EXIT)
if (!unset_source(player, DBFETCH(player)->location, result))
abort_interp("Cannot recycle old style exits.");
CLEAR(oper1);
recycle(fr->descr, player, result);
}
void
prim_setlockstr(PRIM_PROTOTYPE)
{
CHECKOP(2);
oper1 = POP();
oper2 = POP();
if (!valid_object(oper2))
abort_interp("Invalid argument type (1)");
if (oper1->type != PROG_STRING)
abort_interp("Non-string argument (2)");
ref = oper2->data.objref;
if ((mlev < 4) && !permissions(ProgUID, ref))
abort_interp("Permission denied.");
result = setlockstr(fr->descr, player, ref,
oper1->data.string ? oper1->data.string->data : (char *) "");
CLEAR(oper1);
CLEAR(oper2);
PushInt(result);
}
void
prim_getlockstr(PRIM_PROTOTYPE)
{
CHECKOP(1);
oper1 = POP();
if (!valid_object(oper1))
abort_interp("Invalid argument type");
ref = oper1->data.objref;
CHECKREMOTE(ref);
if ((mlev < 3) && !permissions(ProgUID, ref))
abort_interp("Permission denied.");
{
char *tmpstr;
tmpstr = (char *) unparse_boolexp(player, GETLOCK(ref), 0);
CLEAR(oper1);
PushString(tmpstr);
}
}
void
prim_part_pmatch(PRIM_PROTOTYPE)
{
dbref ref;
CHECKOP(1);
oper1 = POP();
if (oper1->type != PROG_STRING)
abort_interp("Non-string argument.");
if (!oper1->data.string)
abort_interp("Empty string argument.");
if (mlev < 3)
abort_interp("Permission denied. Requires Mucker Level 3.");
ref = partial_pmatch(oper1->data.string->data);
CLEAR(oper1);
PushObject(ref);
}
void
prim_checkpassword(PRIM_PROTOTYPE)
{
char *ptr;
CHECKOP(2);
oper2 = POP();
oper1 = POP();
if (mlev < 4)
abort_interp("Permission denied. Requires Wizbit.");
if (oper1->type != PROG_OBJECT)
abort_interp("Player dbref expected. (1)");
ref = oper1->data.objref;
if ((ref != NOTHING && !valid_player(oper1)) || ref == NOTHING)
abort_interp("Player dbref expected. (1)");
if (oper2->type != PROG_STRING)
abort_interp("Password string expected. (2)");
ptr = oper2->data.string ? oper2->data.string->data : "";
if (ref != NOTHING) {
result = check_password(ref, ptr);
} else {
result = 0;
}
CLEAR(oper1);
CLEAR(oper2);
PushInt(result);
}
void
prim_movepennies(PRIM_PROTOTYPE)
{
int result2;
dbref ref2;
CHECKOP(3);
oper1 = POP();
oper2 = POP();
oper3 = POP();
if (mlev < 2)
abort_interp("Requires Mucker Level 2 or better.");
if (!valid_object(oper3))
abort_interp("Invalid object. (1)");
if (!valid_object(oper2))
abort_interp("Invalid object. (2)");
if (oper1->type != PROG_INTEGER)
abort_interp("Non-integer argument (3)");
if (oper1->data.number < 0)
abort_interp("Invalid argument. (3)");
ref = oper3->data.objref;
ref2 = oper2->data.objref;
if (Typeof(ref) == TYPE_PLAYER) {
result = PLAYER_PENNIES(ref);
if (Typeof(ref2) == TYPE_PLAYER) {
result2 = PLAYER_PENNIES(ref2);
if (mlev < 4) {
if (result < (result - oper1->data.number))
abort_interp("Would roll over player's score. (1)");
if ((result - oper1->data.number) < 0)
abort_interp("Result would be negative. (1)");
if (result2 > (result2 + oper1->data.number))
abort_interp("Would roll over player's score. (2)");
if ((result2 + oper1->data.number) > tp_max_pennies)
abort_interp("Would exceed MAX_PENNIES. (2)");
}
result2 += oper1->data.number;
PLAYER_ADD_PENNIES(ref, -(oper1->data.number));
PLAYER_ADD_PENNIES(ref2, oper1->data.number);
DBDIRTY(ref);
DBDIRTY(ref2);
} else if (Typeof(ref2) == TYPE_THING) {
if (mlev < 4)
abort_interp("Permission denied. (2)");
result2 = THING_VALUE(ref2) + oper1->data.number;
if (result < (result - oper1->data.number))
abort_interp("Would roll over player's score. (1)");
if ((result - oper1->data.number) < 0)
abort_interp("Result would be negative. (1)");
PLAYER_ADD_PENNIES(ref, -(oper1->data.number));
THING_SET_VALUE(ref2, (THING_VALUE(ref2) + oper1->data.number));
DBDIRTY(ref);
DBDIRTY(ref2);
} else {
abort_interp("Invalid object type. (2)");
}
} else if (Typeof(ref) == TYPE_THING) {
if (mlev < 4)
abort_interp("Permission denied. (1)");
result = THING_VALUE(ref) - oper1->data.number;
if (result < 1)
abort_interp("Result must be positive. (1)");
if (Typeof(ref2) == TYPE_PLAYER) {
result2 = PLAYER_PENNIES(ref2);
if (result2 > (result2 + oper1->data.number))
abort_interp("Would roll over player's score. (2)");
if ((result2 + oper1->data.number) > tp_max_pennies)
abort_interp("Would exceed MAX_PENNIES. (2)");
THING_SET_VALUE(ref, (THING_VALUE(ref) - oper1->data.number));
PLAYER_ADD_PENNIES(ref2, oper1->data.number);
DBDIRTY(ref);
DBDIRTY(ref2);
} else if (Typeof(ref2) == TYPE_THING) {
THING_SET_VALUE(ref, (THING_VALUE(ref) - oper1->data.number));
THING_SET_VALUE(ref2, (THING_VALUE(ref2) + oper1->data.number));
DBDIRTY(ref);
DBDIRTY(ref2);
} else {
abort_interp("Invalid object type. (2)");
}
} else {
abort_interp("Invalid object type. (1)");
}
CLEAR(oper1);
CLEAR(oper2);
CLEAR(oper3);
}
void
prim_findnext(PRIM_PROTOTYPE)
{
struct flgchkdat check;
dbref who, item, ref, i;
const char* name;
CHECKOP(4);
oper4 = POP(); /* str:flags */
oper3 = POP(); /* str:namepattern */
oper2 = POP(); /* ref:owner */
oper1 = POP(); /* ref:currobj */
if (oper4->type != PROG_STRING)
abort_interp("Expected string argument. (4)");
if (oper3->type != PROG_STRING)
abort_interp("Expected string argument. (3)");
if (oper2->type != PROG_OBJECT)
abort_interp("Expected dbref argument. (2)");
if (oper2->data.objref < NOTHING || oper2->data.objref >= db_top)
abort_interp("Bad object. (2)");
if (oper2->data.objref != NOTHING &&
Typeof(oper2->data.objref) == TYPE_GARBAGE)
abort_interp("Garbage object. (2)");
if (oper1->type != PROG_OBJECT)
abort_interp("Expected dbref argument. (1)");
if (oper1->data.objref < NOTHING || oper1->data.objref >= db_top)
abort_interp("Bad object. (1)");
if (oper1->data.objref != NOTHING &&
Typeof(oper1->data.objref) == TYPE_GARBAGE)
abort_interp("Garbage object. (1)");
item = oper1->data.objref;
who = oper2->data.objref;
name = DoNullInd(oper3->data.string);
if (mlev < 2)
abort_interp("Permission denied. Requires at least Mucker Level 2.");
if (mlev < 3) {
if (who == NOTHING) {
abort_interp("Permission denied. Owner inspecific searches require Mucker Level 3.");
} else if (who != ProgUID) {
abort_interp("Permission denied. Searching for other people's stuff requires Mucker Level 3.");
}
}
if (item == NOTHING) {
item = 0;
} else {
item++;
}
strcpy(buf, name);
ref = NOTHING;
init_checkflags(player, DoNullInd(oper4->data.string), &check);
for (i = item; i < db_top; i++) {
if ((who == NOTHING || OWNER(i) == who) &&
checkflags(i, check) && NAME(i) && Typeof(i) != TYPE_GARBAGE &&
(!*name || equalstr(buf, (char *) NAME(i))))
{
ref = i;
break;
}
}
CLEAR(oper1);
CLEAR(oper2);
CLEAR(oper3);
CLEAR(oper4);
PushObject(ref);
}
/* ============================ */
/* = More ProtoMuck prims = */
/* ============================ */
void
prim_nextentrance(PRIM_PROTOTYPE)
{
dbref linkref, ref;
int foundref = 0;
int i, count;
if (mlev < 3)
abort_interp("Permission denied. Requires Mucker Level 3.");
oper2 = POP();
oper1 = POP();
linkref = oper1->data.objref;
ref = oper2->data.objref;
if (!valid_object(oper1) && (linkref != NOTHING) && (linkref != HOME))
abort_interp("Invalid link reference object (2)");
if (!valid_object(oper2) && ref != NOTHING)
abort_interp("Invalid reference object (1)");
if (linkref == HOME)
linkref = PLAYER_HOME(player);
(void) ref++;
for (; ref < db_top; ref++) {
oper2->data.objref = ref;
if (valid_object(oper2)) {
switch(Typeof(ref)) {
case TYPE_PLAYER:
if (PLAYER_HOME(ref) == linkref)
foundref = 1;
break;
case TYPE_ROOM:
if (DBFETCH(ref)->sp.room.dropto == linkref)
foundref = 1;
break;
case TYPE_THING:
if (THING_HOME(ref) == linkref)
foundref = 1;
break;
case TYPE_EXIT:
count = DBFETCH(ref)->sp.exit.ndest;
for (i = 0; i < count; i++) {
if (DBFETCH(ref)->sp.exit.dest[i] == linkref)
foundref = 1;
}
break;
}
if (foundref)
break;
}
}
if (!foundref)
ref = NOTHING;
CLEAR(oper1);
CLEAR(oper2);
PushObject(ref);
}
void
prim_newplayer(PRIM_PROTOTYPE)
{
dbref newplayer;
char *name, *password;
CHECKOP(2);
oper1 = POP();
oper2 = POP();
if (mlev < 4)
abort_interp("Permission denied. Requires Wizbit.");
if (oper1->type != PROG_STRING)
abort_interp("Non-string argument. (1)");
if (!oper1->data.string)
abort_interp("Empty string argument. (1)");
if (oper2->type != PROG_STRING)
abort_interp("Non-string argument. (2)");
if (!oper2->data.string)
abort_interp("Empty string argument. (2)");
name = oper2->data.string->data;
password = oper1->data.string->data;
if (!ok_player_name(name))
abort_interp("Invalid player name. (1)");
if (!ok_password(password))
abort_interp("Invalid password. (1)");
/* else he doesn't already exist, create him */
newplayer = create_player(name, password);
log_status("PCREATED[MUF]: %s(%d) by %s(%d)\n",
NAME(newplayer), (int) newplayer, NAME(player), (int) player);
CLEAR(oper1);
CLEAR(oper2);
PushObject(newplayer);
}
void
prim_copyplayer(PRIM_PROTOTYPE)
{
dbref newplayer, ref;
char *name, *password;
struct object *newp;
CHECKOP(3);
oper1 = POP();
oper2 = POP();
oper3 = POP();
if (mlev < 4)
abort_interp("Permission denied. Requires Wizbit.");
if (oper1->type != PROG_STRING)
abort_interp("Non-string argument. (3)");
if (!oper1->data.string)
abort_interp("Empty string argument. (3)");
if (oper2->type != PROG_STRING)
abort_interp("Non-string argument. (2)");
if (!oper2->data.string)
abort_interp("Empty string argument. (2)");
ref = oper3->data.objref;
if ((ref != NOTHING && !valid_player(oper3)) || ref == NOTHING)
abort_interp("Player dbref expected. (1)");
CHECKREMOTE(ref);
name = oper2->data.string->data;
password = oper1->data.string->data;
if (!ok_player_name(name))
abort_interp("Invalid player name. (2)");
if (!ok_password(password))
abort_interp("Invalid password. (2)");
/* else he doesn't already exist, create him */
newplayer = create_player(name, password);
/* initialize everything */
FLAGS(newplayer) = FLAGS(ref);
newp = DBFETCH(newplayer);
newp->properties = copy_prop(ref);
newp->exits = NOTHING;
newp->contents = NOTHING;
newp->next = NOTHING;
#ifdef DISKBASE
newp->propsfpos = 0;
newp->propsmode = PROPS_UNLOADED;
newp->propstime = 0;
newp->nextold = NOTHING;
newp->prevold = NOTHING;
dirtyprops(newplayer);
#endif
PLAYER_SET_HOME(newplayer, PLAYER_HOME(ref));
PLAYER_ADD_PENNIES(newplayer, PLAYER_PENNIES(ref));
moveto(newplayer, PLAYER_HOME(ref));
/* link him to player_start */
log_status("PCREATE[MUF]: %s(%d) by %s(%d)\n",
NAME(newplayer), (int) newplayer, NAME(player), (int) player);
CLEAR(oper1);
CLEAR(oper2);
CLEAR(oper3);
PushObject(newplayer);
}
void
prim_toadplayer(PRIM_PROTOTYPE)
{
dbref victim;
dbref recipient;
dbref stuff;
char buf[BUFFER_LEN];
CHECKOP(2);
oper1 = POP();
oper2 = POP();
victim = oper1->data.objref;
if (mlev < 4)
abort_interp("Permission denied. Requires Wizbit.");
if ((ref != NOTHING && !valid_player(oper1)) || ref == NOTHING)
abort_interp("Player dbref expected for player to be toaded (1)");
recipient = oper2->data.objref;
if ((recipient != NOTHING && !valid_player(oper2)) || ref == NOTHING)
abort_interp("Player dbref expected for recipient (2)");
CHECKREMOTE(ref);
CHECKREMOTE(recipient);
if (Typeof(victim) != TYPE_PLAYER) {
abort_interp("You can only toad players.");
return;
}
if (Typeof(recipient) != TYPE_PLAYER) {
abort_interp("Only players can receive the objects.");
return;
}
if (get_property_class( victim, "@/precious" )) {
abort_interp("That player is precious.");
return;
}
if ((FLAGS(victim) & WIZARD)) {
abort_interp("You can't toad a wizard.");
return;
}
/* we're ok, do it */
send_contents(fr->descr, player, HOME);
for (stuff = 0; stuff < db_top; stuff++) {
if (OWNER(stuff) == victim) {
switch (Typeof(stuff)) {
case TYPE_PROGRAM:
dequeue_prog(stuff, 0); /* dequeue player's progs */
FLAGS(stuff) &= ~(ABODE | WIZARD);
SetMLevel(stuff,0);
case TYPE_ROOM:
case TYPE_THING:
case TYPE_EXIT:
OWNER(stuff) = recipient;
DBDIRTY(stuff);
break;
}
}
if (Typeof(stuff) == TYPE_THING && THING_HOME(stuff) == victim) {
THING_SET_HOME(stuff, tp_player_start);
}
}
if (PLAYER_PASSWORD(victim)) {
free((void *) PLAYER_PASSWORD(victim));
PLAYER_SET_PASSWORD(victim, 0);
}
dequeue_prog(victim, 0); /* dequeue progs that player's running */
log_status("TOADED[MUF]: %s(%d) by %s(%d)\n", NAME(victim),
victim, NAME(player), player);
delete_player(victim);
snprintf(buf, sizeof(buf), "A slimy toad named %s", unmangle(victim, PNAME(victim)));
free((void *) NAME(victim));
NAME(victim) = alloc_string(buf);
DBDIRTY(victim);
boot_player_off(victim);
if (PLAYER_DESCRS(victim)) {
free(PLAYER_DESCRS(victim));
PLAYER_SET_DESCRS(victim, NULL);
PLAYER_SET_DESCRCOUNT(victim, 0);
}
ignore_remove_from_all_players(victim);
ignore_flush_cache(victim);
FREE_PLAYER_SP(victim);
ALLOC_THING_SP(victim);
THING_SET_HOME(victim, PLAYER_HOME(recipient));
/* reset name */
FLAGS(victim) = (FLAGS(victim) & ~TYPE_MASK) | TYPE_THING;
OWNER(victim) = recipient;
THING_SET_VALUE(victim, 1);
CLEAR(oper1);
CLEAR(oper2);
}
void
prim_objmem(PRIM_PROTOTYPE)
{
int i;
oper1 = POP();
if (oper1->type != PROG_OBJECT)
abort_interp("Argument must be a dbref.");
ref = oper1->data.objref;
if (ref >= db_top || ref <= NOTHING)
abort_interp("Invalid object.");
CLEAR(oper1);
i = size_object(ref, 0);
PushInt(i);
}
void
prim_instances(PRIM_PROTOTYPE)
{
unsigned short a = 0;
int b = 0;
CHECKOP(1);
oper1 = POP();
if (!valid_object(oper1))
abort_interp("Invalid object.");
ref = oper1->data.objref;
if (Typeof(ref) != TYPE_PROGRAM)
abort_interp("Object must be a program.");
CLEAR(oper1);
a = PROGRAM_INSTANCES(ref);
b = a;
PushInt(b);
}
void
prim_compiledp(PRIM_PROTOTYPE)
{
int i = 0;
CHECKOP(1);
oper1 = POP();
if (!valid_object(oper1))
abort_interp("Invalid object.");
ref = oper1->data.objref;
if (Typeof(ref) != TYPE_PROGRAM)
abort_interp("Object must be a program.");
CLEAR(oper1);
i = PROGRAM_SIZ(ref);
PushInt(i);
}
void
prim_newpassword(PRIM_PROTOTYPE)
{
char *ptr2;
char pad_char[] = "";
CHECKOP(2);
oper1 = POP();
oper2 = POP();
if (mlev < 4)
abort_interp("Permission denied. Requires Wizbit.");
if (oper1->type != PROG_STRING)
abort_interp("Password string expected. (2)");
if (oper2->type != PROG_OBJECT)
abort_interp("Player dbref expected. (1)");
ptr2 = oper1->data.string? oper1->data.string->data : pad_char;
ref = oper2->data.objref;
if (ref != NOTHING && !valid_player(oper2))
abort_interp("Player dbref expected. (1)");
CHECKREMOTE(ref);
set_password(ref, ptr2);
CLEAR(oper1);
CLEAR(oper2);
}
void
prim_newprogram(PRIM_PROTOTYPE)
{
dbref newprog;
char buf[BUFFER_LEN];
int jj;
CHECKOP(1);
oper1 = POP();
if (mlev < 4)
abort_interp("Permission denied. Requires Wizbit.");
if (oper1->type != PROG_STRING)
abort_interp("Expected string argument.");
if (!ok_name(oper1->data.string->data))
abort_interp("Invalid name (2)");
newprog = new_object();
NAME(newprog) = alloc_string(oper1->data.string->data);
snprintf(buf, sizeof(buf), "A scroll containing a spell called %s", oper1->data.string->data);
SETDESC(newprog, buf);
DBFETCH(newprog)->location = player;
FLAGS(newprog) = TYPE_PROGRAM;
jj = MLevel(player);
if (jj < 1)
jj = 1;
if (jj > 3)
jj = 3;
SetMLevel(newprog, jj);
OWNER(newprog) = OWNER(player);
ALLOC_PROGRAM_SP(newprog);
PROGRAM_SET_FIRST(newprog, NULL);
PROGRAM_SET_INSTANCES(newprog, 0);
PROGRAM_SET_CURR_LINE(newprog, 0);
PROGRAM_SET_SIZ(newprog, 0);
PROGRAM_SET_CODE(newprog, NULL);
PROGRAM_SET_START(newprog, NULL);
PROGRAM_SET_PUBS(newprog, NULL);
PROGRAM_SET_MCPBINDS(newprog, NULL);
PROGRAM_SET_PROFTIME(newprog, 0, 0);
PROGRAM_SET_PROFSTART(newprog, 0);
PROGRAM_SET_PROF_USES(newprog, 0);
PLAYER_SET_CURR_PROG(player, newprog);
PUSH(newprog, DBFETCH(player)->contents);
DBDIRTY(newprog);
DBDIRTY(player);
PushObject(newprog);
}
extern struct line *read_program(dbref prog);
void
prim_compile(PRIM_PROTOTYPE)
{
dbref ref;
struct line *tmpline;
CHECKOP(2);
oper2 = POP();
oper1 = POP();
if (mlev < 4)
abort_interp("Permission denied. Requires Wizbit.");
if (!valid_object(oper1))
abort_interp("No program dbref given. (1)");
ref = oper1->data.objref;
if (Typeof(ref) != TYPE_PROGRAM)
abort_interp("No program dbref given. (1)");
if (oper2->type != PROG_INTEGER)
abort_interp("No boolean integer given. (2)");
if (PROGRAM_INSTANCES(ref) > 0)
abort_interp("That program is currently in use.");
tmpline = PROGRAM_FIRST(ref);
PROGRAM_SET_FIRST(ref, read_program(ref));
do_compile(fr->descr, player, ref, oper2->data.number);
free_prog_text(PROGRAM_FIRST(ref));
PROGRAM_SET_FIRST(ref, tmpline);
PushInt(PROGRAM_SIZ(ref));
}
void
prim_uncompile(PRIM_PROTOTYPE)
{
dbref ref;
CHECKOP(1);
oper1 = POP();
if (mlev < 4)
abort_interp("Permission denied. Requires Wizbit.");
if (!valid_object(oper1))
abort_interp("No program dbref given.");
ref = oper1->data.objref;
if (Typeof(ref) != TYPE_PROGRAM)
abort_interp("No program dbref given.");
if (PROGRAM_INSTANCES(ref) > 0)
abort_interp("That program is currently in use.");
uncompile_program(ref);
}
void
prim_getpids(PRIM_PROTOTYPE)
{
stk_array *nw;
CHECKOP(1);
oper1 = POP();
if (mlev < 3)
abort_interp("Permission denied. Requires Mucker Level 3.");
if (oper1->type != PROG_OBJECT)
abort_interp("Non-object argument (1)");
nw = get_pids(oper1->data.objref);
if (program == oper1->data.objref)
{
struct inst temp;
temp.type = PROG_INTEGER;
temp.data.number = fr->pid;
array_appenditem(&nw, &temp);
CLEAR(&temp);
}
CLEAR(oper1);
PushArrayRaw(nw);
}
void
prim_getpidinfo(PRIM_PROTOTYPE)
{
stk_array* nu;
double cpu;
time_t etime;
CHECKOP(1);
oper1 = POP();
if (mlev < 3)
abort_interp("Permission denied. Requires Mucker Level 3.");
if (oper1->type != PROG_INTEGER)
abort_interp("Non-integer argument (1)");
if (oper1->data.number == fr->pid)
{
if ((nu = new_array_dictionary()) == NULL)
abort_interp("Out of memory");
if ((etime = time(NULL) - fr->started) > 0)
{
cpu = ((fr->totaltime.tv_sec + (fr->totaltime.tv_usec / 1000000.0f)) * 100.0f) / etime;
if (cpu > 100.0f)
cpu = 100.0f;
}
else
cpu = 0.0f;
array_set_strkey_intval(&nu, "PID", fr->pid);
array_set_strkey_intval(&nu, "INSTCNT", fr->instcnt);
array_set_strkey_intval(&nu, "DESCR", fr->descr);
array_set_strkey_intval(&nu, "NEXTRUN", 0);
array_set_strkey_intval(&nu, "STARTED", fr->started);
array_set_strkey_refval(&nu, "CALLED_PROG", program);
array_set_strkey_refval(&nu, "TRIG", fr->trig);
array_set_strkey_refval(&nu, "PLAYER", player);
array_set_strkey_fltval(&nu, "CPU", cpu);
array_set_strkey_strval(&nu, "CALLED_DATA", "");
array_set_strkey_strval(&nu, "TYPE", "MUF");
array_set_strkey_strval(&nu, "SUBTYPE", "");
}
else
nu = get_pidinfo(oper1->data.number);
CLEAR(oper1);
PushArrayRaw(nu);
}
void
prim_contents_array(PRIM_PROTOTYPE)
{
stk_array *nw;
int count = 0;
CHECKOP(1);
oper1 = POP();
if (!valid_object(oper1))
abort_interp("Invalid dbref (1)");
ref = oper1->data.objref;
if ((Typeof(ref) == TYPE_PROGRAM) || (Typeof(ref) == TYPE_EXIT))
abort_interp("Dbref cannot be a program nor exit (1)");
CHECKREMOTE(oper1->data.objref);
for(ref = DBFETCH(oper1->data.objref)->contents; (ref >= 0) && (ref < db_top); ref = DBFETCH(ref)->next)
count++;
nw = new_array_packed(count);
for(ref = DBFETCH(oper1->data.objref)->contents, count = 0; (ref >= 0) && (ref < db_top); ref = DBFETCH(ref)->next)
array_set_intkey_refval(&nw, count++, ref);
CLEAR(oper1);
PushArrayRaw(nw);
}
void
prim_exits_array(PRIM_PROTOTYPE)
{
stk_array *nw;
int count = 0;
CHECKOP(1);
oper1 = POP();
if (!valid_object(oper1))
abort_interp("Invalid dbref (1)");
ref = oper1->data.objref;
CHECKREMOTE(oper1->data.objref);
if ((mlev < 3) && !permissions(ProgUID, ref))
abort_interp("Permission denied.");
if ((Typeof(ref) == TYPE_PROGRAM) || (Typeof(ref) == TYPE_EXIT))
abort_interp("Dbref cannot be a program nor exit (1)");
for(ref = DBFETCH(oper1->data.objref)->exits; (ref >= 0) && (ref < db_top); ref = DBFETCH(ref)->next)
count++;
nw = new_array_packed(count);
for(ref = DBFETCH(oper1->data.objref)->exits, count = 0; (ref >= 0) && (ref < db_top); ref = DBFETCH(ref)->next)
array_set_intkey_refval(&nw, count++, ref);
CLEAR(oper1);
PushArrayRaw(nw);
}
stk_array *
array_getlinks(dbref obj)
{
stk_array* nw = new_array_packed(0);
int count = 0;
if ((obj >= 0) && (obj < db_top)) {
switch (Typeof(obj)) {
case TYPE_ROOM:
array_set_intkey_refval(&nw, count++, DBFETCH(obj)->sp.room.dropto);
break;
case TYPE_THING:
array_set_intkey_refval(&nw, count++, THING_HOME(obj));
break;
case TYPE_PLAYER:
array_set_intkey_refval(&nw, count++, PLAYER_HOME(obj));
break;
case TYPE_EXIT:
for (count = 0; count < (DBFETCH(obj)->sp.exit.ndest); count++)
array_set_intkey_refval(&nw, count, (DBFETCH(obj)->sp.exit.dest)[count]);
break;
}
}
return nw;
}
void
prim_getlinks_array(PRIM_PROTOTYPE)
{
CHECKOP(1);
oper1 = POP();
if (!valid_object(oper1))
abort_interp("Invalid object dbref. (1)");
ref = oper1->data.objref;
CHECKREMOTE(oper1->data.objref);
CLEAR(oper1);
PushArrayRaw(array_getlinks(ref));
}
void
prim_program_getlines(PRIM_PROTOTYPE)
{
stk_array* ary;
int start, end;
CHECKOP(3);
oper3 = POP();
oper2 = POP();
oper1 = POP();
start = end = 0;
if (!valid_object(oper1))
abort_interp("Invalid object dbref. (1)");
if (oper2->type != PROG_INTEGER)
abort_interp("Expected integer. (2)");
if (oper3->type != PROG_INTEGER)
abort_interp("Expected integer. (3)");
ref = oper1->data.objref;
start = oper2->data.number;
end = oper3->data.number;
if (Typeof(ref) != TYPE_PROGRAM)
abort_interp("Non-program object. (1)");
if (mlev < 4 && !controls(ProgUID, ref) && !(FLAGS(ref) & VEHICLE))
abort_interp("Permission denied.");
if (start < 0 || end < 0)
abort_interp("Line indexes must be non-negative.");
if (start == 0)
start = 1;
if (end && start > end)
abort_interp("Illogical line range.");
CLEAR(oper1);
CLEAR(oper2);
CLEAR(oper3);
{
/* we make two passes over our linked list's data,
* first we figure out how many lines are
* actually there. This is so we only allocate
* our array once, rather re-allocating 4000 times
* for a 4000-line program listing, while avoiding
* letting calls like '#xxx 1 999999 program_getlines'
* taking up tones of memory.
*/
int i, count;
/* current line we're iterating over */
struct line* curr;
/* first line in the program */
struct line* first;
/* starting line in our segment of the program */
struct line* segment;
curr = first = read_program(ref);
/* find our line */
for (i = 1; curr && i < start; i++)
curr = curr->next;
if (!curr) {
/* alright, we have no data! */
free_prog_text(first);
PushNullArray;
return;
}
segment = curr; /* we need to keep this line */
/* continue our looping */
for (; curr && (!end || i < end); i++)
curr = curr->next;
count = i - start + 1;
if (!curr) /* if we have don't have curr, we counted one beyond
the end of the program, so we account for that. */
count--;
ary = new_array_packed(count);
/*
* so we count down from the number of lines we have,
* and set our array appropriatly.
*/
for(curr = segment, i = 0; count--; i++, curr = curr->next) {
array_set_intkey_strval(&ary, i, curr->this_line);
}
free_prog_text(first);
}
PushArrayRaw(ary);
}
void
prim_program_setlines(PRIM_PROTOTYPE)
{
struct line* lines = 0;
struct line* prev = 0;
array_iter idx;
CHECKOP(2);
oper2 = POP(); /* list:Lines */
oper1 = POP(); /* ref:Program */
if (mlev < 4)
abort_interp("Mucker level 4 or greater required.");
if (oper1->type != PROG_OBJECT)
abort_interp("Non-object argument. (1)");
if (oper2->type != PROG_ARRAY)
abort_interp("Non-array argument. (2)");
if (!valid_object(oper1))
abort_interp("Invalid object. (1)");
if (Typeof(oper1->data.objref) != TYPE_PROGRAM)
abort_interp("Non-program object. (1)");
if (oper2->data.array && (oper2->data.array->type != ARRAY_PACKED))
abort_interp("Array list type required. (2)");
if (!array_is_homogenous(oper2->data.array, PROG_STRING))
abort_interp("Argument not an array of strings. (2)");
if (!controls(ProgUID, oper1->data.objref))
abort_interp("Permission denied.");
if (FLAGS(oper1->data.objref) & INTERNAL)
abort_interp("Program already being edited.");
if (array_first(oper2->data.array, &idx))
{
do
{
array_data* val = array_getitem(oper2->data.array, &idx);
struct line* ln = get_new_line();
ln->this_line = alloc_string(val->data.string ? val->data.string->data : " ");
if (prev)
{
prev->next = ln;
ln->prev = prev;
}
else
lines = ln;
prev = ln;
}
while(array_next(oper2->data.array, &idx));
}
write_program(lines, oper1->data.objref);
log_status("PROGRAM SAVED: %s by %s(%d)\n", unparse_object(player, oper1->data.objref), NAME(player), player);
if (tp_log_programs)
log_program_text(lines, player, oper1->data.objref);
free_prog_text(lines);
CLEAR(oper1);
CLEAR(oper2);
DBDIRTY(program);
}
void
prim_setlinks_array(PRIM_PROTOTYPE)
{
array_iter idx;
int dest_count;
dbref what;
stk_array* arr;
CHECKOP(2);
oper2 = POP(); /* arr:Destination(s) */
oper1 = POP(); /* ref:Source */
if (oper1->type != PROG_OBJECT)
abort_interp("Non-object argument. (1)");
if (oper2->type != PROG_ARRAY)
abort_interp("Non-array argument. (3)");
if (!array_is_homogenous(oper2->data.array, PROG_OBJECT))
abort_interp("Argument not an array of dbrefs. (2)");
if (!valid_object(oper1))
abort_interp("Invalid object. (1)");
if ((mlev < 4) && !permissions(ProgUID, oper1->data.objref))
abort_interp("Permission denied. (1)");
if ((dest_count = array_count(oper2->data.array)) >= MAX_LINKS)
abort_interp("Too many destinations. (2)");
if ((dest_count > 1) && (Typeof(oper1->data.objref) != TYPE_EXIT))
abort_interp("Only exit may be linked to multiple destinations.");
what = oper1->data.objref;
arr = oper2->data.array;
if (array_first(arr, &idx))
{
int found_prp = 0;
do
{
array_data* val = array_getitem(arr, &idx);
dbref where = val->data.objref;
if ((where != HOME) && !valid_object(val))
{
CLEAR(&idx);
abort_interp("Invalid object. (2)");
}
if (!prog_can_link_to(mlev, ProgUID, Typeof(what), where))
{
CLEAR(&idx);
abort_interp("Can't link source to destination. (2)");
}
switch(Typeof(what))
{
case TYPE_EXIT:
switch(Typeof(where))
{
case TYPE_PLAYER:
case TYPE_ROOM:
case TYPE_PROGRAM:
if (found_prp != 0)
{
CLEAR(&idx);
abort_interp("Only one player, room, or program destination allowed.");
}
found_prp = 1;
break;
case TYPE_THING:
break;
case TYPE_EXIT:
if (exit_loop_check(what, where))
{
CLEAR(&idx);
abort_interp("Destination would create loop.");
}
break;
default:
CLEAR(&idx);
abort_interp("Invalid object. (2)");
break;
}
break;
case TYPE_PLAYER:
if (where == HOME)
{
CLEAR(&idx);
abort_interp("Cannot link player to HOME.");
}
break;
case TYPE_THING:
if (where == HOME)
{
CLEAR(&idx);
abort_interp("Cannot link thing to HOME.");
}
if (parent_loop_check(what, where))
{
CLEAR(&idx);
abort_interp("That would case a parent paradox.");
}
break;
case TYPE_ROOM:
break;
default:
CLEAR(&idx);
abort_interp("Invalid object. (1)");
break;
}
}
while(array_next(arr, &idx));
}
if (Typeof(what) == TYPE_EXIT)
{
if (MLevRaw(what))
SetMLevel(what, 0);
if (DBFETCH(what)->sp.exit.dest != NULL)
free((void*)DBFETCH(what)->sp.exit.dest);
}
if (dest_count <= 0)
{
switch(Typeof(what))
{
case TYPE_EXIT:
DBSTORE(what, sp.exit.ndest, 0);
DBSTORE(what, sp.exit.dest, NULL);
break;
case TYPE_ROOM:
DBSTORE(what, sp.room.dropto, NOTHING);
break;
default:
abort_interp("Only exits and rooms may be linked to nothing. (1)");
break;
}
}
else
{
switch(Typeof(what))
{
case TYPE_EXIT:
{
dbref* dests = (dbref*)malloc(sizeof(dbref) * dest_count);
if (dests == NULL)
{
DBSTORE(what, sp.exit.ndest, 0);
DBSTORE(what, sp.exit.dest, NULL);
abort_interp("Out of memory.");
}
if (array_first(arr, &idx))
{
int i = 0;
do
{
if (i < dest_count)
dests[i++] = array_getitem(arr, &idx)->data.objref;
}
while(array_next(arr, &idx));
}
DBSTORE(what, sp.exit.ndest, dest_count);
DBSTORE(what, sp.exit.dest, dests);
}
break;
case TYPE_ROOM:
if (array_first(arr, &idx))
{
DBSTORE(what, sp.room.dropto, array_getitem(arr, &idx)->data.objref);
CLEAR(&idx);
}
break;
case TYPE_PLAYER:
if (array_first(arr, &idx))
{
PLAYER_SET_HOME(what, array_getitem(arr, &idx)->data.objref);
CLEAR(&idx);
}
break;
case TYPE_THING:
if (array_first(arr, &idx))
{
THING_SET_HOME(what, array_getitem(arr, &idx)->data.objref);
CLEAR(&idx);
}
break;
default:
abort_interp("Invalid object. (1)");
break;
}
}
DBDIRTY(what);
CLEAR(oper1);
CLEAR(oper2);
}