asgard/
asgard/.settings/
asgard/area/
asgard/data/clans/
asgard/data/clans/history/
asgard/data/rosters/
asgard/src/notice/
#if defined(macintosh)
#include <types.h>
#else
#include <sys/types.h>
#endif
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <malloc.h>
#include <stdlib.h>
#include "merc.h"
#include "recycle.h"
#include "lookup.h"
#include "tables.h"

#if !defined(macintosh)
extern int _filbuf(FILE *);
#endif

/*
 * Array of containers read for proper re-nesting of objects.
 */
#define MAX_NEST	100
static OBJ_DATA * rgObjNest[MAX_NEST];

/*
 * Local functions.
 */
void fwrite_obj_room( ROOM_INDEX_DATA *ch, OBJ_DATA *obj, FILE *fp, int iNest );
void load_room_obj( ROOM_INDEX_DATA *room , FILE *fp);
void fread_obj_room( ROOM_INDEX_DATA *room, FILE *fp );

#define RECOVER_OBJ_PATH "../recover/"
#define RECOVER_OBJ_FILE "crash.rec"

void crash_dump_obj()
{
	FILE *fp;
	char filename[MAX_INPUT_LENGTH];
	ROOM_INDEX_DATA *pRoomIndex;
	int iHash;

	sprintf(filename, "%s%s", RECOVER_OBJ_PATH, RECOVER_OBJ_FILE);

	if ((fp = fopen(filename, "w")) == NULL)
	{
		printf_debug("fwrite_room_obj: fopen");
		perror(filename);
	}

	for (iHash = 0; iHash < MAX_KEY_HASH; iHash++)
	{
		for (pRoomIndex = room_index_hash[iHash]; pRoomIndex != NULL; pRoomIndex
				= pRoomIndex->next)
		{
			if (pRoomIndex->contents != NULL)
			{
				fprintf(fp, "#%d\n", pRoomIndex->vnum);
				fwrite_obj_room(pRoomIndex, pRoomIndex->contents, fp, 0);
				fprintf(fp, "0\n");
			}
		}
	}
	fprintf(fp, "#0\n");

	fclose(fp);
}

/*
 * Write an object and its contents.
 * This is a hack of fwrite_obj.  It was changed to use room_index_data
 * instead of char_data.
 */
