#include "loadsave.hpp"
#include "loadsave.h"

#include "ability_type.hpp"
#include "artifact_type.hpp"
#include "birth.hpp"
#include "cave_type.hpp"
#include "dungeon_info_type.hpp"
#include "ego_item_type.hpp"
#include "init1.hpp"
#include "init2.hpp"
#include "levels.hpp"
#include "messages.hpp"
#include "modules.hpp"
#include "monster2.hpp"
#include "monster_race.hpp"
#include "monster_type.hpp"
#include "object1.hpp"
#include "object2.hpp"
#include "object_kind.hpp"
#include "player_class.hpp"
#include "player_race.hpp"
#include "player_race_mod.hpp"
#include "player_type.hpp"
#include "quark.hpp"
#include "hooks.hpp"
#include "skill_type.hpp"
#include "store_type.hpp"
#include "tables.hpp"
#include "timer_type.hpp"
#include "town_type.hpp"
#include "trap_type.hpp"
#include "util.hpp"
#include "util.h"
#include "wilderness_map.hpp"
#include "variable.h"
#include "variable.hpp"
#include "xtra2.hpp"
#include "z-rand.hpp"

#include <cassert>
#include <memory>

static u32b vernum; /* Version flag */
static FILE *fff; 	/* Local savefile ptr */

/**
 * Load/save flag
 */
enum class ls_flag_t {
	LOAD = 3,
	SAVE = 7
};

/*
 * Basic byte-level reading from savefile. This provides a single point
 * of interface to the pseudoencryption that ToME (and Angband)
 * uses. I'm thinking about if it might be faster/better to modify all
 * the do_* functions to directly do this stuff -- it'd make the code
 * somewhat uglier to maintain, but concievably might be much faster. Or
 * is it better maybe to scrap the pseudoencryption entirely and adopt
 * some other means of obfuscation, should it still prove useful in any
 * way? -- Improv
 *
 * What's the point of encryption on savefiles anyway? If I wanted to
 * make a cheater savefile, I'd activate debug mode, and hack the game
 * not to save it. There's no point. -- takkaria
 */

static byte sf_get(void)
{
	byte c;

	/* Get a character, decode the value */
	c = getc(fff) & 0xFF;

	/* Return the value */
	return (c);
}


static void sf_put(byte v)
{
	(void)putc((int)v, fff);
}

/*
 * Size-aware read/write routines for the savefile, do all their
 * work through sf_get and sf_put.
 */
static void do_byte(byte *v, ls_flag_t flag)
{
	switch (flag)
	{
	case ls_flag_t::LOAD:
	{
		*v = sf_get();
		return;
	}
	case ls_flag_t::SAVE:
	{
		byte val = *v;
		sf_put(val);
		return;
	}
	}
}

static void do_bool(bool_ *f, ls_flag_t flag)
{
	byte b = *f;
	do_byte(&b, flag);
	if (flag == ls_flag_t::LOAD)
	{
		*f = b;
	}
}

static void do_u16b(u16b *v, ls_flag_t flag)
{
	switch (flag)
	{
	case ls_flag_t::LOAD:
	{
		(*v) = sf_get();
		(*v) |= ((u16b)(sf_get()) << 8);
		return;
	}
	case ls_flag_t::SAVE:
	{
		u16b val;
		val = *v;
		sf_put((byte)(val & 0xFF));
		sf_put((byte)((val >> 8) & 0xFF));
		return;
	}
	}
}

static void do_s16b(s16b *ip, ls_flag_t flag)
{
	do_u16b((u16b *)ip, flag);
}

static void do_u32b(u32b *ip, ls_flag_t flag)
{
	switch(flag)
	{
	case ls_flag_t::LOAD:
	{
		(*ip) = sf_get();
		(*ip) |= ((u32b)(sf_get()) << 8);
		(*ip) |= ((u32b)(sf_get()) << 16);
		(*ip) |= ((u32b)(sf_get()) << 24);
		return;
	}
	case ls_flag_t::SAVE:
	{
		u32b val = *ip;
		sf_put((byte)(val & 0xFF));
		sf_put((byte)((val >> 8) & 0xFF));
		sf_put((byte)((val >> 16) & 0xFF));
		sf_put((byte)((val >> 24) & 0xFF));
		return;
	}
	}
}

static void do_s32b(s32b *ip, ls_flag_t flag)
{
	do_u32b((u32b *)ip, flag);
}

/*
 * Do object memory and similar stuff
 */
static void do_xtra(int k_idx, ls_flag_t flag)
{
	byte tmp8u = 0;
	object_kind *k_ptr = &k_info[k_idx];

	switch(flag)
	{
	case ls_flag_t::SAVE:
	{
		if (k_ptr->aware) tmp8u |= 0x01;
		if (k_ptr->tried) tmp8u |= 0x02;
		if (k_ptr->artifact) tmp8u |= 0x80;

		do_byte(&tmp8u, flag);
		return;
	}
	case ls_flag_t::LOAD:
	{
		do_byte(&tmp8u, flag);
		k_ptr->aware = ((tmp8u & 0x01) ? TRUE : FALSE);
		k_ptr->tried = ((tmp8u & 0x02) ? TRUE : FALSE);
		k_ptr->artifact = ((tmp8u & 0x80) ? TRUE : FALSE);
		return;
	}
	}
}

static void save_string(const char *str)
{
	while (*str)
	{
		do_byte((byte*)str, ls_flag_t::SAVE);
		str++;
	}
	do_byte((byte*)str, ls_flag_t::SAVE);
}

static void load_string(char *str, int max)
{
	int i;

	/* Read the string */
	for (i = 0; TRUE; i++)
	{
		byte tmp8u;

		/* Read a byte */
		do_byte(&tmp8u, ls_flag_t::LOAD);

		/* Collect string while legal */
		if (i < max) str[i] = tmp8u;

		/* End of string */
		if (!tmp8u) break;
	}
	/* Terminate */
	str[max - 1] = '\0';
}

static void do_string(char *str, int max, ls_flag_t flag)
/* Max is ignored for writing */
{
	switch(flag) {
	case ls_flag_t::LOAD:
	{
		load_string(str, max);
		return;
	}
	case ls_flag_t::SAVE:
	{
		save_string(str);
		return;
	}
	}
}

/*
 * Load/Save quick start data
 */
static void do_quick_start(ls_flag_t flag)
{
	s16b tmp16s;
	u32b tmp32u;
	int i;

	do_s16b(&previous_char.sex, flag);
	do_s16b(&previous_char.race, flag);
	do_s16b(&previous_char.rmod, flag);
	do_s16b(&previous_char.pclass, flag);
	do_s16b(&previous_char.spec, flag);
	do_byte(&previous_char.quests, flag);
	do_byte(&previous_char.god, flag);
	do_s32b(&previous_char.grace, flag);
	do_s16b(&previous_char.age, flag);
	do_s16b(&previous_char.wt, flag);
	do_s16b(&previous_char.ht, flag);
	do_s16b(&previous_char.sc, flag);
	do_s32b(&previous_char.au, flag);

	for (i = 0; i < 6; i++) do_s16b(&(previous_char.stat[i]), flag);
	do_s16b(&previous_char.luck, flag);

	do_s16b(&tmp16s, flag);
	do_u32b(&tmp32u, flag);
	do_byte((byte*)&previous_char.quick_ok, flag);

	for (i = 0; i < 4; i++) do_string(previous_char.history[i], 60, flag);
}

/*
 * The special saved subrace
 */
static void do_subrace(ls_flag_t flag)
{
	player_race_mod *sr_ptr = &race_mod_info[SUBRACE_SAVE];
	int i;
	char buf[81];

	buf[80] = '\0'; // Make sure string is always NUL terminated

	if (flag == ls_flag_t::SAVE)
	{
		strncpy(buf, sr_ptr->title, 80);
	}
	do_string(buf, 80, flag);
	if (flag == ls_flag_t::LOAD)
	{
		set_subrace_title(sr_ptr, buf);
	}

	if (flag == ls_flag_t::SAVE)
	{
		strncpy(buf, sr_ptr->desc, 80);
	}
	do_string(buf, 80, flag);
	if (flag == ls_flag_t::LOAD)
	{
		set_subrace_description(sr_ptr, buf);
	}

	do_byte((byte*)&sr_ptr->place, flag);

	for (i = 0; i < 6; i++)
		do_s16b(&sr_ptr->r_adj[i], flag);

	do_byte((byte*)&sr_ptr->luck, flag);
	do_s16b(&sr_ptr->mana, flag);

	do_s16b(&sr_ptr->r_dis, flag);
	do_s16b(&sr_ptr->r_dev, flag);
	do_s16b(&sr_ptr->r_sav, flag);
	do_s16b(&sr_ptr->r_stl, flag);
	do_s16b(&sr_ptr->r_srh, flag);
	do_s16b(&sr_ptr->r_fos, flag);
	do_s16b(&sr_ptr->r_thn, flag);
	do_s16b(&sr_ptr->r_thb, flag);

	do_byte((byte*)&sr_ptr->r_mhp, flag);
	do_s16b(&sr_ptr->r_exp, flag);

	do_byte((byte*)&sr_ptr->b_age, flag);
	do_byte((byte*)&sr_ptr->m_age, flag);

	do_byte((byte*)&sr_ptr->m_b_ht, flag);
	do_byte((byte*)&sr_ptr->m_m_ht, flag);
	do_byte((byte*)&sr_ptr->f_b_ht, flag);
	do_byte((byte*)&sr_ptr->f_m_ht, flag);

	do_byte((byte*)&sr_ptr->m_b_wt, flag);
	do_byte((byte*)&sr_ptr->m_m_wt, flag);
	do_byte((byte*)&sr_ptr->f_b_wt, flag);
	do_byte((byte*)&sr_ptr->f_m_wt, flag);

	do_byte((byte*)&sr_ptr->infra, flag);

	for (i = 0; i < 4; i++)
		do_s16b(&sr_ptr->powers[i], flag);

	for (i = 0; i < BODY_MAX; i++)
		do_byte((byte*)&sr_ptr->body_parts[i], flag);

	do_u32b(&sr_ptr->flags1, flag);
	do_u32b(&sr_ptr->flags2, flag);

	for (i = 0; i < PY_MAX_LEVEL + 1; i++)
	{
		do_u32b(&sr_ptr->oflags1[i], flag);
		do_u32b(&sr_ptr->oflags2[i], flag);
		do_u32b(&sr_ptr->oflags3[i], flag);
		do_u32b(&sr_ptr->oflags4[i], flag);
		do_u32b(&sr_ptr->oflags5[i], flag);
		do_u32b(&sr_ptr->oesp[i], flag);
		do_s16b(&sr_ptr->opval[i], flag);
	}

	do_byte(&sr_ptr->g_attr, flag);
	do_byte((byte*)&sr_ptr->g_char, flag);

	for (i = 0; i < MAX_SKILLS; i++)
	{
		do_byte((byte*)&sr_ptr->skill_basem[i], flag);
		do_u32b(&sr_ptr->skill_base[i], flag);
		do_byte((byte*)&sr_ptr->skill_modm[i], flag);
		do_s16b(&sr_ptr->skill_mod[i], flag);
	}
}


