pdirt/data/
pdirt/data/HELP/
pdirt/data/HELP/0/
pdirt/data/HELP/F/
pdirt/data/HELP/G/
pdirt/data/HELP/H/
pdirt/data/HELP/J/
pdirt/data/HELP/K/
pdirt/data/HELP/O/
pdirt/data/HELP/Q/
pdirt/data/HELP/R/
pdirt/data/HELP/U/
pdirt/data/HELP/V/
pdirt/data/HELP/Y/
pdirt/data/HELP/Z/
pdirt/data/MESSAGES/
pdirt/data/POWERINFO/
pdirt/data/WIZ_ZONES/
pdirt/drv/
pdirt/drv/bin/
pdirt/drv/compiler/converter/
pdirt/drv/compiler/libs/
pdirt/drv/compiler/scripts/
pdirt/drv/include/AberChat/
pdirt/drv/include/InterMud/
pdirt/drv/include/machine/
pdirt/drv/src/InterMud/
pdirt/drv/src/Players/
pdirt/drv/utils/UAFPort/
pdirt/drv/utils/dnsresolv/
pdirt/drv/utils/gdbm/
/*****************************************************************************
 ** Actions handler - Combined from dyrt/dirt
 ** Structured by Marty
 *****************************************************************************/
#define ACTIONS_C

#include <malloc.h>
#include <sys/param.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include "kernel.h"
#include "config.h"
#include "sendsys.h"
#include "global.h"
#include "sflags.h"
#include "bprintf.h"
#include "parse.h"
#include "fight.h"
#include "log.h"
#include "special.h"

struct _ext_msg
{
  char code;			/* Codes EXT_TNAM..EXT_ONAM uses this form */
  char *next;			/* Pointer to next part of string. */
};

struct _ext_msg1
{
  struct _ext_msg e;
  char *str;			/* Code EXT_STRING uses this form */
};

struct _ext_msg2
{
  struct _ext_msg e;		/* Codes EXT_TARGET and EXT_ACTOR uses this form */
  char *male_txt;
  char *female_txt;
};

/* struct for the external commands */
typedef struct _ext
{
  struct _ext *next;
  int flags;
  char *verb;
  char *msg_to_all;
  char *msg_to_me;
}
EXTERN_CMD_REC;

/* These are in addition if the command accept a target */
struct _ext2
{
  EXTERN_CMD_REC e;
  char *msg_to_target;
  char *msg_to_sender;
  char *msg_to_others;
};

/* Datatypes */
static char *ext_msg_names[] =
{"all", "me", "target", "sender", "others",
   TABLE_END};

static char *s_ext[] =
{ "Flowers", 	"Hate",		"Koosh",	"Nod",		"Pet",		
  "Pray", 	"Rose",		"Tickle",	"Wave", 
  TABLE_END
};

/* code is one of the following: */
#define EXT_STRING 1		/* insert string here */
#define EXT_TARGET 2		/* Select string on psex(target) */
#define EXT_ACTOR  3		/* Select string on psex(actor) */
#define EXT_TNAM   4		/* insert pname(target) here */
#define EXT_ANAM   5		/* insert pname(actor) here */
#define EXT_THIM   6		/* Insert psex(target) ? "her" : "him" here */
#define EXT_AHIM   7		/* Insert psex(actor)  ? "her" : "him" here */
#define EXT_THIS   8		/* Insert psex(target) ? "her" : "his" here */
#define EXT_AHIS   9		/* Insert psex(actor)  ? "her" : "his" here */
#define EXT_ONAM  10		/* Insert oname(ob2) here if EXTF_OBJ */
#define EXT_MTXT  11		/* Insert user text via %s here */

#define EXT_ERROR ((char *)(-2))	/* Error return from various functions. */

#define EXTF_ALL     0x01
#define EXTF_SINGLE  0x02
#define EXTF_HOSTILE 0x04
#define EXTF_ALOOF   0x08
#define EXTF_OBJ     0x10	/* Command takes an object as arg */
#define EXTF_TEXT    0x20	/* Command accepts a string at the end */
#define EXTF_FAR     0x40	/* Target may be in other room */

