1stMUD/corefiles/
1stMUD/gods/
1stMUD/notes/
1stMUD/player/
1stMUD/win32/
1stMUD/win32/ROM/
/**************************************************************************
*  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
*  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
*                                                                         *
*  Merc Diku Mud improvements copyright (C) 1992, 1993 by Michael         *
*  Chastain, Michael Quan, and Mitchell Tse.                              *
*                                                                         *
*  In order to use any part of this Merc Diku Mud, you must comply with   *
*  both the original Diku license in 'license.doc' as well the Merc       *
*  license in 'license.txt'.  In particular, you may not remove either of *
*  these copyright notices.                                               *
*                                                                         *
*  Much time and thought has gone into this software and you are          *
*  benefiting.  We hope that you share your changes too.  What goes       *
*  around, comes around.                                                  *
***************************************************************************
*       ROM 2.4 is copyright 1993-1998 Russ Taylor                        *
*       ROM has been brought to you by the ROM consortium                 *
*           Russ Taylor (rtaylor@hypercube.org)                           *
*           Gabrielle Taylor (gtaylor@hypercube.org)                      *
*           Brian Moore (zump@rom.org)                                    *
*       By using this code, you have agreed to follow the terms of the    *
*       ROM license, in the file Rom24/doc/rom.license                    *
***************************************************************************
*       1stMUD ROM Derivative (c) 2001-2002 by Ryan Jennings              *
*            http://1stmud.dlmud.com/  <r-jenn@shaw.ca>                   *
***************************************************************************/
#include <sys/types.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "merc.h"
#include "tables.h"
#include "lookup.h"
#include "interp.h"
#include "olc.h"
#include "recycle.h"
#include "db.h"

struct savetable_type
{
	char *field;
	int type_field;
	void *puntero_field;
	const void *argument;
	const void *argument2;
};

#define FIELD_STRING			0
#define FIELD_FUNCION_INT_TO_STR	1
#define FIELD_LONG_ARRAY        2
#define FIELD_FLAGSTRING		3
#define FIELD_INT			4
#define FIELD_FLAGVECTOR		5
#define FIELD_BOOL			6
#define FIELD_INT_ARRAY		7
#define FIELD_STRING_ARRAY		8
#define FIELD_INT_FLAGSTRING    9
#define FIELD_BOOL_ARRAY		10
#define FIELD_INUTIL			11
#define FIELD_INT_ALLOC_ARRAY   12
#define FIELD_LONG              13
#define FIELD_STRING_ARRAY_NULL 14
#define FIELD_RANK              15

typedef char *STR_FUNC(void *);
typedef bool STR_READ_FUNC(void *, const char *);

CMD_DATA cmd;
SKILL_DATA sk;
RACE_DATA race;
GROUP_DATA grp;
CLASS_DATA cls;
SOCIAL_DATA soc;
CLAN_DATA clan;
STAT_DATA stat;
BAN_DATA ban;
GQUEST gq;
DEITY_DATA deity;
WPWD_DATA pwd;
MBR_DATA mbr;

const char *do_fun_name(DO_FUN *);
DO_FUN *do_fun_lookup(const char *);

const char *skill_gsn_name(int *);
int *gsn_lookup(const char *);

const char *spell_fun_name(SPELL_FUN *);
SPELL_FUN *spell_lookup(const char *);

const char *do_fun_str(void *temp)
{
	DO_FUN **fun = (DO_FUN **) temp;

	return do_fun_name(*fun);
}

const char *position_str(void *temp)
{
	int *flags = (int *) temp;

	return position_table[*flags].name;
}

const char *size_str(void *temp)
{
	int *size = (int *) temp;

	return size_table[UMAX(0, *size)].name;
}

const char *race_str(void *temp)
{
	RACE_DATA **raza = (RACE_DATA **) temp;
	RACE_DATA *tmp;

	for (tmp = race_first; tmp; tmp = tmp->next)
		if (tmp == *raza)
			return tmp->name;

	return "unique";
}

const char *pgsn_str(void *temp)
{
	int **pgsn = (int **) temp;

	return skill_gsn_name(*pgsn);
}

const char *spell_fun_str(void *temp)
{
	SPELL_FUN **spfun = (SPELL_FUN **) temp;

	return spell_fun_name(*spfun);
}

bool do_fun_read(void *temp, char *arg)
{
	DO_FUN **fun = (DO_FUN **) temp;

	*fun = do_fun_lookup(arg);

	return TRUE;
}

bool position_read(void *temp, char *arg)
{
	int *posic = (int *) temp;
	int ffg = position_lookup(arg);

	*posic = UMAX(0, ffg);

	if (ffg == -1)
		return FALSE;
	else
		return TRUE;
}

bool size_read(void *temp, char *arg)
{
	int *size = (int *) temp;
	int ffg = size_lookup(arg);

	*size = UMAX(0, ffg);

	if (ffg == -1)
		return FALSE;
	else
		return TRUE;
}

bool pgsn_read(void *temp, char *arg)
{
	int **pgsn = (int **) temp;
	int *blah = gsn_lookup(arg);

	*pgsn = blah;

	return !str_cmp(arg, "") || blah != NULL;
}

bool spell_fun_read(void *temp, char *arg)
{
	SPELL_FUN **spfun = (SPELL_FUN **) temp;
	SPELL_FUN *blah = spell_lookup(arg);

	*spfun = blah;

	return !str_cmp(arg, "") || blah != NULL;
}

const char *clan_str(void *temp)
{
	CLAN_DATA **clan = (CLAN_DATA **) temp;
	CLAN_DATA *tmp;

	for (tmp = clan_first; tmp; tmp = tmp->next)
		if (tmp == *clan)
			return tmp->name;

	return "unknown";
}

bool clan_read(void *temp, char *arg)
{
	CLAN_DATA **posic = (CLAN_DATA **) temp;

	*posic = clan_lookup(arg);

	if (*posic == NULL)
		return FALSE;
	else
		return TRUE;
}

