1stMUD4.0/bin/
1stMUD4.0/doc/MPDocs/
1stMUD4.0/player/
1stMUD4.0/win32/
1stMUD4.0/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-2003 by Ryan Jennings              *
*            http://1stmud.dlmud.com/  <r-jenn@shaw.ca>                   *
***************************************************************************/
#include "merc.h"
#include "tables.h"
#include "lookup.h"
#include "interp.h"
#include "olc.h"
#include "recycle.h"
#include "db.h"
#include "music.h"
#include "tablesave.h"
#include "save.h"

CMD_DATA cmd;
SKILL_DATA sk;
RACE_DATA race;
GROUP_DATA grp;
CLASS_DATA cls;
SOCIAL_DATA soc;
GQUEST gq;
DEITY_DATA deity;
WAR war;
CHANNEL_DATA cd;
MUD mud;
SONG_DATA song;

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

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

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

PROTOTYPE(const char *gcn_name, (int *));
PROTOTYPE(int *gcn_lookup, (const char *));

RW_FUN(pgcn_rw)
{
	int **pgcn = (int **) temp;

	switch (type)
	{
	case action_read:
		{
			int *blah = gcn_lookup(*arg);

			*pgcn = blah;

			return *pgcn != NULL;
		}
	case action_write:
		{
			*arg = gcn_name(*pgcn);
			return *pgcn != NULL;
		}
	default:
		return FALSE;
	}
}

RW_FUN(do_fun_rw)
{
	DO_FUN **fun = (DO_FUN **) temp;

	switch (type)
	{
	case action_write:
		*arg = do_fun_name(*fun);
		return TRUE;
	case action_read:
		*fun = do_fun_lookup(*arg);
		return TRUE;
	default:
		return FALSE;
	}
}

RW_FUN(position_rw)
{
	position_t *pos = (position_t *) temp;

	switch (type)
	{
	case action_read:
		{
			position_t ffg = position_lookup(*arg);

			*pos = UMAX(POS_NONE, ffg);

			return (ffg != -1);
		}
	case action_write:
		{
			*arg = position_table[UMAX(0, *pos)].name;
			return (*pos != -1);
		}
	default:
		return FALSE;
	}
}

RW_FUN(size_rw)
{
	int *size = (int *) temp;

	switch (type)
	{
	case action_read:
		{
			int ffg = size_lookup(*arg);

			*size = UMAX(0, ffg);

			return (ffg != -1);
		}
	case action_write:
		{
			*arg = size_table[UMAX(0, *size)].name;
			return (*size != -1);
		}
	default:
		return FALSE;
	}
}

RW_FUN(sex_rw)
{
	int *sex = (int *) temp;

	switch (type)
	{
	case action_read:
		{
			int ffg = sex_lookup(*arg);

			*sex = UMAX(0, ffg);

			return (ffg != -1);
		}
	case action_write:
		{
			*arg = sex_table[UMAX(0, *sex)].name;
			return (*sex != -1);
		}
	default:
		return FALSE;
	}
}

RW_FUN(attack_rw)
{
	int *r = (int *) temp;
	switch (type)
	{
	case action_read:
		{
			int ffg = attack_lookup(*arg);

			*r = UMAX(0, ffg);

			return (ffg != -1);
		}
	case action_write:
		{
			*arg = attack_table[UMAX(0, *r)].name;
			return (*r != -1);
		}
	default:
		return FALSE;
	}
}

RW_FUN(pgsn_rw)
{
	int **pgsn = (int **) temp;

	switch (type)
	{
	case action_read:
		{
			int *blah = gsn_lookup(*arg);

			*pgsn = blah;

			return *pgsn != NULL;
		}
	case action_write:
		{
			*arg = skill_gsn_name(*pgsn);
			return *pgsn != NULL;
		}
	default:
		return FALSE;
	}
}

RW_FUN(spell_fun_rw)
{
	SPELL_FUN **spfun = (SPELL_FUN **) temp;

	switch (type)
	{
	case action_read:
		{
			SPELL_FUN *blah = spell_lookup(*arg);

			*spfun = blah;

			return *spfun != NULL;
		}
	case action_write:
		{
			*arg = spell_fun_name(*spfun);
			return *spfun != NULL;
		}
	default:
		return FALSE;
	}
}

