dmuck0.15-beta/docs/muf/
dmuck0.15-beta/game/
dmuck0.15-beta/game/logs/
dmuck0.15-beta/game/muf/
dmuck0.15-beta/game/muf/text/
#include "prims.h"
#include "db.h"
#include "money.h"

/* private globals */
extern inst *p_oper1, *p_oper2, *p_oper3, *p_oper4;
extern int p_result;
extern int p_nargs;
extern dbref p_ref;
char buffer[500];

#ifdef COPYOBJ
/****************************************
 * copyobj ( d -- d ) - copy an object
 ****************************************/
void prims_copyobj (__P_PROTO)
{
  dbref newobj;
  if (!Builder(fr->euid) && !fr->wizard && !(FLAGS(program) & BUILDER))
    abort_interp ("You're not a builder.");
  CHECKOP(1);
  p_oper1 = POP();
  if (!valid_object(p_oper1)) abort_interp("Invalid object.");
  p_ref = p_oper1->data.objref;
  if (Typeof(p_ref) != TYPE_THING) abort_interp("Invalid object type.");
  if (!fr->wizard)
  {
      if (!payfor(fr->euid, OBJECT_DEPOSIT(DBFETCH(p_ref)->pennies)))
        sprintf(buffer, "You don't have enough %s.", PL_MONEY);
        abort_interp(buffer);   /* defined in money.h */  
  }
   
  newobj = new_object();
  *DBFETCH(newobj)= *DBFETCH(p_ref);
  DBSTORE(newobj, desc, dup_string(GET_DESC(p_ref)));
  DBSTORE(newobj, name, dup_string(NAME(p_ref)));
  DBSTORE(newobj, succ, dup_string(GET_SUCC(p_ref)));
  DBSTORE(newobj, fail, dup_string(GET_FAIL(p_ref)));
  DBSTORE(newobj, drop, dup_string(GET_DROP(p_ref)));
  DBSTORE(newobj, osucc, dup_string(GET_OSUCC(p_ref)));
  DBSTORE(newobj, ofail, dup_string(GET_OFAIL(p_ref)));
  DBSTORE(newobj, odrop, dup_string(GET_ODROP(p_ref)));
  copy_prop(p_ref, newobj, access_rights(player, p_ref, program));
  DBSTORE(newobj, key, copy_bool(DBFETCH(p_ref)->key));
  add_backlocks_parse(newobj, DBFETCH(newobj)->key);
  DBSTORE(newobj, exits, NOTHING);

  add_ownerlist(newobj);
  add_backlinks(newobj);

  moveto(newobj, fr->euid);
  DBDIRTY(newobj);

  CLEAR(p_oper1);
  push(arg, top, PROG_OBJECT, MIPSCAST &newobj);
}
#endif /* COPYOBJ */

int prims_recycle_checkcallers (dbref_list *drl, dbref object)
{
  for (;drl;drl = drl->next)
  {
    if (drl->object == object) return 1;
  }
  return 0;
}

/****************************************
 * recycle ( d -- ) recycles an object
 ****************************************/
void prims_recycle (__P_PROTO)
{
  CHECKOP(1);
  p_oper1 = POP();
  if (!valid_object(p_oper1)) abort_interp("Invalid arguement.");
  if (OWNER(p_oper1->data.objref) != fr->euid)
    abort_interp("Permission denied.");

  p_ref = p_oper1->data.objref;

  if (Typeof(p_ref) == program) abort_interp("Can't recycle this program.");
  if (prims_recycle_checkcallers (fr->caller, p_ref))
    abort_interp("Can't recycle a caller.");

  switch (Typeof(p_ref))
  {
    case TYPE_ROOM:
      if (p_ref == PLAYER_START || p_ref == GLOBAL_ENVIRONMENT)
        abort_interp("Can't recycle that room.");
      break;
    case TYPE_PLAYER: abort_interp("Can't recycle players.");
    case TYPE_GARBAGE: abort_interp("Can't recycle garbage.");
  }
  recycle (player, p_ref);

  CLEAR(p_oper1);
}