#define EXT_MSG_ALL      0
#define EXT_MSG_ME       1
#define EXT_MSG_TARGET   2
#define EXT_MSG_SENDER   3
#define EXT_MSG_OTHERS   4

#define EXT_ANGLE_OPEN    0x100	/* %< ok? */
#define EXT_ANGLE_MIDDLE  0x200	/* %: ok? */
#define EXT_ANGLE_CLOSE   0x400	/* %> ok? */
#define EXT_SQ_MIDDLE     0x800	/* %/ ok? */
#define EXT_SQ_CLOSE     0x1000	/* %] ok? */
#define EXT_HAT          0x2000	/* %^ or %~ ok? */
#define EXT_T            0x2000	/* %t ok? */
#define EXT_O            0x4000	/* %o ok? */
#define EXT_M            0x8000	/* %m ok? */

static void ext_free_msg (char *s);
static int ext_get_tok (void);
static char *ext_get_itm (void);
static char *ext_get_string (void);
static char *ext_get_simple (int code);
static char *ext_get_mf (int code, int middle, int end,
			 int fla_m, int fla_c);
static struct _ext_msg *ext_mk_struct (char *s);
static char *ext_get_anything (void);
static char *ext_get_msg (int *w, FILE * f, int bsiz, int l, int h,
			  int *mem_used);
static char *build_action (char *a);

EXTERN_CMD_REC *externs;
static char *buffer;
static char *bufp;
static int cur_tok;
static int ext_who;
static int mused;
static int ext_lino;
static int ext_flags;

/*
 * Function to free a msg.
 */

static void ext_free_msg (char *s)
{
  if (s == NULL || s == EXT_ERROR)
    return;
  if (*s < ' ' || *s > '~')
  {
      switch (((struct _ext_msg *) s)->code) {
      case EXT_STRING:
	  ext_free_msg (((struct _ext_msg1 *) s)->str);
	  break;
      case EXT_TARGET:
      case EXT_ACTOR:
	  ext_free_msg (((struct _ext_msg2 *) s)->male_txt);
	  ext_free_msg (((struct _ext_msg2 *) s)->female_txt);
	  break;
      case EXT_TNAM:
      case EXT_ANAM:
      case EXT_THIM:
      case EXT_AHIM:
      case EXT_THIS:
      case EXT_AHIS:
      case EXT_ONAM:
	  break;
      default:
	  mudlog ("Illegal extern code %d\n", ((struct _ext_msg *) s)->code);
	  return;		/* Don't free anything */
      }
      ext_free_msg (((struct _ext_msg *) s)->next);	/* Free the next part */
  }
  free (s);
}

void clear_all_ext(void)
{  EXTERN_CMD_REC *r,*p;
  
   p = externs;
   while (p != NULL)
   {  r = p->next;
      ext_free_msg(p->verb);
      p = r;
   }
}

static int ext_get_tok (void)
{
  int c;
  int k;
  
  if ((c = *bufp++) == '%')
  {
     switch (c = *bufp++) {
     case 'A':
	  c = 'a';
     case 'a':
     case '[':
	  return cur_tok = 0400 + c;
     case '%':
	  return cur_tok = c;
     case '<':
	  k = EXT_ANGLE_OPEN;
	  break;
     case ':':
	  k = EXT_ANGLE_MIDDLE;
	  break;
     case '>':
	  k = EXT_ANGLE_CLOSE;
	  break;
     case '~':
     case '^':
	  k = EXT_HAT;
	  break;
     case 'T':
	  c = 't';
     case 't':
	  k = EXT_T;
	  break;
     case '/':
	  k = EXT_SQ_MIDDLE;
	  break;
     case ']':
	  k = EXT_SQ_CLOSE;
	  break;
     case 'O':
	  c = 'o';
     case 'o':
	  k = EXT_O;
	  break;
     case 'M':
	  c = 'm';
     case 'm':
	  k = EXT_M;
	  break;
     default:
	  k = 0;
     }
     if (k != 0 && (ext_flags & k) != 0)
	return cur_tok = c + 0400;
     c = '%';
     --bufp;
  }
  if (c < ' ' || c > '~')
    c = 0;
  return cur_tok = c;
}