const struct savetable_type cmdsavetable[] = {
	{"name", FIELD_STRING, (void *) &cmd.name, NULL, NULL},

	{"do_fun", FIELD_FUNCION_INT_TO_STR, (void *) &cmd.do_fun,
	 (const void *) do_fun_str,
	 (const void *) do_fun_read},
	{"position", FIELD_FUNCION_INT_TO_STR, (void *) &cmd.position,
	 (const void *) position_str, (const void *) position_read},
	{"level", FIELD_INT, (void *) &cmd.level, NULL, NULL},

	{"log", FIELD_FLAGSTRING, (void *) &cmd.log, (const void *) log_flags,
	 NULL},
	{"show", FIELD_BOOL, (void *) &cmd.show, NULL, NULL},
	{NULL, 0, NULL, NULL, NULL}
};

const struct savetable_type skillsavetable[] = {
	{"name", FIELD_STRING, (void *) &sk.name, NULL, NULL},

	{"levels", FIELD_INT_ALLOC_ARRAY, (void *) &sk.skill_level,
	 (const void *) &maxClass, (const void *) (LEVEL_IMMORTAL + 1)},
	{"ratings", FIELD_INT_ALLOC_ARRAY, (void *) &sk.rating,
	 (const void *) &maxClass, (const void *) 0},
	{"spell_fun", FIELD_FUNCION_INT_TO_STR, (void *) &sk.spell_fun,
	 (const void *) spell_fun_str, (const void *) spell_fun_read},

	{"target", FIELD_INT_FLAGSTRING, (void *) &sk.target,
	 (const void *) target_flags, NULL},

	{"minimum_position", FIELD_FUNCION_INT_TO_STR,

	 (void *) &sk.minimum_position, (const void *) position_str,
	 (const void *) position_read},
	{"pgsn", FIELD_FUNCION_INT_TO_STR, (void *) &sk.pgsn,
	 (const void *) pgsn_str,
	 (const void *) pgsn_read},
	{"min_mana", FIELD_INT, (void *) &sk.min_mana, NULL, NULL},
	{"beats", FIELD_INT, (void *) &sk.beats, NULL, NULL},
	{"noun_damage", FIELD_STRING, (void *) &sk.noun_damage, NULL, NULL},
	{"msg_off", FIELD_STRING, (void *) &sk.msg_off, NULL, NULL},
	{"msg_obj", FIELD_STRING, (void *) &sk.msg_obj, NULL, NULL},
	{NULL, 0, NULL, NULL, NULL}
};

const struct savetable_type racesavetable[] = {
	{"race", FIELD_STRING, (void *) &race.name, NULL, NULL},
	{"pc", FIELD_BOOL, (void *) &race.pc_race, NULL, NULL},
	{"act", FIELD_FLAGVECTOR, (void *) &race.act, NULL, NULL},
	{"aff", FIELD_FLAGVECTOR, (void *) &race.aff, NULL, NULL},
	{"off", FIELD_FLAGVECTOR, (void *) &race.off, NULL, NULL},
	{"imm", FIELD_FLAGVECTOR, (void *) &race.imm, NULL, NULL},
	{"res", FIELD_FLAGVECTOR, (void *) &race.res, NULL, NULL},
	{"vuln", FIELD_FLAGVECTOR, (void *) &race.vuln, NULL, NULL},
	{"form", FIELD_FLAGVECTOR, (void *) &race.form, NULL, NULL},
	{"parts", FIELD_FLAGVECTOR, (void *) &race.parts, NULL, NULL},
	{"who", FIELD_STRING, (void *) &race.who_name, NULL, NULL},
	{"points", FIELD_INT, (void *) &race.points, NULL, NULL},

	{"classx", FIELD_INT_ALLOC_ARRAY, (void *) &race.class_mult,
	 (const void *) &maxClass, (const void *) 100},
	{"skills", FIELD_STRING_ARRAY_NULL, (void *) &race.skills,
	 (const void *) 5, NULL},

	{"stats", FIELD_INT_ARRAY, (void *) &race.stats, (const void *) MAX_STATS,
	 (const void *) 13},

	{"mstats", FIELD_INT_ARRAY, (void *) &race.max_stats,
	 (const void *) MAX_STATS, (const void *) 25},

	{"size", FIELD_FUNCION_INT_TO_STR, (void *) &race.size,
	 (const void *) size_str,
	 (const void *) size_read},
	{NULL, 0, NULL, NULL, NULL}
};

const struct savetable_type groupsavetable[] = {
	{"name", FIELD_STRING, (void *) &grp.name, NULL, NULL},
	{"ratings", FIELD_INT_ALLOC_ARRAY, (void *) &grp.rating,
	 (const void *) &maxClass, (const void *) 0},
	{"spells", FIELD_STRING_ARRAY_NULL, (void *) &grp.spells,
	 (const void *) MAX_IN_GROUP, NULL},
	{NULL, 0, NULL, NULL, NULL}
};

const struct savetable_type classsavetable[] = {
	{"name", FIELD_STRING, (void *) &cls.name, NULL, NULL},
	{"whoname", FIELD_STRING, (void *) &cls.who_name, NULL, NULL},
	{"prime", FIELD_INT, (void *) &cls.attr_prime, NULL, NULL},
	{"weapon", FIELD_LONG, (void *) &cls.weapon, NULL, NULL},

	{"guild", FIELD_LONG_ARRAY, (void *) &cls.guild,
	 (const void *) MAX_GUILD, NULL},
	{"adept", FIELD_INT, (void *) &cls.skill_adept, NULL, NULL},
	{"thac0", FIELD_INT, (void *) &cls.thac0_00, NULL, NULL},
	{"thac32", FIELD_INT, (void *) &cls.thac0_32, NULL, NULL},
	{"minhp", FIELD_INT, (void *) &cls.hp_min, NULL, NULL},
	{"maxhp", FIELD_INT, (void *) &cls.hp_max, NULL, NULL},
	{"fmana", FIELD_BOOL, (void *) &cls.fMana, NULL, NULL},
	{"basegrp", FIELD_STRING, (void *) &cls.base_group, NULL, NULL},
	{"defaultgrp", FIELD_STRING, (void *) &cls.default_group, NULL, NULL},
	{NULL, 0, NULL, NULL, NULL}
};