/* Load/Save the random spells info */
static void do_spells(int i, ls_flag_t flag)
{
	random_spell *s_ptr = &random_spells[i];
	do_string(s_ptr->name, 30, flag);
	do_string(s_ptr->desc, 30, flag);
	do_s16b(&s_ptr->mana, flag);
	do_s16b(&s_ptr->fail, flag);
	do_u32b(&s_ptr->proj_flags, flag);
	do_byte(&s_ptr->GF, flag);
	do_byte(&s_ptr->radius, flag);
	do_byte(&s_ptr->dam_sides, flag);
	do_byte(&s_ptr->dam_dice, flag);
	do_byte(&s_ptr->level, flag);
	do_byte((byte*)&s_ptr->untried, flag);
}


/*
 * Show information on the screen, one line at a time.
 *
 * Avoid the top two lines, to avoid interference with "msg_print()".
 */
static void note(cptr msg)
{
	static int y = 2;

	/* Draw the message */
	prt(msg, y, 0);

	/* Advance one line (wrap if needed) */
	if (++y >= 24) y = 2;

	/* Flush it */
	Term_fresh();
}


static void skip_ver_byte(u32b version, ls_flag_t flag)
/* Reads and discards a byte if the savefile is as old as/older than version */
{
	if ((flag == ls_flag_t::LOAD) && (vernum <= version))
	{
		byte forget;
		do_byte(&forget, flag);
	}
	return;
}

static void do_ver_s16b(s16b *v, u32b version, s16b defval, ls_flag_t flag)
{
	if ((flag == ls_flag_t::LOAD) && (vernum < version))
	{
		*v = defval;
		return;
	}
	do_s16b(v, flag);
}

/*
 * Misc. other data
 */