static char *ext_get_itm (void)
{
  switch (cur_tok) {
  case 0400 + '<':
      return ext_get_mf (EXT_TARGET, ':', '>', EXT_ANGLE_MIDDLE, EXT_ANGLE_CLOSE);
  case 0400 + '[':
      return ext_get_mf (EXT_ACTOR, '/', ']', EXT_SQ_MIDDLE, EXT_SQ_CLOSE);
  case 0400 + '/':
  case 0400 + ':':
  case 0400 + '>':
  case 0400 + ']':
  case 0:
      return NULL;
  case 0400 + '^':
      return ext_get_simple (ext_who == EXT_MSG_SENDER ? EXT_THIS : EXT_AHIS);
  case 0400 + '~':
      return ext_get_simple (ext_who == EXT_MSG_SENDER ? EXT_THIM : EXT_AHIM);
  case 0400 + 'a':
      return ext_get_simple (EXT_ANAM);
  case 0400 + 't':
      return ext_get_simple (EXT_TNAM);
  case 0400 + 'o':
      return ext_get_simple (EXT_ONAM);
  case 0400 + 'm':
      ext_flags &= ~EXT_M;
      return ext_get_simple (EXT_MTXT);
  }
  return ext_get_string ();
}

static char *ext_get_string (void)
{
  char b[256];
  int c = cur_tok;
  int ct = 0;
  
  while (c >= ' ' && c <= '~')
  {
     b[ct++] = c;
     c = ext_get_tok ();
  }
  if (ct == 0)
    return NULL;
  
  mused += ct + 1;
  b[ct] = '\0';
  return COPY (b);
}

static char *ext_get_simple (int code)
{
  struct _ext_msg *m;
  
  (void) ext_get_tok ();
  m = NEW (struct _ext_msg, 1);
  m->code = code;
  m->next = NULL;
  mused += sizeof (struct _ext_msg);
  
  return (char *) m;
}

static char *ext_get_mf (int code, int middle, int end, int fla_m, int fla_c)
{
  struct _ext_msg2 *s;
  char *m, *f;
  int flags = ext_flags;
  
  (void) ext_get_tok ();
  ext_flags |= fla_m | fla_c;
  
  if ((m = ext_get_anything ()) == EXT_ERROR)
  {
     ext_flags = flags;
     return EXT_ERROR;
  }
  
  f = NULL;
  ext_flags = flags;
  
  if (cur_tok == 0400 + middle)
  {
     ext_flags |= fla_c;
     (void) ext_get_tok ();
     if ((f = ext_get_anything ()) == EXT_ERROR)
     {
        ext_free_msg (m);
        ext_flags = flags;
        return EXT_ERROR;
     }
     ext_flags = flags;
  }
  
  if (cur_tok == 0400 + end)
    (void) ext_get_tok ();
    
  s = NEW (struct _ext_msg2, 1);
  ((struct _ext_msg *) s)->next = NULL;
  ((struct _ext_msg *) s)->code = code;
  s->male_txt = m;
  s->female_txt = f;
  mused += sizeof (struct _ext_msg2);
  return (char *) s;
}

static struct _ext_msg *ext_mk_struct (char *s)
{
  struct _ext_msg1 *m;
  int c;
  
  if (s == NULL || s == EXT_ERROR)
    return (struct _ext_msg *) s;
    
  if (*s >= ' ' && *s <= '~')
  {
     m = NEW (struct _ext_msg1, 1);
     m->str = s;
     ((struct _ext_msg *) m)->code = EXT_STRING;
     ((struct _ext_msg *) m)->next = NULL;
     mused += sizeof (struct _ext_msg1);
     return (struct _ext_msg *) m;
  }
  c = ((struct _ext_msg *) s)->code;
  
  if (c >= EXT_STRING && c <= EXT_ONAM)
    return (struct _ext_msg *) s;
    
  mudlog ("ext_mk_struct: Illegal ext code %d", c);
  return (struct _ext_msg *) EXT_ERROR;
}

