/* $Log: sysdefaults.c,v $
/* Revision 1.4  1999/02/11 00:37:36  cameron
/* Updated PROJECTS to show progress on INL server changes.
/* Disabled voting of HOCKEY or DOGFIGHT in INL server mode.
/* Reset stats at INL game start.
/* Stats cleared at end of INL game.
/* INL RESTART command added, both captains must agree, no pull-out.
/* .planets, .players, .global and INL_log saved at INL game end.
/* Force TOURN to 1 for INL server mode.
/*
/* Revision 1.3  1999/01/28 10:58:01  cameron
/* first pass of inl robot fixes
/*
/* Revision 1.2  1999/01/27 07:30:21  cameron
/* table driven .sysdef parsing to support gum
/*
 * Revision 1.1.1.1  1998/11/12 02:44:53  nobody
 * First import.
 *
 * Revision 1.1.1.1  1998/11/11 00:01:05  ahn
 * Netrek Vanilla Server
 *
 * Revision 1.3  92/03/19  21:34:34  terence
 * Added UDP mods (version 0.2, 3/17/92)
 * 
 * Revision 1.2  92/03/11  15:56:51  terence
 * added UDP mods
 */

#include <stdio.h>
#include <math.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "defs.h"
#include INC_STRINGS
#include "struct.h"
#include "data.h"
#include "copyright2.h"
#include "sysdefaults.h"

static struct stat oldstat;

void shipdefs();

setarray ( struct sysdef_array *a, int v )
{
  int i;

  for (i=0; i<a->max; i++) a->p[i] = v;
}

readsysdefaults()
{
    int i,j;
    FILE *f;
    char buf[200];
    char *s;

    /* Setup defaults. */
    setarray ( &sysdefplanets, 0 );
    startplanets[0]=startplanets[10]=startplanets[20]=startplanets[30]=1;
    setarray ( &sysdefships, 1 );
    setarray ( &sysdefweapons, 1 );

/* Clear ship type sent field, in case the .sysdef change changed ship defs */
    for (i=0;i<NUM_TYPES;i++) {
	sent_ship[i] = 0;
    }

    testtime= -1;
    topgun=0; /* added 12/9/90 TC */
    newturn=0; /* added 1/20/91 TC */
    hiddenenemy=1;
    binconfirm=0;
    plkills=2;
    sbrank=3;
    chaosmode=0;
    tournplayers=5;
    udpAllowed=1;		/* UDP */
    top_armies = 30;            /* added 11/27/93 ATH */
    planet_move = 0;		/* added 9/28/92 NBT */
    wrap_galaxy = 0;		/* added 6/28/95 JRP */
    pingpong_plasma = 0;	/* added 7/6/95 JRP */
#ifdef MINES
    mines = 0;			/* added 8/3/95 JRP */
#endif
#ifdef SB_TRANSWARP
    twarpMode = 0;
    twarpSpeed = 60;
#endif
    start_robot = NO_ROBOT;
    strcpy(Motd,N_MOTD);

    getshipdefaults();

    f=fopen(SysDef_File, "r");
    if (f==NULL) {
	ERROR(1,("No system defaults file!  Using coded defaults.\n"));
        return;
    }
    stat(SysDef_File, &oldstat);

    while (fgets(buf, 199, f)!=NULL) {
	if (buf[0] == '#') continue; /* a comment */
	s=INDEX(buf, '=');
	if (s==NULL) continue;
	*s='\0';
	s++;

	/* check each keyword from file with our list of keywords */
	for (j=0; sysdef_keywords[j].type != SYSDEF_END; j++) {

	    /* check current keyword for a match */
	    if (strcmp(buf,sysdef_keywords[j].key)==0) {
		switch (sysdef_keywords[j].type) {
		case SYSDEF_INT:
		    {
			int *p = (int *) sysdef_keywords[j].p;
			*p = atoi(s);
		    }
		    break;
		case SYSDEF_CHAR:
		    sscanf(s,"%s",sysdef_keywords[j].p);
		    break;
		case SYSDEF_ARRAY:
		    {
			struct sysdef_array *a = sysdef_keywords[j].p;
			setarray(a, 0);
			readstrings(a->name, s, a->keys, a->p, a->max);
		    }
		    break;
		case SYSDEF_ROBOT:
		    if (atoi(s)) start_robot = (int) sysdef_keywords[j].p;
		    break;
		case SYSDEF_SHIP:
		    shipdefs (atoi(s),f);
		    break;
		}
		break;
	    }
	}	

	/* handle not finding it in the keyword list */
	if (sysdef_keywords[j].type == SYSDEF_END) {
	    ERROR(2,("System default %s unknown\n", buf));
	}
    }

    /* Make sure every team can start at some planet! */
    for (i=0; i<4; i++) { 
	int k = 0;
	for (j=0; j<10; j++) {
	    if (startplanets[i*10+j]) {
		k++;
		break;
	    }
	}
	if (k == 0) {
	    ERROR(1,("No starting planets specified for team %d\n", i));
	    startplanets[i*10]=1;
	}
    }

    /* apply minimum and maximum values here */
    if (tournplayers == 0) tournplayers=5;
    if (ping_freq <= 0) ping_freq = 1;
    if (ping_iloss_interval <= 0) ping_iloss_interval = 1;
    if (ping_ghostbust_interval <= 0) ping_ghostbust_interval = 1;

#ifdef BASEPRACTICE
    if (start_robot == BASEP_ROBOT) {
	binconfirm=0;      /* allow robots to join */
	sbrank=0;          /* no SB restriction */
	check_scum=0;
    }
#endif

    if (start_robot == INL_ROBOT) {
      tournplayers=1;
      sbrank=0;				/* no SB restriction		*/
      eventlog=1;			/* enable INL event logging	*/
    }

    fclose(f);
}

