summaryrefslogtreecommitdiff
path: root/src/loadsave.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/loadsave.cc')
-rw-r--r--src/loadsave.cc3190
1 files changed, 3190 insertions, 0 deletions
diff --git a/src/loadsave.cc b/src/loadsave.cc
new file mode 100644
index 00000000..3aaf86e7
--- /dev/null
+++ b/src/loadsave.cc
@@ -0,0 +1,3190 @@
+/* File: loadsave.c */
+
+/* Purpose: interact with savefiles. This file was made by
+ unifying load2.c and save.c from the old codebase. Doing it
+ this way makes maintenance easier and lets us share code. */
+
+#include "angband.h"
+
+#include "messages.h"
+#include "quark.h"
+#include "hooks.h"
+
+#include <memory>
+
+static void do_byte(byte *, int);
+static void do_bool(bool_ *, int);
+static void do_u16b(u16b *, int);
+static void do_s16b(s16b *, int);
+static void do_u32b(u32b *, int);
+static void do_s32b(s32b *, int);
+static void do_string(char *, int, int);
+static void do_lore(int, int);
+static void do_monster(monster_type *, int);
+static void do_randomizer(int flag);
+static void do_spells(int, int);
+static void note(cptr);
+static void do_fate(int, int);
+static void do_item(object_type *, int);
+static void do_options(int);
+static bool_ do_store(store_type *, int);
+static void do_messages(int flag);
+static void do_xtra(int, int);
+static bool_ do_savefile_aux(int);
+static void junkinit(void);
+static void morejunk(void);
+static bool_ do_inventory(int);
+static bool_ do_dungeon(int, bool_);
+static void do_grid(int);
+static void my_sentinel(const char *, u16b, int);
+
+static void do_ver_s16b(s16b *, u32b, s16b, int);
+
+static void skip_ver_byte(u32b, int);
+
+errr rd_savefile(void);
+
+static FILE *fff; /* Local savefile ptr */
+
+/*
+ * 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);
+}
+
+/*
+ * Do object memory and similar stuff
+ */
+static void do_xtra(int k_idx, int flag)
+{
+ byte tmp8u = 0;
+ object_kind *k_ptr = &k_info[k_idx];
+
+ if (flag == LS_SAVE)
+ {
+ if (k_ptr->aware) tmp8u |= 0x01;
+ if (k_ptr->tried) tmp8u |= 0x02;
+ if (k_ptr->know) tmp8u |= 0x04;
+ if (k_ptr->artifact) tmp8u |= 0x80;
+
+ do_byte(&tmp8u, flag);
+ }
+ if (flag == LS_LOAD)
+ {
+ do_byte(&tmp8u, flag);
+ k_ptr->aware = ((tmp8u & 0x01) ? TRUE : FALSE);
+ k_ptr->tried = ((tmp8u & 0x02) ? TRUE : FALSE);
+ k_ptr->know = ((tmp8u & 0x04) ? TRUE : FALSE);
+ k_ptr->artifact = ((tmp8u & 0x80) ? TRUE : FALSE);
+ }
+}
+
+/*
+ * Load/Save quick start data
+ */
+void do_quick_start(int flag)
+{
+ 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(&previous_char.chaos_patron, flag);
+ do_u32b(&previous_char.weapon, 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(int flag)
+{
+ player_race_mod *sr_ptr = &race_mod_info[SUBRACE_SAVE];
+ int i;
+ char buf[81];
+
+ if (flag == LS_SAVE)
+ strncpy(buf, sr_ptr->title + rmp_name, 80);
+ do_string(buf, 80, flag);
+ if (flag == LS_LOAD)
+ strncpy(sr_ptr->title + rmp_name, buf, 80);
+
+ if (flag == LS_SAVE)
+ strncpy(buf, sr_ptr->desc + rmp_text, 80);
+ do_string(buf, 80, flag);
+ if (flag == LS_LOAD)
+ strncpy(sr_ptr->desc + rmp_text, buf, 80);
+
+ 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);
+ }
+}
+
+/*
+ * Misc. other data
+ */
+static char loaded_game_module[80];
+static bool_ do_extra(int flag)
+{
+ int i, j;
+ byte tmp8u = 0;
+ s16b tmp16s = 0;
+ u32b tmp32u = 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_SAVE)
+ {
+ tmp8u = max_d_idx;
+ tmp16s = MAX_DUNGEON_DEPTH;
+ }
+ do_byte(&tmp8u, flag);
+
+ if (flag == LS_LOAD)
+ {
+ if (tmp8u > max_d_idx)
+ {
+ note(format("Too many (%d) dungeon types!", tmp8u));
+ }
+ }
+
+ do_s16b(&tmp16s, flag);
+
+ if (flag == LS_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_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_LOAD) && (tmp16s > MAX_SKILLS))
+ {
+ quit("Too many skills");
+ }
+
+ if (flag == LS_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_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);
+
+ /* Found 24 unused bytes here...
+ Converted it to be the alchemist's
+ known artifact flags.
+ Note that the ego flags and the gained levels
+ record are recorded here too, but we use the
+ _ver_ format to protect save file compatablity.
+ Note that the other alchemist knowledge (item types known)
+ is stored in do_aux, and is a bit flag in a previously
+ unused bit.
+ */
+ for (i = 0; i < 6 ; ++i)
+ do_u32b(&alchemist_known_artifacts[i], flag);
+
+ for (i = 0; i < 32 ; ++i)
+ do_u32b(&alchemist_known_egos[i], flag);
+
+ do_u32b(&alchemist_gained, 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(&p_ptr->arena_number, flag);
+ do_s16b(&p_ptr->inside_arena, flag);
+ do_s16b(&p_ptr->inside_quest, flag);
+ do_byte((byte*)&p_ptr->exit_bldg, 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_SAVE) tmp8u = MAX_PLOTS;
+ do_byte(&tmp8u, flag);
+
+ if ((flag == LS_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_SAVE)
+ {
+ tmp8u = MAX_RANDOM_QUEST;
+ }
+ do_byte(&tmp8u, flag);
+
+ if ((flag == LS_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_SAVE)
+ tmp8u = max_d_idx;
+ do_byte(&tmp8u, flag);
+ for (i = 0; i < tmp8u; i++)
+ {
+ if (flag == LS_SAVE)
+ tmp16s = max_dlv[i];
+ do_s16b(&tmp16s, flag);
+ if ((flag == LS_LOAD) && (i <= max_d_idx))
+ max_dlv[i] = tmp16s;
+ }
+ /* Repair max player level??? */
+ if ((flag == LS_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(&p_ptr->tim_fire_aura, flag);
+ do_ver_s16b(&p_ptr->tim_poison, SAVEFILE_VERSION, 0, flag);
+ do_s16b(&p_ptr->resist_magic, 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(&p_ptr->walk_water, flag);
+ do_s16b(&p_ptr->tim_mental_barrier, flag);
+ do_s16b(&p_ptr->immov_cntr, flag);
+ do_s16b(&p_ptr->strike, flag);
+ do_s16b(&p_ptr->meditation, flag);
+ do_s16b(&p_ptr->tim_reflect, flag);
+ do_s16b(&p_ptr->tim_res_time, 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(&p_ptr->loan, flag);
+ do_s32b(&p_ptr->loan_time, 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_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_SAVE)
+ tmp8u = p_ptr->corruptions[i];
+
+ do_byte(&tmp8u, flag);
+
+ if (flag == LS_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(&p_ptr->maximize, 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(&p_ptr->xtra_spells, 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(&p_ptr->druid_extra, flag);
+ do_u32b(&p_ptr->druid_extra2, flag);
+ do_u32b(&p_ptr->druid_extra3, flag);
+ do_u32b(&p_ptr->music_extra, flag);
+ do_u32b(&p_ptr->music_extra2, flag);
+ do_u32b(&p_ptr->necro_extra, flag);
+ do_u32b(&p_ptr->necro_extra2, flag);
+
+ do_u32b(&p_ptr->race_extra1, flag);
+ do_u32b(&p_ptr->race_extra2, flag);
+ do_u32b(&p_ptr->race_extra3, flag);
+ do_u32b(&p_ptr->race_extra4, flag);
+ do_u32b(&p_ptr->race_extra5, flag);
+ do_u32b(&p_ptr->race_extra6, flag);
+ do_u32b(&p_ptr->race_extra7, 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_SAVE) tmp16s = POWER_MAX;
+ do_s16b(&tmp16s, flag);
+ if ((flag == LS_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 */
+ for (i = 0; i < MAX_BOUNTIES; i++)
+ {
+ do_s16b(&bounties[i][0], flag);
+ do_s16b(&bounties[i][1], flag);
+ }
+ do_u32b(&total_bounties, flag);
+ 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_SAVE) tmp8u = death;
+ do_byte(&tmp8u, flag);
+ if (flag == LS_LOAD) death = tmp8u;
+
+ /* Incompatible module? */
+ if (flag == LS_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_SAVE) tmp8u = feeling;
+ do_byte(&tmp8u, flag);
+ if (flag == LS_LOAD) feeling = tmp8u;
+
+ /* Turn of last "feeling" */
+ do_s32b(&old_turn, flag);
+
+ /* Current turn */
+ do_s32b(&turn, flag);
+
+ 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_SAVE, TRUE);
+
+ my_fclose(fff);
+}
+
+/*
+ * 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;
+
+ /* File type is "SAVE" */
+ FILE_TYPE(FILE_TYPE_SAVE);
+
+ /* 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_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);
+
+ /* Successful save */
+ character_saved = TRUE;
+
+ /* 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);
+}
+
+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;
+}
+
+/*
+ * 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)
+ {
+ /* 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_LOAD);
+ do_byte(&sf_extra, LS_LOAD);
+
+ /* 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;
+ sf_extra = VERSION_EXTRA;
+
+ /* 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)
+ {
+ /* Maybe the scripts want to resurrect char */
+ if (process_hooks_ret(HOOK_LOAD_END, "d", "(d)", death))
+ {
+ character_loaded = process_hooks_return[0].num;
+ death = process_hooks_return[1].num;
+ return TRUE;
+ }
+
+ /* 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);
+}
+
+
+/*
+ * Size-aware read/write routines for the savefile, do all their
+ * work through sf_get and sf_put.
+ */
+
+static void do_byte(byte *v, int flag)
+{
+ if (flag == LS_LOAD)
+ {
+ *v = sf_get();
+ return;
+ }
+ if (flag == LS_SAVE)
+ {
+ byte val = *v;
+ sf_put(val);
+ return;
+ }
+ /* We should never reach here, so bail out */
+ printf("FATAL: do_byte passed %d\n", flag);
+ exit(0);
+}
+
+static void do_bool(bool_ *f, int flag)
+{
+ byte b = *f;
+ do_byte(&b, flag);
+ if (flag == LS_LOAD)
+ {
+ *f = b;
+ }
+}
+
+static void do_u16b(u16b *v, int flag)
+{
+ if (flag == LS_LOAD)
+ {
+ (*v) = sf_get();
+ (*v) |= ((u16b)(sf_get()) << 8);
+ return;
+ }
+ if (flag == LS_SAVE)
+ {
+ u16b val;
+ val = *v;
+ sf_put((byte)(val & 0xFF));
+ sf_put((byte)((val >> 8) & 0xFF));
+ return;
+ }
+ /* Never should reach here, bail out */
+ printf("FATAL: do_u16b passed %d\n", flag);
+ exit(0);
+}
+
+static void do_s16b(s16b *ip, int flag)
+{
+ do_u16b((u16b *)ip, flag);
+}
+
+static void do_u32b(u32b *ip, int flag)
+{
+ if (flag == LS_LOAD)
+ {
+ (*ip) = sf_get();
+ (*ip) |= ((u32b)(sf_get()) << 8);
+ (*ip) |= ((u32b)(sf_get()) << 16);
+ (*ip) |= ((u32b)(sf_get()) << 24);
+ return;
+ }
+ if (flag == LS_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;
+ }
+ /* Bad news if you're here, because you're going down */
+ printf("FATAL: do_u32b passed %d\n", flag);
+ exit(0);
+}
+
+static void do_s32b(s32b *ip, int flag)
+{
+ do_u32b((u32b *)ip, flag);
+}
+
+static void save_string(const char *str)
+{
+ while (*str)
+ {
+ do_byte((byte*)str, LS_SAVE);
+ str++;
+ }
+ do_byte((byte*)str, LS_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_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, int flag)
+/* Max is ignored for writing */
+{
+ if (flag == LS_LOAD)
+ {
+ load_string(str, max);
+ return;
+ }
+ if (flag == LS_SAVE)
+ {
+ save_string(str);
+ return;
+ }
+ printf("FATAL: do_string passed flag %d\n", flag);
+ exit(0);
+}
+
+static void skip_ver_byte(u32b version, int flag)
+/* Reads and discards a byte if the savefile is as old as/older than version */
+{
+ if ((flag == LS_LOAD) && (vernum <= version))
+ {
+ byte forget;
+ do_byte(&forget, flag);
+ }
+ return;
+}
+
+static void do_ver_s16b(s16b *v, u32b version, s16b defval, int flag)
+{
+ if ((flag == LS_LOAD) && (vernum < version))
+ {
+ *v = defval;
+ return;
+ }
+ do_s16b(v, 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();
+}
+
+
+/*
+ * 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, int 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_LOAD)
+ {
+ do_byte(&old_dd, LS_LOAD);
+ do_byte(&old_ds, LS_LOAD);
+ }
+ if (flag == LS_SAVE)
+ {
+ do_byte(&o_ptr->dd, LS_SAVE);
+ do_byte(&o_ptr->ds, LS_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_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_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_SAVE) return ; /* Stick any more shared code before this. The rest
+ of this function is reserved for LS_LOAD's
+ cleanup functions */
+ /*********** END OF LS_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;
+ }
+}
+
+
+
+
+/*
+ * Read a monster
+ */
+static void do_monster(monster_type *m_ptr, int 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_u32b(&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_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);
+ }
+}
+
+
+
+
+
+/*
+ * Handle monster lore
+ */
+static void do_lore(int r_idx, int 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_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 bool_ do_store(store_type *str, int flag)
+/* FIXME! Why does this return anything when
+ it always returns the same thing? */
+{
+ int j;
+
+ byte num;
+
+ byte store_inven_max = STORE_INVEN_MAX;
+
+ /* Some basic info */
+ do_s32b(&str->store_open, flag);
+ do_u16b(&str->owner, flag);
+ if (flag == LS_SAVE) num = str->stock_num;
+
+ /* Could be cleaner, done this way for benefit of the for loop later on */
+ do_byte(&num, flag);
+
+ /* Last visit */
+ do_s32b(&str->last_visit, flag);
+
+ /* Items */
+ for (j = 0; j < num; j++)
+ {
+ if (flag == LS_LOAD)
+ /* Can't this be cleaner? */
+ {
+ object_type forge;
+ /* Wipe the object */
+ object_wipe(&forge);
+ /* Read the item */
+ do_item(&forge, LS_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_SAVE) do_item(&str->stock[j], flag);
+ }
+
+ /* Success */
+ return (TRUE);
+}
+
+/*
+ * RNG state
+ */
+static void do_randomizer(int 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_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(int 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_LOAD) /* There *MUST* be some nice way to unify this! */
+ {
+ u16b c;
+ do_u16b(&c, LS_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_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_SAVE);
+ }
+
+ do_byte((byte*)&autosave_l, flag);
+ do_byte((byte*)&autosave_t, flag);
+ do_s16b(&autosave_freq, flag);
+
+ if (flag == LS_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_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);
+ }
+}
+
+
+/* Load/Save the random spells info */
+static void do_spells(int i, int 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);
+}
+
+
+/*
+ * 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(int flag)
+{
+ if (flag == LS_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_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_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_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_SAVE); /* Sentinel */
+ }
+ /* Success */
+ return (TRUE);
+}
+
+
+
+/*
+ * Read the saved messages
+ */
+static void do_messages(int flag) /* FIXME! We should be able to unify this better */
+{
+ int i;
+ char buf[128];
+ byte color;
+
+ s16b num;
+
+ if (flag == LS_SAVE) num = message_num();
+
+ /* Total */
+ do_s16b(&num, flag);
+
+ /* Read the messages */
+ if (flag == LS_LOAD)
+ {
+ byte tmp8u = 0;
+ for (i = 0; i < num; i++)
+ {
+ /* Read the message */
+ do_string(buf, 128, LS_LOAD);
+ do_byte(&color, flag);
+ do_byte(&tmp8u, flag);
+
+ /* Save the message */
+ message_add(buf, color);
+ }
+ }
+ if (flag == LS_SAVE)
+ {
+ byte holder;
+ byte zero = 0;
+ for (i = num - 1; i >= 0; i--)
+ {
+ do_string((char *)message_str((s16b)i), 0, LS_SAVE);
+ holder = message_color((s16b)i);
+ do_byte(&holder, flag);
+ do_byte(&zero, flag);
+ }
+ }
+}
+
+/*
+ * 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(int 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_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_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_SAVE) compact_objects(0);
+ if (flag == LS_SAVE) compact_monsters(0);
+ if (flag == LS_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_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_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_SAVE);
+ continue; /* Saving is easy */
+ }
+ /* Until the end of the loop, this is all LS_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_LOAD);
+
+ /* Monster */
+ if (o_ptr->held_m_idx)
+ {
+ monster_type *m_ptr;
+
+ /* Monster */
+ m_ptr = &m_list[o_ptr->held_m_idx];
+
+ /* Build a stack */
+ o_ptr->next_o_idx = m_ptr->hold_o_idx;
+
+ /* Place the object */
+ m_ptr->hold_o_idx = o_idx;
+ }
+
+ /* Dungeon */
+ else
+ {
+ /* Access the item location */
+ c_ptr = &cave[o_ptr->iy][o_ptr->ix];
+
+ /* Build a stack */
+ o_ptr->next_o_idx = c_ptr->o_idx;
+
+ /* Place the object */
+ c_ptr->o_idx = o_idx;
+ }
+ }
+
+ /*** Monsters ***/
+
+ if (flag == LS_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_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_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_SAVE);
+ continue; /* Easy to save a monster */
+ }
+ /* From here on, it's all LS_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_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_SAVE && !no_companions) ? max_m_idx : 0;
+
+ /* Read the monster count */
+ do_u16b(&tmp16b, flag);
+
+ /* Hack -- verify */
+ if ((flag == LS_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_LOAD) character_dungeon = TRUE;
+
+ /* Success */
+ return (TRUE);
+}
+
+/* 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_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_blocks(int flag)
+/* Handle blocked-allocation stuff for quests and lua stuff
+ This depends on a dyn_tosave array of s32b's. Adjust as needed
+ if other data structures are desirable. This also is not hooked
+ in yet. Ideally, plug it near the end of the savefile.
+ */
+{
+ s16b numblks, n_iter = 0; /* How many blocks do we have? */
+ do_s16b(&numblks, flag);
+ while (n_iter < numblks)
+ {
+ /* do_s32b(dyn_tosave[n_iter], flag); */
+ n_iter++;
+ }
+ my_sentinel("In blocked-allocation area", 37, flag);
+}
+
+void do_fate(int i, int flag)
+{
+ if ((flag == LS_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(int 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(int 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_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_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);
+ }
+ }
+}
+
+
+/*
+ * Actually read the savefile
+ */
+static bool_ do_savefile_aux(int flag)
+{
+ int i, j;
+
+ byte tmp8u;
+ u16b tmp16u;
+
+ /* Mention the savefile version */
+ if (flag == LS_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_SAVE)
+ {
+ sf_when = time((time_t *) 0); /* Note when file was saved */
+ sf_xtra = 0L; /* What the hell is this? */
+ sf_saves++; /* Increment the saves ctr */
+ }
+
+ /* Handle version bytes. FIXME! DG wants me to change this all around */
+ if (flag == LS_LOAD)
+ {
+ u32b mt32b;
+ byte mtbyte;
+
+ /* Discard all this, we've already read it */
+ do_u32b(&mt32b, flag);
+ do_byte(&mtbyte, flag);
+ }
+ if (flag == LS_SAVE)
+ {
+ u32b saver;
+ saver = SAVEFILE_VERSION;
+ do_u32b(&saver, flag);
+ tmp8u = (byte)rand_int(256);
+ do_byte(&tmp8u, flag); /* 'encryption' */
+ }
+
+ /* Operating system info? Not really. This is just set to 0L */
+ do_u32b(&sf_xtra, 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_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_SAVE) tmp16u = max_r_idx;
+ do_u16b(&tmp16u, flag);
+
+ /* Incompatible save files */
+ if ((flag == LS_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_SAVE) tmp16u = max_k_idx;
+ do_u16b(&tmp16u, flag);
+
+ /* Incompatible save files */
+ if ((flag == LS_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_LOAD) junkinit();
+
+ {
+ u16b max_towns_ldsv;
+ u16b max_quests_ldsv;
+ if (flag == LS_SAVE) max_towns_ldsv = max_towns;
+ /* Number of towns */
+ do_u16b(&max_towns_ldsv, flag);
+ /* Incompatible save files */
+ if ((flag == LS_LOAD) && (max_towns_ldsv > max_towns))
+ {
+ note(format("Too many (%u) towns!", max_towns_ldsv));
+ return (FALSE);
+ }
+ /* Min of random towns */
+ if (flag == LS_SAVE) max_towns_ldsv = TOWN_RANDOM;
+ do_u16b(&max_towns_ldsv, flag);
+ /* Incompatible save files */
+ if ((flag == LS_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_LOAD))
+ {
+ create_stores_stock(i);
+ }
+ }
+ }
+
+ /* Number of dungeon */
+ if (flag == LS_SAVE) max_towns_ldsv = max_d_idx;
+ do_u16b(&max_towns_ldsv, flag);
+
+ /* Incompatible save files */
+ if ((flag == LS_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_SAVE) max_quests_ldsv = TOWN_DUNGEON;
+ do_u16b(&max_quests_ldsv, flag);
+ /* Incompatible save files */
+ if ((flag == LS_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_SAVE) max_quests_ldsv = MAX_Q_IDX;
+ do_u16b(&max_quests_ldsv, flag);
+
+ /* Incompatible save files */
+ if ((flag == LS_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 (j = 0; j < sizeof(quest[i].data)/sizeof(quest[i].data[0]); j++)
+ {
+ do_s32b(&(quest[i].data[j]), flag);
+ }
+
+ /* Init the hooks */
+ if ((flag == LS_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_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_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_SAVE) tmp16u = MAX_RANDARTS;
+ do_u16b(&tmp16u, flag);
+ if ((flag == LS_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_SAVE) tmp16u = max_a_idx;
+ do_u16b(&tmp16u, flag);
+ /* Incompatible save files */
+ if ((flag == LS_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_SAVE) tmp16u = MAX_FATES;
+ do_u16b(&tmp16u, flag);
+
+ /* Incompatible save files */
+ if ((flag == LS_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_SAVE) tmp16u = max_t_idx;
+ do_u16b(&tmp16u, flag);
+
+ /* Incompatible save files */
+ if ((flag == LS_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_SAVE) tmp16u = MAX_INSCRIPTIONS;
+ do_u16b(&tmp16u, flag);
+
+ /* Incompatible save files */
+ if ((flag == LS_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_SAVE) tmp16u = PY_MAX_LEVEL;
+ do_u16b(&tmp16u, flag);
+ /* Incompatible save files */
+ if ((flag == LS_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_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_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_LOAD) note("Restoring Dungeon...");
+ if ((flag == LS_LOAD) && (!do_dungeon(LS_LOAD, FALSE)))
+ {
+ note("Error reading dungeon data");
+ return (FALSE);
+ }
+ if (flag == LS_SAVE) do_dungeon(LS_SAVE, FALSE);
+ my_sentinel("Before ghost data", 435, flag);
+ my_sentinel("After ghost data", 320, flag);
+ }
+
+ {
+ byte foo = 0;
+ if (flag == LS_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_SAVE);
+ }
+ }
+
+ /* Success */
+ return (TRUE);
+}
+
+
+/*
+ * Actually read the savefile
+ */
+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_LOAD);
+
+ /* Check for errors */
+ if (ferror(fff)) err = -1;
+
+ /* Close the file */
+ my_fclose(fff);
+
+ /* Result */
+ return (err);
+}
+
+/*
+ * 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->arena_number = 0;
+ p_ptr->inside_arena = 0;
+ p_ptr->inside_quest = 0;
+ p_ptr->exit_bldg = TRUE;
+ p_ptr->exit_bldg = TRUE;
+ 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];
+}
+
+static void do_grid(int flag)
+/* Does the grid, RLE, blahblah. RLE sucks. I hate it. */
+{
+ int i = 0, y = 0, x = 0;
+ byte count = 0;
+ byte tmp8u = 0;
+ s16b tmp16s = 0;
+ cave_type *c_ptr;
+ byte prev_char = 0;
+ s16b prev_s16b = 0;
+ int ymax = cur_hgt, xmax = cur_wid;
+
+ int part; /* Which section of the grid we're on */
+
+ for (part = 0; part < 9; part++) /* There are 8 fields to the grid, each stored
+ in a seperate RLE data structure */
+ {
+ if (flag == LS_SAVE)
+ {
+ count = 0;
+ prev_s16b = 0;
+ prev_char = 0; /* Clear, prepare for RLE */
+ for (y = 0; y < cur_hgt; y++)
+ {
+ for (x = 0; x < cur_wid; x++)
+ {
+ c_ptr = &cave[y][x];
+ switch (part)
+ {
+ case 0:
+ tmp16s = c_ptr->info;
+ break;
+
+ case 1:
+ tmp8u = c_ptr->feat;
+ break;
+
+ case 2:
+ tmp8u = c_ptr->mimic;
+ break;
+
+ case 3:
+ tmp16s = c_ptr->special;
+ break;
+
+ case 4:
+ tmp16s = c_ptr->special2;
+ break;
+
+ case 5:
+ tmp16s = c_ptr->t_idx;
+ break;
+
+ case 6:
+ tmp16s = c_ptr->inscription;
+ break;
+
+ case 7:
+ tmp8u = c_ptr->mana;
+ break;
+
+ case 8:
+ tmp16s = c_ptr->effect;
+ break;
+ }
+ /* Flush a full run */
+ if ((((part != 1) && (part != 2) && (part != 7)) &&
+ (tmp16s != prev_s16b)) || (((part == 1) || (part == 2)
+ || (part == 7)) &&
+ (tmp8u != prev_char)) ||
+ (count == MAX_UCHAR))
+ {
+ do_byte(&count, LS_SAVE);
+ switch (part)
+ {
+ case 0:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 8:
+ do_s16b(&prev_s16b, LS_SAVE);
+ prev_s16b = tmp16s;
+ break;
+
+ case 1:
+ case 2:
+ case 7:
+ do_byte(&prev_char, LS_SAVE);
+ prev_char = tmp8u;
+ break;
+ }
+ count = 1; /* Reset RLE */
+ }
+ else
+ count++; /* Otherwise, keep going */
+ }
+ }
+ /* Fallen off the end of the world, flush anything left */
+ if (count)
+ {
+ do_byte(&count, LS_SAVE);
+ switch (part)
+ {
+ case 0:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 8:
+ do_s16b(&prev_s16b, LS_SAVE);
+ break;
+
+ case 1:
+ case 2:
+ case 7:
+ do_byte(&prev_char, LS_SAVE);
+ break;
+ }
+ }
+ }
+ if (flag == LS_LOAD)
+ {
+ x = 0;
+ for (y = 0; y < ymax; )
+ {
+ do_byte(&count, LS_LOAD);
+ switch (part)
+ {
+ case 0:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 8:
+ do_s16b(&tmp16s, LS_LOAD);
+ break;
+
+ case 1:
+ case 2:
+ case 7:
+ do_byte(&tmp8u, LS_LOAD);
+ break;
+ }
+ for (i = count; i > 0; i--) /* RLE */
+ {
+ c_ptr = &cave[y][x];
+ switch (part)
+ {
+ case 0:
+ c_ptr->info = tmp16s;
+ break;
+
+ case 1:
+ c_ptr->feat = tmp8u;
+ break;
+
+ case 2:
+ c_ptr->mimic = tmp8u;
+ break;
+
+ case 3:
+ c_ptr->special = tmp16s;
+ break;
+
+ case 4:
+ c_ptr->special2 = tmp16s;
+ break;
+
+ case 5:
+ c_ptr->t_idx = tmp16s;
+ break;
+
+ case 6:
+ c_ptr->inscription = tmp16s;
+ break;
+
+ case 7:
+ c_ptr->mana = tmp8u;
+ break;
+
+ case 8:
+ c_ptr->effect = tmp16s;
+ break;
+ }
+ if (++x >= xmax)
+ {
+ /* Wrap */
+ x = 0;
+ if ((++y) >= ymax) break;
+ }
+ }
+ }
+ }
+ }
+}
+
+static void my_sentinel(const char *place, u16b value, int flag)
+/* This function lets us know exactly where a savefile is
+ broken by reading/writing conveniently a sentinel at this
+ spot */
+{
+ if (flag == LS_SAVE)
+ {
+ do_u16b(&value, flag);
+ return;
+ }
+ if (flag == LS_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);
+}