static char *ext_get_anything (void)
{
  struct _ext_msg *first, *second_last;
  char *s, *t;
  
  if ((s = ext_get_itm ()) == NULL || s == EXT_ERROR)
    return s;
  if ((t = ext_get_itm ()) == EXT_ERROR)
  {
     ext_free_msg (s);
     return EXT_ERROR;
  }
  if (t == NULL)
    return s;
  
  /* build a list with s as first and t as last */
  second_last = first = ext_mk_struct (s);	/* make sure s is a struct */
  first->next = t;
  while ((s = ext_get_itm ()) != NULL && s != EXT_ERROR)
  {
     /* Make sure last is a struct */
     second_last->next = (char *) ext_mk_struct (second_last->next);
      
     /* move second_last to point to last */
     second_last = (struct _ext_msg *) second_last->next;
      
     second_last->next = s;	/* append s to the list */
  }
  if (s == EXT_ERROR)
  {
      /* Clear the list */
      ext_free_msg ((char *) first);
      return EXT_ERROR;
  }
  return (char *) first;
}

static char *ext_get_msg (int *w, FILE * f, int bsiz, int l, int h, 
                          int *mem_used)
{
  char *s;
  int x = *w;
  int fl = ext_flags;
  
  if (bufp == EXT_ERROR)
    return EXT_ERROR;
    
  if (feof (f) || fgets (buffer, bsiz, f) == NULL)
    return NULL;
    
  ++ext_lino;
  bufp = buffer;
  if ((s = strchr (bufp, ':')) != NULL && s > bufp)
  {
     *s = 0;
     if ((x = tlookup (bufp, ext_msg_names)) < l || x > h)
     {
        x = *w;
     } else
     {
	  *w = x;
	  bufp = s + 1;
     }
     *s = ':';
  }
  
  if ((ext_who = x) >= EXT_MSG_TARGET)
  {
      ext_flags |= EXT_T | EXT_ANGLE_OPEN;
  }
  if (x < EXT_MSG_OTHERS)
  {
      ext_flags |= EXT_HAT;
  }
  
  mused = 0;
  (void) ext_get_tok ();
  if ((s = ext_get_anything ()) == EXT_ERROR)
  {
      ext_flags = fl;
      return bufp = EXT_ERROR;
  }
  if (cur_tok != 0)
  {
      ext_free_msg (s);
      printf ("Illegal syntax in actions file\n");
      ext_flags = fl;
      return bufp = EXT_ERROR;
  }
  *mem_used += mused;
  ext_flags = fl;
  
  if (s != NULL)
    ext_flags |= (1 << x);
  return s;
}

static void dump_action (EXTERN_CMD_REC * v)
{
  if (v == NULL)
    return;
  bprintf ("Data about %s:\n", v->verb);
  bprintf ("Next verb: %s\n", (v->next == NULL) ? "<none>" : v->next->verb);
  bprintf ("Flags: ");
  if ((v->flags & EXTF_ALL) != 0)
    bprintf ("a");
  if ((v->flags & EXTF_SINGLE) != 0)
    bprintf ("s");
  if ((v->flags & EXTF_HOSTILE) != 0)
    bprintf ("h");
  if ((v->flags & EXTF_ALOOF) != 0)
    bprintf ("i");
  if ((v->flags & EXTF_FAR) != 0)
    bprintf ("f");
  if ((v->flags & EXTF_OBJ) != 0)
    bprintf ("o");
  if ((v->flags & EXTF_TEXT) != 0)
    bprintf ("t");
  bprintf ("\n");
  
  if ((v->flags & EXTF_ALL) != 0)
  {
      bprintf ("Msg to all: %s\n", build_action (v->msg_to_all));
      bprintf ("Msg to me: %s\n", build_action (v->msg_to_me));
  }
  
  if ((v->flags & EXTF_SINGLE) != 0)
  {
     bprintf ("Msg to target: %s\n",
	       build_action (((struct _ext2 *) v)->msg_to_target));
     bprintf ("Msg to sender: %s\n",
	       build_action (((struct _ext2 *) v)->msg_to_sender));
     if (((struct _ext2 *) v)->msg_to_others != NULL)
     {
	  bprintf ("Msg to others: %s\n",
		   build_action (((struct _ext2 *) v)->msg_to_others));
     }
  }
  bprintf ("\n");
}