static char loaded_game_module[80];
static bool_ do_extra(ls_flag_t flag)
{
	int i, j;
	byte tmp8u = 0;
	s16b tmp16s = 0;
	u32b tmp32u = 0;
	s32b tmp32s = 0;
	u16b tmp16b = 0;
	u32b dummy32u = 0;

	do_string(player_name, 32, flag);

	do_string(died_from, 80, flag);

	for (i = 0; i < 4; i++)
	{
		do_string(history[i], 60, flag);
	}

	/* Handle the special levels info */
	if (flag == ls_flag_t::SAVE)
	{
		tmp8u = max_d_idx;
		tmp16s = MAX_DUNGEON_DEPTH;
	}
	do_byte(&tmp8u, flag);

	if (flag == ls_flag_t::LOAD)
	{
		if (tmp8u > max_d_idx)
		{
			note(format("Too many (%d) dungeon types!", tmp8u));
		}
	}

	do_s16b(&tmp16s, flag);

	if (flag == ls_flag_t::LOAD)
	{
		if (tmp16s > MAX_DUNGEON_DEPTH)
		{
			note(format("Too many (%d) max level by dungeon type!", tmp16s));
		}
	}

	/* Load the special levels history */
	for (i = 0; i < tmp8u; i++)
	{
		for (j = 0; j < tmp16s; j++)
		{
			do_byte((byte*)&special_lvl[j][i], flag);
		}
	}

	do_byte((byte*)&generate_special_feeling, flag);

	/* Load the quick start data */
	do_quick_start(flag);

	/* Load/save the special subrace */
	do_subrace(flag);

	/* Race/Class/Gender/Spells */
	do_s32b(&p_ptr->lives, flag);
	do_byte(&p_ptr->prace, flag);
	do_byte(&p_ptr->pracem, flag);
	do_byte(&p_ptr->pclass, flag);
	do_byte(&p_ptr->pspec, flag);
	do_byte(&p_ptr->psex, flag);
	do_u16b(&tmp16b, flag);
	do_u16b(&tmp16b, flag);
	do_byte(&p_ptr->mimic_form, flag);
	do_s16b(&p_ptr->mimic_level, flag);
	if (flag == ls_flag_t::SAVE) tmp8u = 0;

	do_byte(&p_ptr->hitdie, flag);
	do_u16b(&p_ptr->expfact, flag);

	do_s16b(&p_ptr->age, flag);
	do_s16b(&p_ptr->ht, flag);
	do_s16b(&p_ptr->wt, flag);

	/* Dump the stats (maximum and current) */
	for (i = 0; i < 6; ++i) do_s16b(&p_ptr->stat_max[i], flag);
	for (i = 0; i < 6; ++i) do_s16b(&p_ptr->stat_cur[i], flag);
	for (i = 0; i < 6; ++i) do_s16b(&p_ptr->stat_cnt[i], flag);
	for (i = 0; i < 6; ++i) do_s16b(&p_ptr->stat_los[i], flag);

	/* Dump the skills */
	do_s16b(&p_ptr->skill_points, flag);
	do_s16b(&p_ptr->skill_last_level, flag);
	do_s16b(&p_ptr->melee_style, flag);
	do_s16b(&p_ptr->use_piercing_shots, flag);

	tmp16s = MAX_SKILLS;
	do_s16b(&tmp16s, flag);

	if ((flag == ls_flag_t::LOAD) && (tmp16s > MAX_SKILLS))
	{
		quit("Too many skills");
	}

	if (flag == ls_flag_t::SAVE) old_max_s_idx = max_s_idx;
	do_u16b(&old_max_s_idx, flag);
	for (i = 0; i < tmp16s; ++i)
	{
		if (i < old_max_s_idx)
		{
			do_s32b(&s_info[i].value, flag);
			do_s32b(&s_info[i].mod, flag);
			do_byte((byte*)&s_info[i].dev, flag);
			do_byte((byte*)&s_info[i].hidden, flag);
			do_u32b(&s_info[i].uses, flag);
		}
		else
		{
			do_u32b(&tmp32u, flag);
			do_s16b(&tmp16s, flag);
			do_byte(&tmp8u, flag);
			do_byte(&tmp8u, flag);
			do_u32b(&tmp32u, flag);
		}
	}

	tmp16s = max_ab_idx;
	do_s16b(&tmp16s, flag);

	if ((flag == ls_flag_t::LOAD) && (tmp16s > max_ab_idx))
	{
		quit("Too many abilities");
	}

	for (i = 0; i < tmp16s; ++i)
	{
		do_byte((byte*)&ab_info[i].acquired, flag);
	}

	do_s16b(&p_ptr->luck_base, flag);
	do_s16b(&p_ptr->luck_max, flag);

	do_s32b(&p_ptr->au, flag);

	do_s32b(&p_ptr->max_exp, flag);
	do_s32b(&p_ptr->exp, flag);
	do_u16b(&p_ptr->exp_frac, flag);
	do_s16b(&p_ptr->lev, flag);

	do_s16b(&p_ptr->town_num, flag); 	/* -KMW- */

	/* Write arena and rewards information -KMW- */
	do_s16b(&tmp16s, flag);
	do_s16b(&tmp16s, flag);
	do_s16b(&p_ptr->inside_quest, flag);
	do_byte(&tmp8u, flag);


	/* Save/load spellbinder */
	do_byte(&p_ptr->spellbinder_num, flag);
	do_byte(&p_ptr->spellbinder_trigger, flag);
	for (i = 0; i < 4; i++)
		do_u32b(&p_ptr->spellbinder[i], flag);


	do_byte(&tmp8u, flag); 		/* tmp8u should be 0 at this point */

	if (flag == ls_flag_t::SAVE) tmp8u = MAX_PLOTS;
	do_byte(&tmp8u, flag);

	if ((flag == ls_flag_t::LOAD) && (tmp8u > MAX_PLOTS))
	{
		quit(format("Too many plots, %d %d", tmp8u, MAX_PLOTS));
	}

	for (i = 0; i < tmp8u; i++)
	{
		do_s16b(&plots[i], flag);
	}

	if (flag == ls_flag_t::SAVE)
	{
		tmp8u = MAX_RANDOM_QUEST;
	}
	do_byte(&tmp8u, flag);

	if ((flag == ls_flag_t::LOAD) &&
	                (tmp8u > MAX_RANDOM_QUEST)) quit("Too many random quests");
	for (i = 0; i < tmp8u; i++)
	{
		do_byte(&random_quests[i].type, flag);
		do_s16b(&random_quests[i].r_idx, flag);
		do_byte((byte*)&random_quests[i].done, flag);
	}

	do_s16b(&p_ptr->oldpx, flag);
	do_s16b(&p_ptr->oldpy, flag);

	do_s16b(&p_ptr->mhp, flag);
	do_s16b(&p_ptr->chp, flag);
	do_u16b(&p_ptr->chp_frac, flag);
	do_s16b(&p_ptr->hp_mod, flag);

	do_s16b(&p_ptr->msane, flag);
	do_s16b(&p_ptr->csane, flag);
	do_u16b(&p_ptr->csane_frac, flag);

	do_s16b(&p_ptr->msp, flag);
	do_s16b(&p_ptr->csp, flag);
	do_u16b(&p_ptr->csp_frac, flag);

	/* XXX
	   Here's where tank points were.
	   Those who run the estate of you-know-who is really stupid.
	   I'll never even consider reading her books now. -- neil */
	do_s16b(&tmp16s, flag);
	do_s16b(&tmp16s, flag);
	do_s16b(&tmp16s, flag);
	do_s16b(&tmp16s, flag);

	/* Gods */
	do_s32b(&p_ptr->grace, flag);
	do_s32b(&p_ptr->grace_delay, flag);
	do_byte((byte*)&p_ptr->praying, flag);
	do_s16b(&p_ptr->melkor_sacrifice, flag);
	do_byte(&p_ptr->pgod, flag);

	/* Max Player and Dungeon Levels */
	do_s16b(&p_ptr->max_plv, flag);

	if (flag == ls_flag_t::SAVE)
		tmp8u = max_d_idx;
	do_byte(&tmp8u, flag);
	for (i = 0; i < tmp8u; i++)
	{
		if (flag == ls_flag_t::SAVE)
			tmp16s = max_dlv[i];
		do_s16b(&tmp16s, flag);
		if ((flag == ls_flag_t::LOAD) && (i <= max_d_idx))
			max_dlv[i] = tmp16s;
	}
	/* Repair max player level??? */
	if ((flag == ls_flag_t::LOAD) && (p_ptr->max_plv < p_ptr->lev))
		p_ptr->max_plv = p_ptr->lev;

	do_byte((byte*)&(p_ptr->help.enabled), flag);
	for (i = 0; i < HELP_MAX; i++)
	{
		do_bool(&(p_ptr->help.activated[i]), flag);
	}

	/* More info */
	tmp16s = 0;
	do_s16b(&p_ptr->sc, flag);
	do_s16b(&p_ptr->blind, flag);
	do_s16b(&p_ptr->paralyzed, flag);
	do_s16b(&p_ptr->confused, flag);
	do_s16b(&p_ptr->food, flag);
	do_s32b(&p_ptr->energy, flag);
	do_s16b(&p_ptr->fast, flag);
	do_s16b(&p_ptr->speed_factor, flag);
	do_s16b(&p_ptr->slow, flag);
	do_s16b(&p_ptr->afraid, flag);
	do_s16b(&p_ptr->cut, flag);
	do_s16b(&p_ptr->stun, flag);
	do_s16b(&p_ptr->poisoned, flag);
	do_s16b(&p_ptr->image, flag);
	do_s16b(&p_ptr->protevil, flag);
	do_s16b(&p_ptr->protundead, flag);
	do_s16b(&p_ptr->invuln, flag);
	do_s16b(&p_ptr->hero, flag);
	do_s16b(&p_ptr->shero, flag);
	do_s16b(&p_ptr->shield, flag);
	do_s16b(&p_ptr->shield_power, flag);
	do_s16b(&p_ptr->shield_power_opt, flag);
	do_s16b(&p_ptr->shield_power_opt2, flag);
	do_s16b(&p_ptr->shield_opt, flag);
	do_s16b(&p_ptr->blessed, flag);
	do_s16b(&p_ptr->control, flag);
	do_byte(&p_ptr->control_dir, flag);
	do_s16b(&p_ptr->tim_precognition, flag);
	do_s16b(&p_ptr->tim_thunder, flag);
	do_s16b(&p_ptr->tim_thunder_p1, flag);
	do_s16b(&p_ptr->tim_thunder_p2, flag);
	do_s16b(&p_ptr->tim_project, flag);
	do_s16b(&p_ptr->tim_project_dam, flag);
	do_s16b(&p_ptr->tim_project_gf, flag);
	do_s16b(&p_ptr->tim_project_rad, flag);
	do_s16b(&p_ptr->tim_project_flag, flag);

	do_s16b(&p_ptr->tim_magic_breath, flag);
	do_s16b(&p_ptr->tim_water_breath, flag);

	do_s16b(&p_ptr->tim_roots, flag);
	do_s16b(&p_ptr->tim_roots_ac, flag);
	do_s16b(&p_ptr->tim_roots_dam, flag);

	do_s16b(&p_ptr->tim_invis, flag);
	do_s16b(&p_ptr->word_recall, flag);
	do_s16b(&p_ptr->recall_dungeon, flag);
	do_s16b(&p_ptr->see_infra, flag);
	do_s16b(&p_ptr->tim_infra, flag);
	do_s16b(&p_ptr->oppose_fire, flag);
	do_s16b(&p_ptr->oppose_cold, flag);
	do_s16b(&p_ptr->oppose_acid, flag);
	do_s16b(&p_ptr->oppose_elec, flag);
	do_s16b(&p_ptr->oppose_pois, flag);
	do_s16b(&p_ptr->oppose_ld, flag);
	do_s16b(&p_ptr->oppose_cc, flag);
	do_s16b(&p_ptr->oppose_ss, flag);
	do_s16b(&p_ptr->oppose_nex, flag);

	do_s16b(&p_ptr->tim_esp, flag);
	do_s16b(&p_ptr->tim_wraith, flag);
	do_s16b(&p_ptr->tim_ffall, flag);
	do_ver_s16b(&p_ptr->tim_fly, SAVEFILE_VERSION, 0, flag);
	do_s16b(&tmp16s, flag);
	do_ver_s16b(&p_ptr->tim_poison, SAVEFILE_VERSION, 0, flag);
	do_s16b(&tmp16s, flag);
	do_s16b(&p_ptr->tim_invisible, flag);
	do_s16b(&p_ptr->tim_inv_pow, flag);
	do_s16b(&p_ptr->tim_mimic, flag);
	do_s16b(&p_ptr->lightspeed, flag);
	do_s16b(&p_ptr->tim_lite, flag);
	do_ver_s16b(&p_ptr->tim_regen, SAVEFILE_VERSION, 0, flag);
	do_ver_s16b(&p_ptr->tim_regen_pow, SAVEFILE_VERSION, 0, flag);
	do_s16b(&p_ptr->holy, flag);
	do_s16b(&tmp16s, flag);
	do_s16b(&tmp16s, flag);
	do_s16b(&p_ptr->immov_cntr, flag);
	do_s16b(&p_ptr->strike, flag);
	do_s16b(&tmp16s, flag);
	do_s16b(&p_ptr->tim_reflect, flag);
	do_s16b(&tmp16s, flag);
	do_s16b(&p_ptr->tim_deadly, flag);
	do_s16b(&p_ptr->prob_travel, flag);
	do_s16b(&p_ptr->disrupt_shield, flag);
	do_s16b(&p_ptr->parasite, flag);
	do_s16b(&p_ptr->parasite_r_idx, flag);
	do_s32b(&tmp32s, flag);
	do_s32b(&tmp32s, flag);
	do_s16b(&p_ptr->absorb_soul, flag);
	do_s32b(&p_ptr->inertia_controlled_spell, flag);
	do_s16b(&p_ptr->last_rewarded_level, flag);

	do_s16b(&tmp16s, flag); /* compat */

	if (flag == ls_flag_t::SAVE) { tmp16s = CORRUPTIONS_MAX; }
	do_s16b(&tmp16s, flag);
	if (tmp16s > CORRUPTIONS_MAX) {
		quit("Too many corruptions");
	}

	for (i = 0; i < tmp16s; i++)
	{
		if (flag == ls_flag_t::SAVE)
			tmp8u = p_ptr->corruptions[i];

		do_byte(&tmp8u, flag);

		if (flag == ls_flag_t::LOAD)
			p_ptr->corruptions[i] = tmp8u;
	}

	do_byte((byte*)&p_ptr->corrupt_anti_teleport_stopped, flag);

	do_byte(&p_ptr->confusing, flag);
	do_byte((byte*)&p_ptr->black_breath, flag);
	do_byte((byte*)&fate_flag, flag);
	do_byte(&p_ptr->searching, flag);
	do_byte(&tmp8u, flag);
	do_byte(&p_ptr->preserve, flag);
	do_byte(&p_ptr->special, flag);
	do_byte((byte*)&ambush_flag, flag);
	do_byte(&p_ptr->allow_one_death, flag);
	do_s16b(&tmp16s, flag);

	do_byte(&tmp8u, flag);

	do_s16b(&no_breeds, flag);
	do_s16b(&p_ptr->protgood, flag);

	/* Auxilliary variables */
	do_u32b(&p_ptr->mimic_extra, flag);
	do_u32b(&p_ptr->antimagic_extra, flag);
	do_u32b(&tmp32u, flag);
	do_u32b(&tmp32u, flag);
	do_u32b(&tmp32u, flag);
	do_u32b(&p_ptr->music_extra, flag);
	do_u32b(&tmp32u, flag);
	do_u32b(&p_ptr->necro_extra, flag);
	do_u32b(&p_ptr->necro_extra2, flag);

	do_u32b(&tmp32u, flag);
	do_u32b(&tmp32u, flag);
	do_u32b(&tmp32u, flag);
	do_u32b(&tmp32u, flag);
	do_u32b(&tmp32u, flag);
	do_u32b(&tmp32u, flag);
	do_u32b(&tmp32u, flag);

	do_u16b(&p_ptr->body_monster, flag);
	do_byte((byte*)&p_ptr->disembodied, flag);

	/* Are we in astral mode? */
	do_byte((byte*)&p_ptr->astral, flag);

	if (flag == ls_flag_t::SAVE) tmp16s = POWER_MAX;
	do_s16b(&tmp16s, flag);
	if ((flag == ls_flag_t::LOAD) && (tmp16s > POWER_MAX))
		note(format("Too many (%u) powers!", tmp16s));
	for (i = 0; i < POWER_MAX; i++)
		do_byte((byte*)&p_ptr->powers_mod[i], flag);

	skip_ver_byte(100, flag);

	/* The tactic */
	do_byte((byte*)&p_ptr->tactic, flag);

	/* The movement */
	do_byte((byte*)&p_ptr->movement, flag);

	/* The comapnions killed */
	do_s16b(&p_ptr->companion_killed, flag);

	/* The fate */
	do_byte((byte*)&p_ptr->no_mortal, flag);

	/* The bounties -- kept only for load-compatibility with old savefiles. */
	for (i = 0; i < 24; i++) {
		tmp16s = 0; do_s16b(&tmp16s, flag);
		tmp16s = 0; do_s16b(&tmp16s, flag);
	}
	tmp32u = 0; do_u32b(&tmp32u, flag);

	/* Spells */
	do_s16b(&spell_num, flag);
	for (i = 0; i < MAX_SPELLS; i++)
		do_spells(i, flag);
	do_s16b(&rune_num, flag);
	for (i = 0; i < MAX_RUNES; i++)
	{
		do_string(rune_spells[i].name, 30, flag);
		do_s16b(&rune_spells[i].type, flag);
		do_s16b(&rune_spells[i].rune2, flag);
		do_s16b(&rune_spells[i].mana, flag);
	}

	/* Load random seeds */
	do_u32b(&dummy32u, flag);    /* Load-compatibility with old savefiles. */
	do_u32b(&seed_flavor, flag); /* For consistent object flavors. */
	do_u32b(&dummy32u, flag);    /* Load-compatibility with old savefiles. */

	/* Special stuff */
	do_u16b(&tmp16b, flag);      /* Dummy */
	do_u16b(&total_winner, flag);
	do_u16b(&has_won, flag);
	do_u16b(&noscore, flag);

	/* Write death */
	if (flag == ls_flag_t::SAVE) tmp8u = death;
	do_byte(&tmp8u, flag);
	if (flag == ls_flag_t::LOAD) death = tmp8u;

	/* Incompatible module? */
	if (flag == ls_flag_t::LOAD)
	{
		s32b ok;

		ok = module_savefile_loadable(loaded_game_module);

		/* Argh bad game module! */
		if (!ok)
		{
			note(format("Bad game module. Savefile was saved with module '%s' but game is '%s'.", loaded_game_module, game_module));
			return (FALSE);
		}
	}

	/* Write feeling */
	if (flag == ls_flag_t::SAVE) tmp8u = feeling;
	do_byte(&tmp8u, flag);
	if (flag == ls_flag_t::LOAD) feeling = tmp8u;

	/* Turn of last "feeling" */
	do_s32b(&old_turn, flag);

	/* Current turn */
	do_s32b(&turn, flag);

	return TRUE;
}


/*
 * Read a monster
 */