void fwrite_obj_room(ROOM_INDEX_DATA *room, OBJ_DATA *obj, FILE *fp, int iNest)
{
	EXTRA_DESCR_DATA *ed;
	AFFECT_DATA *paf;

	/*
	 * Slick recursion to write lists backwards,
	 *   so loading them will load in forwards order.
	 */
	if (obj->next_content != NULL)
		fwrite_obj_room(room, obj->next_content, fp, iNest);

	fprintf(fp, "#Object\n");
	fprintf(fp, "Vnum %d\n", obj->pIndexData->vnum);
	if (!obj->pIndexData->new_format)
		fprintf(fp, "Oldstyle\n");
	if (obj->enchanted)
		fprintf(fp, "Enchanted\n");
	fprintf(fp, "Nest %d\n", iNest);

	/* these data are only used if they do not match the defaults */

	if (obj->name != obj->pIndexData->name)
		fprintf(fp, "Name %s~\n", obj->name);
	if (obj->short_descr != obj->pIndexData->short_descr)
		fprintf(fp, "ShD  %s~\n", obj->short_descr);
	if (obj->description != obj->pIndexData->description)
		fprintf(fp, "Desc %s~\n", obj->description);
	if (obj->extra_flags != obj->pIndexData->extra_flags)
		fprintf(fp, "ExtF %d\n", obj->extra_flags);
	if (obj->wear_flags != obj->pIndexData->wear_flags)
		fprintf(fp, "WeaF %d\n", obj->wear_flags);
	if (obj->item_type != obj->pIndexData->item_type)
		fprintf(fp, "Ityp %d\n", obj->item_type);
	if (obj->weight != obj->pIndexData->weight)
		fprintf(fp, "Wt   %d\n", obj->weight);
	if (obj->condition != obj->pIndexData->condition)
		fprintf(fp, "Cond %d\n", obj->condition);

	/* variable data */

	fprintf(fp, "Wear %d\n", obj->wear_loc);
	if (obj->level != obj->pIndexData->level)
		fprintf(fp, "Lev  %d\n", obj->level);
	if (obj->timer != 0)
		fprintf(fp, "Time %d\n", obj->timer);
	fprintf(fp, "Cost %d\n", obj->cost);
	if (obj->value[0] != obj->pIndexData->value[0] || obj->value[1]
			!= obj->pIndexData->value[1] || obj->value[2]
			!= obj->pIndexData->value[2] || obj->value[3]
			!= obj->pIndexData->value[3] || obj->value[4]
			!= obj->pIndexData->value[4])
		fprintf(fp, "Val  %d %d %d %d %d\n", obj->value[0], obj->value[1],
				obj->value[2], obj->value[3], obj->value[4]);

	switch (obj->item_type)
	{
	case ITEM_POTION:
	case ITEM_SCROLL:
		if (obj->value[1] > 0)
		{
			fprintf(fp, "Spell 1 '%s'\n", skill_table[obj->value[1]].name);
		}

		if (obj->value[2] > 0)
		{
			fprintf(fp, "Spell 2 '%s'\n", skill_table[obj->value[2]].name);
		}

		if (obj->value[3] > 0)
		{
			fprintf(fp, "Spell 3 '%s'\n", skill_table[obj->value[3]].name);
		}

		break;

	case ITEM_PILL:
	case ITEM_STAFF:
	case ITEM_WAND:
		if (obj->value[3] > 0)
		{
			fprintf(fp, "Spell 3 '%s'\n", skill_table[obj->value[3]].name);
		}

		break;
	}

	for (paf = obj->affected; paf != NULL; paf = paf->next)
	{
		if (paf->type < 0 || paf->type >= MAX_SKILL)
			continue;
		fprintf(fp, "Affc '%s' %3d %3d %3d %3d %3d %10d\n",
				skill_table[paf->type].name, paf->where, paf->level,
				paf->duration, paf->modifier, paf->location, paf->bitvector);
	}

	for (ed = obj->extra_descr; ed != NULL; ed = ed->next)
	{
		fprintf(fp, "ExDe %s~ %s~\n", ed->keyword, ed->description);
	}

	fprintf(fp, "End\n\n");

	if (obj->contains != NULL)
		fwrite_obj_room(room, obj->contains, fp, iNest + 1);

	return;
}

void crash_recover()
{
	FILE *fp;
	ROOM_INDEX_DATA *room;
	char filename[MIL];

	sprintf(filename, "%s%s", RECOVER_OBJ_PATH, RECOVER_OBJ_FILE);

	if ((fp = fopen(filename, "r")) == NULL)
		return;

	for (;;)
	{
		char letter;
		sh_int vnum;

		letter = fread_letter(fp);
		if (letter != '#')
		{
			printf_debug("crash_recover: #not found.");
			exit(1);
		}
		vnum = fread_number(fp);
		if (vnum == 0)
			break;
		if ((room = get_room_index(vnum)) != NULL)
		{
			load_room_obj(room, fp);
		}
	}
	fclose(fp);
	remove(filename);

}

void load_room_obj(ROOM_INDEX_DATA *room, FILE *fp)
{
	int iNest;

	for (iNest = 0; iNest < MAX_NEST; iNest++)
		rgObjNest[iNest] = NULL;

	for (;;)
	{
		char letter;
		char *word;

		letter = fread_letter(fp);
		if (letter == '*')
		{
			fread_to_eol(fp);
			continue;
		}

		if (letter == '0')
		{
			break;
		}

		if (letter != '#')
		{
			printf_debug("Load_room_obj: # not found.");
			break;
		}

		word = fread_word(fp);
		if (!str_cmp(word, "Object"))
			fread_obj_room(room, fp);
		else
			printf_debug("load_room_obj: invalid keywowrd.");
	}
}

#if defined(KEY)
#undef KEY
#endif

#define KEY( literal, field, value )					\
				if ( !str_cmp( word, literal ) )	\
				{					\
				    field  = value;			\
				    fMatch = TRUE;			\
				    break;				\
				}