const struct savetable_type socialsavetable[] = {
	{"name", FIELD_STRING, (void *) &soc.name, NULL, NULL},
	{"cnoarg", FIELD_STRING, (void *) &soc.char_no_arg, NULL, NULL},
	{"onoarg", FIELD_STRING, (void *) &soc.others_no_arg, NULL, NULL},
	{"cfound", FIELD_STRING, (void *) &soc.char_found, NULL, NULL},
	{"ofound", FIELD_STRING, (void *) &soc.others_found, NULL, NULL},
	{"vfound", FIELD_STRING, (void *) &soc.vict_found, NULL, NULL},
	{"cnotfound", FIELD_STRING, (void *) &soc.char_not_found, NULL, NULL},
	{"cauto", FIELD_STRING, (void *) &soc.char_auto, NULL, NULL},
	{"oauto", FIELD_STRING, (void *) &soc.others_auto, NULL, NULL},
	{NULL, 0, NULL, NULL, NULL}
};

const struct savetable_type clansavetable[] = {
	{"name", FIELD_STRING, (void *) &clan.name, NULL, NULL},
	{"whoname", FIELD_STRING, (void *) &clan.who_name, NULL, NULL},
	{"hall", FIELD_LONG, (void *) &clan.hall, NULL, NULL},
	{"indep", FIELD_BOOL, (void *) &clan.independent, NULL, NULL},
	{"rank", FIELD_RANK, (void *) &clan.rank, (void *) MAX_RANK, NULL},
	{NULL, 0, NULL, NULL, NULL}
};

const struct savetable_type statsavetable[] = {
	{"name", FIELD_STRING, (void *) &stat.name, NULL, NULL},

	{"stats", FIELD_LONG_ARRAY, (void *) &stat.gamestat,
	 (const void *) MAX_GAMESTAT, (const void *) 0},
	{NULL, 0, NULL, NULL, NULL}
};

const struct savetable_type bansavetable[] = {
	{"name", FIELD_STRING, (void *) &ban.name, NULL, NULL},
	{"level", FIELD_INT, (void *) &ban.level, NULL, NULL},
	{"flags", FIELD_FLAGVECTOR, (void *) &ban.ban_flags, NULL, NULL},
	{NULL, 0, NULL, NULL, NULL}
};

const struct savetable_type gqsavetable[] = {

	{"mobs", FIELD_LONG_ARRAY, (void *) &gq.mobs, (void *) MAX_GQUEST_MOB,
	 (void *) -1},
	{"mcount", FIELD_INT, (void *) &gq.mob_count, NULL, NULL},
	{"who", FIELD_STRING, (void *) &gq.who, NULL, NULL},
	{"timer", FIELD_INT, (void *) &gq.timer, NULL, NULL},
	{"involv", FIELD_INT, (void *) &gq.involved, NULL, NULL},
	{"qpoints", FIELD_INT, (void *) &gq.qpoints, NULL, NULL},
	{"gold", FIELD_INT, (void *) &gq.gold, NULL, NULL},
	{"minlev", FIELD_INT, (void *) &gq.minlevel, NULL, NULL},
	{"maxlev", FIELD_INT, (void *) &gq.maxlevel, NULL, NULL},
	{"running", FIELD_INT, (void *) &gq.running, NULL, NULL},
	{"next", FIELD_INT, (void *) &gq.next, NULL, NULL},
	{NULL, 0, NULL, NULL, NULL}
};

const struct savetable_type deitysavetable[] = {
	{"name", FIELD_STRING, (void *) &deity.name, NULL, NULL},
	{"desc", FIELD_STRING, (void *) &deity.desc, NULL, NULL},
	{"skill", FIELD_STRING, (void *) &deity.skillname, NULL, NULL},
	{NULL, 0, NULL, NULL, NULL}
};

const struct savetable_type pwdsavetable[] = {
	{"name", FIELD_STRING, (void *) &pwd.name, NULL, NULL},
	{"pwd", FIELD_STRING, (void *) &pwd.passw, NULL, NULL},
	{NULL, 0, NULL, NULL, NULL}
};

const struct savetable_type mbrsavetable[] = {
	{"name", FIELD_STRING, (void *) &mbr.name, NULL, NULL},
	{"clan", FIELD_FUNCION_INT_TO_STR, (void *) &mbr.clan, (void *) clan_str,
	 (void *) clan_read},
	{"rank", FIELD_INT, (void *) &mbr.rank, NULL, NULL},
	{"level", FIELD_INT, (void *) &mbr.level, NULL, NULL},
	{NULL, 0, NULL, NULL, NULL}
};