static void do_monster(monster_type *m_ptr, ls_flag_t flag)
{
	int i;

	/* Read the monster race */
	do_s16b(&m_ptr->r_idx, flag);

	do_u16b(&m_ptr->ego, flag);

	/* Read the other information */
	do_byte(&m_ptr->fy, flag);
	do_byte(&m_ptr->fx, flag);

	do_s32b(&m_ptr->hp, flag);
	do_s32b(&m_ptr->maxhp, flag);

	do_s16b(&m_ptr->csleep, flag);
	do_byte(&m_ptr->mspeed, flag);
	do_byte(&m_ptr->energy, flag);
	do_byte(&m_ptr->stunned, flag);
	do_byte(&m_ptr->confused, flag);
	do_byte(&m_ptr->monfear, flag);
	do_u32b(&m_ptr->smart, flag);
	do_s16b(&m_ptr->status, flag);
	do_s16b(&m_ptr->possessor, flag);
	do_byte(&m_ptr->speed, flag);
	do_byte(&m_ptr->level, flag);
	do_s16b(&m_ptr->ac, flag);
	do_s32b(&m_ptr->exp, flag);
	do_s16b(&m_ptr->target, flag);

	do_s16b(&m_ptr->bleeding, flag);
	do_s16b(&m_ptr->poisoned, flag);

	do_s32b(&m_ptr->mflag, flag);

	if (flag == ls_flag_t::LOAD) m_ptr->mflag &= PERM_MFLAG_MASK;

	/* Attacks */
	for (i = 0; i < 4; i++)
	{
		do_byte(&m_ptr->blow[i].method, flag);
		do_byte(&m_ptr->blow[i].effect, flag);
		do_byte(&m_ptr->blow[i].d_dice, flag);
		do_byte(&m_ptr->blow[i].d_side, flag);
	}
}



/*
 * Determine if an item can be wielded/worn (e.g. helmet, sword, bow, arrow)
 */
static bool_ wearable_p(object_type *o_ptr)
{
	/* Valid "tval" codes */
	switch (o_ptr->tval)
	{
	case TV_WAND:
	case TV_STAFF:
	case TV_ROD:
	case TV_ROD_MAIN:
	case TV_SHOT:
	case TV_ARROW:
	case TV_BOLT:
	case TV_BOOMERANG:
	case TV_BOW:
	case TV_DIGGING:
	case TV_HAFTED:
	case TV_POLEARM:
	case TV_MSTAFF:
	case TV_SWORD:
	case TV_AXE:
	case TV_BOOTS:
	case TV_GLOVES:
	case TV_HELM:
	case TV_CROWN:
	case TV_SHIELD:
	case TV_CLOAK:
	case TV_SOFT_ARMOR:
	case TV_HARD_ARMOR:
	case TV_DRAG_ARMOR:
	case TV_SCROLL:
	case TV_LITE:
	case TV_POTION:
	case TV_POTION2:
	case TV_AMULET:
	case TV_RING:
	case TV_HYPNOS:
	case TV_INSTRUMENT:
	case TV_DAEMON_BOOK:
	case TV_TRAPKIT:
	case TV_TOOL:
		{
			return (TRUE);
		}
	}

	/* Nope */
	return (FALSE);
}


/*
 * rd/wr an object
 *
 * FIXME! This code probably has a lot of cruft from the old Z/V codebase.
 *
 */
static void do_item(object_type *o_ptr, ls_flag_t flag)
{
	byte old_dd;
	byte old_ds;

	u32b f1, f2, f3, f4, f5, esp;

	object_kind *k_ptr;

	/* Kind */
	do_s16b(&o_ptr->k_idx, flag);

	/* Location */
	do_byte(&o_ptr->iy, flag);
	do_byte(&o_ptr->ix, flag);

	/* Type/Subtype */
	do_byte(&o_ptr->tval, flag);
	do_byte(&o_ptr->sval, flag);

	/* Special pval */
	do_s32b(&o_ptr->pval, flag);

	/* Special pval */
	do_s16b(&o_ptr->pval2, flag);

	/* Special pval */
	do_s32b(&o_ptr->pval3, flag);

	do_byte(&o_ptr->discount, flag);
	do_byte(&o_ptr->number, flag);
	do_s32b(&o_ptr->weight, flag);

	do_byte(&o_ptr->name1, flag);
	do_s16b(&o_ptr->name2, flag);
	do_s16b(&o_ptr->name2b, flag);
	do_s16b(&o_ptr->timeout, flag);

	do_s16b(&o_ptr->to_h, flag);
	do_s16b(&o_ptr->to_d, flag);
	do_s16b(&o_ptr->to_a, flag);

	do_s16b(&o_ptr->ac, flag);

	/* We do special processing of this flag when reading */
	if (flag == ls_flag_t::LOAD)
	{
		do_byte(&old_dd, ls_flag_t::LOAD);
		do_byte(&old_ds, ls_flag_t::LOAD);
	}
	if (flag == ls_flag_t::SAVE)
	{
		do_byte(&o_ptr->dd, ls_flag_t::SAVE);
		do_byte(&o_ptr->ds, ls_flag_t::SAVE);
	}

	do_byte(&o_ptr->ident, flag);

	do_byte(&o_ptr->marked, flag);

	/* flags */
	do_u32b(&o_ptr->art_flags1, flag);
	do_u32b(&o_ptr->art_flags2, flag);
	do_u32b(&o_ptr->art_flags3, flag);
	do_u32b(&o_ptr->art_flags4, flag);
	do_u32b(&o_ptr->art_flags5, flag);
	do_u32b(&o_ptr->art_esp, flag);

	/* obvious flags */
	do_u32b(&o_ptr->art_oflags1, flag);
	do_u32b(&o_ptr->art_oflags2, flag);
	do_u32b(&o_ptr->art_oflags3, flag);
	do_u32b(&o_ptr->art_oflags4, flag);
	do_u32b(&o_ptr->art_oflags5, flag);
	do_u32b(&o_ptr->art_oesp, flag);

	/* Monster holding object */
	do_s16b(&o_ptr->held_m_idx, flag);

	/* Special powers */
	do_byte(&o_ptr->xtra1, flag);
	do_s16b(&o_ptr->xtra2, flag);

	do_byte(&o_ptr->elevel, flag);
	do_s32b(&o_ptr->exp, flag);

	/* Read the pseudo-id */
	do_byte(&o_ptr->sense, flag);

	/* Read the found info */
	do_byte(&o_ptr->found, flag);
	do_s16b(&o_ptr->found_aux1, flag);
	do_s16b(&o_ptr->found_aux2, flag);
	do_s16b(&o_ptr->found_aux3, flag);
	do_s16b(&o_ptr->found_aux4, flag);

	if (flag == ls_flag_t::LOAD)
	{
		char buf[128];
		/* Inscription */
		load_string(buf, 128);
		if (buf[0])
		{
			o_ptr->note = quark_add(buf);
		}
		/* Artifact name */
		load_string(buf, 128);
		if (buf[0])
		{
			o_ptr->art_name = quark_add(buf);
		}
	}
	if (flag == ls_flag_t::SAVE)
	{
		/* Save the inscription (if any) */
		if (o_ptr->note)
		{
			save_string(quark_str(o_ptr->note));
		}
		else
		{
			save_string("");
		}
		if (o_ptr->art_name)
		{
			save_string(quark_str(o_ptr->art_name));
		}
		else
		{
			save_string("");
		}
	}

	if (flag == ls_flag_t::SAVE) return ; 	/* Stick any more shared code before this. The rest
										   of this function is reserved for ls_flag_t::LOAD's
										   cleanup functions */
	/*********** END OF ls_flag_t::SAVE ***************/

	/* Obtain the "kind" template */
	k_ptr = &k_info[o_ptr->k_idx];

	/* Obtain tval/sval from k_info */
	o_ptr->tval = k_ptr->tval;
	if (o_ptr->tval != TV_RANDART) o_ptr->sval = k_ptr->sval;


	/* Repair non "wearable" items */
	if (!wearable_p(o_ptr))
	{
		/* Acquire correct fields */
		o_ptr->to_h = k_ptr->to_h;
		o_ptr->to_d = k_ptr->to_d;
		o_ptr->to_a = k_ptr->to_a;

		/* Acquire correct fields */
		o_ptr->ac = k_ptr->ac;
		o_ptr->dd = k_ptr->dd;
		o_ptr->ds = k_ptr->ds;

		/* All done */
		return;
	}


	/* Extract the flags */
	object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);

	/* Paranoia */
	if (o_ptr->name1)
	{
		artifact_type *a_ptr;

		/* Obtain the artifact info */
		a_ptr = &a_info[o_ptr->name1];

		/* Verify that artifact */
		if (!a_ptr->name) o_ptr->name1 = 0;
	}

	/* Paranoia */
	if (o_ptr->name2)
	{
		ego_item_type *e_ptr;

		/* Obtain the ego-item info */
		e_ptr = &e_info[o_ptr->name2];

		/* Verify that ego-item */
		if (!e_ptr->name) o_ptr->name2 = 0;
	}


	/* Acquire standard fields */
	o_ptr->ac = k_ptr->ac;
	o_ptr->dd = k_ptr->dd;
	o_ptr->ds = k_ptr->ds;

	/* Artifacts */
	if (o_ptr->name1)
	{
		artifact_type *a_ptr;

		/* Obtain the artifact info */
		a_ptr = &a_info[o_ptr->name1];

		/* Acquire new artifact fields */
		o_ptr->ac = a_ptr->ac;
		o_ptr->dd = a_ptr->dd;
		o_ptr->ds = a_ptr->ds;

		/* Acquire new artifact weight */
		o_ptr->weight = a_ptr->weight;
	}

	/* Ego items */
	if (o_ptr->name2)
	{
		o_ptr->dd = old_dd;
		o_ptr->ds = old_ds;
	}

	if (o_ptr->art_name)		/* A random artifact */
	{
		o_ptr->dd = old_dd;
		o_ptr->ds = old_ds;
	}
}

static void do_cave_type(cave_type *c_ptr, ls_flag_t flag)
{
	do_u16b(&c_ptr->info, flag);
	do_byte(&c_ptr->feat, flag);
	do_byte(&c_ptr->mimic, flag);
	do_s16b(&c_ptr->special, flag);
	do_s16b(&c_ptr->special2, flag);
	do_s16b(&c_ptr->t_idx, flag);
	do_s16b(&c_ptr->inscription, flag);
	do_byte(&c_ptr->mana, flag);
	do_s16b(&c_ptr->effect, flag);
}

static void do_grid(ls_flag_t flag)
{
	for (int y = 0; y < cur_hgt; y++)
	{
		for (int x = 0; x < cur_wid; x++)
		{
			do_cave_type(&cave[y][x], flag);
		}
	}
}

static void my_sentinel(const char *place, u16b value, ls_flag_t flag)
/* This function lets us know exactly where a savefile is
   broken by reading/writing conveniently a sentinel at this
   spot */
{
	if (flag == ls_flag_t::SAVE)
	{
		do_u16b(&value, flag);
		return;
	}
	if (flag == ls_flag_t::LOAD)
	{
		u16b found;
		do_u16b(&found, flag);
		if (found == value)		/* All is good */
			return;
		/* All is bad */
		note(format("Savefile broken %s", place));
		return;
	}
	note(format("Impossible has occurred")); 	/* Programmer error */
	exit(0);
}



/*
 * Handle dungeon
 *
 * The monsters/objects must be loaded in the same order
 * that they were stored, since the actual indexes matter.
 */