/*NEEDS REWRITING!*/
void prims_kill (__P_PROTO)
{
  CHECKOP(1);
  p_oper1 = POP();
  if (!p_oper1->type != PROG_INTEGER) abort_interp("Invalid arguement.");
  CLEAR(p_oper1);
}

/****************************************
 * create ( s i -- d ) - create a new THING
 ****************************************/
void prims_create (__P_PROTO)
{
  if (!Builder(fr->euid) && !fr->wizard && !(FLAGS(program) & BUILDER))
    abort_interp ("You're not a builder.");

  CHECKOP(2);
  p_oper2 = POP();
  p_oper1 = POP();

  if (p_oper1->type != PROG_STRING) abort_interp("Non-string arguement. (1)");
  if (p_oper2->type != PROG_INTEGER) abort_interp("Non-integer arguement. (2)");

  if ((*(p_oper1->data.string) == '\0') ||
    !ok_name(p_oper1->data.string))
    abort_interp ("That's a silly name for an object!");

  p_result = (p_oper2->data.number < OBJECT_COST) ?
    OBJECT_COST :
    p_oper2->data.number;

  if (!fr->wizard && !payfor(fr->euid, p_result)) {
     sprintf(buffer, "Not enough %s", PL_MONEY);
     abort_interp(buffer);   /* defined in money.h */  
  }

  p_ref = new_object ();

  DBSTORE(p_ref, flags, TYPE_THING);
  DBSTORE(p_ref, name, dup_string(p_oper1->data.string));
  DBSTORE(p_ref, location, fr->euid);
  DBSTORE(p_ref, owner, OWNER(fr->euid));
  add_ownerlist(p_ref);
  DBSTORE(p_ref, link, fr->euid);
  add_backlinks(p_ref);
  DBSTORE(p_ref, pennies,
    (OBJECT_ENDOWMENT(p_result) > MAX_OBJECT_ENDOWMENT) ?
    MAX_OBJECT_ENDOWMENT :
    OBJECT_ENDOWMENT(p_result));
  DBSTORE(p_ref, exits, NOTHING);

  PUSH(p_ref, DBFETCH(fr->euid)->contents);
  DBDIRTY(p_ref);
  DBDIRTY(fr->euid);

  CLEAR(p_oper1);
  CLEAR(p_oper2);
  push(arg, top, PROG_OBJECT, MIPSCAST &p_ref);
}

/****************************************
 * dig ( s d -- d d ) - creates a new ROOM
 ****************************************/
void prims_dig (__P_PROTO)
{
  dbref parent;
  if (!Builder(fr->euid) && !fr->wizard && !(FLAGS(program) & BUILDER))
    abort_interp ("You're not a builder.");
  CHECKOP(2);
  p_oper2 = POP();
  p_oper1 = POP();

  if (p_oper1->type != PROG_STRING) abort_interp("Non-string argument. (1)");
  if (p_oper2->type != PROG_OBJECT) abort_interp("Non-object arguement. (2)");
  if (p_oper2->data.objref == NOTHING)
    p_oper2->data.objref = DBFETCH(DBFETCH(fr->euid)->location)->location;
  if (p_oper2->data.objref == NOTHING)
    p_oper2->data.objref = DBFETCH(fr->euid)->location;

  if (!valid_object(p_oper2)) abort_interp("Invalid object. (2)");

  parent = p_oper2->data.objref;
  if (Typeof(parent) != TYPE_ROOM) abort_interp ("Parent not a room.");
  if (!can_link_to(fr->euid, TYPE_ROOM, parent)) parent = GLOBAL_ENVIRONMENT;
  if ((*(p_oper1->data.string) == '\0') ||
    !ok_name(p_oper1->data.string))
    abort_interp ("That's a silly name for a room!");
  if (!fr->wizard && !payfor(fr->euid, ROOM_COST)) {
     sprintf(buffer, "Not enough %s", PL_MONEY);
     abort_interp(buffer);   /* defined in money.h */  
   }

  p_ref = new_object();
  FLAGS(p_ref) = TYPE_ROOM | (FLAGS(fr->euid) & JUMP_OK);
  DBSTORE(p_ref, name, dup_string(p_oper1->data.string));
  DBSTORE(p_ref, location, parent);
  DBSTORE(p_ref, owner, OWNER(fr->euid));
  add_ownerlist(p_ref);
  DBSTORE(p_ref, exits, NOTHING);
  DBSTORE(p_ref, link, NOTHING);
  PUSH(p_ref, DBFETCH(parent)->contents);
  DBDIRTY(p_ref);
  DBDIRTY(parent);

  CLEAR(p_oper1);
  CLEAR(p_oper2);
  push(arg, top, PROG_OBJECT, MIPSCAST &p_ref);
  push(arg, top, PROG_OBJECT, MIPSCAST &parent);
}