void load_struct(FILE * fp, void *typebase,
				 const struct savetable_type *table, void *puntero)
{
	const char *word;
	const struct savetable_type *temp;
	flag_t *pentero;
	const char **pstring;
	const char *string;
	int *pint;
	int **array;
	long *plong;
	STR_READ_FUNC *function;
	struct flag_type *flagtable;
	bool found = FALSE;
	bool *pbool;
	int cnt = 0, i;
	RANK_DATA *rdata;

	while (str_cmp((word = fread_word(fp)), "#END"))
	{
		for (temp = table; !IS_NULLSTR(temp->field); temp++)
		{
			if (!str_cmp(word, temp->field))
			{
				switch (temp->type_field)
				{
				case FIELD_STRING:
					pstring =
						(const char **) ((int) temp->puntero_field -
										 (int) typebase + (int) puntero);
					*pstring = fread_string(fp);
					found = TRUE, cnt++;
					break;

				case FIELD_INT:
					pint =
						(int *) ((int) temp->puntero_field - (int) typebase +
								 (int) puntero);
					*pint = fread_number(fp);
					found = TRUE, cnt++;
					break;

				case FIELD_LONG:
					plong =
						(long *) ((int) temp->puntero_field - (int) typebase +
								  (int) puntero);
					*plong = fread_number(fp);
					found = TRUE, cnt++;
					break;

				case FIELD_FUNCION_INT_TO_STR:
					function = (STR_READ_FUNC *) temp->argument2;
					string = fread_string(fp);
					pint =
						(int *) ((int) temp->puntero_field - (int) typebase +
								 (int) puntero);
					if ((*function) (pint, string) == FALSE)
						bugf("field %s invalid, string %s",
							 temp->field, string);
					free_string(string);
					found = TRUE, cnt++;
					break;

				case FIELD_FLAGSTRING:
					flagtable = (struct flag_type *) temp->argument;
					pentero =
						(flag_t *) ((int) temp->puntero_field -
									(int) typebase + (int) puntero);
					string = fread_string(fp);
					*pentero = flag_value(flagtable, string);
					free_string(string);
					found = TRUE, cnt++;
					break;

				case FIELD_INT_FLAGSTRING:
					flagtable = (struct flag_type *) temp->argument;
					pint =
						(int *) ((int) temp->puntero_field - (int) typebase +
								 (int) puntero);
					string = fread_string(fp);
					*pint = flag_value(flagtable, string);
					free_string(string);
					found = TRUE, cnt++;
					break;

				case FIELD_FLAGVECTOR:
					pentero =
						(flag_t *) ((int) temp->puntero_field -
									(int) typebase + (int) puntero);
					*pentero = fread_flag(fp);
					found = TRUE, cnt++;
					break;

				case FIELD_BOOL:
					pbool =
						(bool *) ((int) temp->puntero_field - (int) typebase +
								  (int) puntero);
					string = fread_word(fp);
					*pbool = str_cmp(string, "FALSE") ? TRUE : FALSE;
					found = TRUE, cnt++;
					break;

				case FIELD_INT_ARRAY:
					pint =
						(int *) ((int) temp->puntero_field - (int) typebase +
								 (int) puntero);
					i = 0;
					while (str_cmp((string = fread_word(fp)), "@"))
					{
						if (i == (int) temp->argument)
							bugf("field_shint_array %s has excess elements",
								 temp->field);
						else
							pint[i++] = (int) atoi(string);
					}
					while (i < (int) temp->argument)
						pint[i++] = (int) temp->argument2;
					found = TRUE, cnt++;
					break;

				case FIELD_INT_ALLOC_ARRAY:
					array =
						(int **) ((int) temp->puntero_field - (int) typebase +
								  (int) puntero);
					i = 0;
					alloc_mem(*array, int, *(int *) temp->argument);
					while (str_cmp((string = fread_word(fp)), "@"))
					{
						if (i == *(int *) temp->argument)
							bugf("field_shint_array %s has excess elements",
								 temp->field);
						else
							(*array)[i++] = (int) atoi(string);
					}
					while (i < *(int *) temp->argument)
						(*array)[i++] = (int) temp->argument2;
					found = TRUE, cnt++;
					break;

				case FIELD_LONG_ARRAY:
					plong =
						(long *) ((int) temp->puntero_field - (int) typebase +
								  (int) puntero);
					i = 0;
					while (str_cmp((string = fread_word(fp)), "@"))
					{
						if (i == (int) temp->argument)
							bugf("field_shint_array %s has excess elements",
								 temp->field);
						else
							plong[i++] = (long) atol(string);
					}
					while (i < (int) temp->argument)
						plong[i++] = (long) temp->argument2;
					found = TRUE, cnt++;
					break;

				case FIELD_STRING_ARRAY:
				case FIELD_STRING_ARRAY_NULL:
					pstring =
						(const char **) ((int) temp->puntero_field -
										 (int) typebase + (int) puntero);
					i = 0;
					while (str_cmp((string = fread_string(fp)), "@"))
					{
						if (i == (int) temp->argument)
							bugf("field_string_array %s has excess elements.",
								 temp->field);
						else
							pstring[i++] = string;
					}
					while (i < (int) temp->argument)
						pstring[i++] = NULL;
					found = TRUE, cnt++;
					break;

				case FIELD_RANK:
					rdata =
						(RANK_DATA *) ((int) temp->puntero_field -
									   (int) typebase + (int) puntero);
					i = fread_number(fp);
					//fread_string(fp);
					rdata[i - 1].rankname = fread_string(fp);
					found = TRUE, cnt++;
					break;

				case FIELD_INUTIL:
					fread_to_eol(fp);
					found = TRUE, cnt++;
					break;

				case FIELD_BOOL_ARRAY:
					pbool =
						(bool *) ((int) temp->puntero_field - (int) typebase +
								  (int) puntero);
					i = 0;
					while (str_cmp((string = fread_word(fp)), "@"))
					{
						if ((temp->argument != NULL
							 && i == (int) temp->argument)
							|| (temp->argument == NULL
								&& temp->argument2 != NULL
								&& i == *((int *) temp->argument2)))
							bugf("field_bool_array %s has excess elements",
								 temp->field);
						else
							pbool[i++] = (bool) atoi(string);
					}
					found = TRUE, cnt++;
					break;
				}				// switch
				if (found == TRUE)
					break;
			}					// if
		}						// for

		if (found == FALSE)
		{
			bugf("word %s not found", word);
			fread_to_eol(fp);
		}
		else
			found = FALSE;
	}							// while
}