static bool_ do_dungeon(ls_flag_t flag, bool_ no_companions)
{
	int i;

	cave_type *c_ptr;

	/* Read specific */
	u16b tmp16b = 0;

	my_sentinel("Before do_dungeon", 324, flag);

	/* Header info */
	do_s16b(&dun_level, flag);
	do_byte(&dungeon_type, flag);
	do_s16b(&num_repro, flag);
	do_s16b(&p_ptr->py, flag);
	do_s16b(&p_ptr->px, flag);
	do_s16b(&cur_hgt, flag);
	do_s16b(&cur_wid, flag);
	do_s16b(&max_panel_rows, flag);
	do_s16b(&max_panel_cols, flag);

	do_u32b(&dungeon_flags1, flag);
	do_u32b(&dungeon_flags2, flag);

	/* Last teleportation */
	do_s16b(&last_teleportation_y, flag);
	do_s16b(&last_teleportation_y, flag);

	/* Spell effects */
	tmp16b = MAX_EFFECTS;
	do_u16b(&tmp16b, flag);

	if ((flag == ls_flag_t::LOAD) && (tmp16b > MAX_EFFECTS))
	{
		quit("Too many spell effects");
	}

	for (i = 0; i < tmp16b; ++i)
	{
		do_s16b(&effects[i].type, flag);
		do_s16b(&effects[i].dam, flag);
		do_s16b(&effects[i].time, flag);
		do_u32b(&effects[i].flags, flag);
		do_s16b(&effects[i].cx, flag);
		do_s16b(&effects[i].cy, flag);
		do_s16b(&effects[i].rad, flag);
	}

	/* TO prevent bugs with evolving dungeons */
	for (i = 0; i < 100; i++)
	{
		do_s16b(&floor_type[i], flag);
		do_s16b(&fill_type[i], flag);
	}

	if ((flag == ls_flag_t::LOAD) && (!dun_level && !p_ptr->inside_quest))
	{
		int xstart = 0;
		int ystart = 0;
		/* Init the wilderness */
		process_dungeon_file("w_info.txt", &ystart, &xstart, cur_hgt, cur_wid,
				     TRUE, FALSE);

		/* Init the town */
		xstart = 0;
		ystart = 0;
		init_flags = 0;
		process_dungeon_file("t_info.txt", &ystart, &xstart, cur_hgt, cur_wid,
				     TRUE, FALSE);
	}

	do_grid(flag);

	/*** Objects ***/

	if (flag == ls_flag_t::SAVE) compact_objects(0);
	if (flag == ls_flag_t::SAVE) compact_monsters(0);
	if (flag == ls_flag_t::SAVE)
	{
		tmp16b = o_max;

		if (no_companions)
		{
			for (i = 1; i < o_max; i++)
			{
				object_type *o_ptr = &o_list[i];

				if (o_ptr->held_m_idx && (m_list[o_ptr->held_m_idx].status == MSTATUS_COMPANION)) tmp16b--;
			}
		}

		/* Item count */
		do_u16b(&tmp16b, flag);

		tmp16b = o_max;
	}
	else
		/* Read item count */
		do_u16b(&tmp16b, flag);

	/* Verify maximum */
	if ((flag == ls_flag_t::LOAD) && (tmp16b > max_o_idx))
	{
		note(format("Too many (%d) object entries!", tmp16b));
		return (FALSE);
	}

	/* Dungeon items */
	for (i = 1; i < tmp16b; i++)
	{
		int o_idx;

		object_type *o_ptr;

		if (flag == ls_flag_t::SAVE)
		{
			o_ptr = &o_list[i];
			/* Don't save objects held by companions when no_companions is set */
			if (no_companions && o_ptr->held_m_idx && (m_list[o_ptr->held_m_idx].status == MSTATUS_COMPANION)) continue;

			do_item(o_ptr, ls_flag_t::SAVE);
			continue; 			/* Saving is easy */
		}
		/* Until the end of the loop, this is all ls_flag_t::LOAD */

		/* Get a new record */
		o_idx = o_pop();

		/* Oops */
		if (i != o_idx)
		{
			note(format("Object allocation error (%d <> %d)", i, o_idx));
			return (FALSE);
		}


		/* Acquire place */
		o_ptr = &o_list[o_idx];

		/* Read the item */
		do_item(o_ptr, ls_flag_t::LOAD);

		/* Monster */
		if (o_ptr->held_m_idx)
		{
			/* Monster */
			monster_type *m_ptr = &m_list[o_ptr->held_m_idx];

			/* Place the object */
			m_ptr->hold_o_idxs.push_back(o_idx);
		}

		/* Dungeon */
		else
		{
			/* Access the item location */
			c_ptr = &cave[o_ptr->iy][o_ptr->ix];

			/* Place the object */
			c_ptr->o_idxs.push_back(o_idx);
		}
	}

	/*** Monsters ***/

	if (flag == ls_flag_t::SAVE)
	{
		tmp16b = m_max;

		if (no_companions)
		{
			for (i = 1; i < m_max; i++)
			{
				monster_type *m_ptr = &m_list[i];

				if (m_ptr->status == MSTATUS_COMPANION) tmp16b--;
			}
		}

		/* Write the monster count */
		do_u16b(&tmp16b, flag);

		tmp16b = m_max;
	}
	else
		/* Read the monster count */
		do_u16b(&tmp16b, flag);

	/* Validate */
	if ((flag == ls_flag_t::LOAD) && (tmp16b > max_m_idx))
	{
		note(format("Too many (%d) monster entries!", tmp16b));
		return (FALSE);
	}

	/* Read the monsters */
	for (i = 1; i < tmp16b; i++)
	{
		int m_idx;
		monster_type *m_ptr;
		monster_race *r_ptr;

		if (flag == ls_flag_t::SAVE)
		{
			m_ptr = &m_list[i];

			/* Don't save companions when no_companions is set */
			if (no_companions && m_ptr->status == MSTATUS_COMPANION) continue;

			do_monster(m_ptr, ls_flag_t::SAVE);
			continue; 			/* Easy to save a monster */
		}
		/* From here on, it's all ls_flag_t::LOAD */
		/* Get a new record */
		m_idx = m_pop();

		/* Oops */
		if (i != m_idx)
		{
			note(format("Monster allocation error (%d <> %d)", i, m_idx));
			return (FALSE);
		}

		/* Acquire monster */
		m_ptr = &m_list[m_idx];

		/* Read the monster */
		do_monster(m_ptr, ls_flag_t::LOAD);

		/* Access grid */
		c_ptr = &cave[m_ptr->fy][m_ptr->fx];

		/* Mark the location */
		c_ptr->m_idx = m_idx;

		/* Controlled ? */
		if (m_ptr->mflag & MFLAG_CONTROL)
			p_ptr->control = m_idx;

		/* Access race */
		r_ptr = &r_info[m_ptr->r_idx];

		/* Count XXX XXX XXX */
		r_ptr->cur_num++;
	}

	/* Read the kept monsters */

	tmp16b = (flag == ls_flag_t::SAVE && !no_companions) ? max_m_idx : 0;

	/* Read the monster count */
	do_u16b(&tmp16b, flag);

	/* Hack -- verify */
	if ((flag == ls_flag_t::LOAD) && (tmp16b > max_m_idx))
	{
		note(format("Too many (%d) monster entries!", tmp16b));
		return (FALSE);
	}
	for (i = 1; i < tmp16b; i++)
	{
		monster_type *m_ptr;

		/* Acquire monster */
		m_ptr = &km_list[i];

		/* Read the monster */
		do_monster(m_ptr, flag);
	}

	/*** Success ***/

	/* The dungeon is ready */
	if (flag == ls_flag_t::LOAD) character_dungeon = TRUE;

	/* Success */
	return (TRUE);
}

/* Save the current persistent dungeon -SC- */
void save_dungeon(void)
{
	char tmp[16];
	char name[1024], buf[5];

	/* Save only persistent dungeons */
	if (!get_dungeon_save(buf) || (!dun_level)) return;

	/* Construct filename */
	sprintf(tmp, "%s.%s", player_base, buf);
	path_build(name, 1024, ANGBAND_DIR_SAVE, tmp);

	/* Open the file */
	fff = my_fopen(name, "wb");

	/* Save the dungeon */
	do_dungeon(ls_flag_t::SAVE, TRUE);

	my_fclose(fff);
}

bool_ file_exist(cptr buf)
{
	int fd;
	bool_ result;

	/* Open savefile */
	fd = fd_open(buf, O_RDONLY);

	/* File exists */
	if (fd >= 0)
	{
		fd_close(fd);
		result = TRUE;
	}
	else
		result = FALSE;

	return result;
}


/*
 * Handle monster lore
 */
static void do_lore(int r_idx, ls_flag_t flag)
{
	monster_race *r_ptr = &r_info[r_idx];

	/* Count sights/deaths/kills */
	do_s16b(&r_ptr->r_sights, flag);
	do_s16b(&r_ptr->r_deaths, flag);
	do_s16b(&r_ptr->r_pkills, flag);
	do_s16b(&r_ptr->r_tkills, flag);

	/* Count wakes and ignores */
	do_byte(&r_ptr->r_wake, flag);
	do_byte(&r_ptr->r_ignore, flag);

	/* Extra stuff */
	do_byte(&r_ptr->r_xtra1, flag);
	do_byte(&r_ptr->r_xtra2, flag);

	/* Count drops */
	do_byte(&r_ptr->r_drop_gold, flag);
	do_byte(&r_ptr->r_drop_item, flag);

	/* Count spells */
	do_byte(&r_ptr->r_cast_inate, flag);
	do_byte(&r_ptr->r_cast_spell, flag);

	/* Count blows of each type */
	do_byte(&r_ptr->r_blows[0], flag);
	do_byte(&r_ptr->r_blows[1], flag);
	do_byte(&r_ptr->r_blows[2], flag);
	do_byte(&r_ptr->r_blows[3], flag);

	/* Memorize flags */
	do_u32b(&r_ptr->r_flags1, flag); 	/* Just to remind you */
	do_u32b(&r_ptr->r_flags2, flag); 	/* flag is unrelated to */
	do_u32b(&r_ptr->r_flags3, flag); 	/* the other argument */
	do_u32b(&r_ptr->r_flags4, flag);
	do_u32b(&r_ptr->r_flags5, flag);
	do_u32b(&r_ptr->r_flags6, flag);
	do_u32b(&r_ptr->r_flags7, flag);
	do_u32b(&r_ptr->r_flags8, flag);
	do_u32b(&r_ptr->r_flags9, flag);

	/* Read the "Racial" monster tmp16b per level */
	do_s16b(&r_ptr->max_num, flag);

	do_byte((byte*)&r_ptr->on_saved, flag);

	if (flag == ls_flag_t::LOAD)
	{
		/* Lore flag repair? */
		r_ptr->r_flags1 &= r_ptr->flags1;
		r_ptr->r_flags2 &= r_ptr->flags2;
		r_ptr->r_flags3 &= r_ptr->flags3;
		r_ptr->r_flags4 &= r_ptr->flags4;
		r_ptr->r_flags5 &= r_ptr->flags5;
		r_ptr->r_flags6 &= r_ptr->flags6;
	}
}