void fread_obj_room(ROOM_INDEX_DATA *room, FILE *fp)
{
	OBJ_DATA *obj;
	char *word;
	int iNest;
	bool fMatch;
	bool fNest;
	bool fVnum;
	bool first;
	bool new_format; /* to prevent errors */
	bool make_new; /* update object */

	fVnum = FALSE;
	obj = NULL;
	first = TRUE; /* used to counter fp offset */
	new_format = FALSE;
	make_new = FALSE;

	word = feof(fp) ? "End" : fread_word(fp);
	if (!str_cmp(word, "Vnum"))
	{
		int vnum;
		first = FALSE; /* fp will be in right place */

		vnum = fread_number(fp);
		if (get_obj_index(vnum) == NULL)
		{
			printf_debug("Fread_obj: bad vnum %d.", vnum);
			obj = create_object(get_obj_index(OBJ_VNUM_BAG), -1);
			new_format = TRUE;
		}
		else
		{
			obj = create_object(get_obj_index(vnum), -1);
			new_format = TRUE;
		}

	}

	if (obj == NULL) /* either not found or old style */
	{
		obj = new_obj();
		obj->name = str_dup("");
		obj->short_descr = str_dup("");
		obj->description = str_dup("");
	}

	fNest = FALSE;
	fVnum = TRUE;
	iNest = 0;

	for (;;)
	{
		if (first)
			first = FALSE;
		else
			word = feof(fp) ? "End" : fread_word(fp);
		fMatch = FALSE;

		switch (UPPER(word[0]))
		{
		case '*':
			fMatch = TRUE;
			fread_to_eol(fp);
			break;

		case 'A':
			if (!str_cmp(word, "AffD"))
			{
				AFFECT_DATA *paf;
				int sn;

				paf = new_affect();

				sn = skill_lookup(fread_word(fp));
				if (sn < 0)
					printf_debug("Fread_obj: unknown skill.");
				else
					paf->type = sn;

				paf->level = fread_number(fp);
				paf->duration = fread_number(fp);
				paf->modifier = fread_number(fp);
				paf->location = fread_number(fp);
				paf->bitvector = fread_number(fp);
				paf->next = obj->affected;
				obj->affected = paf;
				fMatch = TRUE;
				break;
			}
			if (!str_cmp(word, "Affc"))
			{
				AFFECT_DATA *paf;
				int sn;

				paf = new_affect();

				sn = skill_lookup(fread_word(fp));
				if (sn < 0)
					printf_debug("Fread_obj: unknown skill.");
				else
					paf->type = sn;

				paf->where = fread_number(fp);
				paf->level = fread_number(fp);
				paf->duration = fread_number(fp);
				paf->modifier = fread_number(fp);
				paf->location = fread_number(fp);
				paf->bitvector = fread_number(fp);
				paf->next = obj->affected;
				obj->affected = paf;
				fMatch = TRUE;
				break;
			}
			break;

		case 'C':
			KEY( "Cond", obj->condition, fread_number( fp ) )
			;
			KEY( "Cost", obj->cost, fread_number( fp ) )
			;
			break;

		case 'D':
			KEY( "Description", obj->description, fread_string( fp ) )
			;
			KEY( "Desc", obj->description, fread_string( fp ) )
			;
			break;

		case 'E':

			if (!str_cmp(word, "Enchanted"))
			{
				obj->enchanted = TRUE;
				fMatch = TRUE;
				break;
			}

			KEY( "ExtraFlags", obj->extra_flags, fread_number( fp ) )
			;
			KEY( "ExtF", obj->extra_flags, fread_number( fp ) )
			;

			if (!str_cmp(word, "ExtraDescr") || !str_cmp(word, "ExDe"))
			{
				EXTRA_DESCR_DATA *ed;

				ed = new_extra_descr();

				ed->keyword = fread_string(fp);
				ed->description = fread_string(fp);
				ed->next = obj->extra_descr;
				obj->extra_descr = ed;
				fMatch = TRUE;
			}

			if (!str_cmp(word, "End"))
			{
				if (!fNest || (fVnum && obj->pIndexData == NULL))
				{
					printf_debug("Fread_obj: incomplete object.");
					free_obj(obj);
					return;
				}
				else
				{
					if (!fVnum)
					{
						free_obj(obj);
						obj = create_object(get_obj_index(OBJ_VNUM_DUMMY), 0);
					}

					if (!new_format)
					{
						obj->next = object_list;
						object_list = obj;
						obj->pIndexData->count++;
					}

					if (!obj->pIndexData->new_format && obj->item_type
							== ITEM_ARMOR && obj->value[1] == 0)
					{
						obj->value[1] = obj->value[0];
						obj->value[2] = obj->value[0];
					}

					if (make_new)
					{
						int wear;

						wear = obj->wear_loc;
						extract_obj(obj);

						obj = create_object(obj->pIndexData, 0);
						obj->wear_loc = wear;
					}
					if (iNest == 0 || rgObjNest[iNest] == NULL)
						obj_to_room(obj, room);
					else
						obj_to_obj(obj, rgObjNest[iNest - 1]);
					if (obj->pIndexData->vnum == OBJ_VNUM_QDIAMOND)
					{
						extract_obj(obj);
					}
					return;
				}
			}
			break;

		case 'I':
			KEY( "ItemType", obj->item_type, fread_number( fp ) )
			;
			KEY( "Ityp", obj->item_type, fread_number( fp ) )
			;
			break;

		case 'L':
			KEY( "Level", obj->level, fread_number( fp ) )
			;
			KEY( "Lev", obj->level, fread_number( fp ) )
			;
			break;

		case 'N':
			KEY( "Name", obj->name, fread_string( fp ) )
			;

			if (!str_cmp(word, "Nest"))
			{
				iNest = fread_number(fp);
				if (iNest < 0 || iNest >= MAX_NEST)
				{
					printf_debug("Fread_obj: bad nest %d.", iNest);
				}
				else
				{
					rgObjNest[iNest] = obj;
					fNest = TRUE;
				}
				fMatch = TRUE;
			}
			break;

		case 'O':
			if (!str_cmp(word, "Oldstyle"))
			{
				if (obj->pIndexData != NULL && obj->pIndexData->new_format)
					make_new = TRUE;
				fMatch = TRUE;
			}
			break;

		case 'S':
			KEY( "ShortDescr", obj->short_descr, fread_string( fp ) )
			;
			KEY( "ShD", obj->short_descr, fread_string( fp ) )
			;

			if (!str_cmp(word, "Spell"))
			{
				int iValue;
				int sn;

				iValue = fread_number(fp);
				sn = skill_lookup(fread_word(fp));
				if (iValue < 0 || iValue > 3)
				{
					printf_debug("Fread_obj: bad iValue %d.", iValue);
				}
				else if (sn < 0)
				{
					printf_debug("Fread_obj: unknown skill.");
				}
				else
				{
					obj->value[iValue] = sn;
				}
				fMatch = TRUE;
				break;
			}

			break;

		case 'T':
			KEY( "Timer", obj->timer, fread_number( fp ) )
			;
			KEY( "Time", obj->timer, fread_number( fp ) )
			;
			break;

		case 'V':
			if (!str_cmp(word, "Values") || !str_cmp(word, "Vals"))
			{
				obj->value[0] = fread_number(fp);
				obj->value[1] = fread_number(fp);
				obj->value[2] = fread_number(fp);
				obj->value[3] = fread_number(fp);
				if (obj->item_type == ITEM_WEAPON && obj->value[0] == 0)
					obj->value[0] = obj->pIndexData->value[0];
				fMatch = TRUE;
				break;
			}

			if (!str_cmp(word, "Val"))
			{
				obj->value[0] = fread_number(fp);
				obj->value[1] = fread_number(fp);
				obj->value[2] = fread_number(fp);
				obj->value[3] = fread_number(fp);
				obj->value[4] = fread_number(fp);
				fMatch = TRUE;
				break;
			}

			if (!str_cmp(word, "Vnum"))
			{
				int vnum;

				vnum = fread_number(fp);
				if ((obj->pIndexData = get_obj_index(vnum)) == NULL)
					printf_debug("Fread_obj: bad vnum %d.", vnum);
				else
					fVnum = TRUE;
				fMatch = TRUE;
				break;
			}
			break;

		case 'W':
			KEY( "WearFlags", obj->wear_flags, fread_number( fp ) )
			;
			KEY( "WeaF", obj->wear_flags, fread_number( fp ) )
			;
			KEY( "WearLoc", obj->wear_loc, fread_number( fp ) )
			;
			KEY( "Wear", obj->wear_loc, fread_number( fp ) )
			;
			KEY( "Weight", obj->weight, fread_number( fp ) )
			;
			KEY( "Wt", obj->weight, fread_number( fp ) )
			;
			break;

		}

		if (!fMatch)
		{
			printf_debug("Fread_obj: no match.");
			fread_to_eol(fp);
		}
	}
	if (obj->pIndexData->vnum == OBJ_VNUM_QDIAMOND)
	{
		extract_obj(obj);
	}
}