void save_struct(FILE * fp, void *typebase,
				 const struct savetable_type *table, void *puntero)
{
	const struct savetable_type *temp;
	const char **pstring;
	int *pint;
	long *plong;
	int **array;
	STR_FUNC *function;
	const char *string;
	flag_t *pentero;
	bool *pbool;
	const struct flag_type *flagtable;
	int cnt = 0, i;
	RANK_DATA *rdata;

	for (temp = table; !IS_NULLSTR(temp->field); temp++)
	{
		switch (temp->type_field)
		{
		default:
			bugf("type_field %d invalid, field %s",
				 temp->type_field, temp->field);
			break;

		case FIELD_STRING:
			pstring =
				(const char **) ((int) temp->puntero_field - (int) typebase +
								 (int) puntero);
			fprintf(fp, "%s\t\t%s~\n", temp->field,
					IS_NULLSTR(*pstring) ? "" : fix_string(*pstring));
			break;

		case FIELD_INT:
			pint =
				(int *) ((int) temp->puntero_field - (int) typebase +
						 (int) puntero);
			fprintf(fp, "%s\t\t%d\n", temp->field, *pint);
			break;

		case FIELD_LONG:
			plong =
				(long *) ((int) temp->puntero_field - (int) typebase +
						  (int) puntero);
			fprintf(fp, "%s\t\t%ld\n", temp->field, *plong);
			break;

		case FIELD_FUNCION_INT_TO_STR:
			function = (STR_FUNC *) temp->argument;
			pint =
				(int *) ((int) temp->puntero_field - (int) typebase +
						 (int) puntero);
			string = (*function) ((void *) pint);
			fprintf(fp, "%s\t\t%s~\n", temp->field, string);
			break;

		case FIELD_FLAGSTRING:
			flagtable = (struct flag_type *) temp->argument;
			pentero =
				(flag_t *) ((int) temp->puntero_field - (int) typebase +
							(int) puntero);
			fprintf(fp, "%s\t\t%s~\n", temp->field,
					flag_string(flagtable, *pentero));
			break;

		case FIELD_INT_FLAGSTRING:
			flagtable = (struct flag_type *) temp->argument;
			pint =
				(int *) ((int) temp->puntero_field - (int) typebase +
						 (int) puntero);
			fprintf(fp, "%s\t\t%s~\n", temp->field,
					flag_string(flagtable, *pint));
			break;

		case FIELD_FLAGVECTOR:
			pentero =
				(flag_t *) ((int) temp->puntero_field - (int) typebase +
							(int) puntero);
			fprintf(fp, "%s\t\t%s\n", temp->field, fwrite_flags(*pentero));
			break;

		case FIELD_BOOL:
			pbool =
				(bool *) ((int) temp->puntero_field - (int) typebase +
						  (int) puntero);
			fprintf(fp, "%s\t\t%s\n", temp->field,
					(*pbool == TRUE) ? "TRUE" : "FALSE");
			break;

		case FIELD_INT_ARRAY:
			pint =
				(int *) ((int) temp->puntero_field - (int) typebase +
						 (int) puntero);
			fprintf(fp, "%s\t\t", temp->field);
			for (i = 0; i < (int) temp->argument; i++)
				fprintf(fp, "%d ", pint[i]);
			fprintf(fp, "@\n");
			break;

		case FIELD_INT_ALLOC_ARRAY:
			array =
				(int **) ((int) temp->puntero_field - (int) typebase +
						  (int) puntero);
			fprintf(fp, "%s\t\t", temp->field);
			for (i = 0; i < *(int *) temp->argument; i++)
				fprintf(fp, "%d ", (*array)[i]);
			fprintf(fp, "@\n");
			break;

		case FIELD_LONG_ARRAY:
			plong =
				(long *) ((int) temp->puntero_field - (int) typebase +
						  (int) puntero);
			fprintf(fp, "%s\t\t", temp->field);
			for (i = 0; i < (int) temp->argument; i++)
				fprintf(fp, "%ld ", plong[i]);
			fprintf(fp, "@\n");
			break;

		case FIELD_STRING_ARRAY:
			pstring =
				(const char **) ((int) temp->puntero_field - (int) typebase +
								 (int) puntero);
			fprintf(fp, "%s\t\t", temp->field);
			for (i = 0; i < (int) temp->argument; i++)
				fprintf(fp, "%s~ ",
						!IS_NULLSTR(pstring[i]) ? fix_string(pstring[i]) : "");
			fprintf(fp, "@~\n");
			break;

		case FIELD_STRING_ARRAY_NULL:
			pstring =
				(const char **) ((int) temp->puntero_field - (int) typebase +
								 (int) puntero);
			fprintf(fp, "%s\t\t", temp->field);
			for (i = 0; i < (int) temp->argument && !IS_NULLSTR(pstring[i]);
				 i++)
				fprintf(fp, "%s~ ",
						!IS_NULLSTR(pstring[i]) ? fix_string(pstring[i]) : "");
			fprintf(fp, "@~\n");
			break;

		case FIELD_BOOL_ARRAY:
			pbool =
				(bool *) ((int) temp->puntero_field - (int) typebase +
						  (int) puntero);
			fprintf(fp, "%s\t\t", temp->field);
			for (i = 0;
				 i <
				 (temp->argument ? (int) temp->
				  argument : *(int *) temp->argument2); i++)
				fprintf(fp, "%d ", pbool[i] == TRUE ? 1 : 0);
			fprintf(fp, "@\n");
			break;

		case FIELD_RANK:
			rdata =
				(RANK_DATA *) ((int) temp->puntero_field - (int) typebase +
							   (int) puntero);
			for (i = 0; i < (int) temp->argument; i++)
			{
				fprintf(fp, "%s\t%s%d ", temp->field,
						strlen(temp->field) < 8 ? "\t" : "", i + 1);
				fprintf(fp, "%s~\n", fix_string(rdata[i].rankname));
			}
			break;

		case FIELD_INUTIL:
			break;
		}

		cnt++;
	}
};

void save_commands(void)
{
	FILE *fp;
	CMD_DATA *i;
#if !defined(WIN32)
	const char *TEMPFILE = COMMAND_FILE ".tmp";

	fp = file_open(TEMPFILE, "w");
#else
	fp = file_open(COMMAND_FILE, "w");
#endif

	if (!fp)
	{
		perror("save_commands");
		file_close(fp);
		return;
	}

	for (i = cmd_first; i; i = i->next)
	{
		fprintf(fp, "#COMMAND\n");
		save_struct(fp, &cmd, cmdsavetable, i);
		fprintf(fp, "#END\n\n");
	}

	fprintf(fp, "#!\n\n");

	file_close(fp);
#if !defined(WIN32)
	rename(TEMPFILE, COMMAND_FILE);
#endif
}

void load_commands(void)
{
	FILE *fp;
	static CMD_DATA emptycmd;
	CMD_DATA *i;
	const char *word;

	fp = file_open(COMMAND_FILE, "r");

	if (fp == NULL)
	{
		perror("load_commands ");
		file_close(fp);
		return;
	}

	while (TRUE)
	{
		word = feof(fp) ? "#!" : fread_word(fp);

		if (!str_cmp(word, "#!"))
			break;

		if (str_cmp(word, "#COMMAND"))
		{
			bugf("word %s", word);
			file_close(fp);
			return;
		}

		i = new_command();
		*i = emptycmd;
		load_struct(fp, &cmd, cmdsavetable, i);
		LINK(i, cmd_first, cmd_last, next, prev);
	}
}

void save_skills(void)
{
	FILE *fp;
	int i;
#if !defined(WIN32)
	const char *TEMPFILE = SKILL_FILE ".tmp";

	fp = file_open(TEMPFILE, "w");
#else
	fp = file_open(SKILL_FILE, "w");
#endif

	if (!fp)
	{
		bug("save_skills: NULL fp", 0);
		file_close(fp);
		return;
	}

	fprintf(fp, "%d\n", maxSkill);

	for (i = 0; i < maxSkill; ++i)
	{
		fprintf(fp, "#SKILL\n");
		save_struct(fp, &sk, skillsavetable, &skill_table[i]);
		fprintf(fp, "#END\n\n");
	}

	fprintf(fp, "#!\n");

	file_close(fp);
#if !defined(WIN32)
	rename(TEMPFILE, SKILL_FILE);
#endif
}