static void dump_act_vb (char *s)
{
  EXTERN_CMD_REC *v;
  int i;
  
  for (v = externs; v != NULL && !EQ (v->verb, wordbuf); v = v->next);
  if (v == NULL)
  {
     if ((i = tlookup (wordbuf, s_ext)) < 0)
     {
	  bprintf ("I don't know about any %s action.\n", wordbuf);
     } else
     {
	  bprintf ("%s is a special action.\n", s_ext[i]);
     }
  } else
  {
      dump_action (v);
  }
}

int boot_extern (FILE * f, char *fname)
{
  char buff[256];
  char *verb;
  EXTERN_CMD_REC *first = NULL, *last = NULL, *this;
  int flags;
  int i, j, low, high;
  
  char *s, *t;
  int mem_used = 0;
  int m_used = 0;
  int lino = 0;
  char *msgs[5];
  
  buffer = buff;
  externs = NULL;
  while (!feof (f) && fgets (buff, sizeof buff, f) != NULL)
  {
     ++ext_lino;
     if (*buff != ':')
	continue;
     s = buff;
     while (*++s == ' ' || *s == '\t');
     t = s;
     while (isalpha (*t))
	++t;
     *t = 0;
     if (t == s)
     {
	  /* No verb given */
	  printf ("Error in actions file line %d, no verb given.", lino);
	  continue;
     }
     verb = COPY (s);
     lowercase (verb);
     m_used = strlen (s) + 1;
     flags = 0;
     do
     {
        ++t;
     } while (*t != '\0' && !isalpha (*t));
     
     while (isalpha (*t))
     {
        switch (*t++) {
        case 'h':
	case 'H':
	      flags |= EXTF_HOSTILE;
	      break;
	case 'i':
	case 'I':
	      flags |= EXTF_ALOOF;
	      break;
	case 'a':
	case 'A':
	      flags |= EXTF_ALL;
	      break;
	case 's':
	case 'S':
	      flags |= EXTF_SINGLE;
	      break;
	case 'o':
	case 'O':
	      flags |= EXTF_OBJ;
	      break;
	case 't':
	case 'T':
	      flags |= EXTF_TEXT;
	      break;
	case 'f':
	case 'F':
	      flags |= EXTF_FAR;
	      break;
	}
     }
      
     if ((flags & EXTF_SINGLE) == 0)
	flags |= EXTF_ALL;
      
     low = ((flags & EXTF_ALL) != 0) ? EXT_MSG_ALL : EXT_MSG_TARGET;
     high = ((flags & EXTF_SINGLE) != 0) ? EXT_MSG_OTHERS : EXT_MSG_ME;
     ext_flags = 0;
     
     if ((flags & EXTF_OBJ) != 0)
	ext_flags |= EXT_O;
      
     for (i = EXT_MSG_ALL; i <= EXT_MSG_OTHERS;)
	msgs[i++] = NULL;
     for (i = low; i <= high; i++)
     {
        j = i;
	if ((flags & EXTF_TEXT) != 0)
	    ext_flags |= EXT_M;
	s = ext_get_msg (&j, f, sizeof buff, low, high, &m_used);
	if (s == EXT_ERROR)
	    break;
	if ((t = msgs[j]) != NULL)
	{
	   mudlog ("ACTION: Double definition for msg for verb %s.\n", verb);
	   ext_free_msg (t);
	}
	msgs[j] = s;
     }
      
     if (s == EXT_ERROR)
     {
	mudlog ("ACTION: Error in actions file for verb %s, error in messages.\n",
	         verb);
     } else
     {
         s = NULL;
	 if (low == EXT_MSG_ALL && (ext_flags & 0x03) != 0x03)
	 {
	    mudlog ("ACTION: Error in actions file for verb %s, missing ALL messages.\n",
		     verb);
	    s = EXT_ERROR;
	 }
	 else if (high == EXT_MSG_OTHERS && (ext_flags & 0x0c) != 0x0c)
	 {
	    mudlog ("ACTION: Error in actions file for verb %s, missing TARGET messages.\n",
	             verb);
	    s = EXT_ERROR;
	 }
      }
      if (s == EXT_ERROR)
      {
	  for (i = EXT_MSG_ALL; i <= EXT_MSG_OTHERS; i++)
	  {
	      if ((s = msgs[i]) != NULL)
		ext_free_msg (s);
	  }
	  free (verb);
	  continue;
      }
      if ((ext_flags & 0x0c) == 0x0c)
      {
	  this = (EXTERN_CMD_REC *) NEW (struct _ext2, 1);
	  m_used += sizeof (struct _ext2);
	  ((struct _ext2 *) this)->msg_to_target = msgs[EXT_MSG_TARGET];
	  ((struct _ext2 *) this)->msg_to_sender = msgs[EXT_MSG_SENDER];
	  ((struct _ext2 *) this)->msg_to_others = msgs[EXT_MSG_OTHERS];
      }
      else
      {
	  this = NEW (EXTERN_CMD_REC, 1);
	  m_used += sizeof (EXTERN_CMD_REC);
      }
      this->next = NULL;
      this->flags = flags;
      this->verb = verb;
      this->msg_to_all = msgs[EXT_MSG_ALL];
      this->msg_to_me = msgs[EXT_MSG_ME];
      
      /*    dump_action(this); */
      if (first == NULL)
      {
	  first = last = this;
      }
      else
      {
	  last->next = this;
	  last = this;
      }
      mem_used += m_used;
  }
  externs = first;
  return mem_used;
}