readstrings(type, string, keys, array, max)
char *type;
char *string;
char **keys;
int *array;
int max;
{
  int i;

  while (*string!='\0') { 
    while (*string=='\n' || *string==' ' || *string==',' || *string=='\t') string++;
    if (*string=='\0') break;
    for (i=0; i<max; i++) {
      if (strncmp(keys[i], string, strlen(keys[i]))==0) {
	string+=strlen(keys[i]);
	array[i]=1;
	break;
      }
    }
    if (i==max) {
      ERROR(1,("%s type %s unknown!\n", type, string));
      string++;
    }
  }
}

/* This function will update all of the defaults if the default file 
 * changed.  It is called often, and assuming the OS caches the file
 * inode info well, this isn't a problem.
 */
int
update_sys_defaults()
{
  struct stat newstat;

  if (stat(SysDef_File, &newstat)==0) {
    if (newstat.st_ino != oldstat.st_ino ||
	newstat.st_mtime != oldstat.st_mtime) {
      readsysdefaults();
      return(1);
    }
  }
  return(0);
}


/*------------------------------------------------------------------------

 Stolen direct from the Paradise 2.2.6 server code 
 This code is used to load shipvals from the .sysdef

 Added 1/9/94 by Steve Sheldon
-------------------------------------------------------------------------*/

/*--------------------------------SHIPDEFS---------------------------------*/
/*    This function gets all of the field values for a ship.  Each line of
input for the ship fields has a single ship field on it.    The name of the
ship field is followed by the value to place in that field.    The function
stops when it encounters a line with "end" on it.     It places the values
into the shipvals so that the next time getship is called, the new values
will be used.    */

void shipdefs (set,f)
    int set;
    FILE *f;					/* file to load from */
{
  struct ship *currship = NULL;
  char buf[256];				/* to get a string from file */
  char field_name[64];				/* to get name of field */
  char value[256];				/* to get name */
  char sdesig[64];				/* to get ship letters */
  int len;					/* hold len of read in string */
  int i;					/* looping var */
  int offset;					/* offset into ship structure */
  
  while (1) {					/* loop until break */
    if (0 == fgets (buf, sizeof (buf), f))	/* get a string of input */
      return;					/* if end of file then break */
    if (buf[0]=='!' || buf[0]=='#')
      continue;					/* skip line with ! or # */
    len = strlen (buf);
    if (buf[len - 1] == '\n')			/* blast trailing newline */
      buf[--len] = 0;
    if (strncmp (buf, "END", 3) == 0) {		/* if end of ship then break */
      return;
    }
    if (shipvals == 0)
      continue;
    
    /* get field name and value */
    sscanf (buf, "%s %s %s", sdesig, field_name, value);
    
    if (!set) continue;
    
    for (i = 0; i < NUM_TYPES; i++) {
      if (strcasecmp(sdesig,shiptypes[i])==0) 
	currship = shipvals + i;	
    }
    if (!currship) {
      ERROR(1,("Unknown ship type (%s)\n",sdesig));
      return;
    }
    
    for (i = 0; ship_fields[i].name; i++) {	/* loop through field names */
      if (strcasecmp (field_name, ship_fields[i].name) == 0) /* found field?*/
	break;
    }
    if (ship_fields[i].name == 0) {		/* if we did not find name */
      fprintf (stderr, "invalid field name in ship %s description `%s'(5d)\n",
	       sdesig,field_name,i);
      continue;					/* print error, get next */
    }
    
    offset = ship_fields[i].offset;		/* get offset into struct */
    switch (ship_fields[i].type) {		/* parse the right type */
    case FT_CHAR:
      sscanf (value, "%c", offset + (char *) currship);
      break;
    case FT_SHORT:
      sscanf (value, "%hi", offset + (char *) currship);
      break;
    case FT_INT:
      sscanf (value, "%i", offset + (char *) currship);
      break;
    case FT_LONG:
      sscanf (value, "%li", offset + (char *) currship);
      break;
    case FT_FLOAT:
      sscanf (value, "%f", offset + (char *) currship);
      break;
    case FT_STRING:
      sscanf (value, "%s", offset + (char *) currship);
      break;
    default:
      fprintf (stderr, "Internal error, unknown field type %d\n",
	       ship_fields[i].type);
    }
  }
}
