/
roa/
roa/lib/boards/
roa/lib/config/
roa/lib/edits/
roa/lib/help/
roa/lib/misc/
roa/lib/plrobjs/
roa/lib/quests/
roa/lib/socials/
roa/lib/www/
roa/lib/www/LEDSign/
roa/lib/www/LEDSign/fonts/
roa/lib/www/LEDSign/scripts/
roa/src/s_inc/
roa/src/sclient/
roa/src/sclient/binary/
roa/src/sclient/text/
roa/src/util/
/************************************************************************
        Realms of Aurealis              James Rhone aka Vall of RoA

                RoA RoomProc code version 1.0 Beta

  roomproc.c    Realms of Aurealis RoomProc code, specifically written
                for RoA with OLCable RoomProcs in mind... note this is
                completely ORIGINAL code, as you can tell by its crude
                form. 

                ******** 100% completely original code ********
                *** BE AWARE OF ALL RIGHTS AND RESERVATIONS ***
                ******** 100% completely original code ********
                        All rights reserved henceforth.

    Please note that no guarantees are associated with any code from
Realms of Aurealis.  All code which has been released to the general
public has been done so with an 'as is' pretense.  RoA is based on both
Diku and CircleMUD and ALL licenses from both *MUST* be adhered to as well
as the RoA license.   *** Read, Learn, Understand, Improve ***
*************************************************************************/
#include "conf.h"
#include "sysdep.h"

#include "structures.h"
#include "utils.h"
#include "db.h"
#include "comm.h"
#include "interpreter.h"
#include "handler.h"
#include "magic.h"
#include "roomproc.h"
#include "acmd.h"
#include "quest.h"
#include "lists.h"
#include "htown.h"
#include "clicomm.h"
#include "fight.h"
#include "nature.h"
#include "global.h"

/* external vars */
extern int rev_dir[];
extern char *comm_dirs[];
extern char *genders[];
extern struct htown_data htowns[];

// external functions
extern struct rtrig_type *free_rtriggers(struct rtrig_type *head);
extern int check_room_affects(chdata *ch, int room);

// prototypes
int rproc_interpreter(rmdata *r, char *comm, chdata *ch, obdata *ob, BOOL reaction);

// local defines
#define MAX_ROOM_REACTIONS 10
#define MAX_ROOM_REACTION_LENGTH 1024

/* simple structure for corresponding roomproc calls... */
const struct rproc_type rproc_calls[] = {
  {"rreset",            do_rreset},
  {"rstart",            do_rstart},
  {"rend",              do_rend},
  {"rpause",            do_rpause},
  {"rgoto",             do_rgoto},
  {"rtrigwait",         do_rtrig_wait},
  {"rtrigoff",          do_rtrig_off},
  {"rtrigon",           do_rtrig_on},
  {"rtrigwax",          do_rtrig_wax},
  {"rtrigadd",          do_rtrig_add},
  {"rtrigdelete",       do_rtrig_delete},
  {"recho",             do_recho},
  {"rechochar",         do_rechochar},
  {"rsoundsendchar",    do_rsoundsendchar},
  {"rsoundsendroom",    do_rsoundsendroom},
  {"rrandom",           do_rrandom},
  {"rexittoggle",       do_rexittoggle},
  {"rexitopen",         do_rexitopen},
  {"rexitclose",        do_rexitclose},
  {"rexitlock",         do_rexitlock},
  {"rexitunlock",       do_rexitunlock},
  {"rexitsecret",       do_rexitsecret},
  {"rexitvisible",      do_rexitvisible},
  {"rexitlead",         do_rexitlead},
  {"rteleport",         do_rteleport},
  {"rtransmob",         do_rtransmob},
  {"rtransobj",         do_rtransobj},
  {"rsetremote",        do_rsetremote},
  {"runsetremote",      do_runsetremote},
  {"rtag",              do_rtag},
  {"rtargetroom",       do_rtarget},
  {"rtargetzone",       do_rtarget_zone},
  {"rtargetset",        do_rtarget_set},
  {"rif",               do_rif},
  {"", NULL} /* last one used for check of end of defines */
};

// what RIF checks are available?
char *rif_BOOLs[] = {
  "tarcharset",         "!tarcharset",
  "tarobjset",          "!tarobjset",
  "tarcharroom",        "!tarcharroom",
  "tarobjroom",         "!tarobjroom",
  "tarcharzone",        "!tarcharzone",
  "tarobjzone",         "!tarobjzone",
  "tarcharpc",          "!tarcharpc",
  "tarcharcompquest",   "!tarcharcompquest",
  "tarcharlevel",
  "npcinroom",          "!npcinroom",
  "objinroom",          "!objinroom",
  "transpresent",       "!transpresent",
  "tarcharonquest",     "!tarcharonquest",
  "tarcharrace",        "!tarcharrace",
  "tarcharclass",       "!tarcharclass",
  "tarchargender",      "!tarchargender",
  "\n"
};


// let imms shut off triggers while they work...
// 6/13/98 -jtrhone
ACMD(do_rpcom)
{
  char *argu = argument;

  if (IS_NPC(ch) || INVALID_ROOM(ch->in_room))
    return;

  skip_spaces(&argu);
  if (!*argu)
  {
    send_to_char("Usage: rpcom <reset | end>.\n\r",ch);
    return;
  }

  if (is_abbrev(argu, "reset"))
  {
    do_rreset(&world[ch->in_room], ""); 
    do_rtrig_on(&world[ch->in_room], ""); 
    return;
  }
  else
  if (is_abbrev(argu, "end"))
  {
    do_rend(&world[ch->in_room], ""); 
    do_rtrig_off(&world[ch->in_room], ""); 
    return;
  }
  else
  {
    send_to_char("Usage: rpcom <reset | end>.\n\r",ch);
    return;
  }
}

// for debugging rprocs... 6/6/98 -jtrhone
void    S2IMM(char *messg, rmdata *r)
{
  chdata *ch;
  char mesg[MAX_STRING_LENGTH -10];

  str_cpy(mesg, messg, MAX_STRING_LENGTH-10, "send_to_room_not_busy");
  str_cat(mesg, "\n\r", MAX_STRING_LENGTH-10, "send_to_room_not_busy");

  for (ch = r->people; ch; ch = ch->next_in_room)
   if (AWAKE(ch) && SEND_OK(ch) && IS_IMMORTAL(ch) && PLR_FLAGGED(ch, PLR_LOGALL))
    send_to_char(mesg, ch);
}

// let immortal see all roomproc commands available
ACMD(do_roomproc_show)
{
  int i,j;

  one_argument(argument, arg);

  if (is_abbrev(arg, "rcommands"))
  {
    strcpy(buf, "%B%6RoomProc Commands%0:\n\r");
    for (i=j=0; *rproc_calls[i].arg; i++)
    {
      sprintf(buf+strlen(buf), "%%5%%B%-19.19s%%0", rproc_calls[i].arg);
      if (!(++j % 4))
        strcat(buf, "\n\r");
    }
    if ((j%4))
      strcat(buf, "\n\r");
    page_string(ch->desc, buf, 1);
  }
  else
  if (is_abbrev(arg, "rifs"))
  {
    strcpy(buf, "%B%6RoomProc RIF Args%0:\n\r");
    for (i=j=0; *rif_BOOLs[i] != '\n'; i++)
    {
      sprintf(buf+strlen(buf), "%%5%%B%-19.19s%%0", rif_BOOLs[i]);
      if (!(++j % 4))
        strcat(buf, "\n\r");
    }
    if ((j%4))
      strcat(buf, "\n\r");
    page_string(ch->desc, buf, 1);
  }
  else
    send_to_char("Usage: rprocshow < rcommands | rifs >.\n\r",ch);
}

// pause a roomproc, 1 per 5 seconds for DTIME rooms
// 1 per 10 seconds for normal roomprocs
int do_rpause(rmdata *r, char *argument)
{
  int num = 0;

  one_argument(argument, arg);
  if (!is_number(arg)) 
    return RP_NORMAL;
  num = atoi(arg);
  num = MAX(0, MIN(num, 99));

  RPROC_WAIT(r) = num;
  sprintf(buf, "Rproc pausing %d.", num);
  S2IMM(buf, r);
  return RP_NORMAL;
}

/* simply start from where th proc last ended */
/* only if actually RENDED that is */
/* if no rproc_cur, then restart */
int do_rstart(rmdata *r, char *argument)
{
  if (RPROC_WAIT(r) >= 0)
    return RP_NORMAL;

  RPROC_WAIT(r) = 0;

  /* ok, begin processing of commands with this roomproc */
  if (!RPROC_CUR(r))  /* only jump to start if not pting to a comm */
    RPROC_CUR(r) = RPROC_BEG(r);

  S2IMM("Rproc started.", r);
  return RP_NORMAL;
}

/* wipes out all waits, sets cur back to beginning */
/* does it regardless if in a proc or not */
int do_rreset(rmdata *r, char *argument)
{
  RPROC_WAIT(r) = 0;
  RPROC_CUR(r) = RPROC_BEG(r);
  RTRIG_WAITING(r) = FALSE;
  S2IMM("Rproc reset.", r);
  return RP_NORMAL;
}

/* ends the processing of a roomproc, sets roomwait to -1 */
int do_rend(rmdata *r, char *argument)
{
  if (RPROC_WAIT(r) < 0)
    return RP_NORMAL; /* already ended */
  RPROC_WAIT(r) = -1;
  S2IMM("Rproc ended.", r);
  return RP_NORMAL;
}

// sets room waiting for a trigger to go off 6.5.98 -jtrhone
int do_rtrig_wait(rmdata *r, char *argument)
{
  if (RTRIG_WAITING(r))  // already awaiting trigger
    return RP_NORMAL;
  if (!RTRIGS(r))        // no trigs? aint gonna wait
    return RP_NORMAL;
  RTRIG_WAITING(r) = TRUE;
  S2IMM("Rproc waiting for trigs.", r);
  return RP_NORMAL;
}

// room will ignore triggers after this call
int do_rtrig_off(rmdata *r, char *argument)
{
  if (RTRIG_IGNORE(r))  // already ignoring triggers
    return RP_RTRIG;
  if (!RTRIGS(r))        // no trigs? aint gonna ignore
    return RP_RTRIG;
  RTRIG_IGNORE(r) = TRUE;
  S2IMM("Rproc ignoring trigs.", r);
  return RP_RTRIG;
}

// room will NOT ignore triggers after this call
int do_rtrig_on(rmdata *r, char *argument)
{
  if (!RTRIG_IGNORE(r))  // already listening to triggers
    return RP_RTRIG;
  if (!RTRIGS(r))        // no trigs? why bother
    return RP_RTRIG;
  RTRIG_IGNORE(r) = FALSE;
  S2IMM("Rproc no longer ignoring trigs.", r);
  return RP_RTRIG;
}