/****************************************
 * open ( s d -- d d ) - creates a new EXIT
 ****************************************/
void prims_open (__P_PROTO)
{
  if (!Builder(fr->euid) && !fr->wizard && !(FLAGS(program) & BUILDER))
    abort_interp ("You're not a builder.");

  CHECKOP(2);
  p_oper2 = POP();
  p_oper1 = POP();
  if (!valid_object(p_oper2)) abort_interp("Invalid object. (2)");
  if (p_oper1->type != PROG_STRING) abort_interp("Non-string argument. (1)");
  if (!ok_name(p_oper1->data.string)) abort_interp ("Illegal exit name.");
  if (!fr->wizard && (fr->euid != OWNER(p_oper2->data.objref)))
    abort_interp ("Permission denied.");
  if (!fr->wizard && !payfor(fr->euid, EXIT_COST)) {
     sprintf(buffer, "Not enough %s", PL_MONEY);
     abort_interp(buffer);   /* defined in money.h */  
   }

  p_ref = new_object ();
  DBSTORE(p_ref, name, dup_string(p_oper1->data.string));
  DBSTORE(p_ref, location, NOTHING);
  DBSTORE(p_ref, sp.exit.ndest, 0);
  DBSTORE(p_ref, sp.exit.dest, NULL);
  DBSTORE(p_ref, owner, OWNER(fr->euid));
  add_ownerlist(p_ref);
  FLAGS(p_ref) = TYPE_EXIT;
  moveto(p_ref, p_oper2->data.objref);
  DBDIRTY(p_ref);

  CLEAR(p_oper1);
  CLEAR(p_oper2);
  push(arg, top, PROG_OBJECT, MIPSCAST &p_ref);
}

/****************************************
 * unlink ( d -- ) unlinks an EXIT
 ****************************************/
void prims_unlink (__P_PROTO)
{
  if (!Builder(fr->euid) && !fr->wizard && !(FLAGS(program) & BUILDER))
    abort_interp ("You're not a builder.");
  CHECKOP(1);
  p_oper1 = POP();

  if (!valid_object(p_oper1)) abort_interp("Invalid object.");
  p_ref = p_oper1->data.objref;
  if (!fr->wizard && (fr->euid != OWNER(p_ref)))
    abort_interp("Permission denied.");

  switch (Typeof(p_ref))
  {
    case TYPE_EXIT:
      remove_backlinks(p_ref);
      if(DBFETCH(p_ref)->sp.exit.ndest != 0)
      {
        if (!fr->wizard)
          DBFETCH(OWNER(p_ref))->pennies += LINK_COST;
        DBDIRTY(OWNER(p_ref));
      }
      DBSTORE(p_ref, sp.exit.ndest, 0);
      if (DBFETCH(p_ref)->sp.exit.dest)
      {
        free ((void *)DBFETCH(p_ref)->sp.exit.dest);
        DBSTORE(p_ref, sp.exit.dest, NULL);
      }
      break;
    case TYPE_ROOM:
      remove_backlinks(p_ref);
      DBSTORE(p_ref, link, NOTHING);
      break;
    default:
      abort_interp("Invalid object type");
  }
  CLEAR(p_oper1);
}

