tmuck2.4/
tmuck2.4/admin/scripts/
tmuck2.4/docs/
tmuck2.4/minimal-db/
tmuck2.4/minimal-db/data/
tmuck2.4/minimal-db/logs/
tmuck2.4/minimal-db/muf/
tmuck2.4/old/
tmuck2.4/src/
tmuck2.4/src/compile/
tmuck2.4/src/editor/
tmuck2.4/src/game/
tmuck2.4/src/interface/
tmuck2.4/src/scripts/
tmuck2.4/src/utilprogs/
/* Copyright (c) 1992 by David Moore.  All rights reserved. */
/* db_prims.c,v 2.11 1997/08/30 06:44:02 dmoore Exp */
#include "config.h"

#include <string.h>

#include "db.h"
#include "code.h"
#include "prim_offsets.h"
#include "buffer.h"
#include "externs.h"

#define SSText(x)	((x)->un.string ? (x)->un.string->data : "")

#define GET_STR_PRIM(NAME, OP) \
    MUF_PRIM(prim_##NAME) \
    { inst obj, result; \
      const char *str; \
      pop_stack(curr_data_st, &obj); \
      str = Get##OP(obj.un.object); \
      result.type = INST_STRING; \
      if (str) result.un.string = make_shared_string(str, strlen(str)); \
      else result.un.string = NULL; \
      push_stack(curr_data_st, &result); }

GET_STR_PRIM(name, Name)
GET_STR_PRIM(desc, Desc)
GET_STR_PRIM(succ, Succ)	
GET_STR_PRIM(fail, Fail)	
GET_STR_PRIM(drop, Drop)
GET_STR_PRIM(osucc, OSucc)	
GET_STR_PRIM(ofail, OFail)	
GET_STR_PRIM(odrop, ODrop)	


#define SET_STR_PRIM(NAME, OP) \
    MUF_PRIM(prim_set##NAME) \
    { inst obj, value; \
      pop_stack(curr_data_st, &value); pop_stack(curr_data_st, &obj); \
      Set##OP(obj.un.object, SSText(&value)); }

SET_STR_PRIM(desc, Desc)
SET_STR_PRIM(succ, Succ)
SET_STR_PRIM(fail, Fail)
SET_STR_PRIM(drop, Drop)
SET_STR_PRIM(osucc, OSucc)
SET_STR_PRIM(ofail, OFail)
SET_STR_PRIM(odrop, ODrop)

MUF_PRIM(prim_setname)
{
    inst obj, value;

    pop_stack(curr_data_st, &value);
    pop_stack(curr_data_st, &obj);

    if (!ok_name(SSText(&value))) {
	interp_error(curr_frame, PRIM_setname, "Invalid name");
	return;
    }

    if (Typeof(obj.un.object) == TYPE_PLAYER) {
	interp_error(curr_frame, PRIM_setname, "Can't set a player's name");
	return;
    }

    SetName(obj.un.object, SSText(&value));
}


#define GET_DBREF_PRIM(NAME, OP) \
    MUF_PRIM(prim_##NAME) \
    { inst obj, result; \
      pop_stack(curr_data_st, &obj); \
      result.type = INST_OBJECT; result.un.object = Get##OP(obj.un.object); \
      push_stack(curr_data_st, &result); }

GET_DBREF_PRIM(contents, Contents)
GET_DBREF_PRIM(exits, Actions)
GET_DBREF_PRIM(getlink, Link)
GET_DBREF_PRIM(loc, Loc)
GET_DBREF_PRIM(next, Next)
GET_DBREF_PRIM(owner, Owner)


#define GET_INT_PRIM(NAME, OP) \
    MUF_PRIM(prim_##NAME) \
    { inst obj, result; \
      pop_stack(curr_data_st, &obj); \
      result.type = INST_INTEGER; result.un.integer = (OP(obj.un.object)); \
      push_stack(curr_data_st, &result); }

GET_INT_PRIM(pennies, GetPennies)
GET_INT_PRIM(exitp, TYPE_EXIT == Typeof)
GET_INT_PRIM(playerp, TYPE_PLAYER == Typeof)
GET_INT_PRIM(progp, TYPE_PROGRAM == Typeof)
GET_INT_PRIM(roomp, TYPE_ROOM == Typeof)
GET_INT_PRIM(thingp, TYPE_THING == Typeof)


MUF_PRIM(prim_okp)
{
    inst arg;
    inst result;

    pop_stack(curr_data_st, &arg);
    
    result.type = INST_INTEGER;
    result.un.integer = ((arg.type == INST_OBJECT) && !Garbage(arg.un.object));

    push_stack(curr_data_st, &result);
}


MUF_PRIM(prim_dbcmp)
{
    inst obj1, obj2;
    inst result;

    pop_stack(curr_data_st, &obj2);
    pop_stack(curr_data_st, &obj1);

    result.type = INST_INTEGER;
    result.un.integer = (obj1.un.object == obj2.un.object);

    push_stack(curr_data_st, &result);
}


MUF_PRIM(prim_dbtop)
{
    inst result;

    result.type = INST_OBJECT;
    result.un.object = db_top;

    push_stack(curr_data_st, &result);
}


static const char *check_moveto(const dbref thing, const dbref dest, const dbref player, const int wizzed)
{
    /* Get rid of this once you can moveto exits around. */
    if (Typeof(thing) == TYPE_EXIT)
	return "Object is an exit";

    if (!moveto_type_ok(thing, dest))
	return "Bad destination";

    if (!moveto_source_ok(thing, dest, player, wizzed))
	return "Permission denied on source";

    if (!moveto_thing_ok(thing, dest, player, wizzed))
	return "Permission denied on object";

    if (!moveto_dest_ok(thing, dest, player, wizzed))
	return "Permission denied on destination";

    if (!moveto_loop_ok(thing, dest))
	return "Destination would cause loop";

    return NULL;
}


MUF_PRIM(prim_check_moveto)
{
    inst arg1, arg2;
    inst result;
    dbref thing, dest;
    const char *error;

    pop_stack(curr_data_st, &arg2);
    pop_stack(curr_data_st, &arg1);

    thing = arg1.un.object;
    dest = arg2.un.object;

    if (dest == HOME) dest = GetHome(thing);
    
    error = check_moveto(thing, dest,
			 frame_euid(curr_frame), frame_wizzed(curr_frame));
    result.type = INST_STRING;
    result.un.string = make_shared_string(error, error ? strlen(error) : 0);

    push_stack(curr_data_st, &result);
}


MUF_PRIM(prim_moveto)
{
    inst arg1, arg2;
    dbref thing, dest;
    const char *error;

    pop_stack(curr_data_st, &arg2);
    pop_stack(curr_data_st, &arg1);

    thing = arg1.un.object;
    dest = arg2.un.object;

    if (dest == HOME) dest = GetHome(thing);
    
    error = check_moveto(thing, dest,
			 frame_euid(curr_frame), frame_wizzed(curr_frame));
    if (error) {
	interp_error(curr_frame, PRIM_moveto, error);
	return;
    }

    move_object(thing, dest, NOTHING);
}


MUF_PRIM(prim_addpennies)
{
    inst what, amount;
    int result, wizzed;

    pop_stack(curr_data_st, &amount);
    pop_stack(curr_data_st, &what);
    
    result = GetPennies(what.un.object) + amount.un.integer;

    wizzed = frame_wizzed(curr_frame);
    
    switch (Typeof(what.un.object)) {
    case TYPE_PLAYER:
	if ((result > MAX_PENNIES)
	    && (amount.un.integer > 0)
	    && !wizzed) {
	    interp_error(curr_frame, PRIM_addpennies,
			 "%i exceeds MAX_PENNIES", result);
	}
	if ((result < 0) && !wizzed) {
	    interp_error(curr_frame, PRIM_addpennies,
			 "%i is negative", result);
	}
	break;
    case TYPE_THING:
	if (!wizzed) {
	    interp_error(curr_frame, PRIM_addpennies,
			 "Only wizards can give pennies to objects");
	}
	break;
    default:
	interp_error(curr_frame, PRIM_addpennies, "Invalid object type");
	break;
    }
	    
    if (!curr_frame->error)
	SetPennies(what.un.object, result);
}


static dbref copyobj(const dbref player, const dbref old)
{
    dbref new;

    new = make_object(TYPE_THING, GetName(old), GetOwner(old),
		      player, GetLink(old));

    SetOnFlag(new, GetFlags(old));
    SetKey(new, copy_bool(GetKey(old)));
    copy_props(old, new);
    SetActions(new, NOTHING);
    move_object(new, player, NOTHING);

    return new;
}


MUF_PRIM(prim_copyobj)
{
    inst arg;
    inst result;

    pop_stack(curr_data_st, &arg);

    if (curr_frame->max_create == 0) {
	interp_error(curr_frame, PRIM_copyobj, "Can't create anymore objects");
	return;
    }

    if (Typeof(arg.un.object) != TYPE_THING) {
	interp_error(curr_frame, PRIM_copyobj, "Can't copy that object type");
	return;
    }

    curr_frame->max_create--;

    result.type = INST_OBJECT;
    result.un.object = copyobj(curr_frame->player, arg.un.object);

    push_stack(curr_data_st, &result);
}


static void check_prop_perms(frame *fr, const dbref object, const char *name, const int check_write, const int prim)
{
    if ((*name == PROP_PRIVATE) || (check_write && *name == PROP_RDONLY))
	check_perms(fr, object, prim);
    if (strchr(name, ':'))
	interp_error(fr, prim, "Can't use ':' in property name");
}


#define TRY_INTERN_PROPS(NAME) \
    MUF_PRIM(prim_##NAME##_i) { prim_##NAME(); }

TRY_INTERN_PROPS(getpropv)
TRY_INTERN_PROPS(getprops)
TRY_INTERN_PROPS(getpropd)
TRY_INTERN_PROPS(rmvprop)
TRY_INTERN_PROPS(addprop)
TRY_INTERN_PROPS(setprop)
TRY_INTERN_PROPS(flagp)


MUF_PRIM(prim_addprop)
{
    inst obj, name, str, val;

    pop_stack(curr_data_st, &val);
    pop_stack(curr_data_st, &str);
    pop_stack(curr_data_st, &name);
    pop_stack(curr_data_st, &obj);

    check_prop_perms(curr_frame, obj.un.object, SSText(&name), 1,
		     PRIM_addprop);
    if (curr_frame->error) return;

    add_property(obj.un.object, SSText(&name), SSText(&str), val.un.integer);
}


MUF_PRIM(prim_setprop)
{
    inst obj, name, what;

    pop_stack(curr_data_st, &what);
    pop_stack(curr_data_st, &name);
    pop_stack(curr_data_st, &obj);

    check_prop_perms(curr_frame, obj.un.object, SSText(&name), 1,
		     PRIM_setprop);
    if (curr_frame->error) return;

    switch (what.type) {
    case INST_STRING:
	add_string_prop(obj.un.object, SSText(&name),
			SSText(&what), NORMAL_PROP, PERM_PROP);
	break;
    case INST_INTEGER:
	add_int_prop(obj.un.object, SSText(&name),
		     what.un.integer, NORMAL_PROP, PERM_PROP);
	break;
    case INST_OBJECT:
	add_dbref_prop(obj.un.object, SSText(&name),
		       what.un.object, NORMAL_PROP, PERM_PROP);
	break;
    default:
	interp_error(curr_frame, PRIM_setprop,
		     "Illegal type to put in property");
	break;
    }
}


MUF_PRIM(prim_getprops)
{
    inst obj, name;
    inst result;
    const char *str;

    pop_stack(curr_data_st, &name);
    pop_stack(curr_data_st, &obj);

    check_prop_perms(curr_frame, obj.un.object, SSText(&name), 0,
		     PRIM_getprops);
    if (curr_frame->error) return;

    str = get_string_prop(obj.un.object, SSText(&name), NORMAL_PROP);

    result.type = INST_STRING;
    if (str) {
        result.un.string = make_shared_string(str, strlen(str));
    } else {
        result.un.string = NULL;
    }

    push_stack(curr_data_st, &result);
}


MUF_PRIM(prim_getpropv)
{
    inst obj, name;
    inst result;

    pop_stack(curr_data_st, &name);
    pop_stack(curr_data_st, &obj);

    check_prop_perms(curr_frame, obj.un.object, SSText(&name), 0,
		     PRIM_getpropv);
    if (curr_frame->error) return;

    result.type = INST_INTEGER;
    result.un.integer = get_int_prop(obj.un.object, SSText(&name),
				     NORMAL_PROP);

    push_stack(curr_data_st, &result);
}


MUF_PRIM(prim_getpropd)
{
    inst obj, name;
    inst result;

    pop_stack(curr_data_st, &name);
    pop_stack(curr_data_st, &obj);

    check_prop_perms(curr_frame, obj.un.object, SSText(&name), 0,
		     PRIM_getpropd);
    if (curr_frame->error) return;

    result.type = INST_OBJECT;
    result.un.object = get_dbref_prop(obj.un.object, SSText(&name),
				      NORMAL_PROP);

    push_stack(curr_data_st, &result);
}


MUF_PRIM(prim_rmvprop)
{
    inst obj, name;

    pop_stack(curr_data_st, &name);
    pop_stack(curr_data_st, &obj);

    check_prop_perms(curr_frame, obj.un.object, SSText(&name), 1,
		     PRIM_rmvprop);
    if (curr_frame->error) return;

    remove_prop(obj.un.object, SSText(&name), NORMAL_PROP);
}


MUF_PRIM(prim_match)
{
    inst str;
    inst result;
    struct match_data md;

    pop_stack(curr_data_st, &str);

    init_match(curr_frame->player, SSText(&str), NOTYPE, &md);
    match_home(&md);
    match_everything(&md,
		     (Wizard(curr_frame->player) || frame_wizzed(curr_frame)));

    result.type = INST_OBJECT;
    result.un.object = match_result(&md);

    push_stack(curr_data_st, &result);
}


MUF_PRIM(prim_rmatch)
{
    inst obj, str;
    inst result;
    struct match_data md;

    pop_stack(curr_data_st, &str);
    pop_stack(curr_data_st, &obj);

    if ((Typeof(obj.un.object) == TYPE_PROGRAM)
	|| (Typeof(obj.un.object) == TYPE_EXIT)) {
	interp_error(curr_frame, PRIM_rmatch,
		     "Requires ROOM, PLAYER, or THING");
	return;
    }

    init_match(curr_frame->player, SSText(&str), TYPE_THING, &md);
    match_rmatch(obj.un.object, &md);

    result.type = INST_OBJECT;
    result.un.object = match_result(&md);

    push_stack(curr_data_st, &result);
}


MUF_PRIM(prim_flagp)
{
    inst obj, flagname;
    inst result;
    object_flag_type flag;

    pop_stack(curr_data_st, &flagname);
    pop_stack(curr_data_st, &obj);
    
    flag = which_flag(Typeof(obj.un.object), SSText(&flagname));

    result.type = INST_INTEGER;
    if (flag != BAD_FLAG) {
	result.un.integer = HasFlag(obj.un.object, flag);
    } else {
	result.un.integer = 0;
    }

    if (flag == WIZARD)
	result.un.integer = Wizard(obj.un.object); /* Quell hides in muf. */

#ifdef GOD_FLAGS
    if (flag == GOD)
	result.un.integer = God(obj.un.object); /* Quell hides in muf. */
#endif

    push_stack(curr_data_st, &result);
}


MUF_PRIM(prim_set)
{
    inst obj, which;
    const char *flagname;
    int bang = 0;
    object_flag_type flag;

    pop_stack(curr_data_st, &which);
    pop_stack(curr_data_st, &obj);

    flagname = SSText(&which);

    if (*flagname == '!') {
	bang = 1;
	flagname++;
    }
    
    flag = which_flag(Typeof(obj.un.object), flagname);

    if (flag == BAD_FLAG) {
	interp_error(curr_frame, PRIM_set, "Unrecognized flag (%s)", flagname);
	return;
    }

    if (restricted(frame_euid(curr_frame), obj.un.object, flag,
		   frame_wizzed(curr_frame), 0)) {
	interp_error(curr_frame, PRIM_set, "Permission denied");
	return;
    }

    if (restricted(frame_euid(curr_frame), obj.un.object, flag, 0, 0)) {
	log_status("FLAG SET: %s %s on %u by %u (prog #%d called from #%d).",
		   unparse_flag(obj.un.object, flag, 1),
		   (bang ? "reset" : "set"),
		   GetOwner(obj.un.object), obj.un.object,
		   curr_frame->player, curr_frame->player,
		   curr_frame->program, curr_frame->orig_program);
    }
    
    if (bang) {
	SetOffFlag(obj.un.object, flag);
    } else {
	SetOnFlag(obj.un.object, flag);
    }

    /* In case they set debugs/setuid, etc. */
    curr_frame->cache_dirty = 1;
}