/*
 * Read a store
 */
static void do_store(store_type *str, ls_flag_t flag)
{
	byte store_inven_max = STORE_INVEN_MAX;

	/* Some basic info */
	do_s32b(&str->store_open, flag);
	do_u16b(&str->owner, flag);

	/* Could be cleaner, done this way for benefit of the for loop later on */
	byte num;
	if (flag == ls_flag_t::SAVE) num = str->stock_num;
	do_byte(&num, flag);

	/* Last visit */
	do_s32b(&str->last_visit, flag);

	/* Items */
	for (int j = 0; j < num; j++)
	{
		if (flag == ls_flag_t::LOAD)
			/* Can't this be cleaner? */
		{
			object_type forge;
			/* Wipe the object */
			object_wipe(&forge);
			/* Read the item */
			do_item(&forge, ls_flag_t::LOAD);
			/* Acquire valid items */
			if ((str->stock_num < store_inven_max) && (str->stock_num < str->stock_size))
			{
				int k = str->stock_num++;

				/* Acquire the item */
				object_copy(&str->stock[k], &forge);
			}
		}
		if (flag == ls_flag_t::SAVE) do_item(&str->stock[j], flag);
	}
}

/*
 * RNG state
 */
static void do_randomizer(ls_flag_t flag)
{
	int i;

	u16b tmp16u = 0;

	/* Tmp */
	do_u16b(&tmp16u, flag);

	/* Place */
	do_u16b(&Rand_place, flag);

	/* State */
	for (i = 0; i < RAND_DEG; i++)
	{
		do_u32b(&Rand_state[i], flag);
	}

	/* Accept */
	if (flag == ls_flag_t::LOAD)
	{
		Rand_quick = FALSE;
	}
}

/*
 * Handle options
 *
 * Normal options are stored as a set of 256 bit flags,
 * plus a set of 256 bit masks to indicate which bit flags were defined
 * at the time the savefile was created.  This will allow new options
 * to be added, and old options to be removed, at any time, without
 * hurting old savefiles.
 *
 * The window options are stored in the same way, but note that each
 * window gets 32 options, and their order is fixed by certain defines.
 */
static void do_options(ls_flag_t flag)
{
	int i, n;

	u32b oflag[8];
	u32b mask[8];

	/*** Special info */

	/* Read "delay_factor" */
	do_byte(&delay_factor, flag);

	/* Read "hitpoint_warn" */
	do_byte(&hitpoint_warn, flag);

	/*** Cheating options ***/
	if (flag == ls_flag_t::LOAD)		/* There *MUST* be some nice way to unify this! */
	{
		u16b c;
		do_u16b(&c, ls_flag_t::LOAD);
		if (c & 0x0002) wizard = TRUE;
		cheat_peek = (c & 0x0100) ? TRUE : FALSE;
		cheat_hear = (c & 0x0200) ? TRUE : FALSE;
		cheat_room = (c & 0x0400) ? TRUE : FALSE;
		cheat_xtra = (c & 0x0800) ? TRUE : FALSE;
		cheat_know = (c & 0x1000) ? TRUE : FALSE;
		cheat_live = (c & 0x2000) ? TRUE : FALSE;
	}
	if (flag == ls_flag_t::SAVE)
	{
		u16b c = 0;
		if (wizard) c |= 0x0002;
		if (cheat_peek) c |= 0x0100;
		if (cheat_hear) c |= 0x0200;
		if (cheat_room) c |= 0x0400;
		if (cheat_xtra) c |= 0x0800;
		if (cheat_know) c |= 0x1000;
		if (cheat_live) c |= 0x2000;
		do_u16b(&c, ls_flag_t::SAVE);
	}

	do_byte((byte*)&autosave_l, flag);
	do_byte((byte*)&autosave_t, flag);
	do_s16b(&autosave_freq, flag);

	if (flag == ls_flag_t::LOAD)
	{
		/* Read the option flags */
		for (n = 0; n < 8; n++) do_u32b(&oflag[n], flag);

		/* Read the option masks */
		for (n = 0; n < 8; n++) do_u32b(&mask[n], flag);

		/* Analyze the options */
		for (n = 0; n < 8; n++)
		{
			/* Analyze the options */
			for (i = 0; i < 32; i++)
			{
				/* Process valid flags */
				if (mask[n] & (1L << i))
				{
					/* Process valid flags */
					if (option_mask[n] & (1L << i))
					{
						/* Set */
						if (oflag[n] & (1L << i))
						{
							/* Set */
							option_flag[n] |= (1L << i);
						}

						/* Clear */
						else
						{
							/* Clear */
							option_flag[n] &= ~(1L << i);
						}
					}
				}
			}
		}


		/*** Window Options ***/

		/* Read the window flags */
		for (n = 0; n < 8; n++) do_u32b(&oflag[n], flag);

		/* Read the window masks */
		for (n = 0; n < 8; n++) do_u32b(&mask[n], flag);

		/* Analyze the options */
		for (n = 0; n < 8; n++)
		{
			/* Analyze the options */
			for (i = 0; i < 32; i++)
			{
				/* Process valid flags */
				if (mask[n] & (1L << i))
				{
					/* Process valid flags */
					if (window_mask[n] & (1L << i))
					{
						/* Set */
						if (oflag[n] & (1L << i))
						{
							/* Set */
							window_flag[n] |= (1L << i);
						}

						/* Clear */
						else
						{
							/* Clear */
							window_flag[n] &= ~(1L << i);
						}
					}
				}
			}
		}
	}
	if (flag == ls_flag_t::SAVE)
	{
		/* Analyze the options */
		for (i = 0; option_info[i].o_desc; i++)
		{
			int os = option_info[i].o_page;
			int ob = option_info[i].o_bit;

			/* Process real entries */
			if (option_info[i].o_var)
			{
				/* Set */
				if (*option_info[i].o_var)
				{
					/* Set */
					option_flag[os] |= (1L << ob);
				}

				/* Clear */
				else
				{
					/* Clear */
					option_flag[os] &= ~(1L << ob);
				}
			}
		}


		/*** Normal options ***/

		/* Dump the flags */
		for (i = 0; i < 8; i++) do_u32b(&option_flag[i], flag);

		/* Dump the masks */
		for (i = 0; i < 8; i++) do_u32b(&option_mask[i], flag);

		/*** Window options ***/

		/* Dump the flags */
		for (i = 0; i < 8; i++) do_u32b(&window_flag[i], flag);

		/* Dump the masks */
		for (i = 0; i < 8; i++) do_u32b(&window_mask[i], flag);
	}
}


/*
 * Handle player inventory
 *
 * FIXME! This function probably could be unified better
 * Note that the inventory is "re-sorted" later by "dungeon()".
 */
static bool_ do_inventory(ls_flag_t flag)
{
	if (flag == ls_flag_t::LOAD)
	{
		int slot = 0;

		object_type forge;
		object_type *q_ptr;

		/* No items */
		inven_cnt = 0;
		equip_cnt = 0;

		/* Read until done */
		while (1)
		{
			u16b n;

			/* Get the next item index */
			do_u16b(&n, ls_flag_t::LOAD);

			/* Nope, we reached the end */
			if (n == 0xFFFF) break;

			/* Get local object */
			q_ptr = &forge;

			/* Wipe the object */
			object_wipe(q_ptr);

			/* Read the item */
			do_item(q_ptr, ls_flag_t::LOAD);

			/* Hack -- verify item */
			if (!q_ptr->k_idx) return (FALSE);

			/* Wield equipment */
			if (n >= INVEN_WIELD)
			{
				/* Copy object */
				object_copy(&p_ptr->inventory[n], q_ptr);

				/* Take care of item sets */
				if (q_ptr->name1)
				{
					wield_set(q_ptr->name1, a_info[q_ptr->name1].set, TRUE);
				}

				/* One more item */
				equip_cnt++;
			}

			/* Warning -- backpack is full */
			else if (inven_cnt == INVEN_PACK)
			{
				/* Oops */
				note("Too many items in the inventory!");

				/* Fail */
				return (FALSE);
			}

			/* Carry inventory */
			else
			{
				/* Get a slot */
				n = slot++;

				/* Copy object */
				object_copy(&p_ptr->inventory[n], q_ptr);

				/* One more item */
				inven_cnt++;
			}
		}
	}
	if (flag == ls_flag_t::SAVE)
	{
		u16b i;
		u16b sent = 0xFFFF;
		for (i = 0; i < INVEN_TOTAL; i++)
		{
			object_type *o_ptr = &p_ptr->inventory[i];
			if (!o_ptr->k_idx) continue;
			do_u16b(&i, flag);
			do_item(o_ptr, flag);
		}
		do_u16b(&sent, ls_flag_t::SAVE); 	/* Sentinel */
	}
	/* Success */
	return (TRUE);
}



/*
 * Read the saved messages
 */
static void do_messages(ls_flag_t flag)   /* FIXME! We should be able to unify this better */
{
	int i;
	char buf[128];
	byte color;

	s16b num;

	/* Total */
	if (flag == ls_flag_t::SAVE) num = message_num();
	do_s16b(&num, flag);

	/* Read the messages */
	if (flag == ls_flag_t::LOAD)
	{
		byte tmp8u = 0;
		for (i = 0; i < num; i++)
		{
			/* Read the message */
			do_string(buf, 128, ls_flag_t::LOAD);
			do_byte(&color, flag);
			do_byte(&tmp8u, flag);

			/* Save the message */
			message_add(buf, color);
		}
	}
	if (flag == ls_flag_t::SAVE)
	{
		byte holder;
		byte zero = 0;
		for (i = num - 1; i >= 0; i--)
		{
			do_string((char *)message_str((s16b)i), 0, ls_flag_t::SAVE);
			holder = message_color((s16b)i);
			do_byte(&holder, flag);
			do_byte(&zero, flag);
		}
	}
}

/* Returns TRUE if we successfully load the dungeon */
bool_ load_dungeon(char *ext)
{
	char tmp[16];
	char name[1024];
	byte old_dungeon_type = dungeon_type;
	s16b old_dun = dun_level;

	/* Construct name */
	sprintf(tmp, "%s.%s", player_base, ext);
	path_build(name, 1024, ANGBAND_DIR_SAVE, tmp);

	/* Open the file */
	fff = my_fopen(name, "rb");

	if (fff == NULL)
	{
		dun_level = old_dun;
		dungeon_type = old_dungeon_type;

		my_fclose(fff);
		return (FALSE);
	}

	/* Read the dungeon */
	if (!do_dungeon(ls_flag_t::LOAD, FALSE))
	{
		dun_level = old_dun;
		dungeon_type = old_dungeon_type;

		my_fclose(fff);
		return (FALSE);
	}

	dun_level = old_dun;
	dungeon_type = old_dungeon_type;

	/* Done */
	my_fclose(fff);
	return (TRUE);
}