static char *ext_copy (char *b, char *m)
{
  char *p;
  char v[50];
  
  if (m == NULL || m == EXT_ERROR)
    {
      *b = 0;
      return b;
    }
  if (*m >= ' ' && *m <= '~')
    return x_strcpy (b, m);
  p = v;
  switch (((struct _ext_msg *) m)->code)
    {
    case EXT_STRING:
      p = ((struct _ext_msg1 *) m)->str;
      break;
    case EXT_TARGET:
      p = psex (pl1) ? ((struct _ext_msg2 *) m)->female_txt :
	((struct _ext_msg2 *) m)->male_txt;
      break;
    case EXT_ACTOR:
      p = (psex (mynum) ? ((struct _ext_msg2 *) m)->female_txt :
	   ((struct _ext_msg2 *) m)->male_txt);
      break;
    case EXT_TNAM:
      sprintf (p, "\001p%s\003", pname (pl1));
      break;
    case EXT_ANAM:
      sprintf (p, "\001p%s\003", pname (mynum));
      break;
    case EXT_THIM:
      p = psex (pl1) ? "her" : "him";
      break;
    case EXT_AHIM:
      p = psex (mynum) ? "her" : "him";
      break;
    case EXT_THIS:
      p = psex (pl1) ? "her" : "his";
      break;
    case EXT_AHIS:
      p = psex (mynum) ? "her" : "his";
      break;
    case EXT_ONAM:
      p = oname (ob2);
      break;
    case EXT_MTXT:
      p = "%s";
    default:
      return b;
    }
  b = x_strcpy (b, p);
  return ext_copy (b, ((struct _ext_msg *) m)->next);
}

static char *
build_act_msg (char *b, char *m)
{
  if (m == NULL || m == EXT_ERROR)
    {
      *b = 0;
      return b;
    }
  if (*m >= ' ' && *m <= '~')
    return x_strcpy (b, m);
  switch (((struct _ext_msg *) m)->code)
    {
    case EXT_STRING:
      b = x_strcpy (b, ((struct _ext_msg1 *) m)->str);
      break;
    case EXT_TARGET:
      *b++ = '%';
      *b++ = '<';
      b = build_act_msg (b, ((struct _ext_msg2 *) m)->male_txt);
      *b++ = '%';
      *b++ = ':';
      b = build_act_msg (b, ((struct _ext_msg2 *) m)->female_txt);
      *b++ = '%';
      *b++ = '>';
      break;
    case EXT_ACTOR:
      *b++ = '%';
      *b++ = '[';
      b = build_act_msg (b, ((struct _ext_msg2 *) m)->male_txt);
      *b++ = '%';
      *b++ = '/';
      b = build_act_msg (b, ((struct _ext_msg2 *) m)->female_txt);
      *b++ = '%';
      *b++ = ']';
      break;
    case EXT_TNAM:
      *b++ = '%';
      *b++ = 't';
      break;
    case EXT_ANAM:
      *b++ = '%';
      *b++ = 'a';
      break;
    case EXT_THIM:
    case EXT_AHIM:
      *b++ = '%';
      *b++ = '~';
      break;
    case EXT_THIS:
    case EXT_AHIS:
      *b++ = '%';
      *b++ = '^';
      break;
    case EXT_ONAM:
      *b++ = '%';
      *b++ = 'o';
      break;
    case EXT_MTXT:
      *b++ = '%';
      *b++ = 'm';
      break;
    default:
      return b;
    }
  *b = 0;
  return build_act_msg (b, ((struct _ext_msg *) m)->next);
}