void load_skills(void)
{
	FILE *fp;
	static SKILL_DATA skzero;
	int i = 0;
	const char *word;

	fp = file_open(SKILL_FILE, "r");

	if (!fp)
	{
		bug("load_skills: Unable to open " SKILL_FILE " to load skills.", 0);
		exit(1);
	}

	fscanf(fp, "%d\n", &maxSkill);

	alloc_mem(skill_table, SKILL_DATA, maxSkill + 1);

	if (!skill_table)
	{
		bugf("Error! Skill_table == NULL, MAX_SKILL : %d", maxSkill);
		exit(1);
	}

	for (;;)
	{
		word = fread_word(fp);

		if (!str_cmp(word, "#!"))
			break;

		if (str_cmp(word, "#SKILL"))
		{
			bugf("word doesn't exist (%s)", word);
			exit(1);
		}

		if (i >= maxSkill)
		{
			bug("load_skills: number greater than maxSkill", 0);
			exit(1);
		}

		skill_table[i] = skzero;
		load_struct(fp, &sk, skillsavetable, &skill_table[i++]);
	}

	skill_table[maxSkill].name = NULL;

	file_close(fp);
}

void save_races(void)
{
	FILE *fp;
	RACE_DATA *temp;
#if !defined(WIN32)
	const char *TEMPFILE = RACE_FILE ".tmp";

	fp = file_open(TEMPFILE, "w");
#else
	fp = file_open(RACE_FILE, "w");
#endif

	if (!fp)
	{
		perror("save_races : fopen");
		return;
	}

	for (temp = race_first; temp; temp = temp->next)
	{
		fprintf(fp, "#RACE\n");
		save_struct(fp, &race, racesavetable, temp);
		fprintf(fp, "#END\n\n");
	}

	fprintf(fp, "#!\n\n");

	file_close(fp);

#if !defined(WIN32)
	rename(TEMPFILE, RACE_FILE);
#endif

}

void load_races(void)
{
	FILE *fp;
	const char *word;
	RACE_DATA *pRace;

	fp = file_open(RACE_FILE, "r");

	if (!fp)
	{
		perror("load_races");
		return;
	}

	while (TRUE)
	{
		word = fread_word(fp);

		if (!str_cmp(word, "#!"))
			break;

		if (str_cmp(word, "#RACE"))
		{
			bugf("word %s", word);
			file_close(fp);
			return;
		}

		pRace = new_race();
		load_struct(fp, &race, racesavetable, pRace);
		LINK(pRace, race_first, race_last, next, prev);
	}
}

void save_groups(void)
{
	FILE *fp;
	int i;
#if !defined(WIN32)
	const char *TEMPFILE = GROUP_FILE ".tmp";

	fp = file_open(TEMPFILE, "w");
#else
	fp = file_open(GROUP_FILE, "w");
#endif

	if (!fp)
	{
		bug("save_groups: NULL fp", 0);
		file_close(fp);
		return;
	}

	fprintf(fp, "%d\n", maxGroup);

	for (i = 0; i < maxGroup; ++i)
	{
		fprintf(fp, "#GROUP\n");
		save_struct(fp, &grp, groupsavetable, &group_table[i]);
		fprintf(fp, "#END\n\n");
	}

	fprintf(fp, "#!\n");

	file_close(fp);
#if !defined(WIN32)
	rename(TEMPFILE, GROUP_FILE);
#endif
}

void load_groups(void)
{
	FILE *fp;
	static GROUP_DATA grpzero;
	int i = 0;
	const char *word;

	fp = file_open(GROUP_FILE, "r");

	if (!fp)
	{
		bug("load_groups: Unable to open " GROUP_FILE " to load groups.", 0);
		exit(1);
	}

	fscanf(fp, "%d\n", &maxGroup);

	alloc_mem(group_table, GROUP_DATA, maxGroup + 1);

	if (!group_table)
	{
		bugf("Error! Group_table == NULL, MAX_GROUP : %d", maxGroup);
		exit(1);
	}

	for (;;)
	{
		word = fread_word(fp);

		if (!str_cmp(word, "#!"))
			break;

		if (str_cmp(word, "#GROUP"))
		{
			bugf("word doesn't exist (%s)", word);
			exit(1);
		}

		if (i >= maxGroup)
		{
			bug("load_groups: number greater than maxGroup", 0);
			exit(1);
		}

		group_table[i] = grpzero;
		load_struct(fp, &grp, groupsavetable, &group_table[i++]);
	}

	group_table[maxGroup].name = NULL;

	file_close(fp);
}

void save_classes(void)
{
	FILE *fp;
	int i;
#if !defined(WIN32)
	const char *TEMPFILE = CLASS_FILE ".tmp";

	fp = file_open(TEMPFILE, "w");
#else
	fp = file_open(CLASS_FILE, "w");
#endif

	if (!fp)
	{
		bug("save_classes: NULL fp", 0);
		file_close(fp);
		return;
	}

	fprintf(fp, "%d\n", maxClass);

	for (i = 0; i < maxClass; ++i)
	{
		fprintf(fp, "#CLASS\n");
		save_struct(fp, &cls, classsavetable, &class_table[i]);
		fprintf(fp, "#END\n\n");
	}

	fprintf(fp, "#!\n");

	file_close(fp);
#if !defined(WIN32)
	rename(TEMPFILE, CLASS_FILE);
#endif
}

void load_classes(void)
{
	FILE *fp;
	static CLASS_DATA clszero;
	int i = 0;
	const char *word;

	fp = file_open(CLASS_FILE, "r");

	if (!fp)
	{
		bug("load_classes: Unable to open " CLASS_FILE " to load classes.", 0);
		exit(1);
	}

	fscanf(fp, "%d\n", &maxClass);

	alloc_mem(class_table, CLASS_DATA, maxClass + 1);

	if (!class_table)
	{
		bugf("Error! Class_table == NULL, MAX_CLASS : %d", maxClass);
		exit(1);
	}

	for (;;)
	{
		word = fread_word(fp);

		if (!str_cmp(word, "#!"))
			break;

		if (str_cmp(word, "#CLASS"))
		{
			bugf("word doesn't exist (%s)", word);
			exit(1);
		}

		if (i >= maxClass)
		{
			bug("load_classes: number greater than maxClass", 0);
			exit(1);
		}

		class_table[i] = clszero;
		load_struct(fp, &cls, classsavetable, &class_table[i++]);
	}

	class_table[maxClass].name = NULL;

	file_close(fp);
}