void do_fate(int i, ls_flag_t flag)
{
	if ((flag == ls_flag_t::LOAD) && (i >= MAX_FATES)) i = MAX_FATES - 1;

	do_byte(&fates[i].fate, flag);
	do_byte(&fates[i].level, flag);
	do_byte(&fates[i].serious, flag);
	do_s16b(&fates[i].o_idx, flag);
	do_s16b(&fates[i].e_idx, flag);
	do_s16b(&fates[i].a_idx, flag);
	do_s16b(&fates[i].v_idx, flag);
	do_s16b(&fates[i].r_idx, flag);
	do_s16b(&fates[i].count, flag);
	do_s16b(&fates[i].time, flag);
	do_byte((byte*)&fates[i].know, flag);
}

/*
 * Load/save timers.
 */
static void do_timers(ls_flag_t flag)
{
	timer_type *t_ptr;

	for (t_ptr = gl_timers; t_ptr != NULL; t_ptr = t_ptr->next)
	{
		do_bool(&t_ptr->enabled, flag);
		do_s32b(&t_ptr->delay, flag);
		do_s32b(&t_ptr->countdown, flag);
	}
}

/*
 * Load/save stores.
 */
static void do_stores(ls_flag_t flag)
{
	u16b tmp16u;
	u16b real_max = 0;

	/* Note that this forbids max_towns from shrinking, but that is fine */
	std::unique_ptr<byte[]> reals(new byte[max_towns]);

	/* Find the real towns */
	if (flag == ls_flag_t::SAVE)
	{
		for (int i = 1; i < max_towns; i++)
		{
			if (!(town_info[i].flags & (TOWN_REAL))) continue;
			reals[real_max++] = i;
		}
	}
	do_u16b(&real_max, flag);
	for (int i = 0; i < real_max; i++)
	{
		do_byte((byte*)&reals[i], flag);
	}

	/* Read the stores */
	if (flag == ls_flag_t::SAVE) tmp16u = max_st_idx;
	do_u16b(&tmp16u, flag);
	assert(tmp16u <= max_st_idx);

	/* Ok now read the real towns */
	for (int i = 0; i < real_max; i++)
	{
		int z = reals[i];

		/* Ultra paranoia */
		if (!town_info[z].stocked) create_stores_stock(z);

		for (int j = 0; j < tmp16u; j++)
		{
			do_store(&town_info[z].store[j], flag);
		}
	}
}

/*
 * Note that this function may not be needed at all.
 * It was taken out of load_player_aux(). Do we need it?
 */
static void junkinit(void)
{
	int i, j;
	p_ptr->inside_quest = 0;
	p_ptr->town_num = 1;
	p_ptr->wilderness_x = 4;
	p_ptr->wilderness_y = 4;
	for (i = 0; i < max_wild_x; i++)
	{
		for (j = 0; j < max_wild_y; j++)
		{
			wild_map[j][i].seed = rand_int(0x10000000);
		}
	}
}

static void morejunk(void)
{
	sp_ptr = &sex_info[p_ptr->psex]; 	/* Sex */
	rp_ptr = &race_info[p_ptr->prace]; 	/* Raceclass */
	rmp_ptr = &race_mod_info[p_ptr->pracem];
	cp_ptr = &class_info[p_ptr->pclass];
	spp_ptr = &class_info[p_ptr->pclass].spec[p_ptr->pspec];
}


/*
 * Actually read the savefile
 */
static bool_ do_savefile_aux(ls_flag_t flag)
{
	int i, j;

	byte tmp8u;
	u16b tmp16u;

	/* Mention the savefile version */
	if (flag == ls_flag_t::LOAD)
	{
		if (vernum < 100)
		{
			note(format("Savefile version %lu too old! ", vernum));
			return FALSE;
		}
		else
		{
			note(format("Loading version %lu savefile... ", vernum));
		}
	}
	if (flag == ls_flag_t::SAVE)
	{
		sf_when = time((time_t *) 0); 	/* Note when file was saved */
		sf_saves++; 				/* Increment the saves ctr */
	}

	/* Handle version bytes. FIXME! DG wants me to change this all around */
	if (flag == ls_flag_t::LOAD)
	{
		u32b mt32b;
		byte mtbyte;

		/* Discard all this, we've already read it */
		do_u32b(&mt32b, flag);
		do_byte(&mtbyte, flag);
	}
	if (flag == ls_flag_t::SAVE)
	{
		u32b saver;
		saver = SAVEFILE_VERSION;
		do_u32b(&saver, flag);
		tmp8u = (byte)rand_int(256);
		do_byte(&tmp8u, flag); 	/* 'encryption' */
	}

	/* Kept only for compatibility; always set to 0 */
	{
		u32b tmp32u = 0;
		do_u32b(&tmp32u, flag);
	}

	/* Time of last save */
	do_u32b(&sf_when, flag);

	/* Number of past lives */
	do_u16b(&sf_lives, flag);

	/* Number of times saved */
	do_u16b(&sf_saves, flag);

	/* Game module */
	if (flag == ls_flag_t::SAVE)
		strcpy(loaded_game_module, game_module);
	do_string(loaded_game_module, 80, flag);

	/* Timers */
	do_timers(flag);

	/* Read RNG state */
	do_randomizer(flag);

	/* Automatizer state */
	do_byte((byte*)&automatizer_enabled, flag);

	/* Then the options */
	do_options(flag);

	/* Then the "messages" */
	do_messages(flag);

	/* Monster Memory */
	if (flag == ls_flag_t::SAVE) tmp16u = max_r_idx;
	do_u16b(&tmp16u, flag);

	/* Incompatible save files */
	if ((flag == ls_flag_t::LOAD) && (tmp16u > max_r_idx))
	{
		note(format("Too many (%u) monster races!", tmp16u));
		return (FALSE);
	}

	/* Read the available records */
	for (i = 0; i < tmp16u; i++)
	{
		/* Read the lore */
		do_lore(i, flag);
	}

	/* Object Memory */
	if (flag == ls_flag_t::SAVE) tmp16u = max_k_idx;
	do_u16b(&tmp16u, flag);

	/* Incompatible save files */
	if ((flag == ls_flag_t::LOAD) && (tmp16u > max_k_idx))
	{
		note(format("Too many (%u) object kinds!", tmp16u));
		return (FALSE);
	}

	/* Read the object memory */
	for (i = 0; i < tmp16u; i++) do_xtra(i, flag);
	if (flag == ls_flag_t::LOAD) junkinit();

	{
		u16b max_towns_ldsv;
		u16b max_quests_ldsv;
		if (flag == ls_flag_t::SAVE) max_towns_ldsv = max_towns;
		/* Number of towns */
		do_u16b(&max_towns_ldsv, flag);
		/* Incompatible save files */
		if ((flag == ls_flag_t::LOAD) && (max_towns_ldsv > max_towns))
		{
			note(format("Too many (%u) towns!", max_towns_ldsv));
			return (FALSE);
		}
		/* Min of random towns */
		if (flag == ls_flag_t::SAVE) max_towns_ldsv = TOWN_RANDOM;
		do_u16b(&max_towns_ldsv, flag);
		/* Incompatible save files */
		if ((flag == ls_flag_t::LOAD) && (max_towns_ldsv != TOWN_RANDOM))
		{
			note(format("Different random towns base (%u)!", max_towns_ldsv));
			return (FALSE);
		}

		for (i = 0; i < max_towns; i++)
		{
			do_byte((byte*)&town_info[i].destroyed, flag);

			if (i >= TOWN_RANDOM)
			{
				do_u32b(&town_info[i].seed, flag);
				do_byte(&town_info[i].numstores, flag);
				do_byte(&town_info[i].flags, flag);

				/* If the town is realy used create a sock */
				if ((town_info[i].flags & (TOWN_REAL)) && (flag == ls_flag_t::LOAD))
				{
					create_stores_stock(i);
				}
			}
		}

		/* Number of dungeon */
		if (flag == ls_flag_t::SAVE) max_towns_ldsv = max_d_idx;
		do_u16b(&max_towns_ldsv, flag);

		/* Incompatible save files */
		if ((flag == ls_flag_t::LOAD) && (max_towns_ldsv > max_d_idx))
		{
			note(format("Too many dungeon types (%u)!", max_towns_ldsv));
			return (FALSE);
		}

		/* Number of towns per dungeon */
		if (flag == ls_flag_t::SAVE) max_quests_ldsv = TOWN_DUNGEON;
		do_u16b(&max_quests_ldsv, flag);
		/* Incompatible save files */
		if ((flag == ls_flag_t::LOAD) && (max_quests_ldsv > TOWN_DUNGEON))
		{
			note(format("Too many town per dungeons (%u)!", max_quests_ldsv));
			return (FALSE);
		}

		for (i = 0; i < max_towns_ldsv; i++)
		{
			for (j = 0; j < max_quests_ldsv; j++)
			{
				do_s16b(&(d_info[i].t_idx[j]), flag);
				do_s16b(&(d_info[i].t_level[j]), flag);
			}
			do_s16b(&(d_info[i].t_num), flag);
		}

		/* Sanity check number of quests */
		if (flag == ls_flag_t::SAVE) max_quests_ldsv = MAX_Q_IDX;
		do_u16b(&max_quests_ldsv, flag);

		/* Incompatible save files */
		if ((flag == ls_flag_t::LOAD) && (max_quests_ldsv != MAX_Q_IDX))
		{
			note(format("Invalid number of quests (%u)!", max_quests_ldsv));
			return (FALSE);
		}

		for (i = 0; i < MAX_Q_IDX; i++)
		{
			do_s16b(&quest[i].status, flag);
			for (auto &quest_data : quest[i].data)
			{
				do_s32b(&quest_data, flag);
			}

			/* Init the hooks */
			if ((flag == ls_flag_t::LOAD) && (quest[i].init != NULL))
			{
				quest[i].init(i);
			}
		}

		/* Position in the wilderness */
		do_s32b(&p_ptr->wilderness_x, flag);
		do_s32b(&p_ptr->wilderness_y, flag);
		do_byte((byte*)&p_ptr->wild_mode, flag);
		do_byte((byte*)&p_ptr->old_wild_mode, flag);

		{
			s32b wild_x_size, wild_y_size;
			if (flag == ls_flag_t::SAVE)
			{
				wild_x_size = max_wild_x;
				wild_y_size = max_wild_y;
			}
			/* Size of the wilderness */
			do_s32b(&wild_x_size, flag);
			do_s32b(&wild_y_size, flag);
			/* Incompatible save files */
			if ((flag == ls_flag_t::LOAD) &&
					((wild_x_size > max_wild_x) || (wild_y_size > max_wild_y)))
			{
				note(format("Wilderness is too big (%u/%u)!",
					    wild_x_size, wild_y_size));
				return (FALSE);
			}
			/* Wilderness seeds */
			for (i = 0; i < wild_x_size; i++)
			{
				for (j = 0; j < wild_y_size; j++)
				{
					do_u32b(&wild_map[j][i].seed, flag);
					do_u16b(&wild_map[j][i].entrance, flag);
					do_byte((byte*)&wild_map[j][i].known, flag);
				}
			}
		}
	}

	/* Load the random artifacts. */
	if (flag == ls_flag_t::SAVE) tmp16u = MAX_RANDARTS;
	do_u16b(&tmp16u, flag);
	if ((flag == ls_flag_t::LOAD) && (tmp16u > MAX_RANDARTS))
	{
		note(format("Too many (%u) random artifacts!", tmp16u));
		return (FALSE);
	}
	for (i = 0; i < tmp16u; i++)
	{
		random_artifact *ra_ptr = &random_artifacts[i];

		do_string(ra_ptr->name_full, 80, flag);
		do_string(ra_ptr->name_short, 80, flag);
		do_byte(&ra_ptr->level, flag);
		do_byte(&ra_ptr->attr, flag);
		do_u32b(&ra_ptr->cost, flag);
		do_byte(&ra_ptr->activation, flag);
		do_byte(&ra_ptr->generated, flag);
	}

	/* Load the Artifacts */
	if (flag == ls_flag_t::SAVE) tmp16u = max_a_idx;
	do_u16b(&tmp16u, flag);
	/* Incompatible save files */
	if ((flag == ls_flag_t::LOAD) && (tmp16u > max_a_idx))
	{
		note(format("Too many (%u) artifacts!", tmp16u));
		return (FALSE);
	}

	/* Read the artifact flags */
	for (i = 0; i < tmp16u; i++)
	{
		do_byte(&(&a_info[i])->cur_num, flag);
	}

	/* Fates */
	if (flag == ls_flag_t::SAVE) tmp16u = MAX_FATES;
	do_u16b(&tmp16u, flag);

	/* Incompatible save files */
	if ((flag == ls_flag_t::LOAD) && (tmp16u > MAX_FATES))
	{
		note(format("Too many (%u) fates!", tmp16u));
		return (FALSE);
	}

	/* Read the fate flags */
	for (i = 0; i < tmp16u; i++)
	{
		do_fate(i, flag);
	}

	/* Load the Traps */
	if (flag == ls_flag_t::SAVE) tmp16u = max_t_idx;
	do_u16b(&tmp16u, flag);

	/* Incompatible save files */
	if ((flag == ls_flag_t::LOAD) && (tmp16u > max_t_idx))
	{
		note(format("Too many (%u) traps!", tmp16u));
		return (FALSE);
	}

	/* fate flags */
	for (i = 0; i < tmp16u; i++)
	{
		do_byte((byte*)&t_info[i].ident, flag);
	}

	/* inscription knowledge */
	if (flag == ls_flag_t::SAVE) tmp16u = MAX_INSCRIPTIONS;
	do_u16b(&tmp16u, flag);

	/* Incompatible save files */
	if ((flag == ls_flag_t::LOAD) && (tmp16u > MAX_INSCRIPTIONS))
	{
		note(format("Too many (%u) inscriptions!", tmp16u));
		return (FALSE);
	}

	/* Read the inscription flag */
	for (i = 0; i < tmp16u; i++)
		do_byte((byte*)&inscription_info[i].know, flag);


	/* Read the extra stuff */
	if (!do_extra(flag))
		return FALSE;


	/* player_hp array */
	if (flag == ls_flag_t::SAVE) tmp16u = PY_MAX_LEVEL;
	do_u16b(&tmp16u, flag);
	/* Incompatible save files */
	if ((flag == ls_flag_t::LOAD) && (tmp16u > PY_MAX_LEVEL))
	{
		note(format("Too many (%u) hitpoint entries!", tmp16u));
		return (FALSE);
	}

	/* Read the player_hp array */
	for (i = 0; i < tmp16u; i++)
	{
		do_s16b(&player_hp[i], flag);
	}

	if (flag == ls_flag_t::LOAD) morejunk();

	/* Read the pet command settings */
	do_byte(&p_ptr->pet_follow_distance, flag);
	do_byte(&p_ptr->pet_open_doors, flag);
	do_byte(&p_ptr->pet_pickup_items, flag);

	/* Dripping Tread */
	do_s16b(&p_ptr->dripping_tread, flag);

	/* Read the inventory */
	if (!do_inventory(flag) && (flag == ls_flag_t::LOAD))	/* do NOT reverse this ordering */
	{
		note("Unable to read inventory");
		return (FALSE);
	}

	/* Stores */
	do_stores(flag);

	/* I'm not dead yet... */
	if (!death)
	{
		/* Dead players have no dungeon */
		if (flag == ls_flag_t::LOAD) note("Restoring Dungeon...");
		if ((flag == ls_flag_t::LOAD) && (!do_dungeon(ls_flag_t::LOAD, FALSE)))
		{
			note("Error reading dungeon data");
			return (FALSE);
		}
		if (flag == ls_flag_t::SAVE) do_dungeon(ls_flag_t::SAVE, FALSE);
		my_sentinel("Before ghost data", 435, flag);
		my_sentinel("After ghost data", 320, flag);
	}

	{
		byte foo = 0;
		if (flag == ls_flag_t::SAVE)
		{
			/*
			 * Safety Padding. It's there
			 * for a good reason. Trust me on
			 * this. Keep this at the *END*
			 * of the file, and do *NOT* try to
			 * read it. Insert any new stuff before
			 * this position.
			 */
			do_byte(&foo, ls_flag_t::SAVE);
		}
	}

	/* Success */
	return (TRUE);
}