// add an rtrigger to rooms list of trigs -jtr
int add_rtrigger(rmdata *r, char *trigger, char *reaction)
{
  rtrig *rt = NULL;

  if (!trigger || !reaction)
  {
    sprintf(buf, "SYSERR: Missing trig or react to room #%d.", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_RTRIG;
  }

  // if adding existing trigger, replace reaction and return
  for (rt = RTRIGS(r); rt; rt=rt->next)
    if (!str_cmp(rt->trigger, trigger))
    {
      FREENULL(rt->reaction);
      rt->reaction = STR_DUP(reaction);
      S2IMM("Rproc replacing existing rtrig.", r);
      return RP_RTRIG;
    }

  // ok new one, create and insert to front
  CREATE(rt, rtrig, 1);
  rt->trigger = STR_DUP(trigger);
  rt->reaction = STR_DUP(reaction);
  rt->next = RTRIGS(r);
  RTRIGS(r) = rt;

  sprintf(buf, "Rproc added rtrig: %s\n\rWith reaction: %s", rt->trigger, rt->reaction);
  S2IMM(buf, r);
  return RP_RTRIG;
}

// rtrigadd utilizes blocks of commands
// rtrigadd <trigger> {block of reactions} adds rtrig_type to rooms trigs list
int do_rtrig_add(rmdata *r, char *trigger)
{
  char *pt; // our placeholder in the mproc list
  int i;
  char reaction[MAX_ROOM_REACTION_LENGTH];

  if (!trigger)
  {
    sprintf(buf, "SYSERR: #%d fatal roomproc error.  No trig to rtrigadd.", r->number);
    mudlog(buf, BUG, LEV_IMM, FALSE);
    do_rend(r, trigger);  // end roomproc
    return RP_RTRIG;
  }

  // must be a start block!
  pt = RPROC_CUR(r);
  skip_spaces(&pt);
  if (!pt || !*pt || *pt != '{')
  {
    sprintf(buf, "SYSERR: #%d fatal roomproc error.  No block after rtrigadd.", r->number);
    mudlog(buf, BUG, LEV_IMM, FALSE);
    do_rend(r, trigger);  // end roomproc
    return RP_RTRIG;
  }

  // yep, all the chars minus the two brackets
  i = chars_in_block(pt);

  if (i <= 0)
  {
    sprintf(buf, "SYSERR: #%d fatal roomproc error.  Reaction block empty.", r->number);
    mudlog(buf, BUG, LEV_IMM, FALSE);
    do_rend(r, trigger);  // end roomproc
    return RP_RTRIG;
  }

  if (i >= MAX_ROOM_REACTION_LENGTH - 2)
  {
    sprintf(buf, "SYSERR: #%d fatal roomproc error.  Reaction block too long.", r->number);
    mudlog(buf, BUG, LEV_IMM, FALSE);
    do_rend(r, trigger);  // end roomproc
    return RP_RTRIG;
  }

  strncpy(reaction, pt+1, i+1);  // add one for newline...
  reaction[i] = '\0';
  add_rtrigger(r, trigger, reaction);

  // OOOOkkk just skip the block...
  RPROC_CUR(r) = skip_block(pt);
  if (!RPROC_CUR(r) || !*RPROC_CUR(r))
    RPROC_CUR(r) = RPROC_BEG(r);

  return RP_RTRIG;
}

// remove an rtrigger from rooms list of trigs -jtr
int do_rtrig_delete(rmdata *r, char *trigger)
{
  rtrig *rt = NULL, *next_rt, *temp;

  if (!trigger)
  {
    sprintf(buf, "SYSERR: Missing trig to room #%d (remove_rtrig).", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_RTRIG;
  }

  if (!RTRIGS(r))
    return RP_RTRIG;

  for (rt = RTRIGS(r); rt; rt=next_rt)
  {
    next_rt = rt->next;
    if (!str_cmp(rt->trigger, trigger))
    {
      REMOVE_FROM_LIST(rt, RTRIGS(r), next);
      if (rt->trigger)
      {
        sprintf(buf, "Rproc removed rtrig: %s", rt->trigger);
        S2IMM(buf, r);
        free_log(rt->trigger, "do_rtrig_delete 1");
      }

      if (rt->reaction)
        free_log(rt->reaction, "do_rtrig_delete 2");

      free_log(rt, "do_rtrig_delete 3");
    }
  }
  return RP_RTRIG;
}

// wax entire trigger list by roomproc command
int do_rtrig_wax(rmdata *r, char *argument)
{
  if (!RTRIGS(r))
    return RP_RTRIG;
  RTRIGS(r) = free_rtriggers(RTRIGS(r));
  RTRIG_WAITING(r) = FALSE;    // cant be waiting if no list eh? -jtr
  S2IMM("Rproc waxed all rtriggers.",r);
  return RP_RTRIG;
}

// execute rproc_interpreter on reaction block with all EXCEPT
// some mtrig commands, and any block commands...
void perform_rtrig_reaction(rmdata *r, char *str, chdata *ch, obdata *ob)
{
  int i;
  char comm[MAX_ROOM_REACTION_LENGTH];
  char *tmp;

  if (!str || !*str) return;

  /* parse the string using * as pseudo EOL along with ISNEWL */
  for (tmp = str, i=0; tmp && *tmp; tmp++)
    if (*tmp && !ISNEWL(*tmp))
        comm[i++] = *tmp;
    else
    {
        comm[i] = '\0';
        if (*comm)
          rproc_interpreter(r, comm, ch, ob, TRUE);
        *comm = '\0';
        i = 0;
    }

  comm[i] = '\0';
  if (*comm)
    rproc_interpreter(r, comm, ch, ob, TRUE);
}

// is string a subset of this trigger
int in_rtrig(char *trigger, char *string)
{
  char *trig;
  int num, i;
  char comm[MAX_ROOM_REACTION_LENGTH];
  extern int match(char *str, char *str2);

  if (!string || !trigger || !*trigger || !*string ) return FALSE;
  else num = 1;

  for (trig = trigger; *trig; trig++)
    if (*trig == '\n' || *trig == '*')
      num++;   /* count the subcommands in string */

  if ((num > MAX_ROOM_REACTIONS) || (strlen(trig) > MAX_ROOM_REACTION_LENGTH))
  {
    sprintf(buf, "SYSUPD: rtrigger failed - %d trigs, length %d", num, strlen(trig));
    mudlog(buf, BUG, LEV_IMM, TRUE);
    return FALSE;
  }

  /* parse the trigger using * as pseudo EOL character */
  for (trig = trigger, i = 0; *trig; trig++)
    if (*trig && !ISNEWL(*trig) && *trig != '*')
    {
        comm[i] = *trig;
        i++;
    }
    else
    {
        comm[i] = '\0';
        if (*comm && *comm != '\n')
        {
          if (*comm == '#')  // the pound indicates a SUBSTRING match(strstr)
          {
            if (*(comm + 1) && match((comm + 1), string))
              return TRUE;
          }
          else
          if (!str_cmp(comm, string))
            return TRUE;
        }
        *comm = '\0';
        i = 0;
    }

  /* now last subtrigger check */
  comm[i] = '\0';
  if (*comm && *comm != '\n')
  {
    if (*comm == '#')  // the pound indicates a SUBSTRING match (strstr)
    {
        if (*(comm + 1) && match((comm + 1), string))
          return TRUE;
    }
    else
    if (!str_cmp(comm, string))
        return TRUE;
  }
  return FALSE;  /* we didnt find any matches */
}

/* does character's command trigger a rproc command? if so do it */
int check_rtrigs(chdata *ch, char *str)
{
  char tmp[MAX_INPUT_LENGTH];
  char *ptr;
  rtrig *rt;
  rmdata *r;

  if (INVALID_ROOM(ch->in_room))
    return FALSE;

  if (!ROOM_FLAGGED(ch->in_room, RPROC) || !str || !*str)
    return FALSE;  /* sorry pal, try again next time */

  r = &world[ch->in_room];

  // lower case entire string arg, cpy to temp buf first
  strcpy(tmp, str);
  for (ptr = tmp; *ptr; ptr++)
   if (isalpha(*ptr))
    *ptr = LOWER(*ptr);

  // rproc rtrigger list capabilities
  if (!RTRIG_IGNORE(r))
   for (rt = RTRIGS(r); rt; rt = rt->next)
    if (in_rtrig(rt->trigger, tmp))
    {
      // set new char target to the one who triggered us
      FREENULL(RTARGET_CHAR(r));
      RTARGET_CHAR(r) = STR_DUP(GET_NAME(ch));

      // now go perform the commands...
      perform_rtrig_reaction(r, rt->reaction, ch, NULL);

      RTRIG_WAITING(r) = FALSE;
      S2IMM("Rtrig reaction triggered.  Rtrigwait removed.", r);
      return TRUE;
    }

  return FALSE;
}

// echo a string to room... (not busy)
// add support for possible remotes  6/13/98 -jtrhone
int do_recho(rmdata *r, char *comm)
{
  char *arg = comm;
  rmdata *tr;

  skip_spaces(&arg);
  if (!*arg)
  {
    sprintf(buf, "SYSERR: No arg to recho, room #%d.", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }

  tr = REMOTE(r) ? REMOTE(r) : r;

  // else, send the argument...
  send_to_room_not_busy(arg, real_room(tr->number));
  return RP_NORMAL;
}

// rechochar <char name> <txt>
int do_rechochar(rmdata *r, char *comm)
{
  char arg1[MAX_INPUT_LENGTH];
  char arg2[MAX_INPUT_LENGTH];
  chdata *vict;
  rmdata *tr;

  half_chop(comm, arg1, arg2);
  if (!*arg1 || !*arg2)
  {
    sprintf(buf, "SYSERR: Invalid arguments sent to rechochar (#%d).", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }

  tr = REMOTE(r) ? REMOTE(r) : r;

  if (!(vict = get_char_room(arg1, real_room(tr->number))))
  {
    S2IMM("rechochar target not found...", r);
    return RP_NORMAL;
  }

  send_to_char(arg2, vict);
  send_to_char("\n\r", vict);
  return RP_NORMAL;
}


/* return the number of commands in a rooms rproc (for gotos) */
int rproc_length(rmdata *r)
{
  char *tmp;
  int count;

  if (!ROOM_FLAGGED(real_room(r->number), RPROC) || !*RPROC_BEG(r))
    return 0;

  for (count = 0, tmp = RPROC_BEG(r); *tmp; tmp++)
    if (*tmp == '\n') count++;

  return count;
}

// do nothing but set tag placeholder for rgotos
// 6/14/98 -jtrhone
int do_rtag(rmdata *r, char *argument)
{
  if (!*argument)
  {
    sprintf(buf, "SYSERR: Undefined rtag tag (#%d).",r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_RTAG;
  }

  return RP_RTAG;
}

// scan a rproc for rtag <tname>
char *get_rtag(char *proc, char *tname)
{
  char *str = proc;
  char arg1[MAX_STRING_LENGTH];
  char arg2[MAX_STRING_LENGTH];

  skip_spaces(&str);
  while (*str)
  {
    half_chop(str, arg1, arg2);
    if (!str_cmp(arg1, "rtag") && is_abbrev(tname, arg2))
      return str;

    str = scan_past_eol(str);
    skip_spaces(&str);
    if (!str || !*str)
      break;
  }

  return NULL;
}

// goto a particular line of the room proc
// updated for use with rtags 6/14/98 -jtrhone
int do_rgoto(rmdata *r, char *argument)
{
  int line, ctr;
  char *tmp;
  char arg1[MAX_INPUT_LENGTH];

  one_argument(argument, arg1);
  if (!*arg1)
  {
    sprintf(buf, "SYSERR:  Missing arg to rgoto (#%d).",r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }

  // lookin for rtag...
  if (!is_number(arg1))
  {
    tmp = get_rtag(RPROC_BEG(r), arg1);
    if (!tmp)
    {
      sprintf(buf, "SYSERR: Unable to locate rtag (%s) in rgoto (#%d).",arg1,r->number);
      mudlog(buf, BRF, LEV_IMM, FALSE);
      return RP_NORMAL;
    }    
   
    // juuuust to make sure
    if (tmp < RPROC_BEG(r))
    {
      sprintf(buf, "SYSERR: Lower bounds failure in rgoto (#%d).",r->number);
      mudlog(buf, BRF, LEV_IMM, FALSE);
      return RP_NORMAL;
    }

    RPROC_CUR(r) = tmp;
    sprintf(buf, "Rproc jumped to tag %s.",arg1);
    S2IMM(buf, r);
    return RP_NORMAL;
  }

  line = atoi(arg1);
  if (line > rproc_length(r) || line < 1)
  {
    sprintf(buf, "SYSERR: Invalid line # to rgoto (#%d)",r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }
 
  sprintf(buf, "Rproc jumped to line %d.",line);
  S2IMM(buf, r);

  if (line == 1)
  {
    RPROC_CUR(r) = RPROC_BEG(r);
    return RP_NORMAL;
  }

  tmp = RPROC_BEG(r);
  ctr = 1;
  while (ctr != line)
  {
    tmp = scan_past_eol(tmp);
    ctr++;
  }

  RPROC_CUR(r) = tmp;
  return RP_NORMAL;
}

// rsoundsendchar <char name> <soundfile name>
// char must have client connection
// add support for possible remotes  6/13/98 -jtrhone
int do_rsoundsendchar(rmdata *r, char *comm)
{
  char arg1[MAX_INPUT_LENGTH];
  char arg2[MAX_INPUT_LENGTH];
  chdata *vict;
  rmdata *tr;

  half_chop(comm, arg1, arg2);
  if (!*arg1 || !*arg2)
  {
    sprintf(buf, "SYSERR: Invalid arguments sent to rsoundsendchar (#%d).", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }

  tr = REMOTE(r) ? REMOTE(r) : r;

  if (!(vict = get_char_room(arg1, real_room(tr->number))))
  {
    S2IMM("rsoundsendchar target not found...", r);
    return RP_NORMAL;
  }

  if (IS_PC(vict) && vict->desc && HAS_CLIENT(vict->desc))
    send_soundfile_to_client(vict->desc, arg2);

  return RP_NORMAL;
}

// rsoundsendroom <soundfile name>
// chars in room must have client connection
// add support for possible remotes  6/13/98 -jtrhone
int do_rsoundsendroom(rmdata *r, char *comm)
{
  char arg1[MAX_INPUT_LENGTH];
  chdata *vict;
  rmdata *tr;

  one_argument(comm, arg1);
  if (!*arg1)
  {
    sprintf(buf, "SYSERR: Invalid arguments sent to rsoundsendroom (#%d).", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }

  tr = REMOTE(r) ? REMOTE(r) : r;

  for (vict = tr->people; vict; vict=vict->next_in_room)
    if (IS_PC(vict) && vict->desc && HAS_CLIENT(vict->desc))
      send_soundfile_to_client(vict->desc, arg1);

  return RP_NORMAL;
}

// rrandom followed by a block of randoms, chooses one and does command
// BLOCK COMMAND, not to be used in other block commands...
int do_rrandom(rmdata *r, char *argument)
{
  char *pt; // our placeholder in the mproc list
  char *tmp, *tmp2;
  int count = 0, pick, i;
  char comm[MAX_INPUT_LENGTH];

  // must be a start block!
  pt = RPROC_CUR(r);
  skip_spaces(&pt);
  if (!pt || !*pt || *pt != '{')
  {
    sprintf(buf, "SYSERR: Room #%d fatal rproc error.  No block after rrandom.", r->number);
    mudlog(buf, BUG, LEV_IMM, FALSE);
    do_rend(r, argument);  // end rproc
  }

  // now count commands in the block
  for (tmp = pt, count = 0; *tmp && *tmp != '}'; tmp++)
  {
    tmp = scan_past_eol(tmp);
    skip_spaces(&tmp);
    if (!tmp || !*tmp || *tmp == '}')
      break;
    else
      count++;
  }

  if (!tmp || !*tmp)
  {
    sprintf(buf, "SYSERR: Room #%d fatal rproc error.  Rrandom blk never ended.", r->number);
    mudlog(buf, BUG, LEV_IMM, FALSE);
    do_rend(r, argument);  // end rproc
  }

  // skip past closing bracket
  tmp = scan_past_eol(tmp);  // this is where we wanna point after we done

  if (!count)
  {
    sprintf(buf, "SYSERR: Room #%d fatal rproc error.  No randoms in rrandom blk.", r->number);
    mudlog(buf, BUG, LEV_IMM, FALSE);
    do_rend(r, argument);  // end rproc
  }

  if (count > 1)
    pick = number(1, count);
  else
    pick = 1;

  // now go thru block and pick the pickth one
  pt = scan_past_eol(pt);

  for (count = 1, *comm = '\0'; count < pick; count++)
    pt = scan_past_eol(pt);
  skip_spaces(&pt);

  /* get length of next command */
  for (i=0, tmp2 = pt; *tmp2 && !ISNEWL(*tmp2) && (i < MAX_INPUT_LENGTH);
       tmp2++, i++)
   ;

  /* copy this command line into comm */
  strncpy(comm, pt, i);
  comm[i] = '\0';

  /* show the imms in the room with logal on */
  S2IMM(comm, r);

  if (*comm != '&')  // process only if not our ignore character
    rproc_interpreter(r, comm, NULL, NULL, TRUE);

  RPROC_CUR(r) = tmp;
  return RP_RRANDOM;
}

// 6/11/98 - jtrhone
// add support for possible remotes  6/13/98 -jtrhone
int do_rexitopen(rmdata *r, char *comm)
{
  char arg1[MAX_INPUT_LENGTH];
  int dir, rroom, room;
  rmdirdata *d;
  rmdata *tr;

  one_argument(comm, arg1);
  if (!*arg1)
  {
    sprintf(buf, "SYSERR: Invalid argument sent to rexitopen (#%d).", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }

  // they are lookin at a direction
  dir = search_block(arg1, comm_dirs, FALSE);

  if (dir < 0 || dir > NUM_OF_DIRS)
  {
    sprintf(buf, "SYSERR: Invalid direction arg sent to rexitopen (#%d).", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }

  tr = REMOTE(r) ? REMOTE(r) : r;

  rroom = real_room(tr->number);
  if (!(d = DIR(rroom, dir)))
  {
    sprintf(buf, "SYSERR: rexitiopen (#%d), direction DNE.", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }

  if (!EXIT_ISDOOR(d))
  {
    sprintf(buf, "SYSERR: rexitopen (#%d), direction cannot be opened.", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }

  if (EXIT_CLOSED(d))
  {
    UNFLAG_EXIT(d, EX_CLOSED);
    for (room = 0; room < top_of_world; room++)
      if (DIR(room, rev_dir[dir]) && EXIT_ISDOOR(DIR(room, rev_dir[dir])) &&
          EXIT_CLOSED(DIR(room, rev_dir[dir])) && DIR(room, rev_dir[dir])->to_room_virtual == tr->number)
      {
        UNFLAG_EXIT(DIR(room, rev_dir[dir]), EX_CLOSED);
      }
  }

  return RP_NORMAL;
}

// 6/11/98 - jtrhone
// add support for possible remotes  6/13/98 -jtrhone
int do_rexitclose(rmdata *r, char *comm)
{
  char arg1[MAX_INPUT_LENGTH];
  int dir, rroom, room;
  rmdirdata *d;
  rmdata *tr;

  one_argument(comm, arg1);
  if (!*arg1)
  {
    sprintf(buf, "SYSERR: Invalid argument sent to rexitclose (#%d).", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }

  // they are lookin at a direction
  dir = search_block(arg1, comm_dirs, FALSE);

  if (dir < 0 || dir > NUM_OF_DIRS)
  {
    sprintf(buf, "SYSERR: Invalid direction arg sent to rexitclose (#%d).", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }

  tr = REMOTE(r) ? REMOTE(r) : r;

  rroom = real_room(tr->number);
  if (!(d = DIR(rroom, dir)))
  {
    sprintf(buf, "SYSERR: rexiticlose (#%d), direction DNE.", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }

  if (!EXIT_ISDOOR(d))
  {
    sprintf(buf, "SYSERR: rexitclose (#%d), direction cannot be closed.", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }

  if (EXIT_OPEN(d))
  {
    FLAG_EXIT(d, EX_CLOSED);
    for (room = 0; room < top_of_world; room++)
      if (DIR(room, rev_dir[dir]) && EXIT_ISDOOR(DIR(room, rev_dir[dir])) &&
          EXIT_OPEN(DIR(room, rev_dir[dir])) && DIR(room, rev_dir[dir])->to_room_virtual == tr->number)
      {
        FLAG_EXIT(DIR(room, rev_dir[dir]), EX_CLOSED);
      }
  }

  return RP_NORMAL;
}

// 6/11/98 - jtrhone
// add support for possible remotes  6/13/98 -jtrhone
int do_rexitlock(rmdata *r, char *comm)
{
  char arg1[MAX_INPUT_LENGTH];
  int dir, rroom, room;
  rmdirdata *d;
  rmdata *tr;

  one_argument(comm, arg1);
  if (!*arg1)
  {
    sprintf(buf, "SYSERR: Invalid argument sent to rexitlock (#%d).", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }

  // they are lookin at a direction
  dir = search_block(arg1, comm_dirs, FALSE);

  if (dir < 0 || dir > NUM_OF_DIRS)
  {
    sprintf(buf, "SYSERR: Invalid direction arg sent to rexitlock (#%d).", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }

  tr = REMOTE(r) ? REMOTE(r) : r;

  rroom = real_room(tr->number);
  if (!(d = DIR(rroom, dir)))
  {
    sprintf(buf, "SYSERR: rexitlock (#%d), direction DNE.", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }

  if (!EXIT_ISDOOR(d))
  {
    sprintf(buf, "SYSERR: rexitlock (#%d), direction cannot be locked.", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }

  if (EXIT_UNLOCKED(d))
  {
    FLAG_EXIT(d, EX_LOCKED);
    for (room = 0; room < top_of_world; room++)
      if (DIR(room, rev_dir[dir]) && EXIT_ISDOOR(DIR(room, rev_dir[dir])) &&
          EXIT_UNLOCKED(DIR(room, rev_dir[dir])) && DIR(room, rev_dir[dir])->to_room_virtual == tr->number)
      {
        FLAG_EXIT(DIR(room, rev_dir[dir]), EX_LOCKED);
      }
  }

  return RP_NORMAL;
}

// 6/11/98 - jtrhone
// add support for possible remotes  6/13/98 -jtrhone
int do_rexitunlock(rmdata *r, char *comm)
{
  char arg1[MAX_INPUT_LENGTH];
  int dir, rroom, room;
  rmdirdata *d;
  rmdata *tr;

  one_argument(comm, arg1);
  if (!*arg1)
  {
    sprintf(buf, "SYSERR: Invalid argument sent to rexitunlock (#%d).", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }

  // they are lookin at a direction
  dir = search_block(arg1, comm_dirs, FALSE);

  if (dir < 0 || dir > NUM_OF_DIRS)
  {
    sprintf(buf, "SYSERR: Invalid direction arg sent to rexitunlock (#%d).", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }

  tr = REMOTE(r) ? REMOTE(r) : r;
  rroom = real_room(tr->number);
  if (!(d = DIR(rroom, dir)))
  {
    sprintf(buf, "SYSERR: rexitunlock (#%d), direction DNE.", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }

  if (!EXIT_ISDOOR(d))
  {
    sprintf(buf, "SYSERR: rexitunlock (#%d), direction cannot be unlocked.", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }

  if (EXIT_LOCKED(d))
  {
    UNFLAG_EXIT(d, EX_LOCKED);
    for (room = 0; room < top_of_world; room++)
      if (DIR(room, rev_dir[dir]) && EXIT_ISDOOR(DIR(room, rev_dir[dir])) &&
          EXIT_LOCKED(DIR(room, rev_dir[dir])) && DIR(room, rev_dir[dir])->to_room_virtual == tr->number)
      {
        UNFLAG_EXIT(DIR(room, rev_dir[dir]), EX_LOCKED);
      }
  }

  return RP_NORMAL;
}

// 6/14/98 - jtrhone
int do_rexitvisible(rmdata *r, char *comm)
{
  char arg1[MAX_INPUT_LENGTH];
  int dir, rroom;
  rmdirdata *d;
  rmdata *tr;

  one_argument(comm, arg1);
  if (!*arg1)
  {
    sprintf(buf, "SYSERR: Invalid argument sent to rexitvisible (#%d).", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }

  // they are lookin at a direction
  dir = search_block(arg1, comm_dirs, FALSE);

  if (dir < 0 || dir > NUM_OF_DIRS)
  {
    sprintf(buf, "SYSERR: Invalid direction arg sent to rexitvisible (#%d).", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }

  tr = REMOTE(r) ? REMOTE(r) : r;
  rroom = real_room(tr->number);
  if (!(d = DIR(rroom, dir)))
  {
    sprintf(buf, "SYSERR: rexitvisible (#%d), direction DNE.", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }

  UNFLAG_EXIT(d, EX_SECRET);
  return RP_NORMAL;
}

// 6/14/98 - jtrhone
int do_rexitsecret(rmdata *r, char *comm)
{
  char arg1[MAX_INPUT_LENGTH];
  int dir, rroom;
  rmdirdata *d;
  rmdata *tr;

  one_argument(comm, arg1);
  if (!*arg1)
  {
    sprintf(buf, "SYSERR: Invalid argument sent to rexitsecret (#%d).", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }

  // they are lookin at a direction
  dir = search_block(arg1, comm_dirs, FALSE);

  if (dir < 0 || dir > NUM_OF_DIRS)
  {
    sprintf(buf, "SYSERR: Invalid direction arg sent to rexitsecret (#%d).", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }

  tr = REMOTE(r) ? REMOTE(r) : r;
  rroom = real_room(tr->number);
  if (!(d = DIR(rroom, dir)))
  {
    sprintf(buf, "SYSERR: rexitsecret (#%d), direction DNE.", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }

  FLAG_EXIT(d, EX_SECRET);
  return RP_NORMAL;
}

// 6/14/98 - jtrhone
int do_rexitlead(rmdata *r, char *comm)
{
  char arg1[MAX_INPUT_LENGTH];
  char arg2[MAX_INPUT_LENGTH];
  int dir, rroom, rvnum, trroom;
  rmdirdata *d;
  rmdata *tr;

  half_chop(comm, arg1, arg2);
  if (!*arg1 || !*arg2)
  {
    sprintf(buf, "SYSERR: Invalid arguments sent to rexitlead (#%d).", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }

  // they are lookin at a direction
  dir = search_block(arg1, comm_dirs, FALSE);

  if (dir < 0 || dir > NUM_OF_DIRS)
  {
    sprintf(buf, "SYSERR: Invalid direction arg sent to rexitlead (#%d).", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }

  tr = REMOTE(r) ? REMOTE(r) : r;
  rroom = real_room(tr->number);
  if (!(d = DIR(rroom, dir)))
  {
    sprintf(buf, "SYSERR: rexitlead (#%d), direction DNE.", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }

  if (!is_number(arg2) || (rvnum = atoi(arg2)) <= 0)
  {
    sprintf(buf, "SYSERR: rexitlead (#%d), target room invalid.", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }

  if ((trroom = real_room(rvnum)) <= 0)
  {
    sprintf(buf, "SYSERR: rexitlead (#%d), target room invalid.", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }

  d->to_room_virtual = rvnum;
  d->to_room = trroom;
  return RP_NORMAL;
}

// 6/11/98 - jtrhone
// toggle exit states
// oc - open close, lu - lock unlock, vs - vis secret
// rexittog n oc (toggles northern exit as open or closed)
// add support for possible remotes  6/13/98 -jtrhone
int do_rexittoggle(rmdata *r, char *comm)
{
  char arg1[MAX_INPUT_LENGTH];
  char arg2[MAX_INPUT_LENGTH];
  int dir, rroom;
  rmdirdata *d;
  rmdata *tr;

  half_chop(comm, arg1, arg2);
  if (!*arg1 || !*arg2)
  {
    sprintf(buf, "SYSERR: Invalid arguments sent to rexittoggle (#%d).", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }

  // they are lookin at a direction
  dir = search_block(arg1, comm_dirs, FALSE);

  if (dir < 0 || dir > NUM_OF_DIRS)
  {
    sprintf(buf, "SYSERR: Invalid direction arg sent to rexittoggle (#%d).", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }

  tr = REMOTE(r) ? REMOTE(r) : r;
  rroom = real_room(tr->number);
  if (!(d = DIR(rroom, dir)))
  {
    sprintf(buf, "SYSERR: rexittoggle (#%d), direction DNE.", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }

  if (!str_cmp(arg2, "oc"))
  {
    if (!EXIT_ISDOOR(d))
    {
      sprintf(buf, "SYSERR: rexittoggle (#%d), direction cannot be OC.", r->number);
      mudlog(buf, BRF, LEV_IMM, FALSE);
      return RP_NORMAL;
    }

    // WELL, we should check if locked / jammed, but nah
    if (EXIT_CLOSED(d))
      UNFLAG_EXIT(d, EX_CLOSED);
    else
      FLAG_EXIT(d, EX_CLOSED);
  }
  else
  if (!str_cmp(arg2, "lu"))
  {
    if (!EXIT_ISDOOR(d))
    {
      sprintf(buf, "SYSERR: rexittoggle (#%d), direction cannot be LU.", r->number);
      mudlog(buf, BRF, LEV_IMM, FALSE);
      return RP_NORMAL;
    }

    // WELL, we should check if locked / jammed, but nah
    if (EXIT_LOCKED(d))
      UNFLAG_EXIT(d, EX_LOCKED);
    else
      FLAG_EXIT(d, EX_LOCKED);
  }
  else
  if (!str_cmp(arg2, "vs"))
  {
    if (EXIT_SECRET(d))
      UNFLAG_EXIT(d, EX_SECRET);
    else
      FLAG_EXIT(d, EX_SECRET);
  }
  else
  {
    sprintf(buf, "SYSERR: rexittoggle (#%d), toggle must be oc, lu, or vs.", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }

  return RP_NORMAL;
}

// teleport entire room or char to vnum 
// rteleport <char | room> <vnum>
// 6/11/98 -jtrhone
// add support for possible remotes  6/13/98 -jtrhone
int do_rteleport(rmdata *r, char *comm)
{
  char arg1[MAX_INPUT_LENGTH];
  char arg2[MAX_INPUT_LENGTH];
  char arg3[MAX_INPUT_LENGTH];
  char arg4[MAX_INPUT_LENGTH];
  chdata *vict, *tmp_vict;
  int room;
  rmdata *tr;

  half_chop(comm, arg1, arg2);
  if (!*arg1 || !*arg2)
  {
    sprintf(buf, "SYSERR: Invalid arguments sent to rteleport (#%d).", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }

  tr = REMOTE(r) ? REMOTE(r) : r;

  if (is_abbrev(arg1, "char"))
  {
    half_chop(arg2, arg3, arg4);
    if (!*arg3 || !*arg4)
    {
      sprintf(buf, "SYSERR: Invalid arguments sent to rteleport (#%d).", r->number);
      mudlog(buf, BRF, LEV_IMM, FALSE);
      return RP_NORMAL;
    }

    if (!(vict = get_char_room(arg3, real_room(tr->number))))
      return RP_NORMAL; 

    if (!is_number(arg4) || INVALID_ROOM((room = real_room(atoi(arg4)))))
    {
      sprintf(buf, "SYSERR: Invalid destination sent to rteleport (#%d).", r->number);
      mudlog(buf, BRF, LEV_IMM, FALSE);
      return RP_NORMAL;
    } 

    char_from_room(vict);
    char_to_room(vict, room);
    do_look_at_room(vict, 0, 0);
    if (check_room_affects(vict, vict->in_room) == CHAR_DIED)
      return RP_NORMAL;
    if (check_death_trap(vict, NULL))
      return RP_NORMAL; 
  }
  else
  if (is_abbrev(arg1, "room"))
  {
    if (!tr->people)
      return RP_NORMAL;

    if (!is_number(arg2) || INVALID_ROOM((room = real_room(atoi(arg2)))))
    {
      sprintf(buf, "SYSERR: Invalid destination sent to rteleport (#%d).", r->number);
      mudlog(buf, BRF, LEV_IMM, FALSE);
      return RP_NORMAL;
    } 
    
    for (vict = tr->people; vict; vict = tmp_vict)
    {
      tmp_vict = vict->next_in_room;

      char_from_room(vict);
      char_to_room(vict, room);
      do_look_at_room(vict, 0, 0);
      if (check_room_affects(vict, vict->in_room) == CHAR_DIED)
        continue;
      if (check_death_trap(vict, NULL))
        continue;
    } 
    return RP_NORMAL; 
  }
  else
  {
    sprintf(buf, "SYSERR: Invalid arguments sent to rteleport (#%d).", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }

  return RP_NORMAL;
}

// trans a mob of vnum in this zone to this room (not from this room)
// rtransmob 10123
// 6/13/98 -jtrhone
// add support for possible remotes  6/13/98 -jtrhone
int do_rtransmob(rmdata *r, char *comm)
{
  char arg1[MAX_INPUT_LENGTH];
  chdata *mob;
  int vnum = 0, i;
  rmdata *tr;

  one_argument(comm, arg1);
  if (!*arg1 || !is_number(arg1))
  {
    sprintf(buf, "SYSERR: Invalid arguments sent to rtransmob (#%d).", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }

  vnum = atoi(arg1);
  if (real_mobile(vnum) <= 0)
  {
    sprintf(buf, "SYSERR: Invalid mob vnum sent to rtransmob (#%d).", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }

  tr = REMOTE(r) ? REMOTE(r) : r;

  for (i = 0; i < top_of_world; i++)
    if (world[i].zone == tr->zone && &world[i] != tr && world[i].people)
      for (mob = world[i].people; mob; mob=mob->next_in_room)
        if (IS_NPC(mob) && GET_MOB_VNUM(mob) == vnum)
        {
          S2IMM("rtransmob: Found mob, transing.", r);
          char_from_room(mob);
          char_to_room(mob, real_room(tr->number));
          return RP_NORMAL;
        } 
  return RP_NORMAL;
}

// trans an obj of vnum in this zone to this room (not from this room)
// rtransobj 10123
// 6/13/98 -jtrhone
// add support for possible remotes  6/13/98 -jtrhone
int do_rtransobj(rmdata *r, char *comm)
{
  char arg1[MAX_INPUT_LENGTH];
  obdata *obj;
  int vnum = 0, i;
  rmdata *tr;

  one_argument(comm, arg1);
  if (!*arg1 || !is_number(arg1))
  {
    sprintf(buf, "SYSERR: Invalid arguments sent to rtransobj (#%d).", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }

  vnum = atoi(arg1);
  if (real_object(vnum) <= 0)
  {
    sprintf(buf, "SYSERR: Invalid obj vnum sent to rtransobj (#%d).", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }

  tr = REMOTE(r) ? REMOTE(r) : r;

  for (i = 0; i < top_of_world; i++)
    if (world[i].zone == tr->zone && &world[i] != tr && world[i].contents)
      for (obj = world[i].contents; obj; obj=obj->next_content)
        if (GET_OBJ_VNUM(obj) == vnum)
        {
          S2IMM("rtransobj: Found obj, transing.", r);
          obj_from_room(obj);
          float_sink_object(obj, real_room(tr->number));
          return RP_NORMAL;
        } 

  return RP_NORMAL;
}

// set room's remote room (so this proc can do things in other rooms)
// rsetremote 3001
// 6/13/98 -jtrhone
int do_rsetremote(rmdata *r, char *comm)
{
  char arg1[MAX_INPUT_LENGTH];
  rmdata *rm;
  int vnum = 0, rroom;

  one_argument(comm, arg1);
  if (!*arg1 || !is_number(arg1))
  {
    sprintf(buf, "SYSERR: Invalid argument sent to rsetremote (#%d).", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_RREMOTE;
  }

  vnum = atoi(arg1);
  if ((rroom = real_room(vnum)) <= 0)
  {
    sprintf(buf, "SYSERR: Invalid room vnum sent to rsetremote (#%d).", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_RREMOTE;
  }

  rm = &world[rroom];
  if (rm == r)
  {
    sprintf(buf, "SYSERR: Room sent to rsetremote matches source room (#%d).", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_RREMOTE;
  }

  REMOTE(r) = rm;
  sprintf(buf, "rsetremote: remote set to %d.", vnum);
  S2IMM(buf, r);

  return RP_RREMOTE;
}

// unset room's remote room
// runsetremote
// 6/13/98 -jtrhone
int do_runsetremote(rmdata *r, char *comm)
{
  REMOTE(r) = NULL;
  S2IMM("runsetremote: remote unset.", r);
  return RP_RREMOTE;
}

// RTARGET UTILITY FUNCTIONS (6/14/98 -jtrhone)
// count number of objects in the room
int r_num_obj_room(rmdata *r)
{
  int i;
  obdata *obj = r->contents;
  for (i=0; obj; obj=obj->next_content, i++)
    ;
  return i;
}

// return ptr to the numTH item in room
obdata *r_get_obj_room(rmdata *r, int num)
{
  int i;
  obdata *obj = r->contents;
  for (i = 0; i < num && obj; obj=obj->next_content, i++)
    if (i == num) break;
  return obj;
}

// return ptr to the numTH object in zone
obdata* r_get_obj_zone(rmdata *r, int num)
{
  int i;
  obdata *obj = object_list;

  for (i=0; obj && i < num; obj=obj->next)
  {
    if (INVALID_ROOM(obj->in_room)) continue;
    if (world[obj->in_room].zone == r->zone)
      i++;
    if (i == num) return obj;
  }
  return NULL;
}

// return how many objects are in ROOMS in zone
int r_num_obj_zone(rmdata *r)
{
  int i;
  obdata *obj = object_list;

  for (i=0; obj; obj=obj->next)
  {
    if (INVALID_ROOM(obj->in_room)) continue;
    if (world[obj->in_room].zone == r->zone)
      i++;
  }
  return i;
}

// target counters for ROOMS
int r_num_pc_room(rmdata *r)
{
  int i;
  chdata *vict = r->people;
  for (i=0; vict; vict = vict->next_in_room)
    if (IS_PC(vict)) i++;

  return i;
}

int r_num_npc_room(rmdata *r)
{
  int i;
  chdata *vict = r->people;
  for (i=0; vict; vict = vict->next_in_room)
    if (IS_NPC(vict)) i++;

  return i;
}

int r_num_any_room(rmdata *r)
{
  int i;
  chdata *vict = r->people;
  for (i=0; vict; vict = vict->next_in_room)
    i++;
  return i;
}

// target counters for ZONE
int r_num_any_zone(rmdata *r)
{
  int i;
  chdata *vict;

  for (i=0, vict = character_list; vict; vict = vict->next)
    if (world[vict->in_room].zone == r->zone)
      i++;

  return i;
}

int r_num_npc_zone(rmdata *r)
{
  int i;
  chdata *vict;

  for (i=0, vict = character_list; vict; vict = vict->next)
    if (IS_NPC(vict) && world[vict->in_room].zone == r->zone)
      i++;

  return i;
}

int r_num_pc_zone(rmdata *r)
{
  int i;
  chdata *vict;

  for (i=0, vict = character_list; vict; vict = vict->next)
    if (IS_PC(vict) && world[vict->in_room].zone == r->zone)
      i++;

  return i;
}

// targetting functions for ROOM
chdata *r_get_any_room(rmdata *r, int num)
{
  int i;
  chdata *vict = r->people;
  for (i = 0; i < num && vict; vict = vict->next_in_room)
    if (++i == num) break;
  return vict;
}

chdata *r_get_pc_room(rmdata *r, int num)
{
  int i;
  chdata *vict = r->people;
  for (i = 0; i < num && vict; vict = vict->next_in_room)
  {
    if (IS_PC(vict)) i++;
    if (i == num) break;
  }
  return vict;
}

chdata *r_get_npc_room(rmdata *r, int num)
{
  int i;
  chdata *vict = r->people;
  for (i = 0; i < num && vict; vict = vict->next_in_room)
  {
    if (IS_NPC(vict)) i++;
    if (i == num) break;
  }
  return vict;
}

// targetting functions for ZONE
chdata *r_get_any_zone(rmdata *r, int num)
{
  int i;
  chdata *vict;

  for (i = 0, vict = character_list; vict && i < num; vict = vict->next)
  {
    if (INVALID_ROOM(vict->in_room)) continue;
    if (world[vict->in_room].zone == r->zone)
      i++;
    if (i == num) return vict;
  }

  return NULL;
}

chdata *r_get_pc_zone(rmdata *r, int num)
{
  int i;
  chdata *vict;

  for (i = 0, vict = character_list; vict && i < num; vict = vict->next)
  {
    if (INVALID_ROOM(vict->in_room)) continue;
    if (world[vict->in_room].zone == r->zone && IS_PC(vict))
      i++;
    if (i == num) return vict;
  }

  return NULL;
}

chdata *r_get_npc_zone(rmdata *r, int num)
{
  int i;
  chdata *vict;

  for (i = 0, vict = character_list; vict && i < num; vict = vict->next)
  {
    if (INVALID_ROOM(vict->in_room)) continue;
    if (world[vict->in_room].zone == r->zone && IS_NPC(vict))
      i++;
    if (i == num) return vict;
  }

  return NULL;
}

/* set a room's target character/object (in room) */
int do_rtarget(rmdata *r, char *comm)
{
  char arg1[MAX_INPUT_LENGTH];
  char arg2[MAX_INPUT_LENGTH];
  int num, pick;
  chdata *vict = NULL;
  obdata *obj = NULL;
  BOOL pc, npc;

  pc = npc = FALSE;
  half_chop(comm, arg1, arg2);
  if (!str_cmp(arg1, "char"))
  {
    if (RTARGET_CHAR(r))
      free_log(RTARGET_CHAR(r), "do_mtarget");
    RTARGET_CHAR(r) = NULL;

    half_chop(arg2, arg1, arg2);
    if (!*arg1)
    {
      sprintf(buf, "SYSERR: Undefined char type (pc | npc | any) to rtarget (#%d).", r->number);
      mudlog(buf, BRF, LEV_IMM, FALSE);
      return RP_NORMAL;
    }
    else
    if (!str_cmp(arg1, "pc")) pc = TRUE;
    else
    if (!str_cmp(arg1, "npc")) npc = TRUE;
    else
    if (!str_cmp(arg1, "any"))
    {
      npc = pc = TRUE;
    }
    else
    {
      sprintf(buf, "SYSERR: Undefined char type (pc | npc | any) to rtarget (#%d).", r->number);
      mudlog(buf, BRF, LEV_IMM, FALSE);
      return RP_NORMAL;
    }

    half_chop(arg2, arg1, arg2);
    if (!*arg1 || !is_number(arg1))
    {
      sprintf(buf, "SYSERR: Undefined character number to rtarget (#%d).",r->number);
      mudlog(buf, BRF, LEV_IMM, FALSE);
      return RP_NORMAL;
    }

    if ((num = atoi(arg1))) /* if a number besides 0 is wanted */
    {
      if ((!pc && (vict = r_get_npc_room(r, num))) ||
          (!npc && (vict = r_get_pc_room(r, num))) ||
          (pc && npc && (vict = r_get_any_room(r, num))) )
      {
        RTARGET_CHAR(r) = str_dup(fname(vict->player.name));
        sprintf(buf, "SYSUPD: Room #%d setting char target to %s", r->number, fname(vict->player.name));
        mudlog(buf, BUG, LEV_IMM, FALSE);
      }
    }
    else
    if (!num) /* this means pick a random character in the room */
    {
      pick = 0;
      if (!pc && r_num_npc_room(r))
        pick = number(1, r_num_npc_room(r));
      else
      if (!npc && r_num_pc_room(r))
        pick = number(1, r_num_pc_room(r));
      else
      if (pc && npc && r_num_any_room(r))
        pick = number(1, r_num_any_room(r));
      if (pick)
      {
        if ((!pc && (vict = r_get_npc_room(r, pick))) ||
            (!npc && (vict = r_get_pc_room(r, pick))) ||
            (pc && npc && (vict = r_get_any_room(r, pick))) )
        {
          RTARGET_CHAR(r) = str_dup(fname(vict->player.name));
          sprintf(buf, "SYSUPD: Rproc #%d setting char target to %s", r->number, fname(vict->player.name));
          mudlog(buf, BUG, LEV_IMM, FALSE);
        }
      }
    }
  }
  else
  if (!str_cmp(arg1, "obj"))
  {
    if (RTARGET_OBJ(r))
      free_log(RTARGET_OBJ(r), "do_rtarget 2");
    RTARGET_OBJ(r) = NULL;

    half_chop(arg2, arg1, arg2);
    if (!*arg1 || !is_number(arg1))
    {
      sprintf(buf, "SYSERR: Undefined object number to rtarget (#%d).",r->number);
      mudlog(buf, BRF, LEV_IMM, FALSE);
      return RP_NORMAL;
    }

    if ((num = atoi(arg1))) /* if a number besides 0 is wanted */
    {
      num--;
      if ((obj = r_get_obj_room(r, num)))
      {
        sprintf(buf, "SYSUPD: Rproc #%d setting obj target to %s", r->number, fname(obj->name));
        mudlog(buf, BUG, LEV_IMM, FALSE);
        RTARGET_OBJ(r) = str_dup(fname(obj->name));
      }
    }
    else
    if (!num && r_num_obj_room(r) && (obj = r_get_obj_room(r, number(0, (r_num_obj_room(r)-1)))))
    {
      sprintf(buf, "SYSUPD: Rproc #%d setting obj target to %s", r->number, fname(obj->name));
      mudlog(buf, BUG, LEV_IMM, FALSE);
      RTARGET_OBJ(r) = str_dup(fname(obj->name));
    }
  }
  else
  {
    sprintf(buf, "SYSERR: Undefined arg (%s) to rtarget (#%d).", arg1, r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }
  return RP_RTARGET;
}

/* set a rooms's target character/object (in zone) */
int do_rtarget_zone(rmdata *r, char *comm)
{
  char arg1[MAX_INPUT_LENGTH];
  char arg2[MAX_INPUT_LENGTH];
  int num, pick;
  chdata *vict = NULL;
  obdata *obj = NULL;
  BOOL pc, npc;

  pc = npc = FALSE;
  half_chop(comm, arg1, arg2);
  if (!str_cmp(arg1, "char"))
  {
    if (RTARGET_CHAR(r))
      free_log(RTARGET_CHAR(r), "do_rtarget_zone");
    RTARGET_CHAR(r) = NULL;

    half_chop(arg2, arg1, arg2);
    if (!*arg1)
    {
      sprintf(buf, "SYSERR: Undefined char type (pc | npc | any) to rtargetzone (#%d).", r->number);
      mudlog(buf, BRF, LEV_IMM, FALSE);
      return RP_NORMAL;
    }
    else
    if (!str_cmp(arg1, "pc")) pc = TRUE;
    else
    if (!str_cmp(arg1, "npc")) npc = TRUE;
    else
    if (!str_cmp(arg1, "any"))
    {
      npc = pc = TRUE;
    }
    else
    {
      sprintf(buf, "SYSERR: Undefined char type (pc | npc | any) to mtargetzone (#%d).", r->number);
      mudlog(buf, BRF, LEV_IMM, FALSE);
      return RP_NORMAL;
    }

    half_chop(arg2, arg1, arg2);
    if (!*arg1 || !is_number(arg1))
    {
      sprintf(buf, "SYSERR: Undefined character number to rtargetzone (#%d).", r->number);
      mudlog(buf, BRF, LEV_IMM, FALSE);
      return RP_NORMAL;
    }

    if ((num = atoi(arg1))) /* if a number besides 0 is wanted */
    {
      if ((!pc && (vict = r_get_npc_zone(r, num))) || (!npc && (vict = r_get_pc_zone(r, num))) ||
          (pc && npc && (vict = r_get_any_zone(r, num))) )
      {
       if (MOB2_FLAGGED(vict, MOB2_NO_MTARGET))
          return RP_RTARGET;

        RTARGET_CHAR(r) = str_dup(fname(vict->player.name));
        sprintf(buf, "SYSUPD: Rproc #%d setting char target to %s", r->number, fname(vict->player.name));
        mudlog(buf, BUG, LEV_IMM, FALSE);
      }
    }
    else
    if (!num) /* this means pick a random character in the zone */
    {
      pick = 0;
      if (!pc && r_num_npc_zone(r))
        pick = number(1, r_num_npc_zone(r));
      else
      if (!npc && r_num_pc_zone(r))
        pick = number(1, r_num_pc_zone(r));
      else
      if (pc && npc && r_num_any_zone(r))
        pick = number(1, r_num_any_zone(r));

      if (pick)
      {
        if ((!pc && (vict = r_get_npc_zone(r, pick))) || (!npc && (vict = r_get_pc_zone(r, pick))) ||
            (pc && npc && (vict = r_get_any_zone(r, pick))) )
        {
          if (MOB2_FLAGGED(vict, MOB2_NO_MTARGET))
            return RP_RTARGET;

          RTARGET_CHAR(r) = str_dup(fname(vict->player.name));
          sprintf(buf, "SYSUPD: Rproc #%d setting char target to %s", r->number, fname(vict->player.name));
          mudlog(buf, BUG, LEV_IMM, FALSE);
        }
      }
    }
  }
  else
  if (!str_cmp(arg1, "obj"))
  {
    if (RTARGET_OBJ(r))
      free_log(RTARGET_OBJ(r), "do_rtarget_zone 2");
    RTARGET_OBJ(r) = NULL;

    half_chop(arg2, arg1, arg2);
    if (!*arg1 || !is_number(arg1))
    {
      sprintf(buf, "SYSERR: Undefined object number to rtargetzone (#%d).",r->number);
      mudlog(buf, BRF, LEV_IMM, FALSE);
      return RP_NORMAL;
    }

    if ((num = atoi(arg1))) /* if a number besides 0 is wanted */
    {
      num--;
      if ((obj = r_get_obj_zone(r, num)))
      {
        sprintf(buf, "SYSUPD: #%d setting obj target to %s", r->number, fname(obj->name));
        mudlog(buf, BUG, LEV_IMM, FALSE);
        RTARGET_OBJ(r) = str_dup(fname(obj->name));
      }
    }
    else
    if (!num && r_num_obj_zone(r) && (obj = r_get_obj_zone(r, number(0, (r_num_obj_zone(r)-1)))))
    {
      sprintf(buf, "SYSUPD: #%d setting obj target to %s", r->number, fname(obj->name));
      mudlog(buf, BUG, LEV_IMM, FALSE);
      RTARGET_OBJ(r) = str_dup(fname(obj->name));
    }
  }
  else
  {
    sprintf(buf, "SYSERR: Undefined arg (%s) to rtargetzone (#%d).", arg1, r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }

  return RP_RTARGET;
}

/* manually set the room's target strings */
int do_rtarget_set(rmdata *r, char *comm)
{
  char arg1[MAX_INPUT_LENGTH];
  char arg2[MAX_INPUT_LENGTH];

  half_chop(comm, arg1, arg2);
  if (is_abbrev(arg1, "char") && *arg2)
  {
    if (RTARGET_CHAR(r))
      free_log(RTARGET_CHAR(r), "do_rtargetset 1");
    RTARGET_CHAR(r) = str_dup(arg2);
  }
  else
  if (is_abbrev(arg1, "obj") && *arg2)
  {
    if (RTARGET_OBJ(r))
      free_log(RTARGET_OBJ(r), "do_mtargetset 2");
    RTARGET_OBJ(r) = str_dup(arg2);
  }
  else
  {
    sprintf(buf, "SYSERR: Rproc (#%d) invalid rtargetset command.", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return RP_NORMAL;
  }
  return RP_RTARGET;
}

// skip a command goto next or jump to beginning if none left
// must add ability to skip rcommand blocks!, if the command structure
// uses them, such as rrandom... rrandom uses a block structure
// if we are pointing at a block, skip it! (rifs mostly)
void goto_next_rcom(rmdata *r)
{
  char arg1[MAX_INPUT_LENGTH];
  char *tmp = RPROC_CUR(r);

  one_argument(tmp, arg1);

  // jump to the top...
  if (!*tmp)
  {
    RPROC_CUR(r) = RPROC_BEG(r);
    return;
  }

  // lets check the command we're skippin to see if it is a block command
  if (*arg1 == '{')
  {
    tmp = skip_block(tmp);
    if (!*tmp)
      tmp = RPROC_BEG(r);
    RPROC_CUR(r) = tmp;
    return;
  }
  else
  if (is_abbrev(arg1, "rrandom") || is_abbrev(arg1, "rtrigadd"))
  {
    tmp = scan_past_eol(tmp);
    tmp = skip_block(tmp);
    if (!*tmp)
      tmp = RPROC_BEG(r);
    RPROC_CUR(r) = tmp;
    return;
  }

  // else do the normal one line skip
  tmp = scan_past_eol(tmp);
  if (!*tmp)
    tmp = RPROC_BEG(r);

  RPROC_CUR(r) = tmp;
}

// see do_mif in mobproc.c, very similar here
// added, modified 6/14/98 -jtrhone
int do_rif(rmdata *r, char *argument)
{
  static char rif_comp[MAX_INPUT_LENGTH];
  static char comp_args[MAX_INPUT_LENGTH];
  char arg1[MAX_INPUT_LENGTH];
  char arg2[MAX_INPUT_LENGTH];
  int vroom, rroom;
  chdata *ch;
  obdata *obj;
  BOOL found;
  int i, cmd;

  int get_race_by_name(char *arg); // races.c, 8/22/98 -jtrhone

  half_chop(argument, rif_comp, comp_args);

  if ((cmd = search_block(rif_comp, rif_BOOLs, FALSE)) < 0)
  {
    sprintf(buf, "SYSUPD: Undefined rproc RIF argument. #%d",r->number);
    mudlog(buf, BUG, LEV_IMM, FALSE);
    sprintf(buf, "SYSUPD: Undefined RIF arg: %s", rif_comp);
    mudlog(buf, BUG, LEV_IMM, FALSE);
    goto_next_rcom(r);
  }

  // add a little flexibility to these... 1/22/98 -jtrhone
  while (*RPROC_CUR(r) && *RPROC_CUR(r) != '{')
    RPROC_CUR(r)++;

  if (*RPROC_CUR(r) != '{')
  {
    sprintf(buf, "SYSUPD: RIF with no following block. #%d",r->number);
    mudlog(buf, BUG, LEV_IMM, FALSE);
    do_rend(r, "");
  }

  switch (cmd) {
    case 0:     //tarcharset
      if (!RTARGET_CHAR(r))
        goto_next_rcom(r);
      break;

    case 1:     //!tarcharset
      if (RTARGET_CHAR(r))
        goto_next_rcom(r);
      break;

    case 2:     //tarobjset
      if (!RTARGET_OBJ(r))
        goto_next_rcom(r);
      break;

    case 3:     //!tarobjset
      if (RTARGET_OBJ(r))
        goto_next_rcom(r);
      break;

    case 4:     //tarcharroom
      if (!RTARGET_CHAR(r) || !get_char_room(RTARGET_CHAR(r), real_room(r->number)))
        goto_next_rcom(r);
      break;

    case 5:     //!tarcharroom
      if (RTARGET_CHAR(r) && get_char_room(RTARGET_CHAR(r), real_room(r->number)))
        goto_next_rcom(r);
      break;

    case 6:     //tarobjroom
      if (!RTARGET_OBJ(r) || !get_obj_in_list(RTARGET_OBJ(r), r->contents))
        goto_next_rcom(r);
      break;

    case 7:     //!tarobjroom
      if (RTARGET_OBJ(r) && get_obj_in_list(RTARGET_OBJ(r), r->contents))
        goto_next_rcom(r);
      break;

    case 8:     //tarcharzone
      if (!RTARGET_CHAR(r) || !get_char_zone(r->zone, RTARGET_CHAR(r)))
        goto_next_rcom(r);
      break;

    case 9:     //!tarcharzone
      if (RTARGET_CHAR(r) && get_char_zone(r->zone, RTARGET_CHAR(r)))
        goto_next_rcom(r);
      break;

    case 10:    //tarobjzone
      if (!RTARGET_OBJ(r) || !get_object_zone(r->zone, RTARGET_OBJ(r)))
        goto_next_rcom(r);
      break;

    case 11:    //!tarobjzone
      if (RTARGET_OBJ(r) && get_object_zone(r->zone, RTARGET_OBJ(r)))
        goto_next_rcom(r);
      break;

    case 12:    //tarcharpc
      if (!RTARGET_CHAR(r) || !(ch = get_char_room(RTARGET_CHAR(r), real_room(r->number))) || !IS_PC(ch))
        goto_next_rcom(r);
      break;

    case 13:    //!tarcharpc
      if (!RTARGET_CHAR(r) || !(ch = get_char_room(RTARGET_CHAR(r), real_room(r->number))) || IS_PC(ch))
        goto_next_rcom(r);
      break;

    case 14:    //tarcharcompquest
      half_chop(comp_args, arg1, arg2);
      if (!is_number(arg1) || (!(vroom = atoi(arg1))) || !VALID_QUEST(vroom))
      {
        sprintf(buf, "SYSERR: rproc #%d invalid quest# check.", r->number);
        mudlog(buf, BRF, LEV_IMM, FALSE);
        return RP_RIF;
      }

      // if is no target, or isnt pc, or hasnt completed quest, skip block
      if (!RTARGET_CHAR(r) || !(ch = get_char_room(RTARGET_CHAR(r), real_room(r->number))) || !IS_PC(ch))
        goto_next_rcom(r);
      else
      if (!COMPLETED_QUEST(ch, vroom))
        goto_next_rcom(r);
      else
        RPROC_CUR(r) = scan_past_eol(RPROC_CUR(r));
      break;

    case 15:    //!tarcharcompquest
      half_chop(comp_args, arg1, arg2);
      if (!is_number(arg1) || (!(vroom = atoi(arg1))) || !VALID_QUEST(vroom))
      {
        sprintf(buf, "SYSERR: rproc #%d invalid quest# check.", r->number);
        mudlog(buf, BRF, LEV_IMM, FALSE);
        return RP_RIF;
      }

      // if is no target, or isnt visible, or isnt pc, or has completed quest, skip block
      if (!RTARGET_CHAR(r) || !(ch = get_char_room(RTARGET_CHAR(r), real_room(r->number))) || !IS_PC(ch))
        goto_next_rcom(r);
      else
      if (COMPLETED_QUEST(ch, vroom))
        goto_next_rcom(r);
      else
        RPROC_CUR(r) = scan_past_eol(RPROC_CUR(r));
      break;

    case 16:    //tarcharlevel
      ch = NULL;
      if (RTARGET_CHAR(r))
      {
        if (!(ch = get_char_room(RTARGET_CHAR(r), real_room(r->number))))
          if (!(ch = get_char_zone(r->zone, RTARGET_CHAR(r))))
            if (!(ch = get_char(RTARGET_CHAR(r))))
            {
              goto_next_rcom(r);
              return RP_RIF;
            }
      }
      else
      {
        goto_next_rcom(r);
        return RP_RIF;
      }

      half_chop(comp_args, arg1, arg2);
      if (!*arg1 || !*arg2)
      {
        sprintf(buf, "SYSERR: rproc #%d unknown tarcharlevel args.", r->number);
        mudlog(buf, BRF, LEV_IMM, FALSE);
        return RP_RIF;
      }

      if (!is_number(arg2) || (i = atoi(arg2)) > LEV_IMPL || i <= 0)
      {
        sprintf(buf, "SYSERR: rproc #%d tarcharlevel invalid level arg.", r->number);
        mudlog(buf, BRF, LEV_IMM, FALSE);
        return RP_RIF;
      }

      found = FALSE;
      switch (*arg1) {
       case '=':                // is equal to
        found = (GET_LEVEL(ch) == i);
        break;
       case '!':                // is != to
        found = (GET_LEVEL(ch) != i);
        break;
       case '<':                // is less than equal to, or is less than
        if (*(arg1+1) == '=')
          found = (GET_LEVEL(ch) <= i);
        else
          found = (GET_LEVEL(ch) < i);
        break;
       case '>':                // is greater than equal to, or is greater than
        if (*(arg1+1) == '=')
          found = (GET_LEVEL(ch) > i);
        else
          found = (GET_LEVEL(ch) >= i);
        break;
       default:
        sprintf(buf, "SYSERR: Unknown rproc comparison, #%d.", r->number);
        mudlog(buf, BRF, LEV_IMM, FALSE);
        return RP_RIF;
      }

      if (!found)
        goto_next_rcom(r);
      else
        RPROC_CUR(r) = scan_past_eol(RPROC_CUR(r));
      break;

    case 17:    //npcinroom
      half_chop(comp_args, arg1, arg2);
      if (!is_number(arg1) || (!(vroom = atoi(arg1))) || ((rroom = real_mobile(vroom)) <= 0))
      {
        sprintf(buf, "SYSERR: rproc #%d invalid npcinroom arg.", r->number);
        mudlog(buf, BRF, LEV_IMM, FALSE);
        return RP_RIF;
      }

      for (found = FALSE, ch = r->people; ch && !found; ch = ch->next_in_room)
        if (IS_NPC(ch) && GET_MOB_VNUM(ch) == vroom)
          found = TRUE;
      if (!found)
        goto_next_rcom(r);
      else
        RPROC_CUR(r) = scan_past_eol(RPROC_CUR(r));
      break;

    case 18:    //!npcinroom
      half_chop(comp_args, arg1, arg2);
      if (!is_number(arg1) || (!(vroom = atoi(arg1))) || ((rroom = real_mobile(vroom)) <= 0))
      {
        sprintf(buf, "SYSERR: rproc #%d invalid npcinroom arg.", r->number);
        mudlog(buf, BRF, LEV_IMM, FALSE);
        return RP_RIF;
      }

      for (found = FALSE, ch = r->people; ch && !found; ch = ch->next_in_room)
       if (IS_NPC(ch) && GET_MOB_VNUM(ch) == vroom)
          found = TRUE;

      if (found)
        goto_next_rcom(r);
      else
        RPROC_CUR(r) = scan_past_eol(RPROC_CUR(r));
      break;

    case 19:    //objinroom
      half_chop(comp_args, arg1, arg2);
      if (!is_number(arg1) || (!(vroom = atoi(arg1))) || ((rroom = real_object(vroom)) <= 0))
      {
        sprintf(buf, "SYSERR: rproc #%d invalid objinroom arg.", r->number);
        mudlog(buf, BRF, LEV_IMM, FALSE);
        return RP_RIF;
      }

      for (found = FALSE, obj = r->contents; obj && !found; obj = obj->next_content)
        if (GET_OBJ_VNUM(obj) == vroom)
          found = TRUE;

      if (!found)
        goto_next_rcom(r);
      else
        RPROC_CUR(r) = scan_past_eol(RPROC_CUR(r));
      break;

    case 20:    //!objinroom
      half_chop(comp_args, arg1, arg2);
      if (!is_number(arg1) || (!(vroom = atoi(arg1))) || ((rroom = real_object(vroom)) <= 0))
      {
        sprintf(buf, "SYSERR: rproc #%d invalid objinroom arg.", r->number);
        mudlog(buf, BRF, LEV_IMM, FALSE);
        return RP_RIF;
      }

      for (found = FALSE, obj = r->contents; obj && !found; obj = obj->next_content)
        if (GET_OBJ_VNUM(obj) == vroom)
          found = TRUE;

      if (found)
        goto_next_rcom(r);
      else
        RPROC_CUR(r) = scan_past_eol(RPROC_CUR(r));
      break;

    case 21:    //transpresent
      half_chop(comp_args, arg1, arg2);
      if (!is_number(arg1))
      {
        sprintf(buf, "SYSERR: rproc #%d invalid trans arg (%s).", r->number, arg1);
        mudlog(buf, BRF, LEV_IMM, FALSE);
        goto_next_rcom(r);
        return RP_RIF;
      }

      if (r->trans_present != atoi(arg1))
        goto_next_rcom(r);
      break;

    case 22:    //!transpresent
      half_chop(comp_args, arg1, arg2);
      if (!is_number(arg1))
      {
        sprintf(buf, "SYSERR: rproc #%d invalid trans arg (%s).", r->number, arg1);
        mudlog(buf, BRF, LEV_IMM, FALSE);
        goto_next_rcom(r);
        return RP_RIF;
      }

      if (r->trans_present == atoi(arg1))
        goto_next_rcom(r);
      break;

    case 23:    //tarcharonquest
      half_chop(comp_args, arg1, arg2);
      if (!is_number(arg1) || (!(vroom = atoi(arg1))) || !VALID_QUEST(vroom))
      {
        sprintf(buf, "SYSERR: rproc #%d invalid quest# check.", r->number);
        mudlog(buf, BRF, LEV_IMM, FALSE);
        return RP_RIF;
      }

      // if is no target, or isnt visible, or isnt pc, or isnt doing quest, skip block
      if (!RTARGET_CHAR(r) || !(ch = get_char_room(RTARGET_CHAR(r), real_room(r->number))) || !IS_PC(ch))
        goto_next_rcom(r);
      else
      if (ONQUEST(ch) != vroom)
        goto_next_rcom(r);
      else
        RPROC_CUR(r) = scan_past_eol(RPROC_CUR(r));
      break;

    case 24:    //!tarcharonquest
      half_chop(comp_args, arg1, arg2);
      if (!is_number(arg1) || (!(vroom = atoi(arg1))) || !VALID_QUEST(vroom))
      {
        sprintf(buf, "SYSERR: rproc #%d invalid quest# check.", r->number);
        mudlog(buf, BRF, LEV_IMM, FALSE);
        return RP_RIF;
      }

      // if is no target, or isnt visible, or isnt pc, or doing quest, skip block
      if (!RTARGET_CHAR(r) || !(ch = get_char_room(RTARGET_CHAR(r), real_room(r->number))) || !IS_PC(ch))
        goto_next_rcom(r);
      else
      if (ONQUEST(ch) == vroom)
        goto_next_rcom(r);
      else
        RPROC_CUR(r) = scan_past_eol(RPROC_CUR(r));
      break;

    case 25:    //tarcharrace <>
      half_chop(comp_args, arg1, arg2);
      if (!*arg1 || (vroom = get_race_by_name(arg1)) <= 0)
      {
         sprintf(buf, "SYSERR: rproc #%d invalid race check.", r->number);
         mudlog(buf, BRF, LEV_IMM, FALSE);
         return RP_RIF;
      }

      // if is no target, or isnt visible, or isnt pc, or not race, skip block
      if (!RTARGET_CHAR(r) || !(ch = get_char_room(RTARGET_CHAR(r), real_room(r->number))) || !IS_PC(ch))
        goto_next_rcom(r);
      else
      if (GET_RACE(ch) != vroom)
        goto_next_rcom(r);
      else
        RPROC_CUR(r) = scan_past_eol(RPROC_CUR(r));
      break;

    case 26:    //!tarcharrace <>
      half_chop(comp_args, arg1, arg2);
      if (!*arg1 || (vroom = get_race_by_name(arg1)) <= 0)
      {
         sprintf(buf, "SYSERR: rproc #%d invalid race check.", r->number);
         mudlog(buf, BRF, LEV_IMM, FALSE);
         return RP_RIF;
      }

      // if is no target, or isnt visible, or isnt pc, or not race, skip block
      if (!RTARGET_CHAR(r) || !(ch = get_char_room(RTARGET_CHAR(r), real_room(r->number))) || !IS_PC(ch))
        goto_next_rcom(r);
      else
      if (GET_RACE(ch) == vroom)
        goto_next_rcom(r);
      else
        RPROC_CUR(r) = scan_past_eol(RPROC_CUR(r));
      break;

    case 27:    //tarcharclass <>
      half_chop(comp_args, arg1, arg2);
      if (!*arg1 || (vroom = get_class_num(arg1)) <= 0)
      {
         sprintf(buf, "SYSERR: rproc #%d invalid class check.", r->number);
         mudlog(buf, BRF, LEV_IMM, FALSE);
         return RP_RIF;
      }

      // if is no target, or isnt visible, or isnt pc, or not class, skip block
      if (!RTARGET_CHAR(r) || !(ch = get_char_room(RTARGET_CHAR(r), real_room(r->number))) || !IS_PC(ch))
        goto_next_rcom(r);
      else
      if (GET_CLASS(ch) != vroom)
        goto_next_rcom(r);
      else
        RPROC_CUR(r) = scan_past_eol(RPROC_CUR(r));
      break;

    case 28:    //!tarcharclass <>
      half_chop(comp_args, arg1, arg2);
      if (!*arg1 || (vroom = get_class_num(arg1)) <= 0)
      {
         sprintf(buf, "SYSERR: rproc #%d invalid class check.", r->number);
         mudlog(buf, BRF, LEV_IMM, FALSE);
         return RP_RIF;
      }

      // if is no target, or isnt visible, or isnt pc, or not class, skip block
      if (!RTARGET_CHAR(r) || !(ch = get_char_room(RTARGET_CHAR(r), real_room(r->number))) || !IS_PC(ch))
        goto_next_rcom(r);
      else
      if (GET_CLASS(ch) == vroom)
        goto_next_rcom(r);
      else
        RPROC_CUR(r) = scan_past_eol(RPROC_CUR(r));
      break;

    case 29:    //tarchargender <>
      half_chop(comp_args, arg1, arg2);
      if (!*arg1 || (vroom = search_block(arg1, genders, FALSE)) <= 0)
      {
         sprintf(buf, "SYSERR: rproc #%d invalid gender check.", r->number);
         mudlog(buf, BRF, LEV_IMM, FALSE);
         return RP_RIF;
      }

      // if is no target, or isnt visible, or isnt pc, or not class, skip block
      if (!RTARGET_CHAR(r) || !(ch = get_char_room(RTARGET_CHAR(r), real_room(r->number))) || !IS_PC(ch))
        goto_next_rcom(r);
      else
      if (GET_SEX(ch) != vroom)
        goto_next_rcom(r);
      else
        RPROC_CUR(r) = scan_past_eol(RPROC_CUR(r));
      break;

    case 30:    //!tarchargender <>
      half_chop(comp_args, arg1, arg2);
      if (!*arg1 || (vroom = search_block(arg1, genders, FALSE)) <= 0)
      {
         sprintf(buf, "SYSERR: rproc #%d invalid gender check.", r->number);
         mudlog(buf, BRF, LEV_IMM, FALSE);
         return RP_RIF;
      }

      // if is no target, or isnt visible, or isnt pc, or not class, skip block
      if (!RTARGET_CHAR(r) || !(ch = get_char_room(RTARGET_CHAR(r), real_room(r->number))) || !IS_PC(ch))
        goto_next_rcom(r);
      else
      if (GET_SEX(ch) == vroom)
        goto_next_rcom(r);
      else
        RPROC_CUR(r) = scan_past_eol(RPROC_CUR(r));
      break;

    default:
      RPROC_CUR(r) = scan_past_eol(RPROC_CUR(r));
      break;
  }

  return RP_RIF;
}

//////////////////////////////////////

// lets do some bounds checking just to make sure -jtrhone
BOOL check_rproc_bounds(rmdata *r)
{
  if (RPROC_CUR(r) < RPROC_BEG(r))
  {
    sprintf(buf, "SYSERR: rproc on room #%d %%B%%1FAILED%%0 lower bounds check.", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return FALSE;
  }

  if (RPROC_CUR(r) > (RPROC_BEG(r) + strlen(RPROC_BEG(r))))
  {
    sprintf(buf, "SYSERR: rproc on room #%d %%B%%1FAILED%%0 upper bounds check.", r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return FALSE;
  }

  return TRUE;
}

// if ch, use ch for subs, else use TARGET_CHAR
// if ob, use ob for subs, else use TARGET_OBJ
BOOL do_rproc_subs(rmdata *r, char *comm, chdata *ch, obdata *ob)
{
  char newcomm[MAX_INPUT_LENGTH];
  int i, j;

  if (!strchr(comm, '+'))
    return FALSE;

  // if ch wasnt passed, try to get a chdata ptr from target char
  if (!ch)
    if (RTARGET_CHAR(r))
      if (!(ch = get_char_room(RTARGET_CHAR(r), real_room(r->number))))
          if (!(ch = get_char(RTARGET_CHAR(r))))
            ;

  for (i=0, j=0; comm[i]; i++)
  {
    newcomm[j] = '\0';
    if (comm[i] != '+')
    {
      newcomm[j] = comm[i];
      j++;
      continue;
    }
    else
    if (comm[i+1])
    {
      i++;
      switch (comm[i])
      {
        case '+': /* double (++) means sub in one + */
          newcomm[j] = comm[i];
          j++; i++;
          break;
        case 'C':   /* sub SHORT (NPC alias, PC normal) name of char target */
          if (ch)
          {
            if (IS_PC(ch))
              strcat(newcomm + j, GET_NAME(ch));
            else
              strcat(newcomm + j, fname(ch->player.name));
            j = strlen(newcomm);
          }
          else
          if (RTARGET_CHAR(r))
          {
            strcat(newcomm + j, RTARGET_CHAR(r));
            j = strlen(newcomm);
          }
          break;
        case 'N': case 'n':     // normal name for pc, short desc for npc
          if (ch)
          {
            strcat(newcomm + j, GET_NAME(ch));
            j = strlen(newcomm);
          }
          else
          if (RTARGET_CHAR(r))
          {
            strcat(newcomm + j, RTARGET_CHAR(r));
            j = strlen(newcomm);
          }
          /* if no sub there, ok, its as if we processed */
         break;

        case 'R': case 'r':
         if (ch)
         {
          strcat(newcomm + j, rcarray[GET_RACE(ch)].race_name);
          j = strlen(newcomm);
         }
          break;

        case 'L': case 'l':
         if (ch)
         {
          strcat(newcomm + j, gskill_names[SPEAKING(ch)]);
          j = strlen(newcomm);
         }
          break;

        case 'H': case 'h':
         if (ch && htowns[GET_HTOWN(ch)].name)
         {
          strcat(newcomm + j, htowns[GET_HTOWN(ch)].name);
          j = strlen(newcomm);
         }
          break;

        case 'c':  /* class, if incog sub race instead */
         if (ch)
         {
          if (PRF_FLAGGED(ch, PRF_INCOGNITO))
            strcat(newcomm + j, rcarray[GET_RACE(ch)].race_name);
          else
            strcat(newcomm + j, clarray[(int)GET_CLASS(ch)].class_name);
          j = strlen(newcomm);
         }
          break;

        case 'O': case 'o':  /* sub name of obj target */
          if (ob)
          {
            strcat(newcomm + j, ob->shdesc);
            j = strlen(newcomm);
          }
          else
          if (RTARGET_OBJ(r))
          {
            strcat(newcomm + j, RTARGET_OBJ(r));
            j = strlen(newcomm);
          }
          /* if no sub there, ok, its as if we processed */
         break;
        default:
          sprintf(buf, "SYSERR:  Undefined +(%c) to rproc #%d.",comm[i+1], r->number);
          mudlog(buf, BRF, LEV_IMM, FALSE);
          return FALSE;
          break;
      }
    }
    else
    {
      sprintf(buf, "SYSERR:  Undefined +sub to rproc #%d.", r->number);
      mudlog(buf, BRF, LEV_IMM, FALSE);
      return FALSE;
    }
  }
  newcomm[j] = '\0';
  strncpy(comm, newcomm, MAX_INPUT_LENGTH - 1);
  return TRUE;
}

// execute and return true if comm is a rproc command
// if reaction, do not execute some mtrig commands or block commands
int rproc_interpreter(rmdata *r, char *comm, chdata *ch, obdata *ob, BOOL reaction)
{
  char arg1[MAX_INPUT_LENGTH];
  char arg2[MAX_INPUT_LENGTH];
  int i;

  if (!ROOM_FLAGGED(real_room(r->number), RPROC))
    return RP_NORMAL;

  half_chop(comm, arg1, arg2);
  for (i = 0; *rproc_calls[i].arg; i++)
    if (is_abbrev(arg1, rproc_calls[i].arg))
    {
      if (reaction)
        if (is_abbrev(arg1, "rtridadd") || is_abbrev(arg1, "rtrigdel") || is_abbrev(arg1, "rtrigwax") ||
            is_abbrev(arg1, "rrandom"))
        {
          sprintf(buf, "SYSERR: %s found in rtrig reaction/random, not parsed (room #%d).", arg1, r->number);
          mudlog(buf, BRF, LEV_IMM, TRUE);
          continue;
        }

      do_rproc_subs(r, arg2, ch, ob);

      // ok, call appropriate function with this command
      return ((*rproc_calls[i].rproc_fn) (r, arg2));
    }

  return RP_NORMAL;
}


// Main rproc interface begins here
// this is called from roomact.c in room_activity()
void do_room_rproc(rmdata *r)
{
  int i;
  int current_command, command_count;
  char *tmp;
  char comm[MAX_INPUT_LENGTH+2];

  if (!RPROC_BEG(r) || !*RPROC_BEG(r))
  {
    sprintf(buf, "SYSERR: room #%d rproc missing instruction set.",r->number);
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return;
  }

  /* check wait states, to see if loop or waiting or finished */
  if (RPROC_WAIT(r) <= -1) return;  /* finished */
  else
  if (RPROC_WAIT(r) > 0)
  {
    RPROC_WAIT(r)--;
    return;  /* waiting for now, see ya */
  }
  else
  if (RTRIGS(r) && RTRIG_WAITING(r))  // waiting for trigger
    return;

  current_command = RP_RIF;
  command_count   = 1;
  while ((current_command == RP_RIF || current_command == RP_RTARGET || 
          current_command == RP_RREMOTE || current_command == RP_RTAG || 
          current_command == RP_RTRIG) && command_count < 5)
  {
    if (!check_rproc_bounds(r))
      return;

    // skip leading white space, allow for nifty look rproc code
    skip_spaces(&RPROC_CUR(r));

    // if we're pointing at close brackets, just skip em
    while ( *RPROC_CUR(r) && *RPROC_CUR(r) == '}' )
      RPROC_CUR(r) = scan_past_eol(RPROC_CUR(r));

    // if null, reset to beginning
    if (!RPROC_CUR(r) || !*RPROC_CUR(r))
      RPROC_CUR(r) = RPROC_BEG(r);

    // get length of next command
    for (i=0, tmp = RPROC_CUR(r); *tmp && !ISNEWL(*tmp) && (i < MAX_INPUT_LENGTH); tmp++, i++)
     ;

    /* copy this command line into comm */
    strncpy(comm, RPROC_CUR(r), i);
    comm[i] = '\0';

    while (*tmp && ISNEWL(*tmp))
      tmp++;

    // reset back to beginning to mproc command list
    if (!*tmp)
      tmp = RPROC_BEG(r);
    RPROC_CUR(r) = tmp;

    // show the room what they typing
    S2IMM(comm,r);

    // send it onto rproc processing
    current_command = rproc_interpreter(r, comm, NULL, NULL, FALSE);

    // prevent infinity -roa
    command_count++;
  }
}