RW_FUN(clan_rw)
{
	CLAN_DATA **c = (CLAN_DATA **) temp;

	switch (type)
	{
	case action_read:
		{
			*c = clan_lookup(*arg);

			return *c != NULL;
		}
	case action_write:
		{
			*arg = *c == NULL ? "unknown" : (*c)->name;
			return *c != NULL;
		}
	default:
		return FALSE;
	}
}

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

	{"do_fun", FIELD_FUNCTION_INT_TO_STR, (void *) &cmd.do_fun,
	 (const void *) do_fun_rw, NULL},
	{"position", FIELD_FUNCTION_INT_TO_STR, (void *) &cmd.position,
	 (const void *) position_rw, NULL},
	{"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_FUNCTION_INT_TO_STR, (void *) &sk.spell_fun,
	 (const void *) spell_fun_rw, NULL},

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

	{"minimum_position", FIELD_FUNCTION_INT_TO_STR,

	 (void *) &sk.minimum_position, (const void *) position_rw,
	 NULL},
	{"pgsn", FIELD_FUNCTION_INT_TO_STR, (void *) &sk.pgsn,
	 (const void *) pgsn_rw, NULL},
	{"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},
	{"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_FUNCTION_INT_TO_STR, (void *) &race.size,
	 (const void *) size_rw, NULL},
	{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},
	{"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 gqsavetable[] = {

	{"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},
	{"mobs", FIELD_LONG_ALLOC_ARRAY, (void *) &gq.mobs, (void *) &gquest_info.mob_count,
	 (void *) -1},
	{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 warsavetable[] = {
	{"who", FIELD_STRING, (void *) &war.who, NULL, NULL},
	{"minlvl", FIELD_INT, (void *) &war.min_level, NULL, NULL},
	{"maxlvl", FIELD_INT, (void *) &war.max_level, NULL, NULL},
	{"inwar", FIELD_INT, (void *) &war.inwar, NULL, NULL},
	{"type", FIELD_INT, (void *) &war.wartype, NULL, NULL},
	{"timer", FIELD_INT, (void *) &war.timer, NULL, NULL},
	{"status", FIELD_INT, (void *) &war.status, NULL, NULL},
	{NULL, 0, NULL, NULL, NULL}
};

const struct savetable_type chansavetable[] = {
	{"pgcn", FIELD_FUNCTION_INT_TO_STR, (void *) &cd.index, (void *) pgcn_rw,
	 NULL},
	{"colour", FIELD_STRING, (void *) &cd.colour, NULL, NULL},
	{"customc", FIELD_INT, (void *) &cd.custom_colour, NULL, NULL},
	{"format", FIELD_STRING, (void *) &cd.format, NULL, NULL},
	{"bit", FIELD_FLAGSTRING, (void *) &cd.bit, (void *) comm_flags, NULL},
	{"specflag", FIELD_INT, (void *) &cd.spec_flag, NULL, NULL},
	{"length", FIELD_INT, (void *) &cd.page_length, NULL, NULL},
	{"name", FIELD_STRING, (void *) &cd.name, NULL, NULL},
	{"desc", FIELD_STRING, (void *) &cd.description, NULL, NULL},
	{NULL, 0, NULL, NULL, NULL}
};

const struct savetable_type mudsavetable[] = {
	{"mud_flags", FIELD_FLAGVECTOR, (void *) &mud.mud_flags, NULL, NULL},
	{"pulse_second", FIELD_INT, (void *) &mud.pulsepersec, NULL, NULL},
	{"arena", FIELD_INT, (void *) &mud.arena, NULL, NULL},
	{"share_value", FIELD_INT, (void *) &mud.share_value, NULL, NULL},
	{"rand_factor", FIELD_INT, (void *) &mud.rand_factor, NULL, NULL},
	{"weath_unit", FIELD_INT, (void *) &mud.weath_unit, NULL, NULL},
	{"max_vector", FIELD_INT, (void *) &mud.max_vector, NULL, NULL},
	{"climate_factor", FIELD_INT, (void *) &mud.climate_factor, NULL, NULL},
	{"max_online", FIELD_INT, (void *) &mud.max_online, NULL, NULL},
	{NULL, 0, NULL, NULL, NULL}
};

const struct savetable_type songsavetable[] = {
	{"name", FIELD_STRING, (void *) &song.name, NULL, NULL},
	{"group", FIELD_STRING, (void *) &song.group, NULL, NULL},
	{"lines", FIELD_INT, (void *) &song.lines, NULL, NULL},

	{"lyrics", FIELD_STRING_ARRAY_NULL, (void *) &song.lyrics,
	 (void *) MAX_LINES, NULL},
	{NULL, 0, NULL, NULL, NULL}
};

void load_struct(READ_DATA * 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;
	long **larray;
	RW_FUNC *function;
	struct flag_type *flagtable;
	bool found = FALSE;
	bool *pbool;
	int cnt = 0, i;
	RANK_DATA *rdata;
	flag_t ftemp;

	while (str_cmp((word = read_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 = read_string(fp);
					found = TRUE, cnt++;
					break;

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

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

				case FIELD_FUNCTION_INT_TO_STR:
					function = (RW_FUNC *) temp->argument;
					string = read_string(fp);
					pint =
						(int *) ((int) temp->puntero_field - (int) typebase +
								 (int) puntero);
					if ((*function) (action_read, 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 = read_string(fp);
					ftemp = flag_value(flagtable, string);
					*pentero = UMAX(0, ftemp);
					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 = read_string(fp);
					ftemp = flag_value(flagtable, string);
					*pint = UMAX(0, ftemp);
					free_string(string);
					found = TRUE, cnt++;
					break;

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

				case FIELD_BOOL:
					pbool =
						(bool *) ((int) temp->puntero_field - (int) typebase +
								  (int) puntero);
					string = read_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 = read_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->array_arg;
					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 = read_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->array_arg;
					found = TRUE, cnt++;
					break;

				case FIELD_LONG_ARRAY:
					plong =
						(long *) ((int) temp->puntero_field - (int) typebase +
								  (int) puntero);
					i = 0;
					while (str_cmp((string = read_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->array_arg;
					found = TRUE, cnt++;
					break;

				case FIELD_LONG_ALLOC_ARRAY:
					larray =
						(long **) ((int) temp->puntero_field - (int) typebase +
								   (int) puntero);
					i = 0;
					alloc_mem(*larray, long, *(int *) temp->argument);
					while (str_cmp((string = read_word(fp)), "@"))
					{
						if (i == *(int *) temp->argument)
							bugf("field_shint_array %s has excess elements",
								 temp->field);
						else
							(*larray)[i++] = (long) atol(string);
					}
					while (i < *(int *) temp->argument)
						(*larray)[i++] = (long) temp->array_arg;
					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 = read_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_DATA:
					rdata =
						(RANK_DATA *) ((int) temp->puntero_field -
									   (int) typebase + (int) puntero);
					i = read_number(fp);
					//read_string(fp);
					rdata[i - 1].rankname = read_string(fp);
					found = TRUE, cnt++;
					break;

				case FIELD_INUTIL:
					read_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 = read_word(fp)), "@"))
					{
						if (temp->argument != NULL && i == (int) temp->argument)
							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);
			read_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;
	long **larray;
	RW_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%s%s~\n", temp->field,
					format_tabs(strlen(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%s%d\n", temp->field,
					format_tabs(strlen(temp->field)), *pint);
			break;

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

		case FIELD_FUNCTION_INT_TO_STR:
			function = (RW_FUNC *) temp->argument;
			pint =
				(int *) ((int) temp->puntero_field - (int) typebase +
						 (int) puntero);
			if ((*function) (action_write, (void *) pint, &string) == FALSE)
				bugf("field %s invalid, string %s", temp->field, string);
			fprintf(fp, "%s%s%s~\n", temp->field,
					format_tabs(strlen(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%s%s~\n", temp->field,
					format_tabs(strlen(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%s%s~\n", temp->field,
					format_tabs(strlen(temp->field)), flag_string(flagtable,
																  *pint));
			break;

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

		case FIELD_BOOL:
			pbool =
				(bool *) ((int) temp->puntero_field - (int) typebase +
						  (int) puntero);
			fprintf(fp, "%s%s%s\n", temp->field,
					format_tabs(strlen(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_LONG_ALLOC_ARRAY:
			larray =
				(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 ", (*larray)[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 < (int) temp->argument; i++)
				fprintf(fp, "%d ", pbool[i] == TRUE ? 1 : 0);
			fprintf(fp, "@\n");
			break;

		case FIELD_RANK_DATA:
			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++;
	}
};

const struct data_save_type data_save_table[] = {
	{rw_commands, "commands"},
	{rw_skills, "skills"},
	{rw_races, "races"},
	{rw_groups, "groups"},
	{rw_classes, "classes"},
	{rw_socials, "socials"},
	{rw_clans, "clans"},
	{rw_stats, "stats"},
	{rw_bans, "bans"},
	{rw_gquest_data, "gquest"},
	{rw_deities, "deities"},
	{rw_webpasswds, "webpasswds"},
	{rw_members, "members"},
	{rw_war_data, "war"},
	{rw_channels, "channels"},
	{rw_mud_data, "mud"},
	{rw_music, "music"},
	{NULL, NULL}
};

TABLESAVE(rw_commands)
{
	rw_list(type, COMMAND_FILE, CMD_DATA, cmd_first, cmd_last, next, prev,
			new_command, "COMMAND", cmd, cmdsavetable);
}

TABLESAVE(rw_skills)
{
	rw_table(type, SKILL_FILE, SKILL_DATA, maxSkill, "SKILL", sk,
			 skillsavetable, skill_table);

	if (type == action_read)
		skill_table[maxSkill].name = NULL;
}

TABLESAVE(rw_races)
{
	rw_list(type, RACE_FILE, RACE_DATA, race_first, race_last, next, prev,
			new_race, "RACE", race, racesavetable);
	if (type == action_read)
	{
		default_race = new_race();
		replace_string(default_race->name, "Unique");
	}
}

TABLESAVE(rw_groups)
{
	rw_table(type, GROUP_FILE, GROUP_DATA, maxGroup, "GROUP", grp,
			 groupsavetable, group_table);

	if (type == action_read)
		group_table[maxGroup].name = NULL;
}

TABLESAVE(rw_classes)
{
	rw_table(type, CLASS_FILE, CLASS_DATA, maxClass, "CLASS", cls,
			 classsavetable, class_table);

	if (type == action_read)
		class_table[maxClass].name = NULL;
}

TABLESAVE(rw_socials)
{
	rw_list(type, SOCIAL_FILE, SOCIAL_DATA, social_first, social_last, next,
			prev, new_social, "SOCIAL", soc, socialsavetable);
}

TABLESAVE(rw_gquest_data)
{
	rw_single(type, GQUEST_FILE, "GQUESTDATA", gq, gqsavetable, gquest_info);
}

TABLESAVE(rw_deities)
{
	rw_list(type, DEITY_FILE, DEITY_DATA, deity_first, deity_last, next, prev,
			new_deity, "DEITY", deity, deitysavetable);
}

TABLESAVE(rw_war_data)
{
	rw_single(type, WAR_FILE, "WARDATA", war, warsavetable, war_info);
}

TABLESAVE(rw_channels)
{
	rw_table(type, CHANNEL_FILE, CHANNEL_DATA, maxChannel, "CHANNEL",
			 cd, chansavetable, channel_table);
}

void init_mud_data(void)
{
	mud_info.pulsepersec = 4;
	mud_info.mud_flags = 0;
	mud_info.share_value = 100;
	mud_info.arena = FIGHT_OPEN;
}

TABLESAVE(rw_mud_data)
{
	if (type == action_read)
		init_mud_data();
	rw_single(type, MUD_FILE, "MUD", mud, mudsavetable, mud_info);
	if (type == action_write)
		write_time();
}

TABLESAVE(rw_music)
{

	rw_table(type, MUSIC_FILE, SONG_DATA, maxSongs, "SONG", song,
			 songsavetable, song_table);
	if (type == action_read)
	{
		int i;

		song_table[maxSongs].name = NULL;
		for (i = 0; i <= MAX_GLOBAL; i++)
			channel_songs[i] = -1;
	}
}