void save_social_table(void)
{
	FILE *fp;
	SOCIAL_DATA *i;
#if !defined(WIN32)
	const char *TEMPFILE = SOCIAL_FILE ".tmp";

	fp = file_open(TEMPFILE, "w");
#else
	fp = file_open(SOCIAL_FILE, "w");
#endif

	if (!fp)
	{
		bug("save_socials: NULL fp", 0);
		file_close(fp);
		return;
	}

	for (i = social_first; i; i = i->next)
	{
		fprintf(fp, "#SOCIAL\n");
		save_struct(fp, &soc, socialsavetable, i);
		fprintf(fp, "#END\n\n");
	}

	fprintf(fp, "#!\n");

	file_close(fp);
#if !defined(WIN32)
	rename(TEMPFILE, SOCIAL_FILE);
#endif
}

void load_social_table(void)
{
	FILE *fp;
	static SOCIAL_DATA socialzero;
	SOCIAL_DATA *pSocial;
	const char *word;

	fp = file_open(SOCIAL_FILE, "r");

	if (!fp)
	{
		bug("load_socials: Unable to open " SOCIAL_FILE " to load socials.", 0);
		exit(1);
	}

	for (;;)
	{
		word = fread_word(fp);

		if (!str_cmp(word, "#!"))
			break;

		if (str_cmp(word, "#SOCIAL"))
		{
			bugf("word doesn't exist (%s)", word);
			exit(1);
		}

		pSocial = new_social();
		*pSocial = socialzero;
		load_struct(fp, &soc, socialsavetable, pSocial);
		LINK(pSocial, social_first, social_last, next, prev);
	}

	file_close(fp);
}

void save_clans(void)
{
	FILE *fp;
	CLAN_DATA *i;
#if !defined(WIN32)
	const char *TEMPFILE = CLAN_FILE ".tmp";

	fp = file_open(TEMPFILE, "w");
#else
	fp = file_open(CLAN_FILE, "w");
#endif

	if (!fp)
	{
		bug("save_clans: NULL fp", 0);
		file_close(fp);
		return;
	}

	for (i = clan_first; i; i = i->next)
	{
		fprintf(fp, "#CLAN\n");
		save_struct(fp, &clan, clansavetable, i);
		fprintf(fp, "#END\n\n");
	}

	fprintf(fp, "#!\n");

	file_close(fp);
#if !defined(WIN32)
	rename(TEMPFILE, CLAN_FILE);
#endif
}

void load_clans(void)
{
	FILE *fp;
	static CLAN_DATA clanzero;
	CLAN_DATA *i;
	const char *word;

	fp = file_open(CLAN_FILE, "r");

	if (!fp)
	{
		bug("load_clans: Unable to open " CLAN_FILE " to load clans.", 0);
		exit(1);
	}

	for (;;)
	{
		word = fread_word(fp);

		if (!str_cmp(word, "#!"))
			break;

		if (str_cmp(word, "#CLAN"))
		{
			bugf("word doesn't exist (%s)", word);
			exit(1);
		}

		i = new_clan();
		*i = clanzero;
		load_struct(fp, &clan, clansavetable, i);
		LINK(i, clan_first, clan_last, next, prev);
	}

	file_close(fp);
}

void save_statlist(void)
{
	STAT_DATA *pstat;
	FILE *fp;
#if !defined(WIN32)
	const char *TEMPFILE = STAT_FILE ".tmp";

	if ((fp = file_open(TEMPFILE, "w")) == NULL)
#else
	if ((fp = file_open(STAT_FILE, "w")) == NULL)
#endif
	{
		perror(STAT_FILE);
		file_close(fp);
		return;
	}

	for (pstat = stat_first; pstat != NULL; pstat = pstat->next)
	{
		fprintf(fp, "#STAT\n");
		save_struct(fp, &stat, statsavetable, pstat);
		fprintf(fp, "#END\n\n");
	}

	fprintf(fp, "#!\n");

	file_close(fp);

#if !defined(WIN32)
	rename(TEMPFILE, STAT_FILE);
#endif
}

void load_statlist(void)
{
	FILE *fp;
	STAT_DATA *pstat;
	const char *word;

	fp = file_open(STAT_FILE, "r");

	if (!fp)
		return;

	for (;;)
	{
		word = fread_word(fp);

		if (!str_cmp(word, "#!"))
			break;

		if (str_cmp(word, "#STAT"))
		{
			bugf("word doesn't exist (%s)", word);
			exit(1);
		}

		pstat = new_stat_data();
		load_struct(fp, &stat, statsavetable, pstat);
		LINK(pstat, stat_first, stat_last, next, prev);
	}
	file_close(fp);
}

void save_bans(void)
{
	BAN_DATA *pban;
	FILE *fp;
#if !defined(WIN32)
	const char *TEMPFILE = BAN_FILE ".tmp";

	if ((fp = file_open(TEMPFILE, "w")) == NULL)
#else
	if ((fp = file_open(BAN_FILE, "w")) == NULL)
#endif
	{
		perror(BAN_FILE);
		file_close(fp);
		return;
	}

	for (pban = ban_first; pban != NULL; pban = pban->next)
	{
		fprintf(fp, "#BAN\n");
		save_struct(fp, &ban, bansavetable, pban);
		fprintf(fp, "#END\n\n");
	}

	fprintf(fp, "#!\n");

	file_close(fp);

#if !defined(WIN32)
	rename(TEMPFILE, BAN_FILE);
	return;
#endif
}

void load_bans(void)
{
	FILE *fp;
	BAN_DATA *pban;
	const char *word;

	fp = file_open(BAN_FILE, "r");

	if (!fp)
		return;

	for (;;)
	{
		word = fread_word(fp);

		if (!str_cmp(word, "#!"))
			break;

		if (str_cmp(word, "#BAN"))
		{
			bugf("word doesn't exist (%s)", word);
			exit(1);
		}

		pban = new_ban();
		load_struct(fp, &ban, bansavetable, pban);
		LINK(pban, ban_first, ban_last, next, prev);
	}
	file_close(fp);
}