/** addlink_check -> checks to make sure there isn't already a link to
    something other than an exit **/
int prims_addlink_check (dbref exit)
{
  int i;
  for (i = 0; i < DBFETCH(exit)->sp.exit.ndest; i++)
  {
    switch (Typeof(DBFETCH(exit)->sp.exit.dest[i]))
    {
      case TYPE_PLAYER:
      case TYPE_ROOM:
      case TYPE_PROGRAM:
      return 1;
    }
  }
  return 0;
}

/** addlink_sub -> checks to see if a link is valid, and links it **/
int prims_addlink_sub (frame *fr, dbref exit, dbref destination)
{
#ifndef TELEPORT_TO_PLAYER
  if (Typeof(destination) == TYPE_PLAYER)
    return 0;
#endif /* TELEPORT_TO_PLAYER */
  if (DBFETCH(exit)->sp.exit.ndest == MAX_LINKS) return 0;
  if (!can_link(fr->euid, exit)) return 0;
  if (!can_link_to(fr->euid, TYPE_EXIT, destination)) return 0;
  switch (Typeof(destination))
  {
    case TYPE_PLAYER:
    case TYPE_ROOM:
    case TYPE_PROGRAM:
      if (prims_addlink_check(exit)) return 0;
      break;
    case TYPE_EXIT:
      if (exit_loop_check(exit, destination)) return 0;
  }

  /* chown it if it isna' linked to anything */
  if (!DBFETCH(exit)->sp.exit.ndest) db_chown(exit, fr->player);

  /* increment the # of destinations */
  DBSTORE(exit, sp.exit.ndest, DBFETCH(exit)->sp.exit.ndest + 1);

  /* realloc if there's more than one dest, malloc new memory if there is
   * no previos destinations.
   */
  if (DBFETCH(exit)->sp.exit.ndest > 1)
  { DBSTORE(exit, sp.exit.dest, (dbref *)realloc(DBFETCH(exit)->sp.exit.dest,
        sizeof(dbref) * DBFETCH(exit)->sp.exit.ndest));
  } else 
    DBSTORE(exit, sp.exit.dest, (dbref *)malloc(sizeof(dbref)));

  /* shove the dest in the array. */
  DBSTORE(exit, sp.exit.dest[DBFETCH(exit)->sp.exit.ndest - 1], destination);
  return 1;
}

/****************************************
 * addlink ( d d -- ) - adds a link to an OBJECT
 ****************************************/
void prims_addlink (__P_PROTO)
{
  if (!Builder(fr->euid) && !fr->wizard && !(FLAGS(program) & BUILDER))
    abort_interp ("You're not a builder.");
  CHECKOP(2);
  p_oper2 = POP();
  p_oper1 = POP();
  if (!valid_object(p_oper1)) abort_interp("Invalid object. (1)");
  if (!valid_object(p_oper2)) abort_interp("Invalid object. (2)");

  switch (Typeof(p_oper1->data.objref))
  {
    case TYPE_EXIT:
      if (fr->euid != OWNER(p_oper1->data.objref))
        abort_interp("Permission denied.");

      remove_backlinks(p_oper1->data.objref);
      if (!prims_addlink_sub (fr, p_oper1->data.objref, p_oper2->data.objref))
        abort_interp ("Can't link.");
      add_backlinks(p_oper1->data.objref);
      break;
    case TYPE_PLAYER:
    case TYPE_THING:
    case TYPE_PROGRAM:
    case TYPE_ROOM:
      if (!controls(fr->euid, p_oper1->data.objref) ||
        !can_link_to(fr->euid, Typeof(p_oper1->data.objref),
	  p_oper2->data.objref))
        abort_interp("Permission denied.");
      remove_backlinks(p_oper1->data.objref);
      DBSTORE(p_oper1->data.objref, link, p_oper2->data.objref);
      add_backlinks(p_oper1->data.objref);
  }

  CLEAR(p_oper1);
  CLEAR(p_oper2);
}