/*
 * Actually read the savefile
 */
static errr rd_savefile(void)
{
	errr err = 0;

	/* The savefile is a binary file */
	fff = my_fopen(savefile, "rb");

	/* Paranoia */
	if (!fff) return ( -1);

	/* Call the sub-function */
	err = !do_savefile_aux(ls_flag_t::LOAD);

	/* Check for errors */
	if (ferror(fff)) err = -1;

	/* Close the file */
	my_fclose(fff);

	/* Result */
	return (err);
}


/*
 * Attempt to Load a "savefile"
 *
 * On multi-user systems, you may only "read" a savefile if you will be
 * allowed to "write" it later, this prevents painful situations in which
 * the player loads a savefile belonging to someone else, and then is not
 * allowed to save his game when he quits.
 *
 * We return "TRUE" if the savefile was usable, and we set the global
 * flag "character_loaded" if a real, living, character was loaded.
 *
 * Note that we always try to load the "current" savefile, even if
 * there is no such file, so we must check for "empty" savefile names.
 */
bool_ load_player(void)
{
	int fd = -1;

	errr err = 0;

	cptr what = "generic";

	/* Paranoia */
	turn = 0;

	/* Paranoia */
	death = FALSE;


	/* Allow empty savefile name */
	if (!savefile[0]) return (TRUE);


	/* XXX XXX XXX Fix this */

	/* Verify the existance of the savefile */
	if (!file_exist(savefile))
	{
		/* Give a message */
		msg_format("Savefile does not exist: %s", savefile);
		msg_print(NULL);

		/* Allow this */
		return (TRUE);
	}

	/* Okay */
	if (!err)
	{
		/* Open the savefile */
		fd = fd_open(savefile, O_RDONLY);

		/* No file */
		if (fd < 0) err = -1;

		/* Message (below) */
		if (err) what = "Cannot open savefile";
	}

	/* Process file */
	if (!err)
	{
		byte tmp8u = 0;

		/* Open the file XXX XXX XXX XXX Should use Angband file interface */
		fff = my_fopen(savefile, "rb");
/*		fff = fdopen(fd, "r"); */

		/* Read the first four bytes */
		do_u32b(&vernum, ls_flag_t::LOAD);
		do_byte(&tmp8u, ls_flag_t::LOAD); // For comatibility with old savefiles

		/* XXX XXX XXX XXX Should use Angband file interface */
		my_fclose(fff);
		/* fclose(fff) */

		/* Close the file */
		fd_close(fd);
	}

	/* Process file */
	if (!err)
	{

		/* Extract version */
		sf_major = VERSION_MAJOR;
		sf_minor = VERSION_MINOR;
		sf_patch = VERSION_PATCH;

		/* Clear screen */
		Term_clear();

		/* Attempt to load */
		err = rd_savefile();

		/* Message (below) */
		if (err) what = "Cannot parse savefile";
	}

	/* Paranoia */
	if (!err)
	{
		/* Invalid turn */
		if (!turn) err = -1;

		/* Message (below) */
		if (err) what = "Broken savefile";
	}


	/* Okay */
	if (!err)
	{
		/* Player is dead */
		if (death)
		{
			/* Player is no longer "dead" */
			death = FALSE;

			/* Cheat death (unless the character retired) */
			if (arg_wizard && !total_winner)
			{
				/* A character was loaded */
				character_loaded = TRUE;

				/* Done */
				return (TRUE);
			}

			/* Count lives */
			sf_lives++;

			/* Forget turns */
			turn = old_turn = 0;

			/* Done */
			return (TRUE);
		}

		/* A character was loaded */
		character_loaded = TRUE;

		/* Still alive */
		if (p_ptr->chp >= 0)
		{
			/* Reset cause of death */
			(void)strcpy(died_from, "(alive and well)");
		}

		/* Success */
		return (TRUE);
	}


	/* Message */
	msg_format("Error (%s) reading %d.%d.%d savefile.",
	           what, sf_major, sf_minor, sf_patch);
	msg_print(NULL);

	/* Oops */
	return (FALSE);
}



/*
 * Medium level player saver
 */
static bool_ save_player_aux(char *name)
{
	bool_ ok = FALSE;
	int fd = -1;
	int mode = 0644;

	/* No file yet */
	fff = NULL;

	/* Create the savefile */
	fd = fd_make(name, mode);

	/* File is okay */
	if (fd >= 0)
	{
		/* Close the "fd" */
		(void)fd_close(fd);

		/* Open the savefile */
		fff = my_fopen(name, "wb");

		/* Successful open */
		if (fff)
		{
			/* Write the savefile */
			if (do_savefile_aux(ls_flag_t::SAVE)) ok = TRUE;

			/* Attempt to close it */
			if (my_fclose(fff)) ok = FALSE;
		}

		/* "broken" savefile */
		if (!ok)
		{
			/* Remove "broken" files */
			(void)fd_kill(name);
		}
	}

	/* Failure */
	if (!ok) return (FALSE);

	/* Success */
	return (TRUE);
}

/*
 * Attempt to save the player in a savefile
 */
bool_ save_player(void)
{
	int result = FALSE;
	char safe[1024];

	/* New savefile */
	strcpy(safe, savefile);
	strcat(safe, ".new");

	/* Remove it */
	fd_kill(safe);

	/* Attempt to save the player */
	if (save_player_aux(safe))
	{
		char temp[1024];

		/* Old savefile */
		strcpy(temp, savefile);
		strcat(temp, ".old");

		/* Remove it */
		fd_kill(temp);

		/* Preserve old savefile */
		fd_move(savefile, temp);

		/* Activate new savefile */
		fd_move(safe, savefile);

		/* Remove preserved savefile */
		fd_kill(temp);

		/* Hack -- Pretend the character was loaded */
		character_loaded = TRUE;

		/* Success */
		result = TRUE;
	}

	save_savefile_names();

	/* Return the result */
	return (result);
}
