/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *                       ABERED (AberMUD Dirt3 editor)                       *
 *                                                                           *
 *    Handle the input and output of mobile data. Input is driven by io.c    *
 *  while output to stdout can come from mob.c, and to a file from io.c      *
 *                                                                           *
 *           Copyright (C) 1993 James Willie. All rights reseved.            *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include <stdio.h>
#include <ctype.h>

#include "types.h"
#include "macros.h"
#include "extern.h"
#include "prototyp.h"

#ifdef ANSI_C
static void flg_read(int  n, PMOB m, FILE *f);
#else
static void flg_read(n,m,f);
#endif

extern int line;

char *Mob_tab[] = {
    "Name",      "Pname",     "Location",   "Description",
    "End",       "Strength",  "Damage",     "Aggression",
    "Armor",     "Speed",     "Pflags",     "Sflags",
    "Mflags",    "Examine",
    TABLE_END
};

/*
**  The guts of the input routine for mobiles. Reads things a line at a time
**  deciding what each line is, and the reading the rest, putting it back
**  as appropriate. It returns NULL to a driving program if a control % is
**  found, or an error is found.
*/
PMOB read_dirt_mob(f)
	FILE *f;
{
  PMOB m;
  char s[128], n[128];
  int c, d, k, i, x;
  char *t;

  m = NULL;
  for (;;) 
  {
    /* Skip blanks */
    for(c = getc(f); isspace(c); c = getc(f))
    {
      if (c == '\n')
        line++;
    }

    for (t = s; isalnum(c) || c == '_';c = getc(f))
      *t++ = c;
    *t = 0;
    if (t == s) 
    {
      if (c == EOF) 
        return FALSE;
      if (c != '%')
        continue;
      ungetc(c,f);
      return NULL;
      break;
    }
    i = -1;
    while (c == ' ' || c == '\t' || c == '=')
      c = getc(f);
    ungetc(c,f);
    k = lookup(Mob_tab, s);

#ifdef DEBUG
    printf("%s[%4d]\n",s,k);
#endif

    if (k != MOB_NAME && m == NULL) 
    {
      printf("Error on line %d: Entry %s is out of sequence.\n", line, s);
      exit(1);
    }
    switch (k) 
    {
      case MOB_NAME:
        d = 0;
        c = getc(f);
        for (t = n; isalnum(c) || c == '_'; c = getc(f)) 
          *t++ = c;
        *t = 0;
        ungetc(c,f);
        if ((m = NEW(MOB)) == NULL)
        {
          printf("Can't create mobile, Out of memory error\n");
          exit(1);
        }
        init_mob(m,n);
        break;

      case MOB_PNAME:
        if (c == '"')
        {
          c = getc(f);
          m->pname = get_text(f, '"');
          line += text_lines;
        }
        else
        {
          get_word(n,f);
          free(m->pname);
          m->pname = COPY(n);
        }
        break;

      case MOB_LOC:
        for (t = n, c = getc(f); isalnum(c) || c == '_'; c = getc(f)) 
          *t++ = c;
        *t = 0;
	ungetc(c, f);
        m->locname = COPY(n);
        m->loc = flbname(n);
        break;

      case MOB_DESC:
        /* Hopefully skip any leading new line chars etc. */
        for(c = getc(f); (isspace(c) || (c == '"')); c = getc(f))
        {
          if (c == '\n')
            line++;
        }
        ungetc(c,f);
        m->desc = get_text(f, '"');
        line += text_lines;
        break;

      case MOB_END:
        d = 0;
        c = getc(f);
        for (t = n; isalnum(c) || c == '_'; c = getc(f)) 
          *t++ = c;
        *t = 0;
        ungetc(c,f);
        if (!EQ(m->name,n))
        {
          printf("Error on line %d: Wrong name on end for mob %s\n",
                 line, m->name);
        }
        return m;
        break;

      case MOB_STR:
        m->hp = get_int(f, &x);
        gint_error(x, Mob_tab[x], m->name);
        break;
      case MOB_ARMOR:
        m->armor = get_int(f, &x);
        gint_error(x, Mob_tab[x], m->name);
        break;
      case MOB_DAM:
        m->damage = get_int(f, &x);
        gint_error(x, Mob_tab[x], m->name);
        break;
      case MOB_AGG:
        m->agg = get_int(f, &x);
        gint_error(x, Mob_tab[x], m->name);
        break;
      case MOB_SPEED:
        m->speed = get_int(f, &x);
        gint_error(x, Mob_tab[x], m->name);
        break;
      case MOB_EXAM:
        /* Get the next char, a " and then read till we find 1 \n, or a char */
        getc(f);
        while(((c = getc(f)) != EOF) && isspace(c) && (c != '\n'))
          ;
        if (c == '\n')
          line++;
        else
          ungetc(c,f);
        m->exam  = get_text(f, '"');
        line += text_lines;
        break;
      case MOB_SFLAGS:
        flg_read(1,m,f);
        break;
      case MOB_PFLAGS:
        flg_read(3,m,f);
        break;
      case MOB_MFLAGS:
        flg_read(2,m,f);
        break;
      default:
        fprintf(stderr,"\nError on line %d: Unknown entry [%s]\n", line, s);
        exit(1);
    }
    while ((c = getc(f)) != '\n') 
    {
      if (c == EOF)
        return FALSE;
    }
    line++;
  }
  return NULL;
}