bool save_gquest_data(void)
{
	FILE *fp;
#if !defined(WIN32)
	char *TEMPFILE = GQUEST_FILE ".tmp";

	if (!(fp = file_open(TEMPFILE, "w")))
#else
	if (!(fp = file_open(GQUEST_FILE, "w")))
#endif
	{
		bugf("Could not open file %s in order to save gquest data.",
			 GQUEST_FILE);
		file_close(fp);
		return FALSE;
	}

	fprintf(fp, "#GQUESTDATA\n");
	save_struct(fp, &gq, gqsavetable, &gquest_info);
	fprintf(fp, "#END\n");
	fprintf(fp, "\n#!\n");
	file_close(fp);
#if !defined(WIN32)
	rename(TEMPFILE, GQUEST_FILE);
#endif
	return TRUE;
}

bool load_gquest_data(void)
{
	FILE *fp;
	const char *word;

	end_gquest(NULL);

	if (!(fp = file_open(GQUEST_FILE, "r")))
	{
		bugf("Could not open file %s in order to read gquest data. Creating.",
			 GQUEST_FILE);
		file_close(fp);
		return save_gquest_data();
	}

	for (;;)
	{
		word = fread_word(fp);

		if (!str_cmp(word, "#!"))
			break;

		if (str_cmp(word, "#GQUESTDATA"))
		{
			bugf("Invalid gquest data file (%s).\n\r", GQUEST_FILE);
			return FALSE;
		}
		load_struct(fp, &gq, gqsavetable, &gquest_info);
	}

	file_close(fp);
	return TRUE;
}

void save_deities(void)
{
	FILE *fp;
	DEITY_DATA *i;
#if !defined(WIN32)
	char *TEMPFILE = DEITY_FILE ".tmp";

	fp = file_open(TEMPFILE, "w");
#else
	fp = file_open(DEITY_FILE, "w");
#endif

	if (!fp)
	{
		bug("save_deities: NULL fp", 0);
		file_close(fp);
		return;
	}

	for (i = deity_first; i; i = i->next)
	{
		fprintf(fp, "#DEITY\n");
		save_struct(fp, &deity, deitysavetable, i);
		fprintf(fp, "#END\n\n");
	}

	fprintf(fp, "#!\n");

	file_close(fp);
#if !defined(WIN32)
	rename(TEMPFILE, DEITY_FILE);
#endif
}

void load_deities(void)
{
	FILE *fp;
	static DEITY_DATA deityzero;
	DEITY_DATA *i;
	const char *word;

	fp = file_open(DEITY_FILE, "r");

	if (!fp)
	{
		bug("load_deities: Unable to open " DEITY_FILE " to load deities.", 0);
		save_deities();
		return;
	}

	for (;;)
	{
		word = fread_word(fp);

		if (!str_cmp(word, "#!"))
			break;

		if (str_cmp(word, "#DEITY"))
		{
			bugf("word doesn't exist (%s)", word);
			exit(1);
		}

		i = new_deity();
		*i = deityzero;
		load_struct(fp, &deity, deitysavetable, i);
		LINK(i, deity_first, deity_last, next, prev);
	}

	file_close(fp);
}

void save_webpasses(void)
{
	WPWD_DATA *ppwd;
	FILE *fp;
#if !defined(WIN32)
	char *TEMPFILE = WPWD_FILE ".tmp";

	if ((fp = file_open(TEMPFILE, "w")) == NULL)
#else
	if ((fp = file_open(WPWD_FILE, "w")) == NULL)
#endif
	{
		perror(WPWD_FILE);
		file_close(fp);
		return;
	}

	for (ppwd = wpwd_first; ppwd != NULL; ppwd = ppwd->next)
	{
		fprintf(fp, "#WPWD\n");
		save_struct(fp, &pwd, pwdsavetable, ppwd);
		fprintf(fp, "#END\n\n");
	}

	fprintf(fp, "#!\n");

	file_close(fp);

#if !defined(WIN32)
	rename(TEMPFILE, WPWD_FILE);
#endif
}

void load_webpasses(void)
{
	FILE *fp;
	WPWD_DATA *ppwd;
	const char *word;

	fp = file_open(WPWD_FILE, "r");

	if (!fp)
	{
		bug("Unable to open " WPWD_FILE " to load pwdlist.", 0);
		save_webpasses();
		file_close(fp);
		return;
	}

	for (;;)
	{
		word = fread_word(fp);

		if (!str_cmp(word, "#!"))
			break;

		if (str_cmp(word, "#WPWD"))
		{
			bugf("word doesn't exist (%s)", word);
			exit(1);
		}

		ppwd = new_pwd();
		load_struct(fp, &pwd, pwdsavetable, ppwd);
		LINK(ppwd, wpwd_first, wpwd_last, next, prev);
	}
	file_close(fp);
}

void save_members(void)
{
	MBR_DATA *pmbr;
	FILE *fp;
#if !defined(WIN32)
	char *TEMPFILE = MBR_FILE ".tmp";

	if ((fp = file_open(TEMPFILE, "w")) == NULL)
#else
	if ((fp = file_open(MBR_FILE, "w")) == NULL)
#endif
	{
		perror(MBR_FILE);
		file_close(fp);
		return;
	}

	for (pmbr = mbr_first; pmbr != NULL; pmbr = pmbr->next)
	{
		if (pmbr->clan == NULL)
		{
			bugf("%s member data invalid.", pmbr->name);
			continue;
		}
		fprintf(fp, "#MBR\n");
		save_struct(fp, &mbr, mbrsavetable, pmbr);
		fprintf(fp, "#END\n\n");
	}

	fprintf(fp, "#!\n");

	file_close(fp);

#if !defined(WIN32)
	rename(TEMPFILE, MBR_FILE);
#endif
}

void load_members(void)
{
	FILE *fp;
	MBR_DATA *pmbr;
	const char *word;

	fp = file_open(MBR_FILE, "r");

	if (!fp)
	{
		bug("Unable to open " MBR_FILE " to load members.", 0);
		save_members();
		return;
	}

	for (;;)
	{
		word = fread_word(fp);

		if (!str_cmp(word, "#!"))
			break;

		if (str_cmp(word, "#MBR"))
		{
			bugf("word doesn't exist (%s)", word);
			exit(1);
		}

		pmbr = new_mbr();
		load_struct(fp, &mbr, mbrsavetable, pmbr);
		LINK(pmbr, mbr_first, mbr_last, next, prev);
	}
	file_close(fp);
}