static char *
build_action (char *a)
{
  static char b[256];
  char *t;
  
  t = build_act_msg (b, a);
  *t = 0;
  return b;
}

/*
 * **  (C) Brian Preble (rassilon@eddie.mit.edu)
 * **  Handles external commands such as Kiss, Hug, Tickle, etc.
 * **
 * **  Enhancements of Alf.
 */
int 
fextern (char *verb)
{
  struct _ext *v;
  char *m;
  int p;
  int o;
  char b[MAX_COM_LEN];
  char b2[MAX_COM_LEN];
  char b3[MAX_COM_LEN];
  
  v = externs;
  verb = strcpy (b, verb);
  o = -1;
  /* Stupid, parse_2, doesn't use vb, but we must give one */
  if (!parse_2 (1))
    return -1;
  
  for (; v != NULL; v = v->next)
    {
      if (!EQ (verb, v->verb))
	continue;

      stp = 0;
      (void) brkword ();
      if ((v->flags & EXTF_ALL) == 0)
	{
	  if (pl1 < 0)
	    continue;
	  p = pl1;
	  brkword ();		/* skip player */
	  if ((v->flags & EXTF_OBJ) != 0)
	    {
	      if (ob2 < 0)
		continue;
	      o = ob2;
	      brkword ();
	    }
	}
      else if ((v->flags & EXTF_SINGLE) == 0)
	{
	  p = -1;
	  if ((v->flags & EXTF_OBJ) != 0)
	    {
	      if (ob1 < 0)
		continue;
	      o = ob1;
	      brkword ();	/* Skip object */
	    }
	}
      else if ((p = pl1) < 0)
	{
	  if ((v->flags & EXTF_OBJ) != 0)
	    {
	      if (ob1 < 0)
		continue;
	      o = ob1;
	      brkword ();
	    }
	}
      else
	{
	  brkword ();
	  if ((v->flags & EXTF_OBJ) != 0)
	    {
	      if (ob2 < 0)
		continue;
	      o = ob2;
	      brkword ();
	    }
	}
      if ((v->flags & EXTF_TEXT) != 0)
      {
	  getreinput (b3);
	  if (EMPTY (b3))
	    continue;
      }
      else
      {
	  *b3 = '\0';
      }
      ob2 = o;
      /* Now pl1 >= 0 if target, ob2 >= 0 if object and b3 is !EMPTY if txt */
      /* Verb found */
      
      if (pfighting (mynum) >= 0)
      {
         bprintf ("Not in a fight!\n");
         return 0;
      }
     
      if (psitting(mynum) > 1 && plev(mynum) < LVL_APPREN)
      {   bprintf("You're fantasizing in your dreams again eh?\n");
          return 0;
      }
 
      if ((v->flags & EXTF_HOSTILE) != 0 && pl1 >= 0)
      {
	  if (testpeace (mynum))
	  {
	      bprintf ("Nah, that's violent.\n");
	      return 0;
          }
      }
      if (p < 0)
      {
          if (ob1 > 0 && obj_fun(ob1) != NULL)
          {   param_s.ob = ob1;
              param_s.plx = mynum;
              param_s.pl = p;
              param_s.loc = ploc(mynum);
              param_s.ret = 1;
              param_s.buf = v->verb;
              obj_fun(ob1)(E_ONACTION);
              if (param_s.ret != 1)
                 return param_s.ret;
          }
	  (void) ext_copy (b, v->msg_to_all);
	  sprintf (b2, b, b3);
	  sprintf (b, "\001s%%s\003%s\n\003", b2);
	  sillycom (b);
	  (void) ext_copy (b, v->msg_to_me);
	  sprintf (b2, b, b3);
	  bprintf ("%s\n", b2);
	  return 0;
     }
     
     if (pvis(p) > plev(real_mynum))
     {    bprintf("Good trick, that.\n");
          return 0;   
     }

     if ((v->flags & EXTF_FAR) == 0 && ploc (pl1) != ploc (mynum))
     {
	  bprintf ("%s is not here.\n", psex (pl1) ? "She" : "He");
	  return 0;
     }

     if (p == mynum)
     {
	  bprintf ("Good trick, that.\n");
	  return 0;
     }
     if ((v->flags & EXTF_ALOOF) != 0 && ststflg (p, SFL_ALOOF) &&
         plev (mynum) < LVL_APPREN)
     {
	  bprintf ("%s thinks %s's too good for mere mortals.\n",
		   pname (p), (psex (p) ? "she" : "he"));
	  return 0;
     }
      
     if (mob_fun(p) != NULL)
     {  param_s.plx = mynum;
        param_s.pl  = p;
        param_s.buf = v->verb;
        param_s.ret = 1;
        param_s.loc = ploc(mynum);
        mob_fun(p)(E_ONACTION);
        if (param_s.ret != 1)
           return param_s.ret;
     }
     
     ext_copy (b2, ((struct _ext2 *) v)->msg_to_target);
     sprintf (b, b2, b3);
     m = b + strlen (b);
     strcpy (m, "\n");
     send_msg (p, 0, LVL_MIN, LVL_MAX, NOBODY, NOBODY, b);
     if ((m = ((struct _ext2 *) v)->msg_to_others) != NULL)
     {
	 ext_copy (b2, m);
	 sprintf (b, b2, b3);
	 send_msg (ploc (mynum), 0, pvis (mynum), LVL_MAX, real_mynum, p,
		   "%s\n", b);
     }
     ext_copy (b2, ((struct _ext2 *) v)->msg_to_sender);
     sprintf (b, b2, b3);
     bprintf ("%s\n", b);
      
     /* Hostile action? */
     if ((v->flags & EXTF_HOSTILE) != 0 && p >= max_players)
     {
        hit_player (p, mynum, pwpn (p));
     }
     return 0;
  }
  return -1;			/* Command not found in extern list */
}

