#include "defs.h" #include "prims.h" #include "property.h" PRIM(moveto) { struct inst *vvictim; struct inst *vdest; dbref victim; dbref dest; dbref matchroom; NARGS(2); vdest = TOS(0); vvictim = TOS(1); if (!valid_object(vvictim) || (!valid_object(vdest) && !is_home(vdest))) { ABORT_INTERP("Non-object argument."); } victim = vvictim->data.objref; dest = vdest->data.objref; matchroom = NOTHING; if ( !(FLAGS(victim) & JUMP_OK) && !permissions(UID,victim) && !PWIZARD ) { ABORT_INTERP("Object can't be moved."); } switch (Typeof(victim)) { case TYPE_PLAYER: if (Typeof(dest) != TYPE_ROOM) ABORT_INTERP("Bad destination."); /* Check permissions */ if (! PWIZARD) { if ( !(FLAGS(DBFETCH(victim)->location) & JUMP_OK) && !permissions(UID,DBFETCH(victim)->location) ) { ABORT_INTERP("Source not JUMP_OK."); } if ( !is_home(vdest) && !(FLAGS(dest) & JUMP_OK) && !permissions(UID,dest) ) { ABORT_INTERP("Destination not JUMP_OK."); } } add_proglock(program,player,PROGLOCK_READ); enter_room(victim,dest,program); if (interp_errored()) return; remove_proglock(program,player); break; case TYPE_PROGRAM: case TYPE_THING: if ( (Typeof(dest) != TYPE_ROOM) && (Typeof(dest) != TYPE_PLAYER) ) { ABORT_INTERP("Bad destination."); } if (! PWIZARD) { if (permissions(UID,dest)) { matchroom = dest; } if (permissions(UID,DBFETCH(victim)->location)) { matchroom = DBFETCH(victim)->location; } if ( (matchroom != NOTHING) && !(FLAGS(matchroom) & JUMP_OK) && !permissions(UID,victim) ) { ABORT_INTERP("Permission denied."); } } moveto(victim,dest); break; case TYPE_ROOM: if (Typeof(dest) != TYPE_ROOM) ABORT_INTERP("Bad destination."); if (victim == GLOBAL_ENVIRONMENT) ABORT_INTERP("Permission denied."); if (dest == HOME) { dest = GLOBAL_ENVIRONMENT; } else { if ( !PWIZARD && ( !permissions(UID,victim) || !can_link_to(UID,TYPE_ROOM,dest) ) ) { ABORT_INTERP("Permission denied."); } if (parent_loop_check(victim,dest)) { ABORT_INTERP("Parent room would create a loop."); } } moveto(victim,dest); break; case TYPE_EXIT: if ( (Typeof(dest) != TYPE_ROOM) && (Typeof(dest) != TYPE_PLAYER) && (Typeof(dest) != TYPE_THING) ) { ABORT_INTERP("Bad destination."); } if ( !PWIZARD && ( !permissions(UID,victim) || !can_link_to(UID,TYPE_EXIT,dest) ) ) { ABORT_INTERP("Permission denied."); } unset_source(UID,DBFETCH(victim)->location,victim); set_source(UID,victim,dest); break; default: ABORT_INTERP("Invalid object type (1)"); break; } POP(2); } PRIM(contents) { struct inst *v; dbref rv; NARGS(1); v = TOS(0); if (!valid_object(v)) ABORT_INTERP("Invalid argument type."); rv = DBFETCH(v->data.objref)->contents; POP(1); MPUSH(PROG_OBJECT,rv); } PRIM(exits) { struct inst *v; dbref x; dbref rv; NARGS(1); v = TOS(0); if (!valid_object(v)) ABORT_INTERP("Invalid argument type."); x = v->data.objref; if (!PWIZARD && !permissions(UID,x)) ABORT_INTERP("Permission denied."); switch (Typeof(x)) { case TYPE_PLAYER: rv = DBFETCH(x)->sp.player.actions; break; case TYPE_ROOM: rv = DBFETCH(x)->sp.room.exits; break; case TYPE_THING: rv = DBFETCH(x)->sp.thing.actions; break; default: rv = NOTHING; break; } POP(1); MPUSH(PROG_OBJECT,rv); } PRIM(daemons) { STACKROOM(1); MPUSH(PROG_OBJECT,head_daemon); } PRIM(next) { struct inst *v; dbref rv; NARGS(1); v = TOS(0); if (!valid_object(v)) ABORT_INTERP("Invalid object."); rv = DBFETCH(v->data.objref)->next; POP(1); MPUSH(PROG_OBJECT,rv); } PRIM(match) { struct inst *v; dbref rv; struct match_data md; NARGS(1); v = TOS(0); if (v->type != PROG_STRING) ABORT_INTERP("Non-string argument."); if (!v->data.string) ABORT_INTERP("Empty string argument."); /* pass OWNER(player), not uid, so that me / here / home are right */ /* the wizard check below lets wizard stuff work anyway. */ init_match(OWNER(player),v->data.string,NOTYPE,&md); match_all_exits(&md); match_neighbor(&md); match_possession(&md); match_me(&md); match_here(&md); match_home(&md); if (Wizard(UID) || PWIZARD) { match_absolute(&md); match_player(&md); } rv = match_result(&md); POP(1); MPUSH(PROG_OBJECT,rv); } PRIM(rmatch) { struct inst *vloc; struct inst *vstring; dbref dbr; struct match_data md; NARGS(2); vstring = TOS(0); vloc = TOS(1); if (vstring->type != PROG_STRING) ABORT_INTERP("Non-string argument. (2)"); if (!vstring->data.string) ABORT_INTERP("Empty string argument. (2)"); if (vloc->type != PROG_OBJECT) ABORT_INTERP("Non-object argument. (1)"); dbr = vloc->data.objref; if (dbr != NOTHING) { if (!valid_object(vloc)) ABORT_INTERP("Invalid argument. (1)"); switch (Typeof(dbr)) { case TYPE_THING: case TYPE_ROOM: case TYPE_PLAYER: break; default: ABORT_INTERP("Invalid argument. (1)"); break; } init_match(UID,vstring->data.string,TYPE_THING,&md); match_rmatch(dbr,&md); dbr = match_result(&md); } POP(2); MPUSH(PROG_OBJECT,dbr); } PRIM(owner) { struct inst *v; dbref rv; NARGS(1); v = TOS(0); if (!valid_object(v)) ABORT_INTERP("Invalid object."); rv = OWNER(v->data.objref); POP(1); MPUSH(PROG_OBJECT,rv); } PRIM(location) { struct inst *v; dbref rv; NARGS(1); v = TOS(0); if (!valid_object(v)) ABORT_INTERP("Invalid object."); rv = DBFETCH(v->data.objref)->location; POP(1); MPUSH(PROG_OBJECT,rv); } PRIM(getlink) { struct inst *v; dbref dbr; NARGS(1); v = TOS(0); if (!valid_object(v)) ABORT_INTERP("Invalid object."); dbr = v->data.objref; switch (Typeof(dbr)) { case TYPE_EXIT: dbr = (DBFETCH(dbr)->sp.exit.ndest) ? DBFETCH(dbr)->sp.exit.dest[0] : NOTHING; break; case TYPE_PLAYER: dbr = DBFETCH(dbr)->sp.player.home; break; case TYPE_THING: dbr = DBFETCH(dbr)->sp.thing.home; break; case TYPE_ROOM: dbr = DBFETCH(dbr)->sp.room.dropto; break; default: ABORT_INTERP("Invalid object type."); break; } POP(1); MPUSH(PROG_OBJECT,dbr); } PRIM(online) { struct descriptor_data *d; int n; n = 0; for (d=descriptor_list;d;d=d->flink) { if (d->connected) { STACKROOM(1); MPUSH(PROG_OBJECT,d->player); n ++; } } STACKROOM(1); MPUSH(PROG_INTEGER,n); } PRIM(db_top) { STACKROOM(1); MPUSH(PROG_INTEGER,(int)db_top); } PRIM(dbtop) { STACKROOM(1); MPUSH(PROG_OBJECT,(dbref)(db_top-1)); } PRIM(chown) { struct inst *vvictim; struct inst *vowner; dbref victim; dbref owner; NARGS(2); vowner = TOS(0); vvictim = TOS(1); if (!valid_object(vvictim)) ABORT_INTERP("Invalid argument (1)"); if (!valid_object(vowner)) ABORT_INTERP("Invalid argument (2)"); victim = vvictim->data.objref; owner = vowner->data.objref; if (!PWIZARD && !(FLAGS(victim) & OWNABLE)) ABORT_INTERP("Permission denied."); if (Typeof(victim) == TYPE_PLAYER) ABORT_INTERP("Can't chown a player."); if (Typeof(owner) != TYPE_PLAYER) ABORT_INTERP("New owner is not a player."); if (!PWIZARD && (owner != UID)) ABORT_INTERP("Can't chown to anyone but yourself."); if (Typeof(victim) == TYPE_DAEMON) { if ( !PWIZARD && ( DBFETCH(owner)->sp.player.daemons >= (TrueWizard(owner) ? MAX_WIZ_DAEMONS : MAX_DAEMONS) ) ) { ABORT_INTERP("New owner would own too many daemons."); } DBFETCH(owner)->sp.player.daemons ++; DBFETCH(OWNER(victim))->sp.player.daemons --; DBDIRTY(OWNER(victim)); } remove_ownerlist(victim); OWNER(victim) = owner; add_ownerlist(victim); POP(2); } PRIM(linkcount) { struct inst *v; dbref dbr; int n; NARGS(1); v = TOS(0); if (!valid_object(v)) ABORT_INTERP("Invalid object."); dbr = v->data.objref; switch (Typeof(dbr)) { case TYPE_EXIT: n = DBFETCH(dbr)->sp.exit.ndest; break; case TYPE_PLAYER: n = 1; break; case TYPE_THING: n = (DBFETCH(dbr)->sp.thing.home != NOTHING); break; case TYPE_ROOM: n = (DBFETCH(dbr)->sp.room.dropto != NOTHING); break; default: n = 0; break; } POP(1); MPUSH(PROG_INTEGER,n); } PRIM(getlinks) { struct inst *v; dbref dbr; int n; int i; NARGS(1); v = TOS(0); if (!valid_object(v)) ABORT_INTERP("Invalid object."); dbr = v->data.objref; switch (Typeof(dbr)) { case TYPE_EXIT: n = DBFETCH(dbr)->sp.exit.ndest; if (n > 0) STACKROOM(n); POP(1); for (i=0;isp.exit.dest[i]); MPUSH(PROG_INTEGER,n); break; case TYPE_PLAYER: STACKROOM(1); POP(1); MPUSH(PROG_OBJECT,DBFETCH(dbr)->sp.player.home); MPUSH(PROG_INTEGER,1); break; case TYPE_THING: POP(1); if (DBFETCH(dbr)->sp.thing.home == NOTHING) { MPUSH(PROG_INTEGER,0); } else { MPUSH(PROG_OBJECT,DBFETCH(dbr)->sp.thing.home); MPUSH(PROG_INTEGER,1); } break; case TYPE_ROOM: POP(1); if (DBFETCH(dbr)->sp.room.dropto == NOTHING) { MPUSH(PROG_INTEGER,0); } else { MPUSH(PROG_OBJECT,DBFETCH(dbr)->sp.room.dropto); MPUSH(PROG_INTEGER,1); } break; default: ABORT_INTERP("Invalid object type."); break; } } PRIM(prog) { STACKROOM(1); MPUSH(PROG_OBJECT,program); } PRIM(caller) { STACKROOM(1); MPUSH(PROG_OBJECT,fr->startcaller); } PRIM(callers) { struct dbref_list *drl; int n; n = 0; for (drl=fr->caller;drl;drl=drl->next) { STACKROOM(1); MPUSH(PROG_OBJECT,drl->object); n ++; } STACKROOM(1); MPUSH(PROG_INTEGER,n); } PRIM(daemon) { STACKROOM(1); MPUSH(PROG_OBJECT,fr->daemon); } PRIM(kill) { struct inst *v; dbref d; NARGS(1); v = TOS(0); if (!valid_object(v)) ABORT_INTERP("Invalid object."); d = v->data.objref; if (Typeof(d) != TYPE_DAEMON) ABORT_INTERP("Not a daemon."); if (d == player) { interp_set_fatal_err(); } else { if (! PWIZARD) { if ( (OWNER(d) != UID) || (FLAGS(d) & UNKILLABLE) ) ABORT_INTERP("Permission denied."); } else if (d == fr->daemon) { interp_set_fatal_err(); log_status("Error in prims_kill: fr->daemon[%d] != player[%d]",(int)fr->daemon,(int)player); } else { remove_daemon(d); } } POP(1); } PRIM(trig) { STACKROOM(1); MPUSH(PROG_OBJECT,fr->trigger); } PRIM(backlinks) { struct inst *v; dbref d; int n; struct dbref_list *drl; NARGS(1); v = TOS(0); if (!valid_object(v)) ABORT_INTERP("Invalid object."); d = v->data.objref; if (!PWIZARD && (OWNER(player) != OWNER(d))) ABORT_INTERP("Permission denied."); POP(1); n = 0; for (drl=DBFETCH(d)->backlinks;drl;drl=drl->next) { STACKROOM(1); MPUSH(PROG_OBJECT,drl->object); n ++; } STACKROOM(1); MPUSH(PROG_INTEGER,n); } PRIM(backlocks) { struct inst *v; dbref d; int n; struct dbref_list *drl; NARGS(1); v = TOS(0); if (!valid_object(v)) ABORT_INTERP("Invalid object."); d = v->data.objref; if (!PWIZARD && (OWNER(player) != OWNER(d))) ABORT_INTERP("Permission denied."); POP(1); n = 0; for (drl=DBFETCH(d)->backlocks;drl;drl=drl->next) { STACKROOM(1); MPUSH(PROG_OBJECT,drl->object); n ++; } STACKROOM(1); MPUSH(PROG_INTEGER,n); } PRIM(backprops) { struct inst *v; dbref d; int n; struct dbref_list *drl; NARGS(1); v = TOS(0); if (!valid_object(v)) ABORT_INTERP("Invalid object."); d = v->data.objref; if (!PWIZARD && (OWNER(player) != OWNER(d))) ABORT_INTERP("Permission denied."); POP(1); n = 0; for (drl=DBFETCH(d)->backprops;drl;drl=drl->next) { STACKROOM(1); MPUSH(PROG_OBJECT,drl->object); n ++; } STACKROOM(1); MPUSH(PROG_INTEGER,n); } PRIM(nextowned) { struct inst *v; dbref rv; NARGS(1); v = TOS(0); if (!valid_object(v)) ABORT_INTERP("Invalid object."); rv = v->data.objref; if (!PWIZARD && (OWNER(player) != OWNER(rv))) ABORT_INTERP("Permission denied."); do { rv = DBFETCH(rv)->nextowned; } while ((rv != NOTHING) && (Typeof(rv) == TYPE_GARBAGE)); POP(1); MPUSH(PROG_OBJECT,rv); } PRIM(numowned) { struct inst *v; dbref owner; dbref d; int n; NARGS(1); v = TOS(0); if (!valid_object(v)) ABORT_INTERP("Invalid object."); owner = OWNER(v->data.objref); if (!PWIZARD && (OWNER(player) != owner)) ABORT_INTERP("Permission denied."); n = 0; for (d=owner;d!=NOTHING;d=DBFETCH(d)->nextowned) { if (Typeof(d) != TYPE_GARBAGE) n ++; } POP(1); if (Typeof(owner) != TYPE_PLAYER) { log_status("Error in prims_numowned: owner (#%d) isn't a player",(int)owner); } else if (n != DBFETCH(owner)->sp.player.dbrefs_owned) { log_status("Error in prims_numowned: we count %d, sp.player (#%d) sez %d",n,(int)owner,DBFETCH(owner)->sp.player.dbrefs_owned); DBSTORE(owner,sp.player.dbrefs_owned,n); } MPUSH(PROG_INTEGER,n); } PRIM(lock) { struct inst *vobj; struct inst *vkey; dbref obj; char *keystring; struct boolexp *key; NARGS(2); vkey = TOS(0); vobj = TOS(1); if ((vobj->type == PROG_STRING) && valid_object(vkey)) { struct inst *t; char tmp[64]; sprintf(&tmp[0],"Please fix the LOCK call in #%d",(int)program); notify(OWNER(program),&tmp[0]); t = vkey; vkey = vobj; vobj = t; } if (!valid_object(vobj)) ABORT_INTERP("Non-object argument."); if (vkey->type != PROG_STRING) ABORT_INTERP("Non-string argument."); obj = vobj->data.objref; if (!PWIZARD && !permissions(UID,obj)) ABORT_INTERP("Permission denied."); keystring = vkey->data.string; if (! keystring) { remove_backlocks_parse(obj,DBFETCH(obj)->key); free_boolexp(DBFETCH(obj)->key); DBSTORE(obj,key,TRUE_BOOLEXP); } else { key = parse_boolexp(player,keystring); if (key == TRUE_BOOLEXP) { ABORT_INTERP("Invalid key."); } else { remove_backlocks_parse(obj,DBFETCH(obj)->key); free_boolexp(DBFETCH(obj)->key); DBSTORE(obj,key,key); add_backlocks_parse(obj,DBFETCH(obj)->key); } } POP(2); } PRIM(unlock) { struct inst *v; dbref obj; NARGS(1); v = TOS(0); if (!valid_object(v)) ABORT_INTERP("Non-object argument."); obj = v->data.objref; if (!PWIZARD && !permissions(UID,obj)) ABORT_INTERP("Permission denied."); remove_backlocks_parse(obj,DBFETCH(obj)->key); free_boolexp(DBFETCH(obj)->key); DBSTORE(obj,key,TRUE_BOOLEXP); POP(1); } static int forcecount; void clearforce() { forcecount = 0; } PRIM(force) { struct inst *vvictim; struct inst *vcmd; dbref victim; char *cmd; NARGS(2); vcmd = TOS(0); vvictim = TOS(1); if ((Typeof(player) == TYPE_PLAYER) && (forcecount++ > 20)) ABORT_INTERP("Excessive forcing."); if (!valid_object(vvictim)) ABORT_INTERP("Non-object argument."); victim = vvictim->data.objref; if (Typeof(victim) != TYPE_PLAYER) ABORT_INTERP("Non-player argument."); if (vcmd->type != PROG_STRING) ABORT_INTERP("Non-string argument."); cmd = vcmd->data.string; vcmd->data.string = 0; POP(2); if ( (victim == OWNER(program)) || (PWIZARD && PERMIT_FORCE(UID,victim)) ) { static char nbuf = '\0'; SERIAL pser; pser = DBFETCH(player)->serial; /* no DoNullInd 'cause that makes it go const */ process_command(victim,cmd?cmd:&nbuf); free(cmd); if (DBFETCH(player)->serial != pser) interp_set_fatal_err(); } else { free(cmd); ABORT_INTERP("Permission denied."); } } PRIM(memused) { struct inst *v; dbref thing; struct object *o; int used; NARGS(1); v = TOS(0); if (!valid_object(v)) ABORT_INTERP("Non-object argument."); thing = v->data.objref; if (!PWIZARD && !permissions(UID,thing)) ABORT_INTERP("Permission denied."); o = DBFETCH(thing); used = sizeof(struct object) + strlen(o->name) + 1 + str_memusage(o->description) + str_memusage(o->fail_message) + str_memusage(o->succ_message) + str_memusage(o->drop_message) + str_memusage(o->ofail) + str_memusage(o->osuccess) + str_memusage(o->odrop) + dbref_list_memused(o->backlinks) + dbref_list_memused(o->backlocks) + dbref_list_memused(o->sleepers) + boolexp_memused(o->key) + plist_memused(o->properties); switch (Typeof(thing)) { case TYPE_ROOM: break; case TYPE_THING: break; case TYPE_EXIT: used += o->sp.exit.ndest * sizeof(dbref); break; case TYPE_PLAYER: used += strlen(o->sp.player.password) + 1 + framestack_memused(o->sp.player.run) + dbref_list_memused(o->sp.player.proglocks); break; case TYPE_PROGRAM: used += dbref_list_memused(o->sp.program.proglocks); if (o->sp.program.codevec) { used += codevec_memused(o->sp.program.codevec,o->sp.program.codesiz) + stabvec_memused(o->sp.program.stabvec,o->sp.program.stabsiz); } break; case TYPE_DAEMON: used += framestack_memused(o->sp.daemon.run) + dbref_list_memused(o->sp.daemon.proglocks); break; case TYPE_GARBAGE: break; } POP(1); MPUSH(PROG_INTEGER,used); } PRIM(uid) { MPUSH(PROG_OBJECT,UID); } PRIM(current_frame_id) { MPUSH(PROG_QUAD,fr->serial); } PRIM(frame_id_busy_p) { struct frame *f; struct inst *v; MUFQUAD q; NARGS(1); v = TOS(0); if (v->type != PROG_QUAD) ABORT_INTERP("Non-quad argument."); q = *v->data.quad; POP(1); for (f=allframes;f;f=f->flink) { if (f->serial == q) { MPUSH(PROG_INTEGER,1); return; } } MPUSH(PROG_INTEGER,0); } PRIM(trigger_exit) { struct inst *vxit; struct inst *vstr; dbref xit; char *str; NARGS(2); vstr = TOS(0); vxit = TOS(1); if (vstr->type != PROG_STRING) ABORT_INTERP("Non-string argument. (2)"); if (! valid_object(vxit)) ABORT_INTERP("Non-object argument. (1)"); xit = vxit->data.objref; str = vstr->data.string; vstr->data.string = 0; POP(2); trigger(UID,xit,0,str,""); free(str); }