/*
**  Writes a single mobile in dirt format to file f
*/
void write_dirt_mob(m,f)
	PMOB m;
	FILE *f;
{
  int i;
  Bool p = FALSE, s = FALSE, b = FALSE;

  if ((m == NULL) || (m == me))
  {
    printf("That mobile has no statistics\n");
    return;
  }
  fprintf(f,"Name          = %s\n", m->name);
  fprintf(f,"Pname         = \"%s\"\n", m->pname);
  fprintf(f,"Location      = %s\n",
          (m->loc == NULL) ? m->locname : m->loc->name);
  fprintf(f,"Strength      = %d\n", m->hp);
  fprintf(f,"Damage        = %d\n", m->damage);
  fprintf(f,"Armor         = %d\n", m->armor);
  fprintf(f,"Speed         = %d\n", m->speed);
  fprintf(f,"Aggression    = %d\n", m->agg);

  /* Decide if we need to write any of slfags, pflags or mflags */
  for (i = 0; (i < NUM_PFLAGS) || (i < NUM_MFLAGS) || (i < NUM_SFLAGS); i++)
  {
    if ((i < NUM_PFLAGS) && (m->pflags[i] == TRUE))
      p = TRUE;
    if ((i < NUM_MFLAGS) && (m->mflags[i] == TRUE))
      b = TRUE;
    if ((i < NUM_SFLAGS) && (m->sflags[i] == TRUE))
      s = TRUE;
  }
  if (p == TRUE)
  {
    fprintf(f,"Pflags        {");
    for (i = 0; i < NUM_PFLAGS; i++)
      if ((m->pflags[i] == TRUE) && (!EMPTY(p_flags[i])))
        fprintf(f," %s", p_flags[i]);
    fprintf(f," }\n");
  }
  if (b == TRUE)
  {
    fprintf(f,"Mflags        {");
    for (i = 0; i < NUM_MFLAGS; i++)
      if ((m->mflags[i] == TRUE) && (!EMPTY(m_flags[i])))
        fprintf(f," %s", m_flags[i]);
    fprintf(f," }\n");
  }
  if (s == TRUE)
  {
    fprintf(f,"Sflags        {");
    for (i = 0; i < NUM_SFLAGS; i++)
      if ((m->sflags[i] == TRUE) && (!EMPTY(s_flags[i])))
        fprintf(f," %s", s_flags[i]);
    fprintf(f," }\n");
  }
    
  if (!EMPTY(m->desc))
  {
    fprintf(f, "Description   = \"");
    if (strlen(m->desc) > 60)
      fprintf(f, "\n");
    write_string(m->desc,f);
    fprintf(f, "\"\n");
  }
  if (!EMPTY(m->exam))
  {
    fprintf(f, "Examine       = \"\n");
    write_string(m->exam,f);
    fprintf(f, "\"\n");
  }
  fprintf(f,"End           = %s\n\n", m->name);
  return;
}

/*
**  Drives read_dirt_mob() to read all the mobiles in certain section of a file
*/
PMOB read_dirt_mobiles(f)
	FILE *f;
{
  PMOB m1 = NULL, m2 = NULL;

#ifdef DEBUG
  int x = line;
#endif

  m1 = read_dirt_mob(f);
  m2 = m1;
  while(m2 != NULL)
  {
    nummob++;

#ifdef DEBUG
    printf("Mobile %s: Lines %d to %d\n", m2->name, x, line);
    x = line+1;
#endif

    m2->next = read_dirt_mob(f);
    m2 = m2->next;
  }
  return m1;
}

/*
**  Called by read_dirt_mob, to read a set of flags and set appropriate
**  mflags, sflags or pflags.
*/
static void flg_read(n,m,f)
	int  n;
        PMOB m;
	FILE *f;
{
  int j, c, Num;
  char r[128];
  char *t;
  char **tab;
  Bool *flg;

  switch(n)
  {
    case 1:
      tab = s_flags;
      Num = NUM_SFLAGS;
      flg = m->sflags;
      break;
    case 2:
      tab = m_flags;
      Num = NUM_MFLAGS;
      flg = m->mflags;
      break;
    case 3:
      tab = p_flags;
      Num = NUM_PFLAGS;
      flg = m->pflags;
      break;
    default:
      printf("Error, unknown flags\n");
      return;
  }

  for (c = getc(f); c != '}'; c = getc(f))
  {
    if (c == '\n')
      line++;

    if (!isalpha(c))
      continue;
    for (t = r; isalpha(c); c = getc(f))
      *t++ = (char)c;
    ungetc(c, f);
    *t = 0;
    j = lookup(tab,r);
    if ((j >= 0) && (j < Num))
    {
      flg[j] = TRUE;
    }
    else
      printf("Error on line %d: Unknown flag on mobile %s:%s\n", line,
             m->name, r);
  }
  return;
}

void init_mob(m,n)
	PMOB m;
	char *n;
{
  int j;

  m->name = COPY(n);
  m->pname = COPY(n);
  m->level = -1;
  m->locname = NULL;
  m->loc = NULL;
  m->hp = 0;
  m->armor = 0;
  m->damage = 10;
  m->agg = 0;
  m->speed = 5;
  for(j = 0; j < NUM_SFLAGS; j++)
    m->sflags[j] = FALSE;
  for(j = 0; j < NUM_MFLAGS; j++)
    m->mflags[j] = FALSE;
  for(j = 0; j < NUM_PFLAGS; j++)
    m->pflags[j] = FALSE;
  m->desc = NULL;
  m->exam = NULL;
  m->next = NULL;
  return;
}