/*
 * **  Displays list of external commands such as Kiss, Hug, Tickle, etc.
 */
/*int lisextern (void)*/
A_COMMAND(lisextern)
{
  char line[80];
  int i = -1;
  char **t;
  EXTERN_CMD_REC *v;
  FILE *fp;
  char fn[50];
 
  if (brkword () != -1)
  {
      dump_act_vb (wordbuf);
  }
  else
  {   sprintf(fn,"%s/%s.actions",TEMP_DIR,pname(mynum));
      if ((fp = fopen(fn,"w")) != NULL)
      {   fprintf(fp,"The following actions are defined:\n");
          for (v = externs; v != NULL; v = v->next)
          {  ++i;
	     if (i % 9 == 0)
	         fprintf (fp,"\n");
	     strcpy (line, v->verb);
	     *line = toupper (*line);
	     fprintf (fp,"%s\t", line);
          }
          for (t = s_ext; *t != TABLE_END; ++t)
          {  ++i;
	     if (i % 9 == 0)
	        fprintf (fp,"\n");
	     fprintf (fp,"%s%c", *t, t[1] == TABLE_END ? '\n' : '\t');
          }
          fprintf (fp,"\n");
          
          fclose(fp);
          read_file(fn,NULL,True,NULL);
          unlink(fn);
      }    
      else
      {   fwerror(fn);
          bprintf ("Dumping directly to screen instead.\nThe following actions are defined:\n");
          for (v = externs; v != NULL; v = v->next)
          { ++i;
	    if (i % 9 == 0)
	       bprintf ("\n");
	    strcpy (line, v->verb);
	    *line = toupper (*line);
	    bprintf ("%s\t", line);
          }
          for (t = s_ext; *t != TABLE_END; ++t)
          {
	    ++i;
	    if (i % 9 == 0)
	       bprintf ("\n");
	    bprintf ("%s%c", *t, t[1] == TABLE_END ? '\n' : '\t');
          }
          bprintf ("\n");
      }
  }
/*  return 0;*/
}